diff --git a/.github/workflows/build.yml.in b/.github/build.in.yml similarity index 85% rename from .github/workflows/build.yml.in rename to .github/build.in.yml index 02dd04d95f5f5..3facc8b60a92b 100644 --- a/.github/workflows/build.yml.in +++ b/.github/build.in.yml @@ -1,3 +1,8 @@ +### 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 @@ -30,6 +35,17 @@ jobs: - name: Look for ignored files uses: credfeto/action-no-ignored-files@v1.1.0 + - name: "Check for Lean files with the executable bit set" + shell: bash + run: | + executable_files="$(find . -name '*.lean' -type f \( -perm -u=x -o -perm -g=x -o -perm -o=x \))" + if [[ -n "$executable_files" ]] + then + echo "ERROR: The following Lean files have the executable bit set." + echo "$executable_files" + exit 1 + fi + - name: install Python if: ${{ 'STYLE_LINT_RUNNER' == 'ubuntu-latest' }} uses: actions/setup-python@v5 @@ -43,9 +59,9 @@ jobs: ./elan-init -y --default-toolchain none echo "$HOME/.elan/bin" >> "${GITHUB_PATH}" - - name: "run style linters: Python ones and their Lean rewrite" + - name: "run style linters" run: | - ./scripts/lint-style.sh + lake exe lint-style - name: Install bibtool if: ${{ 'STYLE_LINT_RUNNER' == 'ubuntu-latest' }} @@ -57,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 @@ -118,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 @@ -137,8 +131,22 @@ jobs: - name: get cache id: get run: | - lake exe cache clean - lake exe cache get + 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" + + - 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 @@ -202,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: | @@ -262,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 }} @@ -275,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 @@ -305,7 +322,7 @@ jobs: - if: contains(steps.PR.outputs.pr_labels, 'auto-merge-after-CI') name: If `auto-merge-after-CI` is present, add a `bors merge` comment. - uses: GrantBirki/comment@v2.0.1 + uses: GrantBirki/comment@v2 with: token: ${{ secrets.AUTO_MERGE_TOKEN }} issue-number: ${{ steps.PR.outputs.number }} 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_comment.yml b/.github/workflows/add_label_from_comment.yml index 12e9585a4639d..30a161785134f 100644 --- a/.github/workflows/add_label_from_comment.yml +++ b/.github/workflows/add_label_from_comment.yml @@ -7,50 +7,15 @@ on: jobs: add_ready_to_merge_label: name: Add ready-to-merge label - if: (toJSON(github.event.issue.pull_request) != 'null') && (startsWith(github.event.comment.body, 'bors r+') || contains(toJSON(github.event.comment.body), '\r\nbors r+') || startsWith(github.event.comment.body, 'bors merge') || contains(toJSON(github.event.comment.body), '\r\nbors merge')) + if: github.event.issue.pull_request && (startsWith(github.event.comment.body, 'bors r+') || contains(toJSON(github.event.comment.body), '\nbors r+') || startsWith(github.event.comment.body, 'bors merge') || contains(toJSON(github.event.comment.body), '\nbors merge')) runs-on: ubuntu-latest steps: - - uses: octokit/request-action@v2.x - name: Get PR head - id: get_pr_head + - id: user_permission + uses: actions-cool/check-user-permission@v2 with: - route: GET /repos/:repository/pulls/:pull_number - repository: ${{ github.repository }} - pull_number: ${{ github.event.issue.number }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - # Parse steps.get_pr_head.outputs.data, since it is a string - - id: parse_pr_head - name: Parse PR head - uses: gr2m/get-json-paths-action@v1.x - with: - json: ${{ steps.get_pr_head.outputs.data }} - head_user: 'head.user.login' - - # we skip the rest if this PR is from a fork, - # since the GITHUB_TOKEN doesn't have write perms - - if: steps.parse_pr_head.outputs.head_user == 'leanprover-community' - uses: octokit/request-action@v2.x - name: Get comment author - id: get_user - with: - route: GET /repos/:repository/collaborators/:username/permission - repository: ${{ github.repository }} - username: ${{ github.event.comment.user.login }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - # Parse steps.get_user.outputs.data, since it is a string - - if: steps.parse_pr_head.outputs.head_user == 'leanprover-community' - id: parse_user - name: Parse comment author permission - uses: gr2m/get-json-paths-action@v1.x - with: - json: ${{ steps.get_user.outputs.data }} - permission: 'permission' + require: 'admin' - - if: (steps.parse_pr_head.outputs.head_user == 'leanprover-community') && (steps.parse_user.outputs.permission == 'admin') + - if: (steps.user_permission.outputs.require-result == 'true') || (github.event.comment.user.login == 'leanprover-community-mathlib4-bot') || (github.event.comment.user.login == 'leanprover-community-bot-assistant') uses: octokit/request-action@v2.x id: add_label name: Add label @@ -62,7 +27,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - if: (steps.parse_pr_head.outputs.head_user == 'leanprover-community') && (steps.parse_user.outputs.permission == 'admin') + - if: (steps.user_permission.outputs.require-result == 'true') || (github.event.comment.user.login == 'leanprover-community-mathlib4-bot') || (github.event.comment.user.login == 'leanprover-community-bot-assistant') id: remove_labels name: Remove "awaiting-author" # we use curl rather than octokit/request-action so that the job won't fail @@ -74,50 +39,15 @@ jobs: add_delegated_label: name: Add delegated label - if: (toJSON(github.event.issue.pull_request) != 'null') && (startsWith(github.event.comment.body, 'bors d') || contains(toJSON(github.event.comment.body), '\r\nbors d')) + if: github.event.issue.pull_request && (startsWith(github.event.comment.body, 'bors d') || contains(toJSON(github.event.comment.body), '\nbors d')) runs-on: ubuntu-latest steps: - - uses: octokit/request-action@v2.x - name: Get PR head - id: get_pr_head - with: - route: GET /repos/:repository/pulls/:pull_number - repository: ${{ github.repository }} - pull_number: ${{ github.event.issue.number }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - # Parse steps.get_pr_head.outputs.data, since it is a string - - id: parse_pr_head - name: Parse PR head - uses: gr2m/get-json-paths-action@v1.x - with: - json: ${{ steps.get_pr_head.outputs.data }} - head_user: 'head.user.login' - - # we skip the rest if this PR is from a fork, - # since the GITHUB_TOKEN doesn't have write perms - - if: steps.parse_pr_head.outputs.head_user == 'leanprover-community' - uses: octokit/request-action@v2.x - name: Get comment author - id: get_user - with: - route: GET /repos/:repository/collaborators/:username/permission - repository: ${{ github.repository }} - username: ${{ github.event.comment.user.login }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - # Parse steps.get_user.outputs.data, since it is a string - - if: steps.parse_pr_head.outputs.head_user == 'leanprover-community' - id: parse_user - name: Parse comment author permission - uses: gr2m/get-json-paths-action@v1.x + - id: user_permission + uses: actions-cool/check-user-permission@v2 with: - json: ${{ steps.get_user.outputs.data }} - permission: 'permission' + require: 'admin' - - if: (steps.parse_pr_head.outputs.head_user == 'leanprover-community') && (steps.parse_user.outputs.permission == 'admin') + - if: (steps.user_permission.outputs.require-result == 'true') || (github.event.comment.user.login == 'leanprover-community-mathlib4-bot') || (github.event.comment.user.login == 'leanprover-community-bot-assistant') uses: octokit/request-action@v2.x id: add_label name: Add label 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/add_label_from_review.yml b/.github/workflows/add_label_from_review.yml index 62f047b912236..9406866ff214e 100644 --- a/.github/workflows/add_label_from_review.yml +++ b/.github/workflows/add_label_from_review.yml @@ -7,50 +7,16 @@ on: jobs: add_ready_to_merge_label: name: Add ready-to-merge label - if: (startsWith(github.event.review.body, 'bors r+') || contains(toJSON(github.event.review.body), '\r\nbors r+') || startsWith(github.event.review.body, 'bors merge') || contains(toJSON(github.event.review.body), '\r\nbors merge')) + if: (startsWith(github.event.review.body, 'bors r+') || contains(toJSON(github.event.review.body), '\nbors r+') || startsWith(github.event.review.body, 'bors merge') || contains(toJSON(github.event.review.body), '\nbors merge')) runs-on: ubuntu-latest steps: - - uses: octokit/request-action@v2.x - name: Get PR head - id: get_pr_head + - id: user_permission + uses: actions-cool/check-user-permission@v2 with: - route: GET /repos/:repository/pulls/:pull_number - repository: ${{ github.repository }} - pull_number: ${{ github.event.pull_request.number }} - env: - GITHUB_TOKEN: ${{ secrets.TRIAGE_TOKEN }} - - # Parse steps.get_pr_head.outputs.data, since it is a string - - id: parse_pr_head - name: Parse PR head - uses: gr2m/get-json-paths-action@v1.x - with: - json: ${{ steps.get_pr_head.outputs.data }} - head_user: 'head.user.login' - - # we skip the rest if this PR is from a fork, - # since the GITHUB_TOKEN doesn't have write perms - - if: steps.parse_pr_head.outputs.head_user == 'leanprover-community' - uses: octokit/request-action@v2.x - name: Get comment author - id: get_user - with: - route: GET /repos/:repository/collaborators/:username/permission - repository: ${{ github.repository }} - username: ${{ github.event.review.user.login }} - env: - GITHUB_TOKEN: ${{ secrets.TRIAGE_TOKEN }} - - # Parse steps.get_user.outputs.data, since it is a string - - if: steps.parse_pr_head.outputs.head_user == 'leanprover-community' - id: parse_user - name: Parse comment author permission - uses: gr2m/get-json-paths-action@v1.x - with: - json: ${{ steps.get_user.outputs.data }} - permission: 'permission' + require: 'write' + token: ${{ secrets.TRIAGE_TOKEN }} - - if: (steps.parse_pr_head.outputs.head_user == 'leanprover-community') && (steps.parse_user.outputs.permission == 'admin') + - if: (steps.user_permission.outputs.require-result == 'true') || (github.event.review.user.login == 'leanprover-community-mathlib4-bot') || (github.event.review.user.login == 'leanprover-community-bot-assistant') uses: octokit/request-action@v2.x id: add_label name: Add label @@ -62,7 +28,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.TRIAGE_TOKEN }} - - if: (steps.parse_pr_head.outputs.head_user == 'leanprover-community') && (steps.parse_user.outputs.permission == 'admin') + - if: (steps.user_permission.outputs.require-result == 'true') || (github.event.review.user.login == 'leanprover-community-mathlib4-bot') || (github.event.review.user.login == 'leanprover-community-bot-assistant') id: remove_labels name: Remove "awaiting-author" # we use curl rather than octokit/request-action so that the job won't fail @@ -74,50 +40,16 @@ jobs: add_delegated_label: name: Add delegated label - if: (startsWith(github.event.review.body, 'bors d') || contains(toJSON(github.event.review.body), '\r\nbors d')) + if: (startsWith(github.event.review.body, 'bors d') || contains(toJSON(github.event.review.body), '\nbors d')) runs-on: ubuntu-latest steps: - - uses: octokit/request-action@v2.x - name: Get PR head - id: get_pr_head - with: - route: GET /repos/:repository/pulls/:pull_number - repository: ${{ github.repository }} - pull_number: ${{ github.event.pull_request.number }} - env: - GITHUB_TOKEN: ${{ secrets.TRIAGE_TOKEN }} - - # Parse steps.get_pr_head.outputs.data, since it is a string - - id: parse_pr_head - name: Parse PR head - uses: gr2m/get-json-paths-action@v1.x - with: - json: ${{ steps.get_pr_head.outputs.data }} - head_user: 'head.user.login' - - # we skip the rest if this PR is from a fork, - # since the GITHUB_TOKEN doesn't have write perms - - if: steps.parse_pr_head.outputs.head_user == 'leanprover-community' - uses: octokit/request-action@v2.x - name: Get comment author - id: get_user - with: - route: GET /repos/:repository/collaborators/:username/permission - repository: ${{ github.repository }} - username: ${{ github.event.review.user.login }} - env: - GITHUB_TOKEN: ${{ secrets.TRIAGE_TOKEN }} - - # Parse steps.get_user.outputs.data, since it is a string - - if: steps.parse_pr_head.outputs.head_user == 'leanprover-community' - id: parse_user - name: Parse comment author permission - uses: gr2m/get-json-paths-action@v1.x + - id: user_permission + uses: actions-cool/check-user-permission@v2 with: - json: ${{ steps.get_user.outputs.data }} - permission: 'permission' + require: 'write' + token: ${{ secrets.TRIAGE_TOKEN }} - - if: (steps.parse_pr_head.outputs.head_user == 'leanprover-community') && (steps.parse_user.outputs.permission == 'admin') + - if: (steps.user_permission.outputs.require-result == 'true') || (github.event.review.user.login == 'leanprover-community-mathlib4-bot') || (github.event.review.user.login == 'leanprover-community-bot-assistant') uses: octokit/request-action@v2.x id: add_label name: Add label diff --git a/.github/workflows/add_label_from_review_comment.yml b/.github/workflows/add_label_from_review_comment.yml new file mode 100644 index 0000000000000..da8b643fb0ee4 --- /dev/null +++ b/.github/workflows/add_label_from_review_comment.yml @@ -0,0 +1,62 @@ +name: Add "ready-to-merge" and "delegated" label from PR review comment + +on: + pull_request_review_comment: + types: [created] + +jobs: + add_ready_to_merge_label: + name: Add ready-to-merge label + if: (startsWith(github.event.comment.body, 'bors r+') || contains(toJSON(github.event.comment.body), '\nbors r+') || startsWith(github.event.comment.body, 'bors merge') || contains(toJSON(github.event.comment.body), '\nbors merge')) + runs-on: ubuntu-latest + steps: + - id: user_permission + uses: actions-cool/check-user-permission@v2 + with: + require: 'write' + token: ${{ secrets.TRIAGE_TOKEN }} + + - if: (steps.user_permission.outputs.require-result == 'true') || (github.event.comment.user.login == 'leanprover-community-mathlib4-bot') || (github.event.comment.user.login == 'leanprover-community-bot-assistant') + uses: octokit/request-action@v2.x + id: add_label + name: Add label + with: + route: POST /repos/:repository/issues/:issue_number/labels + repository: ${{ github.repository }} + issue_number: ${{ github.event.pull_request.number }} + labels: '["ready-to-merge"]' + env: + GITHUB_TOKEN: ${{ secrets.TRIAGE_TOKEN }} + + - if: (steps.user_permission.outputs.require-result == 'true') || (github.event.comment.user.login == 'leanprover-community-mathlib4-bot') || (github.event.comment.user.login == 'leanprover-community-bot-assistant') + id: remove_labels + name: Remove "awaiting-author" + # we use curl rather than octokit/request-action so that the job won't fail + # (and send an annoying email) if the labels don't exist + run: | + curl --request DELETE \ + --url https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels/awaiting-author \ + --header 'authorization: Bearer ${{ secrets.TRIAGE_TOKEN }}' + + add_delegated_label: + name: Add delegated label + if: (startsWith(github.event.comment.body, 'bors d') || contains(toJSON(github.event.comment.body), '\nbors d')) + runs-on: ubuntu-latest + steps: + - id: user_permission + uses: actions-cool/check-user-permission@v2 + with: + require: 'write' + token: ${{ secrets.TRIAGE_TOKEN }} + + - if: (steps.user_permission.outputs.require-result == 'true') || (github.event.comment.user.login == 'leanprover-community-mathlib4-bot') || (github.event.comment.user.login == 'leanprover-community-bot-assistant') + uses: octokit/request-action@v2.x + id: add_label + name: Add label + with: + route: POST /repos/:repository/issues/:issue_number/labels + repository: ${{ github.repository }} + issue_number: ${{ github.event.pull_request.number }} + labels: '["delegated"]' + env: + GITHUB_TOKEN: ${{ secrets.TRIAGE_TOKEN }} diff --git a/.github/workflows/bors.yml b/.github/workflows/bors.yml index e3a683620ffa6..207aee8482616 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 build.yml.in 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 @@ -44,6 +45,17 @@ jobs: - name: Look for ignored files uses: credfeto/action-no-ignored-files@v1.1.0 + - name: "Check for Lean files with the executable bit set" + shell: bash + run: | + executable_files="$(find . -name '*.lean' -type f \( -perm -u=x -o -perm -g=x -o -perm -o=x \))" + if [[ -n "$executable_files" ]] + then + echo "ERROR: The following Lean files have the executable bit set." + echo "$executable_files" + exit 1 + fi + - name: install Python if: ${{ 'bors' == 'ubuntu-latest' }} uses: actions/setup-python@v5 @@ -57,9 +69,9 @@ jobs: ./elan-init -y --default-toolchain none echo "$HOME/.elan/bin" >> "${GITHUB_PATH}" - - name: "run style linters: Python ones and their Lean rewrite" + - name: "run style linters" run: | - ./scripts/lint-style.sh + lake exe lint-style - name: Install bibtool if: ${{ 'bors' == 'ubuntu-latest' }} @@ -71,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 @@ -132,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 @@ -151,8 +141,22 @@ jobs: - name: get cache id: get run: | - lake exe cache clean - lake exe cache get + 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" + + - 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 +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: | @@ -276,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 }} @@ -289,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 @@ -319,7 +332,7 @@ jobs: - if: contains(steps.PR.outputs.pr_labels, 'auto-merge-after-CI') name: If `auto-merge-after-CI` is present, add a `bors merge` comment. - uses: GrantBirki/comment@v2.0.1 + uses: GrantBirki/comment@v2 with: token: ${{ secrets.AUTO_MERGE_TOKEN }} issue-number: ${{ steps.PR.outputs.number }} diff --git a/.github/workflows/bot_fix_style_comment.yaml b/.github/workflows/bot_fix_style_comment.yaml new file mode 100644 index 0000000000000..4414eb4b576b5 --- /dev/null +++ b/.github/workflows/bot_fix_style_comment.yaml @@ -0,0 +1,93 @@ +name: bot fix style (comment) + +on: + issue_comment: + types: [created, edited] + +jobs: + fix_style: + name: Fix style issues from lint + if: (github.event.issue.pull_request) && (startsWith(github.event.comment.body, 'bot fix style') || contains(toJSON(github.event.comment.body), '\nbot fix style')) + runs-on: ubuntu-latest + steps: + - id: user_permission + uses: actions-cool/check-user-permission@v2 + with: + require: 'write' + + - name: Add reaction + if: steps.user_permission.outputs.require-result == 'true' + uses: peter-evans/create-or-update-comment@v4 + with: + comment-id: ${{ github.event.comment.id }} + reactions: rocket + + - name: cleanup + if: steps.user_permission.outputs.require-result == 'true' + run: | + find . -name . -o -prune -exec rm -rf -- {} + + + - uses: actions/checkout@v4 + if: steps.user_permission.outputs.require-result == 'true' + with: + token: ${{ secrets.BOT_FIX_STYLE_TOKEN }} + + - name: Checkout PR branch + if: steps.user_permission.outputs.require-result == 'true' + run: | + gh pr checkout ${{ github.event.issue.number }} + env: + GH_TOKEN: ${{ secrets.BOT_FIX_STYLE_TOKEN }} + + - name: install Python + if: steps.user_permission.outputs.require-result == 'true' + uses: actions/setup-python@v4 + with: + python-version: 3.8 + + - name: install elan + if: steps.user_permission.outputs.require-result == 'true' + 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}" + + # run the same linting steps as in lint_and_suggest_pr.yaml + + - name: lint + if: steps.user_permission.outputs.require-result == 'true' + run: | + lake exe lint-style --fix + + - name: Install bibtool + if: steps.user_permission.outputs.require-result == 'true' + run: | + sudo apt-get update + sudo apt-get install -y bibtool + + - name: lint references.bib + if: steps.user_permission.outputs.require-result == 'true' + run: | + # ignoring the return code allows the following `reviewdog` step to add GitHub suggestions + ./scripts/lint-bib.sh || true + + - name: update {Mathlib, Tactic, Counterexamples, Archive}.lean + if: steps.user_permission.outputs.require-result == 'true' + run: | + # ignoring the return code allows the following `reviewdog` step to add GitHub suggestions + lake exe mk_all || true + + - name: Commit and push changes + if: steps.user_permission.outputs.require-result == 'true' + run: | + # cleanup junk from build + rm elan-init + rm docs/references.bib.old + # setup commit and push + git config user.name "leanprover-community-mathlib4-bot" + git config user.email "leanprover-community-mathlib4-bot@users.noreply.github.com" + git add . + # Don't fail if there's nothing to commit + git commit -m "commit changes from style linters" || true + git push origin HEAD diff --git a/.github/workflows/bot_fix_style_review.yaml b/.github/workflows/bot_fix_style_review.yaml new file mode 100644 index 0000000000000..99fa4ae9a7dab --- /dev/null +++ b/.github/workflows/bot_fix_style_review.yaml @@ -0,0 +1,99 @@ +name: bot fix style (review) + +on: + pull_request_review: + # triggers on a review, whether or not it is accompanied by a comment + types: [submitted] + +jobs: + fix_style: + name: Fix style issues from lint + if: (startsWith(github.event.review.body, 'bot fix style') || contains(toJSON(github.event.review.body), '\nbot fix style')) + runs-on: ubuntu-latest + steps: + - id: user_permission + uses: actions-cool/check-user-permission@v2 + with: + require: 'write' + + # Maybe no API exists for this yet? + # - name: Add reaction + # if: steps.user_permission.outputs.require-result == 'true' + # run: | + # gh api --method POST \ + # -H "Accept: application/vnd.github+json" \ + # -H "X-GitHub-Api-Version: 2022-11-28" \ + # /repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/pulls/${{ github.event.pull_request.number }}/reviews/${{ github.event.review.id }}/reactions \ + # -f "content=rocket" + # env: + # GH_TOKEN: ${{ secrets.BOT_FIX_STYLE_TOKEN }} + + - name: cleanup + if: steps.user_permission.outputs.require-result == 'true' + run: | + find . -name . -o -prune -exec rm -rf -- {} + + + - uses: actions/checkout@v4 + if: steps.user_permission.outputs.require-result == 'true' + with: + token: ${{ secrets.BOT_FIX_STYLE_TOKEN }} + + - name: Checkout PR branch + if: steps.user_permission.outputs.require-result == 'true' + run: | + gh pr checkout ${{ github.event.pull_request.number }} + env: + GH_TOKEN: ${{ secrets.BOT_FIX_STYLE_TOKEN }} + + - name: install Python + if: steps.user_permission.outputs.require-result == 'true' + uses: actions/setup-python@v4 + with: + python-version: 3.8 + + - name: install elan + if: steps.user_permission.outputs.require-result == 'true' + 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}" + + # run the same linting steps as in lint_and_suggest_pr.yaml + + - name: lint + if: steps.user_permission.outputs.require-result == 'true' + run: | + lake exe lint-style --fix + + - name: Install bibtool + if: steps.user_permission.outputs.require-result == 'true' + run: | + sudo apt-get update + sudo apt-get install -y bibtool + + - name: lint references.bib + if: steps.user_permission.outputs.require-result == 'true' + run: | + # ignoring the return code allows the following `reviewdog` step to add GitHub suggestions + ./scripts/lint-bib.sh || true + + - name: update {Mathlib, Tactic, Counterexamples, Archive}.lean + if: steps.user_permission.outputs.require-result == 'true' + run: | + # ignoring the return code allows the following `reviewdog` step to add GitHub suggestions + lake exe mk_all || true + + - name: Commit and push changes + if: steps.user_permission.outputs.require-result == 'true' + run: | + # cleanup junk from build + rm elan-init + rm docs/references.bib.old + # setup commit and push + git config user.name "leanprover-community-mathlib4-bot" + git config user.email "leanprover-community-mathlib4-bot@users.noreply.github.com" + git add . + # Don't fail if there's nothing to commit + git commit -m "commit changes from style linters" || true + git push origin HEAD diff --git a/.github/workflows/bot_fix_style_review_comment.yaml b/.github/workflows/bot_fix_style_review_comment.yaml new file mode 100644 index 0000000000000..097b24ba35954 --- /dev/null +++ b/.github/workflows/bot_fix_style_review_comment.yaml @@ -0,0 +1,97 @@ +name: bot fix style (review comment) + +on: + pull_request_review_comment: + types: [created, edited] + +jobs: + fix_style: + name: Fix style issues from lint + if: (startsWith(github.event.comment.body, 'bot fix style') || contains(toJSON(github.event.comment.body), '\nbot fix style')) + runs-on: ubuntu-latest + steps: + - id: user_permission + uses: actions-cool/check-user-permission@v2 + with: + require: 'write' + + - name: Add reaction + if: steps.user_permission.outputs.require-result == 'true' + run: | + gh api --method POST \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + /repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/pulls/comments/${{ github.event.comment.id }}/reactions \ + -f "content=rocket" + env: + GH_TOKEN: ${{ secrets.BOT_FIX_STYLE_TOKEN }} + + - name: cleanup + if: steps.user_permission.outputs.require-result == 'true' + run: | + find . -name . -o -prune -exec rm -rf -- {} + + + - uses: actions/checkout@v4 + if: steps.user_permission.outputs.require-result == 'true' + with: + token: ${{ secrets.BOT_FIX_STYLE_TOKEN }} + + - name: Checkout PR branch + if: steps.user_permission.outputs.require-result == 'true' + run: | + gh pr checkout ${{ github.event.pull_request.number }} + env: + GH_TOKEN: ${{ secrets.BOT_FIX_STYLE_TOKEN }} + + - name: install Python + if: steps.user_permission.outputs.require-result == 'true' + uses: actions/setup-python@v4 + with: + python-version: 3.8 + + - name: install elan + if: steps.user_permission.outputs.require-result == 'true' + 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}" + + # run the same linting steps as in lint_and_suggest_pr.yaml + + - name: lint + if: steps.user_permission.outputs.require-result == 'true' + run: | + lake exe lint-style --fix + + - name: Install bibtool + if: steps.user_permission.outputs.require-result == 'true' + run: | + sudo apt-get update + sudo apt-get install -y bibtool + + - name: lint references.bib + if: steps.user_permission.outputs.require-result == 'true' + run: | + # ignoring the return code allows the following `reviewdog` step to add GitHub suggestions + ./scripts/lint-bib.sh || true + + - name: update {Mathlib, Tactic, Counterexamples, Archive}.lean + if: steps.user_permission.outputs.require-result == 'true' + run: | + # ignoring the return code allows the following `reviewdog` step to add GitHub suggestions + lake exe mk_all || true + + - name: Commit and push changes + if: steps.user_permission.outputs.require-result == 'true' + run: | + # cleanup junk from build + rm elan-init + rm docs/references.bib.old + # setup commit and push + git config user.name "leanprover-community-mathlib4-bot" + git config user.email "leanprover-community-mathlib4-bot@users.noreply.github.com" + git add . + # Don't fail if there's nothing to commit + git commit -m "commit changes from style linters" || true + git push origin HEAD diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6bceb029713e4..c47cd306ed4da 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 build.yml.in 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 @@ -51,6 +52,17 @@ jobs: - name: Look for ignored files uses: credfeto/action-no-ignored-files@v1.1.0 + - name: "Check for Lean files with the executable bit set" + shell: bash + run: | + executable_files="$(find . -name '*.lean' -type f \( -perm -u=x -o -perm -g=x -o -perm -o=x \))" + if [[ -n "$executable_files" ]] + then + echo "ERROR: The following Lean files have the executable bit set." + echo "$executable_files" + exit 1 + fi + - name: install Python if: ${{ 'ubuntu-latest' == 'ubuntu-latest' }} uses: actions/setup-python@v5 @@ -64,9 +76,9 @@ jobs: ./elan-init -y --default-toolchain none echo "$HOME/.elan/bin" >> "${GITHUB_PATH}" - - name: "run style linters: Python ones and their Lean rewrite" + - name: "run style linters" run: | - ./scripts/lint-style.sh + lake exe lint-style - name: Install bibtool if: ${{ 'ubuntu-latest' == 'ubuntu-latest' }} @@ -78,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 @@ -139,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 @@ -158,8 +148,22 @@ jobs: - name: get cache id: get run: | - lake exe cache clean - lake exe cache get + 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" + + - 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 @@ -223,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: | @@ -283,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 }} @@ -296,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 @@ -326,7 +339,7 @@ jobs: - if: contains(steps.PR.outputs.pr_labels, 'auto-merge-after-CI') name: If `auto-merge-after-CI` is present, add a `bors merge` comment. - uses: GrantBirki/comment@v2.0.1 + uses: GrantBirki/comment@v2 with: token: ${{ secrets.AUTO_MERGE_TOKEN }} issue-number: ${{ steps.PR.outputs.number }} diff --git a/.github/workflows/build_fork.yml b/.github/workflows/build_fork.yml index 344c91f9a8747..c431ad5e7d2f2 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 build.yml.in 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 @@ -48,6 +49,17 @@ jobs: - name: Look for ignored files uses: credfeto/action-no-ignored-files@v1.1.0 + - name: "Check for Lean files with the executable bit set" + shell: bash + run: | + executable_files="$(find . -name '*.lean' -type f \( -perm -u=x -o -perm -g=x -o -perm -o=x \))" + if [[ -n "$executable_files" ]] + then + echo "ERROR: The following Lean files have the executable bit set." + echo "$executable_files" + exit 1 + fi + - name: install Python if: ${{ 'ubuntu-latest' == 'ubuntu-latest' }} uses: actions/setup-python@v5 @@ -61,9 +73,9 @@ jobs: ./elan-init -y --default-toolchain none echo "$HOME/.elan/bin" >> "${GITHUB_PATH}" - - name: "run style linters: Python ones and their Lean rewrite" + - name: "run style linters" run: | - ./scripts/lint-style.sh + lake exe lint-style - name: Install bibtool if: ${{ 'ubuntu-latest' == 'ubuntu-latest' }} @@ -75,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) @@ -136,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 @@ -155,8 +145,22 @@ jobs: - name: get cache id: get run: | - lake exe cache clean - lake exe cache get + 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" + + - 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 @@ -220,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: | @@ -280,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 }} @@ -293,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) @@ -323,7 +336,7 @@ jobs: - if: contains(steps.PR.outputs.pr_labels, 'auto-merge-after-CI') name: If `auto-merge-after-CI` is present, add a `bors merge` comment. - uses: GrantBirki/comment@v2.0.1 + uses: GrantBirki/comment@v2 with: token: ${{ secrets.AUTO_MERGE_TOKEN }} issue-number: ${{ steps.PR.outputs.number }} diff --git a/.github/workflows/dependent-issues.yml b/.github/workflows/dependent-issues.yml index 682c5311f52b0..9e0b3d2da4b71 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: @@ -18,7 +19,7 @@ jobs: check: runs-on: ubuntu-latest steps: - - uses: z0al/dependent-issues@v1 + - uses: z0al/dependent-issues@75d554cd9494b6e1766bc9d08a81c26444ad5c5a env: # (Required) The token to use to make API calls to GitHub. GITHUB_TOKEN: ${{ secrets.DEPENDENT_ISSUES_TOKEN }} diff --git a/.github/workflows/labels_from_comment.yml b/.github/workflows/labels_from_comment.yml index 5b62e2ce226d6..b40b8d4c4daf6 100644 --- a/.github/workflows/labels_from_comment.yml +++ b/.github/workflows/labels_from_comment.yml @@ -10,7 +10,7 @@ on: jobs: update-label: - if: github.event.issue.pull_request != null && (contains(github.event.comment.body, 'awaiting-author') || contains(github.event.comment.body, 'WIP')) + if: github.event.issue.pull_request && (contains(github.event.comment.body, 'awaiting-author') || contains(github.event.comment.body, 'WIP')) runs-on: ubuntu-latest steps: @@ -20,7 +20,7 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const { owner, repo, number: issue_number } = context.issue; - const commentLines = context.payload.comment.body.split('\r\n'); + const commentLines = context.payload.comment.body.split(/\r?\n/); const awaitingAuthor = commentLines.includes('awaiting-author'); const wip = commentLines.includes('WIP'); diff --git a/.github/workflows/lean4checker.yml b/.github/workflows/lean4checker.yml index 3152d364350df..8976cc19badb6 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: @@ -69,7 +70,7 @@ jobs: run: | git clone https://github.com/leanprover/lean4checker cd lean4checker - git checkout v4.11.0-rc1 + git checkout v4.13.0-rc3 # Now that the git hash is embedded in each olean, # we need to compile lean4checker on the same toolchain cp ../lean-toolchain . diff --git a/.github/workflows/lint_and_suggest_pr.yml b/.github/workflows/lint_and_suggest_pr.yml index 64f06540402cd..409e78ebc223e 100644 --- a/.github/workflows/lint_and_suggest_pr.yml +++ b/.github/workflows/lint_and_suggest_pr.yml @@ -28,30 +28,31 @@ jobs: ./elan-init -y --default-toolchain none echo "$HOME/.elan/bin" >> "${GITHUB_PATH}" + # if you update this step (or its dependencies), please also update them in bot_fix_style_comment.yaml - name: lint - continue-on-error: true # allows the following `reviewdog` step to add GitHub suggestions run: | - ./scripts/lint-style.sh --fix + lake exe lint-style --fix - name: suggester / lint-style uses: reviewdog/action-suggester@v1 with: - tool_name: lint-style + tool_name: lint-style (comment with "bot fix style" to have the bot commit all style suggestions) - name: Install bibtool run: | sudo apt-get update sudo apt-get install -y bibtool + # if you update this step (or its dependencies), please also update them in bot_fix_style_comment.yaml - name: lint references.bib - continue-on-error: true # allows the following `reviewdog` step to add GitHub suggestions run: | - ./scripts/lint-bib.sh + # ignoring the return code allows the following `reviewdog` step to add GitHub suggestions + ./scripts/lint-bib.sh || true - name: suggester / lint-bib uses: reviewdog/action-suggester@v1 with: - tool_name: lint-bib + tool_name: lint-bib (comment with "bot fix style" to have the bot commit all style suggestions) check_imported: if: github.repository == 'leanprover-community/mathlib4' && github.event.pull_request.draft == false @@ -71,11 +72,13 @@ jobs: ./elan-init -y --default-toolchain none echo "$HOME/.elan/bin" >> "${GITHUB_PATH}" + # if you update this step (or its dependencies), please also update them in bot_fix_style_comment.yaml - name: update {Mathlib, Tactic, Counterexamples, Archive}.lean - continue-on-error: true # allows the following `reviewdog` step to add GitHub suggestions - run: lake exe mk_all + run: + # ignoring the return code allows the following `reviewdog` step to add GitHub suggestions + lake exe mk_all || true - name: suggester / import list uses: reviewdog/action-suggester@v1 with: - tool_name: imports + tool_name: imports (comment with "bot fix style" to have the bot commit all style suggestions) diff --git a/.github/workflows/maintainer_merge_comment.yml b/.github/workflows/maintainer_merge_comment.yml index 61d41d9ac1375..db769c6592ab6 100644 --- a/.github/workflows/maintainer_merge_comment.yml +++ b/.github/workflows/maintainer_merge_comment.yml @@ -7,7 +7,7 @@ on: jobs: ping_zulip: name: Ping maintainers on Zulip - if: (github.event.issue.pull_request != 'null') && (startsWith(github.event.comment.body, 'maintainer merge') || contains(toJSON(github.event.comment.body), '\nmaintainer merge')) + if: github.event.issue.pull_request && (startsWith(github.event.comment.body, 'maintainer merge') || contains(toJSON(github.event.comment.body), '\nmaintainer merge')) runs-on: ubuntu-latest steps: - name: Check whether user is part of mathlib-reviewers team @@ -20,6 +20,17 @@ jobs: # This feature is only applicable in an issue (or PR) context exit: true # optional. If the action should exit if the user is not part of the team. Defaults to true. + - uses: actions/checkout@v4 + with: + ref: master + - name: Determine Zulip topic + id: determine_topic + run: | + ./scripts/get_tlabel.sh "${PR}" >> "$GITHUB_OUTPUT" + env: + PR: /repos/leanprover-community/mathlib4/issues/${{ github.event.issue.number }} + GH_TOKEN: ${{secrets.GITHUB_TOKEN}} + - name: Send message on Zulip uses: zulip/github-actions-zulip/send-message@v1 with: @@ -28,14 +39,14 @@ jobs: organization-url: 'https://leanprover.zulipchat.com' to: 'mathlib reviewers' type: 'stream' - topic: 'maintainer merge' + topic: ${{ steps.determine_topic.outputs.topic }} content: | ${{ format('{0} requested a maintainer merge from comment on PR [#{1}]({2}):', github.event.comment.user.login, github.event.issue.number, github.event.issue.html_url ) }} > ${{ github.event.issue.title }} - name: Add comment to PR - uses: GrantBirki/comment@v2.0.1 + uses: GrantBirki/comment@v2 with: issue-number: ${{ github.event.issue.number }} body: | diff --git a/.github/workflows/maintainer_merge_review.yml b/.github/workflows/maintainer_merge_review.yml index aaefc4ecbdcb2..c7d8357bbfa64 100644 --- a/.github/workflows/maintainer_merge_review.yml +++ b/.github/workflows/maintainer_merge_review.yml @@ -19,6 +19,17 @@ jobs: token: ${{ secrets.MATHLIB_REVIEWERS_TEAM_KEY }} # required. Personal Access Token with the `read:org` permission exit: true # optional. If the action should exit if the user is not part of the team. Defaults to true. + - uses: actions/checkout@v4 + with: + ref: master + - name: Determine Zulip topic + id: determine_topic + run: | + ./scripts/get_tlabel.sh "${PR}" >> "$GITHUB_OUTPUT" + env: + PR: /repos/leanprover-community/mathlib4/issues/${{ github.event.pull_request.number }} + GH_TOKEN: ${{secrets.GITHUB_TOKEN}} + - name: Send message on Zulip uses: zulip/github-actions-zulip/send-message@v1 with: @@ -27,14 +38,14 @@ jobs: organization-url: 'https://leanprover.zulipchat.com' to: 'mathlib reviewers' type: 'stream' - topic: 'maintainer merge' + topic: ${{ steps.determine_topic.outputs.topic }} content: | ${{ format('{0} requested a maintainer merge from review on PR [#{1}]({2}):', github.event.review.user.login, github.event.pull_request.number, github.event.pull_request.html_url ) }} > ${{ github.event.pull_request.title }} - name: Add comment to PR - uses: GrantBirki/comment@v2.0.1 + uses: GrantBirki/comment@v2 with: issue-number: ${{ github.event.pull_request.number }} body: | diff --git a/.github/workflows/maintainer_merge_review_comment.yml b/.github/workflows/maintainer_merge_review_comment.yml index 48ccc466ac1ea..79a5ea176d9d9 100644 --- a/.github/workflows/maintainer_merge_review_comment.yml +++ b/.github/workflows/maintainer_merge_review_comment.yml @@ -18,6 +18,17 @@ jobs: token: ${{ secrets.MATHLIB_REVIEWERS_TEAM_KEY }} # required. Personal Access Token with the `read:org` permission exit: true # optional. If the action should exit if the user is not part of the team. Defaults to true. + - uses: actions/checkout@v4 + with: + ref: master + - name: Determine Zulip topic + id: determine_topic + run: | + ./scripts/get_tlabel.sh "${PR}" >> "$GITHUB_OUTPUT" + env: + PR: /repos/leanprover-community/mathlib4/issues/${{ github.event.pull_request.number }} + GH_TOKEN: ${{secrets.GITHUB_TOKEN}} + - name: Send message on Zulip uses: zulip/github-actions-zulip/send-message@v1 with: @@ -26,14 +37,14 @@ jobs: organization-url: 'https://leanprover.zulipchat.com' to: 'mathlib reviewers' type: 'stream' - topic: 'maintainer merge' + topic: ${{ steps.determine_topic.outputs.topic }} content: | ${{ format('{0} requested a maintainer merge from review comment on PR [#{1}]({2}):', github.event.comment.user.login, github.event.pull_request.number, github.event.pull_request.html_url ) }} > ${{ github.event.pull_request.title }} - name: Add comment to PR - uses: GrantBirki/comment@v2.0.1 + uses: GrantBirki/comment@v2 with: issue-number: ${{ github.event.pull_request.number }} body: | 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 96cf301b33a26..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 build.yml.in 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,8 @@ include() { s/MAIN_OR_FORK/$3/g; s/JOB_NAME/$4/g; s/STYLE_LINT_RUNNER/$5/g; - " build.yml.in + /^### NB/d + " ../build.in.yml } build_yml > build.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 2b430940e7fa4..25835698e99ab 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' }} @@ -50,9 +51,10 @@ jobs: git tag "nightly-testing-${version}" git push origin "nightly-testing-${version}" hash="$(git rev-parse "nightly-testing-${version}")" - printf 'SHA=%s\n' "${hash}" >> "${GITHUB_ENV}" curl -X POST "http://speed.lean-fro.org/mathlib4/api/queue/commit/e7b27246-a3e6-496a-b552-ff4b45c7236e/$hash" -u "admin:${{ secrets.SPEED }}" fi + hash="$(git rev-parse "nightly-testing-${version}")" + printf 'SHA=%s\n' "${hash}" >> "${GITHUB_ENV}" else echo "Error: The file lean-toolchain does not contain the expected pattern." exit 1 @@ -209,26 +211,15 @@ 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" - # Only post if the message is different - # We compare the first 160 characters, since that includes the date and bump version - if not messages or messages[0]['content'][:160] != payload[:160]: - # Log messages, because the bot seems to repeat itself... - if messages: - print("###### Last message:") - print(messages[0]['content']) - print("###### Current message:") - print(payload) - else: - print('The strings match!') - # Post the reminder message - request = { - 'type': 'stream', - 'to': 'nightly-testing', - 'topic': 'Mathlib bump branch reminders', - 'content': payload - } - result = client.send_message(request) - print(result) + payload += f"```bash\n./scripts/create-adaptation-pr.sh --bumpversion={bump_branch_suffix} --nightlydate={current_version} --nightlysha={sha}\n```\n" + # Post the reminder message + request = { + 'type': 'stream', + 'to': 'nightly-testing', + 'topic': 'Mathlib bump branch reminders', + 'content': payload + } + result = client.send_message(request) + print(result) else: print('No action needed.') 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 ed9b666b0d7eb..847e24854e855 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: @@ -25,6 +26,9 @@ jobs: echo "$HOME/.elan/bin" >> "${GITHUB_PATH}" - uses: actions/checkout@v4 + with: + ## fetch the whole repository, as we want to push to it later + fetch-depth: 0 - name: print lean and lake versions run: | @@ -53,15 +57,14 @@ jobs: run: | bash -o pipefail -c "env LEAN_ABORT_ON_PANIC=1 lake build --wfail -KCI" - - name: update nolints.json and style-exceptions.txt + - name: update nolints.json shell: bash run: | env LEAN_ABORT_ON_PANIC=1 lake exe runLinter --update Mathlib - lake exe lint-style --update - name: configure git setup run: | - git remote add origin-bot "https://leanprover-community-bot:${{ secrets.UPDATE_NOLINTS_TOKEN }}@github.com/leanprover-community/mathlib.git" + git remote add origin-bot "https://leanprover-community-bot:${{ secrets.UPDATE_NOLINTS_TOKEN }}@github.com/leanprover-community/mathlib4.git" git config user.email "leanprover.community@gmail.com" git config user.name "leanprover-community-bot" @@ -70,7 +73,7 @@ jobs: # github using a different username. git config --unset http.https://github.com/.extraheader - - name: file a new PR to update nolints.json and style-exceptions.txt + - name: file a new PR to update nolints.json run: ./scripts/update_nolints_CI.sh env: DEPLOY_GITHUB_TOKEN: ${{ secrets.UPDATE_NOLINTS_TOKEN }} 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 885bef03a2be2..b415c88c6a8c8 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: @@ -19,25 +20,46 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - token: "${{ secrets.NIGHTLY_TESTING }}" + token: "${{ secrets.UPDATE_DEPENDENCIES_TOKEN }}" + + - name: Get sha of branch + id: sha + run: | + echo "sha=$(git rev-parse --verify origin/update-dependencies-bot-use-only)" >> "$GITHUB_OUTPUT" + + - name: Get PR and labels + if: ${{ steps.sha.outputs.sha }} + id: PR # all the steps below are skipped if 'ready-to-merge' is in the list of labels found here + 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: + github-token: ${{ secrets.GITHUB_TOKEN }} + sha: ${{ steps.sha.outputs.sha }} + # Only return if PR is still open + filterOutClosed: true - name: Configure Git User + if: ${{ !contains(steps.PR.outputs.pr_labels, 'ready-to-merge') }} run: | git config user.name "leanprover-community-mathlib4-bot" git config user.email "leanprover-community-mathlib4-bot@users.noreply.github.com" - name: Update dependencies + if: ${{ !contains(steps.PR.outputs.pr_labels, 'ready-to-merge') }} run: lake update - name: Generate PR title + if: ${{ !contains(steps.PR.outputs.pr_labels, 'ready-to-merge') }} run: | echo "timestamp=$(date -u +"%Y-%m-%d-%H-%M")" >> "$GITHUB_ENV" echo "pr_title=chore: update Mathlib dependencies $(date -u +"%Y-%m-%d")" >> "$GITHUB_ENV" - name: Create Pull Request + if: ${{ !contains(steps.PR.outputs.pr_labels, 'ready-to-merge') }} uses: peter-evans/create-pull-request@v6 with: - token: "${{ secrets.NIGHTLY_TESTING }}" + token: "${{ secrets.UPDATE_DEPENDENCIES_TOKEN }}" commit-message: "chore: update Mathlib dependencies ${{ env.timestamp }}" # this branch is referenced in update_dependencies_zulip.yml branch: "update-dependencies-bot-use-only" diff --git a/.github/workflows/update_dependencies_zulip.yml b/.github/workflows/update_dependencies_zulip.yml index 466b06668f31f..f4e72b01d7034 100644 --- a/.github/workflows/update_dependencies_zulip.yml +++ b/.github/workflows/update_dependencies_zulip.yml @@ -1,7 +1,5 @@ name: Monitor Dependency Update Failures -# This action currently uses the NIGHTLY_TESTING secret, but could be moved to a separate secret. - on: workflow_run: workflows: ["continuous integration"] @@ -20,7 +18,7 @@ jobs: uses: actions/github-script@v7 id: construct_message with: - github-token: ${{ secrets.NIGHTLY_TESTING }} + github-token: ${{ secrets.UPDATE_DEPENDENCIES_TOKEN }} result-encoding: string script: | const owner = context.repo.owner, repo = context.repo.repo; @@ -42,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 df1f30db3e121..2804883c9b27e 100644 --- a/Archive.lean +++ b/Archive.lean @@ -9,6 +9,7 @@ import Archive.Imo.Imo1959Q1 import Archive.Imo.Imo1959Q2 import Archive.Imo.Imo1960Q1 import Archive.Imo.Imo1960Q2 +import Archive.Imo.Imo1961Q3 import Archive.Imo.Imo1962Q1 import Archive.Imo.Imo1962Q4 import Archive.Imo.Imo1964Q1 diff --git a/Archive/Arithcc.lean b/Archive/Arithcc.lean index 45f394d134fee..7f9601849cfa4 100644 --- a/Archive/Arithcc.lean +++ b/Archive/Arithcc.lean @@ -3,7 +3,6 @@ Copyright (c) 2020 Xi Wang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Xi Wang -/ -import Mathlib.Init.Data.Nat.Lemmas import Mathlib.Data.Nat.Defs import Mathlib.Order.Basic import Mathlib.Tactic.Common @@ -145,9 +144,9 @@ def outcome : List Instruction → State → State @[simp] theorem outcome_append (p₁ p₂ : List Instruction) (η : State) : outcome (p₁ ++ p₂) η = outcome p₂ (outcome p₁ η) := by - revert η - induction' p₁ with _ _ p₁_ih <;> intros <;> simp - apply p₁_ih + induction p₁ generalizing η with + | nil => simp + | cons _ _ p₁_ih => simp [p₁_ih] end Target @@ -280,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 38de9bc64bc79..30ac2f21636cd 100644 --- a/Archive/Examples/IfNormalization/Result.lean +++ b/Archive/Examples/IfNormalization/Result.lean @@ -15,8 +15,6 @@ import Mathlib.Tactic.Recall See `Statement.lean` for background. -/ -set_option autoImplicit true - macro "◾" : tactic => `(tactic| aesop) macro "◾" : term => `(term| by aesop) @@ -30,17 +28,19 @@ attribute [local simp] normalized hasNestedIf hasConstantIf hasRedundantIf disjo attribute [local simp] apply_ite ite_eq_iff' +variable {b : Bool} {f : ℕ → Bool} {i : ℕ} {t e : IfExpr} + /-! Simp lemmas for `eval`. We don't want a `simp` lemma for `(ite i t e).eval` in general, only once we know the shape of `i`. -/ -@[simp] theorem eval_lit : (lit b).eval f = b := rfl -@[simp] theorem eval_var : (var i).eval f = f i := rfl +@[simp] theorem eval_lit : (lit b).eval f = b := rfl +@[simp] theorem eval_var : (var i).eval f = f i := rfl @[simp] theorem eval_ite_lit : (ite (.lit b) t e).eval f = bif b then t.eval f else e.eval f := rfl @[simp] theorem eval_ite_var : (ite (.var i) t e).eval f = bif f i then t.eval f else e.eval f := rfl -@[simp] theorem eval_ite_ite : +@[simp] theorem eval_ite_ite {a b c d e : IfExpr} : (ite (ite a b c) d e).eval f = (ite a (ite b d e) (ite c d e)).eval f := by cases h : eval f a <;> simp_all [eval] @@ -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 88aa07ae46917..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 @@ -17,14 +17,12 @@ In this variant we eschew the use of `aesop`, and instead write out the proofs. we put primes on the declarations in the file.) -/ -set_option autoImplicit true - namespace IfExpr attribute [local simp] eval normalized hasNestedIf hasConstantIf hasRedundantIf disjoint vars List.disjoint max_add_add_right max_mul_mul_left Nat.lt_add_one_iff le_add_of_le_right -theorem eval_ite_ite' : +theorem eval_ite_ite' {a b c d e : IfExpr} {f : ℕ → Bool} : (ite (ite a b c) d e).eval f = (ite a (ite b d e) (ite c d e)).eval f := by cases h : eval f a <;> simp_all @@ -38,7 +36,7 @@ theorem eval_ite_ite' : `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⟩ @@ -94,22 +92,20 @@ 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, imp_false] + 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' simp_all - · simp_all? says simp_all only [hasNestedIf, Bool.or_self, hasConstantIf, and_self, - hasRedundantIf, Bool.or_false, beq_eq_false_iff_ne, ne_eq, not_false_eq_true, - disjoint, List.disjoint, decide_True, Bool.and_self] + · simp_all · have := ht₃ w 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..a19f23f8431d4 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 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/Imo1959Q2.lean b/Archive/Imo/Imo1959Q2.lean index 2af72963993eb..0325f5e80b580 100644 --- a/Archive/Imo/Imo1959Q2.lean +++ b/Archive/Imo/Imo1959Q2.lean @@ -93,7 +93,7 @@ theorem isGood_iff_of_sqrt_two_lt (hA : sqrt 2 < A) : IsGood x A ↔ x = (A / 2) constructor · intro h have hx : 1 < x := by rwa [h.sqrt_two_lt_iff_one_lt] at hA - rw [isGood_iff_eq_sqrt hx, eq_comm, sqrt_eq_iff_sq_eq] at h <;> linarith + rw [isGood_iff_eq_sqrt hx, eq_comm, sqrt_eq_iff_eq_sq] at h <;> linarith · rintro rfl rw [isGood_iff_eq_sqrt] · conv_lhs => rw [← sqrt_sq this.le] diff --git a/Archive/Imo/Imo1960Q2.lean b/Archive/Imo/Imo1960Q2.lean index 577c0adeee430..60faf4c5c5d66 100644 --- a/Archive/Imo/Imo1960Q2.lean +++ b/Archive/Imo/Imo1960Q2.lean @@ -51,7 +51,7 @@ theorem isGood_iff {x} : IsGood x ↔ x ∈ Ico (-1/2) (45/8) \ {0} := by -- Now, if `x ≥ -1/2`, `x ≠ 0`, then the expression is well-defined. have hx2' : 0 ≤ 2 * x + 1 := by linarith have H : 1 - sqrt (2 * x + 1) ≠ 0 := by - rw [sub_ne_zero, ne_comm, ne_eq, sqrt_eq_iff_sq_eq hx2' zero_le_one] + rw [sub_ne_zero, ne_comm, ne_eq, sqrt_eq_iff_eq_sq hx2' zero_le_one] simpa calc -- Note that the fraction in the LHS is equal to `(1 + sqrt (2 * x + 1)) ^ 2` diff --git a/Archive/Imo/Imo1961Q3.lean b/Archive/Imo/Imo1961Q3.lean new file mode 100644 index 0000000000000..0651cf539ec5f --- /dev/null +++ b/Archive/Imo/Imo1961Q3.lean @@ -0,0 +1,74 @@ +/- +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.Analysis.SpecialFunctions.Trigonometric.Complex + +/-! +# IMO 1961 Q3 + +Solve the equation + +$\cos^n x - \sin^n x = 1$, + +where $n$ is a given positive integer. + +The solution is based on the one at the +[Art of Problem Solving](https://artofproblemsolving.com/wiki/index.php/1961_IMO_Problems/Problem_3) +website. +-/ + +open Real + +theorem Imo1961Q3 {n : ℕ} {x : ℝ} (h₀ : n ≠ 0) : + (cos x) ^ n - (sin x) ^ n = 1 ↔ + (∃ k : ℤ, k * π = x) ∧ Even n ∨ (∃ k : ℤ, k * (2 * π) = x) ∧ Odd n ∨ + (∃ k : ℤ, -(π / 2) + k * (2 * π) = x) ∧ Odd n := by + constructor + · intro h + rcases eq_or_ne (sin x) 0 with hsinx | hsinx + · rw [hsinx, zero_pow h₀, sub_zero, pow_eq_one_iff_of_ne_zero h₀, cos_eq_one_iff, + cos_eq_neg_one_iff] at h + rcases h with ⟨k, rfl⟩ | ⟨⟨k, rfl⟩, hn⟩ + · cases n.even_or_odd with + | inl hn => refine .inl ⟨⟨k * 2, ?_⟩, hn⟩; simp [mul_assoc] + | inr hn => exact .inr <| .inl ⟨⟨_, rfl⟩, hn⟩ + · exact .inl ⟨⟨2 * k + 1, by push_cast; ring⟩, hn⟩ + · rcases eq_or_ne (cos x) 0 with hcosx | hcosx + · right; right + rw [hcosx, zero_pow h₀, zero_sub, ← neg_inj, neg_neg, pow_eq_neg_one_iff, + sin_eq_neg_one_iff] at h + simpa only [eq_comm] using h + · have hcos1 : |cos x| < 1 := by + rw [abs_cos_eq_sqrt_one_sub_sin_sq, sqrt_lt' one_pos] + simp [sq_pos_of_ne_zero hsinx] + have hsin1 : |sin x| < 1 := by + rw [abs_sin_eq_sqrt_one_sub_cos_sq, sqrt_lt' one_pos] + simp [sq_pos_of_ne_zero hcosx] + match n with + | 1 => + rw [pow_one, pow_one, sub_eq_iff_eq_add] at h + have : 2 * sin x * cos x = 0 := by + simpa [h, add_sq, add_assoc, ← two_mul, mul_add, mul_assoc, ← sq] + using cos_sq_add_sin_sq x + simp [hsinx, hcosx] at this + | 2 => + rw [← cos_sq_add_sin_sq x, sub_eq_add_neg, add_right_inj, neg_eq_self ℝ] at h + exact absurd (pow_eq_zero h) hsinx + | (n + 1 + 2) => + set m := n + 1 + refine absurd ?_ h.not_lt + calc + (cos x) ^ (m + 2) - (sin x) ^ (m + 2) ≤ |cos x| ^ (m + 2) + |sin x| ^ (m + 2) := by + simp only [← abs_pow, sub_eq_add_neg] + gcongr + exacts [le_abs_self _, neg_le_abs _] + _ = |cos x| ^ m * cos x ^ 2 + |sin x| ^ m * sin x ^ 2 := by simp [pow_add] + _ < 1 ^ m * cos x ^ 2 + 1 ^ m * sin x ^ 2 := by gcongr + _ = 1 := by simp + · rintro (⟨⟨k, rfl⟩, hn⟩ | ⟨⟨k, rfl⟩, -⟩ | ⟨⟨k, rfl⟩, hn⟩) + · rw [sin_int_mul_pi, zero_pow h₀, sub_zero, ← hn.pow_abs, abs_cos_int_mul_pi, one_pow] + · have : sin (k * (2 * π)) = 0 := by simpa [mul_assoc] using sin_int_mul_pi (k * 2) + simp [h₀, this] + · simp [hn.neg_pow, h₀] 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 288c9e77dabdf..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₂`. @@ -58,7 +58,7 @@ theorem imo1972_q5 (f g : ℝ → ℝ) (hf1 : ∀ x, ∀ y, f (x + y) + f (x - y have h₁ : ∃ x : ℝ, x ∈ S := by use ‖f 0‖; exact Set.mem_range_self 0 have h₂ : ∀ x, ‖f x‖ ≤ k' := by intro x - rw [le_div_iff] + rw [le_div_iff₀] · apply (mul_le_mul_left zero_lt_two).mp (hk₂ x) · exact zero_lt_one.trans hneg apply csSup_le h₁ @@ -87,12 +87,12 @@ 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 suffices 2 * (‖f x‖ * ‖g y‖) ≤ 2 * k by - rwa [le_div_iff hgy, ← mul_le_mul_left (zero_lt_two : (0 : ℝ) < 2)] + rwa [le_div_iff₀ hgy, ← mul_le_mul_left (zero_lt_two : (0 : ℝ) < 2)] calc 2 * (‖f x‖ * ‖g y‖) = ‖2 * f x * g y‖ := by simp [abs_mul, mul_assoc] _ = ‖f (x + y) + f (x - y)‖ := by rw [hf1] diff --git a/Archive/Imo/Imo1986Q5.lean b/Archive/Imo/Imo1986Q5.lean index 9c265680eb14f..82fe5961c1647 100644 --- a/Archive/Imo/Imo1986Q5.lean +++ b/Archive/Imo/Imo1986Q5.lean @@ -26,7 +26,7 @@ Formalization is based on with minor modifications. -/ -open Set NNReal Classical +open NNReal namespace Imo1986Q5 @@ -51,12 +51,12 @@ theorem map_eq_zero : f x = 0 ↔ 2 ≤ x := by theorem map_ne_zero_iff : f x ≠ 0 ↔ x < 2 := by simp [hf.map_eq_zero] theorem map_of_lt_two (hx : x < 2) : f x = 2 / (2 - x) := by - have hx' : 2 - x ≠ 0 := (tsub_pos_of_lt hx).ne' + 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 [NNReal.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 [NNReal.div_le_iff' hx', ← hf.map_eq_zero] + · rw [div_le_iff₀' hx', ← hf.map_eq_zero] refine (mul_eq_zero.1 ?_).resolve_right hfx rw [hf.map_add_rev, hf.map_eq_zero, tsub_add_cancel_of_le hx.le] diff --git a/Archive/Imo/Imo1987Q1.lean b/Archive/Imo/Imo1987Q1.lean index 717900655234a..d10995da9a7a4 100644 --- a/Archive/Imo/Imo1987Q1.lean +++ b/Archive/Imo/Imo1987Q1.lean @@ -46,8 +46,10 @@ 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 [card_congr (fixedPointsEquiv α), card_perm, Finset.filter_not, Finset.card_sdiff, - Finset.filter_eq', Finset.card_univ] + simp only [card_congr (fixedPointsEquiv α), card_sigma, card_perm] + 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/Imo1988Q6.lean b/Archive/Imo/Imo1988Q6.lean index 290391027845f..b2790eea1cb9d 100644 --- a/Archive/Imo/Imo1988Q6.lean +++ b/Archive/Imo/Imo1988Q6.lean @@ -45,7 +45,7 @@ under the following conditions: with `x < y` then there exists a “smaller” point on `H`: a point `(x',y')` with `x' < y' ≤ x`. For reasons of usability, the hyperbola `H` is implemented as an arbitrary predicate. -(In question 6 of IMO1988, where this proof technique was first developped, +(In question 6 of IMO1988, where this proof technique was first developed, the predicate `claim` would be `∃ (d : ℕ), d ^ 2 = k` for some natural number `k`, and the predicate `H` would be `fun a b ↦ a * a + b * b = (a * b + 1) * k`.) diff --git a/Archive/Imo/Imo1994Q1.lean b/Archive/Imo/Imo1994Q1.lean index e8d62532d713d..6ea9e04e8862f 100644 --- a/Archive/Imo/Imo1994Q1.lean +++ b/Archive/Imo/Imo1994Q1.lean @@ -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..367aec35fd5fc 100644 --- a/Archive/Imo/Imo1998Q2.lean +++ b/Archive/Imo/Imo1998Q2.lean @@ -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/Imo2006Q3.lean b/Archive/Imo/Imo2006Q3.lean index b774659da30e3..94b15273531b6 100644 --- a/Archive/Imo/Imo2006Q3.lean +++ b/Archive/Imo/Imo2006Q3.lean @@ -42,7 +42,7 @@ theorem lhs_ineq {x y : ℝ} (hxy : 0 ≤ x * y) : theorem four_pow_four_pos : (0 : ℝ) < 4 ^ 4 := by norm_num theorem mid_ineq {s t : ℝ} : s * t ^ 3 ≤ (3 * t + s) ^ 4 / 4 ^ 4 := by - rw [le_div_iff four_pow_four_pos] + rw [le_div_iff₀ four_pow_four_pos] have : 0 ≤ (s - t) ^ 2 * ((s + 7 * t) ^ 2 + 2 * (4 * t) ^ 2) := by positivity linarith @@ -78,7 +78,7 @@ theorem subst_wlog {x y z s : ℝ} (hxy : 0 ≤ x * y) (hxyz : x + y + z = 0) : theorem subst_proof₁ (x y z s : ℝ) (hxyz : x + y + z = 0) : |x * y * z * s| ≤ sqrt 2 / 32 * (x ^ 2 + y ^ 2 + z ^ 2 + s ^ 2) ^ 2 := by wlog h' : 0 ≤ x * y generalizing x y z; swap - · rw [div_mul_eq_mul_div, le_div_iff' zero_lt_32] + · rw [div_mul_eq_mul_div, le_div_iff₀' zero_lt_32] exact subst_wlog h' hxyz cases' (mul_nonneg_of_three x y z).resolve_left h' with h h · convert this y z x _ h using 2 <;> linarith @@ -103,7 +103,7 @@ theorem proof₂ (M : ℝ) let c := 2 + 3 * α calc _ = 18 ^ 2 * 2 * α / 48 ^ 2 := by ring _ ≤ M := ?_ - rw [div_le_iff (by positivity)] + rw [div_le_iff₀ (by positivity)] calc 18 ^ 2 * 2 * α = 18 ^ 2 * α ^ 2 * α := by linear_combination -324 * α * hα _ = abs (-(18 ^ 2 * α ^ 2 * α)) := by rw [abs_neg, abs_of_nonneg]; positivity 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/Imo2011Q5.lean b/Archive/Imo/Imo2011Q5.lean index 8d7639aea087f..2fdc4ed7d8394 100644 --- a/Archive/Imo/Imo2011Q5.lean +++ b/Archive/Imo/Imo2011Q5.lean @@ -12,9 +12,9 @@ import Mathlib.Algebra.Ring.Int Let `f` be a function from the set of integers to the set of positive integers. Suppose that, for any two integers -`m` and `n`, the difference `f(m) - f(n)` is divisible by -`f(m - n)`. Prove that, for all integers `m` and `n` with -`f(m) ≤ f(n)`, the number `f(n)` is divisible by `f(m)`. +`m` and `n`, the difference `f m - f n` is divisible by +`f (m - n)`. Prove that, for all integers `m` and `n` with +`f m ≤ f n`, the number `f n` is divisible by `f m`. -/ diff --git a/Archive/Imo/Imo2013Q5.lean b/Archive/Imo/Imo2013Q5.lean index 20cccc01e5ed8..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 @@ -58,7 +58,7 @@ theorem le_of_all_pow_lt_succ {x y : ℝ} (hx : 1 < x) (hy : 1 < y) _ ≤ x ^ N - y ^ N := hn N hNp linarith [h N hNp] -/-- Like `le_of_all_pow_lt_succ`, but with a weaker assumption for y. +/-- Like `le_of_all_pow_lt_succ`, but with a weaker assumption for `y`. -/ theorem le_of_all_pow_lt_succ' {x y : ℝ} (hx : 1 < x) (hy : 0 < y) (h : ∀ n : ℕ, 0 < n → x ^ n - 1 < y ^ n) : 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 @@ -234,15 +234,14 @@ theorem imo2013_q5 (f : ℚ → ℝ) (H1 : ∀ x y, 0 < x → 0 < y → f (x * y have H : x * (↑(2 * x.den) : ℚ) = (↑(2 * x.num) : ℚ) := by push_cast; linear_combination 2 * H₀ set x2denom := 2 * x.den set x2num := 2 * x.num - have := x.pos have hx2pos : 0 < 2 * x.den := by positivity have hx2cnezr : (x2denom : ℝ) ≠ (0 : ℝ) := by positivity have : 0 < x.num := by rwa [Rat.num_pos] have hx2num_gt_one : (1 : ℚ) < (2 * x.num : ℤ) := by norm_cast; linarith apply mul_left_cancel₀ hx2cnezr calc - x2denom * f x = f (x2denom * x) := - (h_f_commutes_with_pos_nat_mul x2denom hx2pos x hx).symm + x2denom * f x + = f (x2denom * x) := (h_f_commutes_with_pos_nat_mul x2denom hx2pos x hx).symm _ = f x2num := by congr; linear_combination H _ = x2num := fixed_point_of_gt_1 hx2num_gt_one H1 H2 H4 H5 ha1 hae _ = ((x2num : ℚ) : ℝ) := by norm_cast 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/Imo2021Q1.lean b/Archive/Imo/Imo2021Q1.lean index 8cb685761f6bb..051bea2e28ac9 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) ∧ + (∀ 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 + 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 cf6f08b6fa937..00575c6abc94a 100644 --- a/Archive/Imo/Imo2024Q1.lean +++ b/Archive/Imo/Imo2024Q1.lean @@ -8,6 +8,7 @@ import Mathlib.Algebra.BigOperators.Ring import Mathlib.Algebra.Order.ToIntervalMod import Mathlib.Data.Real.Archimedean import Mathlib.Tactic.Peel +import Mathlib.Tactic.Recall /-! # IMO 2024 Q1 @@ -19,9 +20,9 @@ Determine all real numbers $\alpha$ such that, for every positive integer $n$, t is a multiple of~$n$. We follow Solution 3 from the -[official solutions](https://www.imo2024.uk/s/IMO-2024-Paper-1-Solutions.pdf). First reducing -modulo 2, any answer that is not a multiple of 2 is inductively shown to be contained in a -decreasing sequence of intervals, with empty intersection. +[official solutions](https://www.imo2024.uk/s/IMO-2024-Paper-1-Solutions.pdf). +First reducing modulo 2, any answer that is not a multiple of 2 is inductively shown to be +contained in a decreasing sequence of intervals, with empty intersection. -/ @@ -30,6 +31,9 @@ namespace Imo2024Q1 /-- The condition of the problem. -/ def Condition (α : ℝ) : Prop := (∀ n : ℕ, 0 < n → (n : ℤ) ∣ ∑ i ∈ Finset.Icc 1 n, ⌊i * α⌋) +/-- This is to be determined by the solver of the original problem. -/ +def solutionSet : Set ℝ := {α : ℝ | ∃ m : ℤ, α = 2 * m} + lemma condition_two_mul_int (m : ℤ) : Condition (2 * m) := by rintro n - suffices (n : ℤ) ∣ ∑ i ∈ Finset.Icc 0 n, ⌊((i * (2 * m) : ℤ) : ℝ)⌋ by @@ -37,14 +41,13 @@ lemma condition_two_mul_int (m : ℤ) : Condition (2 * m) := by exact_mod_cast this simp_rw [Int.floor_intCast, ← Finset.sum_mul, ← Nat.Ico_succ_right, ← Finset.range_eq_Ico, ← mul_assoc] - refine dvd_mul_of_dvd_left ?_ _ + apply dvd_mul_of_dvd_left rw [← Nat.cast_sum, ← Nat.cast_ofNat (n := 2), ← Nat.cast_mul, Finset.sum_range_id_mul_two] simp lemma condition_sub_two_mul_int_iff {α : ℝ} (m : ℤ) : Condition (α - 2 * m) ↔ Condition α := by - unfold Condition peel with n hn - refine dvd_iff_dvd_of_dvd_sub ?_ + apply dvd_iff_dvd_of_dvd_sub simp_rw [← Finset.sum_sub_distrib, mul_sub] norm_cast simp_rw [Int.floor_sub_int, sub_sub_cancel_left] @@ -68,32 +71,32 @@ 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 - replace hc := hc ⌈α⁻¹⌉₊ (zero_lt_one.trans hr) - refine hr.ne' ?_ + exact_mod_cast (one_lt_inv₀ h0).2 hn + apply hr.ne' suffices ⌈α⁻¹⌉₊ = (1 : ℤ) from mod_cast this - refine Int.eq_one_of_dvd_one (Int.zero_le_ofNat _) ?_ - convert hc + apply Int.eq_one_of_dvd_one (Int.zero_le_ofNat _) + convert hc ⌈α⁻¹⌉₊ (zero_lt_one.trans hr) rw [← Finset.add_sum_Ico_eq_sum_Icc hr.le] convert (add_zero _).symm · rw [Int.floor_eq_iff] - refine ⟨?_, ?_⟩ + constructor · rw [Int.cast_one] calc 1 ≤ α⁻¹ * α := by simp [h0.ne'] - _ ≤ ⌈α⁻¹⌉₊ * α := by gcongr; exact Nat.le_ceil _ - · calc ⌈α⁻¹⌉₊ * α < (α⁻¹ + 1) * α := by gcongr; exact Nat.ceil_lt_add_one (inv_nonneg.2 h0.le) + _ ≤ ⌈α⁻¹⌉₊ * α := by gcongr; exact Nat.le_ceil α⁻¹ + · calc ⌈α⁻¹⌉₊ * α + _ < (α⁻¹ + 1) * α := by gcongr; exact Nat.ceil_lt_add_one (inv_nonneg.2 h0.le) _ = 1 + α := by field_simp [h0.ne'] _ ≤ (1 : ℕ) + 1 := by gcongr; norm_cast - · refine Finset.sum_eq_zero ?_ + · apply Finset.sum_eq_zero intro x hx rw [Int.floor_eq_zero_iff] refine ⟨by positivity, ?_⟩ rw [Finset.mem_Ico, Nat.lt_ceil] at hx calc x * α < α⁻¹ * α := by gcongr; exact hx.2 - _ ≤ 1 := by simp [h0.ne'] + _ = 1 := by simp [h0.ne'] -lemma mem_Ico_n_of_mem_Ioo (h : α ∈ Set.Ioo 0 2) - {n : ℕ} (hn : 0 < n) : α ∈ Set.Ico ((2 * n - 1) / n : ℝ) 2 := by +lemma mem_Ico_n_of_mem_Ioo (h : α ∈ Set.Ioo 0 2) {n : ℕ} (hn : 0 < n) : + α ∈ Set.Ico ((2 * n - 1) / n : ℝ) 2 := by suffices ∑ i ∈ Finset.Icc 1 n, ⌊i * α⌋ = n ^ 2 ∧ α ∈ Set.Ico ((2 * n - 1) / n : ℝ) 2 from this.2 induction' n, hn using Nat.le_induction with k kpos hk · obtain ⟨h1, h2⟩ := hc.mem_Ico_one_of_mem_Ioo h @@ -107,37 +110,33 @@ lemma mem_Ico_n_of_mem_Ioo (h : α ∈ Set.Ioo 0 2) rw [Finset.mem_Icc] omega rw [← Nat.Icc_insert_succ_right (Nat.le_add_left 1 k), Finset.sum_insert hn11, hks] - replace hc := hc (k + 1) k.succ_pos + specialize hc (k + 1) k.succ_pos rw [hs] at hc ⊢ have hkl' : 2 * k ≤ ⌊(k + 1 : ℕ) * α⌋ := by rw [Int.le_floor] calc ((2 * k : ℤ) : ℝ) = ((2 * k : ℤ) : ℝ) + 0 := (add_zero _).symm _ ≤ ((2 * k : ℤ) : ℝ) + (k - 1) / k := by gcongr; norm_cast; positivity - _ = (k + 1 : ℕ) * ((2 * (k : ℕ) - 1) / ((k : ℕ) : ℝ) : ℝ) := by - field_simp - ring + _ = (k + 1 : ℕ) * ((2 * (k : ℕ) - 1) / ((k : ℕ) : ℝ)) := by field_simp; ring _ ≤ (k + 1 : ℕ) * α := by gcongr have hk2' : ⌊(k + 1 : ℕ) * α⌋ < (k + 1 : ℕ) * 2 := by rw [Int.floor_lt] push_cast gcongr - have hk : ⌊(k + 1 : ℕ) * α⌋ = 2 * k ∨ ⌊(k + 1 : ℕ) * α⌋ = 2 * k + 1 := by omega have hk' : ⌊(k + 1 : ℕ) * α⌋ = 2 * k + 1 := by - rcases hk with hk | hk - · rw [hk] at hc - have hc' : ((k + 1 : ℕ) : ℤ) ∣ ((k + 1 : ℕ) : ℤ) * ((k + 1 : ℕ) : ℤ) - 1 := by - convert hc using 1 - push_cast - ring - rw [dvd_sub_right (dvd_mul_right _ _), ← isUnit_iff_dvd_one, Int.isUnit_iff] at hc' - omega - · exact hk + by_contra + rw [show ⌊(k + 1 : ℕ) * α⌋ = 2 * k by omega] at hc + have hc' : ((k + 1 : ℕ) : ℤ) ∣ ((k + 1 : ℕ) : ℤ) * ((k + 1 : ℕ) : ℤ) - 1 := by + convert hc using 1 + push_cast + ring + rw [dvd_sub_right (dvd_mul_right _ _), ← isUnit_iff_dvd_one, Int.isUnit_iff] at hc' + omega rw [hk'] refine ⟨?_, ?_, h.2⟩ · push_cast ring · rw [Int.floor_eq_iff] at hk' - rw [div_le_iff (by norm_cast; omega), mul_comm α] + rw [div_le_iff₀ (by norm_cast; omega), mul_comm α] convert hk'.1 push_cast ring @@ -154,22 +153,22 @@ 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 (_ : ℝ) lemma condition_iff_of_mem_Ico {α : ℝ} (h : α ∈ Set.Ico 0 2) : Condition α ↔ α = 0 := by - refine ⟨?_, ?_⟩ + constructor · intro hc - rcases Set.eq_left_or_mem_Ioo_of_mem_Ico h with rfl | ho - · rfl - · exact False.elim (not_condition_of_mem_Ioo ho hc) + cases Set.eq_left_or_mem_Ioo_of_mem_Ico h with + | inl h => exact h + | inr ho => exact False.elim (not_condition_of_mem_Ioo ho hc) · rintro rfl convert condition_two_mul_int 0 norm_num -/-- This is to be determined by the solver of the original problem. -/ -def solutionSet : Set ℝ := {α : ℝ | ∃ m : ℤ, α = 2 * m} +recall Imo2024Q1.Condition (α : ℝ) := (∀ n : ℕ, 0 < n → (n : ℤ) ∣ ∑ i ∈ Finset.Icc 1 n, ⌊i * α⌋) +recall Imo2024Q1.solutionSet := {α : ℝ | ∃ m : ℤ, α = 2 * m} theorem result (α : ℝ) : Condition α ↔ α ∈ solutionSet := by refine ⟨fun h ↦ ?_, ?_⟩ diff --git a/Archive/MiuLanguage/DecisionNec.lean b/Archive/MiuLanguage/DecisionNec.lean index ba3cc0bc34669..694b599ac899d 100644 --- a/Archive/MiuLanguage/DecisionNec.lean +++ b/Archive/MiuLanguage/DecisionNec.lean @@ -67,18 +67,24 @@ is 1 or 2 modulo 3. theorem count_equiv_one_or_two_mod3_of_derivable (en : Miustr) : Derivable en → count I en % 3 = 1 ∨ count I en % 3 = 2 := by intro h - induction' h with _ _ h_ih _ _ h_ih _ _ _ h_ih _ _ _ h_ih - · left; rfl - any_goals apply mod3_eq_1_or_mod3_eq_2 h_ih - -- Porting note: `simp_rw [count_append]` usually doesn't work - · left; rw [count_append, count_append]; rfl - · right; simp_rw [count_append, count_cons, beq_iff_eq, ite_false, add_zero, two_mul] - · left; rw [count_append, count_append, count_append] - simp_rw [count_cons_self, count_nil, count_cons, beq_iff_eq, ite_false, add_right_comm, - add_mod_right] + induction h with + | mk => left; rfl + | r1 _ h_ih => + apply mod3_eq_1_or_mod3_eq_2 h_ih; left + rw [count_append, count_append]; rfl + | r2 _ h_ih => + apply mod3_eq_1_or_mod3_eq_2 h_ih; right + simp_rw [count_append, count_cons, beq_iff_eq, reduceCtorEq, ite_false, add_zero, two_mul] + | r3 _ h_ih => + apply mod3_eq_1_or_mod3_eq_2 h_ih; left + rw [count_append, count_append, count_append] + simp_rw [count_cons_self, count_nil, count_cons, beq_iff_eq, reduceCtorEq, ite_false, + add_right_comm, add_mod_right] simp - · left; rw [count_append, count_append, count_append] - simp only [ne_eq, not_false_eq_true, count_cons_of_ne, count_nil, add_zero] + | r4 _ h_ih => + apply mod3_eq_1_or_mod3_eq_2 h_ih; left + rw [count_append, count_append, count_append] + simp only [ne_eq, not_false_eq_true, count_cons_of_ne, count_nil, add_zero, reduceCtorEq] /-- Using the above theorem, we solve the MU puzzle, showing that `"MU"` is not derivable. Once we have proved that `Derivable` is an instance of `DecidablePred`, this will follow @@ -128,7 +134,7 @@ theorem goodm_of_rule1 (xs : Miustr) (h₁ : Derivable (xs ++ ↑[I])) (h₂ : G exact mhead · change ¬M ∈ tail (xs ++ ↑([I] ++ [U])) rw [← append_assoc, tail_append_singleton_of_ne_nil] - · simp_rw [mem_append, mem_singleton, or_false]; exact nmtail + · simp_rw [mem_append, mem_singleton, reduceCtorEq, or_false]; exact nmtail · exact append_ne_nil_of_left_ne_nil this _ theorem goodm_of_rule2 (xs : Miustr) (_ : Derivable (M :: xs)) (h₂ : Goodm (M :: xs)) : diff --git a/Archive/MiuLanguage/DecisionSuf.lean b/Archive/MiuLanguage/DecisionSuf.lean index 10eaa8e26942b..2f1f8bbf87750 100644 --- a/Archive/MiuLanguage/DecisionSuf.lean +++ b/Archive/MiuLanguage/DecisionSuf.lean @@ -94,7 +94,7 @@ theorem der_of_der_append_replicate_U_even {z : Miustr} {m : ℕ} rwa [append_nil, append_assoc] /-! -In fine-tuning my application of `simp`, I issued the following commend to determine which lemmas +In fine-tuning my application of `simp`, I issued the following command to determine which lemmas `simp` uses. `set_option trace.simplify.rewrite true` @@ -231,7 +231,7 @@ example (c : ℕ) (h : c % 3 = 1 ∨ c % 3 = 2) : Derivable (M :: replicate c I) /-! ### `Decstr` is a sufficient condition -The remainder of this file sets up the proof that `Decstr en` is sufficent to ensure +The remainder of this file sets up the proof that `Decstr en` is sufficient to ensure `Derivable en`. Decidability of `Derivable en` is an easy consequence. The proof proceeds by induction on the `count U` of `en`. @@ -256,7 +256,8 @@ theorem count_I_eq_length_of_count_U_zero_and_neg_mem {ys : Miustr} (hu : count · simpa only [count] · rw [mem_cons, not_or] at hm; exact hm.2 · -- case `x = U` gives a contradiction. - exfalso; simp only [count, countP_cons_of_pos (· == U) _ (rfl : U == U)] at hu + exfalso + simp only [count, countP_cons_of_pos (· == U) _ (rfl : U == U), reduceCtorEq] at hu /-- `base_case_suf` is the base case of the sufficiency result. -/ @@ -264,7 +265,8 @@ 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] at hi + 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 rsuffices ⟨c, rfl, hc⟩ : ∃ c, replicate c I = ys ∧ (c % 3 = 1 ∨ c % 3 = 2) @@ -308,16 +310,17 @@ theorem ind_hyp_suf (k : ℕ) (ys : Miustr) (hu : count U ys = succ k) (hdec : D refine ⟨rfl, ?_, ?_, ?_⟩ · -- Porting note: `simp_rw [count_append]` didn't work rw [count_append] at hu - simp_rw [count_cons, beq_self_eq_true, if_true, add_succ, beq_iff_eq, reduceIte, add_zero, - succ_inj'] at hu + simp_rw [count_cons, beq_self_eq_true, if_true, add_succ, beq_iff_eq, reduceCtorEq, reduceIte, + add_zero, succ_inj'] at hu rwa [count_append, count_append] · apply And.intro rfl rw [cons_append, cons_append] dsimp [tail] at nmtail ⊢ rw [mem_append] at nmtail - simpa only [append_assoc, cons_append, nil_append, mem_append, mem_cons, false_or] using nmtail + simpa only [append_assoc, cons_append, nil_append, mem_append, mem_cons, reduceCtorEq, + false_or] using nmtail · rw [count_append, count_append]; rw [← cons_append, count_append] at hic - simp only [count_cons_self, count_nil, count_cons, if_false] at hic ⊢ + simp only [count_cons_self, count_nil, count_cons, if_false, reduceCtorEq] at hic ⊢ rw [add_right_comm, add_mod_right]; exact hic /-- `der_of_decstr` states that `Derivable en` follows from `Decstr en`. diff --git a/Archive/OxfordInvariants/Summer2021/Week3P1.lean b/Archive/OxfordInvariants/Summer2021/Week3P1.lean index 36d9e899fdf80..d14d56211fd18 100644 --- a/Archive/OxfordInvariants/Summer2021/Week3P1.lean +++ b/Archive/OxfordInvariants/Summer2021/Week3P1.lean @@ -110,7 +110,7 @@ theorem OxfordInvariants.Week3P1 (n : ℕ) (a : ℕ → ℕ) (a_pos : ∀ i ≤ have ha₀ : a 0 ≤ a n * b := by -- Needing this is an artifact of `ℕ`-subtraction. rw [← @Nat.cast_le α, Nat.cast_mul, hb, ← - div_le_iff' (a_pos _ <| n.le_succ.trans <| Nat.le_succ _), ← + div_le_iff₀' (a_pos _ <| n.le_succ.trans <| Nat.le_succ _), ← mul_div_mul_right _ _ (a_pos _ <| Nat.le_succ _).ne'] suffices h : ∀ i, i ∈ Finset.range (n + 1) → 0 ≤ (a 0 : α) * a (n + 1) / (a i * a (i + 1)) from Finset.single_le_sum h (Finset.self_mem_range_succ n) diff --git a/Archive/Sensitivity.lean b/Archive/Sensitivity.lean index ae88d8cc7fc27..5cae8d062537c 100644 --- a/Archive/Sensitivity.lean +++ b/Archive/Sensitivity.lean @@ -33,18 +33,15 @@ The project was developed at https://github.com/leanprover-community/lean-sensit archived at https://github.com/leanprover-community/mathlib/blob/master/archive/sensitivity.lean -/ - - namespace Sensitivity /-! The next two lines assert we do not want to give a constructive proof, but rather use classical logic. -/ noncomputable section -open scoped Classical local notation "√" => Real.sqrt -open Function Bool LinearMap Fintype FiniteDimensional Module.DualBases +open Function Bool LinearMap Fintype Module Module.DualBases /-! ### The hypercube @@ -194,6 +191,7 @@ noncomputable def ε : ∀ {n : ℕ}, Q n → V n →ₗ[ℝ] ℝ variable {n : ℕ} +open Classical in theorem duality (p q : Q n) : ε p (e q) = if p = q then 1 else 0 := by induction' n with n IH · rw [show p = q from Subsingleton.elim (α := Q 0) p q] @@ -225,10 +223,12 @@ theorem epsilon_total {v : V n} (h : ∀ p : Q n, (ε p) v = 0) : v = 0 := by open Module +open Classical in /-- `e` and `ε` are dual families of vectors. It implies that `e` is indeed a basis and `ε` computes coefficients of decompositions of vectors on that basis. -/ theorem dualBases_e_ε (n : ℕ) : DualBases (@e n) (@ε n) where - eval := duality + eval_same := by simp [duality] + eval_of_ne _ _ h := by simp [duality, h] total := @epsilon_total _ /-! We will now derive the dimension of `V`, first as a cardinal in `dim_V` and, @@ -237,9 +237,11 @@ since this cardinal is finite, as a natural number in `finrank_V` -/ theorem dim_V : Module.rank ℝ (V n) = 2 ^ n := by have : Module.rank ℝ (V n) = (2 ^ n : ℕ) := by + classical rw [rank_eq_card_basis (dualBases_e_ε _).basis, Q.card] assumption_mod_cast +open Classical in instance : FiniteDimensional ℝ (V n) := FiniteDimensional.of_fintype_basis (dualBases_e_ε _).basis @@ -277,15 +279,16 @@ is necessary since otherwise `n • v` refers to the multiplication defined using only the addition of `V`. -/ -theorem f_squared : ∀ v : V n, (f n) (f n v) = (n : ℝ) • v := by - induction' n with n IH _ <;> intro v - · simp only [Nat.zero_eq, Nat.cast_zero, zero_smul]; rfl - · cases v; rw [f_succ_apply, f_succ_apply]; simp [IH, add_smul (n : ℝ) 1, add_assoc, V]; abel +theorem f_squared (v : V n) : (f n) (f n v) = (n : ℝ) • v := by + induction n with + | zero => simp only [Nat.cast_zero, zero_smul, f_zero, zero_apply] + | succ n IH => + cases v; rw [f_succ_apply, f_succ_apply]; simp [IH, add_smul (n : ℝ) 1, add_assoc, V]; abel /-! We now compute the matrix of `f` in the `e` basis (`p` is the line index, `q` the column index). -/ - +open Classical in theorem f_matrix : ∀ p q : Q n, |ε q (f n (e p))| = if p ∈ q.adjacent then 1 else 0 := by induction' n with n IH · intro p q @@ -360,7 +363,7 @@ local notation "Card " X:70 => Finset.card (Set.toFinset X) equipped with their subspace structures. The notations come from the general theory of lattices, with inf and sup (also known as meet and join). -/ - +open Classical in /-- If a subset `H` of `Q (m+1)` has cardinal at least `2^m + 1` then the subspace of `V (m+1)` spanned by the corresponding basis vectors non-trivially intersects the range of `g m`. -/ @@ -371,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 @@ -395,6 +398,7 @@ theorem exists_eigenvalue (H : Set (Q m.succ)) (hH : Card H ≥ 2 ^ m + 1) : rw [Set.toFinset_card] at hH linarith +open Classical in /-- **Huang sensitivity theorem** also known as the **Huang degree theorem** -/ theorem huang_degree_theorem (H : Set (Q m.succ)) (hH : Card H ≥ 2 ^ m + 1) : ∃ q, q ∈ H ∧ √ (m + 1) ≤ Card H ∩ q.adjacent := by @@ -421,7 +425,8 @@ theorem huang_degree_theorem (H : Set (Q m.succ)) (hH : Card H ≥ 2 ^ m + 1) : _ = |(coeffs y).sum fun (i : Q m.succ) (a : ℝ) => a • (ε q ∘ f m.succ ∘ fun i : Q m.succ => e i) i| := by - erw [(f m.succ).map_finsupp_total, (ε q).map_finsupp_total, Finsupp.total_apply] + erw [(f m.succ).map_finsupp_linearCombination, (ε q).map_finsupp_linearCombination, + Finsupp.linearCombination_apply] _ ≤ ∑ p ∈ (coeffs y).support, |coeffs y p * (ε q <| f m.succ <| e p)| := (norm_sum_le _ fun p => coeffs y p * _) _ = ∑ p ∈ (coeffs y).support, |coeffs y p| * ite (p ∈ q.adjacent) 1 0 := by 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 c58d39203d5df..df05d9256c5a5 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 /-! @@ -21,13 +22,10 @@ https://en.wikipedia.org/wiki/Erdos-Szekeres_theorem#Pigeonhole_principle. sequences, increasing, decreasing, Ramsey, Erdos-Szekeres, Erdős–Szekeres, Erdős-Szekeres -/ - variable {α : Type*} [LinearOrder α] {β : Type*} open Function Finset -open scoped Classical - namespace Theorems100 /-- **Erdős–Szekeres Theorem**: Given a sequence of more than `r * s` distinct values, there is an @@ -150,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 56bcc026d1228..3fd05ee140379 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 @@ -52,7 +52,7 @@ theorem staysPositive_cons {x : ℤ} {l : List ℤ} : theorem sum_nonneg_of_staysPositive : ∀ {l : List ℤ}, l ∈ staysPositive → 0 ≤ l.sum | [], _ => le_rfl - | (_::_), h => (h _ (List.cons_ne_nil _ _) (List.suffix_refl _)).le + | (_::_), h => (h _ (List.cons_ne_nil _ _) List.suffix_rfl).le theorem staysPositive_cons_pos (x : ℤ) (hx : 0 < x) (l : List ℤ) : (x::l) ∈ staysPositive ↔ l ∈ staysPositive := by @@ -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,7 +215,7 @@ 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, + 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] @@ -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,11 +248,11 @@ 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 (List.mem_of_mem_suffix hx hl₂)] + rw [List.eq_of_mem_replicate (hl₂.mem hx)] norm_num theorem countedSequence_int_pos_counted_succ_succ (p q : ℕ) : @@ -262,14 +262,14 @@ 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, + 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 @@ -289,14 +289,14 @@ 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, + 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 @@ -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, @@ -345,19 +345,16 @@ theorem ballot_problem' : linarith field_simp [h₄, h₅, h₆] at * ring - all_goals - refine (ENNReal.mul_lt_top ?_ ?_).ne - · exact (measure_lt_top _ _).ne - · simp [Ne, ENNReal.div_eq_top] + all_goals exact ENNReal.mul_ne_top (measure_ne_top _ _) (by simp [Ne, ENNReal.div_eq_top]) /-- 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, @@ -366,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..02a04dd66801e 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 : diff --git a/Archive/Wiedijk100Theorems/BuffonsNeedle.lean b/Archive/Wiedijk100Theorems/BuffonsNeedle.lean index fafebe0649917..e27b8be9851f2 100644 --- a/Archive/Wiedijk100Theorems/BuffonsNeedle.lean +++ b/Archive/Wiedijk100Theorems/BuffonsNeedle.lean @@ -308,7 +308,7 @@ lemma integral_zero_to_arcsin_min : have hθ_mem : θ ∈ Set.Ioc (-(π / 2)) (π / 2) := by exact ⟨lt_of_lt_of_le (neg_lt_zero.mpr (div_pos Real.pi_pos two_pos)) hθ₁, le_trans hθ₂ (d / l).arcsin_mem_Icc.right⟩ - simp_rw [min_eq_right ((le_div_iff hl).mp ((Real.le_arcsin_iff_sin_le' hθ_mem).mp hθ₂))] + simp_rw [min_eq_right ((le_div_iff₀ hl).mp ((Real.le_arcsin_iff_sin_le' hθ_mem).mp hθ₂))] rw [intervalIntegral.integral_congr this, intervalIntegral.integral_mul_const, integral_sin, Real.cos_zero, Real.cos_arcsin] @@ -328,7 +328,7 @@ lemma integral_arcsin_to_pi_div_two_min (h : d ≤ l) : max_eq_right (d / l).arcsin_le_pi_div_two] at hθ₁ hθ₂ have hθ_mem : θ ∈ Set.Ico (-(π / 2)) (π / 2) := by exact ⟨le_trans (Real.arcsin_mem_Icc (d / l)).left hθ₁, lt_of_le_of_ne hθ₂ hθ_ne_pi_div_two⟩ - simp_rw [min_eq_left ((div_le_iff hl).mp ((Real.arcsin_le_iff_le_sin' hθ_mem).mp hθ₁))] + simp_rw [min_eq_left ((div_le_iff₀ hl).mp ((Real.arcsin_le_iff_le_sin' hθ_mem).mp hθ₁))] rw [intervalIntegral.integral_congr this, intervalIntegral.integral_const, smul_eq_mul] include hd hBₘ hB hl in diff --git a/Archive/Wiedijk100Theorems/CubingACube.lean b/Archive/Wiedijk100Theorems/CubingACube.lean index f2710670e0f47..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 @@ -181,7 +181,7 @@ theorem shiftUp_bottom_subset_bottoms (hc : (cs i).xm ≠ 1) : (cs i).shiftUp.bottom ⊆ ⋃ i : ι, (cs i).bottom := by intro p hp; cases' hp with hp0 hps; rw [tail_shiftUp] at hps have : p ∈ (unitCube : Cube (n + 1)).toSet := by - simp only [toSet, forall_fin_succ, hp0, side_unitCube, mem_setOf_eq, mem_Ico, head_shiftUp] + simp only [toSet, forall_iff_succ, hp0, side_unitCube, mem_setOf_eq, mem_Ico, head_shiftUp] refine ⟨⟨?_, ?_⟩, ?_⟩ · rw [← zero_add (0 : ℝ)]; apply add_le_add · apply zero_le_b h @@ -225,7 +225,7 @@ theorem valley_unitCube [Nontrivial ι] (h : Correct cs) : Valley cs unitCube := intro h0 hv have : v ∈ (unitCube : Cube (n + 1)).toSet := by dsimp only [toSet, unitCube, mem_setOf_eq] - rw [forall_fin_succ, h0]; constructor + rw [forall_iff_succ, h0]; constructor · norm_num [side, unitCube] · exact hv rw [← h.2, mem_iUnion] at this; rcases this with ⟨i, hi⟩ @@ -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,14 +408,14 @@ 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_fin_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₂ apply not_disjoint_iff.mpr ⟨(cs i).b, (cs i).b_mem_toSet, this⟩ (h.1 i_i') have i_i'' : i ≠ i'' := by intro h; induction h; simpa [p', hx'.2] using hi''.2 j' apply Not.elim _ (h.1 i'_i'') - simp_rw [onFun, comp, toSet_disjoint, not_exists, not_disjoint_iff, forall_fin_succ] + simp_rw [onFun, comp, toSet_disjoint, not_exists, not_disjoint_iff, forall_iff_succ] refine ⟨⟨c.b 0, bottom_mem_side h2i', bottom_mem_side h2i''⟩, ?_⟩ intro j₂ by_cases hj₂ : j₂ = j @@ -480,9 +480,9 @@ theorem valley_mi : Valley cs (cs (mi h v)).shiftUp := by have h3i'' : (cs i).w < (cs i'').w := by apply mi_strict_minimal _ h2i''; rintro rfl; apply h2p3; convert hi''.2 let p' := @cons n (fun _ => ℝ) (cs i).xm p3 - have hp' : p' ∈ (cs i').toSet := by simpa [p', toSet, forall_fin_succ, hi'.symm] using h1p3 + have hp' : p' ∈ (cs i').toSet := by simpa [p', toSet, forall_iff_succ, hi'.symm] using h1p3 have h2p' : p' ∈ (cs i'').toSet := by - simp only [p', toSet, forall_fin_succ, cons_succ, cons_zero, mem_setOf_eq] + simp only [p', toSet, forall_iff_succ, cons_succ, cons_zero, mem_setOf_eq] refine ⟨?_, by simpa [toSet] using hi''.2⟩ have : (cs i).b 0 = (cs i'').b 0 := by rw [hi.1, h2i''.1] simp [side, hw', xm, this, h3i''] diff --git a/Archive/Wiedijk100Theorems/FriendshipGraphs.lean b/Archive/Wiedijk100Theorems/FriendshipGraphs.lean index a25f296a01c50..860afa94c8e2e 100644 --- a/Archive/Wiedijk100Theorems/FriendshipGraphs.lean +++ b/Archive/Wiedijk100Theorems/FriendshipGraphs.lean @@ -38,7 +38,6 @@ be phrased in terms of counting walks. -/ - open scoped Classical namespace Theorems100 @@ -82,8 +81,10 @@ include hG in theorem adjMatrix_sq_of_ne {v w : V} (hvw : v ≠ w) : (G.adjMatrix R ^ 2 : Matrix V V R) v w = 1 := by rw [sq, ← Nat.cast_one, ← hG hvw] - simp [commonNeighbors, neighborFinset_eq_filter, Finset.filter_filter, and_comm, - ← neighborFinset_def] + simp only [mul_adjMatrix_apply, neighborFinset_eq_filter, adjMatrix_apply, + sum_boole, filter_filter, and_comm, commonNeighbors, + Fintype.card_ofFinset (s := filter (fun x ↦ x ∈ G.neighborSet v ∩ G.neighborSet w) univ), + Set.mem_inter_iff, mem_neighborSet] include hG in /-- This calculation amounts to counting the number of length 3 walks between nonadjacent vertices. @@ -178,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/Konigsberg.lean b/Archive/Wiedijk100Theorems/Konigsberg.lean index 93d5c585639da..80eff930911c5 100644 --- a/Archive/Wiedijk100Theorems/Konigsberg.lean +++ b/Archive/Wiedijk100Theorems/Konigsberg.lean @@ -73,7 +73,7 @@ lemma not_even_degree_iff (w : Verts) : ¬Even (degree w) ↔ w = V1 ∨ w = V2 lemma setOf_odd_degree_eq : {v | Odd (graph.degree v)} = {Verts.V1, Verts.V2, Verts.V3, Verts.V4} := by ext w - simp [not_even_degree_iff] + simp [not_even_degree_iff, ← Nat.not_even_iff_odd] /-- The Königsberg graph is not Eulerian. -/ theorem not_isEulerian {u v : Verts} (p : graph.Walk u v) (h : p.IsEulerian) : False := by @@ -81,6 +81,6 @@ theorem not_isEulerian {u v : Verts} (p : graph.Walk u v) (h : p.IsEulerian) : F have h' := setOf_odd_degree_eq apply_fun Fintype.card at h' rw [h'] at h - norm_num at h + simp at h end Konigsberg diff --git a/Archive/Wiedijk100Theorems/Partition.lean b/Archive/Wiedijk100Theorems/Partition.lean index 38232baf5bdab..0ced772d9f68f 100644 --- a/Archive/Wiedijk100Theorems/Partition.lean +++ b/Archive/Wiedijk100Theorems/Partition.lean @@ -127,7 +127,7 @@ theorem num_series' [Field α] (i : ℕ) : | zero => simp [mul_sub, zero_pow, constantCoeff_indicator] | succ n => simp only [coeff_one, if_false, mul_sub, mul_one, coeff_indicator, - LinearMap.map_sub] + LinearMap.map_sub, reduceCtorEq] simp_rw [coeff_mul, coeff_X_pow, coeff_indicator, @boole_mul _ _ _ _] erw [sum_ite, sum_ite] simp_rw [@filter_filter _ _ _ _ _, sum_const_zero, add_zero, sum_const, nsmul_eq_mul, mul_one, @@ -206,7 +206,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 @@ -218,7 +218,7 @@ theorem partialGF_prop (α : Type*) [CommSemiring α] (n : ℕ) (s : Finset ℕ) · rw [← mul_left_inj' hi] rw [Function.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' @@ -266,7 +266,7 @@ theorem partialOddGF_prop [Field α] (n m : ℕ) : 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 @@ -314,10 +314,9 @@ theorem partialDistinctGF_prop [CommSemiring α] (n m : ℕ) : convert partialGF_prop α n ((range m).map ⟨Nat.succ, Nat.succ_injective⟩) _ (fun _ => {0, 1}) (fun _ _ => Or.inl rfl) using 2 - · congr - congr! with p + · congr! with p rw [Multiset.nodup_iff_count_le_one] - congr! with i + congr! 1 with i rcases Multiset.count i p.parts with (_ | _ | ms) <;> simp · simp_rw [Finset.prod_map, two_series] congr with i diff --git a/Archive/Wiedijk100Theorems/PerfectNumbers.lean b/Archive/Wiedijk100Theorems/PerfectNumbers.lean index fcca5aa780ae0..e23628d48b3e3 100644 --- a/Archive/Wiedijk100Theorems/PerfectNumbers.lean +++ b/Archive/Wiedijk100Theorems/PerfectNumbers.lean @@ -29,9 +29,6 @@ https://en.wikipedia.org/wiki/Euclid%E2%80%93Euler_theorem namespace Theorems100 -theorem odd_mersenne_succ (k : ℕ) : ¬2 ∣ mersenne (k + 1) := by - simp [← even_iff_two_dvd, ← Nat.even_add_one, parity_simps] - namespace Nat open ArithmeticFunction Finset @@ -43,10 +40,9 @@ theorem sigma_two_pow_eq_mersenne_succ (k : ℕ) : σ 1 (2 ^ k) = mersenne (k + /-- Euclid's theorem that Mersenne primes induce perfect numbers -/ theorem perfect_two_pow_mul_mersenne_of_prime (k : ℕ) (pr : (mersenne (k + 1)).Prime) : Nat.Perfect (2 ^ k * mersenne (k + 1)) := by - rw [Nat.perfect_iff_sum_divisors_eq_two_mul, ← mul_assoc, ← pow_succ', - ← sigma_one_apply, mul_comm, - isMultiplicative_sigma.map_mul_of_coprime - (Nat.prime_two.coprime_pow_of_not_dvd (odd_mersenne_succ _)), + rw [Nat.perfect_iff_sum_divisors_eq_two_mul, ← mul_assoc, ← pow_succ', ← sigma_one_apply, + mul_comm, + isMultiplicative_sigma.map_mul_of_coprime ((Odd.coprime_two_right (by simp)).pow_right _), sigma_two_pow_eq_mersenne_succ] · simp [pr, Nat.prime_two, sigma_one_apply] · positivity @@ -81,9 +77,8 @@ theorem eq_two_pow_mul_prime_mersenne_of_even_perfect {n : ℕ} (ev : Even n) (p rw [Nat.perfect_iff_sum_divisors_eq_two_mul hpos, ← sigma_one_apply, isMultiplicative_sigma.map_mul_of_coprime (Nat.prime_two.coprime_pow_of_not_dvd hm).symm, sigma_two_pow_eq_mersenne_succ, ← mul_assoc, ← pow_succ'] at perf - rcases Nat.Coprime.dvd_of_dvd_mul_left - (Nat.prime_two.coprime_pow_of_not_dvd (odd_mersenne_succ _)) (Dvd.intro _ perf) with - ⟨j, rfl⟩ + obtain ⟨j, rfl⟩ := ((Odd.coprime_two_right (by simp)).pow_right _).dvd_of_dvd_mul_left + (Dvd.intro _ perf) rw [← mul_assoc, mul_comm _ (mersenne _), mul_assoc] at perf have h := mul_left_cancel₀ (by positivity) perf rw [sigma_one_apply, Nat.sum_divisors_eq_sum_properDivisors_add_self, ← succ_mersenne, add_mul, diff --git a/Archive/Wiedijk100Theorems/SolutionOfCubic.lean b/Archive/Wiedijk100Theorems/SolutionOfCubic.lean index b780b1926bc5e..f61bda51e27dd 100644 --- a/Archive/Wiedijk100Theorems/SolutionOfCubic.lean +++ b/Archive/Wiedijk100Theorems/SolutionOfCubic.lean @@ -73,8 +73,8 @@ theorem cubic_monic_eq_zero_iff (hω : IsPrimitiveRoot ω 3) (hp : p = (3 * c - 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 := nonzero_of_invertible _ - have hi3 : (3 : K) ≠ 0 := nonzero_of_invertible _ + 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 @@ -92,7 +92,7 @@ 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 := nonzero_of_invertible _ + 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₁ : a * x ^ 3 + b * x ^ 2 + c * x + d @@ -119,8 +119,8 @@ theorem cubic_eq_zero_iff_of_p_eq_zero (ha : a ≠ 0) (hω : IsPrimitiveRoot ω x = s - b / (3 * a) ∨ x = s * ω - b / (3 * a) ∨ x = s * ω ^ 2 - b / (3 * a) := by have h₁ : ∀ x a₁ a₂ a₃ : K, x = a₁ ∨ x = a₂ ∨ x = a₃ ↔ (x - a₁) * (x - a₂) * (x - a₃) = 0 := by intros; simp only [mul_eq_zero, sub_eq_zero, or_assoc] - have hi2 : (2 : K) ≠ 0 := nonzero_of_invertible _ - have hi3 : (3 : K) ≠ 0 := nonzero_of_invertible _ + have hi2 : (2 : K) ≠ 0 := Invertible.ne_zero _ + have hi3 : (3 : K) ≠ 0 := Invertible.ne_zero _ have h54 : (54 : K) = 2 * 3 ^ 3 := by norm_num have hb2 : b ^ 2 = 3 * a * c := by rw [sub_eq_zero] at hpz; rw [hpz] have hb3 : b ^ 3 = 3 * a * b * c := by rw [pow_succ, hb2]; ring diff --git a/Archive/Wiedijk100Theorems/SumOfPrimeReciprocalsDiverges.lean b/Archive/Wiedijk100Theorems/SumOfPrimeReciprocalsDiverges.lean index 31e32ae2f76a7..e30881c10059f 100644 --- a/Archive/Wiedijk100Theorems/SumOfPrimeReciprocalsDiverges.lean +++ b/Archive/Wiedijk100Theorems/SumOfPrimeReciprocalsDiverges.lean @@ -38,10 +38,6 @@ The formalization follows Erdős's proof by upper and lower estimates. https://en.wikipedia.org/wiki/Divergence_of_the_sum_of_the_reciprocals_of_the_primes -/ - - -open scoped Classical - open Filter Finset namespace Theorems100 @@ -57,6 +53,7 @@ of `p`, i.e., those `e < x` for which there is a prime `p ∈ (k, x]` that divid def U (x k : ℕ) := Finset.biUnion (P x k) (fun p => Finset.filter (fun e => p ∣ e + 1) (range x)) +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 : ℕ) := @@ -157,7 +154,7 @@ theorem card_le_two_pow {x k : ℕ} : 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 + _ ≤ 2 ^ card (range k) := pow_right_mono₀ one_le_two card_image_le _ = 2 ^ k := by rw [card_range k] /-- @@ -217,6 +214,7 @@ theorem Real.tendsto_sum_one_div_prime_atTop : -- This is indeed a partition, so `|U| + |M| = |range x| = x`. have h2 : x = card U' + card M' := by rw [← card_range x, hU', hM', ← range_sdiff_eq_biUnion] + classical exact (card_sdiff_add_card_eq_card (Finset.filter_subset _ _)).symm -- But for the `x` we have chosen above, both `|U|` and `|M|` are less than or equal to `x / 2`, -- and for U, the inequality is strict. diff --git a/Archive/ZagierTwoSquares.lean b/Archive/ZagierTwoSquares.lean index 894cf667b4e0c..f4846d4fea64c 100644 --- a/Archive/ZagierTwoSquares.lean +++ b/Archive/ZagierTwoSquares.lean @@ -50,7 +50,7 @@ lemma zagierSet_lower_bound {x y z : ℕ} (h : (x, y, z) ∈ zagierSet k) : 0 < cases' (Nat.dvd_prime hk.out).1 (dvd_of_mul_left_eq _ h) with e e all_goals simp only [e, self_eq_add_left, ne_eq, add_eq_zero, and_false, not_false_eq_true, - mul_eq_left₀] at h + mul_eq_left₀, reduceCtorEq] at h simp only [h, zero_add] at hk exact Nat.not_prime_one hk.out @@ -148,7 +148,7 @@ theorem eq_of_mem_fixedPoints {t : zagierSet k} (mem : t ∈ fixedPoints (comple split_ifs at mem with less more <;> -- less (completely handled by the pre-applied `simp_all only`) simp_all only [not_lt, Prod.mk.injEq, add_right_eq_self, mul_eq_zero, false_or, - lt_self_iff_false] + lt_self_iff_false, reduceCtorEq] · -- more obtain ⟨_, _, _⟩ := mem; simp_all · -- middle (the one fixed point falls under this case) @@ -161,7 +161,7 @@ theorem eq_of_mem_fixedPoints {t : zagierSet k} (mem : t ∈ fixedPoints (comple cases' (Nat.dvd_prime hk.out).1 (dvd_of_mul_left_eq _ h) with e e · rw [e, mul_one] at h simp_all [h, show z = 0 by linarith [e]] - · simp only [e, mul_left_eq_self₀, add_eq_zero, and_false, or_false] at h + · simp only [e, mul_left_eq_self₀, add_eq_zero, and_false, or_false, reduceCtorEq] at h simp only [h, true_and] linarith [e] 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 850ce0a414f8c..43e3f70652623 100644 --- a/Cache/IO.lean +++ b/Cache/IO.lean @@ -10,7 +10,7 @@ import Lean.Data.RBTree import Lean.Data.Json.Printer import Lean.Data.Json.Parser -set_option autoImplicit true +variable {α : Type} /-- Removes a parent path from the beginning of a path -/ def System.FilePath.withoutParent (path parent : FilePath) : FilePath := @@ -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 3e022f97e0853..71b74cb4b051d 100644 --- a/Cache/Requests.lean +++ b/Cache/Requests.lean @@ -6,8 +6,6 @@ Authors: Arthur Paulino import Lean.Data.Json.Parser import Cache.Hashing -set_option autoImplicit true - namespace Cache.Requests -- FRO cache is flaky so disable until we work out the kinks: https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/The.20cache.20doesn't.20work/near/411058849 @@ -186,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 @@ -255,7 +253,7 @@ def QueryType.prefix : QueryType → String | commits => "&prefix=c/" | all => default -def formatError : IO α := +def formatError {α : Type} : IO α := throw <| IO.userError "Invalid format for curl return" def QueryType.desc : QueryType → String 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/CanonicallyOrderedCommSemiringTwoMul.lean b/Counterexamples/CanonicallyOrderedCommSemiringTwoMul.lean index fef5690af55aa..832f9e8bef97d 100644 --- a/Counterexamples/CanonicallyOrderedCommSemiringTwoMul.lean +++ b/Counterexamples/CanonicallyOrderedCommSemiringTwoMul.lean @@ -134,14 +134,14 @@ theorem mul_L {a b : ℕ × ZMod 2} (ha : a ≠ (0, 1)) (hb : b ≠ (0, 1)) : a rcases a with ⟨a, a2⟩ rcases b with ⟨b, b2⟩ cases b - · rcases mem_zmod_2 b2 with (rfl | rfl) <;> rcases mem_zmod_2 a2 with (rfl | rfl) <;> simp - -- while this looks like a non-terminal `simp`, it (almost) isn't: there is only one goal where - -- it does not finish the proof and on that goal it asks to prove `false` + · rcases mem_zmod_2 b2 with (rfl | rfl) <;> rcases mem_zmod_2 a2 with (rfl | rfl) <;> + simp only [Prod.mk_mul_mk, mul_zero, mul_one, ne_eq, Prod.mk.injEq, zero_ne_one, and_false, + not_false_eq_true, not_true_eq_false] exact hb rfl cases a - · rcases mem_zmod_2 b2 with (rfl | rfl) <;> rcases mem_zmod_2 a2 with (rfl | rfl) <;> simp - -- while this looks like a non-terminal `simp`, it (almost) isn't: there is only one goal where - -- it does not finish the proof and on that goal it asks to prove `false` + · rcases mem_zmod_2 b2 with (rfl | rfl) <;> rcases mem_zmod_2 a2 with (rfl | rfl) <;> + simp only [Prod.mk_mul_mk, mul_zero, zero_mul, mul_one, ne_eq, Prod.mk.injEq, zero_ne_one, + and_false, not_false_eq_true, not_true_eq_false] exact ha rfl · simp [mul_ne_zero _ _, Nat.succ_ne_zero _] diff --git a/Counterexamples/CliffordAlgebraNotInjective.lean b/Counterexamples/CliffordAlgebraNotInjective.lean index b84245b0d53cc..8670d40f77954 100644 --- a/Counterexamples/CliffordAlgebraNotInjective.lean +++ b/Counterexamples/CliffordAlgebraNotInjective.lean @@ -52,7 +52,7 @@ theorem mem_kIdeal_iff (x : MvPolynomial (Fin 3) (ZMod 2)) : have : kIdeal = Ideal.span ((monomial · (1 : ZMod 2)) '' Set.range (Finsupp.single · 2)) := by simp_rw [kIdeal, X, monomial_mul, one_mul, ← Finsupp.single_add, ← Set.range_comp, - Function.comp] + Function.comp_def] rw [this, mem_ideal_span_monomial_image] simp @@ -132,7 +132,7 @@ theorem sq_zero_of_αβγ_mul {x : K} : α * β * γ * x = 0 → x * x = 0 := by rw [Ideal.Quotient.eq_zero_iff_mem, Ideal.Quotient.eq_zero_iff_mem] exact mul_self_mem_kIdeal_of_X0_X1_X2_mul_mem -/-- Though `αβγ` is not itself zero-/ +/-- Though `αβγ` is not itself zero -/ theorem αβγ_ne_zero : α * β * γ ≠ 0 := fun h => X0_X1_X2_not_mem_kIdeal <| Ideal.Quotient.eq_zero_iff_mem.1 h @@ -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/Girard.lean b/Counterexamples/Girard.lean index 2109c68505664..2045588c13e53 100644 --- a/Counterexamples/Girard.lean +++ b/Counterexamples/Girard.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Mathlib.Logic.Basic -import Mathlib.Init.Set +import Mathlib.Data.Set.Defs /-! # Girard's paradox 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/MonicNonRegular.lean b/Counterexamples/MonicNonRegular.lean index 80b870310e2b9..954e6c22a84c6 100644 --- a/Counterexamples/MonicNonRegular.lean +++ b/Counterexamples/MonicNonRegular.lean @@ -88,7 +88,8 @@ theorem monic_X_add_two : Monic (X + C 2 : N₃[X]) := by unfold Monic leadingCoeff nontriviality rw [natDegree_X_add_C 2] - simp only [natDegree_X_add_C 2, coeff_C, coeff_add, coeff_X_one, ite_false, add_zero] + simp only [natDegree_X_add_C 2, coeff_C, coeff_add, coeff_X_one, ite_false, add_zero, + reduceCtorEq] theorem not_isLeftRegular_X_add_two : ¬ IsLeftRegular (X + C 2 : N₃[X]) := by intro h diff --git a/Counterexamples/Phillips.lean b/Counterexamples/Phillips.lean index 3e9c76aabe1c0..cf03d0dc7c250 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 @@ -132,7 +132,7 @@ def boundedIntegrableFunctionsIntegralCLM [MeasurableSpace α] (μ : Measure α) intro f rw [mul_comm] apply norm_integral_le_of_norm_le_const - apply Filter.eventually_of_forall + apply Filter.Eventually.of_forall intro x exact BoundedContinuousFunction.norm_coe_le_norm f.1 x) @@ -269,7 +269,7 @@ theorem exists_discrete_support_nonpos (f : BoundedAdditiveMeasure α) : refine ⟨t, fun u => ?_⟩ calc f (↑u \ ↑s) ≤ S := le_ciSup B _ - _ ≤ 2 * f (↑t \ ↑s) := (div_le_iff' two_pos).1 ht.le + _ ≤ 2 * f (↑t \ ↑s) := (div_le_iff₀' two_pos).1 ht.le choose! F hF using this -- iterate the above construction, by adding at each step a set with measure close to maximal in -- the complement of already chosen points. This is the set `s n` at step `n`. @@ -283,7 +283,7 @@ theorem exists_discrete_support_nonpos (f : BoundedAdditiveMeasure α) : have ε_pos : 0 < ε := ht have I1 : ∀ n, ε / 2 ≤ f (↑(s (n + 1)) \ ↑(s n)) := by intro n - rw [div_le_iff' (show (0 : ℝ) < 2 by norm_num), hε] + rw [div_le_iff₀' (show (0 : ℝ) < 2 by norm_num), hε] convert hF (s n) u using 2 · dsimp ext x @@ -293,11 +293,12 @@ theorem exists_discrete_support_nonpos (f : BoundedAdditiveMeasure α) : simp only [s, Function.iterate_succ', Subtype.coe_mk, union_diff_left, Function.comp] have I2 : ∀ n : ℕ, (n : ℝ) * (ε / 2) ≤ f ↑(s n) := by intro n - induction' n with n IH - · simp only [s, BoundedAdditiveMeasure.empty, id, Nat.cast_zero, zero_mul, - Function.iterate_zero, Subtype.coe_mk, Nat.zero_eq] - rfl - · have : (s (n + 1)).1 = (s (n + 1)).1 \ (s n).1 ∪ (s n).1 := by + induction n with + | zero => + simp only [s, BoundedAdditiveMeasure.empty, id, Nat.cast_zero, zero_mul, + Function.iterate_zero, Subtype.coe_mk, le_rfl] + | succ n IH => + have : (s (n + 1)).1 = (s (n + 1)).1 \ (s n).1 ∪ (s n).1 := by simpa only [s, Function.iterate_succ', union_diff_self] using (diff_union_of_subset subset_union_left).symm rw [this, f.additive] @@ -307,7 +308,7 @@ theorem exists_discrete_support_nonpos (f : BoundedAdditiveMeasure α) : _ ≤ f (↑(s (n + 1 : ℕ)) \ ↑(s n)) + f ↑(s n) := add_le_add (I1 n) IH rcases exists_nat_gt (f.C / (ε / 2)) with ⟨n, hn⟩ have : (n : ℝ) ≤ f.C / (ε / 2) := by - rw [le_div_iff (half_pos ε_pos)]; exact (I2 n).trans (f.le_bound _) + rw [le_div_iff₀ (half_pos ε_pos)]; exact (I2 n).trans (f.le_bound _) exact lt_irrefl _ (this.trans_lt hn) theorem exists_discrete_support (f : BoundedAdditiveMeasure α) : @@ -432,7 +433,7 @@ theorem toFunctions_toMeasure [MeasurableSpace α] (μ : Measure α) [IsFiniteMe have : Integrable (fun _ => (1 : ℝ)) μ := integrable_const (1 : ℝ) apply this.mono' (Measurable.indicator (@measurable_const _ _ _ _ (1 : ℝ)) hs).aestronglyMeasurable - apply Filter.eventually_of_forall + apply Filter.Eventually.of_forall exact norm_indicator_le_one _ theorem toFunctions_toMeasure_continuousPart [MeasurableSpace α] [MeasurableSingletonClass α] @@ -466,14 +467,14 @@ theorem sierpinski_pathological_family (Hcont : #ℝ = aleph 1) : 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] 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 6015b4d98307e..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 := @@ -129,7 +129,7 @@ theorem map_toReal_nhds (a : ℝₗ) : map toReal (𝓝 a) = 𝓝[≥] toReal a simpa only [toReal.image_eq_preimage] using nhdsWithin_Ici_basis_Ico (toReal a) theorem nhds_eq_map (a : ℝₗ) : 𝓝 a = map toReal.symm (𝓝[≥] (toReal a)) := by - simp_rw [← map_toReal_nhds, map_map, (· ∘ ·), toReal.symm_apply_apply, map_id'] + simp_rw [← map_toReal_nhds, map_map, Function.comp_def, toReal.symm_apply_apply, map_id'] theorem nhds_eq_comap (a : ℝₗ) : 𝓝 a = comap toReal (𝓝[≥] (toReal a)) := by rw [← map_toReal_nhds, comap_map toReal.injective] @@ -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 f12b01482968d..703b8f0eded4e 100644 --- a/Counterexamples/ZeroDivisorsInAddMonoidAlgebras.lean +++ b/Counterexamples/ZeroDivisorsInAddMonoidAlgebras.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa -/ import Mathlib.Algebra.GeomSum -import Mathlib.Algebra.Group.UniqueProds +import Mathlib.Algebra.Group.UniqueProds.Basic import Mathlib.Algebra.MonoidAlgebra.Basic import Mathlib.Data.Finsupp.Lex import Mathlib.Data.ZMod.Basic diff --git a/LongestPole/Main.lean b/LongestPole/Main.lean index 1ad6f2a7b33cd..b4abb23680785 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 @@ -22,7 +22,7 @@ open Lean Meta /-- Runs a terminal command and retrieves its output -/ def runCmd (cmd : String) (args : Array String) (throwFailure := true) : IO String := do let out ← IO.Process.output { cmd := cmd, args := args } - if out.exitCode != 0 && throwFailure then throw $ IO.userError out.stderr + if out.exitCode != 0 && throwFailure then throw <| IO.userError out.stderr else return out.stdout def runCurl (args : Array String) (throwFailure := true) : IO String := do diff --git a/LongestPole/SpeedCenterJson.lean b/LongestPole/SpeedCenterJson.lean index 89bfb54a07ffa..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 @@ -47,7 +47,7 @@ structure RunResponse where run : Run deriving ToJson, FromJson -/-- The error response-/ +/-- The error response -/ structure ErrorMessage where repo_id : String message : String diff --git a/Mathlib.lean b/Mathlib.lean index 40bc9f91fafba..945eeef5e1098 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -1,3 +1,4 @@ +import Batteries import Mathlib.Algebra.AddConstMap.Basic import Mathlib.Algebra.AddConstMap.Equiv import Mathlib.Algebra.AddTorsor @@ -20,6 +21,7 @@ import Mathlib.Algebra.Algebra.RestrictScalars import Mathlib.Algebra.Algebra.Spectrum import Mathlib.Algebra.Algebra.Subalgebra.Basic import Mathlib.Algebra.Algebra.Subalgebra.Directed +import Mathlib.Algebra.Algebra.Subalgebra.IsSimpleOrder import Mathlib.Algebra.Algebra.Subalgebra.MulOpposite import Mathlib.Algebra.Algebra.Subalgebra.Operations import Mathlib.Algebra.Algebra.Subalgebra.Order @@ -30,16 +32,20 @@ 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 import Mathlib.Algebra.BigOperators.Group.Finset import Mathlib.Algebra.BigOperators.Group.List import Mathlib.Algebra.BigOperators.Group.Multiset +import Mathlib.Algebra.BigOperators.GroupWithZero.Action import Mathlib.Algebra.BigOperators.GroupWithZero.Finset import Mathlib.Algebra.BigOperators.Intervals import Mathlib.Algebra.BigOperators.Module @@ -52,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 @@ -61,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 @@ -73,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 @@ -170,6 +177,7 @@ import Mathlib.Algebra.ContinuedFractions.TerminatedStable import Mathlib.Algebra.ContinuedFractions.Translations import Mathlib.Algebra.CubicDiscriminant import Mathlib.Algebra.DirectLimit +import Mathlib.Algebra.DirectSum.AddChar import Mathlib.Algebra.DirectSum.Algebra import Mathlib.Algebra.DirectSum.Basic import Mathlib.Algebra.DirectSum.Decomposition @@ -237,6 +245,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 @@ -258,6 +267,10 @@ 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.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 @@ -282,7 +295,8 @@ import Mathlib.Algebra.Group.Subsemigroup.Operations import Mathlib.Algebra.Group.Support import Mathlib.Algebra.Group.TypeTags import Mathlib.Algebra.Group.ULift -import Mathlib.Algebra.Group.UniqueProds +import Mathlib.Algebra.Group.UniqueProds.Basic +import Mathlib.Algebra.Group.UniqueProds.VectorSpace import Mathlib.Algebra.Group.Units import Mathlib.Algebra.Group.Units.Equiv import Mathlib.Algebra.Group.Units.Hom @@ -310,6 +324,7 @@ 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.Basic import Mathlib.Algebra.GroupWithZero.Prod import Mathlib.Algebra.GroupWithZero.Semiconj import Mathlib.Algebra.GroupWithZero.ULift @@ -321,6 +336,7 @@ import Mathlib.Algebra.HierarchyDesign import Mathlib.Algebra.Homology.Additive import Mathlib.Algebra.Homology.Augment import Mathlib.Algebra.Homology.Bifunctor +import Mathlib.Algebra.Homology.BifunctorAssociator import Mathlib.Algebra.Homology.BifunctorFlip import Mathlib.Algebra.Homology.BifunctorHomotopy import Mathlib.Algebra.Homology.BifunctorShift @@ -330,7 +346,9 @@ import Mathlib.Algebra.Homology.ComplexShapeSigns import Mathlib.Algebra.Homology.ConcreteCategory import Mathlib.Algebra.Homology.DerivedCategory.Basic import Mathlib.Algebra.Homology.DerivedCategory.ExactFunctor -import Mathlib.Algebra.Homology.DerivedCategory.Ext +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 import Mathlib.Algebra.Homology.DerivedCategory.SingleTriangle @@ -338,6 +356,7 @@ import Mathlib.Algebra.Homology.DifferentialObject import Mathlib.Algebra.Homology.Embedding.Basic import Mathlib.Algebra.Homology.Embedding.Boundary import Mathlib.Algebra.Homology.Embedding.Extend +import Mathlib.Algebra.Homology.Embedding.HomEquiv import Mathlib.Algebra.Homology.Embedding.IsSupported import Mathlib.Algebra.Homology.Embedding.Restriction import Mathlib.Algebra.Homology.Embedding.TruncGE @@ -488,9 +507,11 @@ import Mathlib.Algebra.Module.Submodule.Range import Mathlib.Algebra.Module.Submodule.RestrictScalars 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.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,9 +548,14 @@ 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 import Mathlib.Algebra.Order.BigOperators.Ring.Finset import Mathlib.Algebra.Order.BigOperators.Ring.List import Mathlib.Algebra.Order.BigOperators.Ring.Multiset @@ -545,17 +571,19 @@ 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 -import Mathlib.Algebra.Order.Field.Unbundled.Basic import Mathlib.Algebra.Order.Floor import Mathlib.Algebra.Order.Floor.Div import Mathlib.Algebra.Order.Floor.Prime import Mathlib.Algebra.Order.Group.Abs 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 @@ -566,8 +594,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 @@ -576,9 +607,12 @@ import Mathlib.Algebra.Order.Group.Unbundled.Abs import Mathlib.Algebra.Order.Group.Unbundled.Basic import Mathlib.Algebra.Order.Group.Unbundled.Int import Mathlib.Algebra.Order.Group.Units +import Mathlib.Algebra.Order.GroupWithZero.Action.Synonym 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 @@ -598,6 +632,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 @@ -621,7 +656,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 @@ -635,6 +669,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 @@ -642,12 +677,18 @@ import Mathlib.Algebra.Order.Ring.Star import Mathlib.Algebra.Order.Ring.Synonym import Mathlib.Algebra.Order.Ring.Unbundled.Basic import Mathlib.Algebra.Order.Ring.Unbundled.Nonneg +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.Sub.Basic -import Mathlib.Algebra.Order.Sub.Canonical import Mathlib.Algebra.Order.Sub.Defs import Mathlib.Algebra.Order.Sub.Prod +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 @@ -740,12 +781,14 @@ 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.Set import Mathlib.Algebra.Ring.Prod import Mathlib.Algebra.Ring.Rat 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 @@ -766,11 +809,11 @@ import Mathlib.Algebra.Star.BigOperators import Mathlib.Algebra.Star.CHSH import Mathlib.Algebra.Star.Center import Mathlib.Algebra.Star.CentroidHom +import Mathlib.Algebra.Star.Conjneg import Mathlib.Algebra.Star.Free import Mathlib.Algebra.Star.Module import Mathlib.Algebra.Star.NonUnitalSubalgebra import Mathlib.Algebra.Star.NonUnitalSubsemiring -import Mathlib.Algebra.Star.Order import Mathlib.Algebra.Star.Pi import Mathlib.Algebra.Star.Pointwise import Mathlib.Algebra.Star.Prod @@ -795,7 +838,9 @@ import Mathlib.AlgebraicGeometry.EllipticCurve.DivisionPolynomial.Basic import Mathlib.AlgebraicGeometry.EllipticCurve.DivisionPolynomial.Degree import Mathlib.AlgebraicGeometry.EllipticCurve.Group 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 @@ -809,6 +854,7 @@ import Mathlib.AlgebraicGeometry.Morphisms.Affine import Mathlib.AlgebraicGeometry.Morphisms.Basic import Mathlib.AlgebraicGeometry.Morphisms.ClosedImmersion import Mathlib.AlgebraicGeometry.Morphisms.Constructors +import Mathlib.AlgebraicGeometry.Morphisms.FinitePresentation import Mathlib.AlgebraicGeometry.Morphisms.FiniteType import Mathlib.AlgebraicGeometry.Morphisms.IsIso import Mathlib.AlgebraicGeometry.Morphisms.OpenImmersion @@ -832,6 +878,7 @@ import Mathlib.AlgebraicGeometry.ProjectiveSpectrum.StructureSheaf import Mathlib.AlgebraicGeometry.ProjectiveSpectrum.Topology import Mathlib.AlgebraicGeometry.Properties import Mathlib.AlgebraicGeometry.Pullbacks +import Mathlib.AlgebraicGeometry.ResidueField import Mathlib.AlgebraicGeometry.Restrict import Mathlib.AlgebraicGeometry.Scheme import Mathlib.AlgebraicGeometry.Sites.BigZariski @@ -866,20 +913,22 @@ 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 @@ -911,6 +960,7 @@ import Mathlib.Analysis.BoxIntegral.Partition.Tagged import Mathlib.Analysis.CStarAlgebra.Basic import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Basic import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Instances +import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Integral import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.NonUnital import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Order import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Restrict @@ -919,8 +969,11 @@ import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Unital import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Unitary 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 +import Mathlib.Analysis.CStarAlgebra.Module.Synonym import Mathlib.Analysis.CStarAlgebra.Multiplier import Mathlib.Analysis.CStarAlgebra.Spectrum import Mathlib.Analysis.CStarAlgebra.Unitization @@ -936,9 +989,11 @@ 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.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 @@ -968,6 +1023,7 @@ 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 @@ -1015,6 +1071,7 @@ import Mathlib.Analysis.Complex.Conformal import Mathlib.Analysis.Complex.Convex import Mathlib.Analysis.Complex.Hadamard import Mathlib.Analysis.Complex.HalfPlane +import Mathlib.Analysis.Complex.IsIntegral import Mathlib.Analysis.Complex.Isometry import Mathlib.Analysis.Complex.Liouville import Mathlib.Analysis.Complex.LocallyUniformLimit @@ -1040,6 +1097,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 @@ -1050,6 +1108,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 @@ -1107,6 +1166,7 @@ import Mathlib.Analysis.InnerProductSpace.ConformalLinearMap import Mathlib.Analysis.InnerProductSpace.Dual import Mathlib.Analysis.InnerProductSpace.EuclideanDist import Mathlib.Analysis.InnerProductSpace.GramSchmidtOrtho +import Mathlib.Analysis.InnerProductSpace.JointEigenspace import Mathlib.Analysis.InnerProductSpace.LaxMilgram import Mathlib.Analysis.InnerProductSpace.LinearPMap import Mathlib.Analysis.InnerProductSpace.MeanErgodic @@ -1120,6 +1180,7 @@ import Mathlib.Analysis.InnerProductSpace.ProdL2 import Mathlib.Analysis.InnerProductSpace.Projection import Mathlib.Analysis.InnerProductSpace.Rayleigh import Mathlib.Analysis.InnerProductSpace.Spectrum +import Mathlib.Analysis.InnerProductSpace.StarOrder import Mathlib.Analysis.InnerProductSpace.Symmetric import Mathlib.Analysis.InnerProductSpace.TwoDim import Mathlib.Analysis.InnerProductSpace.WeakOperatorTopology @@ -1133,6 +1194,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 @@ -1147,6 +1209,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 @@ -1154,6 +1217,8 @@ import Mathlib.Analysis.Normed.Algebra.Unitization 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.UnitBall import Mathlib.Analysis.Normed.Group.AddCircle import Mathlib.Analysis.Normed.Group.AddTorsor @@ -1179,6 +1244,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 @@ -1205,9 +1271,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 @@ -1248,10 +1316,12 @@ 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 import Mathlib.Analysis.SpecialFunctions.Bernstein +import Mathlib.Analysis.SpecialFunctions.BinaryEntropy import Mathlib.Analysis.SpecialFunctions.CompareExp import Mathlib.Analysis.SpecialFunctions.Complex.Analytic import Mathlib.Analysis.SpecialFunctions.Complex.Arctan @@ -1262,6 +1332,7 @@ import Mathlib.Analysis.SpecialFunctions.Complex.Log import Mathlib.Analysis.SpecialFunctions.Complex.LogBounds import Mathlib.Analysis.SpecialFunctions.Complex.LogDeriv import Mathlib.Analysis.SpecialFunctions.ContinuousFunctionalCalculus.ExpLog +import Mathlib.Analysis.SpecialFunctions.ContinuousFunctionalCalculus.Rpow import Mathlib.Analysis.SpecialFunctions.Exp import Mathlib.Analysis.SpecialFunctions.ExpDeriv import Mathlib.Analysis.SpecialFunctions.Exponential @@ -1326,6 +1397,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 @@ -1346,13 +1418,15 @@ import Mathlib.CategoryTheory.Adjunction.Basic import Mathlib.CategoryTheory.Adjunction.Comma import Mathlib.CategoryTheory.Adjunction.Evaluation import Mathlib.CategoryTheory.Adjunction.FullyFaithful -import Mathlib.CategoryTheory.Adjunction.Lifting +import Mathlib.CategoryTheory.Adjunction.Lifting.Left +import Mathlib.CategoryTheory.Adjunction.Lifting.Right import Mathlib.CategoryTheory.Adjunction.Limits import Mathlib.CategoryTheory.Adjunction.Mates import Mathlib.CategoryTheory.Adjunction.Opposites import Mathlib.CategoryTheory.Adjunction.Over import Mathlib.CategoryTheory.Adjunction.Reflective import Mathlib.CategoryTheory.Adjunction.Restrict +import Mathlib.CategoryTheory.Adjunction.Triple import Mathlib.CategoryTheory.Adjunction.Unique import Mathlib.CategoryTheory.Adjunction.Whiskering import Mathlib.CategoryTheory.Balanced @@ -1391,14 +1465,17 @@ 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 import Mathlib.CategoryTheory.ChosenFiniteProducts +import Mathlib.CategoryTheory.ChosenFiniteProducts.Cat import Mathlib.CategoryTheory.ChosenFiniteProducts.FunctorCategory import Mathlib.CategoryTheory.Closed.Cartesian import Mathlib.CategoryTheory.Closed.Functor import Mathlib.CategoryTheory.Closed.FunctorCategory +import Mathlib.CategoryTheory.Closed.FunctorToTypes import Mathlib.CategoryTheory.Closed.Ideal import Mathlib.CategoryTheory.Closed.Monoidal import Mathlib.CategoryTheory.Closed.Types @@ -1447,6 +1524,8 @@ import Mathlib.CategoryTheory.EssentiallySmall import Mathlib.CategoryTheory.Extensive import Mathlib.CategoryTheory.FiberedCategory.BasedCategory import Mathlib.CategoryTheory.FiberedCategory.Cartesian +import Mathlib.CategoryTheory.FiberedCategory.Cocartesian +import Mathlib.CategoryTheory.FiberedCategory.Fibered import Mathlib.CategoryTheory.FiberedCategory.HomLift import Mathlib.CategoryTheory.Filtered.Basic import Mathlib.CategoryTheory.Filtered.Connected @@ -1464,6 +1543,7 @@ import Mathlib.CategoryTheory.Functor.Derived.RightDerived import Mathlib.CategoryTheory.Functor.EpiMono import Mathlib.CategoryTheory.Functor.Flat import Mathlib.CategoryTheory.Functor.FullyFaithful +import Mathlib.CategoryTheory.Functor.FunctorHom import Mathlib.CategoryTheory.Functor.Functorial import Mathlib.CategoryTheory.Functor.Hom import Mathlib.CategoryTheory.Functor.KanExtension.Adjunction @@ -1472,16 +1552,22 @@ 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 import Mathlib.CategoryTheory.GradedObject.Associator import Mathlib.CategoryTheory.GradedObject.Bifunctor +import Mathlib.CategoryTheory.GradedObject.Braiding import Mathlib.CategoryTheory.GradedObject.Monoidal import Mathlib.CategoryTheory.GradedObject.Single import Mathlib.CategoryTheory.GradedObject.Trifunctor @@ -1541,7 +1627,9 @@ import Mathlib.CategoryTheory.Limits.FinallySmall import Mathlib.CategoryTheory.Limits.FintypeCat import Mathlib.CategoryTheory.Limits.Fubini import Mathlib.CategoryTheory.Limits.FullSubcategory -import Mathlib.CategoryTheory.Limits.FunctorCategory +import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic +import Mathlib.CategoryTheory.Limits.FunctorCategory.EpiMono +import Mathlib.CategoryTheory.Limits.FunctorCategory.Finite import Mathlib.CategoryTheory.Limits.FunctorToTypes import Mathlib.CategoryTheory.Limits.HasLimits import Mathlib.CategoryTheory.Limits.IndYoneda @@ -1651,6 +1739,7 @@ import Mathlib.CategoryTheory.Monad.Adjunction import Mathlib.CategoryTheory.Monad.Algebra import Mathlib.CategoryTheory.Monad.Basic import Mathlib.CategoryTheory.Monad.Coequalizer +import Mathlib.CategoryTheory.Monad.Comonadicity import Mathlib.CategoryTheory.Monad.Equalizer import Mathlib.CategoryTheory.Monad.EquivMon import Mathlib.CategoryTheory.Monad.Kleisli @@ -1676,6 +1765,7 @@ import Mathlib.CategoryTheory.Monoidal.Free.Coherence import Mathlib.CategoryTheory.Monoidal.Functor import Mathlib.CategoryTheory.Monoidal.FunctorCategory import Mathlib.CategoryTheory.Monoidal.Functorial +import Mathlib.CategoryTheory.Monoidal.Hopf_ import Mathlib.CategoryTheory.Monoidal.Internal.FunctorCategory import Mathlib.CategoryTheory.Monoidal.Internal.Limits import Mathlib.CategoryTheory.Monoidal.Internal.Module @@ -1691,6 +1781,7 @@ import Mathlib.CategoryTheory.Monoidal.OfHasFiniteProducts import Mathlib.CategoryTheory.Monoidal.Opposite import Mathlib.CategoryTheory.Monoidal.Preadditive import Mathlib.CategoryTheory.Monoidal.Rigid.Basic +import Mathlib.CategoryTheory.Monoidal.Rigid.Braided import Mathlib.CategoryTheory.Monoidal.Rigid.FunctorCategory import Mathlib.CategoryTheory.Monoidal.Rigid.OfEquivalence import Mathlib.CategoryTheory.Monoidal.Skeleton @@ -1706,6 +1797,7 @@ import Mathlib.CategoryTheory.MorphismProperty.Concrete import Mathlib.CategoryTheory.MorphismProperty.Factorization import Mathlib.CategoryTheory.MorphismProperty.IsInvertedBy import Mathlib.CategoryTheory.MorphismProperty.Limits +import Mathlib.CategoryTheory.MorphismProperty.Representable import Mathlib.CategoryTheory.NatIso import Mathlib.CategoryTheory.NatTrans import Mathlib.CategoryTheory.Noetherian @@ -1761,6 +1853,7 @@ import Mathlib.CategoryTheory.SingleObj import Mathlib.CategoryTheory.Sites.Abelian import Mathlib.CategoryTheory.Sites.Adjunction import Mathlib.CategoryTheory.Sites.Canonical +import Mathlib.CategoryTheory.Sites.CartesianClosed import Mathlib.CategoryTheory.Sites.Closed import Mathlib.CategoryTheory.Sites.Coherent.Basic import Mathlib.CategoryTheory.Sites.Coherent.CoherentSheaves @@ -1785,7 +1878,6 @@ import Mathlib.CategoryTheory.Sites.CoverPreserving import Mathlib.CategoryTheory.Sites.Coverage import Mathlib.CategoryTheory.Sites.CoversTop import Mathlib.CategoryTheory.Sites.DenseSubsite -import Mathlib.CategoryTheory.Sites.Discrete import Mathlib.CategoryTheory.Sites.EffectiveEpimorphic import Mathlib.CategoryTheory.Sites.EpiMono import Mathlib.CategoryTheory.Sites.EqualizerSheafCondition @@ -1859,6 +1951,7 @@ import Mathlib.Combinatorics.Additive.AP.Three.Defs import Mathlib.Combinatorics.Additive.Corner.Defs import Mathlib.Combinatorics.Additive.Corner.Roth import Mathlib.Combinatorics.Additive.Dissociation +import Mathlib.Combinatorics.Additive.DoublingConst import Mathlib.Combinatorics.Additive.ETransform import Mathlib.Combinatorics.Additive.Energy import Mathlib.Combinatorics.Additive.ErdosGinzburgZiv @@ -1870,9 +1963,11 @@ import Mathlib.Combinatorics.Configuration import Mathlib.Combinatorics.Derangements.Basic import Mathlib.Combinatorics.Derangements.Exponential import Mathlib.Combinatorics.Derangements.Finite +import Mathlib.Combinatorics.Digraph.Basic import Mathlib.Combinatorics.Enumerative.Catalan import Mathlib.Combinatorics.Enumerative.Composition import Mathlib.Combinatorics.Enumerative.DoubleCounting +import Mathlib.Combinatorics.Enumerative.DyckWord import Mathlib.Combinatorics.Enumerative.Partition import Mathlib.Combinatorics.HalesJewett import Mathlib.Combinatorics.Hall.Basic @@ -1887,6 +1982,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 @@ -1899,6 +1995,7 @@ import Mathlib.Combinatorics.SetFamily.FourFunctions import Mathlib.Combinatorics.SetFamily.HarrisKleitman import Mathlib.Combinatorics.SetFamily.Intersecting import Mathlib.Combinatorics.SetFamily.Kleitman +import Mathlib.Combinatorics.SetFamily.KruskalKatona import Mathlib.Combinatorics.SetFamily.LYM import Mathlib.Combinatorics.SetFamily.Shadow import Mathlib.Combinatorics.SetFamily.Shatter @@ -1914,6 +2011,7 @@ import Mathlib.Combinatorics.SimpleGraph.Connectivity.WalkCounting import Mathlib.Combinatorics.SimpleGraph.Dart import Mathlib.Combinatorics.SimpleGraph.DegreeSum import Mathlib.Combinatorics.SimpleGraph.Density +import Mathlib.Combinatorics.SimpleGraph.Diam import Mathlib.Combinatorics.SimpleGraph.Ends.Defs import Mathlib.Combinatorics.SimpleGraph.Ends.Properties import Mathlib.Combinatorics.SimpleGraph.Finite @@ -1924,6 +2022,7 @@ import Mathlib.Combinatorics.SimpleGraph.Hasse import Mathlib.Combinatorics.SimpleGraph.IncMatrix import Mathlib.Combinatorics.SimpleGraph.Init import Mathlib.Combinatorics.SimpleGraph.LapMatrix +import Mathlib.Combinatorics.SimpleGraph.LineGraph import Mathlib.Combinatorics.SimpleGraph.Maps import Mathlib.Combinatorics.SimpleGraph.Matching import Mathlib.Combinatorics.SimpleGraph.Metric @@ -1968,15 +2067,20 @@ import Mathlib.Computability.TMComputable import Mathlib.Computability.TMToPartrec import Mathlib.Computability.TuringMachine import Mathlib.Condensed.Basic +import Mathlib.Condensed.CartesianClosed import Mathlib.Condensed.Discrete.Basic +import Mathlib.Condensed.Discrete.LocallyConstant +import Mathlib.Condensed.Discrete.Module import Mathlib.Condensed.Epi import Mathlib.Condensed.Equivalence import Mathlib.Condensed.Explicit import Mathlib.Condensed.Functors import Mathlib.Condensed.Light.Basic +import Mathlib.Condensed.Light.CartesianClosed import Mathlib.Condensed.Light.Epi import Mathlib.Condensed.Light.Explicit import Mathlib.Condensed.Light.Functors +import Mathlib.Condensed.Light.Limits import Mathlib.Condensed.Light.Module import Mathlib.Condensed.Light.TopCatAdjunction import Mathlib.Condensed.Light.TopComparison @@ -2088,6 +2192,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 @@ -2100,9 +2205,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 @@ -2174,6 +2276,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 @@ -2182,12 +2285,14 @@ import Mathlib.Data.Int.Log import Mathlib.Data.Int.ModEq import Mathlib.Data.Int.NatPrime import Mathlib.Data.Int.Notation +import Mathlib.Data.Int.Order.Basic import Mathlib.Data.Int.Order.Lemmas import Mathlib.Data.Int.Order.Units 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 @@ -2216,6 +2321,7 @@ import Mathlib.Data.List.Lattice import Mathlib.Data.List.Lemmas import Mathlib.Data.List.Lex import Mathlib.Data.List.MinMax +import Mathlib.Data.List.Monad import Mathlib.Data.List.NatAntidiagonal import Mathlib.Data.List.Nodup import Mathlib.Data.List.NodupEquivFin @@ -2251,6 +2357,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 @@ -2281,6 +2388,7 @@ import Mathlib.Data.Multiset.Interval import Mathlib.Data.Multiset.Lattice import Mathlib.Data.Multiset.NatAntidiagonal import Mathlib.Data.Multiset.Nodup +import Mathlib.Data.Multiset.OrderedMonoid import Mathlib.Data.Multiset.Pi import Mathlib.Data.Multiset.Powerset import Mathlib.Data.Multiset.Range @@ -2291,6 +2399,7 @@ import Mathlib.Data.Multiset.Sym import Mathlib.Data.NNRat.BigOperators import Mathlib.Data.NNRat.Defs import Mathlib.Data.NNRat.Lemmas +import Mathlib.Data.NNRat.Order import Mathlib.Data.NNReal.Basic import Mathlib.Data.NNReal.Star import Mathlib.Data.Nat.BitIndices @@ -2358,6 +2467,7 @@ import Mathlib.Data.Nat.Prime.Defs import Mathlib.Data.Nat.PrimeFin import Mathlib.Data.Nat.Set import Mathlib.Data.Nat.Size +import Mathlib.Data.Nat.Sqrt import Mathlib.Data.Nat.Squarefree import Mathlib.Data.Nat.SuccPred import Mathlib.Data.Nat.Totient @@ -2430,6 +2540,7 @@ import Mathlib.Data.Real.GoldenRatio import Mathlib.Data.Real.Hyperreal import Mathlib.Data.Real.Irrational 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 @@ -2460,13 +2571,14 @@ 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 +import Mathlib.Data.Set.Operations import Mathlib.Data.Set.Opposite import Mathlib.Data.Set.Pairwise.Basic import Mathlib.Data.Set.Pairwise.Lattice -import Mathlib.Data.Set.Pointwise.Basic import Mathlib.Data.Set.Pointwise.BigOperators import Mathlib.Data.Set.Pointwise.BoundedMul import Mathlib.Data.Set.Pointwise.Finite @@ -2524,17 +2636,15 @@ 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.Aliases +import Mathlib.Deprecated.Combinator import Mathlib.Deprecated.Group import Mathlib.Deprecated.HashMap import Mathlib.Deprecated.Ring @@ -2547,6 +2657,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 @@ -2560,13 +2671,17 @@ import Mathlib.Dynamics.Minimal import Mathlib.Dynamics.Newton 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.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 @@ -2574,8 +2689,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.IntermediateField +import Mathlib.FieldTheory.Galois.Basic +import Mathlib.FieldTheory.IntermediateField.Algebraic +import Mathlib.FieldTheory.IntermediateField.Basic import Mathlib.FieldTheory.IsAlgClosed.AlgebraicClosure import Mathlib.FieldTheory.IsAlgClosed.Basic import Mathlib.FieldTheory.IsAlgClosed.Classification @@ -2659,6 +2775,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 @@ -2686,9 +2803,11 @@ import Mathlib.Geometry.RingedSpace.SheafedSpace import Mathlib.Geometry.RingedSpace.Stalks import Mathlib.GroupTheory.Abelianization import Mathlib.GroupTheory.Archimedean +import Mathlib.GroupTheory.ArchimedeanDensely import Mathlib.GroupTheory.ClassEquation import Mathlib.GroupTheory.Commensurable -import Mathlib.GroupTheory.Commutator +import Mathlib.GroupTheory.Commutator.Basic +import Mathlib.GroupTheory.Commutator.Finite import Mathlib.GroupTheory.CommutingProbability import Mathlib.GroupTheory.Complement import Mathlib.GroupTheory.Congruence.Basic @@ -2696,7 +2815,8 @@ import Mathlib.GroupTheory.Congruence.BigOperators import Mathlib.GroupTheory.Congruence.Opposite import Mathlib.GroupTheory.Coprod.Basic import Mathlib.GroupTheory.CoprodI -import Mathlib.GroupTheory.Coset +import Mathlib.GroupTheory.Coset.Basic +import Mathlib.GroupTheory.Coset.Card import Mathlib.GroupTheory.CosetCover import Mathlib.GroupTheory.Coxeter.Basic import Mathlib.GroupTheory.Coxeter.Inversion @@ -2716,15 +2836,14 @@ import Mathlib.GroupTheory.FreeGroup.Basic import Mathlib.GroupTheory.FreeGroup.IsFreeGroup import Mathlib.GroupTheory.FreeGroup.NielsenSchreier import Mathlib.GroupTheory.GroupAction.Basic -import Mathlib.GroupTheory.GroupAction.BigOperators import Mathlib.GroupTheory.GroupAction.Blocks +import Mathlib.GroupTheory.GroupAction.CardCommute import Mathlib.GroupTheory.GroupAction.ConjAct import Mathlib.GroupTheory.GroupAction.DomAct.ActionHom import Mathlib.GroupTheory.GroupAction.DomAct.Basic import Mathlib.GroupTheory.GroupAction.Embedding import Mathlib.GroupTheory.GroupAction.FixedPoints import Mathlib.GroupTheory.GroupAction.FixingSubgroup -import Mathlib.GroupTheory.GroupAction.Group import Mathlib.GroupTheory.GroupAction.Hom import Mathlib.GroupTheory.GroupAction.IterateAct import Mathlib.GroupTheory.GroupAction.Period @@ -2749,6 +2868,7 @@ 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 @@ -2765,7 +2885,8 @@ import Mathlib.GroupTheory.Perm.Support import Mathlib.GroupTheory.Perm.ViaEmbedding import Mathlib.GroupTheory.PresentedGroup import Mathlib.GroupTheory.PushoutI -import Mathlib.GroupTheory.QuotientGroup +import Mathlib.GroupTheory.QuotientGroup.Basic +import Mathlib.GroupTheory.QuotientGroup.Finite import Mathlib.GroupTheory.Schreier import Mathlib.GroupTheory.SchurZassenhaus import Mathlib.GroupTheory.SemidirectProduct @@ -2788,22 +2909,10 @@ import Mathlib.GroupTheory.Sylow import Mathlib.GroupTheory.Torsion import Mathlib.GroupTheory.Transfer import Mathlib.InformationTheory.Hamming +import Mathlib.Init import Mathlib.Init.Algebra.Classes -import Mathlib.Init.Classical -import Mathlib.Init.Core -import Mathlib.Init.Data.Fin.Basic -import Mathlib.Init.Data.Int.Order -import Mathlib.Init.Data.List.Basic -import Mathlib.Init.Data.List.Instances -import Mathlib.Init.Data.List.Lemmas import Mathlib.Init.Data.Nat.Lemmas -import Mathlib.Init.Data.Quot -import Mathlib.Init.Data.Sigma.Basic -import Mathlib.Init.Data.Sigma.Lex import Mathlib.Init.Logic -import Mathlib.Init.Order.LinearOrder -import Mathlib.Init.Quot -import Mathlib.Init.Set import Mathlib.Lean.CoreM import Mathlib.Lean.Elab.Tactic.Basic import Mathlib.Lean.Elab.Term @@ -2872,6 +2981,7 @@ import Mathlib.LinearAlgebra.CliffordAlgebra.Fold import Mathlib.LinearAlgebra.CliffordAlgebra.Grading import Mathlib.LinearAlgebra.CliffordAlgebra.Inversion import Mathlib.LinearAlgebra.CliffordAlgebra.Prod +import Mathlib.LinearAlgebra.CliffordAlgebra.SpinGroup import Mathlib.LinearAlgebra.CliffordAlgebra.Star import Mathlib.LinearAlgebra.Coevaluation import Mathlib.LinearAlgebra.Contraction @@ -2983,6 +3093,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 @@ -3004,6 +3115,10 @@ 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 import Mathlib.LinearAlgebra.Semisimple @@ -3054,10 +3169,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 @@ -3069,6 +3186,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 @@ -3107,6 +3225,7 @@ import Mathlib.MeasureTheory.Covering.LiminfLimsup import Mathlib.MeasureTheory.Covering.OneDim import Mathlib.MeasureTheory.Covering.Vitali import Mathlib.MeasureTheory.Covering.VitaliFamily +import Mathlib.MeasureTheory.Decomposition.Exhaustion import Mathlib.MeasureTheory.Decomposition.Jordan import Mathlib.MeasureTheory.Decomposition.Lebesgue import Mathlib.MeasureTheory.Decomposition.RadonNikodym @@ -3208,11 +3327,14 @@ import Mathlib.MeasureTheory.MeasurableSpace.Defs 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.Measure.AEDisjoint import Mathlib.MeasureTheory.Measure.AEMeasurable import Mathlib.MeasureTheory.Measure.AddContent import Mathlib.MeasureTheory.Measure.Complex import Mathlib.MeasureTheory.Measure.Content +import Mathlib.MeasureTheory.Measure.ContinuousPreimage import Mathlib.MeasureTheory.Measure.Count import Mathlib.MeasureTheory.Measure.Dirac import Mathlib.MeasureTheory.Measure.DiracProba @@ -3246,6 +3368,7 @@ import Mathlib.MeasureTheory.Measure.Portmanteau import Mathlib.MeasureTheory.Measure.ProbabilityMeasure 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 @@ -3260,6 +3383,7 @@ import Mathlib.MeasureTheory.Order.Lattice import Mathlib.MeasureTheory.Order.UpperLower import Mathlib.MeasureTheory.OuterMeasure.AE import Mathlib.MeasureTheory.OuterMeasure.Basic +import Mathlib.MeasureTheory.OuterMeasure.BorelCantelli import Mathlib.MeasureTheory.OuterMeasure.Caratheodory import Mathlib.MeasureTheory.OuterMeasure.Defs import Mathlib.MeasureTheory.OuterMeasure.Induced @@ -3270,6 +3394,7 @@ import Mathlib.MeasureTheory.SetAlgebra import Mathlib.MeasureTheory.SetSemiring import Mathlib.ModelTheory.Algebra.Field.Basic import Mathlib.ModelTheory.Algebra.Field.CharP +import Mathlib.ModelTheory.Algebra.Field.IsAlgClosed import Mathlib.ModelTheory.Algebra.Ring.Basic import Mathlib.ModelTheory.Algebra.Ring.FreeCommRing import Mathlib.ModelTheory.Basic @@ -3280,6 +3405,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 @@ -3326,6 +3452,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 @@ -3336,6 +3464,7 @@ import Mathlib.NumberTheory.Harmonic.EulerMascheroni import Mathlib.NumberTheory.Harmonic.GammaDeriv import Mathlib.NumberTheory.Harmonic.Int import Mathlib.NumberTheory.Harmonic.ZetaAsymp +import Mathlib.NumberTheory.JacobiSum.Basic import Mathlib.NumberTheory.KummerDedekind import Mathlib.NumberTheory.LSeries.AbstractFuncEq import Mathlib.NumberTheory.LSeries.Basic @@ -3343,6 +3472,7 @@ import Mathlib.NumberTheory.LSeries.Convergence import Mathlib.NumberTheory.LSeries.Convolution import Mathlib.NumberTheory.LSeries.Deriv import Mathlib.NumberTheory.LSeries.Dirichlet +import Mathlib.NumberTheory.LSeries.DirichletContinuation import Mathlib.NumberTheory.LSeries.HurwitzZeta import Mathlib.NumberTheory.LSeries.HurwitzZetaEven import Mathlib.NumberTheory.LSeries.HurwitzZetaOdd @@ -3350,6 +3480,7 @@ import Mathlib.NumberTheory.LSeries.HurwitzZetaValues import Mathlib.NumberTheory.LSeries.Linearity import Mathlib.NumberTheory.LSeries.MellinEqDirichlet import Mathlib.NumberTheory.LSeries.RiemannZeta +import Mathlib.NumberTheory.LSeries.ZMod import Mathlib.NumberTheory.LegendreSymbol.AddCharacter import Mathlib.NumberTheory.LegendreSymbol.Basic import Mathlib.NumberTheory.LegendreSymbol.GaussEisensteinLemmas @@ -3387,6 +3518,7 @@ 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.Embeddings @@ -3402,7 +3534,9 @@ import Mathlib.NumberTheory.Padics.Hensel import Mathlib.NumberTheory.Padics.PadicIntegers import Mathlib.NumberTheory.Padics.PadicNorm import Mathlib.NumberTheory.Padics.PadicNumbers -import Mathlib.NumberTheory.Padics.PadicVal +import Mathlib.NumberTheory.Padics.PadicVal.Basic +import Mathlib.NumberTheory.Padics.PadicVal.Defs +import Mathlib.NumberTheory.Padics.ProperSpace import Mathlib.NumberTheory.Padics.RingHoms import Mathlib.NumberTheory.Pell import Mathlib.NumberTheory.PellMatiyasevic @@ -3464,6 +3598,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 @@ -3481,8 +3616,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 @@ -3491,6 +3633,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 @@ -3502,7 +3645,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 @@ -3593,9 +3735,12 @@ 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 import Mathlib.Order.Sublattice +import Mathlib.Order.SuccPred.Archimedean import Mathlib.Order.SuccPred.Basic import Mathlib.Order.SuccPred.CompleteLinearOrder import Mathlib.Order.SuccPred.IntervalSucc @@ -3606,6 +3751,7 @@ import Mathlib.Order.SupClosed import Mathlib.Order.SupIndep import Mathlib.Order.SymmDiff import Mathlib.Order.Synonym +import Mathlib.Order.TypeTags import Mathlib.Order.ULift import Mathlib.Order.UpperLower.Basic import Mathlib.Order.UpperLower.Hom @@ -3617,7 +3763,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 @@ -3625,11 +3770,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 @@ -3637,6 +3784,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 @@ -3645,6 +3793,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 @@ -3671,6 +3820,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 @@ -3712,6 +3862,7 @@ 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 @@ -3731,16 +3882,20 @@ import Mathlib.RingTheory.DedekindDomain.PID import Mathlib.RingTheory.DedekindDomain.SInteger 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.EuclideanDomain import Mathlib.RingTheory.Filtration +import Mathlib.RingTheory.FiniteLength import Mathlib.RingTheory.FinitePresentation import Mathlib.RingTheory.FiniteStability import Mathlib.RingTheory.FiniteType @@ -3752,6 +3907,7 @@ import Mathlib.RingTheory.Flat.CategoryTheory import Mathlib.RingTheory.Flat.EquationalCriterion import Mathlib.RingTheory.Flat.Stability import Mathlib.RingTheory.FractionalIdeal.Basic +import Mathlib.RingTheory.FractionalIdeal.Extended import Mathlib.RingTheory.FractionalIdeal.Norm import Mathlib.RingTheory.FractionalIdeal.Operations import Mathlib.RingTheory.FreeCommRing @@ -3805,9 +3961,13 @@ import Mathlib.RingTheory.JacobsonIdeal import Mathlib.RingTheory.Kaehler.Basic import Mathlib.RingTheory.Kaehler.CotangentComplex import Mathlib.RingTheory.Kaehler.Polynomial +import Mathlib.RingTheory.KrullDimension.Basic +import Mathlib.RingTheory.KrullDimension.Field import Mathlib.RingTheory.LaurentSeries 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 @@ -3816,12 +3976,12 @@ import Mathlib.RingTheory.LocalRing.Module 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 @@ -3843,12 +4003,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 @@ -3910,6 +4072,7 @@ 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 import Mathlib.RingTheory.Regular.RegularSequence @@ -3917,6 +4080,7 @@ 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.Surjective import Mathlib.RingTheory.RingHomProperties import Mathlib.RingTheory.RingInvo @@ -3925,6 +4089,8 @@ 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.StandardSmooth @@ -3935,19 +4101,27 @@ import Mathlib.RingTheory.TensorProduct.MvPolynomial import Mathlib.RingTheory.Trace.Basic import Mathlib.RingTheory.Trace.Defs 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 import Mathlib.RingTheory.Valuation.Integers import Mathlib.RingTheory.Valuation.Integral +import Mathlib.RingTheory.Valuation.Minpoly 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 @@ -3969,6 +4143,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 @@ -3977,7 +4153,6 @@ 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.PartENat import Mathlib.SetTheory.Cardinal.SchroederBernstein import Mathlib.SetTheory.Cardinal.Subfield @@ -3996,10 +4171,12 @@ 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.Topology @@ -4008,9 +4185,12 @@ import Mathlib.SetTheory.Surreal.Dyadic 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 @@ -4033,13 +4213,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 @@ -4095,6 +4287,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 @@ -4128,13 +4321,19 @@ import Mathlib.Tactic.Linarith.Parsing 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.Lint import Mathlib.Tactic.Linter.MinImports 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 @@ -4144,6 +4343,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 @@ -4199,6 +4399,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 @@ -4213,6 +4414,7 @@ import Mathlib.Tactic.Simps.NotationClass import Mathlib.Tactic.SlimCheck import Mathlib.Tactic.SplitIfs import Mathlib.Tactic.Spread +import Mathlib.Tactic.StacksAttribute import Mathlib.Tactic.Subsingleton import Mathlib.Tactic.Substs import Mathlib.Tactic.SuccessIfFailWithMsg @@ -4252,6 +4454,8 @@ 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.ClosedSubgroup import Mathlib.Topology.Algebra.ConstMulAction import Mathlib.Topology.Algebra.Constructions import Mathlib.Topology.Algebra.Constructions.DomMulAct @@ -4263,6 +4467,7 @@ import Mathlib.Topology.Algebra.FilterBasis import Mathlib.Topology.Algebra.Group.Basic import Mathlib.Topology.Algebra.Group.Compact import Mathlib.Topology.Algebra.Group.OpenMapping +import Mathlib.Topology.Algebra.Group.SubmonoidClosure import Mathlib.Topology.Algebra.Group.TopologicalAbelianization import Mathlib.Topology.Algebra.GroupCompletion import Mathlib.Topology.Algebra.GroupWithZero @@ -4280,6 +4485,7 @@ import Mathlib.Topology.Algebra.InfiniteSum.Real import Mathlib.Topology.Algebra.InfiniteSum.Ring import Mathlib.Topology.Algebra.Localization import Mathlib.Topology.Algebra.Module.Alternating.Basic +import Mathlib.Topology.Algebra.Module.Alternating.Topology import Mathlib.Topology.Algebra.Module.Basic import Mathlib.Topology.Algebra.Module.Cardinality import Mathlib.Topology.Algebra.Module.CharacterSpace @@ -4294,6 +4500,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 @@ -4318,6 +4525,7 @@ 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.Star import Mathlib.Topology.Algebra.StarSubalgebra import Mathlib.Topology.Algebra.UniformConvergence @@ -4330,6 +4538,7 @@ import Mathlib.Topology.Algebra.Valued.NormedValued import Mathlib.Topology.Algebra.Valued.ValuationTopology import Mathlib.Topology.Algebra.Valued.ValuedField import Mathlib.Topology.Algebra.WithZeroTopology +import Mathlib.Topology.Baire.BaireMeasurable import Mathlib.Topology.Baire.CompleteMetrizable import Mathlib.Topology.Baire.Lemmas import Mathlib.Topology.Baire.LocallyCompactRegular @@ -4340,6 +4549,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 @@ -4348,12 +4558,14 @@ import Mathlib.Topology.Category.CompHaus.Projective import Mathlib.Topology.Category.CompHausLike.Basic import Mathlib.Topology.Category.CompHausLike.EffectiveEpi import Mathlib.Topology.Category.CompHausLike.Limits +import Mathlib.Topology.Category.CompHausLike.SigmaComparison import Mathlib.Topology.Category.CompactlyGenerated import Mathlib.Topology.Category.Compactum import Mathlib.Topology.Category.FinTopCat import Mathlib.Topology.Category.LightProfinite.AsLimit import Mathlib.Topology.Category.LightProfinite.Basic import Mathlib.Topology.Category.LightProfinite.EffectiveEpi +import Mathlib.Topology.Category.LightProfinite.Extend import Mathlib.Topology.Category.LightProfinite.Limits import Mathlib.Topology.Category.LightProfinite.Sequence import Mathlib.Topology.Category.Locale @@ -4361,6 +4573,7 @@ import Mathlib.Topology.Category.Profinite.AsLimit import Mathlib.Topology.Category.Profinite.Basic import Mathlib.Topology.Category.Profinite.CofilteredLimit import Mathlib.Topology.Category.Profinite.EffectiveEpi +import Mathlib.Topology.Category.Profinite.Extend import Mathlib.Topology.Category.Profinite.Limits import Mathlib.Topology.Category.Profinite.Nobeling import Mathlib.Topology.Category.Profinite.Product @@ -4381,6 +4594,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 @@ -4390,6 +4604,7 @@ import Mathlib.Topology.CompactOpen import Mathlib.Topology.Compactification.OnePoint 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 @@ -4403,24 +4618,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 @@ -4433,14 +4650,19 @@ import Mathlib.Topology.DerivedSet import Mathlib.Topology.DiscreteQuotient import Mathlib.Topology.DiscreteSubset import Mathlib.Topology.EMetricSpace.Basic +import Mathlib.Topology.EMetricSpace.Defs +import Mathlib.Topology.EMetricSpace.Diam 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.Germ @@ -4461,6 +4683,7 @@ import Mathlib.Topology.Instances.CantorSet import Mathlib.Topology.Instances.Complex import Mathlib.Topology.Instances.Discrete import Mathlib.Topology.Instances.ENNReal +import Mathlib.Topology.Instances.ENat import Mathlib.Topology.Instances.EReal import Mathlib.Topology.Instances.Int import Mathlib.Topology.Instances.Irrational @@ -4485,6 +4708,7 @@ 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.UniversallyClosed import Mathlib.Topology.MetricSpace.Algebra @@ -4498,6 +4722,7 @@ import Mathlib.Topology.MetricSpace.Cauchy import Mathlib.Topology.MetricSpace.Closeds import Mathlib.Topology.MetricSpace.Completion import Mathlib.Topology.MetricSpace.Contracting +import Mathlib.Topology.MetricSpace.Defs import Mathlib.Topology.MetricSpace.Dilation import Mathlib.Topology.MetricSpace.DilationEquiv import Mathlib.Topology.MetricSpace.Equicontinuity @@ -4519,14 +4744,19 @@ import Mathlib.Topology.MetricSpace.PiNat import Mathlib.Topology.MetricSpace.Polish import Mathlib.Topology.MetricSpace.ProperSpace import Mathlib.Topology.MetricSpace.ProperSpace.Lemmas +import Mathlib.Topology.MetricSpace.Pseudo.Basic import Mathlib.Topology.MetricSpace.Pseudo.Constructions import Mathlib.Topology.MetricSpace.Pseudo.Defs import Mathlib.Topology.MetricSpace.Pseudo.Lemmas +import Mathlib.Topology.MetricSpace.Pseudo.Pi +import Mathlib.Topology.MetricSpace.Pseudo.Real import Mathlib.Topology.MetricSpace.Sequences 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 @@ -4570,8 +4800,9 @@ 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 @@ -4587,6 +4818,7 @@ import Mathlib.Topology.Sheaves.Init import Mathlib.Topology.Sheaves.Limits import Mathlib.Topology.Sheaves.LocalPredicate import Mathlib.Topology.Sheaves.LocallySurjective +import Mathlib.Topology.Sheaves.MayerVietoris import Mathlib.Topology.Sheaves.Operations import Mathlib.Topology.Sheaves.PUnit import Mathlib.Topology.Sheaves.Presheaf @@ -4621,6 +4853,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 @@ -4634,6 +4867,7 @@ import Mathlib.Topology.VectorBundle.Constructions import Mathlib.Topology.VectorBundle.Hom import Mathlib.Util.AddRelatedDecl import Mathlib.Util.AssertExists +import Mathlib.Util.AssertExistsExt import Mathlib.Util.AssertNoSorry import Mathlib.Util.AtomM import Mathlib.Util.CompileInductive @@ -4653,6 +4887,5 @@ import Mathlib.Util.Superscript import Mathlib.Util.SynthesizeUsing import Mathlib.Util.Tactic import Mathlib.Util.TermBeta -import Mathlib.Util.Time import Mathlib.Util.WhatsNew import Mathlib.Util.WithWeakNamespace diff --git a/Mathlib/Algebra/AddConstMap/Basic.lean b/Mathlib/Algebra/AddConstMap/Basic.lean index cf6f7d5f8a91a..9bed6eb4e7ecd 100644 --- a/Mathlib/Algebra/AddConstMap/Basic.lean +++ b/Mathlib/Algebra/AddConstMap/Basic.lean @@ -21,7 +21,7 @@ such that $\tilde f(x + 1) = \tilde f(x)+1$ for all `x`. In this file we define a structure and a typeclass for bundled maps satisfying `f (x + a) = f x + b`. -We use parameters `a` and `b` instead of `1` to accomodate for two use cases: +We use parameters `a` and `b` instead of `1` to accommodate for two use cases: - maps between circles of different lengths; - self-maps $f\colon S^1\to S^1$ of degree other than one, diff --git a/Mathlib/Algebra/AddTorsor.lean b/Mathlib/Algebra/AddTorsor.lean index c0ef691f61fae..ed65a54d0f15f 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 @@ -247,7 +248,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 96aac9668dc57..f4a24f5977006 100644 --- a/Mathlib/Algebra/Algebra/Basic.lean +++ b/Mathlib/Algebra/Algebra/Basic.lean @@ -23,12 +23,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 +185,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 +194,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 @@ -284,6 +282,16 @@ theorem algebraMap_injective [CommRing R] [Ring A] [Nontrivial A] [Algebra R A] [NoZeroSMulDivisors R A] : Function.Injective (algebraMap R A) := by simpa only [algebraMap_eq_smul_one'] using smul_left_injective R one_ne_zero +@[simp] +lemma algebraMap_eq_zero_iff [CommRing R] [Ring A] [Nontrivial A] [Algebra R A] + [NoZeroSMulDivisors R A] {r : R} : algebraMap R A r = 0 ↔ r = 0 := + map_eq_zero_iff _ <| algebraMap_injective R A + +@[simp] +lemma algebraMap_eq_one_iff [CommRing R] [Ring A] [Nontrivial A] [Algebra R A] + [NoZeroSMulDivisors R A] {r : R} : algebraMap R A r = 1 ↔ r = 1 := + map_eq_one_iff _ <| algebraMap_injective R A + theorem _root_.NeZero.of_noZeroSMulDivisors (n : ℕ) [CommRing R] [NeZero (n : R)] [Ring A] [Nontrivial A] [Algebra R A] [NoZeroSMulDivisors R A] : NeZero (n : A) := NeZero.nat_of_injective <| NoZeroSMulDivisors.algebraMap_injective R A @@ -304,17 +312,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 @@ -322,7 +319,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] @@ -336,7 +332,7 @@ theorem NoZeroSMulDivisors.trans (R A M : Type*) [CommRing R] [Ring A] [IsDomain [NoZeroSMulDivisors A M] : NoZeroSMulDivisors R M := by refine ⟨fun {r m} h => ?_⟩ rw [algebra_compatible_smul A r m] at h - cases' smul_eq_zero.1 h with H H + rcases smul_eq_zero.1 h with H | H · have : Function.Injective (algebraMap R A) := NoZeroSMulDivisors.iff_algebraMap_injective.1 inferInstance left @@ -512,3 +508,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/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 ce14bc0b72a3c..d19412446121d 100644 --- a/Mathlib/Algebra/Algebra/Equiv.lean +++ b/Mathlib/Algebra/Algebra/Equiv.lean @@ -86,6 +86,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 +108,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 +118,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 +128,25 @@ 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 +-- 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 + +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⟩ + +-- Porting note: `toFun_eq_coe` no longer needed in Lean4 + @[simp] theorem toRingEquiv_eq_coe : e.toRingEquiv = e := rfl @@ -173,41 +165,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 +195,65 @@ 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 + +-- @[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_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 +271,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,11 +285,8 @@ 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 theorem coe_apply_coe_coe_symm_apply {F : Type*} [EquivLike F A₁ A₂] [AlgEquivClass F R A₁ A₂] @@ -300,13 +305,8 @@ 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 := by - ext - rfl +theorem symm_symm (e : A₁ ≃ₐ[R] A₂) : e.symm.symm = e := rfl theorem symm_bijective : Function.Bijective (symm : (A₁ ≃ₐ[R] A₂) → A₂ ≃ₐ[R] A₁) := Function.bijective_iff_has_inverse.mpr ⟨_, symm_symm, symm_symm⟩ @@ -316,7 +316,7 @@ theorem mk_coe' (e : A₁ ≃ₐ[R] A₂) (f h₁ h₂ h₃ h₄ h₅) : (⟨⟨f, e, h₁, h₂⟩, h₃, h₄, h₅⟩ : A₂ ≃ₐ[R] A₁) = e.symm := symm_bijective.injective <| ext fun _ => rfl -/-- Auxilliary definition to avoid looping in `dsimp` with `AlgEquiv.symm_mk`. -/ +/-- Auxiliary definition to avoid looping in `dsimp` with `AlgEquiv.symm_mk`. -/ protected def symm_mk.aux (f f') (h₁ h₂ h₃ h₄ h₅) := (⟨⟨f, f', h₁, h₂⟩, h₃, h₄, h₅⟩ : A₁ ≃ₐ[R] A₂).symm @@ -340,12 +340,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 @@ -354,18 +348,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 @@ -383,6 +370,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] @@ -405,21 +437,18 @@ theorem arrowCongr_comp (e₁ : A₁ ≃ₐ[R] A₁') (e₂ : A₂ ≃ₐ[R] A exact (e₂.symm_apply_apply _).symm @[simp] -theorem arrowCongr_refl : arrowCongr AlgEquiv.refl AlgEquiv.refl = Equiv.refl (A₁ →ₐ[R] A₂) := by - ext +theorem arrowCongr_refl : arrowCongr AlgEquiv.refl AlgEquiv.refl = Equiv.refl (A₁ →ₐ[R] A₂) := rfl @[simp] theorem arrowCongr_trans (e₁ : A₁ ≃ₐ[R] A₂) (e₁' : A₁' ≃ₐ[R] A₂') (e₂ : A₂ ≃ₐ[R] A₃) (e₂' : A₂' ≃ₐ[R] A₃') : - arrowCongr (e₁.trans e₂) (e₁'.trans e₂') = (arrowCongr e₁ e₁').trans (arrowCongr e₂ e₂') := by - ext + arrowCongr (e₁.trans e₂) (e₁'.trans e₂') = (arrowCongr e₁ e₁').trans (arrowCongr e₂ e₂') := rfl @[simp] theorem arrowCongr_symm (e₁ : A₁ ≃ₐ[R] A₁') (e₂ : A₂ ≃ₐ[R] A₂') : - (arrowCongr e₁ e₂).symm = arrowCongr e₁.symm e₂.symm := by - ext + (arrowCongr e₁ e₂).symm = arrowCongr e₁.symm e₂.symm := rfl /-- If `A₁` is equivalent to `A₂` and `A₁'` is equivalent to `A₂'`, then the type of maps @@ -438,8 +467,7 @@ def equivCongr (e : A₁ ≃ₐ[R] A₂) (e' : A₁' ≃ₐ[R] A₂') : (A₁ simp_rw [trans_apply, apply_symm_apply] @[simp] -theorem equivCongr_refl : equivCongr AlgEquiv.refl AlgEquiv.refl = Equiv.refl (A₁ ≃ₐ[R] A₁') := by - ext +theorem equivCongr_refl : equivCongr AlgEquiv.refl AlgEquiv.refl = Equiv.refl (A₁ ≃ₐ[R] A₁') := rfl @[simp] @@ -466,7 +494,7 @@ def ofAlgHom (f : A₁ →ₐ[R] A₂) (g : A₂ →ₐ[R] A₁) (h₁ : f.comp theorem coe_algHom_ofAlgHom (f : A₁ →ₐ[R] A₂) (g : A₂ →ₐ[R] A₁) (h₁ h₂) : ↑(ofAlgHom f g h₁ h₂) = f := - AlgHom.ext fun _ => rfl + rfl @[simp] theorem ofAlgHom_coe_algHom (f : A₁ ≃ₐ[R] A₂) (g : A₂ →ₐ[R] A₁) (h₁ h₂) : @@ -558,7 +586,7 @@ def ofLinearEquiv : A₁ ≃ₐ[R] A₂ := map_mul' := map_mul commutes' := (AlgHom.ofLinearMap l map_one map_mul : A₁ →ₐ[R] A₂).commutes } -/-- Auxilliary definition to avoid looping in `dsimp` with `AlgEquiv.ofLinearEquiv_symm`. -/ +/-- Auxiliary definition to avoid looping in `dsimp` with `AlgEquiv.ofLinearEquiv_symm`. -/ protected def ofLinearEquiv_symm.aux := (ofLinearEquiv l map_one map_mul).symm @[simp] @@ -571,13 +599,11 @@ theorem ofLinearEquiv_symm : @[simp] theorem ofLinearEquiv_toLinearEquiv (map_mul) (map_one) : - ofLinearEquiv e.toLinearEquiv map_mul map_one = e := by - ext + ofLinearEquiv e.toLinearEquiv map_mul map_one = e := rfl @[simp] -theorem toLinearEquiv_ofLinearEquiv : toLinearEquiv (ofLinearEquiv l map_one map_mul) = l := by - ext +theorem toLinearEquiv_ofLinearEquiv : toLinearEquiv (ofLinearEquiv l map_one map_mul) = l := rfl end OfLinearEquiv @@ -633,9 +659,7 @@ def autCongr (ϕ : A₁ ≃ₐ[R] A₂) : (A₁ ≃ₐ[R] A₁) ≃* A₂ ≃ₐ simp only [mul_apply, trans_apply, symm_apply_apply] @[simp] -theorem autCongr_refl : autCongr AlgEquiv.refl = MulEquiv.refl (A₁ ≃ₐ[R] A₁) := by - ext - rfl +theorem autCongr_refl : autCongr AlgEquiv.refl = MulEquiv.refl (A₁ ≃ₐ[R] A₁) := rfl @[simp] theorem autCongr_symm (ϕ : A₁ ≃ₐ[R] A₂) : (autCongr ϕ).symm = autCongr ϕ.symm := diff --git a/Mathlib/Algebra/Algebra/Hom.lean b/Mathlib/Algebra/Algebra/Hom.lean index e82539f2a9c02..0942b526635de 100644 --- a/Mathlib/Algebra/Algebra/Hom.lean +++ b/Mathlib/Algebra/Algebra/Hom.lean @@ -39,7 +39,7 @@ infixr:25 " →ₐ " => AlgHom _ notation:25 A " →ₐ[" R "] " B => AlgHom R A B /-- `AlgHomClass F R A B` asserts `F` is a type of bundled algebra homomorphisms -from `A` to `B`. -/ +from `A` to `B`. -/ class AlgHomClass (F : Type*) (R A B : outParam Type*) [CommSemiring R] [Semiring A] [Semiring B] [Algebra R A] [Algebra R B] [FunLike F A B] extends RingHomClass F A B : Prop where @@ -192,7 +192,7 @@ theorem ext {φ₁ φ₂ : A →ₐ[R] B} (H : ∀ x, φ₁ x = φ₂ x) : φ₁ @[simp] theorem mk_coe {f : A →ₐ[R] B} (h₁ h₂ h₃ h₄ h₅) : (⟨⟨⟨⟨f, h₁⟩, h₂⟩, h₃, h₄⟩, h₅⟩ : A →ₐ[R] B) = f := - ext fun _ => rfl + rfl @[simp] theorem commutes (r : R) : φ (algebraMap R A r) = algebraMap R B r := @@ -285,15 +285,15 @@ theorem comp_toRingHom (φ₁ : B →ₐ[R] C) (φ₂ : A →ₐ[R] B) : @[simp] theorem comp_id : φ.comp (AlgHom.id R A) = φ := - ext fun _x => rfl + rfl @[simp] theorem id_comp : (AlgHom.id R B).comp φ = φ := - ext fun _x => rfl + rfl theorem comp_assoc (φ₁ : C →ₐ[R] D) (φ₂ : B →ₐ[R] C) (φ₃ : A →ₐ[R] B) : (φ₁.comp φ₂).comp φ₃ = φ₁.comp (φ₂.comp φ₃) := - ext fun _x => rfl + rfl /-- R-Alg ⥤ R-Mod -/ def toLinearMap : A →ₗ[R] B where @@ -316,7 +316,7 @@ theorem comp_toLinearMap (f : A →ₐ[R] B) (g : B →ₐ[R] C) : @[simp] theorem toLinearMap_id : toLinearMap (AlgHom.id R A) = LinearMap.id := - LinearMap.ext fun _ => rfl + rfl /-- Promote a `LinearMap` to an `AlgHom` by supplying proofs about the behavior on `1` and `*`. -/ @[simps] @@ -330,20 +330,18 @@ def ofLinearMap (f : A →ₗ[R] B) (map_one : f 1 = 1) (map_mul : ∀ x y, f (x @[simp] theorem ofLinearMap_toLinearMap (map_one) (map_mul) : - ofLinearMap φ.toLinearMap map_one map_mul = φ := by - ext + ofLinearMap φ.toLinearMap map_one map_mul = φ := rfl @[simp] theorem toLinearMap_ofLinearMap (f : A →ₗ[R] B) (map_one) (map_mul) : - toLinearMap (ofLinearMap f map_one map_mul) = f := by - ext + toLinearMap (ofLinearMap f map_one map_mul) = f := rfl @[simp] theorem ofLinearMap_id (map_one) (map_mul) : ofLinearMap LinearMap.id map_one map_mul = AlgHom.id R A := - ext fun _ => rfl + rfl theorem map_smul_of_tower {R'} [SMul R' A] [SMul R' B] [LinearMap.CompatibleSMul A B R' R] (r : R') (x : A) : φ (r • x) = r • φ x := @@ -358,8 +356,8 @@ instance End : Monoid (A →ₐ[R] A) where mul := comp mul_assoc ϕ ψ χ := rfl one := AlgHom.id R A - one_mul ϕ := ext fun x => rfl - mul_one ϕ := ext fun x => rfl + one_mul ϕ := rfl + mul_one ϕ := rfl @[simp] theorem one_apply (x : A) : (1 : A →ₐ[R] A) x = x := @@ -423,11 +421,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) @@ -458,11 +470,11 @@ theorem ext_id (f g : R →ₐ[R] A) : f = g := Subsingleton.elim _ _ section MulDistribMulAction instance : MulDistribMulAction (A →ₐ[R] A) Aˣ where - smul := fun f => Units.map f - one_smul := fun x => by ext; rfl - mul_smul := fun x y z => by ext; rfl - smul_mul := fun x y z => by ext; exact map_mul _ _ _ - smul_one := fun x => by ext; exact map_one _ + smul f := Units.map f + one_smul _ := by ext; rfl + mul_smul _ _ _ := by ext; rfl + smul_mul _ _ _ := by ext; exact map_mul _ _ _ + smul_one _ := by ext; exact map_one _ @[simp] theorem smul_units_def (f : A →ₐ[R] A) (x : Aˣ) : diff --git a/Mathlib/Algebra/Algebra/NonUnitalHom.lean b/Mathlib/Algebra/Algebra/NonUnitalHom.lean index 5df753173fa61..34a5518dc4de3 100644 --- a/Mathlib/Algebra/Algebra/NonUnitalHom.lean +++ b/Mathlib/Algebra/Algebra/NonUnitalHom.lean @@ -64,7 +64,7 @@ notation:25 A " →ₙₐ[" R "] " B => NonUnitalAlgHom (MonoidHom.id R) A B attribute [nolint docBlame] NonUnitalAlgHom.toMulHom /-- `NonUnitalAlgSemiHomClass F φ A B` asserts `F` is a type of bundled algebra homomorphisms -from `A` to `B` which are equivariant with respect to `φ`. -/ +from `A` to `B` which are equivariant with respect to `φ`. -/ class NonUnitalAlgSemiHomClass (F : Type*) {R S : outParam Type*} [Monoid R] [Monoid S] (φ : outParam (R →* S)) (A B : outParam Type*) [NonUnitalNonAssocSemiring A] [NonUnitalNonAssocSemiring B] @@ -383,7 +383,7 @@ variable [DistribMulAction R C] @[simps] def prod (f : A →ₙₐ[R] B) (g : A →ₙₐ[R] C) : A →ₙₐ[R] B × C where toFun := Pi.prod f g - map_zero' := by simp only [Pi.prod, Prod.zero_eq_mk, map_zero] + map_zero' := by simp only [Pi.prod, Prod.mk_zero_zero, map_zero] map_add' x y := by simp only [Pi.prod, Prod.mk_add_mk, map_add] map_mul' x y := by simp only [Pi.prod, Prod.mk_mul_mk, map_mul] map_smul' c x := by simp only [Pi.prod, map_smul, MonoidHom.id_apply, id_eq, Prod.smul_mk] @@ -483,7 +483,7 @@ variable (R : Type*) {S A B : Type*} [Monoid R] [Monoid S] [IsScalarTower R S A] [IsScalarTower R S B] /-- If a monoid `R` acts on another monoid `S`, then a non-unital algebra homomorphism -over `S` can be viewed as a non-unital algebra homomorphism over `R`. -/ +over `S` can be viewed as a non-unital algebra homomorphism over `R`. -/ def restrictScalars (f : A →ₙₐ[S] B) : A →ₙₐ[R] B := { (f : A →ₙ+* B) with map_smul' := fun r x ↦ by have := map_smul f (r • 1) x; simpa } diff --git a/Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean b/Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean index 1bc3dc1438938..d7beda182c549 100644 --- a/Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean +++ b/Mathlib/Algebra/Algebra/NonUnitalSubalgebra.lean @@ -458,7 +458,7 @@ def codRestrict (f : F) (S : NonUnitalSubalgebra R B) (hf : ∀ x, f x ∈ S) : @[simp] theorem subtype_comp_codRestrict (f : F) (S : NonUnitalSubalgebra R B) (hf : ∀ x : A, f x ∈ S) : (NonUnitalSubalgebraClass.subtype S).comp (NonUnitalAlgHom.codRestrict f S hf) = f := - NonUnitalAlgHom.ext fun _ => rfl + rfl @[simp] theorem coe_codRestrict (f : F) (S : NonUnitalSubalgebra R B) (hf : ∀ x, f x ∈ S) (x : A) : @@ -726,6 +726,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 +773,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 := @@ -906,7 +918,7 @@ theorem inclusion_injective {S T : NonUnitalSubalgebra R A} (h : S ≤ T) : @[simp] theorem inclusion_self {S : NonUnitalSubalgebra R A} : inclusion (le_refl S) = NonUnitalAlgHom.id R S := - NonUnitalAlgHom.ext fun _ => Subtype.ext rfl + rfl @[simp] theorem inclusion_mk {S T : NonUnitalSubalgebra R A} (h : S ≤ T) (x : A) (hx : x ∈ S) : diff --git a/Mathlib/Algebra/Algebra/Operations.lean b/Mathlib/Algebra/Algebra/Operations.lean index 668fb28578148..15f0ec29f05ab 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.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 @@ -359,12 +359,12 @@ theorem mul_smul_mul_eq_smul_mul_smul (x y : R) : (x * y) • (M * N) = (x • M · rintro ⟨_, hx, rfl⟩ rw [DistribMulAction.toLinearMap_apply] refine Submodule.mul_induction_on hx (fun m hm n hn ↦ ?_) (fun _ _ hn hm ↦ ?_) - · rw [← smul_mul_smul x y m n] + · rw [mul_smul_mul_comm] exact mul_mem_mul (smul_mem_pointwise_smul m x M hm) (smul_mem_pointwise_smul n y N hn) · rw [smul_add] exact Submodule.add_mem _ hn hm · rintro _ ⟨m, hm, rfl⟩ _ ⟨n, hn, rfl⟩ - erw [smul_mul_smul x y m 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. -/ @@ -422,15 +422,15 @@ protected theorem pow_induction_on_left' {C : ∀ (n : ℕ) (x), x ∈ M ^ n → -- Porting note: swapped argument order to match order of `C` {n : ℕ} {x : A} (hx : x ∈ M ^ n) : C n x hx := by - induction' n with n n_ih generalizing x - · rw [pow_zero] at hx + induction n generalizing x with + | zero => + rw [pow_zero] at hx obtain ⟨r, rfl⟩ := hx exact algebraMap r - revert hx - simp_rw [pow_succ'] - intro hx - exact - Submodule.mul_induction_on' (fun m hm x ih => mem_mul _ hm _ _ _ (n_ih ih)) + | succ n n_ih => + revert hx + simp_rw [pow_succ'] + exact fun hx ↦ Submodule.mul_induction_on' (fun m hm x ih => mem_mul _ hm _ _ _ (n_ih ih)) (fun x hx y hy Cx Cy => add _ _ _ _ _ Cx Cy) hx /-- Dependent version of `Submodule.pow_induction_on_right`. -/ @@ -443,15 +443,15 @@ protected theorem pow_induction_on_right' {C : ∀ (n : ℕ) (x), x ∈ M ^ n ∀ m (hm : m ∈ M), C i.succ (x * m) (mul_mem_mul hx hm)) -- Porting note: swapped argument order to match order of `C` {n : ℕ} {x : A} (hx : x ∈ M ^ n) : C n x hx := by - induction' n with n n_ih generalizing x - · rw [pow_zero] at hx + induction n generalizing x with + | zero => + rw [pow_zero] at hx obtain ⟨r, rfl⟩ := hx exact algebraMap r - revert hx - simp_rw [pow_succ] - intro hx - exact - Submodule.mul_induction_on' (fun m hm x ih => mul_mem _ _ hm (n_ih _) _ ih) + | succ n n_ih => + revert hx + simp_rw [pow_succ] + exact fun hx ↦ Submodule.mul_induction_on' (fun m hm x ih => mul_mem _ _ hm (n_ih _) _ ih) (fun x hx y hy Cx Cy => add _ _ _ _ _ Cx Cy) hx /-- To show a property on elements of `M ^ n` holds, it suffices to show that it holds for scalars, diff --git a/Mathlib/Algebra/Algebra/Quasispectrum.lean b/Mathlib/Algebra/Algebra/Quasispectrum.lean index cb01e4b60ed6e..33a5807e877b8 100644 --- a/Mathlib/Algebra/Algebra/Quasispectrum.lean +++ b/Mathlib/Algebra/Algebra/Quasispectrum.lean @@ -259,6 +259,30 @@ instance quasispectrum.instZero [Nontrivial R] (a : A) : Zero (quasispectrum R a variable {R} +/-- A version of `NonUnitalAlgHom.quasispectrum_apply_subset` which allows for `quasispectrum R`, +where `R` is a *semi*ring, but `φ` must still function over a scalar ring `S`. In this case, we +need `S` to be explicit. The primary use case is, for instance, `R := ℝ≥0` and `S := ℝ` or +`S := ℂ`. -/ +lemma NonUnitalAlgHom.quasispectrum_apply_subset' {F R : Type*} (S : Type*) {A B : Type*} + [CommSemiring R] [CommRing S] [NonUnitalRing A] [NonUnitalRing B] [Module R S] + [Module S A] [Module R A] [Module S B] [Module R B] [IsScalarTower R S A] [IsScalarTower R S B] + [FunLike F A B] [NonUnitalAlgHomClass F S A B] (φ : F) (a : A) : + quasispectrum R (φ a) ⊆ quasispectrum R a := by + refine Set.compl_subset_compl.mp fun x ↦ ?_ + simp only [quasispectrum, Set.mem_compl_iff, Set.mem_setOf_eq, not_forall, not_not, + forall_exists_index] + refine fun hx this ↦ ⟨hx, ?_⟩ + rw [Units.smul_def, ← smul_one_smul S] at this ⊢ + simpa [- smul_assoc] using this.map φ + +/-- If `φ` is non-unital algebra homomorphism over a scalar ring `R`, then +`quasispectrum R (φ a) ⊆ quasispectrum R a`. -/ +lemma NonUnitalAlgHom.quasispectrum_apply_subset {F R A B : Type*} + [CommRing R] [NonUnitalRing A] [NonUnitalRing B] [Module R A] [Module R B] + [FunLike F A B] [NonUnitalAlgHomClass F R A B] (φ : F) (a : A) : + quasispectrum R (φ a) ⊆ quasispectrum R a := + NonUnitalAlgHom.quasispectrum_apply_subset' R φ a + @[simp] lemma quasispectrum.coe_zero [Nontrivial R] (a : A) : (0 : quasispectrum R a) = (0 : R) := rfl @@ -312,7 +336,7 @@ 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 diff --git a/Mathlib/Algebra/Algebra/Rat.lean b/Mathlib/Algebra/Algebra/Rat.lean index 6ad708e5d3439..ed05e1a90ee28 100644 --- a/Mathlib/Algebra/Algebra/Rat.lean +++ b/Mathlib/Algebra/Algebra/Rat.lean @@ -3,8 +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, Yury Kudryashov -/ -import Mathlib.Data.Rat.Cast.CharZero import Mathlib.Algebra.Algebra.Defs +import Mathlib.Algebra.GroupWithZero.Action.Basic +import Mathlib.Data.Rat.Cast.CharZero /-! # Further basic results about `Algebra`'s over `ℚ`. @@ -12,9 +13,9 @@ import Mathlib.Algebra.Algebra.Defs This file could usefully be split further. -/ -namespace RingHom +variable {F R S : Type*} -variable {R S : Type*} +namespace RingHom -- Porting note: changed `[Ring R] [Ring S]` to `[Semiring R] [Semiring S]` -- otherwise, Lean failed to find a `Subsingleton (ℚ →+* S)` instance @@ -25,26 +26,89 @@ theorem map_rat_algebraMap [Semiring R] [Semiring S] [Algebra ℚ R] [Algebra end RingHom -section Rat +namespace NNRat +variable [DivisionSemiring R] [CharZero R] + +section Semiring +variable [Semiring S] [Module ℚ≥0 S] + +variable (R) in +/-- `nnqsmul` is equal to any other module structure via a cast. -/ +lemma cast_smul_eq_nnqsmul [Module R S] (q : ℚ≥0) (a : S) : (q : R) • a = q • a := by + refine MulAction.injective₀ (G₀ := ℚ≥0) (Nat.cast_ne_zero.2 q.den_pos.ne') ?_ + dsimp + rw [← mul_smul, den_mul_eq_num, Nat.cast_smul_eq_nsmul, Nat.cast_smul_eq_nsmul, ← smul_assoc, + nsmul_eq_mul q.den, ← cast_natCast, ← cast_mul, den_mul_eq_num, cast_natCast, + Nat.cast_smul_eq_nsmul] + +end Semiring + +section DivisionSemiring +variable [DivisionSemiring S] [CharZero S] + +instance _root_.DivisionSemiring.toNNRatAlgebra : Algebra ℚ≥0 R where + smul_def' := smul_def + toRingHom := castHom _ + commutes' := cast_commute + +instance _root_.RingHomClass.toLinearMapClassNNRat [FunLike F R S] [RingHomClass F R S] : + LinearMapClass F ℚ≥0 R S where + map_smulₛₗ f q a := by simp [smul_def, cast_id] + +variable [SMul R S] + +instance instSMulCommClass [SMulCommClass R S S] : SMulCommClass ℚ≥0 R S where + smul_comm q a b := by simp [smul_def, mul_smul_comm] + +instance instSMulCommClass' [SMulCommClass S R S] : SMulCommClass R ℚ≥0 S := + have := SMulCommClass.symm S R S; SMulCommClass.symm _ _ _ + +end DivisionSemiring +end NNRat + +namespace Rat +variable [DivisionRing R] [CharZero R] + +section Ring +variable [Ring S] [Module ℚ S] + +variable (R) in +/-- `nnqsmul` is equal to any other module structure via a cast. -/ +lemma cast_smul_eq_qsmul [Module R S] (q : ℚ) (a : S) : (q : R) • a = q • a := by + refine MulAction.injective₀ (G₀ := ℚ) (Nat.cast_ne_zero.2 q.den_pos.ne') ?_ + dsimp + rw [← mul_smul, den_mul_eq_num, Nat.cast_smul_eq_nsmul, Int.cast_smul_eq_zsmul, ← smul_assoc, + nsmul_eq_mul q.den, ← cast_natCast, ← cast_mul, den_mul_eq_num, cast_intCast, + Int.cast_smul_eq_zsmul] + +end Ring + +section DivisionRing +variable [DivisionRing S] [CharZero S] + +instance _root_.DivisionRing.toRatAlgebra : Algebra ℚ R where + smul_def' := smul_def + toRingHom := castHom _ + commutes' := cast_commute + +instance _root_.RingHomClass.toLinearMapClassRat [FunLike F R S] [RingHomClass F R S] : + LinearMapClass F ℚ R S where + map_smulₛₗ f q a := by simp [smul_def, cast_id] + +variable [SMul R S] -/-- Every division ring of characteristic zero is an algebra over the rationals. -/ -instance DivisionRing.toRatAlgebra {α} [DivisionRing α] [CharZero α] : Algebra ℚ α where - smul := (· • ·) - smul_def' := Rat.smul_def - toRingHom := Rat.castHom α - commutes' := Rat.cast_commute +instance instSMulCommClass [SMulCommClass R S S] : SMulCommClass ℚ R S where + smul_comm q a b := by simp [smul_def, mul_smul_comm] -/-- The rational numbers are an algebra over the non-negative rationals. -/ -instance : Algebra NNRat ℚ := - NNRat.coeHom.toAlgebra +instance instSMulCommClass' [SMulCommClass S R S] : SMulCommClass R ℚ S := + have := SMulCommClass.symm S R S; SMulCommClass.symm _ _ _ -/-- The two `Algebra ℚ ℚ` instances should coincide. -/ -example : DivisionRing.toRatAlgebra = Algebra.id ℚ := - rfl +end DivisionRing -@[simp] theorem algebraMap_rat_rat : algebraMap ℚ ℚ = RingHom.id ℚ := rfl +@[deprecated Algebra.id.map_eq_id (since := "2024-07-30")] +lemma _root_.algebraMap_rat_rat : algebraMap ℚ ℚ = RingHom.id ℚ := rfl -instance algebra_rat_subsingleton {α} [Semiring α] : Subsingleton (Algebra ℚ α) := +instance algebra_rat_subsingleton {R} [Semiring R] : Subsingleton (Algebra ℚ R) := ⟨fun x y => Algebra.algebra_ext x y <| RingHom.congr_fun <| Subsingleton.elim _ _⟩ end Rat diff --git a/Mathlib/Algebra/Algebra/Spectrum.lean b/Mathlib/Algebra/Algebra/Spectrum.lean index 933fc61e08ab6..65c69f706fb00 100644 --- a/Mathlib/Algebra/Algebra/Spectrum.lean +++ b/Mathlib/Algebra/Algebra/Spectrum.lean @@ -53,7 +53,7 @@ local notation "↑ₐ" => algebraMap R A -- definition and basic properties /-- Given a commutative ring `R` and an `R`-algebra `A`, the *resolvent set* of `a : A` is the `Set R` consisting of those `r : R` for which `r•1 - a` is a unit of the -algebra `A`. -/ +algebra `A`. -/ def resolventSet (a : A) : Set R := {r : R | IsUnit (↑ₐ r - a)} @@ -61,7 +61,7 @@ def resolventSet (a : A) : Set R := is the `Set R` consisting of those `r : R` for which `r•1 - a` is not a unit of the algebra `A`. -The spectrum is simply the complement of the resolvent set. -/ +The spectrum is simply the complement of the resolvent set. -/ def spectrum (a : A) : Set R := (resolventSet R a)ᶜ @@ -113,6 +113,10 @@ theorem zero_not_mem_iff {a : A} : (0 : R) ∉ σ a ↔ IsUnit a := by alias ⟨isUnit_of_zero_not_mem, zero_not_mem⟩ := spectrum.zero_not_mem_iff +@[simp] +lemma _root_.Units.zero_not_mem_spectrum (a : Aˣ) : 0 ∉ spectrum R (a : A) := + spectrum.zero_not_mem R a.isUnit + lemma subset_singleton_zero_compl {a : A} (ha : IsUnit a) : spectrum R a ⊆ {0}ᶜ := Set.subset_compl_singleton_iff.mpr <| spectrum.zero_not_mem R ha @@ -295,6 +299,27 @@ theorem sub_singleton_eq (a : A) (r : R) : σ a - {r} = σ (a - ↑ₐ r) := by end ScalarRing +section ScalarSemifield + +variable {R : Type u} {A : Type v} [Semifield R] [Ring A] [Algebra R A] + +@[simp] +lemma inv₀_mem_iff {r : R} {a : Aˣ} : + r⁻¹ ∈ spectrum R (a : A) ↔ r ∈ spectrum R (↑a⁻¹ : A) := by + obtain (rfl | hr) := eq_or_ne r 0 + · simp [zero_mem_iff] + · lift r to Rˣ using hr.isUnit + simp [inv_mem_iff] + +lemma inv₀_mem_inv_iff {r : R} {a : Aˣ} : + r⁻¹ ∈ spectrum R (↑a⁻¹ : A) ↔ r ∈ spectrum R (a : A) := by + simp + +alias ⟨of_inv₀_mem, inv₀_mem⟩ := inv₀_mem_iff +alias ⟨of_inv₀_mem_inv, inv₀_mem_inv⟩ := inv₀_mem_inv_iff + +end ScalarSemifield + section ScalarField variable {𝕜 : Type u} {A : Type v} @@ -375,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 81ea05a0347ff..311a49067acad 100644 --- a/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean +++ b/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean @@ -241,7 +241,7 @@ def toSubmodule : Subalgebra R A ↪o Submodule R A where map_rel_iff' := SetLike.coe_subset_coe.symm.trans SetLike.coe_subset_coe /- TODO: bundle other forgetful maps between algebraic substructures, e.g. - `to_subsemiring` and `to_subring` in this file. -/ + `toSubsemiring` and `toSubring` in this file. -/ @[simp] theorem mem_toSubmodule {x} : x ∈ (toSubmodule S) ↔ x ∈ S := Iff.rfl @@ -678,6 +678,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 @@ -718,6 +721,11 @@ 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) : @@ -802,7 +810,7 @@ variable (S : Subalgebra R A) This is the algebra version of `Submodule.topEquiv`. -/ @[simps!] def topEquiv : (⊤ : Subalgebra R A) ≃ₐ[R] A := - AlgEquiv.ofAlgHom (Subalgebra.val ⊤) toTop rfl <| AlgHom.ext fun _ => Subtype.ext rfl + AlgEquiv.ofAlgHom (Subalgebra.val ⊤) toTop rfl rfl instance subsingleton_of_subsingleton [Subsingleton A] : Subsingleton (Subalgebra R A) := ⟨fun B C => ext fun x => by simp only [Subsingleton.elim x 0, zero_mem B, zero_mem C]⟩ @@ -1127,10 +1135,10 @@ section Equalizer namespace AlgHom variable {R A B : Type*} [CommSemiring R] [Semiring A] [Algebra R A] [Semiring B] [Algebra R B] -variable {F : Type*} [FunLike F A B] [AlgHomClass F R A B] +variable {F : Type*} /-- The equalizer of two R-algebra homomorphisms -/ -def equalizer (ϕ ψ : F) : Subalgebra R A where +def equalizer (ϕ ψ : F) [FunLike F A B] [AlgHomClass F R A B] : Subalgebra R A where carrier := { a | ϕ a = ψ a } zero_mem' := by simp only [Set.mem_setOf_eq, map_zero] one_mem' := by simp only [Set.mem_setOf_eq, map_one] @@ -1141,6 +1149,8 @@ def equalizer (ϕ ψ : F) : Subalgebra R A where algebraMap_mem' x := by simp only [Set.mem_setOf_eq, AlgHomClass.commutes] +variable [FunLike F A B] [AlgHomClass F R A B] + @[simp] theorem mem_equalizer (φ ψ : F) (x : A) : x ∈ equalizer φ ψ ↔ φ x = ψ x := Iff.rfl diff --git a/Mathlib/Algebra/Algebra/Subalgebra/IsSimpleOrder.lean b/Mathlib/Algebra/Algebra/Subalgebra/IsSimpleOrder.lean new file mode 100644 index 0000000000000..2c9016caf3b6c --- /dev/null +++ b/Mathlib/Algebra/Algebra/Subalgebra/IsSimpleOrder.lean @@ -0,0 +1,33 @@ +/- +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.LinearAlgebra.FiniteDimensional.Defs +import Mathlib.LinearAlgebra.Dimension.FreeAndStrongRankCondition +import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition + +/-! +If `A` is a domain, and a finite-dimensional algebra over a field `F`, with prime dimension, +then there are no non-trivial `F`-subalgebras. +-/ + +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) := + { toNontrivial := + ⟨⟨⊥, ⊤, fun he => + Nat.not_prime_one ((Subalgebra.bot_eq_top_iff_finrank_eq_one.1 he).subst hp)⟩⟩ + eq_bot_or_eq_top := fun K => by + haveI : FiniteDimensional _ _ := .of_finrank_pos hp.pos + letI := divisionRingOfFiniteDimensional F K + refine (hp.eq_one_or_self_of_dvd _ ⟨_, (finrank_mul_finrank F K A).symm⟩).imp ?_ fun h => ?_ + · exact fun h' => Subalgebra.eq_bot_of_finrank_one h' + · exact + Algebra.toSubmodule_eq_top.1 (eq_top_of_finrank_eq <| K.finrank_toSubmodule.trans h) } +-- TODO: `IntermediateField` version + +@[deprecated (since := "2024-08-11")] +alias FiniteDimensional.Subalgebra.is_simple_order_of_finrank_prime := + Subalgebra.isSimpleOrder_of_finrank_prime diff --git a/Mathlib/Algebra/Algebra/Subalgebra/Operations.lean b/Mathlib/Algebra/Algebra/Subalgebra/Operations.lean index 8d05a87504817..b28a1c2c1dc76 100644 --- a/Mathlib/Algebra/Algebra/Subalgebra/Operations.lean +++ b/Mathlib/Algebra/Algebra/Subalgebra/Operations.lean @@ -67,7 +67,7 @@ theorem mem_of_finset_sum_eq_one_of_pow_smul_mem exact ⟨⟨_, hn i⟩, rfl⟩ theorem mem_of_span_eq_top_of_smul_pow_mem - (s : Set S) (l : s →₀ S) (hs : Finsupp.total s S S (↑) l = 1) + (s : Set S) (l : s →₀ S) (hs : Finsupp.linearCombination S ((↑) : s → S) l = 1) (hs' : s ⊆ S') (hl : ∀ i, l i ∈ S') (x : S) (H : ∀ r : s, ∃ n : ℕ, (r : S) ^ n • x ∈ S') : x ∈ S' := mem_of_finset_sum_eq_one_of_pow_smul_mem S' l.support (↑) l hs (fun x => hs' x.2) hl x H diff --git a/Mathlib/Algebra/Algebra/Subalgebra/Pointwise.lean b/Mathlib/Algebra/Algebra/Subalgebra/Pointwise.lean index 2bdc15557b29d..6328cb01ad700 100644 --- a/Mathlib/Algebra/Algebra/Subalgebra/Pointwise.lean +++ b/Mathlib/Algebra/Algebra/Subalgebra/Pointwise.lean @@ -49,7 +49,7 @@ theorem mul_toSubmodule {R : Type*} {A : Type*} [CommSemiring R] [CommSemiring A refine Algebra.adjoin_induction hx (fun x hx => ?_) (fun r => ?_) (fun _ _ => Submodule.add_mem _) fun x y hx hy => ?_ - · cases' hx with hxS hxT + · rcases hx with hxS | hxT · rw [← mul_one x] exact Submodule.mul_mem_mul hxS (show (1 : A) ∈ T from one_mem T) · rw [← one_mul x] 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/Subalgebra/Unitization.lean b/Mathlib/Algebra/Algebra/Subalgebra/Unitization.lean index f8a6bb3e6e61e..2cacd22757a8c 100644 --- a/Mathlib/Algebra/Algebra/Subalgebra/Unitization.lean +++ b/Mathlib/Algebra/Algebra/Subalgebra/Unitization.lean @@ -148,14 +148,15 @@ theorem _root_.AlgHomClass.unitization_injective' {F R S A : Type*} [CommRing R] [FunLike F (Unitization R s) A] [AlgHomClass F R (Unitization R s) A] (f : F) (hf : ∀ x : s, f x = x) : Function.Injective f := by refine (injective_iff_map_eq_zero f).mpr fun x hx => ?_ - induction' x with r a - simp_rw [map_add, hf, ← Unitization.algebraMap_eq_inl, AlgHomClass.commutes] at hx - rw [add_eq_zero_iff_eq_neg] at hx ⊢ - by_cases hr : r = 0 - · ext - · simp [hr] - · simpa [hr] using hx - · exact (h r hr <| hx ▸ (neg_mem a.property)).elim + induction x with + | inl_add_inr r a => + simp_rw [map_add, hf, ← Unitization.algebraMap_eq_inl, AlgHomClass.commutes] at hx + rw [add_eq_zero_iff_eq_neg] at hx ⊢ + by_cases hr : r = 0 + · ext + · simp [hr] + · simpa [hr] using hx + · exact (h r hr <| hx ▸ (neg_mem a.property)).elim /-- This is a generic version which allows us to prove both `NonUnitalSubalgebra.unitization_injective` and `NonUnitalStarSubalgebra.unitization_injective`. -/ diff --git a/Mathlib/Algebra/Algebra/Unitization.lean b/Mathlib/Algebra/Algebra/Unitization.lean index 886c96c934125..42a25ab336b19 100644 --- a/Mathlib/Algebra/Algebra/Unitization.lean +++ b/Mathlib/Algebra/Algebra/Unitization.lean @@ -561,14 +561,16 @@ variable (S R A : Type*) [CommSemiring S] [CommSemiring R] [NonUnitalSemiring A] instance instAlgebra : Algebra S (Unitization R A) := { (Unitization.inlRingHom R A).comp (algebraMap S R) with commutes' := fun s x => by - induction' x with r a - show inl (algebraMap S R s) * _ = _ * inl (algebraMap S R s) - rw [mul_add, add_mul, inl_mul_inl, inl_mul_inl, inl_mul_inr, inr_mul_inl, mul_comm] + induction x with + | inl_add_inr => + show inl (algebraMap S R s) * _ = _ * inl (algebraMap S R s) + rw [mul_add, add_mul, inl_mul_inl, inl_mul_inl, inl_mul_inr, inr_mul_inl, mul_comm] smul_def' := fun s x => by - induction' x with r a - show _ = inl (algebraMap S R s) * _ - rw [mul_add, smul_add,Algebra.algebraMap_eq_smul_one, inl_mul_inl, inl_mul_inr, smul_one_mul, - inl_smul, inr_smul, smul_one_smul] } + induction x with + | inl_add_inr => + show _ = inl (algebraMap S R s) * _ + rw [mul_add, smul_add,Algebra.algebraMap_eq_smul_one, inl_mul_inl, inl_mul_inr, + smul_one_mul, inl_smul, inr_smul, smul_one_smul] } theorem algebraMap_eq_inl_comp : ⇑(algebraMap S (Unitization R A)) = inl ∘ algebraMap S R := rfl @@ -668,20 +670,24 @@ def _root_.NonUnitalAlgHom.toAlgHom (φ : A →ₙₐ[R] C) : Unitization R A toFun := fun x => algebraMap R C x.fst + φ x.snd map_one' := by simp only [fst_one, map_one, snd_one, φ.map_zero, add_zero] map_mul' := fun x y => by - induction' x with x_r x_a - induction' y with y_r y_a - simp only [fst_mul, fst_add, fst_inl, fst_inr, snd_mul, snd_add, snd_inl, snd_inr, add_zero, - map_mul, zero_add, map_add, map_smul φ] - rw [add_mul, mul_add, mul_add] - rw [← Algebra.commutes _ (φ x_a)] - simp only [Algebra.algebraMap_eq_smul_one, smul_one_mul, add_assoc] + induction x with + | inl_add_inr x_r x_a => + induction y with + | inl_add_inr => + simp only [fst_mul, fst_add, fst_inl, fst_inr, snd_mul, snd_add, snd_inl, snd_inr, add_zero, + map_mul, zero_add, map_add, map_smul φ] + rw [add_mul, mul_add, mul_add] + rw [← Algebra.commutes _ (φ x_a)] + simp only [Algebra.algebraMap_eq_smul_one, smul_one_mul, add_assoc] map_zero' := by simp only [fst_zero, map_zero, snd_zero, φ.map_zero, add_zero] map_add' := fun x y => by - induction' x with x_r x_a - induction' y with y_r y_a - simp only [fst_add, fst_inl, fst_inr, add_zero, map_add, snd_add, snd_inl, snd_inr, - zero_add, φ.map_add] - rw [add_add_add_comm] + induction x with + | inl_add_inr => + induction y with + | inl_add_inr => + simp only [fst_add, fst_inl, fst_inr, add_zero, map_add, snd_add, snd_inl, snd_inr, + zero_add, φ.map_add] + rw [add_add_add_comm] commutes' := fun r => by simp only [algebraMap_eq_inl, fst_inl, snd_inl, φ.map_zero, add_zero] @@ -745,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 100% rename from Mathlib/Data/ZMod/Algebra.lean rename to Mathlib/Algebra/Algebra/ZMod.lean index 2f5737b396fd4..a04244c46ce31 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` 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 8ea3c00ea7004..47308730de6b6 100644 --- a/Mathlib/Algebra/Associated/Basic.lean +++ b/Mathlib/Algebra/Associated/Basic.lean @@ -31,20 +31,20 @@ and prove basic properties of this quotient. assert_not_exists OrderedCommMonoid assert_not_exists Multiset -variable {α : Type*} {β : Type*} {γ : Type*} {δ : Type*} +variable {M N : Type*} section Prime -variable [CommMonoidWithZero α] +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 : α) : Prop := +def Prime (p : M) : Prop := p ≠ 0 ∧ ¬IsUnit p ∧ ∀ a b, p ∣ a * b → p ∣ a ∨ p ∣ b namespace Prime -variable {p : α} (hp : Prime p) +variable {p : M} (hp : Prime p) include hp theorem ne_zero : p ≠ 0 := @@ -58,19 +58,19 @@ theorem not_dvd_one : ¬p ∣ 1 := 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 := +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 : α} : p ∣ a * b ↔ p ∣ a ∨ p ∣ b := +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 : α} (ha : ¬ p ∣ a) (hb : ¬ p ∣ b) : ¬ p ∣ a * b := +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 : α} {n : ℕ} (h : p ∣ a ^ n) : p ∣ a := by +theorem dvd_of_dvd_pow {a : M} {n : ℕ} (h : p ∣ a ^ n) : p ∣ a := by induction n with | zero => rw [pow_zero] at h @@ -79,28 +79,28 @@ theorem dvd_of_dvd_pow {a : α} {n : ℕ} (h : p ∣ a ^ n) : p ∣ a := by contradiction | succ n ih => rw [pow_succ'] at h - cases' dvd_or_dvd hp h with dvd_a dvd_pow + 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 := +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 : α) := fun h => h.ne_zero rfl +theorem not_prime_zero : ¬Prime (0 : M) := fun h => h.ne_zero rfl @[simp] -theorem not_prime_one : ¬Prime (1 : α) := fun h => h.not_unit isUnit_one +theorem not_prime_one : ¬Prime (1 : M) := 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 : α} +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 : β) = a) (hp : Prime (f p)) : Prime p := +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 @@ -110,7 +110,7 @@ theorem comap_prime (hinv : ∀ a, g (f a : β) = a) (hp : Prime (f p)) : Prime · intro h convert ← map_dvd g h <;> apply hinv⟩ -theorem MulEquiv.prime_iff (e : α ≃* β) : Prime p ↔ Prime (e p) := +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⟩ @@ -118,15 +118,15 @@ 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 +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 α] {p a b : α} (hp : Prime p) +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 => @@ -138,15 +138,15 @@ theorem Prime.pow_dvd_of_dvd_mul_left [CancelCommMonoidWithZero α] {p a b : α} 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) +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 α] {p a b : α} +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`. - cases' hp.dvd_or_dvd ((dvd_pow_self p (Nat.succ_ne_zero n)).trans hpow) with H hbdiv + 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 @@ -161,24 +161,24 @@ theorem Prime.dvd_of_pow_dvd_pow_mul_pow_of_square_not_dvd [CancelCommMonoidWith rw [pow_two, ← mul_assoc] exact dvd_mul_right _ _ -theorem prime_pow_succ_dvd_mul {α : Type*} [CancelCommMonoidWithZero α] {p x y : α} (h : Prime p) +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 with i ih generalizing x - · rw [pow_one] at hxy ⊢ - exact (h.dvd_or_dvd hxy).resolve_right hy - 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)) + 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 +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 -/ @@ -186,38 +186,38 @@ structure Irreducible [Monoid α] (p : α) : Prop where namespace Irreducible -theorem not_dvd_one [CommMonoid α] {p : α} (hp : Irreducible p) : ¬p ∣ 1 := +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 α] {p : α} (hp : Irreducible p) {a b : α} (h : p = a * b) : +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 α] {p : α} : +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 α] : ¬Irreducible (1 : α) := by simp [irreducible_iff] +theorem not_irreducible_one [Monoid M] : ¬Irreducible (1 : M) := by simp [irreducible_iff] -theorem Irreducible.ne_one [Monoid α] : ∀ {p : α}, Irreducible p → p ≠ 1 +theorem Irreducible.ne_one [Monoid M] : ∀ {p : M}, Irreducible p → p ≠ 1 | _, hp, rfl => not_irreducible_one hp @[simp] -theorem not_irreducible_zero [MonoidWithZero α] : ¬Irreducible (0 : α) +theorem not_irreducible_zero [MonoidWithZero M] : ¬Irreducible (0 : M) | ⟨hn0, h⟩ => - have : IsUnit (0 : α) ∨ IsUnit (0 : α) := h 0 0 (mul_zero 0).symm + have : IsUnit (0 : M) ∨ IsUnit (0 : M) := h 0 0 (mul_zero 0).symm this.elim hn0 hn0 -theorem Irreducible.ne_zero [MonoidWithZero α] : ∀ {p : α}, Irreducible p → p ≠ 0 +theorem Irreducible.ne_zero [MonoidWithZero M] : ∀ {p : M}, Irreducible p → p ≠ 0 | _, hp, rfl => not_irreducible_zero hp -theorem of_irreducible_mul {α} [Monoid α] {x y : α} : Irreducible (x * y) → IsUnit x ∨ IsUnit y +theorem of_irreducible_mul {M} [Monoid M] {x y : M} : Irreducible (x * y) → IsUnit x ∨ IsUnit y | ⟨_, h⟩ => h _ _ rfl -theorem not_irreducible_pow {α} [Monoid α] {x : α} {n : ℕ} (hn : n ≠ 1) : +theorem not_irreducible_pow {M} [Monoid M] {x : M} {n : ℕ} (hn : n ≠ 1) : ¬ Irreducible (x ^ n) := by cases n with | zero => simp @@ -227,7 +227,7 @@ theorem not_irreducible_pow {α} [Monoid α] {x : α} {n : ℕ} (hn : n ≠ 1) : 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) : +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 => ?_ @@ -239,20 +239,26 @@ theorem irreducible_or_factor {α} [Monoid α] (x : α) (h : ¬IsUnit x) : 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) : +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 α] {p q : α} (hp : Irreducible p) (hq : Irreducible q) : +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⟩ +theorem Irreducible.of_map {F : Type*} [Monoid M] [Monoid N] [FunLike F M N] [MonoidHomClass F M N] + {f : F} [IsLocalRingHom 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 α] +variable [Monoid M] -theorem irreducible_units_mul (a : αˣ) (b : α) : Irreducible (↑a * b) ↔ Irreducible b := by +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] @@ -262,11 +268,11 @@ theorem irreducible_units_mul (a : αˣ) (b : α) : Irreducible (↑a * b) ↔ I 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 := +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 : αˣ) (b : α) : Irreducible (b * ↑a) ↔ Irreducible b := by +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] @@ -276,11 +282,11 @@ theorem irreducible_mul_units (a : αˣ) (b : α) : Irreducible (b * ↑a) ↔ I 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 := +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 : α} : +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 @@ -294,7 +300,7 @@ end section CommMonoid -variable [CommMonoid α] {a : α} +variable [CommMonoid M] {a : M} theorem Irreducible.not_square (ha : Irreducible a) : ¬IsSquare a := by rw [isSquare_iff_exists_sq] @@ -307,22 +313,22 @@ end CommMonoid section CommMonoidWithZero -variable [CommMonoidWithZero α] +variable [CommMonoidWithZero M] -theorem Irreducible.prime_of_isPrimal {a : α} +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 α] {a : α} (irr : Irreducible a) : Prime a := +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 α] {a p : α} +variable [CancelCommMonoidWithZero M] {a p : M} protected theorem Prime.irreducible (hp : Prime p) : Irreducible p := ⟨hp.not_unit, fun a b ↦ by @@ -333,10 +339,10 @@ protected theorem Prime.irreducible (hp : Prime p) : Irreducible p := (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 := +theorem irreducible_iff_prime [DecompositionMonoid M] {a : M} : Irreducible a ↔ Prime a := ⟨Irreducible.prime, Prime.irreducible⟩ -theorem succ_dvd_or_succ_dvd_of_succ_sum_dvd_mul (hp : Prime p) {a b : α} {k l : ℕ} : +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 @@ -359,8 +365,8 @@ end CancelCommMonoidWithZero /-- Two elements of a `Monoid` are `Associated` if one of them is another one multiplied by a unit on the right. -/ -def Associated [Monoid α] (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 +375,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 +416,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 +428,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 +535,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 +578,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,11 +589,11 @@ 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 - cases' n with n + rcases n with - | n · simp at hp · rw [Nat.succ.injEq] rw [pow_succ', prime_mul_iff] at hp @@ -598,7 +604,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 +616,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 +684,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 +722,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 +738,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,52 +828,52 @@ 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 /-- `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 - exact Quotient.inductionOn₂ a b $ fun a b hab hba ↦ Units.ext $ Quotient.sound $ - associated_one_of_associated_mul_one $ Quotient.exact hab + exact Quotient.inductionOn₂ a b <| fun a b hab hba ↦ Units.ext <| Quotient.sound <| + associated_one_of_associated_mul_one <| Quotient.exact hab @[deprecated (since := "2024-07-22")] alias mul_eq_one_iff := mul_eq_one @[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 +881,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 +910,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 +931,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 +1015,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 +1027,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 +1039,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 +1086,20 @@ end Associates section CommMonoidWithZero -theorem DvdNotUnit.isUnit_of_irreducible_right [CommMonoidWithZero α] {p q : α} +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 α] {p q : α} (hp : ¬IsUnit p) +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 α] {p q : α} (hp : DvdNotUnit p q) : ¬IsUnit q := by +theorem DvdNotUnit.not_unit [CommMonoidWithZero M] {p q : M} (hp : DvdNotUnit p q) : ¬IsUnit q := by obtain ⟨-, x, hx, rfl⟩ := hp exact fun hc => hx (isUnit_iff_dvd_one.mpr (dvd_of_mul_left_dvd (isUnit_iff_dvd_one.mp hc))) -theorem dvdNotUnit_of_dvdNotUnit_associated [CommMonoidWithZero α] [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 +1110,40 @@ 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 - cases' h with a ha + 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 +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_unit [CancelCommMonoidWithZero α] {q : α} (hq : ¬IsUnit q) +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 -theorem dvd_prime_pow [CancelCommMonoidWithZero α] {p q : α} (hp : Prime p) (n : ℕ) : +@[deprecated (since := "2024-09-22")] +alias pow_injective_of_not_unit := pow_injective_of_not_isUnit + +theorem pow_inj_of_not_isUnit [CancelCommMonoidWithZero M] {q : M} (hq : ¬IsUnit q) + (hq' : q ≠ 0) {m n : ℕ} : q ^ m = q ^ n ↔ m = n := + (pow_injective_of_not_isUnit hq hq').eq_iff + +theorem dvd_prime_pow [CancelCommMonoidWithZero M] {p q : M} (hp : Prime p) (n : ℕ) : q ∣ p ^ n ↔ ∃ i ≤ n, Associated q (p ^ i) := by induction n generalizing q with | 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 fd06fc15dc080..ebe6b44cb5983 100644 --- a/Mathlib/Algebra/BigOperators/Associated.lean +++ b/Mathlib/Algebra/BigOperators/Associated.lean @@ -68,18 +68,59 @@ theorem exists_associated_mem_of_dvd_prod [CancelCommMonoidWithZero α] {p : α} {s : Multiset α} : (∀ r ∈ s, Prime r) → p ∣ s.prod → ∃ q ∈ s, p ~ᵤ q := Multiset.induction_on s (by simp [mt isUnit_iff_dvd_one.2 hp.not_unit]) fun a s ih hs hps => by rw [Multiset.prod_cons] at hps - cases' hp.dvd_or_dvd hps with h h + rcases hp.dvd_or_dvd hps with h | h · have hap := hs a (Multiset.mem_cons.2 (Or.inl rfl)) exact ⟨a, Multiset.mem_cons_self a _, hp.associated_of_dvd hap h⟩ · 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 - induction' s using Multiset.induction_on with a s induct n primes divs generalizing n - · simp only [Multiset.prod_zero, one_dvd] - · rw [Multiset.prod_cons] + induction s using Multiset.induction_on generalizing n with + | empty => simp only [Multiset.prod_zero, one_dvd] + | cons a s induct => + rw [Multiset.prod_cons] obtain ⟨k, rfl⟩ : a ∣ n := div a (Multiset.mem_cons_self a s) apply mul_dvd_mul_left a refine induct _ (fun a ha => h a (Multiset.mem_cons_of_mem ha)) (fun b b_in_s => ?_) @@ -94,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 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..cf6a0e4d72664 --- /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.card : ℚ≥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} {m : N → 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.card := by rw [expect, sum_eq_single_of_mem _ hi h] + +lemma expect_ite_zero (s : Finset ι) (p : ι → Prop) [DecidablePred p] + (h : ∀ i ∈ s, ∀ j ∈ s, p i → p j → i = j) (a : M) : + 𝔼 i ∈ s, ite (p i) a 0 = ite (∃ i ∈ s, p i) (a /ℚ s.card) 0 := by + split_ifs <;> simp [expect, sum_ite_zero _ _ h, *] + +section DecidableEq +variable [DecidableEq ι] + +lemma expect_ite_mem (s t : Finset ι) (f : ι → M) : + 𝔼 i ∈ s, (if i ∈ t then f i else 0) = ((s ∩ t).card / s.card : ℚ≥0) • 𝔼 i ∈ s ∩ t, f i := by + obtain hst | hst := (s ∩ t).eq_empty_or_nonempty + · simp [expect, hst] + · simp [expect, smul_smul, ← inv_mul_eq_div, hst.card_ne_zero] + +@[simp] lemma expect_dite_eq (i : ι) (f : ∀ j, i = j → M) : + 𝔼 j ∈ s, (if h : i = j then f j h else 0) = if i ∈ s then f i rfl /ℚ s.card else 0 := by + split_ifs <;> simp [expect, *] + +@[simp] lemma expect_dite_eq' (i : ι) (f : ∀ j, j = i → M) : + 𝔼 j ∈ s, (if h : j = i then f j h else 0) = if i ∈ s then f i rfl /ℚ s.card else 0 := by + split_ifs <;> simp [expect, *] + +@[simp] lemma expect_ite_eq (i : ι) (f : ι → M) : + 𝔼 j ∈ s, (if i = j then f j else 0) = if i ∈ s then f i /ℚ s.card else 0 := by + split_ifs <;> simp [expect, *] + +@[simp] lemma expect_ite_eq' (i : ι) (f : ι → M) : + 𝔼 j ∈ s, (if j = i then f j else 0) = if i ∈ s then f i /ℚ s.card else 0 := by + 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.card • 𝔼 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] [Field N] [Module ℚ≥0 N] {s : Finset ι} + +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] {s : Finset ι} {f g : ι → M} {m : N → M} + +@[simp] lemma card_mul_expect (s : Finset ι) (f : ι → M) : + s.card * 𝔼 i ∈ s, f i = ∑ i ∈ s, f i := by rw [← nsmul_eq_mul, card_smul_expect] + +@[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] {s : Finset ι} {f g : ι → M} {m : N → 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.card := 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] {f : ι → 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/Fin.lean b/Mathlib/Algebra/BigOperators/Fin.lean index b544301f19d47..f336a553c7f57 100644 --- a/Mathlib/Algebra/BigOperators/Fin.lean +++ b/Mathlib/Algebra/BigOperators/Fin.lean @@ -86,11 +86,16 @@ theorem prod_univ_get' [CommMonoid β] (l : List α) (f : α → β) : ∏ i : Fin l.length, f l[i.1] = (l.map f).prod := by simp [Finset.prod_eq_multiset_prod] -@[to_additive] +@[to_additive (attr := simp)] theorem prod_cons [CommMonoid β] {n : ℕ} (x : β) (f : Fin n → β) : (∏ i : Fin n.succ, (cons x f : Fin n.succ → β) i) = x * ∏ i : Fin n, f i := by simp_rw [prod_univ_succ, cons_zero, cons_succ] +@[to_additive (attr := simp)] +theorem prod_snoc [CommMonoid β] {n : ℕ} (x : β) (f : Fin n → β) : + (∏ i : Fin n.succ, (snoc f x : Fin n.succ → β) i) = (∏ i : Fin n, f i) * x := by + simp [prod_univ_castSucc] + @[to_additive sum_univ_one] theorem prod_univ_one [CommMonoid β] (f : Fin 1 → β) : ∏ i, f i = f 0 := by simp @@ -210,7 +215,7 @@ theorem partialProd_left_inv {G : Type*} [Group G] (f : Fin (n + 1) → G) : @[to_additive] theorem partialProd_right_inv {G : Type*} [Group G] (f : Fin n → G) (i : Fin n) : (partialProd f (Fin.castSucc i))⁻¹ * partialProd f i.succ = f i := by - cases' i with i hn + obtain ⟨i, hn⟩ := i induction i with | zero => simp [-Fin.succ_mk, partialProd_succ] | succ i hi => @@ -264,32 +269,35 @@ end Fin def finFunctionFinEquiv {m n : ℕ} : (Fin n → Fin m) ≃ Fin (m ^ n) := Equiv.ofRightInverseOfCardLE (le_of_eq <| by simp_rw [Fintype.card_fun, Fintype.card_fin]) (fun f => ⟨∑ i, f i * m ^ (i : ℕ), by - induction' n with n ih - · simp - cases m - · exact isEmptyElim (f <| Fin.last _) - simp_rw [Fin.sum_univ_castSucc, Fin.coe_castSucc, Fin.val_last] - refine (Nat.add_lt_add_of_lt_of_le (ih _) <| Nat.mul_le_mul_right _ (Fin.is_le _)).trans_eq ?_ - rw [← one_add_mul (_ : ℕ), add_comm, pow_succ']⟩) + induction n with + | zero => simp + | succ n ih => + cases m + · exact isEmptyElim (f <| Fin.last _) + simp_rw [Fin.sum_univ_castSucc, Fin.coe_castSucc, Fin.val_last] + refine (Nat.add_lt_add_of_lt_of_le (ih _) <| Nat.mul_le_mul_right _ + (Fin.is_le _)).trans_eq ?_ + rw [← one_add_mul (_ : ℕ), add_comm, pow_succ']⟩) (fun a b => ⟨a / m ^ (b : ℕ) % m, by - cases' n with n + rcases n with - | n · exact b.elim0 - cases' m with m + rcases m with - | m · rw [zero_pow n.succ_ne_zero] at a exact a.elim0 · exact Nat.mod_lt _ m.succ_pos⟩) fun a => by dsimp - induction' n with n ih - · subsingleton [(finCongr <| pow_zero _).subsingleton] - simp_rw [Fin.forall_iff, Fin.ext_iff] at ih - ext - simp_rw [Fin.sum_univ_succ, Fin.val_zero, Fin.val_succ, pow_zero, Nat.div_one, - mul_one, pow_succ', ← Nat.div_div_eq_div_mul, mul_left_comm _ m, ← mul_sum] - rw [ih _ (Nat.div_lt_of_lt_mul ?_), Nat.mod_add_div] - -- Porting note: replaces `a.is_lt` in the wildcard above. Caused by a refactor of the `npow` - -- instance for `Fin`. - exact a.is_lt.trans_eq (pow_succ' _ _) + induction n with + | zero => subsingleton [(finCongr <| pow_zero _).subsingleton] + | succ n ih => + simp_rw [Fin.forall_iff, Fin.ext_iff] at ih + ext + simp_rw [Fin.sum_univ_succ, Fin.val_zero, Fin.val_succ, pow_zero, Nat.div_one, + mul_one, pow_succ', ← Nat.div_div_eq_div_mul, mul_left_comm _ m, ← mul_sum] + rw [ih _ (Nat.div_lt_of_lt_mul ?_), Nat.mod_add_div] + -- Porting note: replaces `a.is_lt` in the wildcard above. + -- Caused by a refactor of the `npow` instance for `Fin`. + exact a.is_lt.trans_eq (pow_succ' _ _) theorem finFunctionFinEquiv_apply {m n : ℕ} (f : Fin n → Fin m) : (finFunctionFinEquiv f : ℕ) = ∑ i : Fin n, ↑(f i) * m ^ (i : ℕ) := @@ -305,8 +313,9 @@ theorem finFunctionFinEquiv_single {m n : ℕ} [NeZero m] (i : Fin n) (j : Fin m def finPiFinEquiv {m : ℕ} {n : Fin m → ℕ} : (∀ i : Fin m, Fin (n i)) ≃ Fin (∏ i : Fin m, n i) := Equiv.ofRightInverseOfCardLE (le_of_eq <| by simp_rw [Fintype.card_pi, Fintype.card_fin]) (fun f => ⟨∑ i, f i * ∏ j, n (Fin.castLE i.is_lt.le j), by - induction' m with m ih - · simp + induction m with + | zero => simp + | succ m ih => rw [Fin.prod_univ_castSucc, Fin.sum_univ_castSucc] suffices ∀ (n : Fin m → ℕ) (nn : ℕ) (f : ∀ i : Fin m, Fin (n i)) (fn : Fin nn), @@ -325,7 +334,7 @@ def finPiFinEquiv {m : ℕ} {n : Fin m → ℕ} : (∀ i : Fin m, Fin (n i)) ≃ (fun a b => ⟨(a / ∏ j : Fin b, n (Fin.castLE b.is_lt.le j)) % n b, by cases m · exact b.elim0 - cases' h : n b with nb + rcases h : n b with nb | nb · rw [prod_eq_zero (Finset.mem_univ _) h] at a exact isEmptyElim a exact Nat.mod_lt _ nb.succ_pos⟩) diff --git a/Mathlib/Algebra/BigOperators/Finprod.lean b/Mathlib/Algebra/BigOperators/Finprod.lean index 9a2dc40b1b77f..fbfabaaebfca3 100644 --- a/Mathlib/Algebra/BigOperators/Finprod.lean +++ b/Mathlib/Algebra/BigOperators/Finprod.lean @@ -750,7 +750,7 @@ theorem finprod_mem_insert_one (h : f a = 1) : ∏ᶠ i ∈ insert a s, f i = finprod_mem_insert_of_eq_one_if_not_mem fun _ => h /-- If the multiplicative support of `f` is finite, then for every `x` in the domain of `f`, `f x` -divides `finprod f`. -/ +divides `finprod f`. -/ theorem finprod_mem_dvd {f : α → N} (a : α) (hf : (mulSupport f).Finite) : f a ∣ finprod f := by by_cases ha : a ∈ mulSupport f · rw [finprod_eq_prod_of_mulSupport_toFinset_subset f hf (Set.Subset.refl _)] @@ -1011,7 +1011,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 b828486c30166..10fdcfb6979ea 100644 --- a/Mathlib/Algebra/BigOperators/Finsupp.lean +++ b/Mathlib/Algebra/BigOperators/Finsupp.lean @@ -249,12 +249,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 _ _ @@ -268,9 +268,10 @@ theorem support_sum [DecidableEq β] [Zero M] [AddCommMonoid N] {f : α →₀ M theorem support_finset_sum [DecidableEq β] [AddCommMonoid M] {s : Finset α} {f : α → β →₀ M} : (Finset.sum s f).support ⊆ s.biUnion fun x => (f x).support := by rw [← Finset.sup_eq_biUnion] - induction' s using Finset.cons_induction_on with a s ha ih - · rfl - · rw [Finset.sum_cons, Finset.sup_cons] + induction s using Finset.cons_induction_on with + | h₁ => rfl + | h₂ _ ih => + rw [Finset.sum_cons, Finset.sup_cons] exact support_add.trans (Finset.union_subset_union (Finset.Subset.refl _) ih) @[simp] @@ -345,9 +346,8 @@ 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' - simp [singleAddHom, AddMonoidHom.comp, Function.comp] + ext + simp [singleAddHom, AddMonoidHom.comp, Function.comp_def] map_add' F G := by ext x exact sum_add diff --git a/Mathlib/Algebra/BigOperators/Group/Finset.lean b/Mathlib/Algebra/BigOperators/Group/Finset.lean index f6842570c540f..ee1faae6ee2a2 100644 --- a/Mathlib/Algebra/BigOperators/Group/Finset.lean +++ b/Mathlib/Algebra/BigOperators/Group/Finset.lean @@ -39,6 +39,7 @@ See the documentation of `to_additive.attr` for more information. -- assert_not_exists AddCommMonoidWithOne assert_not_exists MonoidWithZero assert_not_exists MulAction +assert_not_exists OrderedCommMonoid variable {ι κ α β γ : Type*} @@ -213,7 +214,7 @@ macro_rules (kind := bigprodin) | `(∏ $x:ident : $t in $s, $r) => `(∏ $x:ident ∈ ($s : Finset $t), $r) open Lean Meta Parser.Term PrettyPrinter.Delaborator SubExpr -open Batteries.ExtendedBinder +open scoped Batteries.ExtendedBinder /-- Delaborator for `Finset.prod`. The `pp.piBinderTypes` option controls whether to show the domain type when the product is over `Finset.univ`. -/ @@ -456,7 +457,7 @@ of `s`, and over all subsets of `s` to which one adds `x`. -/ of `s`, and over all subsets of `s` to which one adds `x`."] lemma prod_powerset_cons (ha : a ∉ s) (f : Finset α → β) : ∏ t ∈ (s.cons a ha).powerset, f t = (∏ t ∈ s.powerset, f t) * - ∏ t ∈ s.powerset.attach, f (cons a t $ not_mem_mono (mem_powerset.1 t.2) ha) := by + ∏ t ∈ s.powerset.attach, f (cons a t <| not_mem_mono (mem_powerset.1 t.2) ha) := by classical simp_rw [cons_eq_insert] rw [prod_powerset_insert ha, prod_attach _ fun t ↦ f (insert a t)] @@ -538,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 -in the reverse direction, use `Finset.prod_sigma'`. -/ -@[to_additive "Sum over a sigma type equals the sum of fiberwise sums. 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 "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 @@ -721,7 +725,7 @@ but differ in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ lemma prod_univ_pi [DecidableEq ι] [Fintype ι] {κ : ι → Type*} (t : ∀ i, Finset (κ i)) (f : (∀ i ∈ (univ : Finset ι), κ i) → β) : ∏ x ∈ univ.pi t, f x = ∏ x ∈ Fintype.piFinset t, f fun a _ ↦ x a := by - apply prod_nbij' (fun x i ↦ x i $ mem_univ _) (fun x i _ ↦ x i) <;> simp + apply prod_nbij' (fun x i ↦ x i <| mem_univ _) (fun x i _ ↦ x i) <;> simp @[to_additive (attr := simp)] lemma prod_diag [DecidableEq α] (s : Finset α) (f : α × α → β) : @@ -774,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. -/ @@ -1309,16 +1318,16 @@ theorem eventually_constant_prod {u : ℕ → β} {N : ℕ} (hu : ∀ n ≥ N, u (∏ k ∈ range n, u k) = ∏ k ∈ range N, u k := by obtain ⟨m, rfl : n = N + m⟩ := Nat.exists_eq_add_of_le hn clear hn - induction' m with m hm - · simp - · simp [← add_assoc, prod_range_succ, hm, hu] + induction m with + | zero => simp + | succ m hm => simp [← add_assoc, prod_range_succ, hm, hu] @[to_additive] theorem prod_range_add (f : ℕ → β) (n m : ℕ) : (∏ x ∈ range (n + m), f x) = (∏ x ∈ range n, f x) * ∏ x ∈ range m, f (n + x) := by - induction' m with m hm - · simp - · erw [Nat.add_succ, prod_range_succ, prod_range_succ, hm, mul_assoc] + induction m with + | zero => simp + | succ m hm => rw [Nat.add_succ, prod_range_succ, prod_range_succ, hm, mul_assoc] @[to_additive] theorem prod_range_add_div_prod_range {α : Type*} [CommGroup α] (f : ℕ → α) (n m : ℕ) : @@ -1337,7 +1346,9 @@ open List @[to_additive] theorem prod_list_map_count [DecidableEq α] (l : List α) {M : Type*} [CommMonoid M] (f : α → M) : (l.map f).prod = ∏ m ∈ l.toFinset, f m ^ l.count m := by - induction' l with a s IH; · simp only [map_nil, prod_nil, count_nil, pow_zero, prod_const_one] + induction l with + | nil => simp only [map_nil, prod_nil, count_nil, pow_zero, prod_const_one] + | cons a s IH => simp only [List.map, List.prod_cons, toFinset_cons, IH] by_cases has : a ∈ s.toFinset · rw [insert_eq_of_mem has, ← insert_erase has, prod_insert (not_mem_erase _ _), @@ -1426,9 +1437,9 @@ This is a discrete analogue of the fundamental theorem of calculus."] theorem prod_range_induction (f s : ℕ → β) (base : s 0 = 1) (step : ∀ n, s (n + 1) = s n * f n) (n : ℕ) : ∏ k ∈ Finset.range n, f k = s n := by - induction' n with k hk - · rw [Finset.prod_range_zero, base] - · simp only [hk, Finset.prod_range_succ, step, mul_comm] + induction n with + | zero => rw [Finset.prod_range_zero, base] + | succ k hk => simp only [hk, Finset.prod_range_succ, step, mul_comm] /-- A telescoping product along `{0, ..., n - 1}` of a commutative group valued function reduces to the ratio of the last and first factors. -/ @@ -1455,17 +1466,23 @@ theorem eq_prod_range_div' {M : Type*} [CommGroup M] (f : ℕ → M) (n : ℕ) : reduces to the difference of the last and first terms when the function we are summing is monotone. -/ -theorem sum_range_tsub [CanonicallyOrderedAddCommMonoid α] [Sub α] [OrderedSub α] - [ContravariantClass α α (· + ·) (· ≤ ·)] {f : ℕ → α} (h : Monotone f) (n : ℕ) : +theorem sum_range_tsub [AddCommMonoid α] [PartialOrder α] [Sub α] [OrderedSub α] + [CovariantClass α α (· + ·) (· ≤ ·)] [ContravariantClass α α (· + ·) (· ≤ ·)] [ExistsAddOfLE α] + {f : ℕ → α} (h : Monotone f) (n : ℕ) : ∑ i ∈ range n, (f (i + 1) - f i) = f n - f 0 := by apply sum_range_induction - case base => apply tsub_self + case base => apply tsub_eq_of_eq_add; rw [zero_add] case step => intro n have h₁ : f n ≤ f (n + 1) := h (Nat.le_succ _) 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 @@ -1490,7 +1507,7 @@ theorem prod_pow (s : Finset α) (n : ℕ) (f : α → β) : ∏ x ∈ s, f x ^ Multiset.prod_map_pow @[to_additive sum_nsmul_assoc] -lemma prod_pow_eq_pow_sum (s : Finset ι) (f : ι → ℕ) (a : β) : +lemma prod_pow_eq_pow_sum (s : Finset ι) (f : ι → ℕ) (a : β) : ∏ i ∈ s, a ^ f i = a ^ ∑ i ∈ s, f i := cons_induction (by simp) (fun _ _ _ _ ↦ by simp [prod_cons, sum_cons, pow_add, *]) s @@ -1510,45 +1527,41 @@ theorem prod_flip {n : ℕ} (f : ℕ → β) : rw [prod_range_succ', prod_range_succ _ (Nat.succ n)] simp [← ih] -@[to_additive] -theorem prod_involution {s : Finset α} {f : α → β} : - ∀ (g : ∀ a ∈ s, α) (_ : ∀ a ha, f a * f (g a ha) = 1) (_ : ∀ a ha, f a ≠ 1 → g a ha ≠ a) - (g_mem : ∀ a ha, g a ha ∈ s) (_ : ∀ a ha, g (g a ha) (g_mem a ha) = a), - ∏ x ∈ s, f x = 1 := by - haveI := Classical.decEq α; haveI := Classical.decEq β - exact - Finset.strongInductionOn s fun s ih g h g_ne g_mem g_inv => - s.eq_empty_or_nonempty.elim (fun hs => hs.symm ▸ rfl) fun ⟨x, hx⟩ => - have hmem : ∀ y ∈ (s.erase x).erase (g x hx), y ∈ s := fun y hy => - mem_of_mem_erase (mem_of_mem_erase hy) - have g_inj : ∀ {x hx y hy}, g x hx = g y hy → x = y := fun {x hx y hy} h => by - rw [← g_inv x hx, ← g_inv y hy]; simp [h] - have ih' : (∏ y ∈ erase (erase s x) (g x hx), f y) = (1 : β) := - ih ((s.erase x).erase (g x hx)) - ⟨Subset.trans (erase_subset _ _) (erase_subset _ _), fun h => - not_mem_erase (g x hx) (s.erase x) (h (g_mem x hx))⟩ - (fun y hy => g y (hmem y hy)) (fun y hy => h y (hmem y hy)) - (fun y hy => g_ne y (hmem y hy)) - (fun y hy => - mem_erase.2 - ⟨fun h : g y _ = g x hx => by simp [g_inj h] at hy, - mem_erase.2 - ⟨fun h : g y _ = x => by - have : y = g x hx := g_inv y (hmem y hy) ▸ by simp [h] - simp [this] at hy, g_mem y (hmem y hy)⟩⟩) - fun y hy => g_inv y (hmem y hy) - if hx1 : f x = 1 then - ih' ▸ - Eq.symm - (prod_subset hmem fun y hy hy₁ => - have : y = x ∨ y = g x hx := by - simpa [hy, -not_and, mem_erase, not_and_or, or_comm] using hy₁ - this.elim (fun hy => hy.symm ▸ hx1) fun hy => - h x hx ▸ hy ▸ hx1.symm ▸ (one_mul _).symm) - else by - rw [← insert_erase hx, prod_insert (not_mem_erase _ _), ← - insert_erase (mem_erase.2 ⟨g_ne x hx hx1, g_mem x hx⟩), - prod_insert (not_mem_erase _ _), ih', mul_one, h x hx] +/-- The difference with `Finset.prod_ninvolution` is that the involution is allowed to use +membership of the domain of the product, rather than being a non-dependent function. -/ +@[to_additive "The difference with `Finset.sum_ninvolution` is that the involution is allowed to use +membership of the domain of the sum, rather than being a non-dependent function."] +lemma prod_involution (g : ∀ a ∈ s, α) (hg₁ : ∀ a ha, f a * f (g a ha) = 1) + (hg₃ : ∀ a ha, f a ≠ 1 → g a ha ≠ a) + (g_mem : ∀ a ha, g a ha ∈ s) (hg₄ : ∀ a ha, g (g a ha) (g_mem a ha) = a) : + ∏ x ∈ s, f x = 1 := by + classical + induction s using Finset.strongInduction with | H s ih => ?_ + obtain rfl | ⟨x, hx⟩ := s.eq_empty_or_nonempty + · simp + have : {x, g x hx} ⊆ s := by simp [insert_subset_iff, hx, g_mem] + suffices h : ∏ x ∈ s \ {x, g x hx}, f x = 1 by + rw [← prod_sdiff this, h, one_mul] + cases eq_or_ne (g x hx) x with + | inl hx' => simpa [hx'] using hg₃ x hx + | inr hx' => rw [prod_pair hx'.symm, hg₁] + suffices h₃ : ∀ a (ha : a ∈ s \ {x, g x hx}), g a (sdiff_subset ha) ∈ s \ {x, g x hx} from + ih (s \ {x, g x hx}) (ssubset_iff.2 ⟨x, by simp [insert_subset_iff, hx]⟩) _ + (by simp [hg₁]) (fun _ _ => hg₃ _ _) h₃ (fun _ _ => hg₄ _ _) + simp only [mem_sdiff, mem_insert, mem_singleton, not_or, g_mem, true_and] + rintro a ⟨ha₁, ha₂, ha₃⟩ + refine ⟨fun h => by simp [← h, hg₄] at ha₃, fun h => ?_⟩ + have : g (g a ha₁) (g_mem _ _) = g (g x hx) (g_mem _ _) := by simp only [h] + exact ha₂ (by simpa [hg₄] using this) + +/-- The difference with `Finset.prod_involution` is that the involution is a non-dependent function, +rather than being allowed to use membership of the domain of the product. -/ +@[to_additive "The difference with `Finset.sum_involution` is that the involution is a non-dependent +function, rather than being allowed to use membership of the domain of the sum."] +lemma prod_ninvolution (g : α → α) (hg₁ : ∀ a, f a * f (g a) = 1) (hg₂ : ∀ a, f a ≠ 1 → g a ≠ a) + (g_mem : ∀ a, g a ∈ s) (hg₃ : ∀ a, g (g a) = a) : ∏ x ∈ s, f x = 1 := + prod_involution (fun i _ => g i) (fun i _ => hg₁ i) (fun _ _ hi => hg₂ _ hi) + (fun i _ => g_mem i) (fun i _ => hg₃ i) /-- The product of the composition of functions `f` and `g`, is the product over `b ∈ s.image g` of `f b` to the power of the cardinality of the fibre of `b`. See also `Finset.prod_image`. -/ @@ -1639,7 +1652,7 @@ theorem eq_of_card_le_one_of_prod_eq {s : Finset α} (hc : s.card ≤ 1) {f : α · 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)) rw [card_eq_one] at h1 - cases' h1 with x2 hx2 + obtain ⟨x2, hx2⟩ := h1 rw [hx2, mem_singleton] at hx simp_rw [hx2] at h rw [hx] @@ -1674,7 +1687,7 @@ theorem prod_erase [DecidableEq α] (s : Finset α) {f : α → β} {a : α} (h rw [sdiff_singleton_eq_erase] at hnx rwa [eq_of_mem_of_not_mem_erase hx hnx] -/-- See also `Finset.prod_boole`. -/ +/-- See also `Finset.prod_ite_zero`. -/ @[to_additive "See also `Finset.sum_boole`."] theorem prod_ite_one (s : Finset α) (p : α → Prop) [DecidablePred p] (h : ∀ i ∈ s, ∀ j ∈ s, p i → p j → i = j) (a : β) : @@ -1688,7 +1701,7 @@ theorem prod_ite_one (s : Finset α) (p : α → Prop) [DecidablePred p] exact fun i hi => if_neg (h i hi) @[to_additive] -theorem prod_erase_lt_of_one_lt {γ : Type*} [DecidableEq α] [OrderedCommMonoid γ] +theorem prod_erase_lt_of_one_lt {γ : Type*} [DecidableEq α] [CommMonoid γ] [Preorder γ] [CovariantClass γ γ (· * ·) (· < ·)] {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] @@ -1718,9 +1731,11 @@ theorem prod_pow_boole [DecidableEq α] (s : Finset α) (f : α → β) (a : α) theorem prod_dvd_prod_of_dvd {S : Finset α} (g1 g2 : α → β) (h : ∀ a ∈ S, g1 a ∣ g2 a) : S.prod g1 ∣ S.prod g2 := by classical - induction' S using Finset.induction_on' with a T _haS _hTS haT IH - · simp - · rw [Finset.prod_insert haT, prod_insert haT] + induction S using Finset.induction_on' with + | h₁ => simp + | h₂ _haS _hTS haT IH => + rename_i a T + rw [Finset.prod_insert haT, prod_insert haT] exact mul_dvd_mul (h a <| T.mem_insert_self a) <| IH fun b hb ↦ h b <| mem_insert_of_mem hb theorem prod_dvd_prod_of_subset {ι M : Type*} [CommMonoid M] (s t : Finset ι) (f : ι → M) @@ -1755,7 +1770,7 @@ variable [DecidableEq ι] [CancelCommMonoid α] {s t : Finset ι} {f : ι → α @[to_additive] lemma prod_sdiff_eq_prod_sdiff_iff : ∏ i ∈ s \ t, f i = ∏ i ∈ t \ s, f i ↔ ∏ i ∈ s, f i = ∏ i ∈ t, f i := - eq_comm.trans $ eq_iff_eq_of_mul_eq_mul $ by + eq_comm.trans <| eq_iff_eq_of_mul_eq_mul <| by rw [← prod_union disjoint_sdiff_self_left, ← prod_union disjoint_sdiff_self_left, sdiff_union_self_eq_union, sdiff_union_self_eq_union, union_comm] @@ -1989,7 +2004,7 @@ theorem prod_subtype_mul_prod_subtype {α β : Type*} [Fintype α] [CommMonoid @[to_additive] lemma prod_subset {s : Finset ι} {f : ι → α} (h : ∀ i, f i ≠ 1 → i ∈ s) : ∏ i ∈ s, f i = ∏ i, f i := - Finset.prod_subset s.subset_univ $ by simpa [not_imp_comm (a := _ ∈ s)] + Finset.prod_subset s.subset_univ <| by simpa [not_imp_comm (a := _ ∈ s)] @[to_additive] lemma prod_ite_eq_ite_exists (p : ι → Prop) [DecidablePred p] (h : ∀ i j, p i → p j → i = j) @@ -1998,6 +2013,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 @@ -2036,7 +2055,7 @@ variable [CommMonoid α] @[to_additive (attr := simp)] lemma prod_attach_univ [Fintype ι] (f : {i // i ∈ @univ ι _} → α) : ∏ i ∈ univ.attach, f i = ∏ i, f ⟨i, mem_univ _⟩ := - Fintype.prod_equiv (Equiv.subtypeUnivEquiv mem_univ) _ _ $ by simp + Fintype.prod_equiv (Equiv.subtypeUnivEquiv mem_univ) _ _ <| by simp @[to_additive] theorem prod_erase_attach [DecidableEq ι] {s : Finset ι} (f : ι → α) (i : ↑s) : @@ -2067,10 +2086,12 @@ namespace Multiset theorem disjoint_list_sum_left {a : Multiset α} {l : List (Multiset α)} : Multiset.Disjoint l.sum a ↔ ∀ b ∈ l, Multiset.Disjoint b a := by - induction' l with b bs ih - · simp only [zero_disjoint, List.not_mem_nil, IsEmpty.forall_iff, forall_const, List.sum_nil] - · simp_rw [List.sum_cons, disjoint_add_left, List.mem_cons, forall_eq_or_imp] - simp [and_congr_left_iff, iff_self_iff, ih] + induction l with + | nil => + 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, ih] theorem disjoint_list_sum_right {a : Multiset α} {l : List (Multiset α)} : Multiset.Disjoint a l.sum ↔ ∀ b ∈ l, Multiset.Disjoint a b := by @@ -2089,7 +2110,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 @@ -2097,7 +2118,7 @@ theorem disjoint_finset_sum_right {β : Type*} {i : Finset β} {f : β → Multi @[simp] lemma mem_sum {s : Finset ι} {m : ι → Multiset α} : a ∈ ∑ i ∈ s, m i ↔ ∃ i ∈ s, a ∈ m i := by - induction' s using Finset.cons_induction <;> simp [*] + induction s using Finset.cons_induction <;> simp [*] variable [DecidableEq α] @@ -2143,9 +2164,10 @@ theorem toFinset_prod_dvd_prod [CommMonoid α] (S : Multiset α) : S.toFinset.pr theorem prod_sum {α : Type*} {ι : Type*} [CommMonoid α] (f : ι → Multiset α) (s : Finset ι) : (∑ x ∈ s, f x).prod = ∏ x ∈ s, (f x).prod := by classical - induction' s using Finset.induction_on with a t hat ih - · rw [Finset.sum_empty, Finset.prod_empty, Multiset.prod_zero] - · rw [Finset.sum_insert hat, Finset.prod_insert hat, Multiset.prod_add, ih] + induction s using Finset.induction_on with + | empty => rw [Finset.sum_empty, Finset.prod_empty, Multiset.prod_zero] + | insert hat ih => + rw [Finset.sum_insert hat, Finset.prod_insert hat, Multiset.prod_add, ih] end Multiset @@ -2157,9 +2179,10 @@ theorem Units.coe_prod {M : Type*} [CommMonoid M] (f : α → Mˣ) (s : Finset theorem nat_abs_sum_le {ι : Type*} (s : Finset ι) (f : ι → ℤ) : (∑ i ∈ s, f i).natAbs ≤ ∑ i ∈ s, (f i).natAbs := by classical - induction' s using Finset.induction_on with i s his IH - · simp only [Finset.sum_empty, Int.natAbs_zero, le_refl] - · simp only [his, Finset.sum_insert, not_false_iff] + induction s using Finset.induction_on with + | empty => simp only [Finset.sum_empty, Int.natAbs_zero, le_refl] + | insert his IH => + simp only [his, Finset.sum_insert, not_false_iff] exact (Int.natAbs_add_le _ _).trans (Nat.add_le_add_left IH _) /-! ### `Additive`, `Multiplicative` -/ @@ -2240,9 +2263,6 @@ 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 = @@ -2254,3 +2274,5 @@ theorem Finset.sum_sym2_filter_not_isDiag {ι α} [LinearOrder ι] [AddCommMonoi simp [and_assoc] · rintro ⟨⟨i₁, j₁⟩, hij₁⟩ simp + +set_option linter.style.longFile 2400 diff --git a/Mathlib/Algebra/BigOperators/Group/List.lean b/Mathlib/Algebra/BigOperators/Group/List.lean index 0251d89f06740..6a1a5fb8af68e 100644 --- a/Mathlib/Algebra/BigOperators/Group/List.lean +++ b/Mathlib/Algebra/BigOperators/Group/List.lean @@ -12,6 +12,7 @@ import Mathlib.Data.List.Perm import Mathlib.Data.List.ProdSigma import Mathlib.Data.List.Range import Mathlib.Data.List.Rotate +import Mathlib.Data.List.Pairwise /-! # Sums and products from lists @@ -21,9 +22,7 @@ of elements of a list and `List.alternatingProd`, `List.alternatingSum`, their a counterparts. -/ --- Make sure we haven't imported `Data.Nat.Order.Basic` -assert_not_exists OrderedSub -assert_not_exists Ring +assert_not_imported Mathlib.Algebra.Order.Group.Nat variable {ι α β M N P G : Type*} @@ -92,11 +91,12 @@ theorem prod_cons : (a :: l).prod = a * l.prod := 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 a l ih - · simpa - 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) + 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) @[to_additive (attr := simp)] theorem prod_append : (l₁ ++ l₂).prod = l₁.prod * l₂.prod := @@ -125,7 +125,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) @@ -137,24 +137,29 @@ theorem rel_prod {R : M → N → Prop} (h : R 1 1) (hf : (R ⇒ R ⇒ R) (· * (Forall₂ R ⇒ R) prod prod := rel_foldl hf h +@[to_additive] +theorem prod_hom_nonempty {l : List M} {F : Type*} [FunLike F M N] [MulHomClass F M N] (f : F) + (hl : l ≠ []) : (l.map f).prod = f l.prod := + match l, hl with | x :: xs, hl => by induction xs generalizing x <;> aesop + @[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) +@[to_additive] +theorem prod_hom₂_nonempty {l : List ι} (f : M → N → P) + (hf : ∀ a b c d, f (a * b) (c * d) = f a c * f b d) (f₁ : ι → M) (f₂ : ι → N) (hl : l ≠ []) : + (l.map fun i => f (f₁ i) (f₂ i)).prod = f (l.map f₁).prod (l.map f₂).prod := by + match l, hl with | x :: xs, hl => induction xs generalizing x <;> aesop + @[to_additive] 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 - simp only [prod, foldl_map] - -- Porting note: next 3 lines used to be - -- convert l.foldl_hom₂ (fun a b => f a b) _ _ _ _ _ fun a b i => _ - -- · exact hf'.symm - -- · exact hf _ _ _ _ - rw [← l.foldl_hom₂ (fun a b => f a b), hf'] - intros - exact hf _ _ _ _ + 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'] @[to_additive (attr := simp)] theorem prod_map_mul {α : Type*} [CommMonoid α] {l : List ι} {f g : ι → α} : @@ -177,27 +182,21 @@ theorem prod_isUnit : ∀ {L : List M}, (∀ m ∈ L, IsUnit m) → IsUnit L.pro theorem prod_isUnit_iff {α : Type*} [CommMonoid α] {L : List α} : IsUnit L.prod ↔ ∀ m ∈ L, IsUnit m := by refine ⟨fun h => ?_, prod_isUnit⟩ - induction' L with m L ih - · exact fun m' h' => False.elim (not_mem_nil m' h') - rw [prod_cons, IsUnit.mul_iff] at h - 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 + induction L with + | nil => exact fun m' h' => False.elim (not_mem_nil m' h') + | cons m L ih => + rw [prod_cons, IsUnit.mul_iff] at h + 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."] @@ -246,9 +245,10 @@ theorem headI_mul_tail_prod_of_ne_nil [Inhabited M] (l : List M) (h : l ≠ []) @[to_additive] theorem _root_.Commute.list_prod_right (l : List M) (y : M) (h : ∀ x ∈ l, Commute y x) : Commute y l.prod := by - induction' l with z l IH - · simp - · rw [List.forall_mem_cons] at h + induction l with + | nil => simp + | cons z l IH => + rw [List.forall_mem_cons] at h rw [List.prod_cons] exact Commute.mul_right h.1 (IH h.2) @@ -266,14 +266,16 @@ 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 i l hil - · rfl - rw [List.prod_cons, hil fun x hx ↦ hl _ (mem_cons_of_mem i hx), hl _ (mem_cons_self i l), one_mul] + induction l with + | nil => rfl + | cons i l hil => + rw [List.prod_cons, hil fun x hx ↦ hl _ (mem_cons_of_mem i hx), + hl _ (mem_cons_self i l), one_mul] @[to_additive] lemma exists_mem_ne_one_of_prod_ne_one (h : l.prod ≠ 1) : ∃ x ∈ l, x ≠ (1 : M) := by simpa only [not_forall, exists_prop] using mt prod_eq_one h @@ -281,20 +283,22 @@ lemma prod_range_succ' (f : ℕ → M) (n : ℕ) : @[to_additive] lemma prod_erase_of_comm [DecidableEq M] (ha : a ∈ l) (comm : ∀ x ∈ l, ∀ y ∈ l, x * y = y * x) : a * (l.erase a).prod = l.prod := by - induction' l with b l ih - · simp only [not_mem_nil] at ha - obtain rfl | ⟨ne, h⟩ := List.eq_or_ne_mem_of_mem ha - · simp only [erase_cons_head, prod_cons] - rw [List.erase, beq_false_of_ne ne.symm, List.prod_cons, List.prod_cons, ← mul_assoc, - comm a ha b (l.mem_cons_self b), mul_assoc, - ih h fun x hx y hy ↦ comm _ (List.mem_cons_of_mem b hx) _ (List.mem_cons_of_mem b hy)] + induction l with + | nil => simp only [not_mem_nil] at ha + | cons b l ih => + obtain rfl | ⟨ne, h⟩ := List.eq_or_ne_mem_of_mem ha + · simp only [erase_cons_head, prod_cons] + rw [List.erase, beq_false_of_ne ne.symm, List.prod_cons, List.prod_cons, ← mul_assoc, + comm a ha b (l.mem_cons_self b), mul_assoc, + ih h fun x hx y hy ↦ comm _ (List.mem_cons_of_mem b hx) _ (List.mem_cons_of_mem b hy)] @[to_additive] lemma prod_map_eq_pow_single [DecidableEq α] {l : List α} (a : α) (f : α → M) (hf : ∀ a', a' ≠ a → a' ∈ l → f a' = 1) : (l.map f).prod = f a ^ l.count a := by - induction' l with a' as h generalizing a - · rw [map_nil, prod_nil, count_nil, _root_.pow_zero] - · specialize h a fun a' ha' hfa' => hf a' ha' (mem_cons_of_mem _ hfa') + induction l generalizing a with + | nil => rw [map_nil, prod_nil, count_nil, _root_.pow_zero] + | cons a' as h => + specialize h a fun a' ha' hfa' => hf a' ha' (mem_cons_of_mem _ hfa') rw [List.map_cons, List.prod_cons, count_cons, h] simp only [beq_iff_eq] split_ifs with ha' @@ -338,7 +342,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.foldl_op_eq @[to_additive] lemma prod_reverse (l : List M) : prod l.reverse = prod l := (reverse_perm l).prod_eq @@ -416,8 +420,8 @@ theorem prod_reverse_noncomm : ∀ L : List G, L.reverse.prod = (L.map fun x => 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) - | x :: xs, 0, _ => by simp - | x :: xs, i + 1, p => prod_drop_succ xs i _ + | _ :: _, 0, _ => by simp + | _ :: xs, i + 1, p => prod_drop_succ xs i (Nat.lt_of_succ_lt_succ p) /-- Cancellation of a telescoping product. -/ @[to_additive "Cancellation of a telescoping sum."] @@ -426,7 +430,7 @@ theorem prod_range_div' (n : ℕ) (f : ℕ → G) : induction n with | zero => exact (div_self' (f 0)).symm | succ n h => - rw [range_succ, map_append, map_singleton, prod_append, prod_singleton, h, div_mul_div_cancel'] + rw [range_succ, map_append, map_singleton, prod_append, prod_singleton, h, div_mul_div_cancel] lemma prod_rotate_eq_one_of_prod_eq_one : ∀ {l : List G} (_ : l.prod = 1) (n : ℕ), (l.rotate n).prod = 1 @@ -548,14 +552,16 @@ theorem alternatingProd_cons (a : α) (l : List α) : end Alternating lemma sum_nat_mod (l : List ℕ) (n : ℕ) : l.sum % n = (l.map (· % n)).sum % n := by - induction' l with a l ih - · simp only [Nat.zero_mod, map_nil] - · simpa only [map_cons, sum_cons, Nat.mod_add_mod, Nat.add_mod_mod] using congr((a + $ih) % n) + induction l with + | nil => simp only [Nat.zero_mod, map_nil] + | cons a l ih => + simpa only [map_cons, sum_cons, Nat.mod_add_mod, Nat.add_mod_mod] using congr((a + $ih) % n) lemma prod_nat_mod (l : List ℕ) (n : ℕ) : l.prod % n = (l.map (· % n)).prod % n := by - induction' l with a l ih - · simp only [Nat.zero_mod, map_nil] - · simpa only [prod_cons, map_cons, Nat.mod_mul_mod, Nat.mul_mod_mod] using congr((a * $ih) % n) + induction l with + | nil => simp only [Nat.zero_mod, map_nil] + | cons a l ih => + simpa only [prod_cons, map_cons, Nat.mod_mul_mod, Nat.mul_mod_mod] using congr((a * $ih) % n) lemma sum_int_mod (l : List ℤ) (n : ℤ) : l.sum % n = (l.map (· % n)).sum % n := by induction l <;> simp [Int.add_emod, *] @@ -568,9 +574,10 @@ variable [DecidableEq α] /-- Summing the count of `x` over a list filtered by some `p` is just `countP` applied to `p` -/ theorem sum_map_count_dedup_filter_eq_countP (p : α → Bool) (l : List α) : ((l.dedup.filter p).map fun x => l.count x).sum = l.countP p := by - induction' l with a as h - · simp - · simp_rw [List.countP_cons, List.count_cons, List.sum_map_add] + induction l with + | nil => simp + | cons a as h => + simp_rw [List.countP_cons, List.count_cons, List.sum_map_add] congr 1 · refine _root_.trans ?_ h by_cases ha : a ∈ as @@ -587,7 +594,7 @@ theorem sum_map_count_dedup_filter_eq_countP (p : α → Bool) (l : List α) : obtain ⟨a', ha'⟩ := List.mem_map.1 hn split_ifs at ha' with ha · simp only [ha.symm, mem_filter, mem_dedup, find?, mem_cons, true_or, hp, - and_false, false_and] at ha' + and_false, false_and, reduceCtorEq] at ha' · exact ha'.2.symm theorem sum_map_count_dedup_eq_length (l : List α) : @@ -619,7 +626,7 @@ 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 + (List.foldl_eq_foldr _ _).symm namespace List @@ -632,20 +639,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 _ _ _ @@ -688,9 +690,11 @@ theorem neg_one_mem_of_prod_eq_neg_one {l : List ℤ} (h : l.prod = -1) : (-1 : /-- If all elements in a list are bounded below by `1`, then the length of the list is bounded by the sum of the elements. -/ theorem length_le_sum_of_one_le (L : List ℕ) (h : ∀ i ∈ L, 1 ≤ i) : L.length ≤ L.sum := by - induction' L with j L IH h; · simp - rw [sum_cons, length, add_comm] - exact Nat.add_le_add (h _ (mem_cons_self _ _)) (IH fun i hi => h i (mem_cons.2 (Or.inr hi))) + induction L with + | nil => simp + | cons j L IH => + rw [sum_cons, length, add_comm] + exact Nat.add_le_add (h _ (mem_cons_self _ _)) (IH fun i hi => h i (mem_cons.2 (Or.inr hi))) theorem dvd_prod [CommMonoid M] {a} {l : List M} (ha : a ∈ l) : a ∣ l.prod := by let ⟨s, t, h⟩ := append_of_mem ha @@ -756,13 +760,4 @@ lemma unop_map_list_prod {F : Type*} [FunLike F M Nᵐᵒᵖ] [MonoidHomClass F (f l.prod).unop = (l.map (MulOpposite.unop ∘ f)).reverse.prod := by rw [map_list_prod f l, MulOpposite.unop_list_prod, List.map_map] -namespace MonoidHom - -/-- A morphism into the opposite monoid acts on the product by acting on the reversed elements. -/ -@[deprecated _root_.unop_map_list_prod (since := "2023-01-10")] -protected theorem unop_map_list_prod (f : M →* Nᵐᵒᵖ) (l : List M) : - (f l.prod).unop = (l.map (MulOpposite.unop ∘ f)).reverse.prod := - unop_map_list_prod f l - -end MonoidHom end MonoidHom diff --git a/Mathlib/Algebra/BigOperators/Group/Multiset.lean b/Mathlib/Algebra/BigOperators/Group/Multiset.lean index b2d09816f2c5b..b3ab0b0f8c124 100644 --- a/Mathlib/Algebra/BigOperators/Group/Multiset.lean +++ b/Mathlib/Algebra/BigOperators/Group/Multiset.lean @@ -36,17 +36,17 @@ 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 := @@ -63,7 +63,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 @@ -106,23 +106,28 @@ theorem prod_replicate (n : ℕ) (a : α) : (replicate n a).prod = a ^ n := by @[to_additive] theorem prod_map_eq_pow_single [DecidableEq ι] (i : ι) (hf : ∀ i' ≠ i, i' ∈ m → f i' = 1) : (m.map f).prod = f i ^ m.count i := by - induction' m using Quotient.inductionOn with l + induction m using Quotient.inductionOn simp [List.prod_map_eq_pow_single i f hf] @[to_additive] theorem prod_eq_pow_single [DecidableEq α] (a : α) (h : ∀ a' ≠ a, a' ∈ s → a' = 1) : s.prod = a ^ s.count a := by - induction' s using Quotient.inductionOn with l - simp [List.prod_eq_pow_single a h] + induction s using Quotient.inductionOn; simp [List.prod_eq_pow_single a h] @[to_additive] lemma prod_eq_one (h : ∀ x ∈ s, x = (1 : α)) : s.prod = 1 := by - induction' s using Quotient.inductionOn with l; simp [List.prod_eq_one h] + induction s using Quotient.inductionOn; simp [List.prod_eq_one h] @[to_additive] 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) : @@ -136,6 +141,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₁ : ι → α) @@ -172,19 +183,20 @@ 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 ≠ ∅) (p_s : ∀ a ∈ s, p a) : p s.prod := by -- Porting note: used to be `refine' Multiset.induction _ _` - induction' s using Multiset.induction_on with a s hsa - · simp at hs - rw [prod_cons] - by_cases hs_empty : s = ∅ - · simp [hs_empty, p_s a] - have hps : ∀ x, x ∈ s → p x := fun x hxs => p_s x (mem_cons_of_mem hxs) - exact p_mul a s.prod (p_s a (mem_cons_self a s)) (hsa hs_empty hps) + induction s using Multiset.induction_on with + | empty => simp at hs + | cons a s hsa => + rw [prod_cons] + by_cases hs_empty : s = ∅ + · simp [hs_empty, p_s a] + have hps : ∀ x, x ∈ s → p x := fun x hxs => p_s x (mem_cons_of_mem hxs) + exact p_mul a s.prod (p_s a (mem_cons_self a s)) (hsa hs_empty hps) theorem prod_dvd_prod_of_le (h : s ≤ t) : s.prod ∣ t.prod := by obtain ⟨z, rfl⟩ := exists_add_of_le h @@ -194,10 +206,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 +294,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 new file mode 100644 index 0000000000000..c969334d05c0a --- /dev/null +++ b/Mathlib/Algebra/BigOperators/GroupWithZero/Action.lean @@ -0,0 +1,119 @@ +/- +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.Algebra.GroupWithZero.Action.Defs +import Mathlib.Data.Finset.Basic +import Mathlib.Data.Multiset.Basic +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. +-/ + + +variable {α β γ : Type*} + +section + +variable [AddMonoid β] [DistribSMul α β] + +theorem List.smul_sum {r : α} {l : List β} : r • l.sum = (l.map (r • ·)).sum := + map_list_sum (DistribSMul.toAddMonoidHom β r) l + +end + +section + +variable [Monoid α] [Monoid β] [MulDistribMulAction α β] + +theorem List.smul_prod' {r : α} {l : List β} : r • l.prod = (l.map (r • ·)).prod := + map_list_prod (MulDistribMulAction.toMonoidHom β r) l + +end + +section + +variable [AddCommMonoid β] [DistribSMul α β] + +theorem Multiset.smul_sum {r : α} {s : Multiset β} : r • s.sum = (s.map (r • ·)).sum := + (DistribSMul.toAddMonoidHom β r).map_multiset_sum s + +theorem Finset.smul_sum {r : α} {f : γ → β} {s : Finset γ} : + (r • ∑ x ∈ s, f x) = ∑ x ∈ s, r • f x := + map_sum (DistribSMul.toAddMonoidHom β r) f s + +end + +section + +variable [Monoid α] [CommMonoid β] [MulDistribMulAction α β] + +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 γ} : + (r • ∏ x ∈ s, f x) = ∏ x ∈ s, r • f x := + map_prod (MulDistribMulAction.toMonoidHom β r) f s + +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'] + +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/GroupWithZero/Finset.lean b/Mathlib/Algebra/BigOperators/GroupWithZero/Finset.lean index e1f1eccb24706..6031d188022c6 100644 --- a/Mathlib/Algebra/BigOperators/GroupWithZero/Finset.lean +++ b/Mathlib/Algebra/BigOperators/GroupWithZero/Finset.lean @@ -24,15 +24,16 @@ variable [CommMonoidWithZero M₀] {p : ι → Prop} [DecidablePred p] {f : ι lemma prod_eq_zero (hi : i ∈ s) (h : f i = 0) : ∏ j ∈ s, f j = 0 := by classical rw [← prod_erase_mul _ _ hi, h, mul_zero] -lemma prod_boole : ∏ i ∈ s, (ite (p i) 1 0 : M₀) = ite (∀ i ∈ s, p i) 1 0 := by +lemma prod_ite_zero : + (∏ i ∈ s, if p i then f i else 0) = if ∀ i ∈ s, p i then ∏ i ∈ s, f i else 0 := by split_ifs with h - · apply prod_eq_one - intro i hi - rw [if_pos (h i hi)] + · exact prod_congr rfl fun i hi => by simp [h i hi] · push_neg at h rcases h with ⟨i, hi, hq⟩ - apply prod_eq_zero hi - rw [if_neg hq] + exact prod_eq_zero hi (by simp [hq]) + +lemma prod_boole : ∏ i ∈ s, (ite (p i) 1 0 : M₀) = ite (∀ i ∈ s, p i) 1 0 := by + rw [prod_ite_zero, prod_const_one] lemma support_prod_subset (s : Finset ι) (f : ι → κ → M₀) : support (fun x ↦ ∏ i ∈ s, f i x) ⊆ ⋂ i ∈ s, support (f i) := @@ -42,9 +43,9 @@ variable [Nontrivial M₀] [NoZeroDivisors M₀] lemma prod_eq_zero_iff : ∏ x ∈ s, f x = 0 ↔ ∃ a ∈ s, f a = 0 := by classical - induction' s using Finset.induction_on with a s ha ih - · exact ⟨Not.elim one_ne_zero, fun ⟨_, H, _⟩ => by simp at H⟩ - · rw [prod_insert ha, mul_eq_zero, exists_mem_insert, ih] + induction s using Finset.induction_on with + | empty => exact ⟨Not.elim one_ne_zero, fun ⟨_, H, _⟩ => by simp at H⟩ + | insert ha ih => rw [prod_insert ha, mul_eq_zero, exists_mem_insert, ih] lemma prod_ne_zero_iff : ∏ x ∈ s, f x ≠ 0 ↔ ∀ a ∈ s, f a ≠ 0 := by rw [Ne, prod_eq_zero_iff] @@ -57,7 +58,10 @@ lemma support_prod (s : Finset ι) (f : ι → κ → M₀) : end Finset namespace Fintype -variable [Fintype ι] [CommMonoidWithZero M₀] {p : ι → Prop} [DecidablePred p] +variable [Fintype ι] [CommMonoidWithZero M₀] {p : ι → Prop} [DecidablePred p] {f : ι → M₀} + +lemma prod_ite_zero : (∏ i, if p i then f i else 0) = if ∀ i, p i then ∏ i, f i else 0 := by + simp [Finset.prod_ite_zero] lemma prod_boole : ∏ i, (ite (p i) 1 0 : M₀) = ite (∀ i, p i) 1 0 := by simp [Finset.prod_boole] diff --git a/Mathlib/Algebra/BigOperators/Intervals.lean b/Mathlib/Algebra/BigOperators/Intervals.lean index af96f697d0ba2..3193db4f355ef 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)⁻¹ := @@ -193,7 +204,7 @@ theorem prod_Ico_reflect (f : ℕ → M) (k : ℕ) {m n : ℕ} (h : m ≤ n + 1) have : ∀ i < m, i ≤ n := by intro i hi exact (add_le_add_iff_right 1).1 (le_trans (Nat.lt_iff_add_one_le.1 hi) h) - cases' lt_or_le k m with hkm hkm + rcases lt_or_le k m with hkm | hkm · rw [← Nat.Ico_image_const_sub_eq_Ico (this _ hkm)] refine (prod_image ?_).symm simp only [mem_Ico] 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/Ring.lean b/Mathlib/Algebra/BigOperators/Ring.lean index 71bf64045aeca..8ffa27de019be 100644 --- a/Mathlib/Algebra/BigOperators/Ring.lean +++ b/Mathlib/Algebra/BigOperators/Ring.lean @@ -109,10 +109,11 @@ variable [DecidableEq ι] 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 a s ha ih - · rw [pi_empty, sum_singleton] - rfl - · have h₁ : ∀ x ∈ t a, ∀ y ∈ t a, x ≠ y → + induction s using Finset.induction with + | empty => simp + | insert ha ih => + rename_i a s + have h₁ : ∀ x ∈ t a, ∀ y ∈ t a, x ≠ y → Disjoint (image (Pi.cons s a x) (pi s t)) (image (Pi.cons s a y) (pi s t)) := by intro x _ y _ h simp only [disjoint_iff_ne, mem_image] @@ -168,7 +169,7 @@ theorem prod_add (f g : ι → α) (s : Finset ι) : (by simp) (by simp [Classical.em]) (by simp_rw [mem_filter, Function.funext_iff, eq_iff_iff, mem_pi, mem_insert]; tauto) - (by simp_rw [ext_iff, @mem_filter _ _ (id _), mem_powerset]; tauto) + (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, Subtype.map_coe, id_eq, prod_attach, filter_congr_decidable] @@ -238,7 +239,7 @@ lemma prod_sub_ordered [LinearOrder ι] (s : Finset ι) (f g : ι → α) : simp /-- `∏ 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. -/ +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 rw [prod_sub_ordered] diff --git a/Mathlib/Algebra/BigOperators/Ring/List.lean b/Mathlib/Algebra/BigOperators/Ring/List.lean index 55d9be58b9004..5825782ff4ddb 100644 --- a/Mathlib/Algebra/BigOperators/Ring/List.lean +++ b/Mathlib/Algebra/BigOperators/Ring/List.lean @@ -24,9 +24,10 @@ namespace Commute variable [NonUnitalNonAssocSemiring R] lemma list_sum_right (a : R) (l : List R) (h : ∀ b ∈ l, Commute a b) : Commute a l.sum := by - induction' l with x xs ih - · exact Commute.zero_right _ - · rw [List.sum_cons] + induction l with + | nil => exact Commute.zero_right _ + | cons x xs ih => + rw [List.sum_cons] exact (h _ <| mem_cons_self _ _).add_right (ih fun j hj ↦ h _ <| mem_cons_of_mem _ hj) lemma list_sum_left (b : R) (l : List R) (h : ∀ a ∈ l, Commute a b) : Commute l.sum b := @@ -55,7 +56,7 @@ lemma prod_eq_zero : ∀ {l : List M₀}, (0 : M₀) ∈ l → l.prod = 0 -- | absurd h (not_mem_nil _) | a :: l, h => by rw [prod_cons] - cases' mem_cons.1 h with ha hl + rcases mem_cons.1 h with ha | hl exacts [mul_eq_zero_of_left ha.symm _, mul_eq_zero_of_right _ (prod_eq_zero hl)] variable [Nontrivial M₀] [NoZeroDivisors M₀] @@ -82,9 +83,10 @@ lemma sum_map_mul_right : (l.map fun b ↦ f b * r).sum = (l.map f).sum * r := end NonUnitalNonAssocSemiring lemma dvd_sum [NonUnitalSemiring R] {a} {l : List R} (h : ∀ x ∈ l, a ∣ x) : a ∣ l.sum := by - induction' l with x l ih - · exact dvd_zero _ - · rw [List.sum_cons] + induction l with + | nil => exact dvd_zero _ + | cons x l ih => + rw [List.sum_cons] exact dvd_add (h _ (mem_cons_self _ _)) (ih fun x hx ↦ h x (mem_cons_of_mem _ hx)) @[simp] lemma sum_zipWith_distrib_left [Semiring R] (f : ι → κ → R) (a : R) : diff --git a/Mathlib/Algebra/BigOperators/Ring/Nat.lean b/Mathlib/Algebra/BigOperators/Ring/Nat.lean index 1b3759dd9bbe0..935c47b1fec02 100644 --- a/Mathlib/Algebra/BigOperators/Ring/Nat.lean +++ b/Mathlib/Algebra/BigOperators/Ring/Nat.lean @@ -22,11 +22,11 @@ lemma even_sum_iff_even_card_odd {s : Finset ι} (f : ι → ℕ) : rw [← Finset.sum_filter_add_sum_filter_not _ (fun x ↦ Even (f x)), Nat.even_add] simp only [Finset.mem_filter, and_imp, imp_self, implies_true, Finset.even_sum, true_iff] rw [Nat.even_iff, Finset.sum_nat_mod, Finset.sum_filter] - simp (config := { contextual := true }) only [← Nat.odd_iff_not_even, Nat.odd_iff.mp] + simp (config := { contextual := true }) only [Nat.not_even_iff_odd, Nat.odd_iff.mp] simp_rw [← Finset.sum_filter, ← Nat.even_iff, Finset.card_eq_sum_ones] lemma odd_sum_iff_odd_card_odd {s : Finset ι} (f : ι → ℕ) : Odd (∑ i ∈ s, f i) ↔ Odd (s.filter fun x ↦ Odd (f x)).card := by - simp only [Nat.odd_iff_not_even, even_sum_iff_even_card_odd] + simp only [← Nat.not_even_iff_odd, even_sum_iff_even_card_odd] end Finset diff --git a/Mathlib/Algebra/BigOperators/WithTop.lean b/Mathlib/Algebra/BigOperators/WithTop.lean index 5defb21c328a8..17d569cd5b075 100644 --- a/Mathlib/Algebra/BigOperators/WithTop.lean +++ b/Mathlib/Algebra/BigOperators/WithTop.lean @@ -24,27 +24,36 @@ variable [AddCommMonoid α] {s : Finset ι} {f : ι → WithTop α} ∑ i ∈ s, f i = ∑ i ∈ s, (f i : WithTop α) := map_sum addHom f s /-- A sum is infinite iff one term is infinite. -/ -lemma sum_eq_top_iff : ∑ i ∈ s, f i = ⊤ ↔ ∃ i ∈ s, f i = ⊤ := by +@[simp] lemma sum_eq_top : ∑ i ∈ s, f i = ⊤ ↔ ∃ i ∈ s, f i = ⊤ := by induction s using Finset.cons_induction <;> simp [*] +/-- A sum is finite iff all terms are finite. -/ +lemma sum_ne_top : ∑ i ∈ s, f i ≠ ⊤ ↔ ∀ i ∈ s, f i ≠ ⊤ := by simp + variable [LT α] /-- A sum is finite iff all terms are finite. -/ -lemma sum_lt_top_iff : ∑ i ∈ s, f i < ⊤ ↔ ∀ i ∈ s, f i < ⊤ := by - simp only [WithTop.lt_top_iff_ne_top, ne_eq, sum_eq_top_iff, not_exists, not_and] +@[simp] lemma sum_lt_top : ∑ i ∈ s, f i < ⊤ ↔ ∀ i ∈ s, f i < ⊤ := by + simp [WithTop.lt_top_iff_ne_top] -/-- A sum of finite terms is finite. -/ -lemma sum_lt_top (h : ∀ i ∈ s, f i ≠ ⊤) : ∑ i ∈ s, f i < ⊤ := - sum_lt_top_iff.2 fun i hi ↦ WithTop.lt_top_iff_ne_top.2 (h i hi) +@[deprecated (since := "2024-08-25")] alias sum_eq_top_iff := sum_eq_top +@[deprecated (since := "2024-08-25")] alias sum_lt_top_iff := sum_lt_top end AddCommMonoid +section CommMonoidWithZero +variable [CommMonoidWithZero α] [NoZeroDivisors α] [Nontrivial α] [DecidableEq α] + {s : Finset ι} {f : ι → WithTop α} + +/-- A product of finite terms is finite. -/ +lemma prod_ne_top (h : ∀ i ∈ s, f i ≠ ⊤) : ∏ i ∈ s, f i ≠ ⊤ := + prod_induction f (· ≠ ⊤) (fun _ _ ↦ mul_ne_top) coe_ne_top h + /-- A product of finite terms is finite. -/ -lemma prod_lt_top [CommMonoidWithZero α] [NoZeroDivisors α] [Nontrivial α] [DecidableEq α] [LT α] - {s : Finset ι} {f : ι → WithTop α} (h : ∀ i ∈ s, f i ≠ ⊤) : ∏ i ∈ s, f i < ⊤ := - prod_induction f (· < ⊤) (fun _ _ h₁ h₂ ↦ mul_lt_top' h₁ h₂) (coe_lt_top 1) - fun a ha ↦ WithTop.lt_top_iff_ne_top.2 (h a ha) +lemma prod_lt_top [LT α] (h : ∀ i ∈ s, f i < ⊤) : ∏ i ∈ s, f i < ⊤ := + prod_induction f (· < ⊤) (fun _ _ ↦ mul_lt_top) (coe_lt_top _) h +end CommMonoidWithZero end WithTop namespace WithBot @@ -70,10 +79,25 @@ lemma sum_lt_bot (h : ∀ i ∈ s, f i ≠ ⊥) : ⊥ < ∑ i ∈ s, f i := end AddCommMonoid +section CommMonoidWithZero +variable [CommMonoidWithZero α] [NoZeroDivisors α] [Nontrivial α] [DecidableEq α] + {s : Finset ι} {f : ι → WithBot α} + +/-- A product of finite terms is finite. -/ +lemma prod_ne_bot (h : ∀ i ∈ s, f i ≠ ⊥) : ∏ i ∈ s, f i ≠ ⊥ := + prod_induction f (· ≠ ⊥) (fun _ _ ↦ mul_ne_bot) coe_ne_bot h + +/-- A product of finite terms is finite. -/ +lemma bot_lt_prod [LT α] (h : ∀ i ∈ s, ⊥ < f i) : ⊥ < ∏ i ∈ s, f i := + prod_induction f (⊥ < ·) (fun _ _ ↦ bot_lt_mul) (bot_lt_coe _) h + +end CommMonoidWithZero + /-- A product of finite terms is finite. -/ +@[deprecated bot_lt_prod (since := "2024-08-25")] lemma prod_lt_bot [CommMonoidWithZero α] [NoZeroDivisors α] [Nontrivial α] [DecidableEq α] [LT α] {s : Finset ι} {f : ι → WithBot α} (h : ∀ i ∈ s, f i ≠ ⊥) : ⊥ < ∏ i ∈ s, f i := - prod_induction f (⊥ < ·) (fun _ _ h₁ h₂ ↦ bot_lt_mul' h₁ h₂) (bot_lt_coe 1) + prod_induction f (⊥ < ·) (fun _ _ h₁ h₂ ↦ bot_lt_mul h₁ h₂) (bot_lt_coe 1) fun a ha ↦ WithBot.bot_lt_iff_ne_bot.2 (h a ha) end WithBot diff --git a/Mathlib/Algebra/Bounds.lean b/Mathlib/Algebra/Bounds.lean deleted file mode 100644 index 95219c22b4fa9..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.Order.Group.OrderIso -import Mathlib.Data.Set.Pointwise.Basic -import Mathlib.Order.Bounds.OrderIso -import Mathlib.Order.ConditionallyCompleteLattice.Basic -import Mathlib.Algebra.Order.Monoid.Unbundled.OrderDual - -/-! -# 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..36546a9af0623 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 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 48be5957eed6d..9dbed63a629b2 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 := 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, 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, 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 X Y Z => TensorProduct.ext₃ (fun x y z => rfl) + leftUnitor_eq := fun X => TensorProduct.ext' (fun x y => rfl) + rightUnitor_eq := fun X => TensorProduct.ext' (fun x y => rfl) } 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..0d3b3d8260dad 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 diff --git a/Mathlib/Algebra/Category/CoalgebraCat/Basic.lean b/Mathlib/Algebra/Category/CoalgebraCat/Basic.lean index 2e3227b072f57..cbf7f0ebab743 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 diff --git a/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean b/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean index 7fe43405b8530..0a138d78803f1 100644 --- a/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean +++ b/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean @@ -15,15 +15,15 @@ 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 -We make the definiton `CoalgebraCat.instMonoidalCategoryAux` in this file, which is the +We make the definition `CoalgebraCat.instMonoidalCategoryAux` in this file, which is the 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..6eb6644109de4 --- /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 X Y := 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 18557f976c125..d3443fcb9cfc5 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 @@ -78,6 +78,9 @@ instance : free.{u}.IsLeftAdjoint := instance : (forget AddCommGrp.{u}).IsRightAdjoint := ⟨_, ⟨adj⟩⟩ +instance : AddCommGrp.free.{u}.IsLeftAdjoint := + ⟨_, ⟨adj⟩⟩ + /-- As an example, we now give a high-powered proof that the monomorphisms in `AddCommGroup` are just the injective functions. @@ -174,8 +177,8 @@ 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 X Y ↦ { toFun := fun f => MonoidHom.toHomUnits f invFun := fun f => (Units.coeHom Y).comp f left_inv := fun f => MonoidHom.ext fun _ => rfl @@ -185,9 +188,7 @@ def Grp.forget₂MonAdj : forget₂ Grp MonCat ⊣ MonCat.units.{u} where 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 + naturality := by intros; exact MonoidHom.ext fun x => rfl } } instance : MonCat.units.{u}.IsRightAdjoint := ⟨_, ⟨Grp.forget₂MonAdj⟩⟩ @@ -201,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 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 } } instance : CommMonCat.units.{u}.IsRightAdjoint := ⟨_, ⟨CommGrp.forget₂CommMonAdj⟩⟩ diff --git a/Mathlib/Algebra/Category/Grp/Biproducts.lean b/Mathlib/Algebra/Category/Grp/Biproducts.lean index 343c5d74d0527..a45ba714db4a0 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 diff --git a/Mathlib/Algebra/Category/Grp/Colimits.lean b/Mathlib/Algebra/Category/Grp/Colimits.lean index 68b7e009d27e5..218f0d859b5ad 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.GroupTheory.QuotientGroup import Mathlib.CategoryTheory.Limits.Shapes.Kernels import Mathlib.CategoryTheory.Limits.Shapes.FiniteLimits import Mathlib.CategoryTheory.ConcreteCategory.Elementwise +import Mathlib.GroupTheory.QuotientGroup.Basic /-! # 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/EpiMono.lean b/Mathlib/Algebra/Category/Grp/EpiMono.lean index 31c09a8f4a5fe..472da6d5b3651 100644 --- a/Mathlib/Algebra/Category/Grp/EpiMono.lean +++ b/Mathlib/Algebra/Category/Grp/EpiMono.lean @@ -4,9 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jujian Zhang -/ import Mathlib.Algebra.Category.Grp.EquivalenceGroupAddGroup -import Mathlib.GroupTheory.QuotientGroup import Mathlib.CategoryTheory.ConcreteCategory.EpiMono import Mathlib.CategoryTheory.Limits.Constructions.EpiMono +import Mathlib.GroupTheory.QuotientGroup.Basic /-! # Monomorphisms and epimorphisms in `Group` diff --git a/Mathlib/Algebra/Category/Grp/EquivalenceGroupAddGroup.lean b/Mathlib/Algebra/Category/Grp/EquivalenceGroupAddGroup.lean index 4c58186eba37a..ba62f49de2a29 100644 --- a/Mathlib/Algebra/Category/Grp/EquivalenceGroupAddGroup.lean +++ b/Mathlib/Algebra/Category/Grp/EquivalenceGroupAddGroup.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jujian Zhang -/ import Mathlib.Algebra.Category.Grp.Basic -import Mathlib.Algebra.Group.Equiv.TypeTags /-! # Equivalence between `Group` and `AddGroup` @@ -27,7 +26,7 @@ private instance (X : CommGrp) : MulOneClass X.α := X.str.toMulOneClass private instance (X : AddGrp) : AddZeroClass X.α := X.str.toAddZeroClass private instance (X : AddCommGrp) : AddZeroClass X.α := X.str.toAddZeroClass -/-- The functor `Group ⥤ AddGroup` by sending `X ↦ Additive X` and `f ↦ f`. +/-- The functor `Grp ⥤ AddGrp` by sending `X ↦ Additive X` and `f ↦ f`. -/ @[simps] def toAddGrp : Grp ⥤ AddGrp where @@ -38,7 +37,7 @@ end Grp namespace CommGrp -/-- The functor `CommGroup ⥤ AddCommGroup` by sending `X ↦ Additive X` and `f ↦ f`. +/-- The functor `CommGrp ⥤ AddCommGrp` by sending `X ↦ Additive X` and `f ↦ f`. -/ @[simps] def toAddCommGrp : CommGrp ⥤ AddCommGrp where @@ -49,7 +48,7 @@ end CommGrp namespace AddGrp -/-- The functor `AddGroup ⥤ Group` by sending `X ↦ Multiplicative Y` and `f ↦ f`. +/-- The functor `AddGrp ⥤ Grp` by sending `X ↦ Multiplicative Y` and `f ↦ f`. -/ @[simps] def toGrp : AddGrp ⥤ Grp where @@ -60,7 +59,7 @@ end AddGrp namespace AddCommGrp -/-- The functor `AddCommGroup ⥤ CommGroup` by sending `X ↦ Multiplicative Y` and `f ↦ f`. +/-- The functor `AddCommGrp ⥤ CommGrp` by sending `X ↦ Multiplicative Y` and `f ↦ f`. -/ @[simps] def toCommGrp : AddCommGrp ⥤ CommGrp where @@ -69,16 +68,20 @@ def toCommGrp : AddCommGrp ⥤ CommGrp where end AddCommGrp -/-- The equivalence of categories between `Group` and `AddGroup` +/-- The equivalence of categories between `Grp` and `AddGrp` -/ -def groupAddGroupEquivalence : Grp ≌ AddGrp := - CategoryTheory.Equivalence.mk Grp.toAddGrp AddGrp.toGrp - (NatIso.ofComponents fun X => MulEquiv.toGrpIso (MulEquiv.multiplicativeAdditive X)) - (NatIso.ofComponents fun X => AddEquiv.toAddGrpIso (AddEquiv.additiveMultiplicative X)) +@[simps] +def groupAddGroupEquivalence : Grp ≌ AddGrp where + functor := Grp.toAddGrp + inverse := AddGrp.toGrp + unitIso := Iso.refl _ + counitIso := Iso.refl _ -/-- The equivalence of categories between `CommGroup` and `AddCommGroup`. +/-- The equivalence of categories between `CommGrp` and `AddCommGrp`. -/ -def commGroupAddCommGroupEquivalence : CommGrp ≌ AddCommGrp := - CategoryTheory.Equivalence.mk CommGrp.toAddCommGrp AddCommGrp.toCommGrp - (NatIso.ofComponents fun X => MulEquiv.toCommGrpIso (MulEquiv.multiplicativeAdditive X)) - (NatIso.ofComponents fun X => AddEquiv.toAddCommGrpIso (AddEquiv.additiveMultiplicative X)) +@[simps] +def commGroupAddCommGroupEquivalence : CommGrp ≌ AddCommGrp where + functor := CommGrp.toAddCommGrp + inverse := AddCommGrp.toCommGrp + unitIso := Iso.refl _ + counitIso := Iso.refl _ diff --git a/Mathlib/Algebra/Category/Grp/FilteredColimits.lean b/Mathlib/Algebra/Category/Grp/FilteredColimits.lean index fe2f4bcd125da..b79cc51e0f2ed 100644 --- a/Mathlib/Algebra/Category/Grp/FilteredColimits.lean +++ b/Mathlib/Algebra/Category/Grp/FilteredColimits.lean @@ -58,7 +58,7 @@ abbrev G.mk : (Σ j, F.obj j) → G.{v, u} F := theorem G.mk_eq (x y : Σ j, F.obj j) (h : ∃ (k : J) (f : x.1 ⟶ k) (g : y.1 ⟶ k), F.map f x.2 = F.map g y.2) : G.mk.{v, u} F x = G.mk F y := - Quot.EqvGen_sound (Types.FilteredColimit.eqvGen_quot_rel_of_rel (F ⋙ forget Grp) x y h) + Quot.eqvGen_sound (Types.FilteredColimit.eqvGen_quot_rel_of_rel (F ⋙ forget Grp) x y h) /-- The "unlifted" version of taking inverses in the colimit. -/ @[to_additive "The \"unlifted\" version of negation in the colimit."] @@ -94,7 +94,7 @@ noncomputable instance colimitGroup : Group (G.{v, u} F) := { colimitInv.{v, u} F, (G.{v, u} F).str with inv_mul_cancel := fun x => by refine Quot.inductionOn x ?_; clear x; intro x - cases' x with j x + obtain ⟨j, x⟩ := x erw [colimit_inv_mk_eq, colimit_mul_mk_eq (F ⋙ forget₂ Grp MonCat.{max v u}) ⟨j, _⟩ ⟨j, _⟩ j (𝟙 j) (𝟙 j), colimit_one_eq (F ⋙ forget₂ Grp MonCat.{max v u}) j] 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/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 f605284f69e1f..0763ecc4606e9 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 @@ -126,7 +126,7 @@ instance hasLimit : HasLimit F := end /-- A functor `F : J ⥤ Grp.{u}` has a limit iff `(F ⋙ forget Grp).sections` is -`u`-small. -/ +`u`-small. -/ @[to_additive "A functor `F : J ⥤ AddGrp.{u}` has a limit iff `(F ⋙ forget AddGrp).sections` is `u`-small."] lemma hasLimit_iff_small_sections : @@ -281,7 +281,7 @@ instance hasLimit : HasLimit F := end /-- A functor `F : J ⥤ CommGrp.{u}` has a limit iff `(F ⋙ forget CommGrp).sections` is -`u`-small. -/ +`u`-small. -/ @[to_additive "A functor `F : J ⥤ AddCommGrp.{u}` has a limit iff `(F ⋙ forget AddCommGrp).sections` is `u`-small."] lemma hasLimit_iff_small_sections : 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..413f5f5b36aba 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 diff --git a/Mathlib/Algebra/Category/ModuleCat/Abelian.lean b/Mathlib/Algebra/Category/ModuleCat/Abelian.lean index 274f4ea89cd2d..401fb715425c1 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Abelian.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Abelian.lean @@ -39,7 +39,7 @@ def normalMono (hf : Mono f) : NormalMono f where calc M ≃ₗ[R] f.ker.quotient : (Submodule.quotEquivOfEqBot _ (ker_eq_bot_of_mono _)).symm ... ≃ₗ[R] f.range : LinearMap.quotKerEquivRange f - ... ≃ₗ[R] r.range.mkq.ker : LinearEquiv.ofEq _ _ (Submodule.ker_mkQ _).symm + ... ≃ₗ[R] r.range.mkQ.ker : LinearEquiv.ofEq _ _ (Submodule.ker_mkQ _).symm ``` -/ IsKernel.isoKernel _ _ (kernelIsLimit _) diff --git a/Mathlib/Algebra/Category/ModuleCat/Adjunctions.lean b/Mathlib/Algebra/Category/ModuleCat/Adjunctions.lean index 9035d34b23389..5fbd14b8fb7c0 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 diff --git a/Mathlib/Algebra/Category/ModuleCat/Algebra.lean b/Mathlib/Algebra/Category/ModuleCat/Algebra.lean index c350e298ae22e..96c3070180a88 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 diff --git a/Mathlib/Algebra/Category/ModuleCat/Basic.lean b/Mathlib/Algebra/Category/ModuleCat/Basic.lean index 48187e0d55415..ec69a10b56fc3 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₂) := @@ -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..4bb37bb584fd6 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 @@ -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 c747c278eb8b7..25c3bca193dcb 100644 --- a/Mathlib/Algebra/Category/ModuleCat/ChangeOfRings.lean +++ b/Mathlib/Algebra/Category/ModuleCat/ChangeOfRings.lean @@ -143,20 +143,23 @@ def semilinearMapAddEquiv {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] (f : section -variable {R : Type u₁} [Ring R] (f : R →+* R) (hf : f = RingHom.id R) +variable {R : Type u₁} [Ring R] (f : R →+* R) /-- For a `R`-module `M`, the restriction of scalars of `M` by the identity morphisms identifies to `M`. -/ -def restrictScalarsId'App (M : ModuleCat R) : (restrictScalars f).obj M ≅ M := +def restrictScalarsId'App (hf : f = RingHom.id R) (M : ModuleCat R) : + (restrictScalars f).obj M ≅ M := LinearEquiv.toModuleIso' <| @AddEquiv.toLinearEquiv _ _ _ _ _ _ (((restrictScalars f).obj M).isModule) _ (by rfl) (fun r x ↦ by subst hf; rfl) -lemma restrictScalarsId'App_hom_apply (M : ModuleCat R) (x : M) : +variable (hf : f = RingHom.id R) + +@[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 @@ -189,19 +192,21 @@ end section variable {R₁ : Type u₁} {R₂ : Type u₂} {R₃ : Type u₃} [Ring R₁] [Ring R₂] [Ring R₃] - (f : R₁ →+* R₂) (g : R₂ →+* R₃) (gf : R₁ →+* R₃) (hgf : gf = g.comp f) + (f : R₁ →+* R₂) (g : R₂ →+* R₃) (gf : R₁ →+* R₃) /-- For each `R₃`-module `M`, restriction of scalars of `M` by a composition of ring morphisms identifies to successively restricting scalars. -/ -def restrictScalarsComp'App (M : ModuleCat R₃) : +def restrictScalarsComp'App (hgf : gf = g.comp f) (M : ModuleCat R₃) : (restrictScalars gf).obj M ≅ (restrictScalars f).obj ((restrictScalars g).obj M) := (AddEquiv.toLinearEquiv (by rfl) (fun r x ↦ by subst hgf; rfl)).toModuleIso' -lemma restrictScalarsComp'App_hom_apply (M : ModuleCat R₃) (x : M) : +variable (hgf : gf = g.comp f) + +@[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 @@ -286,22 +291,21 @@ def map' {M1 M2 : ModuleCat.{v} R} (l : M1 ⟶ M2) : obj' f M1 ⟶ obj' f M2 := theorem map'_id {M : ModuleCat.{v} R} : map' f (𝟙 M) = 𝟙 _ := LinearMap.ext fun x : obj' f M => by dsimp only [map'] - -- Porting note: this got put in the dsimp by mathport - rw [ModuleCat.id_apply] - induction' x using TensorProduct.induction_on with _ _ m s ihx ihy - · rw [map_zero] -- Porting note: simp only [map_zero] failed - · -- Porting note: issues with synthesizing Algebra R S + rw [ModuleCat.id_apply] -- Porting note: this got put in the dsimp by mathport + induction x using TensorProduct.induction_on with + | zero => rw [map_zero] + | tmul => -- Porting note: issues with synthesizing Algebra R S erw [@LinearMap.baseChange_tmul R S M M _ _ (_), ModuleCat.id_apply] - · rw [map_add, ihx, ihy] + | add _ _ ihx ihy => rw [map_add, ihx, ihy] theorem map'_comp {M₁ M₂ M₃ : ModuleCat.{v} R} (l₁₂ : M₁ ⟶ M₂) (l₂₃ : M₂ ⟶ M₃) : map' f (l₁₂ ≫ l₂₃) = map' f l₁₂ ≫ map' f l₂₃ := LinearMap.ext fun x : obj' f M₁ => by dsimp only [map'] - induction' x using TensorProduct.induction_on with _ _ x y ihx ihy - · rfl - · rfl - · rw [map_add, map_add, ihx, ihy] -- Porting note: simp again failing where rw succeeds + induction x using TensorProduct.induction_on with + | zero => rfl + | tmul => rfl + | add _ _ ihx ihy => rw [map_add, map_add, ihx, ihy] end ExtendScalars @@ -527,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] @@ -560,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 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] } instance {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] (f : R →+* S) : (restrictScalars.{max u₂ w} f).IsLeftAdjoint := @@ -660,14 +665,15 @@ def HomEquiv.fromExtendScalars {X Y} (g : X ⟶ (restrictScalars f).obj Y) : rw [map_add] · intro s z change lift _ (s • z) = s • lift _ z - induction' z using TensorProduct.induction_on with s' x x y ih1 ih2 - · rw [smul_zero, map_zero, smul_zero] - · rw [LinearMap.coe_mk, ExtendScalars.smul_tmul] + induction z using TensorProduct.induction_on with + | zero => rw [smul_zero, map_zero, smul_zero] + | tmul s' x => + rw [LinearMap.coe_mk, ExtendScalars.smul_tmul] erw [lift.tmul, lift.tmul] set s' : S := s' change (s * s') • (g x) = s • s' • (g x) rw [mul_smul] - · rw [smul_add, map_add, ih1, ih2, map_add, smul_add] + | add _ _ ih1 ih2 => rw [smul_add, map_add, ih1, ih2, map_add, smul_add] /-- Given `R`-module X and `S`-module Y, `S`-linear linear maps `(extendScalars f).obj X ⟶ Y` bijectively correspond to `R`-linear maps `X ⟶ (restrictScalars f).obj Y`. @@ -680,15 +686,16 @@ def homEquiv {X Y} : left_inv g := by letI m1 : Module R S := Module.compHom S f; letI m2 : Module R Y := Module.compHom Y f apply LinearMap.ext; intro z - induction' z using TensorProduct.induction_on with x s z1 z2 ih1 ih2 - · rw [map_zero, map_zero] - · erw [TensorProduct.lift.tmul] + induction z using TensorProduct.induction_on with + | zero => rw [map_zero, map_zero] + | tmul x s => + erw [TensorProduct.lift.tmul] simp only [LinearMap.coe_mk] change S at x dsimp erw [← LinearMap.map_smul, ExtendScalars.smul_tmul, mul_one x] rfl - · rw [map_add, map_add, ih1, ih2] + | add _ _ ih1 ih2 => rw [map_add, map_add, ih1, ih2] right_inv g := by letI m1 : Module R S := Module.compHom S f; letI m2 : Module R Y := Module.compHom Y f apply LinearMap.ext; intro x @@ -744,14 +751,15 @@ def Counit.map {Y} : (restrictScalars f ⋙ extendScalars f).obj Y ⟶ Y where letI m1 : Module R S := Module.compHom S f letI m2 : Module R Y := Module.compHom Y f dsimp only - induction' z using TensorProduct.induction_on with s' y z1 z2 ih1 ih2 - · rw [smul_zero, map_zero, smul_zero] - · rw [ExtendScalars.smul_tmul, LinearMap.coe_mk] + induction z using TensorProduct.induction_on with + | zero => rw [smul_zero, map_zero, smul_zero] + | tmul s' y => + rw [ExtendScalars.smul_tmul, LinearMap.coe_mk] erw [TensorProduct.lift.tmul, TensorProduct.lift.tmul] set s' : S := s' change (s * s') • y = s • s' • y rw [mul_smul] - · rw [smul_add, map_add, map_add, ih1, ih2, smul_add] + | add _ _ ih1 ih2 => rw [smul_add, map_add, map_add, ih1, ih2, smul_add] -- Porting note: this file has to probably be reworked when -- coercions and instance synthesis are fixed for concrete categories @@ -770,9 +778,10 @@ def counit : restrictScalars.{max v u₂,u₁,u₂} f ⋙ extendScalars f ⟶ letI m2 : Module R Y := Module.compHom Y f letI m2 : Module R Y' := Module.compHom Y' f apply LinearMap.ext; intro z - induction' z using TensorProduct.induction_on with s' y z₁ z₂ ih₁ ih₂ - · rw [map_zero, map_zero] - · dsimp + induction z using TensorProduct.induction_on with + | zero => rw [map_zero, map_zero] + | tmul s' y => + dsimp rw [ModuleCat.coe_comp, ModuleCat.coe_comp, Function.comp_apply, Function.comp_apply, ExtendScalars.map_tmul, restrictScalars.map_apply] -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 @@ -781,8 +790,7 @@ def counit : restrictScalars.{max v u₂,u₁,u₂} f ⋙ extendScalars f ⟶ set s' : S := s' change s' • g y = g (s' • y) rw [map_smul] - · rw [map_add,map_add] - congr 1 + | add _ _ ih₁ ih₂ => rw [map_add, map_add]; congr 1 end ExtendRestrictScalarsAdj /-- Given commutative rings `R, S` and a ring hom `f : R →+* S`, the extension and restriction of @@ -790,31 +798,32 @@ 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 s x _ _ _ _ - · rw [map_zero, map_zero] - · 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 - · 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 + -- 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 } 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..dd77562189b3e 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 diff --git a/Mathlib/Algebra/Category/ModuleCat/Differentials/Presheaf.lean b/Mathlib/Algebra/Category/ModuleCat/Differentials/Presheaf.lean index 1c06b0681c172..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] @@ -143,15 +143,17 @@ lemma app_apply (d : M.Derivation' φ') {X : Dᵒᵖ} (b : R.obj X) : section variable (d : ∀ (X : Dᵒᵖ), (M.obj X).Derivation (φ'.app X)) - (d_map : ∀ ⦃X Y : Dᵒᵖ⦄ (f : X ⟶ Y) (x : R.obj X), - (d Y).d ((R.map f) x) = (M.map f) ((d X).d x)) /-- Given a morphism of presheaves of commutative rings `φ'`, this is the in derivation `M.Derivation' φ'` that is given by a compatible family of derivations with values in the modules `M.obj X` for all `X`. -/ -def mk : M.Derivation' φ' where +def mk (d_map : ∀ ⦃X Y : Dᵒᵖ⦄ (f : X ⟶ Y) (x : R.obj X), + (d Y).d ((R.map f) x) = (M.map f) ((d X).d x)) : M.Derivation' φ' where d {X} := AddMonoidHom.mk' (d X).d (by simp) +variable (d_map : ∀ ⦃X Y : Dᵒᵖ⦄ (f : X ⟶ Y) (x : R.obj X), + (d Y).d ((R.map f) x) = (M.map f) ((d X).d x)) + @[simp] lemma mk_app (X : Dᵒᵖ) : (mk d d_map).app X = d X := rfl @@ -173,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/EpiMono.lean b/Mathlib/Algebra/Category/ModuleCat/EpiMono.lean index d6f7847ecf6bc..ce1d6cca433f8 100644 --- a/Mathlib/Algebra/Category/ModuleCat/EpiMono.lean +++ b/Mathlib/Algebra/Category/ModuleCat/EpiMono.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.Quotient import Mathlib.Algebra.Category.ModuleCat.Basic diff --git a/Mathlib/Algebra/Category/ModuleCat/FilteredColimits.lean b/Mathlib/Algebra/Category/ModuleCat/FilteredColimits.lean index 5beb3d1633472..16abcd3247283 100644 --- a/Mathlib/Algebra/Category/ModuleCat/FilteredColimits.lean +++ b/Mathlib/Algebra/Category/ModuleCat/FilteredColimits.lean @@ -51,7 +51,7 @@ abbrev M.mk : (Σ j, F.obj j) → M F := theorem M.mk_eq (x y : Σ j, F.obj j) (h : ∃ (k : J) (f : x.1 ⟶ k) (g : y.1 ⟶ k), F.map f x.2 = F.map g y.2) : M.mk F x = M.mk F y := - Quot.EqvGen_sound (Types.FilteredColimit.eqvGen_quot_rel_of_rel (F ⋙ forget (ModuleCat R)) x y h) + Quot.eqvGen_sound (Types.FilteredColimit.eqvGen_quot_rel_of_rel (F ⋙ forget (ModuleCat R)) x y h) /-- The "unlifted" version of scalar multiplication in the colimit. -/ def colimitSMulAux (r : R) (x : Σ j, F.obj j) : M F := @@ -80,7 +80,7 @@ theorem colimit_smul_mk_eq (r : R) (x : Σ j, F.obj j) : r • M.mk F x = M.mk F rfl private theorem colimitModule.one_smul (x : (M F)) : (1 : R) • x = x := by - refine Quot.inductionOn x ?_; clear x; intro x; cases' x with j x + refine Quot.inductionOn x ?_; clear x; intro x; obtain ⟨j, x⟩ := x erw [colimit_smul_mk_eq F 1 ⟨j, x⟩] simp rfl @@ -88,11 +88,11 @@ private theorem colimitModule.one_smul (x : (M F)) : (1 : R) • x = x := by -- Porting note (#11083): writing directly the `Module` instance makes things very slow. instance colimitMulAction : MulAction R (M F) where one_smul x := by - refine Quot.inductionOn x ?_; clear x; intro x; cases' x with j x + refine Quot.inductionOn x ?_; clear x; intro x; obtain ⟨j, x⟩ := x erw [colimit_smul_mk_eq F 1 ⟨j, x⟩, one_smul] rfl mul_smul r s x := by - refine Quot.inductionOn x ?_; clear x; intro x; cases' x with j x + refine Quot.inductionOn x ?_; clear x; intro x; obtain ⟨j, x⟩ := x erw [colimit_smul_mk_eq F (r * s) ⟨j, x⟩, colimit_smul_mk_eq F s ⟨j, x⟩, colimit_smul_mk_eq F r ⟨j, _⟩, mul_smul] @@ -102,12 +102,12 @@ instance colimitSMulWithZero : SMulWithZero R (M F) := erw [colimit_zero_eq _ (IsFiltered.nonempty.some : J), colimit_smul_mk_eq, smul_zero] rfl zero_smul := fun x => by - refine Quot.inductionOn x ?_; clear x; intro x; cases' x with j x + refine Quot.inductionOn x ?_; clear x; intro x; obtain ⟨j, x⟩ := x erw [colimit_smul_mk_eq, zero_smul, colimit_zero_eq _ j] rfl } private theorem colimitModule.add_smul (r s : R) (x : (M F)) : (r + s) • x = r • x + s • x := by - refine Quot.inductionOn x ?_; clear x; intro x; cases' x with j x + refine Quot.inductionOn x ?_; clear x; intro x; obtain ⟨j, x⟩ := x erw [colimit_smul_mk_eq, _root_.add_smul, colimit_smul_mk_eq, colimit_smul_mk_eq, colimit_add_mk_eq _ ⟨j, _⟩ ⟨j, _⟩ j (𝟙 j) (𝟙 j)] simp only [Functor.comp_obj, forget₂_obj, Functor.comp_map, CategoryTheory.Functor.map_id, @@ -118,7 +118,7 @@ instance colimitModule : Module R (M F) := { colimitMulAction F, colimitSMulWithZero F with smul_add := fun r x y => by - refine Quot.induction_on₂ x y ?_; clear x y; intro x y; cases' x with i x; cases' y with j y + refine Quot.induction_on₂ x y ?_; clear x y; intro x y; obtain ⟨i, x⟩ := x; obtain ⟨j, y⟩ := y erw [colimit_add_mk_eq _ ⟨i, _⟩ ⟨j, _⟩ (max' i j) (IsFiltered.leftToMax i j) (IsFiltered.rightToMax i j), colimit_smul_mk_eq, smul_add, colimit_smul_mk_eq, colimit_smul_mk_eq, colimit_add_mk_eq _ ⟨i, _⟩ ⟨j, _⟩ (max' i j) (IsFiltered.leftToMax i j) @@ -154,7 +154,7 @@ def colimitDesc (t : Cocone F) : colimit F ⟶ t.pt := (F ⋙ forget₂ (ModuleCatMax.{v, u} R) AddCommGrp.{max v u})).desc ((forget₂ (ModuleCat R) AddCommGrp.{max v u}).mapCocone t) with map_smul' := fun r x => by - refine Quot.inductionOn x ?_; clear x; intro x; cases' x with j x + refine Quot.inductionOn x ?_; clear x; intro x; obtain ⟨j, x⟩ := x erw [colimit_smul_mk_eq] exact LinearMap.map_smul (t.ι.app j) r x } diff --git a/Mathlib/Algebra/Category/ModuleCat/Free.lean b/Mathlib/Algebra/Category/ModuleCat/Free.lean index 7c67bb3e86b4f..9f822325b9425 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Free.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Free.lean @@ -14,19 +14,19 @@ This file proves results about linear independence and span in exact sequences o ## Main theorems * `linearIndependent_shortExact`: Given a short exact sequence `0 ⟶ X₁ ⟶ X₂ ⟶ X₃ ⟶ 0` of - `R`-modules and linearly independent families `v : ι → X₁` and `w : ι' → X₃`, we get a linearly + `R`-modules and linearly independent families `v : ι → X₁` and `w : ι' → X₃`, we get a linearly independent family `ι ⊕ ι' → X₂` * `span_rightExact`: Given an exact sequence `X₁ ⟶ X₂ ⟶ X₃ ⟶ 0` of `R`-modules and spanning - families `v : ι → X₁` and `w : ι' → X₃`, we get a spanning family `ι ⊕ ι' → X₂` + families `v : ι → X₁` and `w : ι' → X₃`, we get a spanning family `ι ⊕ ι' → X₂` * Using `linearIndependent_shortExact` and `span_rightExact`, we prove `free_shortExact`: In a - short exact sequence `0 ⟶ X₁ ⟶ X₂ ⟶ X₃ ⟶ 0` where `X₁` and `X₃` are free, `X₂` is free as well. + short exact sequence `0 ⟶ X₁ ⟶ X₂ ⟶ X₃ ⟶ 0` where `X₁` and `X₃` are free, `X₂` is free as well. ## Tags linear algebra, module, free -/ -open CategoryTheory +open CategoryTheory Module namespace ModuleCat @@ -61,8 +61,8 @@ include hv hm in v| u| w| ι → ι ⊕ ι' ← ι' ``` -where the top row is an exact sequence of modules and the maps on the bottom are `Sum.inl` and -`Sum.inr`. If `u` is injective and `v` and `w` are linearly independent, then `u` is linearly +where the top row is an exact sequence of modules and the maps on the bottom are `Sum.inl` and +`Sum.inr`. If `u` is injective and `v` and `w` are linearly independent, then `u` is linearly independent. -/ theorem linearIndependent_leftExact : LinearIndependent R u := by rw [linearIndependent_sum] @@ -76,7 +76,7 @@ end include hS' hv in /-- Given a short exact sequence `0 ⟶ X₁ ⟶ X₂ ⟶ X₃ ⟶ 0` of `R`-modules and linearly independent - families `v : ι → N` and `w : ι' → P`, we get a linearly independent family `ι ⊕ ι' → M` -/ + families `v : ι → N` and `w : ι' → P`, we get a linearly independent family `ι ⊕ ι' → M` -/ theorem linearIndependent_shortExact {w : ι' → S.X₃} (hw : LinearIndependent R w) : LinearIndependent R (Sum.elim (S.f ∘ v) (S.g.toFun.invFun ∘ w)) := by apply linearIndependent_leftExact hS'.exact hv _ hS'.mono_f rfl @@ -98,8 +98,8 @@ include hS in v| u| w| ι → ι ⊕ ι' ← ι' ``` -where the top row is an exact sequence of modules and the maps on the bottom are `Sum.inl` and -`Sum.inr`. If `v` spans `X₁` and `w` spans `X₃`, then `u` spans `X₂`. -/ +where the top row is an exact sequence of modules and the maps on the bottom are `Sum.inl` and +`Sum.inr`. If `v` spans `X₁` and `w` spans `X₃`, then `u` spans `X₂`. -/ theorem span_exact {β : Type*} {u : ι ⊕ β → S.X₂} (huv : u ∘ Sum.inl = S.f ∘ v) (hv : ⊤ ≤ span R (range v)) (hw : ⊤ ≤ span R (range (S.g ∘ u ∘ Sum.inr))) : @@ -135,7 +135,7 @@ theorem span_exact {β : Type*} {u : ι ⊕ β → S.X₂} (huv : u ∘ Sum.inl include hS in /-- Given an exact sequence `X₁ ⟶ X₂ ⟶ X₃ ⟶ 0` of `R`-modules and spanning - families `v : ι → X₁` and `w : ι' → X₃`, we get a spanning family `ι ⊕ ι' → X₂` -/ + families `v : ι → X₁` and `w : ι' → X₃`, we get a spanning family `ι ⊕ ι' → X₂` -/ theorem span_rightExact {w : ι' → S.X₃} (hv : ⊤ ≤ span R (range v)) (hw : ⊤ ≤ span R (range w)) (hE : Epi S.g) : ⊤ ≤ span R (range (Sum.elim (S.f ∘ v) (S.g.toFun.invFun ∘ w))) := by @@ -144,13 +144,13 @@ 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 -/-- In a short exact sequence `0 ⟶ X₁ ⟶ X₂ ⟶ X₃ ⟶ 0`, given bases for `X₁` and `X₃` -indexed by `ι` and `ι'` respectively, we get a basis for `X₂` indexed by `ι ⊕ ι'`. -/ +/-- In a short exact sequence `0 ⟶ X₁ ⟶ X₂ ⟶ X₃ ⟶ 0`, given bases for `X₁` and `X₃` +indexed by `ι` and `ι'` respectively, we get a basis for `X₂` indexed by `ι ⊕ ι'`. -/ noncomputable def Basis.ofShortExact (bN : Basis ι R S.X₁) (bP : Basis ι' R S.X₃) : Basis (ι ⊕ ι') R S.X₂ := @@ -159,7 +159,7 @@ def Basis.ofShortExact include hS' -/-- In a short exact sequence `0 ⟶ X₁ ⟶ X₂ ⟶ X₃ ⟶ 0`, if `X₁` and `X₃` are free, +/-- In a short exact sequence `0 ⟶ X₁ ⟶ X₂ ⟶ X₃ ⟶ 0`, if `X₁` and `X₃` are free, then `X₂` is free. -/ theorem free_shortExact [Module.Free R S.X₁] [Module.Free R S.X₃] : Module.Free R S.X₂ := @@ -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/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 8644e70e9cf72..cad418c48ab2a 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 @@ -256,21 +256,21 @@ open Opposite -- Porting note: simp wasn't firing but rw was, annoying instance : MonoidalPreadditive (ModuleCat.{u} R) := by refine ⟨?_, ?_, ?_, ?_⟩ - · dsimp only [autoParam]; intros + · intros refine TensorProduct.ext (LinearMap.ext fun x => LinearMap.ext fun y => ?_) simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply] rw [LinearMap.zero_apply] -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 erw [MonoidalCategory.whiskerLeft_apply] rw [LinearMap.zero_apply, TensorProduct.tmul_zero] - · dsimp only [autoParam]; intros + · intros refine TensorProduct.ext (LinearMap.ext fun x => LinearMap.ext fun y => ?_) simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply] rw [LinearMap.zero_apply] -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 erw [MonoidalCategory.whiskerRight_apply] rw [LinearMap.zero_apply, TensorProduct.zero_tmul] - · dsimp only [autoParam]; intros + · intros refine TensorProduct.ext (LinearMap.ext fun x => LinearMap.ext fun y => ?_) simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply] rw [LinearMap.add_apply] @@ -278,7 +278,7 @@ instance : MonoidalPreadditive (ModuleCat.{u} R) := by erw [MonoidalCategory.whiskerLeft_apply, MonoidalCategory.whiskerLeft_apply] erw [MonoidalCategory.whiskerLeft_apply] rw [LinearMap.add_apply, TensorProduct.tmul_add] - · dsimp only [autoParam]; intros + · intros refine TensorProduct.ext (LinearMap.ext fun x => LinearMap.ext fun y => ?_) simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply] rw [LinearMap.add_apply] @@ -290,14 +290,14 @@ instance : MonoidalPreadditive (ModuleCat.{u} R) := by -- Porting note: simp wasn't firing but rw was, annoying instance : MonoidalLinear R (ModuleCat.{u} R) := by refine ⟨?_, ?_⟩ - · dsimp only [autoParam]; intros + · intros refine TensorProduct.ext (LinearMap.ext fun x => LinearMap.ext fun y => ?_) simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply] rw [LinearMap.smul_apply] -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 erw [MonoidalCategory.whiskerLeft_apply, MonoidalCategory.whiskerLeft_apply] rw [LinearMap.smul_apply, TensorProduct.tmul_smul] - · dsimp only [autoParam]; intros + · intros refine TensorProduct.ext (LinearMap.ext fun x => LinearMap.ext fun y => ?_) simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply] rw [LinearMap.smul_apply] diff --git a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Closed.lean b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Closed.lean index e741ce18b6323..55bbfb7b8390c 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 @@ -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 622c9e6a838a6..caf2f760e93ea 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 -/ 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,191 @@ 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} +/-- 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 +lemma ofPresheaf_presheaf : (ofPresheaf M map_smul).presheaf = M := 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])⟩ - -@[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 +224,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 +242,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 X Y f => by ext x; apply naturality } - 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 +267,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 +307,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 +322,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 +331,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 +372,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 +387,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 +407,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/Abelian.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Abelian.lean index 80d80075b9e8a..42747bed79af5 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Abelian.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Abelian.lean @@ -22,7 +22,7 @@ namespace PresheafOfModules variable {C : Type u₁} [Category.{v₁} C] (R : Cᵒᵖ ⥤ RingCat.{u}) noncomputable instance : NormalEpiCategory (PresheafOfModules.{v} R) where - normalEpiOfEpi p _ := NormalEpi.mk _ (kernel.ι p) (kernel.condition _) + normalEpiOfEpi p _ := NormalEpi.mk _ (kernel.ι p) (kernel.condition _) (evaluationJointlyReflectsColimits _ _ (fun _ => Abelian.isColimitMapCoconeOfCokernelCoforkOfπ _ _)) 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..26b9df8025f49 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,10 +58,10 @@ 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)) ≫ (preservesColimitIso (ModuleCat.restrictScalars (R.map f)) (F ⋙ evaluation R Y)).inv @@ -69,8 +70,8 @@ noncomputable def colimitBundledCore : BundledCorePresheafOfModules R where rw [ι_colimMap_assoc, whiskerLeft_app, restriction_app] erw [ι_preservesColimitsIso_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] @@ -78,32 +79,26 @@ noncomputable def colimitBundledCore : BundledCorePresheafOfModules R where ι_preservesColimitsIso_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, + 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, ← ι_preservesColimitsIso_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/Limits.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Limits.lean index 4fd891084e89b..a8c8858cd5bfe 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Limits.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Limits.lean @@ -6,7 +6,7 @@ Authors: Joël Riou import Mathlib.Algebra.Category.ModuleCat.Presheaf import Mathlib.Algebra.Category.ModuleCat.ChangeOfRings import Mathlib.CategoryTheory.Limits.Preserves.Limits -import Mathlib.CategoryTheory.Limits.FunctorCategory +import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic /-! # Limits in categories of presheaves of modules @@ -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,19 +51,17 @@ 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)) ≫ (preservesLimitIso (ModuleCat.restrictScalars (R.map f)) (F ⋙ evaluation R Y)).inv @@ -72,7 +74,8 @@ noncomputable def limitBundledCore : BundledCorePresheafOfModules R where simp only [limMap_π, Functor.comp_obj, evaluation_obj, whiskerLeft_app, restriction_app, assoc] erw [preservesLimitsIso_hom_π] - rw [← ModuleCat.restrictScalarsId'App_inv_naturality, restrictionApp_id] + rw [← ModuleCat.restrictScalarsId'App_inv_naturality, map_id, + ModuleCat.restrictScalarsId'_inv_app] dsimp map_comp {X Y Z} f g := by dsimp @@ -81,8 +84,9 @@ 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 [preservesLimitsIso_hom_π] + rw [← ModuleCat.restrictScalarsComp'App_inv_naturality] dsimp rw [← Functor.map_comp_assoc, ← Functor.map_comp_assoc, assoc, preservesLimitsIso_inv_π] @@ -92,27 +96,21 @@ noncomputable def limitBundledCore : BundledCorePresheafOfModules R where 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, preservesLimitsIso_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/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..db55107701398 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 sheaififcationAdjunction_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 69db169f3d58c..fb4312736f67f 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 @@ -222,9 +220,7 @@ 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) @@ -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₀'⟩⟩ + rintro Y f ⟨⟨⟨r₀, hr₀⟩, ⟨m₀ : M₀.obj _, hm₀⟩⟩, ⟨m₀' : M₀.obj _, hm₀'⟩⟩ erw [(A.val.map f.op).map_add, map_smul_eq α φ r m f.op r₀ hr₀ m₀ hm₀, 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 @@ -269,7 +265,7 @@ 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₀⟩⟩ + rintro Y f ⟨⟨⟨r₀ : R₀.obj _, hr₀⟩, ⟨r₀' : R₀.obj _, hr₀'⟩⟩, ⟨m₀ : M₀.obj _, hm₀⟩⟩ erw [map_smul_eq α φ (r * r') m f.op (r₀ * r₀') (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₀) @@ -298,7 +294,7 @@ lemma map_smul : rintro Y f ⟨⟨r₀, hr₀⟩, ⟨m₀, hm₀⟩⟩ erw [← 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))` @@ -362,23 +361,20 @@ variable {M₀' : PresheafOfModules.{v} R₀} {A' : Sheaf J AddCommGrp.{v}} (φ' : M₀'.presheaf ⟶ A'.val) [Presheaf.IsLocallyInjective J φ'] [Presheaf.IsLocallySurjective J φ'] (τ₀ : M₀ ⟶ M₀') (τ : A ⟶ A') - (fac : τ₀.hom ≫ φ' = φ ≫ τ.val) /-- The morphism of sheaves of modules `sheafify α φ ⟶ sheafify α φ'` induced by morphisms `τ₀ : M₀ ⟶ M₀'` and `τ : A ⟶ A'` which satisfy `τ₀.hom ≫ φ' = φ ≫ τ.val`. -/ @[simps] -def sheafifyMap : 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 80b2ec54bb07d..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 @@ -59,11 +59,11 @@ instance moduleCat_enoughProjectives : EnoughProjectives (ModuleCat.{max u v} R) f := Finsupp.basisSingleOne.constr ℕ _root_.id epi := (epi_iff_range_eq_top _).mpr (range_eq_top.2 fun m => ⟨Finsupp.single m (1 : R), by - -- Porting note: simp [Finsupp.total_single] fails but rw succeeds + -- Porting note: simp [Finsupp.linearCombination_single] fails but rw succeeds dsimp [Basis.constr] simp only [Finsupp.lmapDomain_id, comp_id] -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [Finsupp.total_single] + erw [Finsupp.linearCombination_single] rw [one_smul] rfl ⟩) }⟩ 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 e40d0e818c4af..53503eb352661 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Sheaf/ChangeOfRings.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Sheaf/ChangeOfRings.lean @@ -43,24 +43,25 @@ end SheafOfModules namespace PresheafOfModules variable {R R' : Cᵒᵖ ⥤ RingCat.{u}} (α : R ⟶ R') - {M₁ M₂ : PresheafOfModules.{v} R'} (hM₂ : Presheaf.IsSheaf J M₂.presheaf) - [Presheaf.IsLocallySurjective J α] + {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 : +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/Sheaf/Generators.lean b/Mathlib/Algebra/Category/ModuleCat/Sheaf/Generators.lean index ef7b06211193e..fdd0855f1ac33 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Sheaf/Generators.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Sheaf/Generators.lean @@ -66,8 +66,6 @@ def ofEpi (σ : M.GeneratingSections) (p : M ⟶ N) [Epi p] : rw [← freeHomEquiv_symm_comp] apply epi_comp -attribute [local instance] epi_comp - lemma opEpi_id (σ : M.GeneratingSections) : σ.ofEpi (𝟙 M) = σ := 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/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/Basic.lean b/Mathlib/Algebra/Category/MonCat/Basic.lean index d4510713aa6c0..22bdae9208498 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 diff --git a/Mathlib/Algebra/Category/MonCat/Colimits.lean b/Mathlib/Algebra/Category/MonCat/Colimits.lean index 87b46212fbf27..bfb19dcc5a1bc 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 @@ -212,14 +212,17 @@ def colimitIsColimit : IsColimit (colimitCocone F) where desc s := descMorphism F s uniq s m w := by ext x - induction' x using Quot.inductionOn with x - induction' x with j x x y hx hy - · change _ = s.ι.app j _ + induction x using Quot.inductionOn with | h x => ?_ + induction x with + | of j => + change _ = s.ι.app j _ rw [← w j] rfl - · rw [quot_one, map_one] + | one => + rw [quot_one, map_one] rfl - · rw [quot_mul, map_mul, hx, hy] + | mul x y hx hy => + rw [quot_mul, map_mul, hx, hy] dsimp [descMorphism, DFunLike.coe, descFun] simp only [← quot_mul, descFunLift] diff --git a/Mathlib/Algebra/Category/MonCat/FilteredColimits.lean b/Mathlib/Algebra/Category/MonCat/FilteredColimits.lean index 8ef1a354bfcd7..9624ff56fed29 100644 --- a/Mathlib/Algebra/Category/MonCat/FilteredColimits.lean +++ b/Mathlib/Algebra/Category/MonCat/FilteredColimits.lean @@ -56,7 +56,7 @@ noncomputable abbrev M.mk : (Σ j, F.obj j) → M.{v, u} F := theorem M.mk_eq (x y : Σ j, F.obj j) (h : ∃ (k : J) (f : x.1 ⟶ k) (g : y.1 ⟶ k), F.map f x.2 = F.map g y.2) : M.mk.{v, u} F x = M.mk F y := - Quot.EqvGen_sound (Types.FilteredColimit.eqvGen_quot_rel_of_rel (F ⋙ forget MonCat) x y h) + Quot.eqvGen_sound (Types.FilteredColimit.eqvGen_quot_rel_of_rel (F ⋙ forget MonCat) x y h) variable [IsFiltered J] @@ -99,7 +99,7 @@ noncomputable def colimitMulAux (x y : Σ j, F.obj j) : M.{v, u} F := theorem colimitMulAux_eq_of_rel_left {x x' y : Σ j, F.obj j} (hxx' : Types.FilteredColimit.Rel (F ⋙ forget MonCat) x x') : colimitMulAux.{v, u} F x y = colimitMulAux.{v, u} F x' y := by - cases' x with j₁ x; cases' y with j₂ y; cases' x' with j₃ x' + obtain ⟨j₁, x⟩ := x; obtain ⟨j₂, y⟩ := y; obtain ⟨j₃, x'⟩ := x' obtain ⟨l, f, g, hfg⟩ := hxx' simp? at hfg says simp only [Functor.comp_obj, Functor.comp_map, forget_map] at hfg obtain ⟨s, α, β, γ, h₁, h₂, h₃⟩ := @@ -122,7 +122,7 @@ theorem colimitMulAux_eq_of_rel_left {x x' y : Σ j, F.obj j} theorem colimitMulAux_eq_of_rel_right {x y y' : Σ j, F.obj j} (hyy' : Types.FilteredColimit.Rel (F ⋙ forget MonCat) y y') : colimitMulAux.{v, u} F x y = colimitMulAux.{v, u} F x y' := by - cases' y with j₁ y; cases' x with j₂ x; cases' y' with j₃ y' + obtain ⟨j₁, y⟩ := y; obtain ⟨j₂, x⟩ := x; obtain ⟨j₃, y'⟩ := y' obtain ⟨l, f, g, hfg⟩ := hyy' simp only [Functor.comp_obj, Functor.comp_map, forget_map] at hfg obtain ⟨s, α, β, γ, h₁, h₂, h₃⟩ := @@ -164,7 +164,7 @@ using a custom object `k` and morphisms `f : x.1 ⟶ k` and `g : y.1 ⟶ k`. `x` and `y`, using a custom object `k` and morphisms `f : x.1 ⟶ k` and `g : y.1 ⟶ k`."] theorem colimit_mul_mk_eq (x y : Σ j, F.obj j) (k : J) (f : x.1 ⟶ k) (g : y.1 ⟶ k) : M.mk.{v, u} F x * M.mk F y = M.mk F ⟨k, F.map f x.2 * F.map g y.2⟩ := by - cases' x with j₁ x; cases' y with j₂ y + obtain ⟨j₁, x⟩ := x; obtain ⟨j₂, y⟩ := y obtain ⟨s, α, β, h₁, h₂⟩ := IsFiltered.bowtie (IsFiltered.leftToMax j₁ j₂) f (IsFiltered.rightToMax j₁ j₂) g refine M.mk_eq F _ _ ?_ @@ -183,7 +183,7 @@ noncomputable instance colimitMulOneClass : MulOneClass (M.{v, u} F) := one_mul := fun x => by refine Quot.inductionOn x ?_ intro x - cases' x with j x + obtain ⟨j, x⟩ := x rw [colimit_one_eq F j, colimit_mul_mk_eq F ⟨j, 1⟩ ⟨j, x⟩ j (𝟙 j) (𝟙 j), MonoidHom.map_one, one_mul, F.map_id] -- Porting note: `id_apply` does not work here, but the two sides are def-eq @@ -191,7 +191,7 @@ noncomputable instance colimitMulOneClass : MulOneClass (M.{v, u} F) := mul_one := fun x => by refine Quot.inductionOn x ?_ intro x - cases' x with j x + obtain ⟨j, x⟩ := x rw [colimit_one_eq F j, colimit_mul_mk_eq F ⟨j, x⟩ ⟨j, 1⟩ j (𝟙 j) (𝟙 j), MonoidHom.map_one, mul_one, F.map_id] -- Porting note: `id_apply` does not work here, but the two sides are def-eq @@ -204,9 +204,9 @@ noncomputable instance colimitMonoid : Monoid (M.{v, u} F) := refine Quot.induction_on₃ x y z ?_ clear x y z intro x y z - cases' x with j₁ x - cases' y with j₂ y - cases' z with j₃ z + obtain ⟨j₁, x⟩ := x + obtain ⟨j₂, y⟩ := y + obtain ⟨j₃, z⟩ := z change M.mk F _ * M.mk F _ * M.mk F _ = M.mk F _ * M.mk F _ dsimp rw [colimit_mul_mk_eq F ⟨j₁, x⟩ ⟨j₂, y⟩ (IsFiltered.max j₁ (IsFiltered.max j₂ j₃)) @@ -272,8 +272,8 @@ def colimitDesc (t : Cocone F) : colimit.{v, u} F ⟶ t.pt where refine Quot.induction_on₂ x y ?_ clear x y intro x y - cases' x with i x - cases' y with j y + obtain ⟨i, x⟩ := x + obtain ⟨j, y⟩ := y rw [colimit_mul_mk_eq F ⟨i, x⟩ ⟨j, y⟩ (max' i j) (IsFiltered.leftToMax i j) (IsFiltered.rightToMax i j)] dsimp [Types.TypeMax.colimitCoconeIsColimit] diff --git a/Mathlib/Algebra/Category/MonCat/Limits.lean b/Mathlib/Algebra/Category/MonCat/Limits.lean index 0de870438eedb..77a05ad7f091f 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 diff --git a/Mathlib/Algebra/Category/Ring/Adjunctions.lean b/Mathlib/Algebra/Category/Ring/Adjunctions.lean index 49cbc29469c4e..7e9619ecea87c 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 diff --git a/Mathlib/Algebra/Category/Ring/Basic.lean b/Mathlib/Algebra/Category/Ring/Basic.lean index f195911a46493..4e1a2a7998aae 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 := @@ -176,10 +172,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 := @@ -273,7 +265,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 +286,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 := @@ -412,7 +400,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 +412,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 @@ -546,6 +523,12 @@ 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) diff --git a/Mathlib/Algebra/Category/Ring/Colimits.lean b/Mathlib/Algebra/Category/Ring/Colimits.lean index 5d7cc51769fd3..b2c1204a2af62 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 diff --git a/Mathlib/Algebra/Category/Ring/FilteredColimits.lean b/Mathlib/Algebra/Category/Ring/FilteredColimits.lean index 99fcc64a9f41a..9b383c982cbde 100644 --- a/Mathlib/Algebra/Category/Ring/FilteredColimits.lean +++ b/Mathlib/Algebra/Category/Ring/FilteredColimits.lean @@ -62,7 +62,7 @@ instance colimitSemiring : Semiring.{max v u} <| R.{v, u} F := (F ⋙ forget₂ SemiRingCat AddCommMonCat.{max v u}) with mul_zero := fun x => by refine Quot.inductionOn x ?_; clear x; intro x - cases' x with j x + obtain ⟨j, x⟩ := x erw [colimit_zero_eq _ j, colimit_mul_mk_eq _ ⟨j, _⟩ ⟨j, _⟩ j (𝟙 j) (𝟙 j)] rw [CategoryTheory.Functor.map_id] dsimp @@ -70,7 +70,7 @@ instance colimitSemiring : Semiring.{max v u} <| R.{v, u} F := rfl zero_mul := fun x => by refine Quot.inductionOn x ?_; clear x; intro x - cases' x with j x + obtain ⟨j, x⟩ := x erw [colimit_zero_eq _ j, colimit_mul_mk_eq _ ⟨j, _⟩ ⟨j, _⟩ j (𝟙 j) (𝟙 j)] rw [CategoryTheory.Functor.map_id] dsimp @@ -78,7 +78,7 @@ instance colimitSemiring : Semiring.{max v u} <| R.{v, u} F := rfl left_distrib := fun x y z => by refine Quot.induction_on₃ x y z ?_; clear x y z; intro x y z - cases' x with j₁ x; cases' y with j₂ y; cases' z with j₃ z + obtain ⟨j₁, x⟩ := x; obtain ⟨j₂, y⟩ := y; obtain ⟨j₃, z⟩ := z let k := IsFiltered.max₃ j₁ j₂ j₃ let f := IsFiltered.firstToMax₃ j₁ j₂ j₃ let g := IsFiltered.secondToMax₃ j₁ j₂ j₃ @@ -91,7 +91,7 @@ instance colimitSemiring : Semiring.{max v u} <| R.{v, u} F := rfl right_distrib := fun x y z => by refine Quot.induction_on₃ x y z ?_; clear x y z; intro x y z - cases' x with j₁ x; cases' y with j₂ y; cases' z with j₃ z + obtain ⟨j₁, x⟩ := x; obtain ⟨j₂, y⟩ := y; obtain ⟨j₃, z⟩ := z let k := IsFiltered.max₃ j₁ j₂ j₃ let f := IsFiltered.firstToMax₃ j₁ j₂ j₃ let g := IsFiltered.secondToMax₃ j₁ j₂ j₃ diff --git a/Mathlib/Algebra/Category/Ring/Instances.lean b/Mathlib/Algebra/Category/Ring/Instances.lean index c1e005f022104..fc588d27c8248 100644 --- a/Mathlib/Algebra/Category/Ring/Instances.lean +++ b/Mathlib/Algebra/Category/Ring/Instances.lean @@ -38,7 +38,7 @@ instance Localization.epi' {R : CommRingCat} (M : Submonoid R) : instance CommRingCat.isLocalRingHom_comp {R S T : CommRingCat} (f : R ⟶ S) (g : S ⟶ T) [IsLocalRingHom g] [IsLocalRingHom f] : IsLocalRingHom (f ≫ g) := - _root_.isLocalRingHom_comp _ _ + RingHom.isLocalRingHom_comp _ _ theorem isLocalRingHom_of_iso {R S : CommRingCat} (f : R ≅ S) : IsLocalRingHom f.hom := { map_nonunit := fun a ha => by diff --git a/Mathlib/Algebra/Category/Ring/Limits.lean b/Mathlib/Algebra/Category/Ring/Limits.lean index a7f813b611915..a0c514581878e 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 diff --git a/Mathlib/Algebra/CharP/CharAndCard.lean b/Mathlib/Algebra/CharP/CharAndCard.lean index bbd284531afbf..75671724d2c94 100644 --- a/Mathlib/Algebra/CharP/CharAndCard.lean +++ b/Mathlib/Algebra/CharP/CharAndCard.lean @@ -70,8 +70,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..34b448a97de44 100644 --- a/Mathlib/Algebra/CharP/Defs.lean +++ b/Mathlib/Algebra/CharP/Defs.lean @@ -11,6 +11,7 @@ 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 /-! # Characteristic of semirings @@ -18,6 +19,8 @@ import Mathlib.Data.ULift assert_not_exists Finset +open Set + variable (R : Type*) namespace CharP @@ -91,12 +94,19 @@ end AddMonoidWithOne section AddGroupWithOne variable [AddGroupWithOne R] (p : ℕ) [CharP R p] {a b : ℤ} +lemma intCast_injOn_Ico [IsRightCancelAdd R] : InjOn (Int.cast : ℤ → R) (Ico 0 p) := by + rintro a ⟨ha₀, ha⟩ b ⟨hb₀, hb⟩ hab + lift a to ℕ using ha₀ + lift b to ℕ using hb₀ + norm_cast at * + exact natCast_injOn_Iio _ _ ha hb hab + lemma intCast_eq_zero_iff (a : ℤ) : (a : R) = 0 ↔ (p : ℤ) ∣ a := by rcases lt_trichotomy a 0 with (h | rfl | h) - · rw [← neg_eq_zero, ← Int.cast_neg, ← 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] @@ -411,7 +421,6 @@ end CharZero namespace Fin -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] +instance charP (n : ℕ) [NeZero n] : CharP (Fin n) n where cast_eq_zero_iff' _ := natCast_eq_zero end Fin diff --git a/Mathlib/Algebra/CharP/ExpChar.lean b/Mathlib/Algebra/CharP/ExpChar.lean index ef45c8099756c..3c3955406e021 100644 --- a/Mathlib/Algebra/CharP/ExpChar.lean +++ b/Mathlib/Algebra/CharP/ExpChar.lean @@ -55,12 +55,12 @@ instance (S : Type*) [Semiring S] (p) [ExpChar R p] [ExpChar S p] : ExpChar (R variable {R} in /-- The exponential characteristic is unique. -/ theorem ExpChar.eq {p q : ℕ} (hp : ExpChar R p) (hq : ExpChar R q) : p = q := by - cases' hp with hp _ hp' hp - · cases' hq with hq _ hq' hq - exacts [rfl, False.elim (Nat.not_prime_zero (CharP.eq R hq (CharP.ofCharZero R) ▸ hq'))] - · cases' hq with hq _ hq' hq - exacts [False.elim (Nat.not_prime_zero (CharP.eq R hp (CharP.ofCharZero R) ▸ hp')), - CharP.eq R hp hq] + 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 @@ -68,7 +68,7 @@ theorem ExpChar.congr {p : ℕ} (q : ℕ) [hq : ExpChar R q] (h : q = p) : ExpCh noncomputable def ringExpChar (R : Type*) [NonAssocSemiring R] : ℕ := max (ringChar R) 1 theorem ringExpChar.eq (q : ℕ) [h : ExpChar R q] : ringExpChar R = q := by - cases' h with _ _ h _ + rcases h with _ | h · haveI := CharP.ofCharZero R rw [ringExpChar, ringChar.eq R 0]; rfl rw [ringExpChar, ringChar.eq R q] @@ -80,16 +80,16 @@ theorem ringExpChar.eq_one (R : Type*) [NonAssocSemiring R] [CharZero R] : ringE /-- 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 - cases' hq with q hq_one hq_prime hq_hchar + rcases hq with q | hq_prime · rfl - · exact False.elim <| hq_prime.ne_zero <| hq_hchar.eq R hp + · 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 - cases' hq with q hq_one hq_prime hq_hchar + 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 hq_hchar⟩ + · 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`. -/ @@ -138,7 +138,7 @@ 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 - cases' CharP.char_is_prime_or_zero R p with h h + rcases CharP.char_is_prime_or_zero R p with h | h · exact h · contradiction @@ -173,7 +173,7 @@ 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 - cases' hR with _ _ hprime _ + rcases hR with _ | hprime · haveI := charZero_of_injective_ringHom h; exact .zero haveI := charP_of_injective_ringHom h q; exact .prime hprime @@ -199,61 +199,61 @@ theorem expChar_of_injective_algebraMap {R A : Type*} 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 - cases' hR with _ _ hprime _ + 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 - cases' hR with _ _ hprime _ + 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 - cases' hR with _ _ hprime _ + 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 - cases' hR with _ _ hprime _ + 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 - cases' hR with _ _ hprime _ + 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 - cases' hR with _ _ hprime _ + 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 - cases' hR with _ _ hprime _ + 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 - cases' hR with _ _ hprime _ + 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 - cases' hR with _ _ hprime _ + 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 - cases' hR with _ _ hprime _ + rcases hR with _ | hprime · simp only [one_pow, pow_one] haveI := Fact.mk hprime; exact CharP.neg_one_pow_char_pow R q n diff --git a/Mathlib/Algebra/CharP/IntermediateField.lean b/Mathlib/Algebra/CharP/IntermediateField.lean index 9854b6a841e48..a577f00bd38d8 100644 --- a/Mathlib/Algebra/CharP/IntermediateField.lean +++ b/Mathlib/Algebra/CharP/IntermediateField.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.IntermediateField import Mathlib.Algebra.CharP.ExpChar +import Mathlib.FieldTheory.IntermediateField.Basic +import Mathlib.Algebra.EuclideanDomain.Field /-! diff --git a/Mathlib/Algebra/CharP/Invertible.lean b/Mathlib/Algebra/CharP/Invertible.lean index ecff3a748a171..bdf5259b6cf73 100644 --- a/Mathlib/Algebra/CharP/Invertible.lean +++ b/Mathlib/Algebra/CharP/Invertible.lean @@ -28,7 +28,7 @@ def invertibleOfRingCharNotDvd {t : ℕ} (not_dvd : ¬ringChar K ∣ t) : Invert theorem not_ringChar_dvd_of_invertible {t : ℕ} [Invertible (t : K)] : ¬ringChar K ∣ t := by rw [← ringChar.spec, ← Ne] - exact nonzero_of_invertible (t : K) + exact Invertible.ne_zero (t : K) /-- A natural number `t` is invertible in a field `K` of characteristic `p` if `p` does not divide `t`. -/ diff --git a/Mathlib/Algebra/CharP/LocalRing.lean b/Mathlib/Algebra/CharP/LocalRing.lean index adc445b11a41a..645df7bf14817 100644 --- a/Mathlib/Algebra/CharP/LocalRing.lean +++ b/Mathlib/Algebra/CharP/LocalRing.lean @@ -30,7 +30,7 @@ theorem charP_zero_or_prime_power (R : Type*) [CommRing R] [LocalRing R] (q : let r := ringChar K let n := q.factorization r -- `r := char(R/m)` is either prime or zero: - cases' CharP.char_is_prime_or_zero K r with r_prime r_zero + rcases CharP.char_is_prime_or_zero K r with r_prime | r_zero · let a := q / r ^ n -- If `r` is prime, we can write it as `r = a * q^n` ... have q_eq_a_mul_rn : q = r ^ n * a := by rw [Nat.mul_div_cancel' (Nat.ord_proj_dvd q r)] @@ -47,7 +47,6 @@ theorem charP_zero_or_prime_power (R : Type*) [CommRing R] [LocalRing R] (q : have r_dvd_a := (ringChar.spec K a).1 a_cast_zero exact absurd r_dvd_a r_ne_dvd_a -- Let `b` be the inverse of `a`. - cases' a_unit.exists_left_inv with a_inv h_inv_mul_a have rn_cast_zero : ↑(r ^ n) = (0 : R) := by rw [← @mul_one R _ ↑(r ^ n), mul_comm, ← Classical.choose_spec a_unit.exists_left_inv, mul_assoc, ← Nat.cast_mul, ← q_eq_a_mul_rn, CharP.cast_eq_zero R q] diff --git a/Mathlib/Algebra/CharZero/Defs.lean b/Mathlib/Algebra/CharZero/Defs.lean index c583ee8ed3603..c82356e6fa6e7 100644 --- a/Mathlib/Algebra/CharZero/Defs.lean +++ b/Mathlib/Algebra/CharZero/Defs.lean @@ -4,8 +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.Tactic.Cases -import Mathlib.Algebra.NeZero import Mathlib.Logic.Function.Basic /-! @@ -47,16 +45,12 @@ variable {R : Type*} theorem charZero_of_inj_zero [AddGroupWithOne R] (H : ∀ n : ℕ, (n : R) = 0 → n = 0) : CharZero R := ⟨@fun m n h => by - induction' m with m ih generalizing n - · rw [H n] - rw [← h, Nat.cast_zero] - - cases' n with n - · apply H - rw [h, Nat.cast_zero] - - simp only [Nat.cast_succ, add_right_cancel_iff] at h - rwa [ih]⟩ + induction m generalizing n with + | zero => rw [H n]; rw [← h, Nat.cast_zero] + | succ m ih => + cases n + · apply H; rw [h, Nat.cast_zero] + · simp only [Nat.cast_succ, add_right_cancel_iff] at h; rwa [ih]⟩ namespace Nat diff --git a/Mathlib/Algebra/CharZero/Lemmas.lean b/Mathlib/Algebra/CharZero/Lemmas.lean index 4a3176488e297..15bdc16d9f97e 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 diff --git a/Mathlib/Algebra/CharZero/Quotient.lean b/Mathlib/Algebra/CharZero/Quotient.lean index 309850f089606..8a44865763c7e 100644 --- a/Mathlib/Algebra/CharZero/Quotient.lean +++ b/Mathlib/Algebra/CharZero/Quotient.lean @@ -3,7 +3,9 @@ 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.GroupTheory.QuotientGroup +import Mathlib.Algebra.Field.Basic +import Mathlib.GroupTheory.QuotientGroup.Basic +import Mathlib.Algebra.Order.Group.Unbundled.Int /-! # Lemmas about quotients in characteristic zero diff --git a/Mathlib/Algebra/ContinuedFractions/Basic.lean b/Mathlib/Algebra/ContinuedFractions/Basic.lean index cdf31ebeb15da..6a34dbcebe789 100644 --- a/Mathlib/Algebra/ContinuedFractions/Basic.lean +++ b/Mathlib/Algebra/ContinuedFractions/Basic.lean @@ -41,7 +41,7 @@ numerics, number theory, approximations, fractions -- Fix a carrier `α`. variable (α : Type*) -/-!### Definitions-/ +/-!### Definitions -/ -- Porting note: Originally `protected structure GenContFract.Pair` /-- We collect a partial numerator `aᵢ` and partial denominator `bᵢ` in a pair `⟨aᵢ, bᵢ⟩`. -/ diff --git a/Mathlib/Algebra/ContinuedFractions/Computation/ApproximationCorollaries.lean b/Mathlib/Algebra/ContinuedFractions/Computation/ApproximationCorollaries.lean index 22eed92dcfa54..73f695ecae794 100644 --- a/Mathlib/Algebra/ContinuedFractions/Computation/ApproximationCorollaries.lean +++ b/Mathlib/Algebra/ContinuedFractions/Computation/ApproximationCorollaries.lean @@ -37,11 +37,9 @@ Moreover, we show the convergence of the continued fractions computations, that convergence, fractions -/ - variable {K : Type*} (v : K) [LinearOrderedField K] [FloorRing K] open GenContFract (of) -open GenContFract open scoped Topology namespace GenContFract @@ -79,7 +77,7 @@ theorem of_convergence_epsilon : exists N intro n n_ge_N let g := of v - cases' Decidable.em (g.TerminatedAt n) with terminatedAt_n not_terminatedAt_n + rcases Decidable.em (g.TerminatedAt n) with terminatedAt_n | not_terminatedAt_n · have : v = g.convs n := of_correctness_of_terminatedAt terminatedAt_n have : v - g.convs n = 0 := sub_eq_zero.mpr this rw [this] @@ -99,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 31e49bd225ba9..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 @@ -111,7 +108,7 @@ theorem succ_nth_stream_b_le_nth_stream_fr_inv {ifp_n ifp_succ_n : IntFractPair (succ_nth_stream_eq : IntFractPair.stream v (n + 1) = some ifp_succ_n) : (ifp_succ_n.b : K) ≤ ifp_n.fr⁻¹ := by suffices (⌊ifp_n.fr⁻¹⌋ : K) ≤ ifp_n.fr⁻¹ by - cases' ifp_n with _ ifp_n_fr + obtain ⟨_, ifp_n_fr⟩ := ifp_n have : ifp_n_fr ≠ 0 := by intro h simp [h, IntFractPair.stream, nth_stream_eq] at succ_nth_stream_eq @@ -264,9 +261,9 @@ theorem zero_le_of_contsAux_b : 0 ≤ ((of v).contsAux n).b := by induction n with | zero => rfl | succ n IH => - cases' Decidable.em <| g.TerminatedAt (n - 1) with terminated not_terminated + rcases Decidable.em <| g.TerminatedAt (n - 1) with terminated | not_terminated · -- terminating case - cases' n with n + rcases n with - | n · simp [zero_le_one] · have : g.contsAux (n + 2) = g.contsAux (n + 1) := contsAux_stable_step_of_terminated terminated @@ -299,7 +296,7 @@ theorem le_of_succ_get?_den {b : K} /-- Shows that the sequence of denominators is monotone, that is `Bₙ ≤ Bₙ₊₁`. -/ theorem of_den_mono : (of v).dens n ≤ (of v).dens (n + 1) := by let g := of v - cases' Decidable.em <| g.partDens.TerminatedAt n with terminated not_terminated + rcases Decidable.em <| g.partDens.TerminatedAt n with terminated | not_terminated · have : g.partDens.get? n = none := by rwa [Stream'.Seq.TerminatedAt] at terminated have : g.TerminatedAt n := terminatedAt_iff_partDen_none.2 (by rwa [Stream'.Seq.TerminatedAt] at terminated) @@ -361,7 +358,7 @@ theorem sub_convs_eq {ifp : IntFractPair K} rwa [g_finite_correctness] -- To continue, we need use the determinant equality. So let's derive the needed hypothesis. have n_eq_zero_or_not_terminatedAt_pred_n : n = 0 ∨ ¬g.TerminatedAt (n - 1) := by - cases' n with n' + rcases n with - | n' · simp · have : IntFractPair.stream v (n' + 1) ≠ none := by simp [stream_nth_eq] have : ¬g.TerminatedAt n' := @@ -373,13 +370,13 @@ theorem sub_convs_eq {ifp : IntFractPair K} -- however, for this, we first have to derive quite a few tedious inequalities. have pB_ineq : (fib n : K) ≤ pB := haveI : n ≤ 1 ∨ ¬g.TerminatedAt (n - 2) := by - cases' n_eq_zero_or_not_terminatedAt_pred_n with n_eq_zero not_terminatedAt_pred_n + rcases n_eq_zero_or_not_terminatedAt_pred_n with n_eq_zero | not_terminatedAt_pred_n · simp [n_eq_zero] · exact Or.inr <| mt (terminated_stable (n - 1).pred_le) not_terminatedAt_pred_n fib_le_of_contsAux_b this have B_ineq : (fib (n + 1) : K) ≤ B := haveI : n + 1 ≤ 1 ∨ ¬g.TerminatedAt (n + 1 - 2) := by - cases' n_eq_zero_or_not_terminatedAt_pred_n with n_eq_zero not_terminatedAt_pred_n + rcases n_eq_zero_or_not_terminatedAt_pred_n with n_eq_zero | not_terminatedAt_pred_n · simp [n_eq_zero, le_refl] · exact Or.inr not_terminatedAt_pred_n fib_le_of_contsAux_b this diff --git a/Mathlib/Algebra/ContinuedFractions/Computation/CorrectnessTerminating.lean b/Mathlib/Algebra/ContinuedFractions/Computation/CorrectnessTerminating.lean index 735682d954a59..a0117d970346f 100644 --- a/Mathlib/Algebra/ContinuedFractions/Computation/CorrectnessTerminating.lean +++ b/Mathlib/Algebra/ContinuedFractions/Computation/CorrectnessTerminating.lean @@ -96,16 +96,16 @@ theorem compExactValue_correctness_of_stream_eq_some : ∀ {ifp_n : IntFractPair K}, IntFractPair.stream v n = some ifp_n → v = compExactValue ((of v).contsAux n) ((of v).contsAux <| n + 1) ifp_n.fr := by let g := of v - induction' n with n IH - · intro ifp_zero stream_zero_eq - -- Nat.zero - have : IntFractPair.of v = ifp_zero := by + induction n with + | zero => + intro ifp_zero stream_zero_eq + obtain rfl : IntFractPair.of v = ifp_zero := by have : IntFractPair.stream v 0 = some (IntFractPair.of v) := rfl - simpa only [Nat.zero_eq, this, Option.some.injEq] using stream_zero_eq - cases this - cases' Decidable.em (Int.fract v = 0) with fract_eq_zero fract_ne_zero - -- Int.fract v = 0; we must then have `v = ⌊v⌋` - · suffices v = ⌊v⌋ by + simpa only [this, Option.some.injEq] using stream_zero_eq + cases eq_or_ne (Int.fract v) 0 with + | inl fract_eq_zero => + -- Int.fract v = 0; we must then have `v = ⌊v⌋` + suffices v = ⌊v⌋ by -- Porting note: was `simpa [contsAux, fract_eq_zero, compExactValue]` field_simp [nextConts, nextNum, nextDen, compExactValue] have : (IntFractPair.of v).fr = Int.fract v := rfl @@ -113,13 +113,14 @@ theorem compExactValue_correctness_of_stream_eq_some : calc v = Int.fract v + ⌊v⌋ := by rw [Int.fract_add_floor] _ = ⌊v⌋ := by simp [fract_eq_zero] - -- Int.fract v ≠ 0; the claim then easily follows by unfolding a single computation step - · field_simp [contsAux, nextConts, nextNum, nextDen, of_h_eq_floor, compExactValue] + | inr fract_ne_zero => + -- Int.fract v ≠ 0; the claim then easily follows by unfolding a single computation step + field_simp [contsAux, nextConts, nextNum, nextDen, of_h_eq_floor, compExactValue] -- Porting note: this and the if_neg rewrite are needed have : (IntFractPair.of v).fr = Int.fract v := rfl rw [this, if_neg fract_ne_zero, Int.floor_add_fract] - · intro ifp_succ_n succ_nth_stream_eq - -- Nat.succ + | succ n IH => + intro ifp_succ_n succ_nth_stream_eq obtain ⟨ifp_n, nth_stream_eq, nth_fract_ne_zero, -⟩ : ∃ ifp_n, IntFractPair.stream v n = some ifp_n ∧ ifp_n.fr ≠ 0 ∧ IntFractPair.of ifp_n.fr⁻¹ = ifp_succ_n := @@ -128,9 +129,10 @@ theorem compExactValue_correctness_of_stream_eq_some : let conts := g.contsAux (n + 2) set pconts := g.contsAux (n + 1) with pconts_eq set ppconts := g.contsAux n with ppconts_eq - cases' Decidable.em (ifp_succ_n.fr = 0) with ifp_succ_n_fr_eq_zero ifp_succ_n_fr_ne_zero - -- ifp_succ_n.fr = 0 - · suffices v = conts.a / conts.b by simpa [compExactValue, ifp_succ_n_fr_eq_zero] + cases eq_or_ne ifp_succ_n.fr 0 with + | inl ifp_succ_n_fr_eq_zero => + -- ifp_succ_n.fr = 0 + suffices v = conts.a / conts.b by simpa [compExactValue, ifp_succ_n_fr_eq_zero] -- use the IH and the fact that ifp_n.fr⁻¹ = ⌊ifp_n.fr⁻¹⌋ to prove this case obtain ⟨ifp_n', nth_stream_eq', ifp_n_fract_inv_eq_floor⟩ : ∃ ifp_n, IntFractPair.stream v n = some ifp_n ∧ ifp_n.fr⁻¹ = ⌊ifp_n.fr⁻¹⌋ := @@ -143,8 +145,9 @@ theorem compExactValue_correctness_of_stream_eq_some : suffices v = compExactValue ppconts pconts ifp_n.fr by simpa [conts, contsAux, s_nth_eq, compExactValue, nth_fract_ne_zero] using this exact IH nth_stream_eq - -- ifp_succ_n.fr ≠ 0 - · -- use the IH to show that the following equality suffices + | inr ifp_succ_n_fr_ne_zero => + -- ifp_succ_n.fr ≠ 0 + -- use the IH to show that the following equality suffices suffices compExactValue ppconts pconts ifp_n.fr = compExactValue pconts conts ifp_succ_n.fr by have : v = compExactValue ppconts pconts ifp_n.fr := IH nth_stream_eq @@ -212,14 +215,14 @@ theorem of_correctness_of_nth_stream_eq_none (nth_stream_eq_none : IntFractPair. | succ n IH => let g := of v change v = g.convs n - have : + obtain ⟨nth_stream_eq_none⟩ | ⟨ifp_n, nth_stream_eq, nth_stream_fr_eq_zero⟩ : IntFractPair.stream v n = none ∨ ∃ ifp, IntFractPair.stream v n = some ifp ∧ ifp.fr = 0 := IntFractPair.succ_nth_stream_eq_none_iff.1 nth_stream_eq_none - rcases this with (⟨nth_stream_eq_none⟩ | ⟨ifp_n, nth_stream_eq, nth_stream_fr_eq_zero⟩) - · cases' n with n' - · contradiction - -- IntFractPair.stream v 0 ≠ none - · have : g.TerminatedAt n' := + · cases n with + | zero => contradiction + | succ n' => + -- IntFractPair.stream v 0 ≠ none + have : g.TerminatedAt n' := of_terminatedAt_n_iff_succ_nth_intFractPair_stream_eq_none.2 nth_stream_eq_none have : g.convs (n' + 1) = g.convs n' := diff --git a/Mathlib/Algebra/ContinuedFractions/Computation/TerminatesIffRat.lean b/Mathlib/Algebra/ContinuedFractions/Computation/TerminatesIffRat.lean index 8170aa40b0814..29595521c11a7 100644 --- a/Mathlib/Algebra/ContinuedFractions/Computation/TerminatesIffRat.lean +++ b/Mathlib/Algebra/ContinuedFractions/Computation/TerminatesIffRat.lean @@ -73,9 +73,9 @@ nonrec theorem exists_gcf_pair_rat_eq_of_nth_contsAux : use Pair.mk ⌊v⌋ 1 simp [g] -- 2 ≤ n - · cases' IH (n + 1) <| lt_add_one (n + 1) with pred_conts pred_conts_eq + · obtain ⟨pred_conts, pred_conts_eq⟩ := IH (n + 1) <| lt_add_one (n + 1) -- invoke the IH - cases' s_ppred_nth_eq : g.s.get? n with gp_n + rcases s_ppred_nth_eq : g.s.get? n with gp_n | gp_n -- option.none · use pred_conts have : g.contsAux (n + 2) = g.contsAux (n + 1) := @@ -83,8 +83,8 @@ nonrec theorem exists_gcf_pair_rat_eq_of_nth_contsAux : simp only [this, pred_conts_eq] -- option.some · -- invoke the IH a second time - cases' IH n <| lt_of_le_of_lt n.le_succ <| lt_add_one <| n + 1 with ppred_conts - ppred_conts_eq + obtain ⟨ppred_conts, ppred_conts_eq⟩ := + IH n <| lt_of_le_of_lt n.le_succ <| lt_add_one <| n + 1 obtain ⟨a_eq_one, z, b_eq_z⟩ : gp_n.a = 1 ∧ ∃ z : ℤ, gp_n.b = (z : K) := of_partNum_eq_one_and_exists_int_partDen_eq s_ppred_nth_eq -- finally, unfold the recurrence to obtain the required rational value. @@ -171,8 +171,8 @@ theorem coe_stream_nth_rat_eq (v_eq_q : v = (↑q : K)) (n : ℕ) : cases stream_q_nth_eq : IntFractPair.stream q n with | none => simp [IntFractPair.stream, IH.symm, v_eq_q, stream_q_nth_eq] | some ifp_n => - cases' ifp_n with b fr - cases' Decidable.em (fr = 0) with fr_zero fr_ne_zero + obtain ⟨b, fr⟩ := ifp_n + rcases Decidable.em (fr = 0) with fr_zero | fr_ne_zero · simp [IntFractPair.stream, IH.symm, v_eq_q, stream_q_nth_eq, fr_zero] · replace IH : some (IntFractPair.mk b (fr : K)) = IntFractPair.stream (↑q) n := by rwa [stream_q_nth_eq] at IH @@ -210,7 +210,7 @@ theorem coe_of_s_rat_eq (v_eq_q : v = (↑q : K)) : /-- Given `(v : K), (q : ℚ), and v = q`, we have that `of q = of v` -/ theorem coe_of_rat_eq (v_eq_q : v = (↑q : K)) : (⟨(of q).h, (of q).s.map (Pair.map (↑))⟩ : GenContFract K) = of v := by - cases' gcf_v_eq : of v with h s; subst v + rcases gcf_v_eq : of v with ⟨h, s⟩; subst v -- Porting note: made coercion target explicit obtain rfl : ↑⌊(q : K)⌋ = h := by injection gcf_v_eq -- Porting note: was @@ -220,7 +220,7 @@ theorem coe_of_rat_eq (v_eq_q : v = (↑q : K)) : theorem of_terminates_iff_of_rat_terminates {v : K} {q : ℚ} (v_eq_q : v = (q : K)) : (of v).Terminates ↔ (of q).Terminates := by - constructor <;> intro h <;> cases' h with n h <;> use n <;> + constructor <;> intro h <;> obtain ⟨n, h⟩ := h <;> use n <;> simp only [Stream'.Seq.TerminatedAt, (coe_of_s_get?_rat_eq v_eq_q n).symm] at h ⊢ <;> cases h' : (of q).s.get? n <;> simp only [h'] at h <;> -- Porting note: added @@ -267,7 +267,7 @@ theorem stream_succ_nth_fr_num_lt_nth_fr_num_rat {ifp_n ifp_succ_n : IntFractPai have : ifp_n = ifp_n' := by injection Eq.trans stream_nth_eq.symm stream_nth_eq' cases this rw [← IntFractPair.of_eq_ifp_succ_n] - cases' nth_stream_fr_nonneg_lt_one stream_nth_eq with zero_le_ifp_n_fract ifp_n_fract_lt_one + obtain ⟨zero_le_ifp_n_fract, _⟩ := nth_stream_fr_nonneg_lt_one stream_nth_eq have : 0 < ifp_n.fr := lt_of_le_of_ne zero_le_ifp_n_fract <| ifp_n_fract_ne_zero.symm exact of_inv_fr_num_lt_num_of_pos this @@ -292,7 +292,7 @@ theorem stream_nth_fr_num_le_fr_num_sub_n_rat : theorem exists_nth_stream_eq_none_of_rat (q : ℚ) : ∃ n : ℕ, IntFractPair.stream q n = none := by let fract_q_num := (Int.fract q).num; let n := fract_q_num.natAbs + 1 - cases' stream_nth_eq : IntFractPair.stream q n with ifp + rcases stream_nth_eq : IntFractPair.stream q n with ifp | ifp · use n, stream_nth_eq · -- arrive at a contradiction since the numerator decreased num + 1 times but every fractional -- value is nonnegative. diff --git a/Mathlib/Algebra/ContinuedFractions/Computation/Translations.lean b/Mathlib/Algebra/ContinuedFractions/Computation/Translations.lean index 34c8347407af7..d732ff25b6a7a 100644 --- a/Mathlib/Algebra/ContinuedFractions/Computation/Translations.lean +++ b/Mathlib/Algebra/ContinuedFractions/Computation/Translations.lean @@ -63,7 +63,7 @@ variable {n : ℕ} theorem stream_eq_none_of_fr_eq_zero {ifp_n : IntFractPair K} (stream_nth_eq : IntFractPair.stream v n = some ifp_n) (nth_fr_eq_zero : ifp_n.fr = 0) : IntFractPair.stream v (n + 1) = none := by - cases' ifp_n with _ fr + obtain ⟨_, fr⟩ := ifp_n change fr = 0 at nth_fr_eq_zero simp [IntFractPair.stream, stream_nth_eq, nth_fr_eq_zero] @@ -249,7 +249,7 @@ theorem of_s_head_aux (v : K) : (of v).s.get? 0 = (IntFractPair.stream v 1).bind rw [of, IntFractPair.seq1] simp only [of, Stream'.Seq.map_tail, Stream'.Seq.map, Stream'.Seq.tail, Stream'.Seq.head, Stream'.Seq.get?, Stream'.map] - rw [← Stream'.get_succ, Stream'.get, Option.map] + rw [← Stream'.get_succ, Stream'.get, Option.map.eq_def] split <;> simp_all only [Option.some_bind, Option.none_bind, Function.comp_apply] /-- This gives the first pair of coefficients of the continued fraction of a non-integer `v`. @@ -304,7 +304,7 @@ are all equal to `a`. -/ theorem convs'_of_int (a : ℤ) : (of (a : K)).convs' n = a := by induction n with - | zero => simp only [zeroth_conv'_eq_h, of_h_eq_floor, floor_intCast, Nat.zero_eq] + | zero => simp only [zeroth_conv'_eq_h, of_h_eq_floor, floor_intCast] | succ => rw [convs', of_h_eq_floor, floor_intCast, add_right_eq_self] exact convs'Aux_succ_none ((of_s_of_int K a).symm ▸ Stream'.Seq.get?_nil 0) _ diff --git a/Mathlib/Algebra/ContinuedFractions/ConvergentsEquiv.lean b/Mathlib/Algebra/ContinuedFractions/ConvergentsEquiv.lean index 2ffc624d496a8..99e76fa64a5f5 100644 --- a/Mathlib/Algebra/ContinuedFractions/ConvergentsEquiv.lean +++ b/Mathlib/Algebra/ContinuedFractions/ConvergentsEquiv.lean @@ -136,7 +136,7 @@ theorem squashSeq_succ_n_tail_eq_squashSeq_tail_n : s.ge_stable (n + 1).le_succ s_succ_succ_nth_eq -- apply extensionality with `m` and continue by cases `m = n`. ext1 m - cases' Decidable.em (m = n) with m_eq_n m_ne_n + rcases Decidable.em (m = n) with m_eq_n | m_ne_n · simp [*, squashSeq] · cases s_succ_mth_eq : s.get? (m + 1) · simp only [*, squashSeq, Stream'.Seq.get?_tail, Stream'.Seq.get?_zipWith, @@ -166,9 +166,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] @@ -227,12 +224,12 @@ theorem contsAux_eq_contsAux_squashGCF_of_le {m : ℕ} : (by clear m intro m IH m_le_n - cases' m with m' + rcases m with - | m' · rfl - · cases' n with n' + · rcases n with - | n' · exact (m'.not_succ_le_zero m_le_n).elim -- 1 ≰ 0 - · cases' m' with m'' + · rcases m' with - | m'' · rfl · -- get some inequalities to instantiate the IH for m'' and m'' + 1 have m'_lt_n : m'' + 1 < n' + 1 := m_le_n @@ -250,7 +247,7 @@ at the squashed position is not zero. -/ theorem succ_nth_conv_eq_squashGCF_nth_conv [Field K] (nth_partDen_ne_zero : ∀ {b : K}, g.partDens.get? n = some b → b ≠ 0) : g.convs (n + 1) = (squashGCF g n).convs n := by - cases' Decidable.em (g.TerminatedAt n) with terminatedAt_n not_terminatedAt_n + rcases Decidable.em (g.TerminatedAt n) with terminatedAt_n | not_terminatedAt_n · have : squashGCF g n = g := squashGCF_eq_self_of_terminated terminatedAt_n simp only [this, convs_stable_of_terminated n.le_succ terminatedAt_n] · obtain ⟨⟨a, b⟩, s_nth_eq⟩ : ∃ gp_n, g.s.get? n = some gp_n := @@ -335,7 +332,7 @@ theorem convs_eq_convs' [LinearOrderedField K] -- first replace the rhs with the squashed computation suffices g.convs (n + 1) = g'.convs' n by rwa [succ_nth_conv'_eq_squashGCF_nth_conv'] - cases' Decidable.em (TerminatedAt g n) with terminatedAt_n not_terminatedAt_n + rcases Decidable.em (TerminatedAt g n) with terminatedAt_n | not_terminatedAt_n · have g'_eq_g : g' = g := squashGCF_eq_self_of_terminated terminatedAt_n rw [convs_stable_of_terminated n.le_succ terminatedAt_n, g'_eq_g, IH _] intro _ _ m_lt_n s_mth_eq @@ -345,7 +342,7 @@ theorem convs_eq_convs' [LinearOrderedField K] rwa [← IH] intro gp' m m_lt_n s_mth_eq' -- case distinction on m + 1 = n or m + 1 < n - cases' m_lt_n with n succ_m_lt_n + rcases m_lt_n with n | succ_m_lt_n · -- the difficult case at the squashed position: we first obtain the values from -- the sequence obtain ⟨gp_succ_m, s_succ_mth_eq⟩ : ∃ gp_succ_m, g.s.get? (m + 1) = some gp_succ_m := diff --git a/Mathlib/Algebra/ContinuedFractions/TerminatedStable.lean b/Mathlib/Algebra/ContinuedFractions/TerminatedStable.lean index 712ff1ebf90e9..f2405467d8aa7 100644 --- a/Mathlib/Algebra/ContinuedFractions/TerminatedStable.lean +++ b/Mathlib/Algebra/ContinuedFractions/TerminatedStable.lean @@ -54,9 +54,10 @@ theorem convs'Aux_stable_step_of_terminated {s : Stream'.Seq <| Pair K} theorem convs'Aux_stable_of_terminated {s : Stream'.Seq <| Pair K} (n_le_m : n ≤ m) (terminatedAt_n : s.TerminatedAt n) : convs'Aux s m = convs'Aux s n := by - induction' n_le_m with m n_le_m IH - · rfl - · refine (convs'Aux_stable_step_of_terminated ?_).trans IH + induction n_le_m with + | refl => rfl + | step n_le_m IH => + refine (convs'Aux_stable_step_of_terminated (?_)).trans IH exact s.terminated_stable n_le_m terminatedAt_n theorem conts_stable_of_terminated (n_le_m : n ≤ m) (terminatedAt_n : g.TerminatedAt n) : diff --git a/Mathlib/Algebra/CubicDiscriminant.lean b/Mathlib/Algebra/CubicDiscriminant.lean index b200ea3ac1f44..7280b1a8b0e49 100644 --- a/Mathlib/Algebra/CubicDiscriminant.lean +++ b/Mathlib/Algebra/CubicDiscriminant.lean @@ -240,9 +240,9 @@ def equiv : Cubic R ≃ { p : R[X] // p.degree ≤ 3 } where invFun f := ⟨coeff f 3, coeff f 2, coeff f 1, coeff f 0⟩ left_inv P := by ext <;> simp only [Subtype.coe_mk, coeffs] right_inv f := by - -- Porting note: Added `simp only [Nat.zero_eq, Nat.succ_eq_add_one] <;> ring_nf` + -- Porting note: Added `simp only [Nat.succ_eq_add_one] <;> ring_nf` -- There's probably a better way to do this. - ext (_ | _ | _ | _ | n) <;> simp only [Nat.zero_eq, Nat.succ_eq_add_one] <;> ring_nf + ext (_ | _ | _ | _ | n) <;> simp only [Nat.succ_eq_add_one] <;> ring_nf <;> try simp only [coeffs] have h3 : 3 < 4 + n := by linarith only rw [coeff_eq_zero h3, diff --git a/Mathlib/Algebra/DirectLimit.lean b/Mathlib/Algebra/DirectLimit.lean index 993dcaec82950..bcbcb659f05d8 100644 --- a/Mathlib/Algebra/DirectLimit.lean +++ b/Mathlib/Algebra/DirectLimit.lean @@ -137,20 +137,20 @@ protected theorem induction_on [Nonempty ι] [IsDirected ι (· ≤ ·)] {C : Di let ⟨i, x, h⟩ := exists_of z h ▸ ih i x -variable {P : Type u₁} [AddCommGroup P] [Module R P] (g : ∀ i, G i →ₗ[R] P) -variable (Hg : ∀ i j hij x, g j (f i j hij x) = g i x) -variable (R ι G f) +variable {P : Type u₁} [AddCommGroup P] [Module R P] +variable (R ι G f) in /-- The universal property of the direct limit: maps from the components to another module that respect the directed system structure (i.e. make some diagram commute) give rise to a unique map out of the direct limit. -/ -def lift : DirectLimit G f →ₗ[R] P := +def lift (g : ∀ i, G i →ₗ[R] P) (Hg : ∀ i j hij x, g j (f i j hij x) = g i x) : + DirectLimit G f →ₗ[R] P := liftQ _ (DirectSum.toModule R ι P g) (span_le.2 fun a ⟨i, j, hij, x, hx⟩ => by rw [← hx, SetLike.mem_coe, LinearMap.sub_mem_ker_iff, DirectSum.toModule_lof, DirectSum.toModule_lof, Hg]) -variable {R ι G f} +variable (g : ∀ i, G i →ₗ[R] P) (Hg : ∀ i j hij x, g j (f i j hij x) = g i x) theorem lift_of {i} (x) : lift R ι G f g Hg (of R ι G f i x) = g i x := DirectSum.toModule_lof R _ _ @@ -170,9 +170,10 @@ lemma lift_injective [IsDirected ι (· ≤ ·)] · apply Function.injective_of_subsingleton simp_rw [injective_iff_map_eq_zero] at injective ⊢ intros z hz - induction' z using DirectLimit.induction_on with _ g - rw [lift_of] at hz - rw [injective _ g hz, _root_.map_zero] + induction z using DirectLimit.induction_on with + | ih _ g => + rw [lift_of] at hz + rw [injective _ g hz, _root_.map_zero] section functorial @@ -315,12 +316,8 @@ theorem of.zero_exact_aux [∀ i (k : G i), Decidable (k ≠ 0)] [Nonempty ι] [ ⟨k, fun l 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]⟩) + 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]⟩ @@ -429,9 +426,8 @@ lemma lift_injective [IsDirected ι (· ≤ ·)] · apply Function.injective_of_subsingleton simp_rw [injective_iff_map_eq_zero] at injective ⊢ intros z hz - induction' z using DirectLimit.induction_on with _ g - rw [lift_of] at hz - rw [injective _ g hz, _root_.map_zero] + induction z using DirectLimit.induction_on with + | ih _ g => rw [lift_of] at hz; rw [injective _ g hz, _root_.map_zero] section functorial @@ -721,9 +717,7 @@ 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` @@ -790,18 +784,16 @@ theorem of_injective [IsDirected ι (· ≤ ·)] [DirectedSystem G fun i j h => rw [hfx, (f' i j hij).map_zero] variable (P : Type u₁) [CommRing P] -variable (g : ∀ i, G i →+* P) -variable (Hg : ∀ i j hij x, g j (f i j hij x) = g i x) open FreeCommRing -variable (G f) - +variable (G f) in /-- The universal property of the direct limit: maps from the components to another ring that respect the directed system structure (i.e. make some diagram commute) give rise to a unique map out of the direct limit. -/ -def lift : DirectLimit G f →+* P := +def lift (g : ∀ i, G i →+* P) (Hg : ∀ i j hij x, g j (f i j hij x) = g i x) : + DirectLimit G f →+* P := Ideal.Quotient.lift _ (FreeCommRing.lift fun x : Σi, G i => g x.1 x.2) (by suffices Ideal.span _ ≤ @@ -815,7 +807,7 @@ def lift : DirectLimit G f →+* P := simp only [RingHom.map_sub, lift_of, Hg, RingHom.map_one, RingHom.map_add, RingHom.map_mul, (g i).map_one, (g i).map_add, (g i).map_mul, sub_self]) -variable {G f} +variable (g : ∀ i, G i →+* P) (Hg : ∀ i j hij x, g j (f i j hij x) = g i x) -- Porting note: the @[simp] attribute would trigger a `simpNF` linter error: -- failed to synthesize CommMonoidWithZero (Ring.DirectLimit G f) @@ -836,9 +828,8 @@ lemma lift_injective [Nonempty ι] [IsDirected ι (· ≤ ·)] Function.Injective (lift G f P g Hg) := by simp_rw [injective_iff_map_eq_zero] at injective ⊢ intros z hz - induction' z using DirectLimit.induction_on with _ g - rw [lift_of] at hz - rw [injective _ g hz, _root_.map_zero] + induction z using DirectLimit.induction_on with + | ih _ g => rw [lift_of] at hz; rw [injective _ g hz, _root_.map_zero] section functorial @@ -947,7 +938,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]⟩ @@ -975,7 +966,9 @@ protected noncomputable abbrev field [DirectedSystem 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 inv_zero := dif_pos rfl nnqsmul := _ + nnqsmul_def := fun q a => rfl qsmul := _ + qsmul_def := fun q a => rfl end diff --git a/Mathlib/Algebra/DirectSum/AddChar.lean b/Mathlib/Algebra/DirectSum/AddChar.lean new file mode 100644 index 0000000000000..a9a6296c82833 --- /dev/null +++ b/Mathlib/Algebra/DirectSum/AddChar.lean @@ -0,0 +1,35 @@ +/- +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.DirectSum.Basic +import Mathlib.Algebra.Group.AddChar + +/-! +# Direct sum of additive characters + +This file defines the direct sum of additive characters. +-/ + +open Function +open scoped DirectSum + +variable {ι R : Type*} {G : ι → Type*} [DecidableEq ι] [∀ i, AddCommGroup (G i)] [CommMonoid R] + +namespace AddChar +section DirectSum + +/-- Direct sum of additive characters. -/ +@[simps!] +def directSum (ψ : ∀ i, AddChar (G i) R) : AddChar (⨁ i, G i) R := + toAddMonoidHomEquiv.symm <| DirectSum.toAddMonoid fun i ↦ toAddMonoidHomEquiv (ψ i) + +lemma directSum_injective : + Injective (directSum : (∀ i, AddChar (G i) R) → AddChar (⨁ i, G i) R) := by + refine toAddMonoidHomEquiv.symm.injective.comp <| DirectSum.toAddMonoid_injective.comp ?_ + rintro ψ χ h + simpa [funext_iff] using h + +end DirectSum +end AddChar diff --git a/Mathlib/Algebra/DirectSum/Decomposition.lean b/Mathlib/Algebra/DirectSum/Decomposition.lean index 45f344b63d1ae..68b4f5db83e65 100644 --- a/Mathlib/Algebra/DirectSum/Decomposition.lean +++ b/Mathlib/Algebra/DirectSum/Decomposition.lean @@ -57,8 +57,8 @@ class Decomposition where /-- `DirectSum.Decomposition` instances, while carrying data, are always equal. -/ instance : Subsingleton (Decomposition ℳ) := ⟨fun x y ↦ by - cases' x with x xl xr - cases' y with y yl yr + obtain ⟨_, _, xr⟩ := x + obtain ⟨_, yl, _⟩ := y congr exact Function.LeftInverse.eq_rightInverse xr yl⟩ diff --git a/Mathlib/Algebra/DirectSum/Internal.lean b/Mathlib/Algebra/DirectSum/Internal.lean index ac5d09c97b8de..4c03bf25b2f72 100644 --- a/Mathlib/Algebra/DirectSum/Internal.lean +++ b/Mathlib/Algebra/DirectSum/Internal.lean @@ -66,10 +66,12 @@ theorem SetLike.algebraMap_mem_graded [Zero ι] [CommSemiring S] [Semiring R] [A theorem SetLike.natCast_mem_graded [Zero ι] [AddMonoidWithOne R] [SetLike σ R] [AddSubmonoidClass σ R] (A : ι → σ) [SetLike.GradedOne A] (n : ℕ) : (n : R) ∈ A 0 := by - induction' n with _ n_ih - · rw [Nat.cast_zero] + induction n with + | zero => + rw [Nat.cast_zero] exact zero_mem (A 0) - · rw [Nat.cast_succ] + | succ _ n_ih => + rw [Nat.cast_succ] exact add_mem n_ih (SetLike.one_mem_graded _) @[deprecated (since := "2024-04-17")] diff --git a/Mathlib/Algebra/DirectSum/LinearMap.lean b/Mathlib/Algebra/DirectSum/LinearMap.lean index 24dc43c284d75..25ffc82193de4 100644 --- a/Mathlib/Algebra/DirectSum/LinearMap.lean +++ b/Mathlib/Algebra/DirectSum/LinearMap.lean @@ -82,8 +82,8 @@ 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 - (wellFounded_submodule_gt R M) 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 - (isNoetherian_iff_wellFounded.mp inferInstance) 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 5d0336e5ed1e4..291bd79759b1b 100644 --- a/Mathlib/Algebra/DirectSum/Module.lean +++ b/Mathlib/Algebra/DirectSum/Module.lean @@ -28,7 +28,7 @@ universe u v w u₁ namespace DirectSum -open DirectSum +open DirectSum Finsupp section General @@ -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 := @@ -335,7 +335,7 @@ theorem IsInternal.collectedBasis_coe (h : IsInternal A) {α : ι → Type*} -- Porting note: was -- simp only [IsInternal.collectedBasis, toModule, coeLinearMap, Basis.coe_ofRepr, -- Basis.repr_symm_apply, DFinsupp.lsum_apply_apply, DFinsupp.mapRange.linearEquiv_apply, - -- DFinsupp.mapRange.linearEquiv_symm, DFinsupp.mapRange_single, Finsupp.total_single, + -- DFinsupp.mapRange.linearEquiv_symm, DFinsupp.mapRange_single, linearCombination_single, -- LinearEquiv.ofBijective_apply, LinearEquiv.symm_symm, LinearEquiv.symm_trans_apply, one_smul, -- sigmaFinsuppAddEquivDFinsupp_apply, sigmaFinsuppEquivDFinsupp_single, -- sigmaFinsuppLequivDFinsupp_apply] @@ -346,10 +346,10 @@ theorem IsInternal.collectedBasis_coe (h : IsInternal A) {α : ι → Type*} sigmaFinsuppAddEquivDFinsupp_apply] rw [DFinsupp.mapRange.linearEquiv_symm] erw [DFinsupp.mapRange.linearEquiv_apply] - simp only [DFinsupp.mapRange_single, Basis.repr_symm_apply, Finsupp.total_single, one_smul, + 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 05a579900593c..adc80f5bfe07a 100644 --- a/Mathlib/Algebra/DirectSum/Ring.lean +++ b/Mathlib/Algebra/DirectSum/Ring.lean @@ -265,17 +265,18 @@ instance semiring : Semiring (⨁ i, A i) := theorem ofPow {i} (a : A i) (n : ℕ) : of _ i a ^ n = of _ (n • i) (GradedMonoid.GMonoid.gnpow _ a) := by - induction' n with n n_ih - · exact of_eq_of_gradedMonoid_eq (pow_zero <| GradedMonoid.mk _ a).symm - · rw [pow_succ, n_ih, of_mul_of] + induction n with + | zero => exact of_eq_of_gradedMonoid_eq (pow_zero <| GradedMonoid.mk _ a).symm + | succ n n_ih => + rw [pow_succ, n_ih, of_mul_of] exact of_eq_of_gradedMonoid_eq (pow_succ (GradedMonoid.mk _ a) n).symm theorem ofList_dProd {α} (l : List α) (fι : α → ι) (fA : ∀ a, A (fι a)) : of A _ (l.dProd fι fA) = (l.map fun a => of A (fι a) (fA a)).prod := by - induction' l with head tail - · simp only [List.map_nil, List.prod_nil, List.dProd_nil] - rfl - · rename_i ih + induction l with + | nil => simp only [List.map_nil, List.prod_nil, List.dProd_nil]; rfl + | cons head tail => + rename_i ih simp only [List.map_cons, List.prod_cons, List.dProd_cons, ← ih] rw [DirectSum.of_mul_of (fA head)] rfl diff --git a/Mathlib/Algebra/EuclideanDomain/Basic.lean b/Mathlib/Algebra/EuclideanDomain/Basic.lean index 92b8a34c4f9ba..a91e02383e95b 100644 --- a/Mathlib/Algebra/EuclideanDomain/Basic.lean +++ b/Mathlib/Algebra/EuclideanDomain/Basic.lean @@ -237,7 +237,7 @@ theorem lcm_dvd {x y z : R} (hxz : x ∣ z) (hyz : y ∣ z) : lcm x y ∣ z := b rwa [hxy.1] at hxz rcases gcd_dvd x y with ⟨⟨r, hr⟩, ⟨s, hs⟩⟩ suffices x * y ∣ z * gcd x y by - cases' this with p hp + obtain ⟨p, hp⟩ := this use p generalize gcd x y = g at hxy hs hp ⊢ subst hs diff --git a/Mathlib/Algebra/EuclideanDomain/Defs.lean b/Mathlib/Algebra/EuclideanDomain/Defs.lean index 81b62ab8bf111..429e46451dffe 100644 --- a/Mathlib/Algebra/EuclideanDomain/Defs.lean +++ b/Mathlib/Algebra/EuclideanDomain/Defs.lean @@ -6,6 +6,7 @@ Authors: Louis Carlin, Mario Carneiro import Mathlib.Algebra.Divisibility.Basic import Mathlib.Algebra.Group.Basic import Mathlib.Algebra.Ring.Defs +import Mathlib.Order.RelClasses /-! # Euclidean domains @@ -67,7 +68,7 @@ universe u satisfying `b * (a / b) + a % b = a`. The definition of a Euclidean domain usually includes a valuation function `R → ℕ`. This definition is slightly generalised to include a well founded relation - `r` with the property that `r (a % b) b`, instead of a valuation. -/ + `r` with the property that `r (a % b) b`, instead of a valuation. -/ class EuclideanDomain (R : Type u) extends CommRing R, Nontrivial R where /-- A division function (denoted `/`) on `R`. This satisfies the property `b * (a / b) + a % b = a`, where `%` denotes `remainder`. -/ @@ -101,6 +102,9 @@ local infixl:50 " ≺ " => EuclideanDomain.r local instance wellFoundedRelation : WellFoundedRelation R where wf := r_wellFounded +instance isWellFounded : IsWellFounded R (· ≺ ·) where + wf := r_wellFounded + -- see Note [lower instance priority] instance (priority := 70) : Div R := ⟨EuclideanDomain.quotient⟩ diff --git a/Mathlib/Algebra/Exact.lean b/Mathlib/Algebra/Exact.lean index 8a023b47a692f..e3eb8a8116504 100644 --- a/Mathlib/Algebra/Exact.lean +++ b/Mathlib/Algebra/Exact.lean @@ -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/Field/Basic.lean b/Mathlib/Algebra/Field/Basic.lean index b0dabde1c5792..420cf3c602577 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 @@ -242,27 +242,27 @@ 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] + nnratCast_def q := hf <| by rw [nnratCast, NNRat.cast_def, div, natCast, natCast] nnqsmul := (· • ·) - nnqsmul_def q a := hf $ by rw [nnqsmul, NNRat.smul_def, mul, nnratCast] + nnqsmul_def q a := hf <| by rw [nnqsmul, NNRat.smul_def, mul, nnratCast] /-- 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 c29f6e33d0c67..4bb07df74d908 100644 --- a/Mathlib/Algebra/Field/Defs.lean +++ b/Mathlib/Algebra/Field/Defs.lean @@ -43,11 +43,10 @@ a `GroupWithZero` lemma instead. field, division ring, skew field, skew-field, skewfield -/ --- `NeZero` should not be needed in the basic algebraic hierarchy. -assert_not_exists NeZero +assert_not_imported Mathlib.Tactic.Common --- Check that we have not imported `Mathlib.Tactic.Common` yet. -assert_not_exists Mathlib.Tactic.scopedNS +-- `NeZero` theory should not be needed in the basic algebraic hierarchy +assert_not_imported Mathlib.Algebra.NeZero assert_not_exists MonoidHom @@ -55,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`. @@ -82,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. @@ -110,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. @@ -162,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. @@ -176,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/Opposite.lean b/Mathlib/Algebra/Field/Opposite.lean index cde950bef7a7c..99f0c22d73388 100644 --- a/Mathlib/Algebra/Field/Opposite.lean +++ b/Mathlib/Algebra/Field/Opposite.lean @@ -35,7 +35,7 @@ instance instDivisionSemiring [DivisionSemiring α] : DivisionSemiring αᵐᵒ __ := instGroupWithZero nnqsmul := _ nnqsmul_def := fun q a => rfl - nnratCast_def q := unop_injective $ by rw [unop_nnratCast, unop_div, unop_natCast, unop_natCast, + 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] instance instDivisionRing [DivisionRing α] : DivisionRing αᵐᵒᵖ where @@ -63,7 +63,7 @@ instance instDivisionSemiring [DivisionSemiring α] : DivisionSemiring αᵃᵒ __ := instGroupWithZero nnqsmul := _ nnqsmul_def := fun q a => rfl - nnratCast_def q := unop_injective $ by rw [unop_nnratCast, unop_div, unop_natCast, unop_natCast, + nnratCast_def q := unop_injective <| by rw [unop_nnratCast, unop_div, unop_natCast, unop_natCast, NNRat.cast_def, div_eq_mul_inv] instance instDivisionRing [DivisionRing α] : DivisionRing αᵃᵒᵖ where diff --git a/Mathlib/Algebra/Field/Power.lean b/Mathlib/Algebra/Field/Power.lean index 8f85d4bef98a9..b59970a8b25f1 100644 --- a/Mathlib/Algebra/Field/Power.lean +++ b/Mathlib/Algebra/Field/Power.lean @@ -22,7 +22,7 @@ section DivisionRing variable [DivisionRing α] {n : ℤ} theorem Odd.neg_zpow (h : Odd n) (a : α) : (-a) ^ n = -a ^ n := by - have hn : n ≠ 0 := by rintro rfl; exact Int.odd_iff_not_even.1 h even_zero + have hn : n ≠ 0 := by rintro rfl; exact Int.not_even_iff_odd.2 h even_zero obtain ⟨k, rfl⟩ := h simp_rw [zpow_add' (.inr (.inl hn)), zpow_one, zpow_mul, zpow_two, neg_mul_neg, neg_mul_eq_mul_neg] diff --git a/Mathlib/Algebra/Field/Subfield.lean b/Mathlib/Algebra/Field/Subfield.lean index b304f131e2f96..30b6731d7f52c 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 @@ -313,15 +313,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 := @@ -545,6 +545,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 +666,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 diff --git a/Mathlib/Algebra/Free.lean b/Mathlib/Algebra/Free.lean index 68fa9ba945b69..134a4e81ed9ff 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 @@ -244,10 +243,10 @@ instance : LawfulTraversable FreeMagma.{u} := rw [traverse_mul, ih1, ih2, mul_map_seq] comp_traverse := fun f g x ↦ FreeMagma.recOnPure x - (fun x ↦ by simp only [(· ∘ ·), traverse_pure, traverse_pure', functor_norm]) + (fun x ↦ by simp only [Function.comp_def, traverse_pure, traverse_pure', functor_norm]) (fun x y ih1 ih2 ↦ by rw [traverse_mul, ih1, ih2, traverse_mul] - simp [Functor.Comp.map_mk, Functor.map_map, (· ∘ ·), Comp.seq_mk, seq_map_assoc, + simp [Functor.Comp.map_mk, Functor.map_map, Function.comp_def, Comp.seq_mk, seq_map_assoc, map_seq, traverse_mul]) naturality := fun η α β f x ↦ FreeMagma.recOnPure x @@ -592,7 +591,7 @@ theorem traverse_mul (x y : FreeSemigroup α) : (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) - by rw [ih]; simp only [(· ∘ ·), (mul_assoc _ _ _).symm, functor_norm]) + by rw [ih]; simp only [Function.comp_def, (mul_assoc _ _ _).symm, functor_norm]) x @[to_additive (attr := simp)] @@ -618,9 +617,10 @@ instance : LawfulTraversable FreeSemigroup.{u} := FreeSemigroup.recOnMul x (fun x ↦ 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, (· ∘ ·)]) - fun x y ih1 ih2 ↦ by (rw [traverse_mul, ih1, ih2, - traverse_mul, Functor.Comp.map_mk]; simp only [Function.comp, functor_norm, traverse_mul]) + recOnPure x (fun x ↦ by simp only [traverse_pure, functor_norm, Function.comp_def]) + fun x y ih1 ih2 ↦ by + rw [traverse_mul, ih1, ih2, traverse_mul, Functor.Comp.map_mk] + simp only [Function.comp_def, functor_norm, traverse_mul] naturality := fun η α β f x ↦ recOnPure x (fun x ↦ by simp only [traverse_pure, functor_norm, Function.comp]) (fun x y ih1 ih2 ↦ by simp only [traverse_mul, functor_norm, ih1, ih2]) diff --git a/Mathlib/Algebra/FreeAlgebra.lean b/Mathlib/Algebra/FreeAlgebra.lean index 9c12c522bad65..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 @@ -151,7 +152,7 @@ namespace FreeAlgebra attribute [local instance] Pre.hasCoeGenerator Pre.hasCoeSemiring Pre.hasMul Pre.hasAdd Pre.hasZero Pre.hasOne Pre.hasSMul -/-! Define the basic operations-/ +/-! Define the basic operations -/ instance instSMul {A} [CommSemiring A] [Algebra R A] : SMul R (FreeAlgebra A X) where smul r := Quot.map (HMul.hMul (algebraMap R A r : Pre A X)) fun _ _ ↦ Rel.mul_compat_right @@ -294,7 +295,7 @@ variable {A : Type*} [Semiring A] [Algebra R A] private def liftAux (f : X → A) : FreeAlgebra R X →ₐ[R] A where toFun a := Quot.liftOn a (liftFun _ _ f) fun a b h ↦ by - induction' h + induction h · exact (algebraMap R A).map_add _ _ · exact (algebraMap R A).map_mul _ _ · apply Algebra.commutes @@ -526,7 +527,7 @@ namespace FreeAlgebra /-- An induction principle for the free algebra. If `C` holds for the `algebraMap` of `r : R` into `FreeAlgebra R X`, the `ι` of `x : X`, and is -preserved under addition and muliplication, then it holds for all of `FreeAlgebra R X`. +preserved under addition and multiplication, then it holds for all of `FreeAlgebra R X`. -/ @[elab_as_elim, induction_eliminator] theorem induction {C : FreeAlgebra R X → Prop} @@ -567,7 +568,7 @@ variable {A : Type*} [Semiring A] [Algebra R A] theorem _root_.Algebra.adjoin_range_eq_range_freeAlgebra_lift (f : X → A) : Algebra.adjoin R (Set.range f) = (FreeAlgebra.lift R f).range := by simp only [← Algebra.map_top, ← adjoin_range_ι, AlgHom.map_adjoin, ← Set.range_comp, - (· ∘ ·), lift_ι_apply] + Function.comp_def, lift_ι_apply] /-- Noncommutative version of `Algebra.adjoin_range_eq_range`. -/ theorem _root_.Algebra.adjoin_eq_range_freeAlgebra_lift (s : Set A) : diff --git a/Mathlib/Algebra/GCDMonoid/Basic.lean b/Mathlib/Algebra/GCDMonoid/Basic.lean index 6442ad5f441a8..fee781f192238 100644 --- a/Mathlib/Algebra/GCDMonoid/Basic.lean +++ b/Mathlib/Algebra/GCDMonoid/Basic.lean @@ -400,7 +400,7 @@ theorem gcd_mul_left [NormalizedGCDMonoid α] (a b c : α) : gcd (a * b) (a * c) = normalize a * gcd b c := (by_cases (by rintro rfl; simp only [zero_mul, gcd_zero_left, normalize_zero])) fun ha : a ≠ 0 => - suffices gcd (a * b) (a * c) = normalize (a * gcd b c) by simpa + suffices gcd (a * b) (a * c) = normalize (a * gcd b c) by simpa [- normalize_apply] let ⟨d, eq⟩ := dvd_gcd (dvd_mul_right a b) (dvd_mul_right a c) gcd_eq_normalize (eq.symm ▸ mul_dvd_mul_left a @@ -478,7 +478,7 @@ theorem dvd_mul_gcd_iff_dvd_mul [GCDMonoid α] {m n k : α} : k ∣ m * gcd k n Note: In general, this representation is highly non-unique. -See `Nat.prodDvdAndDvdOfDvdProd` for a constructive version on `ℕ`. -/ +See `Nat.prodDvdAndDvdOfDvdProd` for a constructive version on `ℕ`. -/ instance [h : Nonempty (GCDMonoid α)] : DecompositionMonoid α where primal k m n H := by cases h @@ -510,13 +510,13 @@ theorem gcd_pow_right_dvd_pow_gcd [GCDMonoid α] {a b : α} {k : ℕ} : exact (gcd_zero_left' (0 ^ k : α)).dvd.trans (pow_dvd_pow_of_dvd (gcd_zero_left' (0 : α)).symm.dvd _) - · induction' k with k hk - · rw [pow_zero, pow_zero] - exact (gcd_one_right' a).dvd - rw [pow_succ', pow_succ'] - trans gcd a b * gcd a (b ^ k) - · exact gcd_mul_dvd_mul_gcd a b (b ^ k) - · exact (mul_dvd_mul_iff_left hg).mpr hk + · induction k with + | zero => rw [pow_zero, pow_zero]; exact (gcd_one_right' a).dvd + | succ k hk => + rw [pow_succ', pow_succ'] + trans gcd a b * gcd a (b ^ k) + · exact gcd_mul_dvd_mul_gcd a b (b ^ k) + · exact (mul_dvd_mul_iff_left hg).mpr hk theorem gcd_pow_left_dvd_pow_gcd [GCDMonoid α] {a b : α} {k : ℕ} : gcd (a ^ k) b ∣ gcd a b ^ k := calc @@ -589,8 +589,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 +666,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, ← @@ -767,7 +767,7 @@ theorem lcm_mul_left [NormalizedGCDMonoid α] (a b c : α) : lcm (a * b) (a * c) = normalize a * lcm b c := (by_cases (by rintro rfl; simp only [zero_mul, lcm_zero_left, normalize_zero])) fun ha : a ≠ 0 => - suffices lcm (a * b) (a * c) = normalize (a * lcm b c) by simpa + suffices lcm (a * b) (a * c) = normalize (a * lcm b c) by simpa [- normalize_apply] have : a ∣ lcm (a * b) (a * c) := (dvd_mul_right _ _).trans (dvd_lcm_left _ _) let ⟨d, eq⟩ := this lcm_eq_normalize @@ -820,7 +820,7 @@ end GCDMonoid section UniqueUnit -variable [CancelCommMonoidWithZero α] [Unique αˣ] +variable [CancelCommMonoidWithZero α] [Subsingleton αˣ] -- see Note [lower instance priority] instance (priority := 100) normalizationMonoidOfUniqueUnits : NormalizationMonoid α where @@ -855,8 +855,8 @@ instance subsingleton_gcdMonoid_of_unique_units : Subsingleton (GCDMonoid α) := instance subsingleton_normalizedGCDMonoid_of_unique_units : Subsingleton (NormalizedGCDMonoid α) := ⟨by intro a b - cases' a with a_norm a_gcd - cases' b with b_norm b_gcd + cases a; rename_i a_norm a_gcd _ _ + cases b; rename_i b_norm b_gcd _ _ have := Subsingleton.elim a_gcd b_gcd subst this have := Subsingleton.elim a_norm b_norm @@ -1306,7 +1306,7 @@ 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) diff --git a/Mathlib/Algebra/GCDMonoid/Finset.lean b/Mathlib/Algebra/GCDMonoid/Finset.lean index 306e3162d1017..89d7b6ca4f3ef 100644 --- a/Mathlib/Algebra/GCDMonoid/Finset.lean +++ b/Mathlib/Algebra/GCDMonoid/Finset.lean @@ -97,7 +97,7 @@ theorem lcm_mono (h : s₁ ⊆ s₂) : s₁.lcm f ∣ s₂.lcm f := theorem lcm_image [DecidableEq β] {g : γ → β} (s : Finset γ) : (s.image g).lcm f = s.lcm (f ∘ g) := by - classical induction' s using Finset.induction with c s _ ih <;> simp [*] + classical induction s using Finset.induction <;> simp [*] theorem lcm_eq_lcm_image [DecidableEq α] : s.lcm f = (s.image f).lcm id := Eq.symm <| lcm_image _ @@ -170,7 +170,7 @@ theorem gcd_mono (h : s₁ ⊆ s₂) : s₂.gcd f ∣ s₁.gcd f := theorem gcd_image [DecidableEq β] {g : γ → β} (s : Finset γ) : (s.image g).gcd f = s.gcd (f ∘ g) := by - classical induction' s using Finset.induction with c s _ ih <;> simp [*] + classical induction s using Finset.induction <;> simp [*] theorem gcd_eq_gcd_image [DecidableEq α] : s.gcd f = (s.image f).gcd id := Eq.symm <| gcd_image _ diff --git a/Mathlib/Algebra/GCDMonoid/Multiset.lean b/Mathlib/Algebra/GCDMonoid/Multiset.lean index bb77c1ff32a3f..ea5a208bda10a 100644 --- a/Mathlib/Algebra/GCDMonoid/Multiset.lean +++ b/Mathlib/Algebra/GCDMonoid/Multiset.lean @@ -73,9 +73,9 @@ theorem normalize_lcm (s : Multiset α) : normalize s.lcm = s.lcm := @[simp] nonrec theorem lcm_eq_zero_iff [Nontrivial α] (s : Multiset α) : s.lcm = 0 ↔ (0 : α) ∈ s := by - induction' s using Multiset.induction_on with a s ihs - · simp only [lcm_zero, one_ne_zero, not_mem_zero] - · simp only [mem_cons, lcm_cons, lcm_eq_zero_iff, ihs, @eq_comm _ a] + induction s using Multiset.induction_on with + | empty => simp only [lcm_zero, one_ne_zero, not_mem_zero] + | cons a s ihs => simp only [mem_cons, lcm_cons, lcm_eq_zero_iff, ihs, @eq_comm _ a] variable [DecidableEq α] diff --git a/Mathlib/Algebra/GCDMonoid/Nat.lean b/Mathlib/Algebra/GCDMonoid/Nat.lean index c5dadae8f727c..11c7bd9c63679 100644 --- a/Mathlib/Algebra/GCDMonoid/Nat.lean +++ b/Mathlib/Algebra/GCDMonoid/Nat.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Jens Wagemaker, Aaron Anderson -/ import Mathlib.Algebra.GCDMonoid.Basic -import Mathlib.Algebra.Order.Group.Abs -import Mathlib.Algebra.Order.Ring.Int +import Mathlib.Algebra.Order.Group.Unbundled.Int +import Mathlib.Algebra.Ring.Int import Mathlib.Data.Int.GCD /-! @@ -23,6 +23,8 @@ import Mathlib.Data.Int.GCD natural numbers, integers, normalization monoid, gcd monoid, greatest common divisor -/ +assert_not_exists OrderedCommMonoid + /-- `ℕ` is a gcd_monoid. -/ instance : GCDMonoid ℕ where gcd := Nat.gcd @@ -54,10 +56,10 @@ instance normalizationMonoid : NormalizationMonoid ℤ where normUnit a := if 0 ≤ a then 1 else -1 normUnit_zero := if_pos le_rfl normUnit_mul {a b} hna hnb := by - cases' hna.lt_or_lt with ha ha <;> cases' hnb.lt_or_lt with hb hb <;> - simp [mul_nonneg_iff, ha.le, ha.not_le, hb.le, hb.not_le] + rcases hna.lt_or_lt with ha | ha <;> rcases hnb.lt_or_lt with hb | hb <;> + simp [Int.mul_nonneg_iff, ha.le, ha.not_le, hb.le, hb.not_le] normUnit_coe_units u := - (units_eq_one_or u).elim (fun eq => eq.symm ▸ if_pos zero_le_one) fun eq => + (units_eq_one_or u).elim (fun eq => eq.symm ▸ if_pos Int.one_nonneg) fun eq => eq.symm ▸ if_neg (not_le_of_gt <| show (-1 : ℤ) < 0 by decide) -- Porting note: added @@ -76,10 +78,14 @@ theorem normalize_coe_nat (n : ℕ) : normalize (n : ℤ) = n := normalize_of_nonneg (ofNat_le_ofNat_of_le <| Nat.zero_le n) theorem abs_eq_normalize (z : ℤ) : |z| = normalize z := by - cases le_total 0 z <;> simp [-normalize_apply, normalize_of_nonneg, normalize_of_nonpos, *] + cases le_total 0 z <;> + simp [-normalize_apply, 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 := - abs_eq_self.1 <| by rw [abs_eq_normalize, hz] +theorem nonneg_of_normalize_eq_self {z : ℤ} (hz : normalize z = z) : 0 ≤ z := by + by_cases h : 0 ≤ z + · exact h + · rw [normalize_of_nonpos (le_of_not_le h)] at hz + omega theorem nonneg_iff_normalize_eq_self (z : ℤ) : normalize z = z ↔ 0 ≤ z := ⟨nonneg_of_normalize_eq_self, normalize_of_nonneg⟩ @@ -125,7 +131,7 @@ theorem natAbs_lcm (i j : ℤ) : natAbs (GCDMonoid.lcm i j) = Int.lcm i j := end GCDMonoid theorem exists_unit_of_abs (a : ℤ) : ∃ (u : ℤ) (_ : IsUnit u), (Int.natAbs a : ℤ) = u * a := by - cases' natAbs_eq a with h h + rcases natAbs_eq a with h | h · use 1, isUnit_one rw [← h, one_mul] · use -1, isUnit_one.neg diff --git a/Mathlib/Algebra/GeomSum.lean b/Mathlib/Algebra/GeomSum.lean index bce4d36d459b2..70a08526df06e 100644 --- a/Mathlib/Algebra/GeomSum.lean +++ b/Mathlib/Algebra/GeomSum.lean @@ -123,7 +123,7 @@ theorem neg_one_geom_sum [Ring α] {n : ℕ} : simp only [geom_sum_succ', Nat.even_add_one, hk] split_ifs with h · rw [h.neg_one_pow, add_zero] - · rw [(Nat.odd_iff_not_even.2 h).neg_one_pow, neg_add_cancel] + · rw [(Nat.not_even_iff_odd.1 h).neg_one_pow, neg_add_cancel] theorem geom_sum₂_self {α : Type*} [CommRing α] (x : α) (n : ℕ) : ∑ i ∈ range n, x ^ i * x ^ (n - 1 - i) = n * x ^ (n - 1) := @@ -282,7 +282,7 @@ protected theorem Commute.geom_sum₂_succ_eq {α : Type u} [Ring α] {x y : α} (h.symm.pow_right _).eq, mul_assoc, ← pow_succ'] refine sum_congr rfl fun i hi => ?_ suffices n - 1 - i + 1 = n - i by rw [this] - cases' n with n + rcases n with - | n · exact absurd (List.mem_range.mp hi) i.not_lt_zero · rw [tsub_add_eq_add_tsub (Nat.le_sub_one_of_lt (List.mem_range.mp hi)), tsub_add_cancel_of_le (Nat.succ_le_iff.mpr n.succ_pos)] @@ -393,7 +393,7 @@ theorem Nat.pred_mul_geom_sum_le (a b n : ℕ) : theorem Nat.geom_sum_le {b : ℕ} (hb : 2 ≤ b) (a n : ℕ) : ∑ i ∈ range n, a / b ^ i ≤ a * b / (b - 1) := by refine (Nat.le_div_iff_mul_le <| tsub_pos_of_lt hb).2 ?_ - cases' n with n + rcases n with - | n · rw [sum_range_zero, zero_mul] exact Nat.zero_le _ rw [mul_comm] @@ -401,7 +401,7 @@ theorem Nat.geom_sum_le {b : ℕ} (hb : 2 ≤ b) (a n : ℕ) : theorem Nat.geom_sum_Ico_le {b : ℕ} (hb : 2 ≤ b) (a n : ℕ) : ∑ i ∈ Ico 1 n, a / b ^ i ≤ a / (b - 1) := by - cases' n with n + rcases n with - | n · rw [Ico_eq_empty_of_le (zero_le_one' ℕ), sum_empty] exact Nat.zero_le _ rw [← add_le_add_iff_left a] @@ -440,7 +440,7 @@ theorem geom_sum_alternating_of_le_neg_one [StrictOrderedRing α] (hx : x + 1 if Even n then (∑ i ∈ range n, x ^ i) ≤ 0 else 1 ≤ ∑ i ∈ range n, x ^ i := by have hx0 : x ≤ 0 := (le_add_of_nonneg_right zero_le_one).trans hx induction n with - | zero => simp only [Nat.zero_eq, range_zero, sum_empty, le_refl, ite_true, even_zero] + | zero => simp only [range_zero, sum_empty, le_refl, ite_true, even_zero] | succ n ih => simp only [Nat.even_add_one, geom_sum_succ] split_ifs at ih with h @@ -482,9 +482,9 @@ 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.odd_iff_not_even] at h + rw [← Nat.not_even_iff_odd] at h rcases lt_trichotomy (x + 1) 0 with (hx | hx | hx) · have := geom_sum_alternating_of_lt_neg_one hx k.one_lt_succ_succ simp only [h, if_false] at this @@ -495,7 +495,7 @@ theorem Odd.geom_sum_pos [LinearOrderedRing α] (h : Odd n) : 0 < ∑ i ∈ rang theorem geom_sum_pos_iff [LinearOrderedRing α] (hn : n ≠ 0) : (0 < ∑ i ∈ range n, x ^ i) ↔ Odd n ∨ 0 < x + 1 := by refine ⟨fun h => ?_, ?_⟩ - · rw [or_iff_not_imp_left, ← not_le, ← Nat.even_iff_not_odd] + · rw [or_iff_not_imp_left, ← not_le, Nat.not_odd_iff_even] refine fun hn hx => h.not_le ?_ simpa [if_pos hn] using geom_sum_alternating_of_le_neg_one hx n · rintro (hn | hx') @@ -520,7 +520,7 @@ theorem geom_sum_eq_zero_iff_neg_one [LinearOrderedRing α] (hn : n ≠ 0) : refine ⟨fun h => ?_, @fun ⟨h, hn⟩ => by simp only [h, hn, neg_one_geom_sum, if_true]⟩ contrapose! h have hx := eq_or_ne x (-1) - cases' hx with hx hx + rcases hx with hx | hx · rw [hx, neg_one_geom_sum] simp only [h hx, ite_false, ne_eq, one_ne_zero, not_false_eq_true] · exact geom_sum_ne_zero hx hn @@ -528,7 +528,7 @@ theorem geom_sum_eq_zero_iff_neg_one [LinearOrderedRing α] (hn : n ≠ 0) : theorem geom_sum_neg_iff [LinearOrderedRing α] (hn : n ≠ 0) : ∑ i ∈ range n, x ^ i < 0 ↔ Even n ∧ x + 1 < 0 := by rw [← not_iff_not, not_lt, le_iff_lt_or_eq, eq_comm, - or_congr (geom_sum_pos_iff hn) (geom_sum_eq_zero_iff_neg_one hn), Nat.odd_iff_not_even, ← + or_congr (geom_sum_pos_iff hn) (geom_sum_eq_zero_iff_neg_one hn), ← Nat.not_even_iff_odd, ← add_eq_zero_iff_eq_neg, not_and, not_lt, le_iff_lt_or_eq, eq_comm, ← imp_iff_not_or, or_comm, and_comm, Decidable.and_or_imp, or_comm] diff --git a/Mathlib/Algebra/GradedMonoid.lean b/Mathlib/Algebra/GradedMonoid.lean index 4fb0daab42a52..5f4ad73f043d1 100644 --- a/Mathlib/Algebra/GradedMonoid.lean +++ b/Mathlib/Algebra/GradedMonoid.lean @@ -302,9 +302,9 @@ 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 _ _ -@[simp] +@[scoped simp] theorem GradeZero.smul_eq_mul (a b : A 0) : a • b = a * b := rfl @@ -321,7 +321,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/Defs.lean b/Mathlib/Algebra/Group/Action/Defs.lean index b0519ca6ce79c..733f6bd366afc 100644 --- a/Mathlib/Algebra/Group/Action/Defs.lean +++ b/Mathlib/Algebra/Group/Action/Defs.lean @@ -48,7 +48,7 @@ assert_not_exists MonoidWithZero open Function (Injective Surjective) -variable {M N G H A B α β γ δ : Type*} +variable {M N G H α β γ δ : Type*} /-! ### Faithful actions -/ @@ -354,6 +354,24 @@ lemma smul_smul_smul_comm [SMul α β] [SMul α γ] [SMul β δ] [SMul α δ] [S [IsScalarTower α β δ] [IsScalarTower α γ δ] [SMulCommClass β γ δ] (a : α) (b : β) (c : γ) (d : δ) : (a • b) • c • d = (a • c) • b • d := by rw [smul_assoc, smul_assoc, smul_comm b] +/-- Note that the `IsScalarTower α β β` and `SMulCommClass α β β` typeclass arguments are usually +satisfied by `Algebra α β`. -/ +@[to_additive] +lemma smul_mul_smul_comm [Mul α] [Mul β] [SMul α β] [IsScalarTower α β β] + [IsScalarTower α α β] [SMulCommClass α β β] (a : α) (b : β) (c : α) (d : β) : + (a • b) * (c • d) = (a * c) • (b * d) := by + have : SMulCommClass β α β := .symm ..; exact smul_smul_smul_comm a b c d + +@[to_additive (attr := deprecated (since := "2024-08-29"))] +alias smul_mul_smul := smul_mul_smul_comm + +/-- Note that the `IsScalarTower α β β` and `SMulCommClass α β β` typeclass arguments are usually +satisfied by `Algebra α β`. -/ +@[to_additive] +lemma mul_smul_mul_comm [Mul α] [Mul β] [SMul α β] [IsScalarTower α β β] + [IsScalarTower α α β] [SMulCommClass α β β] (a b : α) (c d : β) : + (a * b) • (c * d) = (a • c) * (b • d) := smul_smul_smul_comm a b c d + variable [SMul M α] @[to_additive] @@ -444,19 +462,12 @@ instance IsScalarTower.left : IsScalarTower M M α where variable {M} -/-- Note that the `IsScalarTower M α α` and `SMulCommClass M α α` typeclass arguments are -usually satisfied by `Algebra M α`. -/ -@[to_additive] -- Porting note: nolint to_additive_doc -lemma smul_mul_smul [Mul α] (r s : M) (x y : α) [IsScalarTower M α α] [SMulCommClass M α α] : - r • x * s • y = (r * s) • (x * y) := by - rw [smul_mul_assoc, mul_smul_comm, ← smul_assoc, smul_eq_mul] - section Monoid variable [Monoid N] [MulAction M N] [IsScalarTower M N N] [SMulCommClass M N N] lemma smul_pow (r : M) (x : N) : ∀ n, (r • x) ^ n = r ^ n • x ^ n | 0 => by simp - | n + 1 => by rw [pow_succ', smul_pow _ _ n, smul_mul_smul, ← pow_succ', ← pow_succ'] + | n + 1 => by rw [pow_succ', smul_pow _ _ n, smul_mul_smul_comm, ← pow_succ', ← pow_succ'] end Monoid @@ -476,7 +487,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⟩ @@ -489,7 +500,7 @@ end Mul variable [Group H] [MulAction G H] [SMulCommClass G H H] [IsScalarTower G H H] lemma smul_inv (g : G) (a : H) : (g • a)⁻¹ = g⁻¹ • a⁻¹ := - inv_eq_of_mul_eq_one_right $ by rw [smul_mul_smul, mul_inv_cancel, mul_inv_cancel, one_smul] + inv_eq_of_mul_eq_one_right <| by rw [smul_mul_smul_comm, mul_inv_cancel, mul_inv_cancel, one_smul] lemma smul_zpow (g : G) (a : H) (n : ℤ) : (g • a) ^ n = g ^ n • a ^ n := by cases n <;> simp [smul_pow, smul_inv] diff --git a/Mathlib/Algebra/Group/Action/Opposite.lean b/Mathlib/Algebra/Group/Action/Opposite.lean index 8092a68ff91c7..1217487ac1eda 100644 --- a/Mathlib/Algebra/Group/Action/Opposite.lean +++ b/Mathlib/Algebra/Group/Action/Opposite.lean @@ -27,7 +27,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 +97,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 +124,7 @@ end examples end RightActions section -variable {α β : Type*} [Monoid α] [MulAction αᵐᵒᵖ β] +variable [Monoid α] [MulAction αᵐᵒᵖ β] open scoped RightActions diff --git a/Mathlib/Algebra/Group/Action/Prod.lean b/Mathlib/Algebra/Group/Action/Prod.lean index 0ce4d03aff4d1..e4434083c689b 100644 --- a/Mathlib/Algebra/Group/Action/Prod.lean +++ b/Mathlib/Algebra/Group/Action/Prod.lean @@ -132,7 +132,7 @@ section BundledSMul def smulMulHom [Monoid α] [Mul β] [MulAction α β] [IsScalarTower α β β] [SMulCommClass α β β] : α × β →ₙ* β where toFun a := a.1 • a.2 - map_mul' _ _ := (smul_mul_smul _ _ _ _).symm + map_mul' _ _ := (smul_mul_smul_comm _ _ _ _).symm /-- Scalar multiplication as a monoid homomorphism. -/ @[simps] @@ -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/Sum.lean b/Mathlib/Algebra/Group/Action/Sum.lean index 5bc1602680cfc..0286b8e19b6e9 100644 --- a/Mathlib/Algebra/Group/Action/Sum.lean +++ b/Mathlib/Algebra/Group/Action/Sum.lean @@ -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/Units.lean b/Mathlib/Algebra/Group/Action/Units.lean index d7ad6e43cfdf4..b1b817a1fb920 100644 --- a/Mathlib/Algebra/Group/Action/Units.lean +++ b/Mathlib/Algebra/Group/Action/Units.lean @@ -69,8 +69,8 @@ instance mulAction' [Group G] [Monoid M] [MulAction G M] [SMulCommClass G M M] [IsScalarTower G M M] : MulAction G Mˣ where smul g m := ⟨g • (m : M), (g⁻¹ • ((m⁻¹ : Mˣ) : M)), - by rw [smul_mul_smul, Units.mul_inv, mul_inv_cancel, one_smul], - by rw [smul_mul_smul, Units.inv_mul, inv_mul_cancel, one_smul]⟩ + 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 _ _ _ diff --git a/Mathlib/Algebra/Group/AddChar.lean b/Mathlib/Algebra/Group/AddChar.lean index a8bb7908842b0..f9a1d383c185c 100644 --- a/Mathlib/Algebra/Group/AddChar.lean +++ b/Mathlib/Algebra/Group/AddChar.lean @@ -23,6 +23,15 @@ We also include some constructions specific to the case when `A = R` is a ring; For more refined results of a number-theoretic nature (primitive characters, Gauss sums, etc) see `Mathlib.NumberTheory.LegendreSymbol.AddCharacter`. +# Implementation notes + +Due to their role as the dual of an additive group, additive characters must themselves be an +additive group. This contrasts to their pointwise operations which make them a multiplicative group. +We simply define both the additive and multiplicative group structures and prove them equal. + +For more information on this design decision, see the following zulip thread: +https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/Additive.20characters + ## Tags additive character @@ -33,6 +42,8 @@ additive character -/ open Function Multiplicative +open Finset hiding card +open Fintype (card) section AddCharDef @@ -171,11 +182,28 @@ lemma coe_toAddMonoidHomEquiv (ψ : AddChar A M) : @[simp] lemma toAddMonoidHomEquiv_symm_apply (ψ : A →+ Additive M) (a : A) : toAddMonoidHomEquiv.symm ψ a = Additive.toMul (ψ a) := rfl -/-- The trivial additive character (sending everything to `1`) is `(1 : AddChar A M).` -/ +/-- The trivial additive character (sending everything to `1`). -/ instance instOne : One (AddChar A M) := toMonoidHomEquiv.one +/-- The trivial additive character (sending everything to `1`). -/ +instance instZero : Zero (AddChar A M) := ⟨1⟩ + @[simp, norm_cast] lemma coe_one : ⇑(1 : AddChar A M) = 1 := rfl +@[simp, norm_cast] lemma coe_zero : ⇑(0 : AddChar A M) = 1 := rfl @[simp] lemma one_apply (a : A) : (1 : AddChar A M) a = 1 := rfl +@[simp] lemma zero_apply (a : A) : (0 : AddChar A M) a = 1 := rfl + +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⟩ @@ -220,7 +248,9 @@ lemma compAddMonoidHom_injective_right (ψ : AddChar B M) (hψ : Injective ψ) : rw [DFunLike.ext'_iff] at h ⊢; exact hψ.comp_left h lemma eq_one_iff : ψ = 1 ↔ ∀ x, ψ x = 1 := DFunLike.ext_iff +lemma eq_zero_iff : ψ = 0 ↔ ∀ x, ψ x = 1 := DFunLike.ext_iff lemma ne_one_iff : ψ ≠ 1 ↔ ∃ x, ψ x ≠ 1 := DFunLike.ne_iff +lemma ne_zero_iff : ψ ≠ 0 ↔ ∃ x, ψ x ≠ 1 := DFunLike.ne_iff /-- An additive character is *nontrivial* if it takes a value `≠ 1`. -/ @[deprecated (since := "2024-06-06")] @@ -232,19 +262,51 @@ 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 -variable {A M : Type*} [AddMonoid A] [CommMonoid M] +variable {ι A M : Type*} [AddMonoid A] [CommMonoid M] /-- When `M` is commutative, `AddChar A M` is a commutative monoid. -/ instance instCommMonoid : CommMonoid (AddChar A M) := toMonoidHomEquiv.commMonoid +/-- When `M` is commutative, `AddChar A M` is an additive commutative monoid. -/ +instance instAddCommMonoid : AddCommMonoid (AddChar A M) := Additive.addCommMonoid @[simp, norm_cast] lemma coe_mul (ψ χ : AddChar A M) : ⇑(ψ * χ) = ψ * χ := rfl +@[simp, norm_cast] lemma coe_add (ψ χ : AddChar A M) : ⇑(ψ + χ) = ψ * χ := rfl @[simp, norm_cast] lemma coe_pow (ψ : AddChar A M) (n : ℕ) : ⇑(ψ ^ n) = ψ ^ n := rfl -@[simp, norm_cast] lemma mul_apply (ψ φ : AddChar A M) (a : A) : (ψ * φ) a = ψ a * φ a := rfl -@[simp, norm_cast] lemma pow_apply (ψ : AddChar A M) (n : ℕ) (a : A) : (ψ ^ n) a = (ψ a) ^ n := rfl +@[simp, norm_cast] lemma coe_nsmul (n : ℕ) (ψ : AddChar A M) : ⇑(n • ψ) = ψ ^ n := rfl + +@[simp, norm_cast] +lemma coe_prod (s : Finset ι) (ψ : ι → AddChar A M) : ∏ i in s, ψ i = ∏ i in s, ⇑(ψ i) := by + induction s using Finset.cons_induction <;> simp [*] + +@[simp, norm_cast] +lemma coe_sum (s : Finset ι) (ψ : ι → AddChar A M) : ∑ i in s, ψ i = ∏ i in s, ⇑(ψ i) := by + induction s using Finset.cons_induction <;> simp [*] + +@[simp] lemma mul_apply (ψ φ : AddChar A M) (a : A) : (ψ * φ) a = ψ a * φ a := rfl +@[simp] lemma add_apply (ψ φ : AddChar A M) (a : A) : (ψ + φ) a = ψ a * φ a := rfl +@[simp] lemma pow_apply (ψ : AddChar A M) (n : ℕ) (a : A) : (ψ ^ n) a = (ψ a) ^ n := rfl +@[simp] lemma nsmul_apply (ψ : AddChar A M) (n : ℕ) (a : A) : (n • ψ) a = (ψ a) ^ n := rfl + +lemma prod_apply (s : Finset ι) (ψ : ι → AddChar A M) (a : A) : + (∏ i in s, ψ i) a = ∏ i in s, ψ i a := by rw [coe_prod, Finset.prod_apply] + +lemma sum_apply (s : Finset ι) (ψ : ι → AddChar A M) (a : A) : + (∑ i in s, ψ i) a = ∏ i in s, ψ i a := by rw [coe_sum, Finset.prod_apply] + +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) := @@ -255,8 +317,41 @@ def toMonoidHomMulEquiv : AddChar A M ≃* (Multiplicative A →* M) := def toAddMonoidAddEquiv : Additive (AddChar A M) ≃+ (A →+ Additive M) := { toAddMonoidHomEquiv with map_add' := fun φ ψ ↦ by rfl } +/-- The double dual embedding. -/ +def doubleDualEmb : A →+ AddChar (AddChar A M) M where + toFun a := { toFun := fun ψ ↦ ψ a + map_zero_eq_one' := by simp + map_add_eq_mul' := by simp } + map_zero' := by ext; simp + map_add' _ _ := by ext; simp [map_add_eq_mul] + +@[simp] lemma doubleDualEmb_apply (a : A) (ψ : AddChar A M) : doubleDualEmb a ψ = ψ a := rfl + end toCommMonoid +section CommSemiring +variable {A R : Type*} [AddGroup A] [Fintype A] [CommSemiring R] [IsDomain R] + {ψ : AddChar A R} + +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 + refine eq_zero_of_mul_eq_self_left hx ?_ + rw [Finset.mul_sum] + exact Fintype.sum_equiv (Equiv.addLeft x) _ _ fun y ↦ (map_add_eq_mul ..).symm + +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 + +end CommSemiring + /-! ## Additive characters of additive abelian groups -/ @@ -273,7 +368,13 @@ instance instCommGroup : CommGroup (AddChar A M) := inv := fun ψ ↦ ψ.compAddMonoidHom negAddMonoidHom inv_mul_cancel := fun ψ ↦ by ext1 x; simp [negAddMonoidHom, ← map_add_eq_mul]} -@[simp] lemma inv_apply (ψ : AddChar A M) (x : A) : ψ⁻¹ x = ψ (-x) := rfl +/-- The additive characters on a commutative additive group form a commutative group. -/ +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 +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 @@ -303,11 +404,22 @@ 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) (x : A) : ψ⁻¹ x = (ψ x)⁻¹ := by rw [inv_apply, map_neg_eq_inv] +lemma inv_apply' (ψ : AddChar A M) (a : A) : ψ⁻¹ a = (ψ a)⁻¹ := by rw [inv_apply, map_neg_eq_inv] +lemma neg_apply' (ψ : AddChar A M) (a : A) : (-ψ) a = (ψ a)⁻¹ := map_neg_eq_inv _ _ + +lemma div_apply' (ψ χ : AddChar A M) (a : A) : (ψ / χ) a = ψ a / χ a := by + rw [div_apply, map_neg_eq_inv, div_eq_mul_inv] + +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 _ _ @@ -315,7 +427,15 @@ lemma map_sub_eq_div (ψ : AddChar A M) (a b : A) : ψ (a - b) = ψ a / ψ b := 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₀] + +@[simp] lemma coe_ne_zero (ψ : AddChar A M₀) : (ψ : A → M₀) ≠ 0 := + ne_iff.2 ⟨0, fun h ↦ by simpa only [h, Pi.zero_apply, zero_ne_one] using map_zero_eq_one ψ⟩ + +end MonoidWithZero /-! ## Additive characters of rings diff --git a/Mathlib/Algebra/Group/Aut.lean b/Mathlib/Algebra/Group/Aut.lean index cb169b83f1a64..567b51be95470 100644 --- a/Mathlib/Algebra/Group/Aut.lean +++ b/Mathlib/Algebra/Group/Aut.lean @@ -17,7 +17,7 @@ The definition of multiplication in the automorphism groups agrees with function multiplication in `Equiv.Perm`, and multiplication in `CategoryTheory.End`, but not with `CategoryTheory.comp`. -This file is kept separate from `Data/Equiv/MulAdd` so that `GroupTheory.Perm` is free to use +This file is kept separate from `Algebra/Group/Equiv/*` so that `GroupTheory.Perm` is free to use equivalences (and other files that use them) before the group structure is defined. ## Tags diff --git a/Mathlib/Algebra/Group/Basic.lean b/Mathlib/Algebra/Group/Basic.lean index 9ebc3308c99d3..244c63da588ad 100644 --- a/Mathlib/Algebra/Group/Basic.lean +++ b/Mathlib/Algebra/Group/Basic.lean @@ -8,7 +8,6 @@ import Mathlib.Algebra.Group.Defs import Mathlib.Data.Nat.Defs import Mathlib.Data.Int.Defs import Mathlib.Logic.Function.Basic -import Mathlib.Tactic.Cases import Mathlib.Tactic.SimpRw import Mathlib.Tactic.SplitIfs @@ -91,7 +90,7 @@ section Semigroup variable [Semigroup α] @[to_additive] -instance Semigroup.to_isAssociative : Std.Associative (α := α) (· * ·) := ⟨mul_assoc⟩ +instance Semigroup.to_isAssociative : Std.Associative (α := α) (· * ·) := ⟨mul_assoc⟩ /-- Composing two multiplications on the left by `y` then `x` is equal to a multiplication on the left by `x * y`. @@ -149,12 +148,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 @@ -173,7 +172,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) : @@ -189,11 +188,11 @@ lemma pow_sub_mul_pow (a : M) (h : m ≤ n) : a ^ (n - m) * a ^ m = a ^ n := by @[to_additive sub_one_nsmul_add] lemma mul_pow_sub_one (hn : n ≠ 0) (a : M) : a * a ^ (n - 1) = a ^ n := by - rw [← pow_succ', Nat.sub_add_cancel $ Nat.one_le_iff_ne_zero.2 hn] + rw [← pow_succ', Nat.sub_add_cancel <| Nat.one_le_iff_ne_zero.2 hn] @[to_additive add_sub_one_nsmul] lemma pow_sub_one_mul (hn : n ≠ 0) (a : M) : a ^ (n - 1) * a = a ^ n := by - rw [← pow_succ, Nat.sub_add_cancel $ Nat.one_le_iff_ne_zero.2 hn] + rw [← pow_succ, Nat.sub_add_cancel <| Nat.one_le_iff_ne_zero.2 hn] /-- If `x ^ n = 1`, then `x ^ m` is the same as `x ^ (m % n)` -/ @[to_additive nsmul_eq_mod_nsmul "If `n • x = 0`, then `m • x` is the same as `(m % n) • x`"] @@ -317,7 +316,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] @@ -409,7 +408,7 @@ theorem one_div_one_div : 1 / (1 / a) = a := by simp theorem div_eq_div_iff_comm : a / b = c / d ↔ b / a = d / c := inv_inj.symm.trans <| by simp only [inv_div] -@[to_additive SubtractionMonoid.toSubNegZeroMonoid] +@[to_additive] instance (priority := 100) DivisionMonoid.toDivInvOneMonoid : DivInvOneMonoid α := { DivisionMonoid.toDivInvMonoid with inv_one := by simpa only [one_div, inv_inv] using (inv_div (1 : α) 1).symm } @@ -524,6 +523,8 @@ theorem div_eq_inv_mul : a / b = b⁻¹ * a := by simp @[to_additive] theorem inv_mul_eq_div : a⁻¹ * b = b / a := by simp +@[to_additive] lemma inv_div_comm (a b : α) : a⁻¹ / b = b⁻¹ / a := by simp + @[to_additive] theorem inv_mul' : (a * b)⁻¹ = a⁻¹ / b := by simp @@ -585,14 +586,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 @@ -642,6 +645,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 @@ -727,13 +740,15 @@ theorem div_left_inj : b / a = c / a ↔ b = c := by rw [div_eq_mul_inv, div_eq_mul_inv] exact mul_left_inj _ -@[to_additive (attr := simp) sub_add_sub_cancel] -theorem div_mul_div_cancel' (a b c : G) : a / b * (b / c) = a / c := by +@[to_additive (attr := simp)] +theorem div_mul_div_cancel (a b c : G) : a / b * (b / c) = a / c := by rw [← mul_div_assoc, div_mul_cancel] -@[to_additive (attr := simp) sub_sub_sub_cancel_right] -theorem div_div_div_cancel_right' (a b c : G) : a / c / (b / c) = a / b := by - rw [← inv_div c b, div_inv_eq_mul, div_mul_div_cancel'] +@[to_additive (attr := simp)] +theorem div_div_div_cancel_right (a b c : G) : a / c / (b / c) = a / b := by + rw [← inv_div c b, div_inv_eq_mul, div_mul_div_cancel] + +@[deprecated (since := "2024-08-24")] alias div_div_div_cancel_right' := div_div_div_cancel_right @[to_additive] theorem div_eq_one : a / b = 1 ↔ a = b := @@ -832,6 +847,18 @@ lemma mul_zpow_self (a : G) (n : ℤ) : a ^ n * a = a ^ (n + 1) := (zpow_add_one @[to_additive sub_zsmul] lemma zpow_sub (a : G) (m n : ℤ) : a ^ (m - n) = a ^ m * (a ^ n)⁻¹ := by rw [Int.sub_eq_add_neg, zpow_add, zpow_neg] +@[to_additive natCast_sub_natCast_zsmul] +lemma zpow_natCast_sub_natCast (a : G) (m n : ℕ) : a ^ (m - n : ℤ) = a ^ m / a ^ n := by + simpa [div_eq_mul_inv] using zpow_sub a m n + +@[to_additive natCast_sub_one_zsmul] +lemma zpow_natCast_sub_one (a : G) (n : ℕ) : a ^ (n - 1 : ℤ) = a ^ n / a := by + simpa [div_eq_mul_inv] using zpow_sub a n 1 + +@[to_additive one_sub_natCast_zsmul] +lemma zpow_one_sub_natCast (a : G) (n : ℕ) : a ^ (1 - n : ℤ) = a / a ^ n := by + simpa [div_eq_mul_inv] using zpow_sub a 1 n + @[to_additive] lemma zpow_mul_comm (a : G) (m n : ℤ) : a ^ m * a ^ n = a ^ n * a ^ m := by rw [← zpow_add, Int.add_comm, zpow_add] @@ -852,11 +879,13 @@ addition by `g` and `-g` on the left. For additive subgroups generated by more t `AddSubgroup.closure_induction_left`."] lemma zpow_induction_left {g : G} {P : G → Prop} (h_one : P (1 : G)) (h_mul : ∀ a, P a → P (g * a)) (h_inv : ∀ a, P a → P (g⁻¹ * a)) (n : ℤ) : P (g ^ n) := by - induction' n using Int.induction_on with n ih n ih - · rwa [zpow_zero] - · rw [Int.add_comm, zpow_add, zpow_one] + induction n using Int.induction_on with + | hz => rwa [zpow_zero] + | hp n ih => + rw [Int.add_comm, zpow_add, zpow_one] exact h_mul _ ih - · rw [Int.sub_eq_add_neg, Int.add_comm, zpow_add, zpow_neg_one] + | hn n ih => + rw [Int.sub_eq_add_neg, Int.add_comm, zpow_add, zpow_neg_one] exact h_inv _ ih /-- To show a property of all powers of `g` it suffices to show it is closed under multiplication @@ -867,11 +896,13 @@ addition by `g` and `-g` on the right. For additive subgroups generated by more see `AddSubgroup.closure_induction_right`."] lemma zpow_induction_right {g : G} {P : G → Prop} (h_one : P (1 : G)) (h_mul : ∀ a, P a → P (a * g)) (h_inv : ∀ a, P a → P (a * g⁻¹)) (n : ℤ) : P (g ^ n) := by - induction' n using Int.induction_on with n ih n ih - · rwa [zpow_zero] - · rw [zpow_add_one] + induction n using Int.induction_on with + | hz => rwa [zpow_zero] + | hp n ih => + rw [zpow_add_one] exact h_mul _ ih - · rw [zpow_sub_one] + | hn n ih => + rw [zpow_sub_one] exact h_inv _ ih end Group @@ -945,9 +976,11 @@ theorem mul_mul_div_cancel (a b c : G) : a * c * (b / c) = a * b := by theorem div_mul_mul_cancel (a b c : G) : a / c * (b * c) = a * b := by rw [mul_left_comm, div_mul_cancel, mul_comm] -@[to_additive (attr := simp) sub_add_sub_cancel'] -theorem div_mul_div_cancel'' (a b c : G) : a / b * (c / a) = c / b := by - rw [mul_comm]; apply div_mul_div_cancel' +@[to_additive (attr := simp)] +theorem div_mul_div_cancel' (a b c : G) : a / b * (c / a) = c / b := by + rw [mul_comm]; apply div_mul_div_cancel + +@[deprecated (since := "2024-08-24")] alias div_mul_div_cancel'' := div_mul_div_cancel' @[to_additive (attr := simp)] theorem mul_div_div_cancel (a b c : G) : a * b / (a / c) = b * c := by @@ -955,7 +988,7 @@ theorem mul_div_div_cancel (a b c : G) : a * b / (a / c) = b * c := by @[to_additive (attr := simp)] theorem div_div_div_cancel_left (a b c : G) : c / a / (c / b) = b / a := by - rw [← inv_div b c, div_inv_eq_mul, mul_comm, div_mul_div_cancel'] + rw [← inv_div b c, div_inv_eq_mul, mul_comm, div_mul_div_cancel] @[to_additive] theorem div_eq_div_iff_mul_eq_mul : a / b = c / d ↔ a * d = c * b := by diff --git a/Mathlib/Algebra/Group/Center.lean b/Mathlib/Algebra/Group/Center.lean index de1591f22ebe2..786c03ef1f1db 100644 --- a/Mathlib/Algebra/Group/Center.lean +++ b/Mathlib/Algebra/Group/Center.lean @@ -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 f7933b6cd9c28..324484366c26a 100644 --- a/Mathlib/Algebra/Group/Commute/Defs.lean +++ b/Mathlib/Algebra/Group/Commute/Defs.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Neil Strickland, Yury Kudryashov -/ import Mathlib.Algebra.Group.Semiconj.Defs -import Mathlib.Init.Algebra.Classes +import Mathlib.Order.Defs /-! # Commuting pairs of elements in monoids @@ -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 77426efb55ff3..3dbb4606b7541 100644 --- a/Mathlib/Algebra/Group/Conj.lean +++ b/Mathlib/Algebra/Group/Conj.lean @@ -99,7 +99,7 @@ theorem conj_pow {i : ℕ} {a b : α} : (a * b * a⁻¹) ^ i = a * b ^ i * a⁻ @[simp] theorem conj_zpow {i : ℤ} {a b : α} : (a * b * a⁻¹) ^ i = a * b ^ i * a⁻¹ := by - induction' i + induction i · change (a * b * a⁻¹) ^ (_ : ℤ) = a * b ^ (_ : ℤ) * a⁻¹ simp [zpow_natCast] · simp only [zpow_negSucc, conj_pow, mul_inv_rev, inv_inv] diff --git a/Mathlib/Algebra/Group/Defs.lean b/Mathlib/Algebra/Group/Defs.lean index 078d8fe493dd1..7f7d7ece643cd 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 @@ -332,7 +331,7 @@ class LeftCancelSemigroup (G : Type u) extends Semigroup G where library_note "lower cancel priority" /-- We lower the priority of inheriting from cancellative structures. -This attemts to avoid expensive checks involving bundling and unbundling with the `IsDomain` class. +This attempts to avoid expensive checks involving bundling and unbundling with the `IsDomain` class. since `IsDomain` already depends on `Semiring`, we can synthesize that one first. Zulip discussion: https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/Why.20is.20.60simpNF.60.20complaining.20here.3F -/ @@ -553,7 +552,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 +632,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 +651,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 +679,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 +807,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 +848,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 +879,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 := @@ -957,7 +956,7 @@ class InvOneClass (G : Type*) extends One G, Inv G where protected inv_one : (1 : G)⁻¹ = 1 /-- A `DivInvMonoid` where `1⁻¹ = 1`. -/ -@[to_additive SubNegZeroMonoid] +@[to_additive] class DivInvOneMonoid (G : Type*) extends DivInvMonoid G, InvOneClass G -- FIXME: `to_additive` is not operating on the second parent. (#660) @@ -983,7 +982,7 @@ class SubtractionMonoid (G : Type u) extends SubNegMonoid G, InvolutiveNeg G whe `(a * b)⁻¹ = b⁻¹ * a⁻¹` and `a * b = 1 → a⁻¹ = b`. This is the immediate common ancestor of `Group` and `GroupWithZero`. -/ -@[to_additive SubtractionMonoid] +@[to_additive] class DivisionMonoid (G : Type u) extends DivInvMonoid G, InvolutiveInv G where protected mul_inv_rev (a b : G) : (a * b)⁻¹ = b⁻¹ * a⁻¹ /-- Despite the asymmetry of `inv_eq_of_mul`, the symmetric version is true thanks to the @@ -1031,7 +1030,7 @@ There is also a division operation `/` such that `a / b = a * b⁻¹`, with a default so that `a / b = a * b⁻¹` holds by definition. Use `Group.ofLeftAxioms` or `Group.ofRightAxioms` to define a group structure -on a type with the minumum proof obligations. +on a type with the minimum proof obligations. -/ class Group (G : Type u) extends DivInvMonoid G where protected inv_mul_cancel : ∀ a : G, a⁻¹ * a = 1 @@ -1042,7 +1041,7 @@ There is also a binary operation `-` such that `a - b = a + -b`, with a default so that `a - b = a + -b` holds by definition. Use `AddGroup.ofLeftAxioms` or `AddGroup.ofRightAxioms` to define an -additive group structure on a type with the minumum proof obligations. +additive group structure on a type with the minimum proof obligations. -/ class AddGroup (A : Type u) extends SubNegMonoid A where protected neg_add_cancel : ∀ a : A, -a + a = 0 @@ -1051,7 +1050,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 := @@ -1090,7 +1089,7 @@ theorem mul_inv_cancel_right (a b : G) : a * b * b⁻¹ = a := by theorem inv_mul_cancel_right (a b : G) : a * b⁻¹ * b = a := by rw [mul_assoc, inv_mul_cancel, mul_one] -@[to_additive AddGroup.toSubtractionMonoid] +@[to_additive] instance (priority := 100) Group.toDivisionMonoid : DivisionMonoid G := { inv_inv := fun a ↦ inv_eq_of_mul (inv_mul_cancel a) mul_inv_rev := diff --git a/Mathlib/Algebra/Group/Equiv/Basic.lean b/Mathlib/Algebra/Group/Equiv/Basic.lean index 6e39d0838d7ec..cb72fdfe7db40 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,15 @@ protected theorem injective (e : M ≃* N) : Function.Injective e := protected theorem surjective (e : M ≃* N) : Function.Surjective e := EquivLike.surjective e +-- Porting note (#10618): `simp` can prove this +@[to_additive] +theorem apply_eq_iff_eq (e : M ≃* N) {x y : M} : e x = e y ↔ x = y := + e.injective.eq_iff + +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 +282,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 +315,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 +327,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 +338,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 +356,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 +389,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 +461,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 /-! 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..3896969ce6795 --- /dev/null +++ b/Mathlib/Algebra/Group/EvenFunction.lean @@ -0,0 +1,152 @@ +/- +Copyright (c) 2024 David Loeffler. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: David Loeffler +-/ +import Mathlib.Algebra.Group.Action.Pi +import Mathlib.Algebra.Module.Defs +import Mathlib.Algebra.BigOperators.Group.Finset + +/-! +# 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). +-/ + +open scoped BigOperators + +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..9385f63b70721 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 -/ @@ -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 e1a97f26ed9b8..9eb317e8d7b71 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,10 +98,10 @@ 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'`. -/ +For the iff statement on the triviality of the kernel, see `injective_iff_map_eq_one'`. -/ @[to_additive "A homomorphism from an additive group to an additive monoid is injective iff its kernel is trivial. For the iff statement on the triviality of the kernel, @@ -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 fa2cc235e3d24..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 -/ @@ -106,3 +105,5 @@ theorem comp_assoc {Q : Type*} [Monoid Q] exact ⟨by simp only [← κ.comp_eq, ← h, ← κ'.comp_eq, MonoidHom.comp_assoc]⟩ end MonoidHom.CompTriple + +end MonoidHomCompTriple diff --git a/Mathlib/Algebra/Group/Hom/Defs.lean b/Mathlib/Algebra/Group/Hom/Defs.lean index a64a2118ac2da..1a3bf932f98fd 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 @@ -312,7 +334,7 @@ variable [MulOneClass M] [MulOneClass N] /-- `M →* N` is the type of functions `M → N` that preserve the `Monoid` structure. `MonoidHom` is also used for group homomorphisms. -When possible, instead of parametrizing results over `(f : M →+ N)`, +When possible, instead of parametrizing results over `(f : M →* N)`, you should parametrize over `(F : Type*) [MonoidHomClass F M N] (f : F)`. When you extend this structure, make sure to extend `MonoidHomClass`. @@ -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 @@ -837,8 +866,8 @@ instance : Monoid (Monoid.End M) where mul_assoc _ _ _ := MonoidHom.comp_assoc _ _ _ 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 n f := (npowRec n f).copy f^[n] <| by induction n <;> simp [npowRec, *] <;> rfl + npow_succ n f := DFunLike.coe_injective <| Function.iterate_succ _ _ instance : Inhabited (Monoid.End M) := ⟨1⟩ @@ -878,8 +907,8 @@ instance monoid : Monoid (AddMonoid.End A) where mul_assoc _ _ _ := AddMonoidHom.comp_assoc _ _ _ 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 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 _ _ @[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 68214b8258570..ccb3633809bca 100644 --- a/Mathlib/Algebra/Group/Indicator.lean +++ b/Mathlib/Algebra/Group/Indicator.lean @@ -41,7 +41,7 @@ section One variable [One M] [One N] {s t : Set α} {f g : α → M} {a : α} -/-- `Set.mulIndicator s f a` is `f a` if `a ∈ s`, `1` otherwise. -/ +/-- `Set.mulIndicator s f a` is `f a` if `a ∈ s`, `1` otherwise. -/ @[to_additive "`Set.indicator s f a` is `f a` if `a ∈ s`, `0` otherwise."] noncomputable def mulIndicator (s : Set α) (f : α → M) (x : α) : M := haveI := Classical.decPred (· ∈ s) diff --git a/Mathlib/Algebra/Group/InjSurj.lean b/Mathlib/Algebra/Group/InjSurj.lean index 4f2c17838f4dc..c25210c59545a 100644 --- a/Mathlib/Algebra/Group/InjSurj.lean +++ b/Mathlib/Algebra/Group/InjSurj.lean @@ -26,7 +26,7 @@ And there are versions for (additive) (commutative) semigroups/monoids. ## Implementation note -The `nsmul` and `zsmul` assumptions on any tranfer definition for an algebraic structure involving +The `nsmul` and `zsmul` assumptions on any transfer definition for an algebraic structure involving both addition and multiplication (eg `AddMonoidWithOne`) is `∀ n x, f (n • x) = n • f x`, which is what we would expect. However, we cannot do the same for transfer definitions built using `to_additive` (eg `AddMonoid`) @@ -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,15 +232,15 @@ 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 [reducible non-instances]. -/ -@[to_additive subNegZeroMonoid +@[to_additive "A type endowed with `0`, `+`, unary `-`, and binary `-` is a `SubNegZeroMonoid` if it admits an injective map that preserves `0`, `+`, unary `-`, and binary `-` to a `SubNegZeroMonoid`. This version takes custom `nsmul` and `zsmul` as `[SMul ℕ M₁]` and @@ -253,7 +253,7 @@ protected abbrev divInvOneMonoid [DivInvOneMonoid M₂] (f : M₁ → M₂) (hf /-- A type endowed with `1`, `*`, `⁻¹`, and `/` is a `DivisionMonoid` if it admits an injective map that preserves `1`, `*`, `⁻¹`, and `/` to a `DivisionMonoid`. See note [reducible non-instances] -/ -@[to_additive subtractionMonoid +@[to_additive "A type endowed with `0`, `+`, unary `-`, and binary `-` is a `SubtractionMonoid` if it admits an injective map that preserves `0`, `+`, unary `-`, and binary `-` to a `SubtractionMonoid`. This version takes custom `nsmul` and `zsmul` as `[SMul ℕ M₁]` @@ -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..e30cfc2cfe4b0 100644 --- a/Mathlib/Algebra/Group/Int.lean +++ b/Mathlib/Algebra/Group/Int.lean @@ -47,7 +47,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 diff --git a/Mathlib/Algebra/Group/Invertible/Defs.lean b/Mathlib/Algebra/Group/Invertible/Defs.lean index a44dee8152e49..58a3021aca712 100644 --- a/Mathlib/Algebra/Group/Invertible/Defs.lean +++ b/Mathlib/Algebra/Group/Invertible/Defs.lean @@ -90,51 +90,64 @@ class Invertible [Mul α] [One α] (a : α) : Type u where mul_invOf_self : a * invOf = 1 /-- The inverse of an `Invertible` element -/ -prefix:max - "⅟" =>-- This notation has the same precedence as `Inv.inv`. - Invertible.invOf +-- This notation has the same precedence as `Inv.inv`. +prefix:max "⅟" => Invertible.invOf @[simp] theorem invOf_mul_self' [Mul α] [One α] (a : α) {_ : Invertible a} : ⅟ a * a = 1 := Invertible.invOf_mul_self -theorem invOf_mul_self [Mul α] [One α] (a : α) [Invertible a] : ⅟ a * a = 1 := - Invertible.invOf_mul_self +theorem invOf_mul_self [Mul α] [One α] (a : α) [Invertible a] : ⅟ a * a = 1 := invOf_mul_self' _ @[simp] theorem mul_invOf_self' [Mul α] [One α] (a : α) {_ : Invertible a} : a * ⅟ a = 1 := Invertible.mul_invOf_self -theorem mul_invOf_self [Mul α] [One α] (a : α) [Invertible a] : a * ⅟ a = 1 := - Invertible.mul_invOf_self +theorem mul_invOf_self [Mul α] [One α] (a : α) [Invertible a] : a * ⅟ a = 1 := mul_invOf_self' _ @[simp] -theorem invOf_mul_self_assoc' [Monoid α] (a b : α) {_ : Invertible a} : ⅟ a * (a * b) = b := by +theorem invOf_mul_cancel_left' [Monoid α] (a b : α) {_ : Invertible a} : ⅟ a * (a * b) = b := by rw [← mul_assoc, invOf_mul_self, one_mul] +example {G} [Group G] (a b : G) : a⁻¹ * (a * b) = b := inv_mul_cancel_left a b -theorem invOf_mul_self_assoc [Monoid α] (a b : α) [Invertible a] : ⅟ a * (a * b) = b := by - rw [← mul_assoc, invOf_mul_self, one_mul] +theorem invOf_mul_cancel_left [Monoid α] (a b : α) [Invertible a] : ⅟ a * (a * b) = b := + invOf_mul_cancel_left' _ _ + +@[deprecated (since := "2024-09-07")] alias invOf_mul_self_assoc' := invOf_mul_cancel_left' +@[deprecated (since := "2024-09-07")] alias invOf_mul_self_assoc := invOf_mul_cancel_left @[simp] -theorem mul_invOf_self_assoc' [Monoid α] (a b : α) {_ : Invertible a} : a * (⅟ a * b) = b := by +theorem mul_invOf_cancel_left' [Monoid α] (a b : α) {_ : Invertible a} : a * (⅟ a * b) = b := by rw [← mul_assoc, mul_invOf_self, one_mul] +example {G} [Group G] (a b : G) : a * (a⁻¹ * b) = b := mul_inv_cancel_left a b -theorem mul_invOf_self_assoc [Monoid α] (a b : α) [Invertible a] : a * (⅟ a * b) = b := by - rw [← mul_assoc, mul_invOf_self, one_mul] +theorem mul_invOf_cancel_left [Monoid α] (a b : α) [Invertible a] : a * (⅟ a * b) = b := + mul_invOf_cancel_left' a b + +@[deprecated (since := "2024-09-07")] alias mul_invOf_self_assoc' := mul_invOf_cancel_left' +@[deprecated (since := "2024-09-07")] alias mul_invOf_self_assoc := mul_invOf_cancel_left @[simp] -theorem mul_invOf_mul_self_cancel' [Monoid α] (a b : α) {_ : Invertible b} : a * ⅟ b * b = a := by +theorem invOf_mul_cancel_right' [Monoid α] (a b : α) {_ : Invertible b} : a * ⅟ b * b = a := by simp [mul_assoc] +example {G} [Group G] (a b : G) : a * b⁻¹ * b = a := inv_mul_cancel_right a b -theorem mul_invOf_mul_self_cancel [Monoid α] (a b : α) [Invertible b] : a * ⅟ b * b = a := by - simp [mul_assoc] +theorem invOf_mul_cancel_right [Monoid α] (a b : α) [Invertible b] : a * ⅟ b * b = a := + invOf_mul_cancel_right' _ _ + +@[deprecated (since := "2024-09-07")] alias mul_invOf_mul_self_cancel' := invOf_mul_cancel_right' +@[deprecated (since := "2024-09-07")] alias mul_invOf_mul_self_cancel := invOf_mul_cancel_right @[simp] -theorem mul_mul_invOf_self_cancel' [Monoid α] (a b : α) {_ : Invertible b} : a * b * ⅟ b = a := by +theorem mul_invOf_cancel_right' [Monoid α] (a b : α) {_ : Invertible b} : a * b * ⅟ b = a := by simp [mul_assoc] +example {G} [Group G] (a b : G) : a * b * b⁻¹ = a := mul_inv_cancel_right a b -theorem mul_mul_invOf_self_cancel [Monoid α] (a b : α) [Invertible b] : a * b * ⅟ b = a := by - simp [mul_assoc] +theorem mul_invOf_cancel_right [Monoid α] (a b : α) [Invertible b] : a * b * ⅟ b = a := + mul_invOf_cancel_right' _ _ + +@[deprecated (since := "2024-09-07")] alias mul_mul_invOf_self_cancel' := mul_invOf_cancel_right' +@[deprecated (since := "2024-09-07")] alias mul_mul_invOf_self_cancel := mul_invOf_cancel_right theorem invOf_eq_right_inv [Monoid α] {a b : α} [Invertible a] (hac : a * b = 1) : ⅟ a = b := left_inv_eq_right_inv (invOf_mul_self _) hac @@ -185,8 +198,7 @@ def invertibleOne [Monoid α] : Invertible (1 : α) := theorem invOf_one' [Monoid α] {_ : Invertible (1 : α)} : ⅟ (1 : α) = 1 := invOf_eq_right_inv (mul_one _) -theorem invOf_one [Monoid α] [Invertible (1 : α)] : ⅟ (1 : α) = 1 := - invOf_eq_right_inv (mul_one _) +theorem invOf_one [Monoid α] [Invertible (1 : α)] : ⅟ (1 : α) = 1 := invOf_one' /-- `a` is the inverse of `⅟a`. -/ instance invertibleInvOf [One α] [Mul α] {a : α} [Invertible a] : Invertible (⅟ a) := @@ -226,15 +238,15 @@ theorem mul_left_inj_of_invertible : c * a = c * b ↔ a = b := ⟨fun h => by simpa using congr_arg (⅟c * ·) h, congr_arg (_ * ·)⟩ theorem invOf_mul_eq_iff_eq_mul_left : ⅟c * a = b ↔ a = c * b := by - rw [← mul_left_inj_of_invertible (c := c), mul_invOf_self_assoc] + rw [← mul_left_inj_of_invertible (c := c), mul_invOf_cancel_left] theorem mul_left_eq_iff_eq_invOf_mul : c * a = b ↔ a = ⅟c * b := by - rw [← mul_left_inj_of_invertible (c := ⅟c), invOf_mul_self_assoc] + rw [← mul_left_inj_of_invertible (c := ⅟c), invOf_mul_cancel_left] theorem mul_invOf_eq_iff_eq_mul_right : a * ⅟c = b ↔ a = b * c := by - rw [← mul_right_inj_of_invertible (c := c), mul_invOf_mul_self_cancel] + rw [← mul_right_inj_of_invertible (c := c), invOf_mul_cancel_right] theorem mul_right_eq_iff_eq_mul_invOf : a * c = b ↔ a = b * ⅟c := by - rw [← mul_right_inj_of_invertible (c := ⅟c), mul_mul_invOf_self_cancel] + rw [← mul_right_inj_of_invertible (c := ⅟c), mul_invOf_cancel_right] end diff --git a/Mathlib/Algebra/Group/Nat.lean b/Mathlib/Algebra/Group/Nat.lean index c9678bda255d1..8ccb770e633d4 100644 --- a/Mathlib/Algebra/Group/Nat.lean +++ b/Mathlib/Algebra/Group/Nat.lean @@ -5,6 +5,7 @@ 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 /-! # The natural numbers form a monoid @@ -96,7 +97,7 @@ lemma not_even_iff : ¬ Even n ↔ n % 2 = 1 := by rw [even_iff, mod_two_ne_zero @[simp] lemma not_even_one : ¬Even 1 := by simp [even_iff] @[parity_simps] lemma even_add : Even (m + n) ↔ (Even m ↔ Even n) := by - cases' mod_two_eq_zero_or_one m with h₁ h₁ <;> cases' mod_two_eq_zero_or_one n with h₂ h₂ <;> + rcases mod_two_eq_zero_or_one m with h₁ | h₁ <;> rcases mod_two_eq_zero_or_one n with h₂ | h₂ <;> simp [even_iff, h₁, h₂, Nat.add_mod] @[parity_simps] lemma even_add_one : Even (n + 1) ↔ ¬Even n := by simp [even_add] @@ -117,7 +118,7 @@ lemma two_not_dvd_two_mul_sub_one : ∀ {n}, 0 < n → ¬2 ∣ 2 * n - 1 by_cases h : Even n <;> simp [h] @[parity_simps] lemma even_mul : Even (m * n) ↔ Even m ∨ Even n := by - cases' mod_two_eq_zero_or_one m with h₁ h₁ <;> cases' mod_two_eq_zero_or_one n with h₂ h₂ <;> + rcases mod_two_eq_zero_or_one m with h₁ | h₁ <;> rcases mod_two_eq_zero_or_one n with h₂ | h₂ <;> simp [even_iff, h₁, h₂, Nat.mul_mod] /-- If `m` and `n` are natural numbers, then the natural number `m^n` is even diff --git a/Mathlib/Algebra/Group/NatPowAssoc.lean b/Mathlib/Algebra/Group/NatPowAssoc.lean index edb971427d8ac..0c97d42dd642b 100644 --- a/Mathlib/Algebra/Group/NatPowAssoc.lean +++ b/Mathlib/Algebra/Group/NatPowAssoc.lean @@ -116,9 +116,9 @@ instance Monoid.PowAssoc : NatPowAssoc M where @[simp, norm_cast] theorem Nat.cast_npow (R : Type*) [NonAssocSemiring R] [Pow R ℕ] [NatPowAssoc R] (n m : ℕ) : (↑(n ^ m) : R) = (↑n : R) ^ m := by - induction' m with m ih - · simp only [pow_zero, Nat.cast_one, npow_zero] - · rw [npow_add, npow_add, Nat.cast_mul, ih, npow_one, npow_one] + induction m with + | zero => simp only [pow_zero, Nat.cast_one, npow_zero] + | succ m ih => rw [npow_add, npow_add, Nat.cast_mul, ih, npow_one, npow_one] @[simp, norm_cast] theorem Int.cast_npow (R : Type*) [NonAssocRing R] [Pow R ℕ] [NatPowAssoc R] diff --git a/Mathlib/Algebra/Group/Opposite.lean b/Mathlib/Algebra/Group/Opposite.lean index 1f1389337c3a4..a66f4838ff8fd 100644 --- a/Mathlib/Algebra/Group/Opposite.lean +++ b/Mathlib/Algebra/Group/Opposite.lean @@ -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,11 +161,10 @@ 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' _ _ -@[to_additive AddOpposite.instSubtractionMonoid] +@[to_additive] instance instDivisionMonoid [DivisionMonoid α] : DivisionMonoid αᵐᵒᵖ where toDivInvMonoid := instDivInvMonoid __ := instInvolutiveInv diff --git a/Mathlib/Algebra/Group/Pi/Basic.lean b/Mathlib/Algebra/Group/Pi/Basic.lean index 92f9824806c5f..7a88ae8220a12 100644 --- a/Mathlib/Algebra/Group/Pi/Basic.lean +++ b/Mathlib/Algebra/Group/Pi/Basic.lean @@ -193,7 +193,7 @@ instance divInvMonoid [∀ i, DivInvMonoid (f i)] : DivInvMonoid (∀ i, f i) wh zpow_succ' := by intros; ext; exact DivInvMonoid.zpow_succ' _ _ zpow_neg' := by intros; ext; exact DivInvMonoid.zpow_neg' _ _ -@[to_additive Pi.subNegZeroMonoid] +@[to_additive] instance divInvOneMonoid [∀ i, DivInvOneMonoid (f i)] : DivInvOneMonoid (∀ i, f i) where inv_one := by ext; exact inv_one @@ -201,7 +201,7 @@ instance divInvOneMonoid [∀ i, DivInvOneMonoid (f i)] : DivInvOneMonoid (∀ i instance involutiveInv [∀ i, InvolutiveInv (f i)] : InvolutiveInv (∀ i, f i) where inv_inv := by intros; ext; exact inv_inv _ -@[to_additive Pi.subtractionMonoid] +@[to_additive] instance divisionMonoid [∀ i, DivisionMonoid (f i)] : DivisionMonoid (∀ i, f i) where __ := divInvMonoid __ := involutiveInv @@ -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..672442bbd487d 100644 --- a/Mathlib/Algebra/Group/Pi/Lemmas.lean +++ b/Mathlib/Algebra/Group/Pi/Lemmas.lean @@ -38,6 +38,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] @@ -239,6 +248,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. diff --git a/Mathlib/Data/Finset/Pointwise/Basic.lean b/Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean similarity index 95% rename from Mathlib/Data/Finset/Pointwise/Basic.lean rename to Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean index a20237588d38e..5e5ebeefca3c2 100644 --- a/Mathlib/Data/Finset/Pointwise/Basic.lean +++ b/Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean @@ -3,15 +3,15 @@ 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.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.Finset.Preimage import Mathlib.Data.Set.Pointwise.Finite -import Mathlib.Data.Set.Pointwise.SMul import Mathlib.Data.Set.Pointwise.ListOfFn -import Mathlib.Data.ULift -import Mathlib.Algebra.BigOperators.Group.Finset -import Mathlib.Algebra.Order.Ring.Nat +import Mathlib.Data.Set.Pointwise.SMul /-! # Pointwise operations of finsets @@ -210,17 +210,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 @@ -271,6 +272,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] @@ -341,11 +345,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₂ @@ -369,7 +373,7 @@ theorem singleton_mul (a : α) : {a} * s = s.image (a * ·) := 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 @@ -416,7 +420,7 @@ 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 := @@ -525,11 +529,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₂ @@ -555,7 +559,7 @@ theorem singleton_div (a : α) : {a} / s = s.image (a / ·) := 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 @@ -602,7 +606,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 : β} : @@ -772,10 +776,9 @@ scoped[Pointwise] attribute [instance] Finset.monoid Finset.addMonoid @[to_additive] theorem pow_mem_pow (ha : a ∈ s) : ∀ n : ℕ, a ^ n ∈ s ^ n | 0 => by - rw [pow_zero] - exact one_mem_one + simp only [pow_zero, mem_one] | n + 1 => by - rw [pow_succ] + simp only [pow_succ] exact mul_mem_mul (pow_mem_pow ha n) ha @[to_additive] @@ -873,7 +876,7 @@ protected theorem mul_eq_one_iff : s * t = 1 ↔ ∃ a b, s = {a} ∧ t = {b} simp_rw [← coe_inj, coe_mul, coe_one, Set.mul_eq_one_iff, coe_singleton] /-- `Finset α` is a division monoid under pointwise operations if `α` is. -/ -@[to_additive subtractionMonoid +@[to_additive "`Finset α` is a subtraction monoid under pointwise operations if `α` is."] protected def divisionMonoid : DivisionMonoid (Finset α) := coe_injective.divisionMonoid _ coe_one coe_mul coe_inv coe_div coe_pow coe_zpow @@ -898,6 +901,12 @@ 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 + end DivisionMonoid /-- `Finset α` is a commutative division monoid under pointwise operations if `α` is. -/ @@ -990,12 +999,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 : @@ -1120,11 +1129,11 @@ theorem smul_empty (s : Finset α) : s • (∅ : Finset β) = ∅ := theorem smul_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 smul_nonempty_iff : (s • t).Nonempty ↔ s.Nonempty ∧ t.Nonempty := image₂_nonempty_iff -@[to_additive] +@[to_additive (attr := aesop safe apply (rule_sets := [finsetNonempty]))] theorem Nonempty.smul : s.Nonempty → t.Nonempty → (s • t).Nonempty := Nonempty.image₂ @@ -1144,7 +1153,7 @@ theorem smul_singleton (b : β) : s • ({b} : Finset β) = s.image (· • b) : theorem singleton_smul_singleton (a : α) (b : β) : ({a} : Finset α) • ({b} : Finset β) = {a • b} := image₂_singleton -@[to_additive (attr := mono)] +@[to_additive (attr := mono, gcongr)] theorem smul_subset_smul : s₁ ⊆ s₂ → t₁ ⊆ t₂ → s₁ • t₁ ⊆ s₂ • t₂ := image₂_subset @@ -1191,7 +1200,7 @@ theorem union_smul_inter_subset_union [DecidableEq α] : (s₁ ∪ s₂) • (t 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₂ + subset_set_image₂ end SMul @@ -1241,10 +1250,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₂ @@ -1265,7 +1275,7 @@ theorem singleton_vsub (a : β) : ({a} : Finset β) -ᵥ t = t.image (a -ᵥ ·) 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 @@ -1300,7 +1310,7 @@ 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 @@ -1352,11 +1362,11 @@ theorem smul_finset_empty (a : α) : a • (∅ : Finset β) = ∅ := theorem smul_finset_eq_empty : a • s = ∅ ↔ s = ∅ := image_eq_empty -@[to_additive (attr := simp, aesop safe apply (rule_sets := [finsetNonempty]))] +@[to_additive (attr := simp)] theorem smul_finset_nonempty : (a • s).Nonempty ↔ s.Nonempty := image_nonempty -@[to_additive] +@[to_additive (attr := aesop safe apply (rule_sets := [finsetNonempty]))] theorem Nonempty.smul_finset (hs : s.Nonempty) : (a • s).Nonempty := hs.image _ @@ -1364,7 +1374,7 @@ theorem Nonempty.smul_finset (hs : s.Nonempty) : (a • s).Nonempty := theorem singleton_smul (a : α) : ({a} : Finset α) • t = a • t := image₂_singleton_left -@[to_additive (attr := mono)] +@[to_additive (attr := mono, gcongr)] theorem smul_finset_subset_smul_finset : s ⊆ t → a • s ⊆ a • t := image_subset_image @@ -1376,6 +1386,10 @@ theorem smul_finset_singleton (b : β) : a • ({b} : Finset β) = {a • b} := theorem smul_finset_union : a • (s₁ ∪ s₂) = a • s₁ ∪ a • s₂ := image_union _ _ +@[to_additive] +lemma smul_finset_insert (a : α) (b : β) (s : Finset β) : a • insert b s = insert (a • b) (a • s) := + image_insert .. + @[to_additive] theorem smul_finset_inter_subset : a • (s₁ ∩ s₂) ⊆ a • s₁ ∩ a • s₂ := image_inter_subset _ _ _ @@ -1420,7 +1434,7 @@ instance smulCommClass [SMul α γ] [SMul β γ] [SMulCommClass α β γ] : @[to_additive vaddAssocClass] instance isScalarTower [SMul α β] [SMul α γ] [SMul β γ] [IsScalarTower α β γ] : IsScalarTower α β (Finset γ) := - ⟨fun a b s => by simp only [← image_smul, image_image, smul_assoc, Function.comp]⟩ + ⟨fun a b s => by simp only [← image_smul, image_image, smul_assoc, Function.comp_def]⟩ variable [DecidableEq β] @@ -1572,6 +1586,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 @@ -1590,6 +1615,17 @@ 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 Group @@ -1601,6 +1637,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 @@ -1674,6 +1713,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 @@ -1828,7 +1870,7 @@ variable [Monoid α] [AddGroup β] [DistribMulAction α β] [DecidableEq β] (a @[simp] theorem smul_finset_neg : a • -t = -(a • t) := by - simp only [← image_smul, ← image_neg, Function.comp, image_image, smul_neg] + simp only [← image_smul, ← image_neg, Function.comp_def, image_image, smul_neg] @[simp] protected theorem smul_neg : s • -t = -(s • t) := by @@ -1844,7 +1886,7 @@ variable [Ring α] [AddCommGroup β] [Module α β] [DecidableEq β] {s : Finset @[simp] theorem neg_smul_finset : -a • t = -(a • t) := by - simp only [← image_smul, ← image_neg, image_image, neg_smul, Function.comp] + simp only [← image_smul, ← image_neg, image_image, neg_smul, Function.comp_def] @[simp] protected theorem neg_smul [DecidableEq α] : -s • t = -(s • t) := by @@ -1913,6 +1955,10 @@ namespace Set section One +-- Redeclaring an instance for better keys +@[to_additive] +instance instFintypeOne [One α] : Fintype (1 : Set α) := Set.fintypeSingleton _ + variable [One α] @[to_additive (attr := simp)] @@ -1995,3 +2041,5 @@ instance Nat.decidablePred_mem_vadd_set {s : Set ℕ} [DecidablePred (· ∈ s)] DecidablePred (· ∈ a +ᵥ 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 diff --git a/Mathlib/Data/Finset/Pointwise/Interval.lean b/Mathlib/Algebra/Group/Pointwise/Finset/Interval.lean similarity index 98% rename from Mathlib/Data/Finset/Pointwise/Interval.lean rename to Mathlib/Algebra/Group/Pointwise/Finset/Interval.lean index 9178e9e993251..fd9cc57c0dd5b 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 diff --git a/Mathlib/Data/Set/Pointwise/Basic.lean b/Mathlib/Algebra/Group/Pointwise/Set/Basic.lean similarity index 65% rename from Mathlib/Data/Set/Pointwise/Basic.lean rename to Mathlib/Algebra/Group/Pointwise/Set/Basic.lean index bc6cb8dcea2ee..bb8aba1b06f3a 100644 --- a/Mathlib/Data/Set/Pointwise/Basic.lean +++ b/Mathlib/Algebra/Group/Pointwise/Set/Basic.lean @@ -6,10 +6,7 @@ Authors: Johan Commelin, Floris van Doorn import Mathlib.Algebra.Group.Equiv.Basic import Mathlib.Algebra.Group.Units.Hom import Mathlib.Algebra.Opposites -import Mathlib.Algebra.Ring.Defs -import Mathlib.Algebra.GroupWithZero.Basic import Mathlib.Data.Set.Lattice -import Mathlib.Tactic.Common /-! # Pointwise operations of sets @@ -25,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 @@ -50,7 +52,7 @@ set multiplication, set addition, pointwise addition, pointwise multiplication, pointwise subtraction -/ - +assert_not_exists MonoidWithZero assert_not_exists OrderedAddCommMonoid library_note "pointwise nat action"/-- @@ -179,10 +181,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 @@ -234,7 +244,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 @@ -322,7 +332,7 @@ theorem singleton_mul : {a} * t = (a * ·) '' t := 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 @@ -372,47 +382,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`."] @@ -510,7 +536,7 @@ theorem singleton_div : {a} / t = (· / ·) a '' t := 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 @@ -560,50 +586,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 @@ -707,10 +1073,9 @@ scoped[Pointwise] attribute [instance] Set.monoid Set.addMonoid @[to_additive] theorem pow_mem_pow (ha : a ∈ s) : ∀ n : ℕ, a ^ n ∈ s ^ n | 0 => by - rw [pow_zero] - exact one_mem_one + simp only [pow_zero, mem_one] | n + 1 => by - rw [pow_succ] + simp only [pow_succ] exact mul_mem_mul (pow_mem_pow ha _) ha @[to_additive] @@ -726,9 +1091,10 @@ theorem pow_subset_pow (hst : s ⊆ t) : ∀ n : ℕ, s ^ n ⊆ t ^ n theorem pow_subset_pow_of_one_mem (hs : (1 : α) ∈ s) (hn : m ≤ n) : s ^ m ⊆ s ^ n := by -- Porting note: `Nat.le_induction` didn't work as an induction principle in mathlib3, this was -- `refine Nat.le_induction ...` - induction' n, hn using Nat.le_induction with _ _ ih - · exact Subset.rfl - · dsimp only + induction n, hn using Nat.le_induction with + | base => exact Subset.rfl + | succ _ _ ih => + dsimp only rw [pow_succ'] exact ih.trans (subset_mul_right _ hs) @@ -749,14 +1115,7 @@ theorem univ_mul_of_one_mem (ht : (1 : α) ∈ t) : univ * t = univ := theorem univ_mul_univ : (univ : Set α) * univ = univ := mul_univ_of_one_mem <| mem_univ _ ---TODO: `to_additive` trips up on the `1 : ℕ` used in the pattern-matching. -@[simp] -theorem nsmul_univ {α : Type*} [AddMonoid α] : ∀ {n : ℕ}, n ≠ 0 → n • (univ : Set α) = univ - | 0 => fun h => (h rfl).elim - | 1 => fun _ => one_nsmul _ - | n + 2 => fun _ => by rw [succ_nsmul, nsmul_univ n.succ_ne_zero, univ_add_univ] - -@[to_additive existing (attr := simp) nsmul_univ] +@[to_additive (attr := simp) nsmul_univ] theorem univ_pow : ∀ {n : ℕ}, n ≠ 0 → (univ : Set α) ^ n = univ | 0 => fun h => (h rfl).elim | 1 => fun _ => pow_one _ @@ -796,7 +1155,7 @@ protected theorem mul_eq_one_iff : s * t = 1 ↔ ∃ a b, s = {a} ∧ t = {b} rw [singleton_mul_singleton, h, singleton_one] /-- `Set α` is a division monoid under pointwise operations if `α` is. -/ -@[to_additive subtractionMonoid +@[to_additive "`Set α` is a subtraction monoid under pointwise operations if `α` is."] protected noncomputable def divisionMonoid : DivisionMonoid (Set α) := { Set.monoid, Set.involutiveInv, Set.div, @Set.ZPow α _ _ _ with @@ -826,6 +1185,12 @@ 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 + end DivisionMonoid /-- `Set α` is a commutative division monoid under pointwise operations if `α` is. -/ @@ -835,55 +1200,7 @@ protected noncomputable def divisionCommMonoid [DivisionCommMonoid α] : DivisionCommMonoid (Set α) := { Set.divisionMonoid, Set.commSemigroup with } -/-- `Set α` has distributive negation if `α` has. -/ -protected noncomputable def hasDistribNeg [Mul α] [HasDistribNeg α] : HasDistribNeg (Set α) := - { Set.involutiveNeg with - neg_mul := fun _ _ => by - simp_rw [← image_neg] - exact image2_image_left_comm neg_mul - mul_neg := fun _ _ => by - simp_rw [← image_neg] - exact image_image2_right_comm mul_neg } - -scoped[Pointwise] - attribute [instance] Set.divisionCommMonoid Set.subtractionCommMonoid Set.hasDistribNeg - -section Distrib - -variable [Distrib α] (s t u : Set α) - -/-! -Note that `Set α` is not a `Distrib` because `s * t + s * u` has cross terms that `s * (t + u)` -lacks. --/ - - -theorem mul_add_subset : s * (t + u) ⊆ s * t + s * u := - image2_distrib_subset_left mul_add - -theorem add_mul_subset : (s + t) * u ⊆ s * u + t * u := - image2_distrib_subset_right add_mul - -end Distrib - -section MulZeroClass - -variable [MulZeroClass α] {s t : Set α} - -/-! Note that `Set` is not a `MulZeroClass` because `0 * ∅ ≠ 0`. -/ - - -theorem mul_zero_subset (s : Set α) : s * 0 ⊆ 0 := by simp [subset_def, mem_mul] - -theorem zero_mul_subset (s : Set α) : 0 * s ⊆ 0 := by simp [subset_def, 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] Set.divisionCommMonoid Set.subtractionCommMonoid section Group @@ -915,7 +1232,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 @@ -956,31 +1273,15 @@ 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 -section GroupWithZero - -variable [GroupWithZero α] {s t : Set α} - -theorem div_zero_subset (s : Set α) : s / 0 ⊆ 0 := by simp [subset_def, mem_div] - -theorem zero_div_subset (s : Set α) : 0 / s ⊆ 0 := by simp [subset_def, 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 - section Mul variable [Mul α] [Mul β] [FunLike F α β] [MulHomClass F α β] (m : F) {s t : Set α} @@ -994,12 +1295,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) : @@ -1023,12 +1324,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/Data/Finset/Pointwise/Card.lean b/Mathlib/Algebra/Group/Pointwise/Set/Card.lean similarity index 96% rename from Mathlib/Data/Finset/Pointwise/Card.lean rename to Mathlib/Algebra/Group/Pointwise/Set/Card.lean index 5516539f11c50..341ed441df932 100644 --- a/Mathlib/Data/Finset/Pointwise/Card.lean +++ b/Mathlib/Algebra/Group/Pointwise/Set/Card.lean @@ -3,7 +3,7 @@ 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.Algebra.Group.Pointwise.Finset.Basic import Mathlib.SetTheory.Cardinal.Finite /-! diff --git a/Mathlib/Algebra/Group/Prod.lean b/Mathlib/Algebra/Group/Prod.lean index d1a779b29708d..d7cb9b0f80a16 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 @@ -89,6 +89,9 @@ theorem snd_one [One M] [One N] : (1 : M × N).2 = 1 := theorem one_eq_mk [One M] [One N] : (1 : M × N) = (1, 1) := rfl +@[to_additive (attr := simp)] +theorem mk_one_one [One M] [One N] : ((1 : M), (1 : N)) = 1 := rfl + @[to_additive (attr := simp)] theorem mk_eq_one [One M] [One N] {x : M} {y : N} : (x, y) = 1 ↔ x = 1 ∧ y = 1 := mk.inj_iff @@ -215,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) := @@ -232,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) := diff --git a/Mathlib/Algebra/Group/Semiconj/Defs.lean b/Mathlib/Algebra/Group/Semiconj/Defs.lean index bae3512e418c7..cfeabeb0d12db 100644 --- a/Mathlib/Algebra/Group/Semiconj/Defs.lean +++ b/Mathlib/Algebra/Group/Semiconj/Defs.lean @@ -2,12 +2,11 @@ Copyright (c) 2019 Yury Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov - -Some proofs and docs came from `Algebra/Commute` (c) Neil Strickland -/ +-- 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.Tactic.Cases +import Mathlib.Order.Defs /-! # Semiconjugate elements of a semigroup @@ -116,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 142307a0a9682..5a31a5e5130e9 100644 --- a/Mathlib/Algebra/Group/Semiconj/Units.lean +++ b/Mathlib/Algebra/Group/Semiconj/Units.lean @@ -2,9 +2,9 @@ Copyright (c) 2019 Yury Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov - -Some proofs and docs came from `Algebra/Commute` (c) Neil Strickland -/ +-- 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 @@ -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 c307e84d8c382..556df038ddca9 100644 --- a/Mathlib/Algebra/Group/Subgroup/Basic.lean +++ b/Mathlib/Algebra/Group/Subgroup/Basic.lean @@ -69,7 +69,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 @@ -86,7 +86,7 @@ assert_not_exists Multiset assert_not_exists Ring open Function -open Int +open scoped Int variable {G G' G'' : Type*} [Group G] [Group G'] [Group G''] variable {A : Type*} [AddGroup A] @@ -94,27 +94,27 @@ 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 +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 G : Type*) [Neg G] [SetLike S G] : Prop where +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 G : Type*) [DivInvMonoid G] [SetLike S G] extends SubmonoidClass S G, - InvMemClass S G : Prop +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 G : Type*) [SubNegMonoid G] [SetLike S G] extends AddSubmonoidClass S G, - NegMemClass S G : Prop +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 @@ -583,8 +583,8 @@ theorem coe_pow (x : H) (n : ℕ) : ((x ^ n : H) : G) = (x : G) ^ n := theorem coe_zpow (x : H) (n : ℤ) : ((x ^ n : H) : G) = (x : G) ^ n := rfl -@[to_additive] -- This can be proved by `Submonoid.mk_eq_one` -theorem mk_eq_one {g : G} {h} : (⟨g, h⟩ : H) = 1 ↔ g = 1 := by simp +@[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."] @@ -877,16 +877,22 @@ theorem closure_eq_of_le (h₁ : k ⊆ K) (h₂ : K ≤ closure k) : closure k = /-- An induction principle for closure membership. If `p` holds for `1` and all elements of `k`, and is preserved under multiplication and inverse, then `p` holds for all elements of the closure -of `k`. -/ +of `k`. + +See also `Subgroup.closure_induction_left` and `Subgroup.closure_induction_right` for versions that +only require showing `p` is preserved by multiplication by elements in `k`. -/ @[to_additive (attr := elab_as_elim) "An induction principle for additive closure membership. If `p` holds for `0` and all elements of `k`, and is preserved under addition and inverses, then `p` - holds for all elements of the additive closure of `k`."] + holds for all elements of the additive closure of `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`. -/ +/-- 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 _)) @@ -1014,6 +1020,10 @@ theorem mem_closure_singleton {x y : G} : y ∈ closure ({x} : Set G) ↔ ∃ n theorem closure_singleton_one : closure ({1} : Set G) = ⊥ := by simp [eq_bot_iff_forall, mem_closure_singleton] +@[to_additive (attr := simp)] +lemma mem_closure_singleton_self (x : G) : x ∈ closure ({x} : Set G) := by + simpa [-subset_closure] using subset_closure (k := {x}) + @[to_additive] theorem le_closure_toSubmonoid (S : Set G) : Submonoid.closure S ≤ (closure S).toSubmonoid := Submonoid.closure_le.2 subset_closure @@ -1070,7 +1080,7 @@ theorem toAddSubgroup_comap {G₂ : Type*} [Group G₂] (f : G →* G₂) (s : S @[simp] theorem _root_.AddSubgroup.toSubgroup_comap {A A₂ : Type*} [AddGroup A] [AddGroup A₂] - (f : A →+ A₂) (s : AddSubgroup A₂) : + (f : A →+ A₂) (s : AddSubgroup A₂) : s.toSubgroup.comap (AddMonoidHom.toMultiplicative f) = AddSubgroup.toSubgroup (s.comap f) := rfl @[to_additive (attr := simp)] @@ -1195,6 +1205,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) := @@ -1360,7 +1380,7 @@ theorem top_prod_top : (⊤ : Subgroup G).prod (⊤ : Subgroup N) = ⊤ := @[to_additive] theorem bot_prod_bot : (⊥ : Subgroup G).prod (⊥ : Subgroup N) = ⊥ := - SetLike.coe_injective <| by simp [coe_prod, Prod.one_eq_mk] + SetLike.coe_injective <| by simp [coe_prod] @[to_additive le_prod_iff] theorem le_prod_iff {H : Subgroup G} {K : Subgroup N} {J : Subgroup (G × N)} : @@ -1703,11 +1723,11 @@ def _root_.NormalizerCondition := variable {G} /-- Alternative phrasing of the normalizer condition: Only the full group is self-normalizing. -This may be easier to work with, as it avoids inequalities and negations. -/ +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) @@ -1764,7 +1784,7 @@ instance subgroupOf_isCommutative [H.IsCommutative] : (H.subgroupOf K).IsCommuta @[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 [Submonoid.mk_mul_mk, Subtype.mk.injEq] using mul_comm (⟨a, ha⟩ : H) (⟨b, hb⟩ : H) + simpa only [MulMemClass.mk_mul_mk, Subtype.mk.injEq] using mul_comm (⟨a, ha⟩ : H) (⟨b, hb⟩ : H) end Subgroup @@ -2114,10 +2134,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 @@ -2131,7 +2155,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 => @@ -2202,13 +2226,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') : @@ -2370,7 +2394,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} : @@ -2575,7 +2599,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] @@ -2906,3 +2930,5 @@ def noncenter (G : Type*) [Monoid G] : Set (ConjClasses G) := g ∈ noncenter G ↔ g.carrier.Nontrivial := Iff.rfl end ConjClasses + +set_option linter.style.longFile 3000 diff --git a/Mathlib/Algebra/Group/Subgroup/Finite.lean b/Mathlib/Algebra/Group/Subgroup/Finite.lean index 14f53f72374fd..6e5342a357f4e 100644 --- a/Mathlib/Algebra/Group/Subgroup/Finite.lean +++ b/Mathlib/Algebra/Group/Subgroup/Finite.lean @@ -102,26 +102,24 @@ theorem card_top : Nat.card (⊤ : Subgroup G) = Nat.card G := Nat.card_congr Subgroup.topEquiv.toEquiv @[to_additive] -theorem eq_top_of_card_eq [Finite H] (h : Nat.card H = Nat.card G) : - H = ⊤ := by - have : Nonempty H := ⟨1, one_mem H⟩ - have h' : Nat.card H ≠ 0 := Nat.card_pos.ne' - have : Finite G := (Nat.finite_of_card_ne_zero (h ▸ h')) - have : Fintype G := Fintype.ofFinite G - have : Fintype H := Fintype.ofFinite H - rw [Nat.card_eq_fintype_card, Nat.card_eq_fintype_card] at h - rw [SetLike.ext'_iff, coe_top, ← Finset.coe_univ, ← (H : Set G).coe_toFinset, Finset.coe_inj, ← - Finset.card_eq_iff_eq_univ, ← h, Set.toFinset_card] - congr +theorem eq_of_le_of_card_ge {H K : Subgroup G} [Finite K] (hle : H ≤ K) + (hcard : Nat.card K ≤ Nat.card H) : + H = K := + SetLike.coe_injective <| Set.Finite.eq_of_subset_of_card_le (Set.toFinite _) hle hcard + +@[to_additive] +theorem eq_top_of_le_card [Finite G] (h : Nat.card G ≤ Nat.card H) : H = ⊤ := + eq_of_le_of_card_ge le_top (Nat.card_congr (Equiv.Set.univ G) ▸ h) + +@[to_additive] +theorem eq_top_of_card_eq [Finite H] (h : Nat.card H = Nat.card G) : H = ⊤ := by + have : Finite G := Nat.finite_of_card_ne_zero (h ▸ Nat.card_pos.ne') + exact eq_top_of_le_card _ (Nat.le_of_eq h.symm) @[to_additive (attr := simp)] theorem card_eq_iff_eq_top [Finite H] : Nat.card H = Nat.card G ↔ H = ⊤ := Iff.intro (eq_top_of_card_eq H) (fun h ↦ by simpa only [h] using card_top) -@[to_additive] -theorem eq_top_of_le_card [Finite G] (h : Nat.card G ≤ Nat.card H) : H = ⊤ := - eq_top_of_card_eq H (le_antisymm (Nat.card_le_card_of_injective H.subtype H.subtype_injective) h) - @[to_additive] theorem eq_bot_of_card_le [Finite H] (h : Nat.card H ≤ 1) : H = ⊥ := let _ := Finite.card_le_one_iff_subsingleton.mp h @@ -147,6 +145,10 @@ theorem one_lt_card_iff_ne_bot [Finite H] : 1 < Nat.card H ↔ H ≠ ⊥ := theorem card_le_card_group [Finite G] : Nat.card H ≤ Nat.card G := Nat.card_le_card_of_injective _ Subtype.coe_injective +@[to_additive] +theorem card_le_of_le {H K : Subgroup G} [Finite K] (h : H ≤ K) : Nat.card H ≤ Nat.card K := + Nat.card_le_card_of_injective _ (Subgroup.inclusion_injective h) + end Subgroup namespace Subgroup @@ -161,11 +163,16 @@ variable {η : Type*} {f : η → Type*} [∀ i, Group (f i)] theorem pi_mem_of_mulSingle_mem_aux [DecidableEq η] (I : Finset η) {H : Subgroup (∀ i, f i)} (x : ∀ i, f i) (h1 : ∀ i, i ∉ I → x i = 1) (h2 : ∀ i, i ∈ I → Pi.mulSingle i (x i) ∈ H) : x ∈ H := by - induction' I using Finset.induction_on with i I hnmem ih generalizing x - · convert one_mem H - ext i - exact h1 i (Finset.not_mem_empty i) - · have : x = Function.update x i 1 * Pi.mulSingle i (x i) := by + induction I using Finset.induction_on generalizing x with + | empty => + 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 ext j by_cases heq : j = i · subst heq @@ -195,7 +202,7 @@ theorem pi_mem_of_mulSingle_mem [Finite η] [DecidableEq η] {H : Subgroup (∀ cases nonempty_fintype η exact pi_mem_of_mulSingle_mem_aux Finset.univ x (by simp) fun i _ => h i -/-- For finite index types, the `Subgroup.pi` is generated by the embeddings of the groups. -/ +/-- For finite index types, the `Subgroup.pi` is generated by the embeddings of the groups. -/ @[to_additive "For finite index types, the `Subgroup.pi` is generated by the embeddings of the additive groups."] theorem pi_le_iff [DecidableEq η] [Finite η] {H : ∀ i, Subgroup (f i)} {J : Subgroup (∀ i, f i)} : diff --git a/Mathlib/Algebra/Group/Subgroup/MulOpposite.lean b/Mathlib/Algebra/Group/Subgroup/MulOpposite.lean index a7a48a1eb4d46..296424c376749 100644 --- a/Mathlib/Algebra/Group/Subgroup/MulOpposite.lean +++ b/Mathlib/Algebra/Group/Subgroup/MulOpposite.lean @@ -15,7 +15,6 @@ subgroup, subgroups -/ - variable {ι : Sort*} {G : Type*} [Group G] namespace Subgroup @@ -29,6 +28,13 @@ protected def op (H : Subgroup G) : Subgroup Gᵐᵒᵖ where mul_mem' ha hb := H.mul_mem hb ha inv_mem' := H.inv_mem +/- We redeclare this instance to get keys +`SMul (@Subtype (MulOpposite _) (@Membership.mem (MulOpposite _) + (Subgroup (MulOpposite _) _) _ (@Subgroup.op _ _ _))) _` +compared to the keys for `Submonoid.smul` +`SMul (@Subtype _ (@Membership.mem _ (Submonoid _ _) _ _)) _` -/ +@[to_additive] instance instSMul (H : Subgroup G) : SMul H.op G := Submonoid.smul .. + @[to_additive (attr := simp)] theorem mem_op {x : Gᵐᵒᵖ} {S : Subgroup G} : x ∈ S.op ↔ x.unop ∈ S := Iff.rfl @@ -86,17 +92,41 @@ def opEquiv : Subgroup G ≃o Subgroup Gᵐᵒᵖ where right_inv := op_unop map_rel_iff' := op_le_op_iff +@[to_additive] +theorem op_injective : (@Subgroup.op G _).Injective := opEquiv.injective + +@[to_additive] +theorem unop_injective : (@Subgroup.unop G _).Injective := opEquiv.symm.injective + +@[to_additive (attr := simp)] +theorem op_inj {S T : Subgroup G} : S.op = T.op ↔ S = T := opEquiv.eq_iff_eq + +@[to_additive (attr := simp)] +theorem unop_inj {S T : Subgroup Gᵐᵒᵖ} : S.unop = T.unop ↔ S = T := opEquiv.symm.eq_iff_eq + @[to_additive (attr := simp)] theorem op_bot : (⊥ : Subgroup G).op = ⊥ := opEquiv.map_bot +@[to_additive (attr := simp)] +theorem op_eq_bot {S : Subgroup G} : S.op = ⊥ ↔ S = ⊥ := op_injective.eq_iff' op_bot + @[to_additive (attr := simp)] theorem unop_bot : (⊥ : Subgroup Gᵐᵒᵖ).unop = ⊥ := opEquiv.symm.map_bot @[to_additive (attr := simp)] -theorem op_top : (⊤ : Subgroup G).op = ⊤ := opEquiv.map_top +theorem unop_eq_bot {S : Subgroup Gᵐᵒᵖ} : S.unop = ⊥ ↔ S = ⊥ := unop_injective.eq_iff' unop_bot + +@[to_additive (attr := simp)] +theorem op_top : (⊤ : Subgroup G).op = ⊤ := rfl + +@[to_additive (attr := simp)] +theorem op_eq_top {S : Subgroup G} : S.op = ⊤ ↔ S = ⊤ := op_injective.eq_iff' op_top @[to_additive (attr := simp)] -theorem unop_top : (⊤ : Subgroup Gᵐᵒᵖ).unop = ⊤ := opEquiv.symm.map_top +theorem unop_top : (⊤ : Subgroup Gᵐᵒᵖ).unop = ⊤ := rfl + +@[to_additive (attr := simp)] +theorem unop_eq_top {S : Subgroup Gᵐᵒᵖ} : S.unop = ⊤ ↔ S = ⊤ := unop_injective.eq_iff' unop_top @[to_additive] theorem op_sup (S₁ S₂ : Subgroup G) : (S₁ ⊔ S₂).op = S₁.op ⊔ S₂.op := @@ -107,11 +137,10 @@ theorem unop_sup (S₁ S₂ : Subgroup Gᵐᵒᵖ) : (S₁ ⊔ S₂).unop = S₁ opEquiv.symm.map_sup _ _ @[to_additive] -theorem op_inf (S₁ S₂ : Subgroup G) : (S₁ ⊓ S₂).op = S₁.op ⊓ S₂.op := opEquiv.map_inf _ _ +theorem op_inf (S₁ S₂ : Subgroup G) : (S₁ ⊓ S₂).op = S₁.op ⊓ S₂.op := rfl @[to_additive] -theorem unop_inf (S₁ S₂ : Subgroup Gᵐᵒᵖ) : (S₁ ⊓ S₂).unop = S₁.unop ⊓ S₂.unop := - opEquiv.symm.map_inf _ _ +theorem unop_inf (S₁ S₂ : Subgroup Gᵐᵒᵖ) : (S₁ ⊓ S₂).unop = S₁.unop ⊓ S₂.unop := rfl @[to_additive] theorem op_sSup (S : Set (Subgroup G)) : (sSup S).op = sSup (.unop ⁻¹' S) := @@ -151,9 +180,8 @@ 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 - simp_rw [closure, unop_sInf, Set.preimage_setOf_eq, Subgroup.op_coe] - congr with a - exact MulOpposite.op_surjective.forall + rw [← op_inj, op_unop, op_closure] + 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."] @@ -173,4 +201,31 @@ theorem smul_opposite_mul {H : Subgroup G} (x g : G) (h : H.op) : h • (g * x) = g * h • x := mul_assoc _ _ _ +@[to_additive] +theorem op_normalizer (H : Subgroup G) : H.normalizer.op = H.op.normalizer := by + ext x + simp [mem_normalizer_iff', MulOpposite.op_surjective.forall, iff_comm] + +@[to_additive] +theorem unop_normalizer (H : Subgroup Gᵐᵒᵖ) : H.normalizer.unop = H.unop.normalizer := by + rw [← op_inj, op_unop, op_normalizer, op_unop] + +@[to_additive (attr := simp)] +theorem normal_op {H : Subgroup G} : H.op.Normal ↔ H.Normal := by + simp only [← normalizer_eq_top, ← op_normalizer, op_eq_top] + +@[to_additive] alias ⟨Normal.of_op, Normal.op⟩ := normal_op + +@[to_additive] +instance op.instNormal {H : Subgroup G} [H.Normal] : H.op.Normal := .op ‹_› + +@[to_additive (attr := simp)] +theorem normal_unop {H : Subgroup Gᵐᵒᵖ} : H.unop.Normal ↔ H.Normal := by + rw [← normal_op, op_unop] + +@[to_additive] alias ⟨Normal.of_unop, Normal.unop⟩ := normal_unop + +@[to_additive] +instance unop.instNormal {H : Subgroup Gᵐᵒᵖ} [H.Normal] : H.unop.Normal := .unop ‹_› + end Subgroup diff --git a/Mathlib/Algebra/Group/Subgroup/Order.lean b/Mathlib/Algebra/Group/Subgroup/Order.lean index 36a107b58fb58..7e9cd2eefee49 100644 --- a/Mathlib/Algebra/Group/Subgroup/Order.lean +++ b/Mathlib/Algebra/Group/Subgroup/Order.lean @@ -14,13 +14,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) := @@ -110,3 +111,17 @@ instance toLinearOrderedCommGroup [LinearOrderedCommGroup G] (H : Subgroup G) : (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) fun _ _ => rfl end Subgroup + +@[to_additive] +lemma Subsemigroup.strictMono_topEquiv {G : Type*} [OrderedCommMonoid G] : + StrictMono (topEquiv (M := G)) := fun _ _ ↦ id + +@[to_additive] +lemma MulEquiv.strictMono_subsemigroupCongr {G : Type*} [OrderedCommMonoid G] {S T : Subsemigroup G} + (h : S = T) : StrictMono (subsemigroupCongr h) := fun _ _ ↦ id + +@[to_additive] +lemma MulEquiv.strictMono_symm {G G' : Type*} [LinearOrderedCommMonoid G] + [LinearOrderedCommMonoid G'] {e : G ≃* G'} (he : StrictMono e) : StrictMono e.symm := by + intro + simp [← he.lt_iff_lt] diff --git a/Mathlib/Algebra/Group/Subgroup/Pointwise.lean b/Mathlib/Algebra/Group/Subgroup/Pointwise.lean index 71e4f17ffc5ea..99bb82ddad9cc 100644 --- a/Mathlib/Algebra/Group/Subgroup/Pointwise.lean +++ b/Mathlib/Algebra/Group/Subgroup/Pointwise.lean @@ -72,7 +72,7 @@ theorem closure_toSubmonoid (S : Set G) : (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 => ?_ 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) @@ -113,6 +113,10 @@ theorem closure_induction_right {p : (x : G) → x ∈ closure s → Prop} (one theorem closure_inv (s : Set G) : closure s⁻¹ = closure s := by simp only [← toSubmonoid_eq, closure_toSubmonoid, inv_inv, union_comm] +@[to_additive (attr := simp)] +lemma closure_singleton_inv (x : G) : closure {x⁻¹} = closure {x} := by + rw [← Set.inv_singleton, closure_inv] + /-- An induction principle for closure membership. If `p` holds for `1` and all elements of `k` and their inverse, and is preserved under multiplication, then `p` holds for all elements of the closure of `k`. -/ @@ -242,6 +246,16 @@ instance sup_normal (H K : Subgroup G) [hH : H.Normal] [hK : K.Normal] : (H ⊔ refine ⟨g * h * g⁻¹, hH.conj_mem h hh g, g * k * g⁻¹, hK.conj_mem k hk g, ?_⟩ simp only [mul_assoc, inv_mul_cancel_left] +@[to_additive] +theorem smul_mem_of_mem_closure_of_mem {X : Type*} [MulAction G X] {s : Set G} {t : Set X} + (hs : ∀ g ∈ s, g⁻¹ ∈ s) (hst : ∀ᵉ (g ∈ s) (x ∈ t), g • x ∈ t) {g : G} + (hg : g ∈ Subgroup.closure s) {x : X} (hx : x ∈ t) : g • x ∈ t := by + induction hg using Subgroup.closure_induction'' generalizing x with + | one => simpa + | mem g' hg' => exact hst g' hg' x hx + | inv_mem g' hg' => exact hst g'⁻¹ (hs g' hg') x hx + | mul _ _ _ _ h₁ h₂ => rw [mul_smul]; exact h₁ (h₂ hx) + @[to_additive] theorem smul_opposite_image_mul_preimage' (g : G) (h : Gᵐᵒᵖ) (s : Set G) : (fun y => h • y) '' ((g * ·) ⁻¹' s) = (g * ·) ⁻¹' ((fun y => h • y) '' s) := by @@ -378,6 +392,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 diff --git a/Mathlib/Algebra/Group/Subgroup/ZPowers.lean b/Mathlib/Algebra/Group/Subgroup/ZPowers.lean index b91454a9b1837..7d8c98bdefc66 100644 --- a/Mathlib/Algebra/Group/Subgroup/ZPowers.lean +++ b/Mathlib/Algebra/Group/Subgroup/ZPowers.lean @@ -227,3 +227,10 @@ theorem center_eq_infi' (S : Set G) (hS : closure S = ⊤) : rw [center_eq_iInf S hS, ← iInf_subtype''] end Subgroup + +lemma AddSubgroup.closure_singleton_int_one_eq_top : closure ({1} : Set ℤ) = ⊤ := by + ext + simp [mem_closure_singleton] + +lemma AddSubgroup.zmultiples_one_eq_top : zmultiples (1 : ℤ) = ⊤ := by + rw [zmultiples_eq_closure, closure_singleton_int_one_eq_top] diff --git a/Mathlib/Algebra/Group/Submonoid/Basic.lean b/Mathlib/Algebra/Group/Submonoid/Basic.lean index 35c066cced16e..623c641fbcfa6 100644 --- a/Mathlib/Algebra/Group/Submonoid/Basic.lean +++ b/Mathlib/Algebra/Group/Submonoid/Basic.lean @@ -65,14 +65,14 @@ 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 +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 : Type*) [Zero M] [SetLike S M] : Prop where +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 @@ -96,7 +96,7 @@ 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 +class SubmonoidClass (S : Type*) (M : outParam Type*) [MulOneClass M] [SetLike S M] extends MulMemClass S M, OneMemClass S M : Prop section @@ -115,7 +115,7 @@ 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 +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 @@ -376,7 +376,7 @@ theorem closure_induction {p : M → Prop} {x} (h : x ∈ closure s) (mem : ∀ (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`. -/ +/-- 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} (mem : ∀ (x) (h : x ∈ s), p x (subset_closure h)) (one : p 1 (one_mem _)) @@ -387,7 +387,7 @@ theorem closure_induction' (s : Set M) {p : ∀ x, x ∈ closure s → Prop} closure_induction hx (fun x hx => ⟨_, mem x hx⟩) ⟨_, one⟩ fun x y ⟨hx', hx⟩ ⟨hy', hy⟩ => ⟨_, mul _ _ _ _ hx hy⟩ -/-- An induction principle for closure membership for predicates with two arguments. -/ +/-- 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) diff --git a/Mathlib/Algebra/Group/Submonoid/Membership.lean b/Mathlib/Algebra/Group/Submonoid/Membership.lean index 8c8595e52f624..3f5261db6d422 100644 --- a/Mathlib/Algebra/Group/Submonoid/Membership.lean +++ b/Mathlib/Algebra/Group/Submonoid/Membership.lean @@ -131,7 +131,7 @@ theorem multiset_prod_mem {M} [CommMonoid M] (S : Submonoid M) (m : Multiset M) @[to_additive] theorem multiset_noncommProd_mem (S : Submonoid M) (m : Multiset M) (comm) (h : ∀ x ∈ m, x ∈ S) : m.noncommProd comm ∈ S := by - induction' m using Quotient.inductionOn with l + induction m using Quotient.inductionOn with | h l => ?_ simp only [Multiset.quot_mk_to_coe, Multiset.noncommProd_coe] exact Submonoid.list_prod_mem _ h @@ -293,7 +293,7 @@ variable {S : Submonoid M} [Fintype S] open Fintype /- curly brackets `{}` are used here instead of instance brackets `[]` because - the instance in a goal is often not the same as the one inferred by type class inference. -/ + the instance in a goal is often not the same as the one inferred by type class inference. -/ @[to_additive] theorem card_bot {_ : Fintype (⊥ : Submonoid M)} : card (⊥ : Submonoid M) = 1 := card_eq_one_iff.2 @@ -356,9 +356,10 @@ 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 x y ih - · exact one - · simp only [map_mul, FreeMonoid.lift_eval_of] + induction l with + | h0 => exact one + | ih 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] @@ -439,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] diff --git a/Mathlib/Algebra/Group/Submonoid/MulOpposite.lean b/Mathlib/Algebra/Group/Submonoid/MulOpposite.lean index 3a6e6f07ce8ba..9157b526b564c 100644 --- a/Mathlib/Algebra/Group/Submonoid/MulOpposite.lean +++ b/Mathlib/Algebra/Group/Submonoid/MulOpposite.lean @@ -75,17 +75,41 @@ def opEquiv : Submonoid M ≃o Submonoid Mᵐᵒᵖ where right_inv := op_unop map_rel_iff' := op_le_op_iff +@[to_additive] +theorem op_injective : (@Submonoid.op M _).Injective := opEquiv.injective + +@[to_additive] +theorem unop_injective : (@Submonoid.unop M _).Injective := opEquiv.symm.injective + +@[to_additive (attr := simp)] +theorem op_inj {S T : Submonoid M} : S.op = T.op ↔ S = T := opEquiv.eq_iff_eq + +@[to_additive (attr := simp)] +theorem unop_inj {S T : Submonoid Mᵐᵒᵖ} : S.unop = T.unop ↔ S = T := opEquiv.symm.eq_iff_eq + @[to_additive (attr := simp)] theorem op_bot : (⊥ : Submonoid M).op = ⊥ := opEquiv.map_bot +@[to_additive (attr := simp)] +theorem op_eq_bot {S : Submonoid M} : S.op = ⊥ ↔ S = ⊥ := op_injective.eq_iff' op_bot + @[to_additive (attr := simp)] theorem unop_bot : (⊥ : Submonoid Mᵐᵒᵖ).unop = ⊥ := opEquiv.symm.map_bot @[to_additive (attr := simp)] -theorem op_top : (⊤ : Submonoid M).op = ⊤ := opEquiv.map_top +theorem unop_eq_bot {S : Submonoid Mᵐᵒᵖ} : S.unop = ⊥ ↔ S = ⊥ := unop_injective.eq_iff' unop_bot + +@[to_additive (attr := simp)] +theorem op_top : (⊤ : Submonoid M).op = ⊤ := rfl + +@[to_additive (attr := simp)] +theorem op_eq_top {S : Submonoid M} : S.op = ⊤ ↔ S = ⊤ := op_injective.eq_iff' op_top + +@[to_additive (attr := simp)] +theorem unop_top : (⊤ : Submonoid Mᵐᵒᵖ).unop = ⊤ := rfl @[to_additive (attr := simp)] -theorem unop_top : (⊤ : Submonoid Mᵐᵒᵖ).unop = ⊤ := opEquiv.symm.map_top +theorem unop_eq_top {S : Submonoid Mᵐᵒᵖ} : S.unop = ⊤ ↔ S = ⊤ := unop_injective.eq_iff' unop_top @[to_additive] theorem op_sup (S₁ S₂ : Submonoid M) : (S₁ ⊔ S₂).op = S₁.op ⊔ S₂.op := @@ -96,11 +120,10 @@ theorem unop_sup (S₁ S₂ : Submonoid Mᵐᵒᵖ) : (S₁ ⊔ S₂).unop = S opEquiv.symm.map_sup _ _ @[to_additive] -theorem op_inf (S₁ S₂ : Submonoid M) : (S₁ ⊓ S₂).op = S₁.op ⊓ S₂.op := opEquiv.map_inf _ _ +theorem op_inf (S₁ S₂ : Submonoid M) : (S₁ ⊓ S₂).op = S₁.op ⊓ S₂.op := rfl @[to_additive] -theorem unop_inf (S₁ S₂ : Submonoid Mᵐᵒᵖ) : (S₁ ⊓ S₂).unop = S₁.unop ⊓ S₂.unop := - opEquiv.symm.map_inf _ _ +theorem unop_inf (S₁ S₂ : Submonoid Mᵐᵒᵖ) : (S₁ ⊓ S₂).unop = S₁.unop ⊓ S₂.unop := rfl @[to_additive] theorem op_sSup (S : Set (Submonoid M)) : (sSup S).op = sSup (.unop ⁻¹' S) := @@ -140,9 +163,8 @@ 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 - simp_rw [closure, unop_sInf, Set.preimage_setOf_eq, Submonoid.op_coe] - congr with a - exact MulOpposite.op_surjective.forall + rw [← op_inj, op_unop, op_closure] + 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 213f451a27df5..f84160423a5b5 100644 --- a/Mathlib/Algebra/Group/Submonoid/Operations.lean +++ b/Mathlib/Algebra/Group/Submonoid/Operations.lean @@ -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 @@ -531,8 +541,6 @@ protected theorem pow_mem {M : Type*} [Monoid M] (S : Submonoid M) {x : M} (hx : x ^ n ∈ S := pow_mem hx n --- Porting note: coe_pow removed, syntactic tautology - /-- 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 := @@ -581,8 +589,9 @@ theorem coe_equivMapOfInjective_apply (f : M →* N) (hf : Function.Injective f) 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 (((↑) : closure s → M) ⁻¹' s)) - (fun g hg => subset_closure hg) ?_ (fun g₁ g₂ hg₁ hg₂ => ?_) hx + 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 _ @@ -626,7 +635,7 @@ theorem top_prod_top : (⊤ : Submonoid M).prod (⊤ : Submonoid N) = ⊤ := @[to_additive bot_prod_bot] theorem bot_prod_bot : (⊥ : Submonoid M).prod (⊥ : Submonoid N) = ⊥ := - SetLike.coe_injective <| by simp [coe_prod, Prod.one_eq_mk] + SetLike.coe_injective <| by simp [coe_prod] -- Porting note: to_additive translated the name incorrectly in mathlib 3. /-- The product of submonoids is isomorphic to their product as monoids. -/ @@ -829,6 +838,11 @@ def codRestrict {S} [SetLike S N] [SubmonoidClass S N] (f : M →* N) (s : S) (h map_one' := Subtype.eq f.map_one map_mul' x y := Subtype.eq (f.map_mul x y) +@[to_additive (attr := simp)] +lemma injective_codRestrict {S} [SetLike S N] [SubmonoidClass S N] (f : M →* N) (s : S) + (h : ∀ x, f x ∈ s) : Function.Injective (f.codRestrict s h) ↔ Function.Injective f := + ⟨fun H _ _ hxy ↦ H <| Subtype.eq hxy, fun H _ _ hxy ↦ H (congr_arg Subtype.val hxy)⟩ + /-- Restriction of a monoid hom to its range interpreted as a submonoid. -/ @[to_additive "Restriction of an `AddMonoid` hom to its range interpreted as a submonoid."] def mrangeRestrict {N} [MulOneClass N] (f : M →* N) : M →* (mrange f) := @@ -851,8 +865,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] @@ -861,7 +875,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) := @@ -910,10 +924,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) diff --git a/Mathlib/Algebra/Group/Submonoid/Units.lean b/Mathlib/Algebra/Group/Submonoid/Units.lean index 2754d556e4588..96ce6d155d1e4 100644 --- a/Mathlib/Algebra/Group/Submonoid/Units.lean +++ b/Mathlib/Algebra/Group/Submonoid/Units.lean @@ -40,13 +40,13 @@ variable {M : Type*} [Monoid M] open Units open Pointwise in -/-- The units of `S`, packaged as a subgroup of `Mˣ`. -/ +/-- The units of `S`, packaged as a subgroup of `Mˣ`. -/ @[to_additive " The additive units of `S`, packaged as an additive subgroup of `AddUnits M`. "] def Submonoid.units (S : Submonoid M) : Subgroup Mˣ where toSubmonoid := S.comap (coeHom M) ⊓ (S.comap (coeHom M))⁻¹ inv_mem' ha := ⟨ha.2, ha.1⟩ -/-- A subgroup of units represented as a submonoid of `M`. -/ +/-- A subgroup of units represented as a submonoid of `M`. -/ @[to_additive " A additive subgroup of additive units represented as a additive submonoid of `M`. "] def Subgroup.ofUnits (S : Subgroup Mˣ) : Submonoid M := S.toSubmonoid.map (coeHom M) @@ -327,6 +327,6 @@ lemma val_mem_ofUnits_iff_mem (H : Subgroup Gˣ) (x : Gˣ) : (x : G) ∈ H.ofUni @[to_additive " The equivalence between the greatest subgroup of additive units contained within `T` and `T` itself. "] def unitsEquivSelf (H : Subgroup G) : H.units ≃* H := - H.unitsEquivUnitsType.trans toUnits.symm + H.unitsEquivUnitsType.trans (toUnits (G := H)).symm end Subgroup diff --git a/Mathlib/Algebra/Group/Subsemigroup/Basic.lean b/Mathlib/Algebra/Group/Subsemigroup/Basic.lean index eb038acc2f5ba..c5801a38f6bdb 100644 --- a/Mathlib/Algebra/Group/Subsemigroup/Basic.lean +++ b/Mathlib/Algebra/Group/Subsemigroup/Basic.lean @@ -57,14 +57,14 @@ 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 +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 : Type*) [Add M] [SetLike S M] : Prop where +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 @@ -111,7 +111,7 @@ 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 := +theorem coe_set_mk (s : Set M) (h_mul) : (mk s h_mul : Set M) = s := rfl @[to_additive (attr := simp)] @@ -298,7 +298,7 @@ theorem closure_induction {p : M → Prop} {x} (h : x ∈ closure s) (mem : ∀ (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`. -/ +/-- 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} (mem : ∀ (x) (h : x ∈ s), p x (subset_closure h)) @@ -309,7 +309,7 @@ theorem closure_induction' (s : Set M) {p : ∀ x, x ∈ closure s → Prop} closure_induction hx (fun x hx => ⟨_, mem x hx⟩) fun x y ⟨hx', hx⟩ ⟨hy', hy⟩ => ⟨_, mul _ _ _ _ hx hy⟩ -/-- An induction principle for closure membership for predicates with two arguments. -/ +/-- 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) diff --git a/Mathlib/Algebra/Group/Subsemigroup/Operations.lean b/Mathlib/Algebra/Group/Subsemigroup/Operations.lean index 0c804659e191b..85f523619d7ca 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 @@ -301,14 +311,15 @@ theorem map_id (S : Subsemigroup M) : S.map (MulHom.id M) = S := section GaloisCoinsertion -variable {ι : Type*} {f : M →ₙ* N} (hf : Function.Injective f) -include hf +variable {ι : Type*} {f : M →ₙ* N} /-- `map f` and `comap f` form a `GaloisCoinsertion` when `f` is injective. -/ @[to_additive " `map f` and `comap f` form a `GaloisCoinsertion` when `f` is injective. "] -def gciMapComap : GaloisCoinsertion (map f) (comap f) := +def gciMapComap (hf : Function.Injective f) : GaloisCoinsertion (map f) (comap f) := (gc_map_comap f).toGaloisCoinsertion fun S x => by simp [mem_comap, mem_map, hf.eq_iff] +variable (hf : Function.Injective f) +include hf @[to_additive] theorem comap_map_eq_of_injective (S : Subsemigroup M) : (S.map f).comap f = S := @@ -488,9 +499,9 @@ theorem coe_equivMapOfInjective_apply (f : M →ₙ* N) (hf : Function.Injective 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 (((↑) : closure s → M) ⁻¹' s)) - (fun _ hg => subset_closure hg) (fun _ _ _ _ => Subsemigroup.mul_mem _) hx + 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' /-- Given `Subsemigroup`s `s`, `t` of semigroups `M`, `N` respectively, `s × t` as a subsemigroup of `M × N`. -/ @@ -530,7 +541,7 @@ theorem top_prod_top : (⊤ : Subsemigroup M).prod (⊤ : Subsemigroup N) = ⊤ @[to_additive bot_prod_bot] theorem bot_prod_bot : (⊥ : Subsemigroup M).prod (⊥ : Subsemigroup N) = ⊥ := - SetLike.coe_injective <| by simp [coe_prod, Prod.one_eq_mk] + SetLike.coe_injective <| by simp [coe_prod] /-- The product of subsemigroups is isomorphic to their product as semigroups. -/ @[to_additive prodEquiv @@ -594,6 +605,15 @@ theorem coe_srange (f : M →ₙ* N) : (f.srange : Set N) = Set.range f := theorem mem_srange {f : M →ₙ* N} {y : N} : y ∈ f.srange ↔ ∃ x, f x = y := Iff.rfl +@[to_additive] +private theorem srange_mk_aux_mul {f : M → N} (hf : ∀ (x y : M), f (x * y) = f x * f y) + {x y : N} (hx : x ∈ Set.range f) (hy : y ∈ Set.range f) : + x * y ∈ Set.range f := + (srange ⟨f, hf⟩).mul_mem hx hy + +@[to_additive (attr := simp)] theorem srange_mk (f : M → N) (hf) : + srange ⟨f, hf⟩ = ⟨Set.range f, srange_mk_aux_mul hf⟩ := rfl + @[to_additive] theorem srange_eq_map (f : M →ₙ* N) : f.srange = (⊤ : Subsemigroup M).map f := copy_eq _ 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.lean b/Mathlib/Algebra/Group/UniqueProds/Basic.lean similarity index 98% rename from Mathlib/Algebra/Group/UniqueProds.lean rename to Mathlib/Algebra/Group/UniqueProds/Basic.lean index 82f5f510f979c..99d252eee8364 100644 --- a/Mathlib/Algebra/Group/UniqueProds.lean +++ b/Mathlib/Algebra/Group/UniqueProds/Basic.lean @@ -3,9 +3,10 @@ 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.LinearAlgebra.Basis.VectorSpace +import Mathlib.Algebra.Group.ULift +import Mathlib.Data.Finsupp.Defs /-! # Unique products and related notions @@ -27,7 +28,7 @@ Here you can see several examples of Types that have `UniqueSums/Prods` ```lean import Mathlib.Data.Real.Basic import Mathlib.Data.PNat.Basic -import Mathlib.Algebra.Group.UniqueProds +import Mathlib.Algebra.Group.UniqueProds.Basic example : UniqueSums ℕ := inferInstance example : UniqueSums ℕ+ := inferInstance @@ -45,6 +46,12 @@ about the grading type and then a generic statement of the form "look at the coe The file `Algebra/MonoidAlgebra/NoZeroDivisors` contains several examples of this use. -/ +assert_not_exists Cardinal +assert_not_exists Subsemiring +assert_not_exists Algebra +assert_not_exists Submodule +assert_not_exists StarModule + /-- 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`. -/ @@ -63,13 +70,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] +@[to_additive of_card_le_one] theorem of_card_le_one (hA : A.Nonempty) (hB : B.Nonempty) (hA1 : A.card ≤ 1) (hB1 : B.card ≤ 1) : ∃ 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 @@ -106,7 +116,7 @@ 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 simp_rw [card_le_one_iff, mem_filter, mem_product] @@ -117,6 +127,9 @@ 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] @@ -635,12 +648,6 @@ instance {ι G} [AddZeroClass G] [TwoUniqueSums G] : TwoUniqueSums (ι →₀ G) TwoUniqueSums.of_injective_addHom Finsupp.coeFnAddHom.toAddHom DFunLike.coe_injective inferInstance -/-- Any `ℚ`-vector space has `TwoUniqueSums`, because it is isomorphic to some - `(Basis.ofVectorSpaceIndex ℚ G) →₀ ℚ` by choosing a basis, and `ℚ` already has - `TwoUniqueSums` because it's ordered. -/ -instance [AddCommGroup G] [Module ℚ G] : TwoUniqueSums G := - TwoUniqueSums.of_injective_addHom _ (Basis.ofVectorSpace ℚ G).repr.injective inferInstance - /-- Any `FreeMonoid` has the `TwoUniqueProds` property. -/ instance FreeMonoid.instTwoUniqueProds {κ : Type*} : TwoUniqueProds (FreeMonoid κ) := .of_mulHom ⟨Multiplicative.ofAdd ∘ List.length, fun _ _ ↦ congr_arg _ (List.length_append _ _)⟩ diff --git a/Mathlib/Algebra/Group/UniqueProds/VectorSpace.lean b/Mathlib/Algebra/Group/UniqueProds/VectorSpace.lean new file mode 100644 index 0000000000000..3b1ba113d4f00 --- /dev/null +++ b/Mathlib/Algebra/Group/UniqueProds/VectorSpace.lean @@ -0,0 +1,19 @@ +/- +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.UniqueProds.Basic +import Mathlib.LinearAlgebra.Basis.VectorSpace + +/-! +# A `ℚ`-vector space has `TwoUniqueSums`. +-/ + +variable {G : Type*} + +/-- Any `ℚ`-vector space has `TwoUniqueSums`, because it is isomorphic to some + `(Basis.ofVectorSpaceIndex ℚ G) →₀ ℚ` by choosing a basis, and `ℚ` already has + `TwoUniqueSums` because it's ordered. -/ +instance [AddCommGroup G] [Module ℚ G] : TwoUniqueSums G := + TwoUniqueSums.of_injective_addHom _ (Basis.ofVectorSpace ℚ G).repr.injective inferInstance diff --git a/Mathlib/Algebra/Group/Units.lean b/Mathlib/Algebra/Group/Units.lean index 7ae26582ac369..1c93daf4e3123 100644 --- a/Mathlib/Algebra/Group/Units.lean +++ b/Mathlib/Algebra/Group/Units.lean @@ -379,7 +379,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 @@ -464,6 +464,72 @@ 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 α] @@ -498,6 +564,8 @@ theorem mul_eq_one : a * b = 1 ↔ a = 1 ∧ b = 1 := 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 /-! @@ -583,9 +651,9 @@ 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 +theorem units_eq_one [Subsingleton 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 diff --git a/Mathlib/Algebra/Group/Units/Equiv.lean b/Mathlib/Algebra/Group/Units/Equiv.lean index a3ae5f7904381..12d6fb5b2285c 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,10 @@ 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 isLocalRingHom_equiv [Monoid M] [Monoid N] [EquivLike F M N] + [MulEquivClass F M N] (f : F) : IsLocalRingHom 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` diff --git a/Mathlib/Algebra/Group/Units/Hom.lean b/Mathlib/Algebra/Group/Units/Hom.lean index 1a84f0441934c..09f626ae87904 100644 --- a/Mathlib/Algebra/Group/Units/Hom.lean +++ b/Mathlib/Algebra/Group/Units/Hom.lean @@ -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 `βˣ`. +* `IsLocalRingHom`: 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 `IsLocalRingHom`. -/ 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 `IsLocalRingHom.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,49 @@ theorem liftRight_inv_mul (f : M →* N) (h : ∀ x, IsUnit (f x)) (x) : end Monoid end IsUnit + +section IsLocalRingHom + +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 IsLocalRingHom (f : F) : 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 + +@[simp] +theorem IsUnit.of_map (f : F) [IsLocalRingHom f] (a : R) (h : IsUnit (f a)) : IsUnit a := + IsLocalRingHom.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) [IsLocalRingHom f] (a : R) : IsUnit (f a) ↔ IsUnit a := + ⟨IsLocalRingHom.map_nonunit a, IsUnit.map f⟩ + +theorem isLocalRingHom_of_leftInverse [FunLike G S R] [MonoidHomClass G S R] + {f : F} (g : G) (hfg : Function.LeftInverse g f) : IsLocalRingHom f where + map_nonunit a ha := by rwa [isUnit_map_of_leftInverse g hfg] at ha + +instance MonoidHom.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 := g) (f a) + +-- see note [lower instance priority] +instance (priority := 100) isLocalRingHom_toMonoidHom (f : F) [IsLocalRingHom f] : + IsLocalRingHom (f : R →* S) := + ⟨IsLocalRingHom.map_nonunit (f := f)⟩ + +theorem MonoidHom.isLocalRingHom_of_comp (f : R →* S) (g : S →* T) [IsLocalRingHom (g.comp f)] : + IsLocalRingHom f := + ⟨fun _ ha => (isUnit_map_iff (g.comp f) _).mp (ha.map g)⟩ + +end IsLocalRingHom 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/GroupWithZero/Action/Defs.lean b/Mathlib/Algebra/GroupWithZero/Action/Defs.lean index a2e67fb1c2e12..d30f29f25d6f4 100644 --- a/Mathlib/Algebra/GroupWithZero/Action/Defs.lean +++ b/Mathlib/Algebra/GroupWithZero/Action/Defs.lean @@ -3,11 +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, Yury Kudryashov -/ -import Mathlib.Algebra.Group.Action.Defs -import Mathlib.Algebra.Group.Hom.Defs -import Mathlib.Algebra.Group.TypeTags -import Mathlib.Algebra.Opposites -import Mathlib.Logic.Embedding.Basic +import Mathlib.Algebra.Group.Action.Units +import Mathlib.Algebra.Group.Equiv.Basic +import Mathlib.Algebra.GroupWithZero.Units.Basic /-! # Definitions of group actions @@ -45,10 +43,49 @@ More sophisticated lemmas belong in `GroupTheory.GroupAction`. group action -/ +assert_not_exists Equiv.Perm.equivUnitsEnd +assert_not_exists Prod.fst_mul +assert_not_exists Ring -variable {M N G A B α β γ δ : Type*} +open Function -open Function (Injective Surjective) +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) + +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 /-- Typeclass for scalar multiplication that preserves `0` on the right. -/ class SMulZeroClass (M A : Type*) [Zero A] extends SMul M A where @@ -391,3 +428,24 @@ theorem AddMonoid.End.smul_def [AddMonoid α] (f : AddMonoid.End α) (a : α) : 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 α β] + +lemma smul_eq_zero_iff_eq (a : α) {x : β} : a • x = 0 ↔ x = 0 := + ⟨fun h => by rw [← inv_smul_smul a x, h, smul_zero], fun h => h.symm ▸ smul_zero _⟩ + +lemma smul_ne_zero_iff_ne (a : α) {x : β} : a • x ≠ 0 ↔ x ≠ 0 := + not_congr <| smul_eq_zero_iff_eq a + +end Group diff --git a/Mathlib/Algebra/GroupWithZero/Action/Opposite.lean b/Mathlib/Algebra/GroupWithZero/Action/Opposite.lean index d6555ef552eb7..27bab44a1aaed 100644 --- a/Mathlib/Algebra/GroupWithZero/Action/Opposite.lean +++ b/Mathlib/Algebra/GroupWithZero/Action/Opposite.lean @@ -6,6 +6,7 @@ Authors: Eric Wieser import Mathlib.Algebra.Group.Action.Opposite import Mathlib.Algebra.GroupWithZero.Action.Defs import Mathlib.Algebra.GroupWithZero.NeZero +import Mathlib.Algebra.SMulWithZero /-! # Scalar actions on and by `Mᵐᵒᵖ` @@ -26,16 +27,27 @@ 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 Actions on the opposite type just act on the underlying type. -/ - namespace MulOpposite +instance instSMulZeroClass [AddMonoid α] [SMulZeroClass M α] : SMulZeroClass M αᵐᵒᵖ where + smul_zero _ := unop_injective <| smul_zero _ + +instance instSMulWithZero [MonoidWithZero M] [AddMonoid α] [SMulWithZero M α] : + SMulWithZero M αᵐᵒᵖ where + zero_smul _ := unop_injective <| zero_smul _ _ + +instance instMulActionWithZero [MonoidWithZero M] [AddMonoid α] [MulActionWithZero M α] : + MulActionWithZero M αᵐᵒᵖ where + smul_zero _ := unop_injective <| smul_zero _ + zero_smul _ := unop_injective <| zero_smul _ _ + instance instDistribMulAction [Monoid M] [AddMonoid α] [DistribMulAction M α] : DistribMulAction M αᵐᵒᵖ where smul_add _ _ _ := unop_injective <| smul_add _ _ _ diff --git a/Mathlib/Algebra/GroupWithZero/Action/Prod.lean b/Mathlib/Algebra/GroupWithZero/Action/Prod.lean index 5d43252e1d1a7..b825703247594 100644 --- a/Mathlib/Algebra/GroupWithZero/Action/Prod.lean +++ b/Mathlib/Algebra/GroupWithZero/Action/Prod.lean @@ -18,7 +18,7 @@ This file defines instances for `MulActionWithZero` and related structures on ` * `Algebra.GroupWithZero.Action.Units` -/ -assert_not_exists MonoidWithZero +assert_not_exists Ring variable {M N α β : Type*} @@ -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 e56fe65a0de40..c517ff3399f1e 100644 --- a/Mathlib/Algebra/GroupWithZero/Action/Units.lean +++ b/Mathlib/Algebra/GroupWithZero/Action/Units.lean @@ -61,3 +61,10 @@ instance mulDistribMulAction' [Group G] [Monoid M] [MulDistribMulAction G M] [SM smul_mul := fun _ _ _ => Units.ext <| smul_mul' _ _ _ } end Units + +section Monoid +variable [Monoid G] [AddMonoid M] [DistribMulAction G M] {u : G} {x : M} + +@[simp] lemma IsUnit.smul_eq_zero (hu : IsUnit u) : u • x = 0 ↔ x = 0 := smul_eq_zero_iff_eq hu.unit + +end Monoid diff --git a/Mathlib/Algebra/GroupWithZero/Basic.lean b/Mathlib/Algebra/GroupWithZero/Basic.lean index d5a2ad48bcf5f..b6f9678b599f4 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] @@ -150,7 +150,7 @@ lemma pow_eq_zero_of_le : ∀ {m n} (hmn : m ≤ n) (ha : 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] -lemma ne_zero_pow (hn : n ≠ 0) (ha : a ^ n ≠ 0) : a ≠ 0 := by rintro rfl; exact ha $ zero_pow hn +lemma ne_zero_pow (hn : n ≠ 0) (ha : a ^ n ≠ 0) : a ≠ 0 := by rintro rfl; exact ha <| zero_pow hn @[simp] lemma zero_pow_eq_zero [Nontrivial M₀] : (0 : M₀) ^ n = 0 ↔ n ≠ 0 := @@ -234,7 +234,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 +291,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] @@ -398,10 +398,10 @@ lemma zpow_sub_one₀ (ha : a ≠ 0) (n : ℤ) : a ^ (n - 1) = a ^ n * a⁻¹ := _ = a ^ n * a⁻¹ := by rw [← zpow_add_one₀ ha, Int.sub_add_cancel] lemma zpow_add₀ (ha : a ≠ 0) (m n : ℤ) : a ^ (m + n) = a ^ m * a ^ n := by - induction' n using Int.induction_on with n ihn n ihn - · simp - · simp only [← Int.add_assoc, zpow_add_one₀ ha, ihn, mul_assoc] - · rw [zpow_sub_one₀ ha, ← mul_assoc, ← ihn, ← zpow_sub_one₀ ha, Int.add_sub_assoc] + induction n using Int.induction_on with + | hz => simp + | hp n ihn => simp only [← Int.add_assoc, zpow_add_one₀ ha, ihn, mul_assoc] + | hn n ihn => rw [zpow_sub_one₀ ha, ← mul_assoc, ← ihn, ← zpow_sub_one₀ ha, Int.add_sub_assoc] lemma zpow_add' {m n : ℤ} (h : a ≠ 0 ∨ m + n ≠ 0 ∨ m = 0 ∧ n = 0) : a ^ (m + n) = a ^ m * a ^ n := by @@ -411,8 +411,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 +421,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/Center.lean b/Mathlib/Algebra/GroupWithZero/Center.lean index d8366c9759d48..3f721aaa7d178 100644 --- a/Mathlib/Algebra/GroupWithZero/Center.lean +++ b/Mathlib/Algebra/GroupWithZero/Center.lean @@ -38,7 +38,7 @@ lemma center_units_subset : center G₀ˣ ⊆ ((↑) : G₀ˣ → G₀) ⁻¹' c intro u hu a obtain rfl | ha := eq_or_ne a 0 · rw [zero_mul, mul_zero] - · exact congr_arg Units.val $ hu $ Units.mk0 a ha + · exact congr_arg Units.val <| hu <| Units.mk0 a ha /-- In a group with zero, the center of the units is the preimage of the center. -/ lemma center_units_eq : center G₀ˣ = ((↑) : G₀ˣ → G₀) ⁻¹' center G₀ := diff --git a/Mathlib/Algebra/GroupWithZero/Commute.lean b/Mathlib/Algebra/GroupWithZero/Commute.lean index 59423cb09016f..24a2a0afe674b 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 {G₀ : Type*} [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..14ace092e132d 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 @@ -216,7 +216,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/Hom.lean b/Mathlib/Algebra/GroupWithZero/Hom.lean index 7f2b2a294119a..75d6481cf412f 100644 --- a/Mathlib/Algebra/GroupWithZero/Hom.lean +++ b/Mathlib/Algebra/GroupWithZero/Hom.lean @@ -175,11 +175,11 @@ lemma comp_assoc (f : α →*₀ β) (g : β →*₀ γ) (h : γ →*₀ δ) : lemma cancel_right {g₁ g₂ : β →*₀ γ} {f : α →*₀ β} (hf : Surjective f) : g₁.comp f = g₂.comp f ↔ g₁ = g₂ := - ⟨fun h ↦ ext $ hf.forall.2 (DFunLike.ext_iff.1 h), fun h ↦ h ▸ rfl⟩ + ⟨fun h ↦ ext <| hf.forall.2 (DFunLike.ext_iff.1 h), fun h ↦ h ▸ rfl⟩ lemma cancel_left {g : β →*₀ γ} {f₁ f₂ : α →*₀ β} (hg : Injective g) : g.comp f₁ = g.comp f₂ ↔ f₁ = f₂ := - ⟨fun h ↦ ext fun x ↦ hg $ by rw [← comp_apply, h, + ⟨fun h ↦ ext fun x ↦ hg <| by rw [← comp_apply, h, comp_apply], fun h ↦ h ▸ rfl⟩ lemma toMonoidHom_injective : Injective (toMonoidHom : (α →*₀ β) → α →* β) := 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 36f4cf1c801f9..6895aebeb4888 100644 --- a/Mathlib/Algebra/GroupWithZero/Invertible.lean +++ b/Mathlib/Algebra/GroupWithZero/Invertible.lean @@ -18,16 +18,18 @@ universe u variable {α : Type u} -theorem nonzero_of_invertible [MulZeroOneClass α] (a : α) [Nontrivial α] [Invertible a] : a ≠ 0 := +theorem Invertible.ne_zero [MulZeroOneClass α] (a : α) [Nontrivial α] [Invertible a] : a ≠ 0 := fun ha => zero_ne_one <| calc 0 = ⅟ a * a := by simp [ha] - _ = 1 := invOf_mul_self a + _ = 1 := invOf_mul_self -instance (priority := 100) Invertible.ne_zero [MulZeroOneClass α] [Nontrivial α] (a : α) +@[deprecated (since := "2024-08-15")] alias nonzero_of_invertible := Invertible.ne_zero + +instance (priority := 100) Invertible.toNeZero [MulZeroOneClass α] [Nontrivial α] (a : α) [Invertible a] : NeZero a := - ⟨nonzero_of_invertible a⟩ + ⟨Invertible.ne_zero a⟩ section MonoidWithZero variable [MonoidWithZero α] @@ -48,15 +50,15 @@ def invertibleOfNonzero {a : α} (h : a ≠ 0) : Invertible a := @[simp] theorem invOf_eq_inv (a : α) [Invertible a] : ⅟ a = a⁻¹ := - invOf_eq_right_inv (mul_inv_cancel₀ (nonzero_of_invertible a)) + invOf_eq_right_inv (mul_inv_cancel₀ (Invertible.ne_zero a)) @[simp] theorem inv_mul_cancel_of_invertible (a : α) [Invertible a] : a⁻¹ * a = 1 := - inv_mul_cancel₀ (nonzero_of_invertible a) + inv_mul_cancel₀ (Invertible.ne_zero a) @[simp] theorem mul_inv_cancel_of_invertible (a : α) [Invertible a] : a * a⁻¹ = 1 := - mul_inv_cancel₀ (nonzero_of_invertible a) + mul_inv_cancel₀ (Invertible.ne_zero a) /-- `a` is the inverse of `a⁻¹` -/ def invertibleInv {a : α} [Invertible a] : Invertible a⁻¹ := @@ -64,15 +66,15 @@ def invertibleInv {a : α} [Invertible a] : Invertible a⁻¹ := @[simp] theorem div_mul_cancel_of_invertible (a b : α) [Invertible b] : a / b * b = a := - div_mul_cancel₀ a (nonzero_of_invertible b) + div_mul_cancel₀ a (Invertible.ne_zero b) @[simp] theorem mul_div_cancel_of_invertible (a b : α) [Invertible b] : a * b / b = a := - mul_div_cancel_right₀ a (nonzero_of_invertible b) + mul_div_cancel_right₀ a (Invertible.ne_zero b) @[simp] theorem div_self_of_invertible (a : α) [Invertible a] : a / a = 1 := - div_self (nonzero_of_invertible a) + div_self (Invertible.ne_zero a) /-- `b / a` is the inverse of `a / b` -/ def invertibleDiv (a b : α) [Invertible a] [Invertible b] : Invertible (a / b) := diff --git a/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean b/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean index 0ed3c88eff1ab..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) : @@ -283,7 +283,7 @@ def unitsNonZeroDivisorsEquiv : M₀⁰ˣ ≃* M₀ˣ where right_inv _ := rfl @[simp, norm_cast] lemma nonZeroDivisors.associated_coe : Associated (a : M₀) b ↔ Associated a b := - unitsNonZeroDivisorsEquiv.symm.exists_congr_left.trans $ by simp [Associated]; norm_cast + unitsNonZeroDivisorsEquiv.symm.exists_congr_left.trans <| by simp [Associated]; norm_cast end MonoidWithZero @@ -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/Set/Basic.lean b/Mathlib/Algebra/GroupWithZero/Pointwise/Set/Basic.lean new file mode 100644 index 0000000000000..ec178273360b2 --- /dev/null +++ b/Mathlib/Algebra/GroupWithZero/Pointwise/Set/Basic.lean @@ -0,0 +1,59 @@ +/- +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.Basic +import Mathlib.Algebra.GroupWithZero.Basic + +/-! +# Pointwise operations of sets in a group with zero + +This file proves properties of pointwise operations of sets in a group with zero. + +## Tags + +set multiplication, set addition, pointwise addition, pointwise multiplication, +pointwise subtraction +-/ + +assert_not_exists OrderedAddCommMonoid +assert_not_exists Ring + +open Function +open scoped Pointwise + +variable {F α β γ : Type*} + +namespace Set + +section MulZeroClass +variable [MulZeroClass α] {s t : Set α} + +/-! Note that `Set` is not a `MulZeroClass` because `0 * ∅ ≠ 0`. -/ + +lemma mul_zero_subset (s : Set α) : s * 0 ⊆ 0 := by simp [subset_def, mem_mul] +lemma zero_mul_subset (s : Set α) : 0 * s ⊆ 0 := by simp [subset_def, 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 α] {s t : Set α} + +lemma div_zero_subset (s : Set α) : s / 0 ⊆ 0 := by simp [subset_def, mem_div] +lemma zero_div_subset (s : Set α) : 0 / s ⊆ 0 := by simp [subset_def, 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 + +end GroupWithZero +end Set diff --git a/Mathlib/Algebra/GroupWithZero/Semiconj.lean b/Mathlib/Algebra/GroupWithZero/Semiconj.lean index f702796fd87ed..0dfc56212073d 100644 --- a/Mathlib/Algebra/GroupWithZero/Semiconj.lean +++ b/Mathlib/Algebra/GroupWithZero/Semiconj.lean @@ -5,7 +5,6 @@ Authors: Johan Commelin -/ import Mathlib.Algebra.GroupWithZero.Units.Basic import Mathlib.Algebra.Group.Semiconj.Units -import Mathlib.Init.Classical /-! # Lemmas about semiconjugate elements in a `GroupWithZero`. @@ -14,7 +13,7 @@ import Mathlib.Init.Classical 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 c7f47fc71a812..4daea455977cf 100644 --- a/Mathlib/Algebra/GroupWithZero/Units/Basic.lean +++ b/Mathlib/Algebra/GroupWithZero/Units/Basic.lean @@ -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 @@ -322,11 +327,11 @@ lemma mul_div_mul_right (a b : G₀) (hc : c ≠ 0) : a * c / (b * c) = a / b := -- TODO: Duplicate of `mul_inv_cancel_right₀` lemma mul_mul_div (a : G₀) (hb : b ≠ 0) : a = a * b * (1 / b) := (hb.isUnit.mul_mul_div _).symm -lemma div_div_div_cancel_right (a : G₀) (hc : c ≠ 0) : a / c / (b / c) = a / b := by +lemma div_div_div_cancel_right₀ (hc : c ≠ 0) (a b : G₀) : a / c / (b / c) = a / b := by rw [div_div_eq_mul_div, div_mul_cancel₀ _ hc] -lemma div_mul_div_cancel (a : G₀) (hc : c ≠ 0) : a / c * (c / b) = a / b := by - rw [← mul_div_assoc, div_mul_cancel₀ _ hc] +lemma div_mul_div_cancel₀ (hb : b ≠ 0) : a / b * (b / c) = a / c := by + rw [← mul_div_assoc, div_mul_cancel₀ _ hb] lemma div_mul_cancel_of_imp (h : b = 0 → a = 0) : a / b * b = a := by obtain rfl | hb := eq_or_ne b 0 <;> simp [*] @@ -355,6 +360,15 @@ lemma inv_pow_sub_of_lt (a : G₀) (h : n < m) : a⁻¹ ^ (m - n) = (a ^ m)⁻¹ lemma zpow_sub₀ (ha : a ≠ 0) (m n : ℤ) : a ^ (m - n) = a ^ m / a ^ n := by rw [Int.sub_eq_add_neg, zpow_add₀ ha, zpow_neg, div_eq_mul_inv] +lemma zpow_natCast_sub_natCast₀ (ha : a ≠ 0) (m n : ℕ) : a ^ (m - n : ℤ) = a ^ m / a ^ n := by + simpa using zpow_sub₀ ha m n + +lemma zpow_natCast_sub_one₀ (ha : a ≠ 0) (n : ℕ) : a ^ (n - 1 : ℤ) = a ^ n / a := by + simpa using zpow_sub₀ ha n 1 + +lemma zpow_one_sub_natCast₀ (ha : a ≠ 0) (n : ℕ) : a ^ (1 - n : ℤ) = a / a ^ n := by + simpa using zpow_sub₀ ha 1 n + lemma zpow_ne_zero {a : G₀} : ∀ n : ℤ, a ≠ 0 → a ^ n ≠ 0 | (_ : ℕ) => by rw [zpow_natCast]; exact pow_ne_zero _ | .negSucc n => fun ha ↦ by rw [zpow_negSucc]; exact inv_ne_zero (pow_ne_zero _ ha) @@ -450,6 +464,9 @@ lemma div_helper (b : G₀) (h : a ≠ 0) : 1 / (a * b) * a = 1 / b := by lemma div_div_div_cancel_left' (a b : G₀) (hc : c ≠ 0) : c / a / (c / b) = b / a := by rw [div_div_div_eq, mul_comm, mul_div_mul_right _ _ hc] +@[simp] lemma div_mul_div_cancel₀' (ha : a ≠ 0) (b c : G₀) : a / b * (c / a) = c / b := by + rw [mul_comm, div_mul_div_cancel₀ ha] + end CommGroupWithZero section NoncomputableDefs diff --git a/Mathlib/Algebra/GroupWithZero/Units/Lemmas.lean b/Mathlib/Algebra/GroupWithZero/Units/Lemmas.lean index c413ab0a165b8..407a0fb1b6c75 100644 --- a/Mathlib/Algebra/GroupWithZero/Units/Lemmas.lean +++ b/Mathlib/Algebra/GroupWithZero/Units/Lemmas.lean @@ -15,10 +15,34 @@ 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 isLocalRingHom_of_exists_map_ne_one [FunLike F G₀ M] [MonoidHomClass F G₀ M] {f : F} + (hf : ∃ x : G₀, f x ≠ 1) : IsLocalRingHom 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⟩ + +instance [GroupWithZero G₀] [FunLike F G₀ M₀] [MonoidWithZeroHomClass F G₀ M₀] [Nontrivial M₀] + (f : F) : IsLocalRingHom f := + isLocalRingHom_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 +118,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 +131,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..9790623ef1ff9 100644 --- a/Mathlib/Algebra/GroupWithZero/WithZero.lean +++ b/Mathlib/Algebra/GroupWithZero/WithZero.lean @@ -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 3101d26f94bdc..b2fe9b97fe510 100644 --- a/Mathlib/Algebra/HierarchyDesign.lean +++ b/Mathlib/Algebra/HierarchyDesign.lean @@ -1,8 +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, 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..85979eabec627 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 diff --git a/Mathlib/Algebra/Homology/Augment.lean b/Mathlib/Algebra/Homology/Augment.lean index 4daeaa8a4bcf3..c72e003fc7557 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 @@ -231,7 +231,7 @@ def augment (C : CochainComplex V ℕ) {X : V} (f : X ⟶ C.X 0) (w : f ≫ C.d cases k · exact w · rw [C.shape, comp_zero] - simp only [Nat.zero_eq, ComplexShape.up_Rel, zero_add] + simp only [ComplexShape.up_Rel, zero_add] exact (Nat.one_lt_succ_succ _).ne @[simp] diff --git a/Mathlib/Algebra/Homology/BifunctorAssociator.lean b/Mathlib/Algebra/Homology/BifunctorAssociator.lean new file mode 100644 index 0000000000000..77c349d2de113 --- /dev/null +++ b/Mathlib/Algebra/Homology/BifunctorAssociator.lean @@ -0,0 +1,398 @@ +/- +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.GradedObject.Associator +import Mathlib.CategoryTheory.Linear.LinearFunctor +import Mathlib.Algebra.Homology.Bifunctor + +/-! +# The associator for actions of bifunctors on homological complexes + +In this file, we shall adapt (TODO) the results of the file +`CategoryTheory.GradedObject.Associator` to the case of homological complexes. +Given functors `F₁₂ : C₁ ⥤ C₂ ⥤ C₁₂`, `G : C₁₂ ⥤ C₃ ⥤ C₄`, +`F : C₁ ⥤ C₂₃ ⥤ C₄`, `G₂₃ : C₂ ⥤ C₃ ⥤ C₂₃` equipped with an isomorphism +`associator : bifunctorComp₁₂ F₁₂ G ≅ bifunctorComp₂₃ F G₂₃` (which informally means +that we have natural isomorphisms `G(F₁₂(X₁, X₂), X₃) ≅ F(X₁, G₂₃(X₂, X₃))`), +we shall define an isomorphism `mapBifunctorAssociator` from +`mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄` to +`mapBifunctor K₁ (mapBifunctor K₂ K₃ G₂₃ c₂₃) F c₄` when +we have three homological complexes `K₁ : HomologicalComplex C₁ c₁`, +`K₂ : HomologicalComplex C₂ c₂` and `K₃ : HomologicalComplex C₃ c₃`, +assumptions `TotalComplexShape c₁ c₂ c₁₂`, `TotalComplexShape c₁₂ c₃ c₄`, +`TotalComplexShape c₂ c₃ c₂₃`, `TotalComplexShape c₁ c₂₃ c₄`, +and `ComplexShape.Associative c₁ c₂ c₃ c₁₂ c₂₃ c₄` about the complex +shapes, and technical assumptions +`[HasGoodTrifunctor₁₂Obj F₁₂ G K₁ K₂ K₃ c₁₂ c₄]` and +`[HasGoodTrifunctor₂₃Obj F G₂₃ K₁ K₂ K₃ c₁₂ c₂₃ c₄]` about the +commutation of certain functors to certain coproducts. + +The main application of these results shall be the construction of +the associator for the monoidal category structure on homological complexes (TODO). + +-/ + +open CategoryTheory Category Limits + +namespace HomologicalComplex + +variable {C₁ C₂ C₁₂ C₂₃ C₃ C₄ : Type*} + [Category C₁] [Category C₂] [Category C₃] [Category C₄] [Category C₁₂] [Category C₂₃] + [HasZeroMorphisms C₁] [HasZeroMorphisms C₂] [HasZeroMorphisms C₃] + [Preadditive C₁₂] [Preadditive C₂₃] [Preadditive C₄] + {F₁₂ : C₁ ⥤ C₂ ⥤ C₁₂} {G : C₁₂ ⥤ C₃ ⥤ C₄} + {F : C₁ ⥤ C₂₃ ⥤ C₄} {G₂₃ : C₂ ⥤ C₃ ⥤ C₂₃} + [F₁₂.PreservesZeroMorphisms] [∀ (X₁ : C₁), (F₁₂.obj X₁).PreservesZeroMorphisms] + [G.Additive] [∀ (X₁₂ : C₁₂), (G.obj X₁₂).PreservesZeroMorphisms] + [G₂₃.PreservesZeroMorphisms] [∀ (X₂ : C₂), (G₂₃.obj X₂).PreservesZeroMorphisms] + [F.PreservesZeroMorphisms] [∀ (X₁ : C₁), (F.obj X₁).Additive] + (associator : bifunctorComp₁₂ F₁₂ G ≅ bifunctorComp₂₃ F G₂₃) + {ι₁ ι₂ ι₃ ι₁₂ ι₂₃ ι₄ : Type*} + [DecidableEq ι₁₂] [DecidableEq ι₂₃] [DecidableEq ι₄] + {c₁ : ComplexShape ι₁} {c₂ : ComplexShape ι₂} {c₃ : ComplexShape ι₃} + (K₁ : HomologicalComplex C₁ c₁) (K₂ : HomologicalComplex C₂ c₂) + (K₃ : HomologicalComplex C₃ c₃) + (c₁₂ : ComplexShape ι₁₂) (c₂₃ : ComplexShape ι₂₃) (c₄ : ComplexShape ι₄) + [TotalComplexShape c₁ c₂ c₁₂] [TotalComplexShape c₁₂ c₃ c₄] + [TotalComplexShape c₂ c₃ c₂₃] [TotalComplexShape c₁ c₂₃ c₄] + [HasMapBifunctor K₁ K₂ F₁₂ c₁₂] [HasMapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄] + [HasMapBifunctor K₂ K₃ G₂₃ c₂₃] [HasMapBifunctor K₁ (mapBifunctor K₂ K₃ G₂₃ c₂₃) F c₄] + [ComplexShape.Associative c₁ c₂ c₃ c₁₂ c₂₃ c₄] + +variable (F₁₂ G) in +/-- Given bifunctors `F₁₂ : C₁ ⥤ C₂ ⥤ C₁₂`, `G : C₁₂ ⥤ C₃ ⥤ C₄`, homological complexes +`K₁ : HomologicalComplex C₁ c₁`, `K₂ : HomologicalComplex C₂ c₂` and +`K₃ : HomologicalComplex C₃ c₃`, and complexes shapes `c₁₂`, `c₄`, this asserts +that for all `i₁₂ : ι₁₂` and `i₃ : ι₃`, the functor `G(-, K₃.X i₃)` commutes with +the coproducts of the `F₁₂(X₁ i₁, X₂ i₂)` such that `π c₁ c₂ c₁₂ ⟨i₁, i₂⟩ = i₁₂`. -/ +abbrev HasGoodTrifunctor₁₂Obj := + GradedObject.HasGoodTrifunctor₁₂Obj F₁₂ G + (ComplexShape.ρ₁₂ c₁ c₂ c₃ c₁₂ c₄) K₁.X K₂.X K₃.X + +variable (F G₂₃) in +/-- Given bifunctors `F : C₁ ⥤ C₂₃ ⥤ C₄`, `G₂₃ : C₂ ⥤ C₃ ⥤ C₂₃`, homological complexes +`K₁ : HomologicalComplex C₁ c₁`, `K₂ : HomologicalComplex C₂ c₂` and +`K₃ : HomologicalComplex C₃ c₃`, and complexes shapes `c₁₂`, `c₂₃`, `c₄` +with `ComplexShape.Associative c₁ c₂ c₃ c₁₂ c₂₃ c₄`, this asserts that for +all `i₁ : ι₁` and `i₂₃ : ι₂₃`, the functor `F(K₁.X i₁, _)` commutes with +the coproducts of the `G₂₃(K₂.X i₂, K₃.X i₃)` +such that `π c₂ c₃ c₂₃ ⟨i₂, i₃⟩ = i₂₃`. -/ +abbrev HasGoodTrifunctor₂₃Obj := + GradedObject.HasGoodTrifunctor₂₃Obj F G₂₃ + (ComplexShape.ρ₂₃ c₁ c₂ c₃ c₁₂ c₂₃ c₄) K₁.X K₂.X K₃.X + +instance : + (((GradedObject.mapBifunctor F₁₂ ι₁ ι₂).obj K₁.X).obj K₂.X).HasMap + (ComplexShape.π c₁ c₂ c₁₂) := + inferInstanceAs (HasMapBifunctor K₁ K₂ F₁₂ c₁₂) + +instance : + (((GradedObject.mapBifunctor G ι₁₂ ι₃).obj (GradedObject.mapBifunctorMapObj F₁₂ + (ComplexShape.π c₁ c₂ c₁₂) K₁.X K₂.X)).obj K₃.X).HasMap + (ComplexShape.π c₁₂ c₃ c₄) := + inferInstanceAs (HasMapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄) + +instance : + (((GradedObject.mapBifunctor F ι₁ ι₂₃).obj K₁.X).obj + (GradedObject.mapBifunctorMapObj G₂₃ + (ComplexShape.π c₂ c₃ c₂₃) K₂.X K₃.X)).HasMap (ComplexShape.π c₁ c₂₃ c₄) := + inferInstanceAs (HasMapBifunctor K₁ (mapBifunctor K₂ K₃ G₂₃ c₂₃) F c₄) + +/-- The associator isomorphism for the action of bifunctors +on homological complexes, in each degree. -/ +noncomputable def mapBifunctorAssociatorX + [H₁₂ : HasGoodTrifunctor₁₂Obj F₁₂ G K₁ K₂ K₃ c₁₂ c₄] + [H₂₃ : HasGoodTrifunctor₂₃Obj F G₂₃ K₁ K₂ K₃ c₁₂ c₂₃ c₄](j : ι₄) : + (mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄).X j ≅ + (mapBifunctor K₁ (mapBifunctor K₂ K₃ G₂₃ c₂₃) F c₄).X j := + (GradedObject.eval j).mapIso + (GradedObject.mapBifunctorAssociator (associator := associator) + (H₁₂ := H₁₂) (H₂₃ := H₂₃)) + +namespace mapBifunctor₁₂ + +section + +variable (F₁₂ G) + +/-- The inclusion of a summand in `mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄`. -/ +noncomputable def ι (i₁ : ι₁) (i₂ : ι₂) (i₃ : ι₃) (j : ι₄) + (h : ComplexShape.r c₁ c₂ c₃ c₁₂ c₄ (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 := + GradedObject.ιMapBifunctor₁₂BifunctorMapObj _ _ (ComplexShape.ρ₁₂ c₁ c₂ c₃ c₁₂ c₄) _ _ _ _ _ _ _ h + +lemma ι_eq (i₁ : ι₁) (i₂ : ι₂) (i₃ : ι₃) (i₁₂ : ι₁₂) (j : ι₄) + (h₁₂ : ComplexShape.π c₁ c₂ c₁₂ ⟨i₁, i₂⟩ = i₁₂) + (h : ComplexShape.π c₁₂ c₃ c₄ (i₁₂, i₃) = j) : + ι F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j (by rw [← h, ← h₁₂]; rfl) = + (G.map (ιMapBifunctor K₁ K₂ F₁₂ c₁₂ i₁ i₂ i₁₂ h₁₂)).app (K₃.X i₃) ≫ + ιMapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄ i₁₂ i₃ j h := by + subst h₁₂ + rfl + +/-- The inclusion of a summand in `mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄`, +or zero. -/ +noncomputable def ιOrZero (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 := + if h : ComplexShape.r c₁ c₂ c₃ c₁₂ c₄ (i₁, i₂, i₃) = j then + ι F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j h + else 0 + +lemma ιOrZero_eq (i₁ : ι₁) (i₂ : ι₂) (i₃ : ι₃) (j : ι₄) + (h : ComplexShape.r c₁ c₂ c₃ c₁₂ c₄ (i₁, i₂, i₃) = j) : + ιOrZero F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j = + ι F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j h := dif_pos h + +lemma ιOrZero_eq_zero (i₁ : ι₁) (i₂ : ι₂) (i₃ : ι₃) (j : ι₄) + (h : ComplexShape.r c₁ c₂ c₃ c₁₂ c₄ (i₁, i₂, i₃) ≠ j) : + ιOrZero F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j = 0 := dif_neg h + +variable {F₁₂ G K₁ K₂ K₃ c₁₂ c₄} in +@[ext] +lemma hom_ext + [HasGoodTrifunctor₁₂Obj F₁₂ G K₁ K₂ K₃ c₁₂ c₄] {j : ι₄} {A : C₄} + {f g : (mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄).X j ⟶ A} + (hfg : ∀ (i₁ : ι₁) (i₂ : ι₂) (i₃ : ι₃) + (h : ComplexShape.r c₁ c₂ c₃ c₁₂ c₄ (i₁, i₂, i₃) = j), + ι F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j h ≫ f = + ι F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j h ≫ g) : + f = g := + GradedObject.mapBifunctor₁₂BifunctorMapObj_ext hfg + +end + +section + +variable {K₁ K₂ K₃ c₁₂ c₄} +variable [HasGoodTrifunctor₁₂Obj F₁₂ G K₁ K₂ K₃ c₁₂ c₄] {j : ι₄} {A : C₄} + (f : ∀ (i₁ : ι₁) (i₂ : ι₂) (i₃ : ι₃) (_ : ComplexShape.r c₁ c₂ c₃ c₁₂ c₄ (i₁, i₂, i₃) = j), + (G.obj ((F₁₂.obj (K₁.X i₁)).obj (K₂.X i₂))).obj (K₃.X i₃) ⟶ A) + +/-- Constructor for morphisms from +`(mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄).X j`. -/ +noncomputable def mapBifunctor₁₂Desc : + (mapBifunctor (mapBifunctor K₁ K₂ F₁₂ c₁₂) K₃ G c₄).X j ⟶ A := + GradedObject.mapBifunctor₁₂BifunctorDesc (ρ₁₂ := ComplexShape.ρ₁₂ c₁ c₂ c₃ c₁₂ c₄) f + +@[reassoc (attr := simp)] +lemma ι_mapBifunctor₁₂Desc (i₁ : ι₁) (i₂ : ι₂) (i₃ : ι₃) + (h : ComplexShape.r c₁ c₂ c₃ c₁₂ c₄ (i₁, i₂, i₃) = j) : + ι F₁₂ G K₁ K₂ K₃ c₁₂ c₄ i₁ i₂ i₃ j h ≫ mapBifunctor₁₂Desc f = + f i₁ i₂ i₃ h := by + apply GradedObject.ι_mapBifunctor₁₂BifunctorDesc + +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/ComplexShape.lean b/Mathlib/Algebra/Homology/ComplexShape.lean index 217da35df2a5d..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 @@ -86,9 +86,7 @@ def symm (c : ComplexShape ι) : ComplexShape ι where prev_eq w w' := c.next_eq w w' @[simp] -theorem symm_symm (c : ComplexShape ι) : c.symm.symm = c := by - ext - simp +theorem symm_symm (c : ComplexShape ι) : c.symm.symm = c := rfl theorem symm_bijective : Function.Bijective (ComplexShape.symm : ComplexShape ι → ComplexShape ι) := diff --git a/Mathlib/Algebra/Homology/ComplexShapeSigns.lean b/Mathlib/Algebra/Homology/ComplexShapeSigns.lean index aa22deaab5726..224aa9d155bb6 100644 --- a/Mathlib/Algebra/Homology/ComplexShapeSigns.lean +++ b/Mathlib/Algebra/Homology/ComplexShapeSigns.lean @@ -33,7 +33,7 @@ variable {I₁ I₂ I₃ I₁₂ I₂₃ J : Type*} of a total complex functor `HomologicalComplex₂ C c₁ c₂ ⥤ HomologicalComplex C c₁₂` which sends `K` to a complex which in degree `i₁₂ : I₁₂` consists of the coproduct of the `(K.X i₁).X i₂` such that `π ⟨i₁, i₂⟩ = i₁₂`. -/ -class TotalComplexShape where +class TotalComplexShape where /-- a map on indices -/ π : I₁ × I₂ → I₁₂ /-- the sign of the horizontal differential in the total complex -/ 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/Basic.lean b/Mathlib/Algebra/Homology/DerivedCategory/Basic.lean index c04665c5b4098..da302f9893e1b 100644 --- a/Mathlib/Algebra/Homology/DerivedCategory/Basic.lean +++ b/Mathlib/Algebra/Homology/DerivedCategory/Basic.lean @@ -253,4 +253,23 @@ noncomputable def singleFunctorsPostcompQIso : SingleFunctors.postcompIsoOfIso (CochainComplex.singleFunctors C) (quotientCompQhIso C) +lemma singleFunctorsPostcompQIso_hom_hom (n : ℤ) : + (singleFunctorsPostcompQIso C).hom.hom n = 𝟙 _ := by + ext X + dsimp [singleFunctorsPostcompQIso, HomotopyCategory.singleFunctorsPostcompQuotientIso, + quotientCompQhIso, HomologicalComplexUpToQuasiIso.quotientCompQhIso] + rw [CategoryTheory.Functor.map_id, SingleFunctors.id_hom, NatTrans.id_app] + erw [Category.id_comp, Category.id_comp] + rfl + +lemma singleFunctorsPostcompQIso_inv_hom (n : ℤ) : + (singleFunctorsPostcompQIso C).inv.hom n = 𝟙 _ := by + ext X + dsimp [singleFunctorsPostcompQIso, HomotopyCategory.singleFunctorsPostcompQuotientIso, + quotientCompQhIso, HomologicalComplexUpToQuasiIso.quotientCompQhIso] + erw [CategoryTheory.Functor.map_id] + rw [SingleFunctors.id_hom, NatTrans.id_app] + erw [Category.id_comp, Category.id_comp] + rfl + end DerivedCategory diff --git a/Mathlib/Algebra/Homology/DerivedCategory/Ext.lean b/Mathlib/Algebra/Homology/DerivedCategory/Ext/Basic.lean similarity index 89% rename from Mathlib/Algebra/Homology/DerivedCategory/Ext.lean rename to Mathlib/Algebra/Homology/DerivedCategory/Ext/Basic.lean index cc231f472e59d..774df032bb48c 100644 --- a/Mathlib/Algebra/Homology/DerivedCategory/Ext.lean +++ b/Mathlib/Algebra/Homology/DerivedCategory/Ext/Basic.lean @@ -36,8 +36,7 @@ sheaves over `X` shall be in `Type u`. ## TODO * compute `Ext X Y 0` -* define the class in `Ext S.X₃ S.X₁ 1` of a short exact short complex `S` -* construct the long exact sequences of `Ext`. +* construct the contravariant long exact sequences of `Ext`. -/ @@ -47,7 +46,7 @@ namespace CategoryTheory variable (C : Type u) [Category.{v} C] [Abelian C] -open Localization Limits ZeroObject +open Localization Limits ZeroObject DerivedCategory Pretriangulated /-- The property that morphisms between single complexes in arbitrary degrees are `w`-small in the derived category. -/ @@ -58,14 +57,14 @@ abbrev HasExt : Prop := -- TODO: when the canonical t-structure is formalized, replace `n : ℤ` by `n : ℕ` lemma hasExt_iff [HasDerivedCategory.{w'} C] : HasExt.{w} C ↔ ∀ (X Y : C) (n : ℤ), Small.{w} - ((DerivedCategory.singleFunctor C 0).obj X ⟶ - (((DerivedCategory.singleFunctor C 0).obj Y)⟦n⟧)) := by + ((singleFunctor C 0).obj X ⟶ + (((singleFunctor C 0).obj Y)⟦n⟧)) := by dsimp [HasExt] - simp only [hasSmallLocalizedShiftedHom_iff _ _ DerivedCategory.Q] + simp only [hasSmallLocalizedShiftedHom_iff _ _ Q] constructor · intro h X Y n exact (small_congr ((shiftFunctorZero _ ℤ).app - ((DerivedCategory.singleFunctor C 0).obj X)).homFromEquiv).1 (h X Y 0 n) + ((singleFunctor C 0).obj X)).homFromEquiv).1 (h X Y 0 n) · intro h X Y a b refine (small_congr ?_).1 (h X Y (b - a)) exact (Functor.FullyFaithful.ofFullyFaithful @@ -103,6 +102,22 @@ lemma comp_assoc {a₁ a₂ a₃ a₁₂ a₂₃ a : ℕ} (α : Ext X Y a₁) ( α.comp (β.comp γ h₂₃) (by omega) := SmallShiftedHom.comp_assoc _ _ _ _ _ _ (by omega) +@[simp] +lemma comp_assoc_of_second_deg_zero + {a₁ a₃ a₁₃ : ℕ} (α : Ext X Y a₁) (β : Ext Y Z 0) (γ : Ext Z T a₃) + (h₁₃ : a₁ + a₃ = a₁₃) : + (α.comp β (add_zero _)).comp γ h₁₃ = α.comp (β.comp γ (zero_add _)) h₁₃ := by + apply comp_assoc + omega + +@[simp] +lemma comp_assoc_of_third_deg_zero + {a₁ a₂ a₁₂ : ℕ} (α : Ext X Y a₁) (β : Ext Y Z a₂) (γ : Ext Z T 0) + (h₁₂ : a₁ + a₂ = a₁₂) : + (α.comp β h₁₂).comp γ (add_zero _) = α.comp (β.comp γ (add_zero _)) h₁₂ := by + apply comp_assoc + omega + section variable [HasDerivedCategory.{w'} C] @@ -110,14 +125,13 @@ variable [HasDerivedCategory.{w'} C] /-- When an instance of `[HasDerivedCategory.{w'} C]` is available, this is the bijection between `Ext.{w} X Y n` and a type of morphisms in the derived category. -/ noncomputable def homEquiv {n : ℕ} : - Ext.{w} X Y n ≃ ShiftedHom ((DerivedCategory.singleFunctor C 0).obj X) - ((DerivedCategory.singleFunctor C 0).obj Y) (n : ℤ) := - SmallShiftedHom.equiv (HomologicalComplex.quasiIso C (ComplexShape.up ℤ)) DerivedCategory.Q + Ext.{w} X Y n ≃ ShiftedHom ((singleFunctor C 0).obj X) + ((singleFunctor C 0).obj Y) (n : ℤ) := + SmallShiftedHom.equiv (HomologicalComplex.quasiIso C (ComplexShape.up ℤ)) Q /-- The morphism in the derived category which corresponds to an element in `Ext X Y a`. -/ noncomputable abbrev hom {a : ℕ} (α : Ext X Y a) : - ShiftedHom ((DerivedCategory.singleFunctor C 0).obj X) - ((DerivedCategory.singleFunctor C 0).obj Y) (a : ℤ) := + ShiftedHom ((singleFunctor C 0).obj X) ((singleFunctor C 0).obj Y) (a : ℤ) := homEquiv α @[simp] @@ -137,7 +151,7 @@ noncomputable def mk₀ (f : X ⟶ Y) : Ext X Y 0 := SmallShiftedHom.mk₀ _ _ ( @[simp] lemma mk₀_hom [HasDerivedCategory.{w'} C] (f : X ⟶ Y) : - (mk₀ f).hom = ShiftedHom.mk₀ _ (by simp) ((DerivedCategory.singleFunctor C 0).map f) := by + (mk₀ f).hom = ShiftedHom.mk₀ _ (by simp) ((singleFunctor C 0).map f) := by apply SmallShiftedHom.equiv_mk₀ @[simp 1100] @@ -172,8 +186,7 @@ only in order to prove properties of the abelian group structure on `Ext`-groups Do not use this definition: use the more general `hom` instead. -/ noncomputable abbrev hom' (α : Ext X Y n) : letI := HasDerivedCategory.standard C - ShiftedHom ((DerivedCategory.singleFunctor C 0).obj X) - ((DerivedCategory.singleFunctor C 0).obj Y) (n : ℤ) := + ShiftedHom ((singleFunctor C 0).obj X) ((singleFunctor C 0).obj Y) (n : ℤ) := letI := HasDerivedCategory.standard C α.hom @@ -247,7 +260,7 @@ lemma biprod_ext {X₁ X₂ : C} {α β : Ext (X₁ ⊞ X₂) Y n} rw [Ext.ext_iff] at h₁ h₂ ⊢ simp only [comp_hom, mk₀_hom, ShiftedHom.mk₀_comp] at h₁ h₂ apply BinaryCofan.IsColimit.hom_ext - (isBinaryBilimitOfPreserves (DerivedCategory.singleFunctor C 0) + (isBinaryBilimitOfPreserves (singleFunctor C 0) (BinaryBiproduct.isBilimit X₁ X₂)).isColimit all_goals assumption @@ -289,8 +302,8 @@ lemma neg_hom (α : Ext X Y n) : (-α).hom = -α.hom := by /-- When an instance of `[HasDerivedCategory.{w'} C]` is available, this is the additive bijection between `Ext.{w} X Y n` and a type of morphisms in the derived category. -/ noncomputable def homAddEquiv {n : ℕ} : - Ext.{w} X Y n ≃+ ShiftedHom ((DerivedCategory.singleFunctor C 0).obj X) - ((DerivedCategory.singleFunctor C 0).obj Y) (n : ℤ) where + Ext.{w} X Y n ≃+ + ShiftedHom ((singleFunctor C 0).obj X) ((singleFunctor C 0).obj Y) (n : ℤ) where toEquiv := homEquiv map_add' := by simp 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 new file mode 100644 index 0000000000000..2869c7955e0c0 --- /dev/null +++ b/Mathlib/Algebra/Homology/DerivedCategory/Ext/ExtClass.lean @@ -0,0 +1,108 @@ +/- +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.DerivedCategory.Ext.Basic +import Mathlib.Algebra.Homology.DerivedCategory.SingleTriangle + +/-! +# The Ext class of a short exact sequence + +In this file, given a short exact short complex `S : ShortComplex C` +in an abelian category, we construct the associated class in +`Ext S.X₃ S.X₁ 1`. + +-/ + +universe w' w v u + +namespace CategoryTheory + +variable {C : Type u} [Category.{v} C] [Abelian C] [HasExt.{w} C] + +open Localization Limits ZeroObject DerivedCategory Pretriangulated + +open Abelian + +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} +variable (hS : S.ShortExact) + +section + +local notation "W" => HomologicalComplex.quasiIso C (ComplexShape.up ℤ) +local notation "S'" => S.map (CochainComplex.singleFunctor C 0) +local notation "hS'" => hS.map_of_exact (HomologicalComplex.single _ _ _) +local notation "K" => CochainComplex.mappingCone (ShortComplex.f S') +local notation "qis" => CochainComplex.mappingCone.descShortComplex S' +local notation "hqis" => CochainComplex.mappingCone.quasiIso_descShortComplex hS' +local notation "δ" => Triangle.mor₃ (CochainComplex.mappingCone.triangle (ShortComplex.f S')) + +instance : HasSmallLocalizedShiftedHom.{w} W ℤ (S').X₃ (S').X₁ := by + dsimp + infer_instance + +include hS in +private lemma hasSmallLocalizedHom_S'_X₃_K : + HasSmallLocalizedHom.{w} W (S').X₃ K := by + rw [Localization.hasSmallLocalizedHom_iff_target W (S').X₃ qis hqis] + dsimp + apply Localization.hasSmallLocalizedHom_of_hasSmallLocalizedShiftedHom₀ (M := ℤ) + +include hS in +private lemma hasSmallLocalizedShiftedHom_K_S'_X₁ : + HasSmallLocalizedShiftedHom.{w} W ℤ K (S').X₁ := by + rw [Localization.hasSmallLocalizedShiftedHom_iff_source.{w} W ℤ qis hqis (S').X₁] + infer_instance + +/-- The class in `Ext S.X₃ S.X₁ 1` that is attached to a short exact +short complex `S` in an abelian category. -/ +noncomputable def extClass : Ext.{w} S.X₃ S.X₁ 1 := by + have := hS.hasSmallLocalizedHom_S'_X₃_K + have := hS.hasSmallLocalizedShiftedHom_K_S'_X₁ + change SmallHom W (S').X₃ ((S').X₁⟦(1 : ℤ)⟧) + exact (SmallHom.mkInv qis hqis).comp (SmallHom.mk W δ) + +@[simp] +lemma extClass_hom [HasDerivedCategory.{w'} C] : hS.extClass.hom = hS.singleδ := by + change SmallShiftedHom.equiv W Q hS.extClass = _ + dsimp [extClass, SmallShiftedHom.equiv] + erw [SmallHom.equiv_comp, Iso.homToEquiv_apply] + rw [SmallHom.equiv_mkInv, SmallHom.equiv_mk] + dsimp [singleδ, triangleOfSESδ] + rw [Category.assoc, Category.assoc, Category.assoc, + singleFunctorsPostcompQIso_hom_hom, singleFunctorsPostcompQIso_inv_hom] + erw [Category.id_comp, Functor.map_id, Category.comp_id] + rfl + +end + +@[simp] +lemma comp_extClass : (Ext.mk₀ S.g).comp hS.extClass (zero_add 1) = 0 := by + letI := HasDerivedCategory.standard C + ext + simp only [Ext.comp_hom, Ext.mk₀_hom, extClass_hom, Ext.zero_hom, + ShiftedHom.mk₀_comp] + exact comp_distTriang_mor_zero₂₃ _ hS.singleTriangle_distinguished + +@[simp] +lemma extClass_comp : hS.extClass.comp (Ext.mk₀ S.f) (add_zero 1) = 0 := by + letI := HasDerivedCategory.standard C + ext + simp only [Ext.comp_hom, Ext.mk₀_hom, extClass_hom, Ext.zero_hom, + ShiftedHom.comp_mk₀] + exact comp_distTriang_mor_zero₃₁ _ hS.singleTriangle_distinguished + +end ShortExact + +end ShortComplex + +end CategoryTheory diff --git a/Mathlib/Algebra/Homology/DerivedCategory/HomologySequence.lean b/Mathlib/Algebra/Homology/DerivedCategory/HomologySequence.lean index 454e664b1fd81..2df568198c70f 100644 --- a/Mathlib/Algebra/Homology/DerivedCategory/HomologySequence.lean +++ b/Mathlib/Algebra/Homology/DerivedCategory/HomologySequence.lean @@ -45,7 +45,7 @@ instance (n : ℤ) : (homologyFunctor C n).IsHomological := (homologyFunctor C n) _ (homologyFunctorFactorsh C n) /-- The functors `homologyFunctor C n : DerivedCategory C ⥤ C` for all `n : ℤ` are part -of a "shift sequence", i.e. they satisfy compatiblities with shifts. -/ +of a "shift sequence", i.e. they satisfy compatibilities with shifts. -/ noncomputable instance : (homologyFunctor C 0).ShiftSequence ℤ := Functor.ShiftSequence.induced (homologyFunctorFactorsh C 0) ℤ (homologyFunctor C) (homologyFunctorFactorsh C) @@ -54,15 +54,14 @@ variable {C} namespace HomologySequence -variable (T : Triangle (DerivedCategory C)) (hT : T ∈ distTriang _) - (n₀ n₁ : ℤ) (h : n₀ + 1 = n₁) -include hT - /-- The connecting homomorphism on the homology sequence attached to a distinguished triangle in the derived category. -/ -noncomputable def δ : (homologyFunctor C n₀).obj T.obj₃ ⟶ (homologyFunctor C n₁).obj T.obj₁ := +noncomputable def δ (T : Triangle (DerivedCategory C)) + (n₀ n₁ : ℤ) (h : n₀ + 1 = n₁) : + (homologyFunctor C n₀).obj T.obj₃ ⟶ (homologyFunctor C n₁).obj T.obj₁ := (homologyFunctor C 0).shiftMap T.mor₃ n₀ n₁ (by rw [add_comm 1, h]) +variable (T : Triangle (DerivedCategory C)) (hT : T ∈ distTriang _) (n₀ n₁ : ℤ) (h : n₀ + 1 = n₁) include hT @[reassoc (attr := simp)] 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/Embedding/Basic.lean b/Mathlib/Algebra/Homology/Embedding/Basic.lean index 38d9eed123c27..5408a2e292f45 100644 --- a/Mathlib/Algebra/Homology/Embedding/Basic.lean +++ b/Mathlib/Algebra/Homology/Embedding/Basic.lean @@ -52,7 +52,7 @@ namespace ComplexShape /-- An embedding of a complex shape `c : ComplexShape ι` into a complex shape `c' : ComplexShape ι'` consists of a injective map `f : ι → ι'` which satisfies -a compatiblity with respect to the relations `c.Rel` and `c'.Rel`. -/ +a compatibility with respect to the relations `c.Rel` and `c'.Rel`. -/ structure Embedding where /-- the map between the underlying types of indices -/ f : ι → ι' diff --git a/Mathlib/Algebra/Homology/Embedding/HomEquiv.lean b/Mathlib/Algebra/Homology/Embedding/HomEquiv.lean new file mode 100644 index 0000000000000..ae8a61b3f4536 --- /dev/null +++ b/Mathlib/Algebra/Homology/Embedding/HomEquiv.lean @@ -0,0 +1,211 @@ +/- +Copyright (c) 2024 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +import Mathlib.Algebra.Homology.Embedding.Restriction +import Mathlib.Algebra.Homology.Embedding.Extend +import Mathlib.Algebra.Homology.Embedding.Boundary +import Mathlib.CategoryTheory.MorphismProperty.Basic + +/-! +# Relations between `extend` and `restriction` + +Given an embedding `e : Embedding c c'` of complex shapes satisfying `e.IsRelIff`, +we obtain a bijection `e.homEquiv` between the type of morphisms +`K ⟶ L.extend e` (with `K : HomologicalComplex C c'` and `L : HomologicalComplex C c`) +and the subtype of morphisms `φ : K.restriction e ⟶ L` which satisfy a certain +condition `e.HasLift φ`. + +## TODO +* obtain dual results for morphisms `L.extend e ⟶ K`. + +-/ + +open CategoryTheory Category Limits + +namespace ComplexShape + +variable {ι ι' : Type*} {c : ComplexShape ι} {c' : ComplexShape ι'} (e : Embedding c c') + {C : Type*} [Category C] [HasZeroMorphisms C] [HasZeroObject C] + +namespace Embedding + +open HomologicalComplex + +variable {K K' : HomologicalComplex C c'} {L L' : HomologicalComplex C c} + [e.IsRelIff] + +section + +/-- The condition on a morphism `K.restriction e ⟶ L` which allows to +extend it as a morphism `K ⟶ L.extend e`, see `Embedding.homEquiv`. -/ +def HasLift (φ : K.restriction e ⟶ L) : Prop := + ∀ (j : ι) (_ : e.BoundaryGE j) (i' : ι') + (_ : c'.Rel i' (e.f j)), K.d i' _ ≫ φ.f j = 0 + +namespace liftExtend + +variable (φ : K.restriction e ⟶ L) + +variable {e} + +open Classical in +/-- Auxiliary definition for `liftExtend`. -/ +noncomputable def f (i' : ι') : K.X i' ⟶ (L.extend e).X i' := + if hi' : ∃ i, e.f i = i' then + (K.restrictionXIso e hi'.choose_spec).inv ≫ φ.f hi'.choose ≫ + (L.extendXIso e hi'.choose_spec).inv + else 0 + +lemma f_eq {i' : ι'} {i : ι} (hi : e.f i = i') : + f φ i' = (K.restrictionXIso e hi).inv ≫ φ.f i ≫ (L.extendXIso e hi).inv := by + have hi' : ∃ k, e.f k = i' := ⟨i, hi⟩ + have : hi'.choose = i := e.injective_f (by rw [hi'.choose_spec, hi]) + dsimp [f] + rw [dif_pos ⟨i, hi⟩] + subst this + rfl + +@[reassoc (attr := simp)] +lemma comm (hφ : e.HasLift φ) (i' j' : ι') : + f φ i' ≫ (L.extend e).d i' j' = K.d i' j' ≫ f φ j' := by + by_cases hij' : c'.Rel i' j' + · by_cases hi' : ∃ i, e.f i = i' + · obtain ⟨i, hi⟩ := hi' + rw [f_eq φ hi] + by_cases hj' : ∃ j, e.f j = j' + · obtain ⟨j, hj⟩ := hj' + rw [f_eq φ hj, L.extend_d_eq e hi hj] + subst hi hj + simp [HomologicalComplex.restrictionXIso] + · apply (L.isZero_extend_X e j' (by simpa using hj')).eq_of_tgt + · have : (L.extend e).d i' j' = 0 := by + apply (L.isZero_extend_X e i' (by simpa using hi')).eq_of_src + rw [this, comp_zero] + by_cases hj' : ∃ j, e.f j = j' + · obtain ⟨j, rfl⟩ := hj' + rw [f_eq φ rfl] + dsimp [restrictionXIso] + rw [id_comp, reassoc_of% (hφ j (e.boundaryGE hij' + (by simpa using hi')) i' hij'), zero_comp] + · have : f φ j' = 0 := by + apply (L.isZero_extend_X e j' (by simpa using hj')).eq_of_tgt + rw [this, comp_zero] + · simp [HomologicalComplex.shape _ _ _ hij'] + +end liftExtend + +variable (φ : K.restriction e ⟶ L) (hφ : e.HasLift φ) + +/-- The morphism `K ⟶ L.extend e` given by a morphism `K.restriction e ⟶ L` +which satisfy `e.HasLift φ`. -/ +noncomputable def liftExtend : + K ⟶ L.extend e where + f i' := liftExtend.f φ i' + comm' _ _ _ := liftExtend.comm φ hφ _ _ + +variable {i' : ι'} {i : ι} (hi : e.f i = i') + +lemma liftExtend_f : + (e.liftExtend φ hφ).f i' = (K.restrictionXIso e hi).inv ≫ φ.f i ≫ + (L.extendXIso e hi).inv := by + apply liftExtend.f_eq + +/-- Given `φ : K.restriction e ⟶ L` such that `hφ : e.HasLift φ`, this is +the isomorphisms in the category of arrows between the maps +`(e.liftExtend φ hφ).f i'` and `φ.f i` when `e.f i = i'`. -/ +noncomputable def liftExtendfArrowIso : + Arrow.mk ((e.liftExtend φ hφ).f i') ≅ Arrow.mk (φ.f i) := + Arrow.isoMk (K.restrictionXIso e hi).symm (L.extendXIso e hi) + (by simp [e.liftExtend_f φ hφ hi]) + +lemma isIso_liftExtend_f_iff (hi : e.f i = i') : + IsIso ((e.liftExtend φ hφ).f i') ↔ IsIso (φ.f i) := + (MorphismProperty.isomorphisms C).arrow_mk_iso_iff (e.liftExtendfArrowIso φ hφ hi) + +lemma mono_liftExtend_f_iff (hi : e.f i = i') : + Mono ((e.liftExtend φ hφ).f i') ↔ Mono (φ.f i) := + (MorphismProperty.monomorphisms C).arrow_mk_iso_iff (e.liftExtendfArrowIso φ hφ hi) + +lemma epi_liftExtend_f_iff (hi : e.f i = i') : + Epi ((e.liftExtend φ hφ).f i') ↔ Epi (φ.f i) := + (MorphismProperty.epimorphisms C).arrow_mk_iso_iff (e.liftExtendfArrowIso φ hφ hi) + +end + +namespace homRestrict + +variable {e} +variable (ψ : K ⟶ L.extend e) + +/-- Auxiliary definition for `Embedding.homRestrict`. -/ +noncomputable def f (i : ι) : (K.restriction e).X i ⟶ L.X i := + ψ.f (e.f i) ≫ (L.extendXIso e rfl).hom + +lemma f_eq {i : ι} {i' : ι'} (h : e.f i = i') : + f ψ i = (K.restrictionXIso e h).hom ≫ ψ.f i' ≫ (L.extendXIso e h).hom := by + subst h + simp [f, restrictionXIso] + +@[reassoc (attr := simp)] +lemma comm (i j : ι) : + f ψ i ≫ L.d i j = K.d (e.f i) (e.f j) ≫ f ψ j := by + dsimp [f] + simp only [assoc, ← ψ.comm_assoc, L.extend_d_eq e rfl rfl, Iso.inv_hom_id, comp_id] + +end homRestrict + +/-- The morphism `K.restriction e ⟶ L` induced by a morphism `K ⟶ L.extend e`. -/ +noncomputable def homRestrict (ψ : K ⟶ L.extend e) : K.restriction e ⟶ L where + f i := homRestrict.f ψ i + +lemma homRestrict_f (ψ : K ⟶ L.extend e) {i : ι} {i' : ι'} (h : e.f i = i') : + (e.homRestrict ψ).f i = (K.restrictionXIso e h).hom ≫ ψ.f i' ≫ (L.extendXIso e h).hom := + homRestrict.f_eq ψ h + +lemma homRestrict_hasLift (ψ : K ⟶ L.extend e) : + e.HasLift (e.homRestrict ψ) := by + intro j hj i' hij' + have : (L.extend e).d i' (e.f j) = 0 := by + apply (L.isZero_extend_X e i' (hj.not_mem hij')).eq_of_src + dsimp [homRestrict] + rw [homRestrict.f_eq ψ rfl, restrictionXIso, eqToIso_refl, Iso.refl_hom, id_comp, + ← ψ.comm_assoc, this, zero_comp, comp_zero] + +@[simp] +lemma liftExtend_homRestrict (ψ : K ⟶ L.extend e) : + e.liftExtend (e.homRestrict ψ) (e.homRestrict_hasLift ψ) = ψ := by + ext i' + by_cases hi' : ∃ i, e.f i = i' + · obtain ⟨i, rfl⟩ := hi' + simp [e.homRestrict_f _ rfl, e.liftExtend_f _ _ rfl] + · apply (L.isZero_extend_X e i' (by simpa using hi')).eq_of_tgt + +@[simp] +lemma homRestrict_liftExtend (φ : K.restriction e ⟶ L) (hφ : e.HasLift φ) : + e.homRestrict (e.liftExtend φ hφ) = φ := by + ext i + simp [e.homRestrict_f _ rfl, e.liftExtend_f _ _ rfl] + +@[reassoc] +lemma homRestrict_precomp (α : K' ⟶ K) (ψ : K ⟶ L.extend e) : + e.homRestrict (α ≫ ψ) = restrictionMap α e ≫ e.homRestrict ψ := by + ext i + simp [homRestrict_f _ _ rfl, restrictionXIso] + +variable (K L) + +/-- The bijection between `K ⟶ L.extend e` and the subtype of `K.restriction e ⟶ L` +consisting of morphisms `φ` such that `e.HasLift φ`. -/ +@[simps] +noncomputable def homEquiv : + (K ⟶ L.extend e) ≃ { φ : K.restriction e ⟶ L // e.HasLift φ } where + toFun ψ := ⟨e.homRestrict ψ, e.homRestrict_hasLift ψ⟩ + invFun φ := e.liftExtend φ.1 φ.2 + left_inv ψ := by simp + right_inv φ := by simp + +end Embedding + +end ComplexShape diff --git a/Mathlib/Algebra/Homology/Embedding/TruncGE.lean b/Mathlib/Algebra/Homology/Embedding/TruncGE.lean index 3cfeee56bada8..c0c9a8b3cbd18 100644 --- a/Mathlib/Algebra/Homology/Embedding/TruncGE.lean +++ b/Mathlib/Algebra/Homology/Embedding/TruncGE.lean @@ -110,8 +110,8 @@ noncomputable def truncGE'XIsoOpcycles {i : ι} {i' : ι'} (hi' : e.f i = i') (h (K.truncGE' e).X i ≅ K.opcycles i' := (truncGE'.XIsoOpcycles K e hi) ≪≫ eqToIso (by subst hi'; rfl) -lemma truncGE'_d_eq {i j : ι} (hij : c.Rel i j) {i' j' : ι'} - (hi' : e.f i = i') (hj' : e.f j = j') (hi : ¬ e.BoundaryGE i) : +lemma truncGE'_d_eq {i j : ι} (hij : c.Rel i j) {i' j' : ι'} + (hi' : e.f i = i') (hj' : e.f j = j') (hi : ¬ e.BoundaryGE i) : (K.truncGE' e).d i j = (K.truncGE'XIso e hi' hi).hom ≫ K.d i' j' ≫ (K.truncGE'XIso e hj' (e.not_boundaryGE_next hij)).inv := by dsimp [truncGE', truncGE'.d] diff --git a/Mathlib/Algebra/Homology/ExactSequence.lean b/Mathlib/Algebra/Homology/ExactSequence.lean index 0afb27611c949..bf8559ea76f1a 100644 --- a/Mathlib/Algebra/Homology/ExactSequence.lean +++ b/Mathlib/Algebra/Homology/ExactSequence.lean @@ -159,7 +159,7 @@ lemma exact_iff_of_iso {S₁ S₂ : ComposableArrows C n} (e : S₁ ≅ S₂) : lemma exact₀ (S : ComposableArrows C 0) : S.Exact where toIsComplex := S.isComplex₀ -- See https://github.com/leanprover/lean4/issues/2862 - exact i hi := by simp [autoParam] at hi + exact i hi := by simp at hi lemma exact₁ (S : ComposableArrows C 1) : S.Exact where toIsComplex := S.isComplex₁ diff --git a/Mathlib/Algebra/Homology/HomologicalBicomplex.lean b/Mathlib/Algebra/Homology/HomologicalBicomplex.lean index c693b7880842a..dbd85f9d8e710 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 @@ -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..2494b21c2eb58 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 diff --git a/Mathlib/Algebra/Homology/HomologySequence.lean b/Mathlib/Algebra/Homology/HomologySequence.lean index 7a54cb2191c0a..6a325db2f53a9 100644 --- a/Mathlib/Algebra/Homology/HomologySequence.lean +++ b/Mathlib/Algebra/Homology/HomologySequence.lean @@ -230,7 +230,8 @@ obtained by applying the functors `homologyFunctor C c i`, `opcyclesFunctor C c `cyclesFunctor C c j`, `homologyFunctor C c j` to `S`. Applying the snake lemma to this gives the homology sequence of `S`. -/ @[simps] -noncomputable def snakeInput : ShortComplex.SnakeInput C where +noncomputable def snakeInput (hS : S.ShortExact) (i j : ι) (hij : c.Rel i j) : + ShortComplex.SnakeInput C where L₀ := (homologyFunctor C c i).mapShortComplex.obj S L₁ := (opcyclesFunctor C c i).mapShortComplex.obj S L₂ := (cyclesFunctor C c j).mapShortComplex.obj S @@ -282,7 +283,7 @@ namespace ShortComplex namespace ShortExact /-- The connecting homoomorphism `S.X₃.homology i ⟶ S.X₁.homology j` for a short exact -short complex `S`. -/ +short complex `S`. -/ noncomputable def δ : S.X₃.homology i ⟶ S.X₁.homology j := (snakeInput hS i j hij).δ @[reassoc (attr := simp)] diff --git a/Mathlib/Algebra/Homology/HomologySequenceLemmas.lean b/Mathlib/Algebra/Homology/HomologySequenceLemmas.lean index acf08cce2512f..26d1411fed80d 100644 --- a/Mathlib/Algebra/Homology/HomologySequenceLemmas.lean +++ b/Mathlib/Algebra/Homology/HomologySequenceLemmas.lean @@ -103,8 +103,6 @@ noncomputable def mapComposableArrows₅ (i j : ι) (hij : c.Rel i j) : (naturality' (mapComposableArrows₂ φ j) 0 1) (naturality' (mapComposableArrows₂ φ j) 1 2) -attribute [local instance] epi_comp - include hS₁ hS₂ lemma mono_homologyMap_τ₃ (i : ι) diff --git a/Mathlib/Algebra/Homology/Homotopy.lean b/Mathlib/Algebra/Homology/Homotopy.lean index bc2fd8fdf31ef..f8c43c0d2b844 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 @@ -101,7 +101,7 @@ theorem dNext_nat (C D : ChainComplex V ℕ) (i : ℕ) (f : ∀ i j, C.X i ⟶ D dsimp [dNext] cases i · simp only [shape, ChainComplex.next_nat_zero, ComplexShape.down_Rel, Nat.one_ne_zero, - not_false_iff, zero_comp] + not_false_iff, zero_comp, reduceCtorEq] · congr <;> simp theorem prevD_nat (C D : CochainComplex V ℕ) (i : ℕ) (f : ∀ i j, C.X i ⟶ D.X j) : @@ -109,7 +109,7 @@ theorem prevD_nat (C D : CochainComplex V ℕ) (i : ℕ) (f : ∀ i j, C.X i ⟶ dsimp [prevD] cases i · simp only [shape, CochainComplex.prev_nat_zero, ComplexShape.up_Rel, Nat.one_ne_zero, - not_false_iff, comp_zero] + not_false_iff, comp_zero, reduceCtorEq] · congr <;> simp -- Porting note(#5171): removed @[has_nonempty_instance] 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/MappingCone.lean b/Mathlib/Algebra/Homology/HomotopyCategory/MappingCone.lean index 41a763809646d..42704741a95dc 100644 --- a/Mathlib/Algebra/Homology/HomotopyCategory/MappingCone.lean +++ b/Mathlib/Algebra/Homology/HomotopyCategory/MappingCone.lean @@ -51,7 +51,7 @@ open HomComplex /-- The left inclusion in the mapping cone, as a cochain of degree `-1`. -/ noncomputable def inl : Cochain F (mappingCone φ) (-1) := - Cochain.mk (fun p q hpq => homotopyCofiber.inlX φ p q (by dsimp; omega)) + Cochain.mk (fun p q hpq => homotopyCofiber.inlX φ p q (by dsimp; omega)) /-- The right inclusion in the mapping cone. -/ noncomputable def inr : G ⟶ mappingCone φ := homotopyCofiber.inr φ @@ -286,14 +286,16 @@ lemma δ_snd : section -variable {K : CochainComplex C ℤ} {n m : ℤ} (α : Cochain F K m) - (β : Cochain G K n) (h : m + 1 = n) +variable {K : CochainComplex C ℤ} {n m : ℤ} /-- Given `φ : F ⟶ G`, this is the cochain in `Cochain (mappingCone φ) K n` that is constructed from two cochains `α : Cochain F K m` (with `m + 1 = n`) and `β : Cochain F K n`. -/ -noncomputable def descCochain : Cochain (mappingCone φ) K n := +noncomputable def descCochain (α : Cochain F K m) (β : Cochain G K n) (h : m + 1 = n) : + Cochain (mappingCone φ) K n := (fst φ).1.comp α (by rw [← h, add_comm]) + (snd φ).comp β (zero_add n) +variable (α : Cochain F K m) (β : Cochain G K n) (h : m + 1 = n) + @[simp] lemma inl_descCochain : (inl φ).comp (descCochain φ α β h) (by omega) = α := by @@ -346,15 +348,17 @@ noncomputable def descCocycle {K : CochainComplex C ℤ} {n m : ℤ} section -variable {K : CochainComplex C ℤ} (α : Cochain F K (-1)) (β : G ⟶ K) - (eq : δ (-1) 0 α = Cochain.ofHom (φ ≫ β)) +variable {K : CochainComplex C ℤ} /-- Given `φ : F ⟶ G`, this is the morphism `mappingCone φ ⟶ K` that is constructed from a cochain `α : Cochain F K (-1)` and a morphism `β : G ⟶ K` such that `δ (-1) 0 α = Cochain.ofHom (φ ≫ β)`. -/ -noncomputable def desc : mappingCone φ ⟶ K := +noncomputable def desc (α : Cochain F K (-1)) (β : G ⟶ K) + (eq : δ (-1) 0 α = Cochain.ofHom (φ ≫ β)) : mappingCone φ ⟶ K := Cocycle.homOf (descCocycle φ α (Cocycle.ofHom β) (neg_add_cancel 1) (by simp [eq])) +variable (α : Cochain F K (-1)) (β : G ⟶ K) (eq : δ (-1) 0 α = Cochain.ofHom (φ ≫ β)) + @[simp] lemma ofHom_desc : Cochain.ofHom (desc φ α β eq) = descCochain φ α (Cochain.ofHom β) (neg_add_cancel 1) := by @@ -400,13 +404,15 @@ noncomputable def descHomotopy {K : CochainComplex C ℤ} (f₁ f₂ : mappingCo section variable {K : CochainComplex C ℤ} {n m : ℤ} - (α : Cochain K F m) (β : Cochain K G n) (h : n + 1 = m) /-- Given `φ : F ⟶ G`, this is the cochain in `Cochain (mappingCone φ) K n` that is constructed from two cochains `α : Cochain F K m` (with `m + 1 = n`) and `β : Cochain F K n`. -/ -noncomputable def liftCochain : Cochain K (mappingCone φ) n := +noncomputable def liftCochain (α : Cochain K F m) (β : Cochain K G n) (h : n + 1 = m) : + Cochain K (mappingCone φ) n := α.comp (inl φ) (by omega) + β.comp (Cochain.ofHom (inr φ)) (add_zero n) +variable (α : Cochain K F m) (β : Cochain K G n) (h : n + 1 = m) + @[simp] lemma liftCochain_fst : (liftCochain φ α β h).comp (fst φ).1 h = α := by diff --git a/Mathlib/Algebra/Homology/HomotopyCategory/Pretriangulated.lean b/Mathlib/Algebra/Homology/HomotopyCategory/Pretriangulated.lean index 0ad80b275377d..d5e210fe2d0c1 100644 --- a/Mathlib/Algebra/Homology/HomotopyCategory/Pretriangulated.lean +++ b/Mathlib/Algebra/Homology/HomotopyCategory/Pretriangulated.lean @@ -125,14 +125,15 @@ end mapOfHomotopy section map variable {K₁ L₁ K₂ L₂ K₃ L₃ : CochainComplex C ℤ} (φ₁ : K₁ ⟶ L₁) (φ₂ : K₂ ⟶ L₂) (φ₃ : K₃ ⟶ L₃) - (a : K₁ ⟶ K₂) (b : L₁ ⟶ L₂) (comm : φ₁ ≫ b = a ≫ φ₂) - (a' : K₂ ⟶ K₃) (b' : L₂ ⟶ L₃) (comm' : φ₂ ≫ b' = a' ≫ φ₃) + (a : K₁ ⟶ K₂) (b : L₁ ⟶ L₂) /-- The morphism `mappingCone φ₁ ⟶ mappingCone φ₂` that is induced by a commutative square. -/ -noncomputable def map : mappingCone φ₁ ⟶ mappingCone φ₂ := +noncomputable def map (comm : φ₁ ≫ b = a ≫ φ₂) : mappingCone φ₁ ⟶ mappingCone φ₂ := desc φ₁ ((Cochain.ofHom a).comp (inl φ₂) (zero_add _)) (b ≫ inr φ₂) (by simp [reassoc_of% comm]) +variable (comm : φ₁ ≫ b = a ≫ φ₂) + lemma map_eq_mapOfHomotopy : map φ₁ φ₂ a b comm = mapOfHomotopy (Homotopy.ofEq comm) := by simp [map, mapOfHomotopy] @@ -140,9 +141,12 @@ lemma map_id : map φ φ (𝟙 _) (𝟙 _) (by rw [id_comp, comp_id]) = 𝟙 _ : ext n simp [ext_from_iff _ (n + 1) n rfl, map] +variable (a' : K₂ ⟶ K₃) (b' : L₂ ⟶ L₃) + @[reassoc] -lemma map_comp : map φ₁ φ₃ (a ≫ a') (b ≫ b') (by rw [reassoc_of% comm, comm', assoc]) = - map φ₁ φ₂ a b comm ≫ map φ₂ φ₃ a' b' comm' := by +lemma map_comp (comm' : φ₂ ≫ b' = a' ≫ φ₃) : + map φ₁ φ₃ (a ≫ a') (b ≫ b') (by rw [reassoc_of% comm, comm', assoc]) = + map φ₁ φ₂ a b comm ≫ map φ₂ φ₃ a' b' comm' := by ext n simp [ext_from_iff _ (n+1) n rfl, map] diff --git a/Mathlib/Algebra/Homology/HomotopyCategory/Shift.lean b/Mathlib/Algebra/Homology/HomotopyCategory/Shift.lean index 9341e60b09122..01810e1dc41e4 100644 --- a/Mathlib/Algebra/Homology/HomotopyCategory/Shift.lean +++ b/Mathlib/Algebra/Homology/HomotopyCategory/Shift.lean @@ -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] 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 88c9ce69aaee4..dfbe3a72907ca 100644 --- a/Mathlib/Algebra/Homology/HomotopyCofiber.lean +++ b/Mathlib/Algebra/Homology/HomotopyCofiber.lean @@ -240,10 +240,8 @@ noncomputable def inr : G ⟶ homotopyCofiber φ where section -variable (hc : ∀ j, ∃ i, c.Rel i j) - /-- The composition `φ ≫ mappingCone.inr φ` is homotopic to `0`. -/ -noncomputable def inrCompHomotopy : +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 @@ -258,6 +256,8 @@ noncomputable def inrCompHomotopy : · rw [dNext_eq_zero _ _ hj, zero_add, zero_f, add_zero, homotopyCofiber_d, inlX_d' _ _ _ _ hj, comp_f, inr_f] +variable (hc : ∀ j, ∃ i, c.Rel i j) + lemma inrCompHomotopy_hom (i j : ι) (hij : c.Rel j i) : (inrCompHomotopy φ hc).hom i j = inlX φ i j hij := dif_pos hij diff --git a/Mathlib/Algebra/Homology/ImageToKernel.lean b/Mathlib/Algebra/Homology/ImageToKernel.lean index 7ab7f5ff1347d..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 @@ -147,7 +147,7 @@ instance imageToKernel_epi_of_epi_of_zero [HasImages V] [Epi f] : simp only [imageToKernel_zero_right] haveI := epi_image_of_epi f rw [← imageSubobject_arrow] - exact @epi_comp _ _ _ _ _ _ (epi_comp _ _) _ _ + infer_instance end diff --git a/Mathlib/Algebra/Homology/LocalCohomology.lean b/Mathlib/Algebra/Homology/LocalCohomology.lean index 77e73c476b11a..4ea0bfce99d36 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 @@ -201,7 +201,7 @@ def idealPowersToSelfLERadical (J : Ideal R) : ℕᵒᵖ ⥤ SelfLERadical J := FullSubcategory.lift _ (idealPowersDiagram J) fun k => by change _ ≤ (J ^ unop k).radical cases' unop k with n - · simp [Ideal.radical_top, pow_zero, Ideal.one_eq_top, le_top, Nat.zero_eq] + · simp [Ideal.radical_top, pow_zero, Ideal.one_eq_top, le_top] · simp only [J.radical_pow n.succ_ne_zero, Ideal.le_radical] variable {I J K : Ideal R} @@ -232,8 +232,8 @@ instance ideal_powers_initial [hR : IsNoetherian R R] : -- 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/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..474f801a48272 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/Ab.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/Ab.lean @@ -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 diff --git a/Mathlib/Algebra/Homology/ShortComplex/ExactFunctor.lean b/Mathlib/Algebra/Homology/ShortComplex/ExactFunctor.lean index feb861d1e0060..d61079ee62930 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/ExactFunctor.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/ExactFunctor.lean @@ -112,24 +112,24 @@ lemma preservesFiniteLimits_tfae : List.TFAE [ ∀ (S : ShortComplex C), S.ShortExact → (S.map F).Exact ∧ Mono (F.map S.f), ∀ (S : ShortComplex C), S.Exact ∧ Mono S.f → (S.map F).Exact ∧ Mono (F.map S.f), - ∀ ⦃X Y : C⦄ (f : X ⟶ Y), Nonempty $ PreservesLimit (parallelPair f 0) F, - Nonempty $ PreservesFiniteLimits F + ∀ ⦃X Y : C⦄ (f : X ⟶ Y), Nonempty <| PreservesLimit (parallelPair f 0) F, + 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) let φ : T.map F ⟶ S.map F := { τ₁ := 𝟙 _ τ₂ := 𝟙 _ - τ₃ := F.map $ Abelian.factorThruCoimage S.g + τ₃ := F.map <| Abelian.factorThruCoimage S.g comm₂₃ := show 𝟙 _ ≫ F.map _ = F.map (cokernel.π _) ≫ _ by rw [Category.id_comp, ← F.map_comp, cokernel.π_desc] } 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 @@ -171,16 +171,16 @@ lemma preservesFiniteColimits_tfae : List.TFAE [ ∀ (S : ShortComplex C), S.ShortExact → (S.map F).Exact ∧ Epi (F.map S.g), ∀ (S : ShortComplex C), S.Exact ∧ Epi S.g → (S.map F).Exact ∧ Epi (F.map S.g), - ∀ ⦃X Y : C⦄ (f : X ⟶ Y), Nonempty $ PreservesColimit (parallelPair f 0) F, - Nonempty $ PreservesFiniteColimits F + ∀ ⦃X Y : C⦄ (f : X ⟶ Y), Nonempty <| PreservesColimit (parallelPair f 0) F, + 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) let φ : S.map F ⟶ T.map F := - { τ₁ := F.map $ Abelian.factorThruImage S.f + { τ₁ := F.map <| Abelian.factorThruImage S.f τ₂ := 𝟙 _ τ₃ := 𝟙 _ comm₁₂ := show _ ≫ F.map (kernel.ι _) = F.map _ ≫ 𝟙 _ by @@ -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,21 +233,19 @@ lemma exact_tfae : List.TFAE exact h f |>.some tfae_have 2 → 1 - · intro hF S hS - 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 $ - hF (.mk S.g (0 : S.X₃ ⟶ 0) $ by simp) (exact_iff_epi _ (by simp) |>.2 hS.epi_g) + | 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 <| + hF (.mk S.g (0 : S.X₃ ⟶ 0) <| by simp) (exact_iff_epi _ (by simp) |>.2 hS.epi_g) 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/HomologicalComplex.lean b/Mathlib/Algebra/Homology/ShortComplex/HomologicalComplex.lean index c14da91511cae..fb3e8617e352d 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/HomologicalComplex.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/HomologicalComplex.lean @@ -318,8 +318,6 @@ lemma p_opcyclesMap : K.pOpcycles i ≫ opcyclesMap φ i = φ.f i ≫ L.pOpcycle instance [Mono (φ.f i)] : Mono (cyclesMap φ i) := mono_of_mono_fac (cyclesMap_i φ i) -attribute [local instance] epi_comp - instance [Epi (φ.f i)] : Epi (opcyclesMap φ i) := epi_of_epi_fac (p_opcyclesMap φ i) variable (K) diff --git a/Mathlib/Algebra/Homology/ShortComplex/LeftHomology.lean b/Mathlib/Algebra/Homology/ShortComplex/LeftHomology.lean index 1d91f59bef1b9..1022a52c7ab90 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/LeftHomology.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/LeftHomology.lean @@ -388,10 +388,10 @@ section variable (S) variable [S.HasLeftHomology] -/-- The left homology of a short complex, given by the `H` field of a chosen left homology data. -/ +/-- The left homology of a short complex, given by the `H` field of a chosen left homology data. -/ noncomputable def leftHomology : C := S.leftHomologyData.H -/-- The cycles of a short complex, given by the `K` field of a chosen left homology data. -/ +/-- The cycles of a short complex, given by the `K` field of a chosen left homology data. -/ noncomputable def cycles : C := S.leftHomologyData.K /-- The "homology class" map `S.cycles ⟶ S.leftHomology`. -/ 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/Preadditive.lean b/Mathlib/Algebra/Homology/ShortComplex/Preadditive.lean index dee25030965f5..8d23c46c9a207 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/Preadditive.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/Preadditive.lean @@ -451,7 +451,7 @@ def add (h : Homotopy φ₁ φ₂) (h' : Homotopy φ₃ φ₄) : Homotopy (φ₁ comm₂ := by rw [add_τ₂, add_τ₂, h.comm₂, h'.comm₂, comp_add, add_comp]; abel comm₃ := by rw [add_τ₃, add_τ₃, h.comm₃, h'.comm₃, add_comp]; abel -/-- Homotopy between morphisms of short complexes is compatible with substraction. -/ +/-- Homotopy between morphisms of short complexes is compatible with subtraction. -/ @[simps] def sub (h : Homotopy φ₁ φ₂) (h' : Homotopy φ₃ φ₄) : Homotopy (φ₁ - φ₃) (φ₂ - φ₄) where h₀ := h.h₀ - h'.h₀ @@ -508,7 +508,7 @@ def op (h : Homotopy φ₁ φ₂) : Homotopy (opMap φ₁) (opMap φ₂) where /-- The homotopy between morphisms in `ShortComplex C` that is induced by a homotopy between morphisms in `ShortComplex Cᵒᵖ`. -/ @[simps] -def unop {S₁ S₂ : ShortComplex Cᵒᵖ} {φ₁ φ₂ : S₁ ⟶ S₂} (h : Homotopy φ₁ φ₂) : +def unop {S₁ S₂ : ShortComplex Cᵒᵖ} {φ₁ φ₂ : S₁ ⟶ S₂} (h : Homotopy φ₁ φ₂) : Homotopy (unopMap φ₁) (unopMap φ₂) where h₀ := h.h₃.unop h₁ := h.h₂.unop diff --git a/Mathlib/Algebra/Homology/ShortComplex/RightHomology.lean b/Mathlib/Algebra/Homology/ShortComplex/RightHomology.lean index 5a62395fcb632..865ffa00b94fb 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/RightHomology.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/RightHomology.lean @@ -1004,7 +1004,7 @@ variable (φ : S₁ ⟶ S₂) (h : RightHomologyData S₁) [Epi φ.τ₁] [IsIso /-- If `φ : S₁ ⟶ S₂` is a morphism of short complexes such that `φ.τ₁` is epi, `φ.τ₂` is an iso and `φ.τ₃` is mono, then a right homology data for `S₁` induces a right homology data for `S₂` with the same `Q` and `H` fields. This is obtained by dualising `LeftHomologyData.ofEpiOfIsIsoOfMono'`. -The inverse construction is `ofEpiOfIsIsoOfMono'`. -/ +The inverse construction is `ofEpiOfIsIsoOfMono'`. -/ noncomputable def ofEpiOfIsIsoOfMono : RightHomologyData S₂ := by haveI : Epi (opMap φ).τ₁ := by dsimp; infer_instance haveI : IsIso (opMap φ).τ₂ := by dsimp; infer_instance @@ -1032,7 +1032,7 @@ variable (φ : S₁ ⟶ S₂) (h : RightHomologyData S₂) [Epi φ.τ₁] [IsIso /-- If `φ : S₁ ⟶ S₂` is a morphism of short complexes such that `φ.τ₁` is epi, `φ.τ₂` is an iso and `φ.τ₃` is mono, then a right homology data for `S₂` induces a right homology data for `S₁` with the same `Q` and `H` fields. This is obtained by dualising `LeftHomologyData.ofEpiOfIsIsoOfMono`. -The inverse construction is `ofEpiOfIsIsoOfMono`. -/ +The inverse construction is `ofEpiOfIsIsoOfMono`. -/ noncomputable def ofEpiOfIsIsoOfMono' : RightHomologyData S₁ := by haveI : Epi (opMap φ).τ₁ := by dsimp; infer_instance haveI : IsIso (opMap φ).τ₂ := by dsimp; infer_instance 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..f29c9eed69daf 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 @@ -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/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/Jordan/Basic.lean b/Mathlib/Algebra/Jordan/Basic.lean index edd1a4df00c40..b6e455cab6209 100644 --- a/Mathlib/Algebra/Jordan/Basic.lean +++ b/Mathlib/Algebra/Jordan/Basic.lean @@ -82,12 +82,12 @@ class IsJordan [Mul A] : Prop where lmul_comm_rmul_rmul : ∀ a b : A, a * b * (a * a) = a * (b * (a * a)) rmul_comm_rmul_rmul : ∀ a b : A, b * a * (a * a) = b * (a * a) * a -/-- A commutative Jordan multipication -/ +/-- A commutative Jordan multiplication -/ class IsCommJordan [CommMagma A] : Prop where lmul_comm_rmul_rmul : ∀ a b : A, a * b * (a * a) = a * (b * (a * a)) -- see Note [lower instance priority] -/-- A (commutative) Jordan multiplication is also a Jordan multipication -/ +/-- A (commutative) Jordan multiplication is also a Jordan multiplication -/ instance (priority := 100) IsCommJordan.toIsJordan [CommMagma A] [IsCommJordan A] : IsJordan A where lmul_comm_rmul a b := by rw [mul_comm, mul_comm a b] lmul_lmul_comm_lmul a b := by @@ -101,7 +101,7 @@ instance (priority := 100) IsCommJordan.toIsJordan [CommMagma A] [IsCommJordan A rw [mul_comm b a, IsCommJordan.lmul_comm_rmul_rmul, mul_comm] -- see Note [lower instance priority] -/-- Semigroup multiplication satisfies the (non-commutative) Jordan axioms-/ +/-- Semigroup multiplication satisfies the (non-commutative) Jordan axioms -/ instance (priority := 100) Semigroup.isJordan [Semigroup A] : IsJordan A where lmul_comm_rmul a b := by rw [mul_assoc] lmul_lmul_comm_lmul a b := by rw [mul_assoc, mul_assoc] 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 6ad77f8f9d079..232b3327a85d3 100644 --- a/Mathlib/Algebra/Lie/BaseChange.lean +++ b/Mathlib/Algebra/Lie/BaseChange.lean @@ -169,10 +169,10 @@ def baseChange : LieSubmodule A (A ⊗[R] L) (A ⊗[R] M) := intro x m hm simp only [AddSubsemigroup.mem_carrier, AddSubmonoid.mem_toSubsemigroup, Submodule.mem_toAddSubmonoid] at hm ⊢ - obtain ⟨c, rfl⟩ := (Finsupp.mem_span_iff_total _ _ _).mp hm + obtain ⟨c, rfl⟩ := (Finsupp.mem_span_iff_linearCombination _ _ _).mp hm refine x.induction_on (by simp) (fun a y ↦ ?_) (fun y z hy hz ↦ ?_) · change toEnd A (A ⊗[R] L) (A ⊗[R] M) _ _ ∈ _ - simp_rw [Finsupp.total_apply, Finsupp.sum, map_sum, map_smul, toEnd_apply_apply] + simp_rw [Finsupp.linearCombination_apply, Finsupp.sum, map_sum, map_smul, toEnd_apply_apply] suffices ∀ n : (N : Submodule R M).map (TensorProduct.mk R A M 1), ⁅a ⊗ₜ[R] y, (n : A ⊗[R] M)⁆ ∈ (N : Submodule R M).baseChange A by exact Submodule.sum_mem _ fun n _ ↦ Submodule.smul_mem _ _ (this n) diff --git a/Mathlib/Algebra/Lie/Basic.lean b/Mathlib/Algebra/Lie/Basic.lean index c8a7cd3805a7b..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) @@ -385,13 +385,11 @@ theorem coe_linearMap_comp (f : L₂ →ₗ⁅R⁆ L₃) (g : L₁ →ₗ⁅R⁆ rfl @[simp] -theorem comp_id (f : L₁ →ₗ⁅R⁆ L₂) : f.comp (id : L₁ →ₗ⁅R⁆ L₁) = f := by - ext +theorem comp_id (f : L₁ →ₗ⁅R⁆ L₂) : f.comp (id : L₁ →ₗ⁅R⁆ L₁) = f := rfl @[simp] -theorem id_comp (f : L₁ →ₗ⁅R⁆ L₂) : (id : L₂ →ₗ⁅R⁆ L₂).comp f = f := by - ext +theorem id_comp (f : L₁ →ₗ⁅R⁆ L₂) : (id : L₂ →ₗ⁅R⁆ L₂).comp f = f := rfl /-- The inverse of a bijective morphism is a morphism. -/ @@ -473,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 @@ -538,9 +535,7 @@ def symm (e : L₁ ≃ₗ⁅R⁆ L₂) : L₂ ≃ₗ⁅R⁆ L₁ := { LieHom.inverse e.toLieHom e.invFun e.left_inv e.right_inv, e.toLinearEquiv.symm with } @[simp] -theorem symm_symm (e : L₁ ≃ₗ⁅R⁆ L₂) : e.symm.symm = e := by - ext - rfl +theorem symm_symm (e : L₁ ≃ₗ⁅R⁆ L₂) : e.symm.symm = e := rfl theorem symm_bijective : Function.Bijective (LieEquiv.symm : (L₁ ≃ₗ⁅R⁆ L₂) → L₂ ≃ₗ⁅R⁆ L₁) := Function.bijective_iff_has_inverse.mpr ⟨_, symm_symm, symm_symm⟩ @@ -626,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) @@ -859,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 @@ -941,8 +934,7 @@ theorem apply_eq_iff_eq_symm_apply {m : M} {n : N} (e : M ≃ₗ⁅R,L⁆ N) : (e : M ≃ N).apply_eq_iff_eq_symm_apply @[simp] -theorem symm_symm (e : M ≃ₗ⁅R,L⁆ N) : e.symm.symm = e := by - rfl +theorem symm_symm (e : M ≃ₗ⁅R,L⁆ N) : e.symm.symm = e := rfl theorem symm_bijective : Function.Bijective (LieModuleEquiv.symm : (M ≃ₗ⁅R,L⁆ N) → N ≃ₗ⁅R,L⁆ M) := diff --git a/Mathlib/Algebra/Lie/CartanExists.lean b/Mathlib/Algebra/Lie/CartanExists.lean index 25735e2642f2f..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 @@ -210,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 @@ -320,7 +320,7 @@ lemma engel_isBot_of_isMin (hLK : finrank K L ≤ #K) (U : LieSubalgebra K L) rw [← hn] clear hn induction n with - | zero => simp only [Nat.zero_eq, pow_zero, LinearMap.one_apply] + | zero => simp only [pow_zero, LinearMap.one_apply] | succ n ih => rw [pow_succ', pow_succ', LinearMap.mul_apply, ih]; rfl classical -- Now let `n` be the smallest power such that `⁅v, _⁆ ^ n` kills `z'`. @@ -360,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 acf506d5862cc..c904d1921c59f 100644 --- a/Mathlib/Algebra/Lie/CartanSubalgebra.lean +++ b/Mathlib/Algebra/Lie/CartanSubalgebra.lean @@ -59,9 +59,9 @@ theorem normalizer_eq_self_of_isCartanSubalgebra (H : LieSubalgebra R L) [H.IsCa @[simp] theorem ucs_eq_self_of_isCartanSubalgebra (H : LieSubalgebra R L) [H.IsCartanSubalgebra] (k : ℕ) : H.toLieSubmodule.ucs k = H.toLieSubmodule := by - induction' k with k ih - · simp - · simp [ih] + induction k with + | zero => simp + | succ k ih => simp [ih] theorem isCartanSubalgebra_iff_isUcsLimit : H.IsCartanSubalgebra ↔ H.toLieSubmodule.IsUcsLimit := by constructor @@ -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/Classical.lean b/Mathlib/Algebra/Lie/Classical.lean index 23b88270b6e03..cc6d16181296e 100644 --- a/Mathlib/Algebra/Lie/Classical.lean +++ b/Mathlib/Algebra/Lie/Classical.lean @@ -329,7 +329,7 @@ theorem indefiniteDiagonal_assoc : Sum.elim_inl, if_true, eq_self_iff_true, Matrix.one_apply_eq, Matrix.fromBlocks_apply₁₁, DMatrix.zero_apply, Equiv.sumAssoc_apply_inl_inr, if_false, Matrix.fromBlocks_apply₁₂, Matrix.fromBlocks_apply₂₁, Matrix.fromBlocks_apply₂₂, Equiv.sumAssoc_apply_inr, - Sum.elim_inr, Sum.inl_injective.eq_iff, Sum.inr_injective.eq_iff] <;> + Sum.elim_inr, Sum.inl_injective.eq_iff, Sum.inr_injective.eq_iff, reduceCtorEq] <;> congr 1 /-- An equivalence between two possible definitions of the classical Lie algebra of type B. -/ diff --git a/Mathlib/Algebra/Lie/Derivation/Basic.lean b/Mathlib/Algebra/Lie/Derivation/Basic.lean index 0d155c7a5b6fe..00c92eef36252 100644 --- a/Mathlib/Algebra/Lie/Derivation/Basic.lean +++ b/Mathlib/Algebra/Lie/Derivation/Basic.lean @@ -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 e6c9325939168..65e346eb954d5 100644 --- a/Mathlib/Algebra/Lie/Derivation/Killing.lean +++ b/Mathlib/Algebra/Lie/Derivation/Killing.lean @@ -86,8 +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 := - 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 7d4a6efc56417..973c229bb0534 100644 --- a/Mathlib/Algebra/Lie/DirectSum.lean +++ b/Mathlib/Algebra/Lie/DirectSum.lean @@ -157,14 +157,14 @@ def lieAlgebraOf [DecidableEq ι] (j : ι) : L j →ₗ⁅R⁆ ⨁ i, L i := erw [AddHom.coe_mk, single_apply, single_apply] · simp? [h] says simp only [h, ↓reduceDIte, single_apply] · intros - erw [single_add] + rw [single_add] · -- This used to be the end of the proof before leanprover/lean4#2644 -- with `simp [of, singleAddHom]` simp only [of, singleAddHom, bracket_apply] erw [AddHom.coe_mk, single_apply, single_apply] · simp only [h, dite_false, single_apply, lie_self] · intros - erw [single_add] } + rw [single_add] } /-- The projection map onto one component, as a morphism of Lie algebras. -/ @[simps] diff --git a/Mathlib/Algebra/Lie/Engel.lean b/Mathlib/Algebra/Lie/Engel.lean index 75a7f7b2c26dc..4b96b9ada30d7 100644 --- a/Mathlib/Algebra/Lie/Engel.lean +++ b/Mathlib/Algebra/Lie/Engel.lean @@ -109,11 +109,13 @@ theorem lcs_le_lcs_of_is_nilpotent_span_sup_eq_top {n i j : ℕ} (I.lcs M (j + 1) : Submodule R M) by simpa only [bot_sup_eq, LieIdeal.incl_coe, Submodule.map_zero, hxn] using this n intro l - induction' l with l ih - · simp only [Nat.zero_eq, add_zero, LieIdeal.lcs_succ, pow_zero, LinearMap.one_eq_id, + induction l with + | zero => + simp only [add_zero, LieIdeal.lcs_succ, pow_zero, LinearMap.one_eq_id, Submodule.map_id] exact le_sup_of_le_left hIM - · simp only [LieIdeal.lcs_succ, i.add_succ l, lie_top_eq_of_span_sup_eq_top hxI, sup_le_iff] + | succ l ih => + simp only [LieIdeal.lcs_succ, i.add_succ l, lie_top_eq_of_span_sup_eq_top hxI, sup_le_iff] refine ⟨(Submodule.map_mono ih).trans ?_, le_sup_of_le_right ?_⟩ · rw [Submodule.map_sup, ← Submodule.map_comp, ← LinearMap.mul_eq_comp, ← pow_succ', ← I.lcs_succ] @@ -131,9 +133,9 @@ theorem isNilpotentOfIsNilpotentSpanSupEqTop (hnp : IsNilpotent <| toEnd R L M x use k * n simpa [hk'] using this k intro l - induction' l with l ih - · simp - · exact (l.succ_mul n).symm ▸ lcs_le_lcs_of_is_nilpotent_span_sup_eq_top hxI hn ih + induction l with + | zero => simp + | succ l ih => exact (l.succ_mul n).symm ▸ lcs_le_lcs_of_is_nilpotent_span_sup_eq_top hxI hn ih end LieSubmodule @@ -198,7 +200,9 @@ theorem LieAlgebra.exists_engelian_lieSubalgebra_of_lt_normalizer {K : LieSubalg have hI₂ : (R ∙ (⟨x, hxK'⟩ : K')) ⊔ (LieSubmodule.toSubmodule I) = ⊤ := by rw [← LieIdeal.coe_to_lieSubalgebra_to_submodule R K' I, hI₁] apply Submodule.map_injective_of_injective (K' : Submodule R L).injective_subtype - simp + simp only [LieSubalgebra.coe_ofLe, Submodule.map_sup, Submodule.map_subtype_range_inclusion, + Submodule.map_top, Submodule.range_subtype] + rw [Submodule.map_subtype_span_singleton] have e : K ≃ₗ⁅R⁆ I := (LieSubalgebra.equivOfLe hKK').trans (LieEquiv.ofEq _ _ ((LieSubalgebra.coe_set_eq _ _).mpr hI₁.symm)) @@ -258,7 +262,7 @@ theorem LieAlgebra.isEngelian_of_isNoetherian [IsNoetherian R L] : LieAlgebra.Is refine isNoetherian_of_surjective L (LieHom.rangeRestrict (toEnd R L M)) ?_ simp only [LieHom.range_coeSubmodule, LieHom.coe_toLinearMap, LinearMap.range_eq_top] exact LieHom.surjective_rangeRestrict (toEnd R L M) - obtain ⟨K, hK₁, hK₂⟩ := (LieSubalgebra.wellFounded_of_noetherian R L').has_min s hs + obtain ⟨K, hK₁, hK₂⟩ := (LieSubalgebra.wellFoundedGT_of_noetherian R L').wf.has_min s hs have hK₃ : K = ⊤ := by by_contra contra obtain ⟨K', hK'₁, hK'₂⟩ := this K hK₁ contra diff --git a/Mathlib/Algebra/Lie/EngelSubalgebra.lean b/Mathlib/Algebra/Lie/EngelSubalgebra.lean index 73ab3ad4f7c2b..6720922dae1f2 100644 --- a/Mathlib/Algebra/Lie/EngelSubalgebra.lean +++ b/Mathlib/Algebra/Lie/EngelSubalgebra.lean @@ -127,7 +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; simpa using 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 @@ -135,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 0c18a9d49f2d5..bcd4cad1d3887 100644 --- a/Mathlib/Algebra/Lie/IdealOperations.lean +++ b/Mathlib/Algebra/Lie/IdealOperations.lean @@ -175,7 +175,7 @@ theorem lie_sup : ⁅I, N ⊔ N'⁆ = ⁅I, N⁆ ⊔ ⁅I, N'⁆ := by apply mono_lie_right <;> [exact le_sup_left; exact le_sup_right] suffices ⁅I, N ⊔ N'⁆ ≤ ⁅I, N⁆ ⊔ ⁅I, N'⁆ by exact le_antisymm this h rw [lieIdeal_oper_eq_span, lieSpan_le]; rintro m ⟨x, ⟨n, hn⟩, h⟩; erw [LieSubmodule.mem_sup] - erw [LieSubmodule.mem_sup] at hn; rcases hn with ⟨n₁, hn₁, n₂, hn₂, hn'⟩ + rw [LieSubmodule.mem_sup] at hn; rcases hn with ⟨n₁, hn₁, n₂, hn₂, hn'⟩ use ⁅(x : L), (⟨n₁, hn₁⟩ : N)⁆; constructor; · apply lie_coe_mem_lie use ⁅(x : L), (⟨n₂, hn₂⟩ : N')⁆; constructor; · apply lie_coe_mem_lie simp [← h, ← hn'] @@ -187,7 +187,7 @@ theorem sup_lie : ⁅I ⊔ J, N⁆ = ⁅I, N⁆ ⊔ ⁅J, N⁆ := by apply mono_lie_left <;> [exact le_sup_left; exact le_sup_right] suffices ⁅I ⊔ J, N⁆ ≤ ⁅I, N⁆ ⊔ ⁅J, N⁆ by exact le_antisymm this h rw [lieIdeal_oper_eq_span, lieSpan_le]; rintro m ⟨⟨x, hx⟩, n, h⟩; erw [LieSubmodule.mem_sup] - erw [LieSubmodule.mem_sup] at hx; rcases hx with ⟨x₁, hx₁, x₂, hx₂, hx'⟩ + rw [LieSubmodule.mem_sup] at hx; rcases hx with ⟨x₁, hx₁, x₂, hx₂, hx'⟩ use ⁅((⟨x₁, hx₁⟩ : I) : L), (n : N)⁆; constructor; · apply lie_coe_mem_lie use ⁅((⟨x₂, hx₂⟩ : J) : L), (n : N)⁆; constructor; · apply lie_coe_mem_lie simp [← h, ← hx'] @@ -275,7 +275,7 @@ theorem comap_bracket_eq {J₁ J₂ : LieIdeal R L'} (h : f.IsIdealMorphism) : congr; simp only [LieHom.coe_toLinearMap, Set.mem_setOf_eq]; ext y constructor · rintro ⟨⟨x₁, hx₁⟩, ⟨x₂, hx₂⟩, hy⟩; rw [← hy] - erw [LieSubmodule.mem_inf, f.mem_idealRange_iff h] at hx₁ hx₂ + rw [LieSubmodule.mem_inf, f.mem_idealRange_iff h] at hx₁ hx₂ obtain ⟨⟨z₁, hz₁⟩, hz₁'⟩ := hx₁; rw [← hz₁] at hz₁' obtain ⟨⟨z₂, hz₂⟩, hz₂'⟩ := hx₂; rw [← hz₂] at hz₂' refine ⟨⁅z₁, z₂⁆, ⟨⟨z₁, hz₁'⟩, ⟨z₂, hz₂'⟩, rfl⟩, ?_⟩ diff --git a/Mathlib/Algebra/Lie/InvariantForm.lean b/Mathlib/Algebra/Lie/InvariantForm.lean index ba8b199d8e77c..e95fdc8b0f1bf 100644 --- a/Mathlib/Algebra/Lie/InvariantForm.lean +++ b/Mathlib/Algebra/Lie/InvariantForm.lean @@ -61,14 +61,12 @@ lemma _root_.LinearMap.BilinForm.lieInvariant_iff [LieAlgebra R L] [LieModule R LinearMap.zero_apply, sub_eq_zero] at h simp [← h] -variable (hΦ_inv : Φ.lieInvariant L) - /-- The orthogonal complement of a Lie submodule `N` with respect to an invariant bilinear form `Φ` is the Lie submodule of elements `y` such that `Φ x y = 0` for all `x ∈ N`. -/ @[simps!] -def orthogonal (N : LieSubmodule R L M) : LieSubmodule R L M where +def orthogonal (hΦ_inv : Φ.lieInvariant L) (N : LieSubmodule R L M) : LieSubmodule R L M where __ := Φ.orthogonal N lie_mem {x y} := by suffices (∀ n ∈ N, Φ n y = 0) → ∀ n ∈ N, Φ n ⁅x, y⁆ = 0 by @@ -79,6 +77,8 @@ def orthogonal (N : LieSubmodule R L M) : LieSubmodule R L M where rw [← neg_eq_zero, ← hΦ_inv] exact H _ <| N.lie_mem ha +variable (hΦ_inv : Φ.lieInvariant L) + @[simp] lemma orthogonal_toSubmodule (N : LieSubmodule R L M) : (orthogonal Φ hΦ_inv N).toSubmodule = Φ.orthogonal N.toSubmodule := rfl @@ -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..4efe977e0587c 100644 --- a/Mathlib/Algebra/Lie/Killing.lean +++ b/Mathlib/Algebra/Lie/Killing.lean @@ -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 ad16dcc5bdd9a..84d773813fa84 100644 --- a/Mathlib/Algebra/Lie/Nilpotent.lean +++ b/Mathlib/Algebra/Lie/Nilpotent.lean @@ -64,9 +64,9 @@ theorem lcs_succ : N.lcs (k + 1) = ⁅(⊤ : LieIdeal R L), N.lcs k⁆ := @[simp] lemma lcs_sup {N₁ N₂ : LieSubmodule R L M} {k : ℕ} : (N₁ ⊔ N₂).lcs k = N₁.lcs k ⊔ N₂.lcs k := by - induction' k with k ih - · simp - · simp only [LieSubmodule.lcs_succ, ih, LieSubmodule.lie_sup] + induction k with + | zero => simp + | succ k ih => simp only [LieSubmodule.lcs_succ, ih, LieSubmodule.lie_sup] end LieSubmodule @@ -94,17 +94,19 @@ namespace LieSubmodule open LieModule theorem lcs_le_self : N.lcs k ≤ N := by - induction' k with k ih - · simp - · simp only [lcs_succ] + induction k with + | zero => simp + | succ k ih => + simp only [lcs_succ] exact (LieSubmodule.mono_lie_right ⊤ ih).trans (N.lie_le_right ⊤) variable [LieModule R L M] theorem lowerCentralSeries_eq_lcs_comap : lowerCentralSeries R L N k = (N.lcs k).comap N.incl := by - induction' k with k ih - · simp - · simp only [lcs_succ, lowerCentralSeries_succ] at ih ⊢ + induction k with + | zero => simp + | succ k ih => + simp only [lcs_succ, lowerCentralSeries_succ] at ih ⊢ have : N.lcs k ≤ N.incl.range := by rw [N.range_incl] apply lcs_le_self @@ -123,19 +125,21 @@ variable (R L M) theorem antitone_lowerCentralSeries : Antitone <| lowerCentralSeries R L M := by intro l k - induction' k with k ih generalizing l <;> intro h - · exact (Nat.le_zero.mp h).symm ▸ le_rfl - · rcases Nat.of_le_succ h with (hk | hk) + induction k generalizing l with + | zero => exact fun h ↦ (Nat.le_zero.mp h).symm ▸ le_rfl + | succ k ih => + intro h + rcases Nat.of_le_succ h with (hk | hk) · rw [lowerCentralSeries_succ] exact (LieSubmodule.mono_lie_right ⊤ (ih hk)).trans (LieSubmodule.lie_le_right _ _) · exact hk.symm ▸ le_rfl theorem eventually_iInf_lowerCentralSeries_eq [IsArtinian R M] : ∀ᶠ l in Filter.atTop, ⨅ k, lowerCentralSeries R L M k = lowerCentralSeries R L M l := by - have h_wf : WellFounded ((· > ·) : (LieSubmodule R L M)ᵒᵈ → (LieSubmodule R L M)ᵒᵈ → Prop) := - LieSubmodule.wellFounded_of_isArtinian R L M + have h_wf : WellFoundedGT (LieSubmodule R L M)ᵒᵈ := + LieSubmodule.wellFoundedLT_of_isArtinian R L M obtain ⟨n, hn : ∀ m, n ≤ m → lowerCentralSeries R L M n = lowerCentralSeries R L M m⟩ := - WellFounded.monotone_chain_condition.mp h_wf ⟨_, antitone_lowerCentralSeries R L M⟩ + WellFounded.monotone_chain_condition.mp h_wf.wf ⟨_, antitone_lowerCentralSeries R L M⟩ refine Filter.eventually_atTop.mpr ⟨n, fun l hl ↦ le_antisymm (iInf_le _ _) (le_iInf fun m ↦ ?_)⟩ rcases le_or_lt l m with h | h · rw [← hn _ hl, ← hn _ (hl.trans h)] @@ -156,38 +160,43 @@ variable [LieModule R L M] theorem iterate_toEnd_mem_lowerCentralSeries (x : L) (m : M) (k : ℕ) : (toEnd R L M x)^[k] m ∈ lowerCentralSeries R L M k := by - induction' k with k ih - · simp only [Nat.zero_eq, Function.iterate_zero, lowerCentralSeries_zero, LieSubmodule.mem_top] - · simp only [lowerCentralSeries_succ, Function.comp_apply, Function.iterate_succ', + induction k with + | zero => simp only [Function.iterate_zero, lowerCentralSeries_zero, LieSubmodule.mem_top] + | succ k ih => + simp only [lowerCentralSeries_succ, Function.comp_apply, Function.iterate_succ', toEnd_apply_apply] exact LieSubmodule.lie_mem_lie (LieSubmodule.mem_top x) ih theorem iterate_toEnd_mem_lowerCentralSeries₂ (x y : L) (m : M) (k : ℕ) : (toEnd R L M x ∘ₗ toEnd R L M y)^[k] m ∈ lowerCentralSeries R L M (2 * k) := by - induction' k with k ih - · simp - have hk : 2 * k.succ = (2 * k + 1) + 1 := rfl - simp only [lowerCentralSeries_succ, Function.comp_apply, Function.iterate_succ', hk, + induction k with + | zero => simp + | succ k ih => + have hk : 2 * k.succ = (2 * k + 1) + 1 := rfl + simp only [lowerCentralSeries_succ, Function.comp_apply, Function.iterate_succ', hk, toEnd_apply_apply, LinearMap.coe_comp, toEnd_apply_apply] - refine LieSubmodule.lie_mem_lie (LieSubmodule.mem_top x) ?_ - exact LieSubmodule.lie_mem_lie (LieSubmodule.mem_top y) ih + refine LieSubmodule.lie_mem_lie (LieSubmodule.mem_top x) ?_ + exact LieSubmodule.lie_mem_lie (LieSubmodule.mem_top y) ih variable {R L M} theorem map_lowerCentralSeries_le (f : M →ₗ⁅R,L⁆ M₂) : (lowerCentralSeries R L M k).map f ≤ lowerCentralSeries R L M₂ k := by - induction' k with k ih - · simp only [Nat.zero_eq, lowerCentralSeries_zero, le_top] - · simp only [LieModule.lowerCentralSeries_succ, LieSubmodule.map_bracket_eq] + induction k with + | zero => simp only [lowerCentralSeries_zero, le_top] + | succ k ih => + simp only [LieModule.lowerCentralSeries_succ, LieSubmodule.map_bracket_eq] exact LieSubmodule.mono_lie_right ⊤ ih lemma map_lowerCentralSeries_eq {f : M →ₗ⁅R,L⁆ M₂} (hf : Function.Surjective f) : (lowerCentralSeries R L M k).map f = lowerCentralSeries R L M₂ k := by apply le_antisymm (map_lowerCentralSeries_le k f) - induction' k with k ih - · rwa [lowerCentralSeries_zero, lowerCentralSeries_zero, top_le_iff, f.map_top, f.range_eq_top] - · simp only [lowerCentralSeries_succ, LieSubmodule.map_bracket_eq] + induction k with + | zero => + rwa [lowerCentralSeries_zero, lowerCentralSeries_zero, top_le_iff, f.map_top, f.range_eq_top] + | succ => + simp only [lowerCentralSeries_succ, LieSubmodule.map_bracket_eq] apply LieSubmodule.mono_lie_right assumption @@ -197,9 +206,10 @@ open LieAlgebra theorem derivedSeries_le_lowerCentralSeries (k : ℕ) : derivedSeries R L k ≤ lowerCentralSeries R L L k := by - induction' k with k h - · rw [derivedSeries_def, derivedSeriesOfIdeal_zero, lowerCentralSeries_zero] - · have h' : derivedSeries R L k ≤ ⊤ := by simp only [le_top] + induction k with + | zero => rw [derivedSeries_def, derivedSeriesOfIdeal_zero, lowerCentralSeries_zero] + | succ k h => + have h' : derivedSeries R L k ≤ ⊤ := by simp only [le_top] rw [derivedSeries_def, derivedSeriesOfIdeal_succ, lowerCentralSeries_succ] exact LieSubmodule.mono_lie h' h @@ -413,9 +423,10 @@ theorem nontrivial_max_triv_of_isNilpotent [Nontrivial M] [IsNilpotent R L M] : theorem coe_lcs_range_toEnd_eq (k : ℕ) : (lowerCentralSeries R (toEnd R L M).range M k : Submodule R M) = lowerCentralSeries R L M k := by - induction' k with k ih - · simp - · simp only [lowerCentralSeries_succ, LieSubmodule.lieIdeal_oper_eq_linear_span', ← + induction k with + | zero => simp + | succ k ih => + simp only [lowerCentralSeries_succ, LieSubmodule.lieIdeal_oper_eq_linear_span', ← (lowerCentralSeries R (toEnd R L M).range M k).mem_coeSubmodule, ih] congr ext m @@ -459,15 +470,16 @@ theorem ucs_add (k l : ℕ) : N.ucs (k + l) = (N.ucs l).ucs k := @[gcongr, mono] theorem ucs_mono (k : ℕ) (h : N₁ ≤ N₂) : N₁.ucs k ≤ N₂.ucs k := by - induction' k with k ih - · simpa - simp only [ucs_succ] - gcongr + induction k with + | zero => simpa + | succ k ih => + simp only [ucs_succ] + gcongr theorem ucs_eq_self_of_normalizer_eq_self (h : N₁.normalizer = N₁) (k : ℕ) : N₁.ucs k = N₁ := by - induction' k with k ih - · simp - · rwa [ucs_succ, ih] + induction k with + | zero => simp + | succ k ih => rwa [ucs_succ, ih] /-- If a Lie module `M` contains a self-normalizing Lie submodule `N`, then all terms of the upper central series of `M` are contained in `N`. @@ -481,9 +493,10 @@ theorem ucs_le_of_normalizer_eq_self (h : N₁.normalizer = N₁) (k : ℕ) : simp theorem lcs_add_le_iff (l k : ℕ) : N₁.lcs (l + k) ≤ N₂ ↔ N₁.lcs l ≤ N₂.ucs k := by - induction' k with k ih generalizing l - · simp - rw [(by abel : l + (k + 1) = l + 1 + k), ih, ucs_succ, lcs_succ, top_lie_le_iff_le_normalizer] + induction k generalizing l with + | zero => simp + | succ k ih => + rw [(by abel : l + (k + 1) = l + 1 + k), ih, ucs_succ, lcs_succ, top_lie_le_iff_le_normalizer] theorem lcs_le_iff (k : ℕ) : N₁.lcs k ≤ N₂ ↔ N₁ ≤ N₂.ucs k := by -- Porting note: `convert` needed type annotations @@ -504,9 +517,9 @@ theorem _root_.LieModule.isNilpotent_iff_exists_ucs_eq_top : theorem ucs_comap_incl (k : ℕ) : ((⊥ : LieSubmodule R L M).ucs k).comap N.incl = (⊥ : LieSubmodule R L N).ucs k := by - induction' k with k ih - · exact N.ker_incl - · simp [← ih] + induction k with + | zero => exact N.ker_incl + | succ k ih => simp [← ih] theorem isNilpotent_iff_exists_self_le_ucs : LieModule.IsNilpotent R L N ↔ ∃ k, N ≤ (⊥ : LieSubmodule R L M).ucs k := by @@ -530,9 +543,10 @@ variable (hf : Surjective f) (hg : Surjective g) (hfg : ∀ x m, ⁅f x, g m⁆ include hf hg hfg in theorem Function.Surjective.lieModule_lcs_map_eq (k : ℕ) : (lowerCentralSeries R L M k : Submodule R M).map g = lowerCentralSeries R L₂ M₂ k := by - induction' k with k ih - · simpa [LinearMap.range_eq_top] - · suffices + induction k with + | zero => simpa [LinearMap.range_eq_top] + | succ k ih => + suffices g '' {m | ∃ (x : L) (n : _), n ∈ lowerCentralSeries R L M k ∧ ⁅x, n⁆ = m} = {m | ∃ (x : L₂) (n : _), n ∈ lowerCentralSeries R L M k ∧ ⁅x, g n⁆ = m} by simp only [← LieSubmodule.mem_coeSubmodule] at this @@ -620,18 +634,20 @@ morphisms between Lie modules over different Lie algebras. -/ theorem coe_lowerCentralSeries_ideal_quot_eq {I : LieIdeal R L} (k : ℕ) : LieSubmodule.toSubmodule (lowerCentralSeries R L (L ⧸ I) k) = LieSubmodule.toSubmodule (lowerCentralSeries R (L ⧸ I) (L ⧸ I) k) := by - induction' k with k ih - · simp only [Nat.zero_eq, LieModule.lowerCentralSeries_zero, LieSubmodule.top_coeSubmodule, + induction k with + | zero => + simp only [LieModule.lowerCentralSeries_zero, LieSubmodule.top_coeSubmodule, LieIdeal.top_coe_lieSubalgebra, LieSubalgebra.top_coe_submodule] - · simp only [LieModule.lowerCentralSeries_succ, LieSubmodule.lieIdeal_oper_eq_linear_span] + | succ k ih => + simp only [LieModule.lowerCentralSeries_succ, LieSubmodule.lieIdeal_oper_eq_linear_span] congr 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 @@ -639,9 +655,10 @@ theorem coe_lowerCentralSeries_ideal_quot_eq {I : LieIdeal R L} (k : ℕ) : -- Porting note: added `LieSubmodule.toSubmodule` in the statement theorem LieModule.coe_lowerCentralSeries_ideal_le {I : LieIdeal R L} (k : ℕ) : LieSubmodule.toSubmodule (lowerCentralSeries R I I k) ≤ lowerCentralSeries R L I k := by - induction' k with k ih - · simp - · simp only [LieModule.lowerCentralSeries_succ, LieSubmodule.lieIdeal_oper_eq_linear_span] + induction k with + | zero => simp + | succ k ih => + simp only [LieModule.lowerCentralSeries_succ, LieSubmodule.lieIdeal_oper_eq_linear_span] apply Submodule.span_mono rintro x ⟨⟨y, -⟩, ⟨z, hz⟩, rfl : ⁅y, z⁆ = x⟩ exact ⟨⟨y.val, LieSubmodule.mem_top _⟩, ⟨z, ih hz⟩, rfl⟩ @@ -661,9 +678,10 @@ theorem LieAlgebra.non_trivial_center_of_isNilpotent [Nontrivial L] [IsNilpotent theorem LieIdeal.map_lowerCentralSeries_le (k : ℕ) {f : L →ₗ⁅R⁆ L'} : LieIdeal.map f (lowerCentralSeries R L L k) ≤ lowerCentralSeries R L' L' k := by - induction' k with k ih - · simp only [Nat.zero_eq, LieModule.lowerCentralSeries_zero, le_top] - · simp only [LieModule.lowerCentralSeries_succ] + induction k with + | zero => simp only [LieModule.lowerCentralSeries_zero, le_top] + | succ k ih => + simp only [LieModule.lowerCentralSeries_succ] exact le_trans (LieIdeal.map_bracket_le f) (LieSubmodule.mono_lie le_top ih) theorem LieIdeal.lowerCentralSeries_map_eq (k : ℕ) {f : L →ₗ⁅R⁆ L'} (h : Function.Surjective f) : @@ -671,9 +689,9 @@ theorem LieIdeal.lowerCentralSeries_map_eq (k : ℕ) {f : L →ₗ⁅R⁆ L'} (h have h' : (⊤ : LieIdeal R L).map f = ⊤ := by rw [← f.idealRange_eq_map] exact f.idealRange_eq_top_of_surjective h - induction' k with k ih - · simp only [LieModule.lowerCentralSeries_zero]; exact h' - · simp only [LieModule.lowerCentralSeries_succ, LieIdeal.map_bracket_eq f h, ih, h'] + induction k with + | zero => simp only [LieModule.lowerCentralSeries_zero]; exact h' + | succ k ih => simp only [LieModule.lowerCentralSeries_succ, LieIdeal.map_bracket_eq f h, ih, h'] theorem Function.Injective.lieAlgebra_isNilpotent [h₁ : IsNilpotent R L'] {f : L →ₗ⁅R⁆ L'} (h₂ : Function.Injective f) : IsNilpotent R L := @@ -750,9 +768,10 @@ theorem lcs_top : (⊤ : LieIdeal R L).lcs M k = lowerCentralSeries R L M k := -- Porting note: added `LieSubmodule.toSubmodule` in the statement theorem coe_lcs_eq [LieModule R L M] : LieSubmodule.toSubmodule (I.lcs M k) = lowerCentralSeries R I M k := by - induction' k with k ih - · simp - · simp_rw [lowerCentralSeries_succ, lcs_succ, LieSubmodule.lieIdeal_oper_eq_linear_span', ← + induction k with + | zero => simp + | succ k ih => + simp_rw [lowerCentralSeries_succ, lcs_succ, LieSubmodule.lieIdeal_oper_eq_linear_span', ← (I.lcs M k).mem_coeSubmodule, ih, LieSubmodule.mem_coeSubmodule, LieSubmodule.mem_top, true_and, (I : LieSubalgebra R L).coe_bracket_of_module] congr @@ -804,9 +823,9 @@ variable (R A L M : Type*) [CommRing R] [LieRing L] [LieAlgebra R L] lemma LieSubmodule.lowerCentralSeries_tensor_eq_baseChange (k : ℕ) : lowerCentralSeries A (A ⊗[R] L) (A ⊗[R] M) k = (lowerCentralSeries R L M k).baseChange A := by - induction' k with k ih - · simp - simp only [lowerCentralSeries_succ, ih, ← baseChange_top, lie_baseChange] + induction k with + | zero => simp + | succ k ih => simp only [lowerCentralSeries_succ, ih, ← baseChange_top, lie_baseChange] instance LieModule.instIsNilpotentTensor [IsNilpotent R L M] : IsNilpotent A (A ⊗[R] L) (A ⊗[R] M) := by diff --git a/Mathlib/Algebra/Lie/NonUnitalNonAssocAlgebra.lean b/Mathlib/Algebra/Lie/NonUnitalNonAssocAlgebra.lean index 18edee2b23811..124c5f21cd8a8 100644 --- a/Mathlib/Algebra/Lie/NonUnitalNonAssocAlgebra.lean +++ b/Mathlib/Algebra/Lie/NonUnitalNonAssocAlgebra.lean @@ -14,8 +14,8 @@ separate `Mul` typeclass used for general algebras. It is useful to have a special typeclass for Lie algebras because: * it enables us to use the traditional notation `⁅x, y⁆` for the Lie multiplication, - * associative algebras carry a natural Lie algebra structure via the ring commutator and so we need - them to carry both `Mul` and `Bracket` simultaneously, + * associative algebras carry a natural Lie algebra structure via the ring commutator and so we + need them to carry both `Mul` and `Bracket` simultaneously, * more generally, Poisson algebras (not yet defined) need both typeclasses. However there are times when it is convenient to be able to regard a Lie algebra as a general @@ -23,8 +23,8 @@ algebra and we provide some basic definitions for doing so here. ## Main definitions - * `CommutatorRing` turns a Lie ring into a `NonUnitalNonAssocSemiring` by turning its - `Bracket` (denoted `⁅, ⁆`) into a `Mul` (denoted `*`). + * `CommutatorRing` turns a Lie ring into a `NonUnitalNonAssocRing` by turning its + `Bracket` (denoted `⁅ , ⁆`) into a `Mul` (denoted `*`). * `LieHom.toNonUnitalAlgHom` ## Tags @@ -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 363b9a3da015a..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 [LinearMap.restrict_apply] + 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 4768863c8499a..ada8114afb6da 100644 --- a/Mathlib/Algebra/Lie/Semisimple/Basic.lean +++ b/Mathlib/Algebra/Lie/Semisimple/Basic.lean @@ -11,7 +11,7 @@ import Mathlib.Order.BooleanGenerators The famous Cartan-Dynkin-Killing classification of semisimple Lie algebras renders them one of the most important classes of Lie algebras. In this file we prove basic results -abot simple and semisimple Lie algebras. +about simple and semisimple Lie algebras. ## Main declarations @@ -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`. @@ -301,7 +306,7 @@ theorem subsingleton_of_hasTrivialRadical_lie_abelian [HasTrivialRadical R L] [h theorem abelian_radical_of_hasTrivialRadical [HasTrivialRadical R L] : IsLieAbelian (radical R L) := by - rw [HasTrivialRadical.radical_eq_bot]; infer_instance + 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 to be reductive. 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 e458dfb53a90d..1ce5fd8fdcf58 100644 --- a/Mathlib/Algebra/Lie/Solvable.lean +++ b/Mathlib/Algebra/Lie/Solvable.lean @@ -73,9 +73,9 @@ variable {R L} local notation "D" => derivedSeriesOfIdeal R L theorem derivedSeriesOfIdeal_add (k l : ℕ) : D (k + l) I = D k (D l I) := by - induction' k with k ih - · rw [Nat.zero_add, derivedSeriesOfIdeal_zero] - · rw [Nat.succ_add k l, derivedSeriesOfIdeal_succ, derivedSeriesOfIdeal_succ, ih] + induction k with + | zero => rw [Nat.zero_add, derivedSeriesOfIdeal_zero] + | succ k ih => rw [Nat.succ_add k l, derivedSeriesOfIdeal_succ, derivedSeriesOfIdeal_succ, ih] @[mono] theorem derivedSeriesOfIdeal_le {I J : LieIdeal R L} {k l : ℕ} (h₁ : I ≤ J) (h₂ : l ≤ k) : @@ -131,11 +131,12 @@ variable {R L} theorem derivedSeries_eq_derivedSeriesOfIdeal_comap (k : ℕ) : derivedSeries R I k = (derivedSeriesOfIdeal R L k I).comap I.incl := by - induction' k with k ih - · simp only [Nat.zero_eq, derivedSeries_def, comap_incl_self, derivedSeriesOfIdeal_zero] - · simp only [derivedSeries_def, derivedSeriesOfIdeal_succ] at ih ⊢; rw [ih] - exact comap_bracket_incl_of_le I - (derivedSeriesOfIdeal_le_self I k) (derivedSeriesOfIdeal_le_self I k) + induction k with + | zero => simp only [derivedSeries_def, comap_incl_self, derivedSeriesOfIdeal_zero] + | succ k ih => + simp only [derivedSeries_def, derivedSeriesOfIdeal_succ] at ih ⊢; rw [ih] + exact comap_bracket_incl_of_le I (derivedSeriesOfIdeal_le_self I k) + (derivedSeriesOfIdeal_le_self I k) theorem derivedSeries_eq_derivedSeriesOfIdeal_map (k : ℕ) : (derivedSeries R I k).map I.incl = derivedSeriesOfIdeal R L k I := by @@ -156,28 +157,32 @@ theorem derivedSeries_add_eq_bot {k l : ℕ} {I J : LieIdeal R L} (hI : derivedS _ ≤ ⊥ := by rw [hI, hJ]; simp theorem derivedSeries_map_le (k : ℕ) : (derivedSeries R L' k).map f ≤ derivedSeries R L k := by - induction' k with k ih - · simp only [Nat.zero_eq, derivedSeries_def, derivedSeriesOfIdeal_zero, le_top] - · simp only [derivedSeries_def, derivedSeriesOfIdeal_succ] at ih ⊢ + induction k with + | zero => simp only [derivedSeries_def, derivedSeriesOfIdeal_zero, le_top] + | succ k ih => + simp only [derivedSeries_def, derivedSeriesOfIdeal_succ] at ih ⊢ exact le_trans (map_bracket_le f) (LieSubmodule.mono_lie ih ih) theorem derivedSeries_map_eq (k : ℕ) (h : Function.Surjective f) : (derivedSeries R L' k).map f = derivedSeries R L k := by - induction' k with k ih - · change (⊤ : LieIdeal R L').map f = ⊤ + induction k with + | zero => + change (⊤ : LieIdeal R L').map f = ⊤ rw [← f.idealRange_eq_map] exact f.idealRange_eq_top_of_surjective h - · simp only [derivedSeries_def, map_bracket_eq f h, ih, derivedSeriesOfIdeal_succ] + | succ k ih => simp only [derivedSeries_def, map_bracket_eq f h, ih, derivedSeriesOfIdeal_succ] theorem derivedSeries_succ_eq_top_iff (n : ℕ) : derivedSeries R L (n + 1) = ⊤ ↔ derivedSeries R L 1 = ⊤ := by simp only [derivedSeries_def] - induction' n with n ih; · simp - rw [derivedSeriesOfIdeal_succ] - refine ⟨fun h ↦ ?_, fun h ↦ by rwa [ih.mpr h]⟩ - rw [← ih, eq_top_iff] - conv_lhs => rw [← h] - exact LieSubmodule.lie_le_right _ _ + induction n with + | zero => simp + | succ n ih => + rw [derivedSeriesOfIdeal_succ] + refine ⟨fun h ↦ ?_, fun h ↦ by rwa [ih.mpr h]⟩ + rw [← ih, eq_top_iff] + conv_lhs => rw [← h] + exact LieSubmodule.lie_le_right _ _ theorem derivedSeries_eq_top (n : ℕ) (h : derivedSeries R L 1 = ⊤) : derivedSeries R L n = ⊤ := by @@ -193,11 +198,11 @@ 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] : - IsSolvable R (↥(I + J)) := by + IsSolvable R (I + J) := by obtain ⟨k, hk⟩ := id hI; obtain ⟨l, hl⟩ := id hJ exact ⟨⟨k + l, LieIdeal.derivedSeries_add_eq_bot hk hl⟩⟩ @@ -261,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.wellFounded_of_noetherian R L L - 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 ⊢ @@ -282,7 +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 - rw [eq_top_iff]; exact le_sSup <| inferInstanceAs (IsSolvable R (⊤ : LieIdeal 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). @@ -328,11 +335,14 @@ 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] cases' h : derivedLengthOfIdeal R L I with k - · infer_instance + · dsimp; infer_instance · rw [derivedSeries_of_derivedLength_succ] at h; exact h.1 theorem derivedLength_zero (I : LieIdeal R L) [hI : IsSolvable R I] : diff --git a/Mathlib/Algebra/Lie/Subalgebra.lean b/Mathlib/Algebra/Lie/Subalgebra.lean index f5b3887358c7b..be459970fb977 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. -/ @@ -220,7 +223,8 @@ variable [Module R M] /-- Given a Lie algebra `L` containing a Lie subalgebra `L' ⊆ L`, together with a Lie module `M` of `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 simp only [coe_bracket_of_module, smul_lie, Submodule.coe_smul_of_tower] + smul_lie t x m := by + 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 @@ -291,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] @@ -500,21 +504,16 @@ theorem eq_bot_iff : K = ⊥ ↔ ∀ x : L, x ∈ K → x = 0 := by instance subsingleton_of_bot : Subsingleton (LieSubalgebra R (⊥ : LieSubalgebra R L)) := by apply subsingleton_of_bot_eq_top ext ⟨x, hx⟩; change x ∈ ⊥ at hx; rw [LieSubalgebra.mem_bot] at hx; subst hx - simp only [true_iff_iff, eq_self_iff_true, Submodule.mk_eq_zero, mem_bot, mem_top] + simp only [mem_bot, mem_top, iff_true] + rfl theorem subsingleton_bot : Subsingleton (⊥ : LieSubalgebra R L) := show Subsingleton ((⊥ : LieSubalgebra R L) : Set L) by simp variable (R L) -theorem wellFounded_of_noetherian [IsNoetherian R L] : - WellFounded ((· > ·) : LieSubalgebra R L → LieSubalgebra R L → Prop) := - let f : - ((· > ·) : LieSubalgebra R L → LieSubalgebra R L → Prop) →r - ((· > ·) : Submodule R L → Submodule R L → Prop) := - { toFun := (↑) - map_rel' := @fun _ _ h ↦ h } - RelHomClass.wellFounded f (isNoetherian_iff_wellFounded.mp inferInstance) +instance wellFoundedGT_of_noetherian [IsNoetherian R L] : WellFoundedGT (LieSubalgebra R L) := + RelHomClass.isWellFounded (⟨toSubmodule, @fun _ _ h ↦ h⟩ : _ →r (· > ·)) variable {R L K K' f} @@ -561,7 +560,7 @@ theorem coe_ofLe : (ofLe h : Submodule R K') = LinearMap.range (Submodule.inclus rfl /-- Given nested Lie subalgebras `K ⊆ K'`, there is a natural equivalence from `K` to its image in -`K'`. -/ +`K'`. -/ noncomputable def equivOfLe : K ≃ₗ⁅R⁆ ofLe h := (inclusion h).equivRangeOfInjective (inclusion_injective h) diff --git a/Mathlib/Algebra/Lie/Submodule.lean b/Mathlib/Algebra/Lie/Submodule.lean index 08978bd95d8ba..1ce9ee98b69dc 100644 --- a/Mathlib/Algebra/Lie/Submodule.lean +++ b/Mathlib/Algebra/Lie/Submodule.lean @@ -72,14 +72,12 @@ instance : Zero (LieSubmodule R L M) := instance : Inhabited (LieSubmodule R L M) := ⟨0⟩ -instance coeSubmodule : CoeOut (LieSubmodule R L M) (Submodule R M) := - ⟨toSubmodule⟩ +instance (priority := high) coeSort : CoeSort (LieSubmodule R L M) (Type w) where + coe N := { x : M // x ∈ N } -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⟩ +instance (priority := mid) coeSubmodule : CoeOut (LieSubmodule R L M) (Submodule R M) := + ⟨toSubmodule⟩ --- Syntactic tautology @[norm_cast] theorem coe_toSubmodule : ((N : Submodule R M) : Set M) = N := @@ -111,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 @@ -158,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 @@ -190,9 +177,20 @@ theorem coe_smul (t : R) (m : N) : (↑(t • m) : M) = t • (m : M) := rfl @[simp, norm_cast] -theorem coe_bracket (x : L) (m : N) : (↑⁅x, m⁆ : M) = ⁅x, ↑m⁆ := +theorem coe_bracket (x : L) (m : N) : + (↑⁅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 @@ -248,7 +246,8 @@ 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) : ⁅x, m⁆ = ⁅(↑x : L), m⁆ := + (I : LieIdeal R L) [LieRingModule L M] (x : I) (m : M) : + ⁅x, m⁆ = ⁅(↑x : L), m⁆ := LieSubalgebra.coe_bracket_of_module (I : LieSubalgebra R L) x m /-- Transfer the `LieModule` instance from the coercion `LieIdeal → LieSubalgebra`. -/ @@ -323,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 @@ -436,10 +438,13 @@ instance : SupSet (LieSubmodule R L M) where obtain ⟨s, hs, hsm⟩ := Submodule.mem_sSup_iff_exists_finset.mp hm clear hm classical - induction' s using Finset.induction_on with q t hqt ih generalizing m - · replace hsm : m = 0 := by simpa using hsm + induction s using Finset.induction_on generalizing m with + | empty => + replace hsm : m = 0 := by simpa using hsm simp [hsm] - · rw [Finset.iSup_insert] at hsm + | insert hqt ih => + rename_i q t + rw [Finset.iSup_insert] at hsm obtain ⟨m', hm', u, hu, rfl⟩ := Submodule.mem_sup.mp hsm rw [lie_add] refine add_mem ?_ (ih (Subset.trans (by simp) hs) hu) @@ -542,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 @@ -560,18 +566,14 @@ variable (R L M) inj' := coeSubmodule_injective map_rel_iff' := Iff.rfl } -theorem wellFounded_of_noetherian [IsNoetherian R M] : - WellFounded ((· > ·) : LieSubmodule R L M → LieSubmodule R L M → Prop) := - RelHomClass.wellFounded (toSubmodule_orderEmbedding R L M).dual.ltEmbedding <| - isNoetherian_iff_wellFounded.mp inferInstance +instance wellFoundedGT_of_noetherian [IsNoetherian R M] : WellFoundedGT (LieSubmodule R L M) := + RelHomClass.isWellFounded (toSubmodule_orderEmbedding R L M).dual.ltEmbedding -theorem wellFounded_of_isArtinian [IsArtinian R M] : - WellFounded ((· < ·) : LieSubmodule R L M → LieSubmodule R L M → Prop) := - RelHomClass.wellFounded (toSubmodule_orderEmbedding R L M).ltEmbedding <| - IsArtinian.wellFounded_submodule_lt R M +theorem wellFoundedLT_of_isArtinian [IsArtinian R M] : WellFoundedLT (LieSubmodule R L M) := + RelHomClass.isWellFounded (toSubmodule_orderEmbedding R L M).ltEmbedding instance [IsArtinian R M] : IsAtomic (LieSubmodule R L M) := - isAtomic_of_orderBot_wellFounded_lt <| wellFounded_of_isArtinian R L M + isAtomic_of_orderBot_wellFounded_lt <| (wellFoundedLT_of_isArtinian R L M).wf @[simp] theorem subsingleton_iff : Subsingleton (LieSubmodule R L M) ↔ Subsingleton M := @@ -829,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 := @@ -986,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 @@ -1047,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 @@ -1154,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' : @@ -1248,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] @@ -1256,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] @@ -1269,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] @@ -1309,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 diff --git a/Mathlib/Algebra/Lie/TensorProduct.lean b/Mathlib/Algebra/Lie/TensorProduct.lean index 9d5d16473476a..0fe6b3f7fb9e8 100644 --- a/Mathlib/Algebra/Lie/TensorProduct.lean +++ b/Mathlib/Algebra/Lie/TensorProduct.lean @@ -195,14 +195,14 @@ applying the action of `L` on `M`, we obtain morphism of Lie modules `f : I ⊗ This lemma states that `⁅I, N⁆ = range f`. -/ theorem lieIdeal_oper_eq_tensor_map_range : - ⁅I, N⁆ = ((toModuleHom R L M).comp (mapIncl I N : (↥I) ⊗[R] (↥N) →ₗ⁅R,L⁆ L ⊗[R] M)).range := by + ⁅I, N⁆ = ((toModuleHom R L M).comp (mapIncl I N : I ⊗[R] N →ₗ⁅R,L⁆ L ⊗[R] M)).range := by rw [← coe_toSubmodule_eq_iff, lieIdeal_oper_eq_linear_span, LieModuleHom.coeSubmodule_range, LieModuleHom.coe_linearMap_comp, LinearMap.range_comp, mapIncl_def, coe_linearMap_map, 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 735f6856fa8fe..bddebc215744c 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 @@ -103,22 +103,22 @@ lemma traceForm_lieInvariant : (traceForm R L M).lieInvariant L := by exact isNilpotent_toEnd_of_isNilpotent₂ R L M x y @[simp] -lemma traceForm_weightSpace_eq [Module.Free R M] +lemma traceForm_genWeightSpace_eq [Module.Free R M] [IsDomain R] [IsPrincipalIdealRing R] [LieAlgebra.IsNilpotent R L] [IsNoetherian R M] [LinearWeights R L M] (χ : L → R) (x y : L) : - traceForm R L (weightSpace M χ) x y = finrank R (weightSpace M χ) • (χ x * χ y) := by - set d := finrank R (weightSpace M χ) + traceForm R L (genWeightSpace M χ) x y = finrank R (genWeightSpace M χ) • (χ x * χ y) := by + set d := finrank R (genWeightSpace M χ) have h₁ : χ y • d • χ x - χ y • χ x • (d : R) = 0 := by simp [mul_comm (χ x)] have h₂ : χ x • d • χ y = d • (χ x * χ y) := by simpa [nsmul_eq_mul, smul_eq_mul] using mul_left_comm (χ x) d (χ y) - have := traceForm_eq_zero_of_isNilpotent R L (shiftedWeightSpace R L M χ) + have := traceForm_eq_zero_of_isNilpotent R L (shiftedGenWeightSpace R L M χ) replace this := LinearMap.congr_fun (LinearMap.congr_fun this x) y rwa [LinearMap.zero_apply, LinearMap.zero_apply, traceForm_apply_apply, - shiftedWeightSpace.toEnd_eq, shiftedWeightSpace.toEnd_eq, + shiftedGenWeightSpace.toEnd_eq, shiftedGenWeightSpace.toEnd_eq, ← LinearEquiv.conj_comp, LinearMap.trace_conj', LinearMap.comp_sub, LinearMap.sub_comp, LinearMap.sub_comp, map_sub, map_sub, map_sub, LinearMap.comp_smul, LinearMap.smul_comp, LinearMap.comp_id, LinearMap.id_comp, LinearMap.map_smul, LinearMap.map_smul, - trace_toEnd_weightSpace, trace_toEnd_weightSpace, + trace_toEnd_genWeightSpace, trace_toEnd_genWeightSpace, LinearMap.comp_smul, LinearMap.smul_comp, LinearMap.id_comp, map_smul, map_smul, LinearMap.trace_id, ← traceForm_apply_apply, h₁, h₂, sub_zero, sub_eq_zero] at this @@ -127,10 +127,12 @@ lemma traceForm_weightSpace_eq [Module.Free R M] lemma traceForm_eq_zero_if_mem_lcs_of_mem_ucs {x y : L} (k : ℕ) (hx : x ∈ (⊤ : LieIdeal R L).lcs L k) (hy : y ∈ (⊥ : LieIdeal R L).ucs k) : traceForm R L M x y = 0 := by - induction' k with k ih generalizing x y - · replace hy : y = 0 := by simpa using hy + induction k generalizing x y with + | zero => + replace hy : y = 0 := by simpa using hy simp [hy] - · rw [LieSubmodule.ucs_succ, LieSubmodule.mem_normalizer] at hy + | succ k ih => + 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 ↦ ?_) @@ -159,9 +161,9 @@ lemma traceForm_apply_eq_zero_of_mem_lcs_of_mem_center {x y : L} /-- Given a bilinear form `B` on a representation `M` of a nilpotent Lie algebra `L`, if `B` is invariant (in the sense that the action of `L` is skew-adjoint wrt `B`) then components of the Fitting decomposition of `M` are orthogonal wrt `B`. -/ -lemma eq_zero_of_mem_weightSpace_mem_posFitting [LieAlgebra.IsNilpotent R L] +lemma eq_zero_of_mem_genWeightSpace_mem_posFitting [LieAlgebra.IsNilpotent R L] {B : LinearMap.BilinForm R M} (hB : ∀ (x : L) (m n : M), B ⁅x, m⁆ n = - B m ⁅x, n⁆) - {m₀ m₁ : M} (hm₀ : m₀ ∈ weightSpace M (0 : L → R)) (hm₁ : m₁ ∈ posFittingComp R L M) : + {m₀ m₁ : M} (hm₀ : m₀ ∈ genWeightSpace M (0 : L → R)) (hm₁ : m₁ ∈ posFittingComp R L M) : B m₀ m₁ = 0 := by replace hB : ∀ x (k : ℕ) m n, B m ((φ x ^ k) n) = (- 1 : R) ^ k • B ((φ x ^ k) m) n := by intro x k @@ -177,7 +179,7 @@ lemma eq_zero_of_mem_weightSpace_mem_posFitting [LieAlgebra.IsNilpotent R L] apply LieSubmodule.iSup_induction _ hm₁ this (map_zero _) aesop clear hm₁ m₁; intro x m₁ hm₁ - simp only [mem_weightSpace, Pi.zero_apply, zero_smul, sub_zero] at hm₀ + simp only [mem_genWeightSpace, Pi.zero_apply, zero_smul, sub_zero] at hm₀ obtain ⟨k, hk⟩ := hm₀ x obtain ⟨m, rfl⟩ := (mem_posFittingCompOf R x m₁).mp hm₁ k simp [hB, hk] @@ -211,21 +213,22 @@ open TensorProduct variable [LieAlgebra.IsNilpotent R L] [IsDomain R] [IsPrincipalIdealRing R] -lemma traceForm_eq_sum_weightSpaceOf +lemma traceForm_eq_sum_genWeightSpaceOf [NoZeroSMulDivisors R M] [IsNoetherian R M] [IsTriangularizable R L M] (z : L) : traceForm R L M = - ∑ χ ∈ (finite_weightSpaceOf_ne_bot R L M z).toFinset, traceForm R L (weightSpaceOf M χ z) := by + ∑ χ ∈ (finite_genWeightSpaceOf_ne_bot R L M z).toFinset, + traceForm R L (genWeightSpaceOf M χ z) := by ext x y have hxy : ∀ χ : R, MapsTo ((toEnd R L M x).comp (toEnd R L M y)) - (weightSpaceOf M χ z) (weightSpaceOf M χ z) := + (genWeightSpaceOf M χ z) (genWeightSpaceOf M χ z) := fun χ m hm ↦ LieSubmodule.lie_mem _ <| LieSubmodule.lie_mem _ hm - have hfin : {χ : R | (weightSpaceOf M χ z : Submodule R M) ≠ ⊥}.Finite := by - convert finite_weightSpaceOf_ne_bot R L M z - exact LieSubmodule.coeSubmodule_eq_bot_iff (weightSpaceOf M _ _) + have hfin : {χ : R | (genWeightSpaceOf M χ z : Submodule R M) ≠ ⊥}.Finite := by + 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_weightSpaceOf 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) @@ -273,9 +276,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) + · simpa only [Module.End.maxGenEigenspace_def] using IsTriangularizable.iSup_eq_top (1 ⊗ₜ[R] x) · exact fun μ ↦ trace_toEnd_eq_zero_of_mem_lcs A (A ⊗[R] L) - (weightSpaceOf (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. -/ @@ -299,7 +302,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 @@ -319,7 +325,7 @@ 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] exact Submodule.coe_eq_zero.mpr (LieModule.IsTrivial.trivial (⟨y, hy⟩ : I) n) @@ -342,7 +348,7 @@ lemma killingForm_eq_zero_of_mem_zeroRoot_mem_posFitting (hx₀ : x₀ ∈ LieAlgebra.zeroRootSubalgebra R L H) (hx₁ : x₁ ∈ LieModule.posFittingComp R H L) : killingForm R L x₀ x₁ = 0 := - LieModule.eq_zero_of_mem_weightSpace_mem_posFitting R H L + LieModule.eq_zero_of_mem_genWeightSpace_mem_posFitting R H L (fun x y z ↦ LieModule.traceForm_apply_lie_apply' R L L x y z) hx₀ hx₁ namespace LieIdeal @@ -386,7 +392,7 @@ lemma killingForm_eq : end LieIdeal -open LieModule FiniteDimensional +open LieModule Module open Submodule (span subset_span) namespace LieModule @@ -395,25 +401,42 @@ variable [Field K] [LieAlgebra K L] [Module K M] [LieModule K L M] [FiniteDimens variable [LieAlgebra.IsNilpotent K L] [LinearWeights K L M] [IsTriangularizable K L M] lemma traceForm_eq_sum_finrank_nsmul_mul (x y : L) : - traceForm K L M x y = ∑ χ : Weight K L M, finrank K (weightSpace M χ) • (χ x * χ y) := by + traceForm K L M x y = ∑ χ : Weight K L M, finrank K (genWeightSpace M χ) • (χ x * χ y) := by have hxy : ∀ χ : Weight K L M, MapsTo (toEnd K L M x ∘ₗ toEnd K L M y) - (weightSpace M χ) (weightSpace M χ) := + (genWeightSpace M χ) (genWeightSpace M χ) := fun χ m hm ↦ LieSubmodule.lie_mem _ <| LieSubmodule.lie_mem _ hm classical have hds := DirectSum.isInternal_submodule_of_independent_of_iSup_eq_top - (LieSubmodule.independent_iff_coe_toSubmodule.mp <| independent_weightSpace' K L M) - (LieSubmodule.iSup_eq_top_iff_coe_toSubmodule.mp <| iSup_weightSpace_eq_top' K L M) + (LieSubmodule.independent_iff_coe_toSubmodule.mp <| independent_genWeightSpace' K L M) + (LieSubmodule.iSup_eq_top_iff_coe_toSubmodule.mp <| iSup_genWeightSpace_eq_top' K L M) simp_rw [traceForm_apply_apply, LinearMap.trace_eq_sum_trace_restrict hds hxy, - ← traceForm_weightSpace_eq K L M _ x y] + ← 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 (weightSpace M χ) • + traceForm K L M = ∑ χ : Weight K L M, finrank K (genWeightSpace M χ) • (χ : L →ₗ[K] K).smulRight (χ : L →ₗ[K] K) := by ext 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/UniversalEnveloping.lean b/Mathlib/Algebra/Lie/UniversalEnveloping.lean index 2d6a8ff9c4a7d..7f8985b6da9ee 100644 --- a/Mathlib/Algebra/Lie/UniversalEnveloping.lean +++ b/Mathlib/Algebra/Lie/UniversalEnveloping.lean @@ -96,7 +96,7 @@ def lift : (L →ₗ⁅R⁆ A) ≃ (UniversalEnvelopingAlgebra R L →ₐ[R] A) toFun f := RingQuot.liftAlgHom R ⟨TensorAlgebra.lift R (f : L →ₗ[R] A), by - intro a b h; induction' h with x y + intro a b h; induction h simp only [LieRing.of_associative_ring_bracket, map_add, TensorAlgebra.lift_ι_apply, LieHom.coe_toLinearMap, LieHom.map_lie, map_mul, sub_add_cancel]⟩ invFun F := (F : UniversalEnvelopingAlgebra R L →ₗ⁅R⁆ A).comp (ι R) diff --git a/Mathlib/Algebra/Lie/Weights/Basic.lean b/Mathlib/Algebra/Lie/Weights/Basic.lean index 9b309c2715513..e0f030da4cacc 100644 --- a/Mathlib/Algebra/Lie/Weights/Basic.lean +++ b/Mathlib/Algebra/Lie/Weights/Basic.lean @@ -25,16 +25,16 @@ Basic definitions and properties of the above ideas are provided in this file. ## Main definitions - * `LieModule.weightSpaceOf` - * `LieModule.weightSpace` + * `LieModule.genWeightSpaceOf` + * `LieModule.genWeightSpace` * `LieModule.Weight` * `LieModule.posFittingCompOf` * `LieModule.posFittingComp` - * `LieModule.iSup_ucs_eq_weightSpace_zero` + * `LieModule.iSup_ucs_eq_genWeightSpace_zero` * `LieModule.iInf_lowerCentralSeries_eq_posFittingComp` - * `LieModule.isCompl_weightSpace_zero_posFittingComp` - * `LieModule.independent_weightSpace` - * `LieModule.iSup_weightSpace_eq_top` + * `LieModule.isCompl_genWeightSpace_zero_posFittingComp` + * `LieModule.independent_genWeightSpace` + * `LieModule.iSup_genWeightSpace_eq_top` ## References @@ -50,12 +50,11 @@ variable {K R L M : Type*} [CommRing R] [LieRing L] [LieAlgebra R L] namespace LieModule -open Set Function LieAlgebra TensorProduct TensorProduct.LieModule -open scoped TensorProduct +open Set Function TensorProduct LieModule -section notation_weightSpaceOf +section notation_genWeightSpaceOf -/-- Until we define `LieModule.weightSpaceOf`, it is useful to have some notation as follows: -/ +/-- Until we define `LieModule.genWeightSpaceOf`, it is useful to have some notation as follows: -/ local notation3 "𝕎("M", " χ", " x")" => (toEnd R L M x).maxGenEigenspace χ /-- See also `bourbaki1975b` Chapter VII §1.1, Proposition 2 (ii). -/ @@ -143,10 +142,10 @@ lemma lie_mem_maxGenEigenspace_toEnd variable (M) /-- If `M` is a representation of a nilpotent Lie algebra `L`, `χ` is a scalar, and `x : L`, then -`weightSpaceOf M χ x` is the maximal generalized `χ`-eigenspace of the action of `x` on `M`. +`genWeightSpaceOf M χ x` is the maximal generalized `χ`-eigenspace of the action of `x` on `M`. It is a Lie submodule because `L` is nilpotent. -/ -def weightSpaceOf [LieAlgebra.IsNilpotent R L] (χ : R) (x : L) : LieSubmodule R L M := +def genWeightSpaceOf [LieAlgebra.IsNilpotent R L] (χ : R) (x : L) : LieSubmodule R L M := { 𝕎(M, χ, x) with lie_mem := by intro y m hm @@ -155,33 +154,34 @@ def weightSpaceOf [LieAlgebra.IsNilpotent R L] (χ : R) (x : L) : LieSubmodule R rw [← zero_add χ] exact lie_mem_maxGenEigenspace_toEnd (by simp) hm } -end notation_weightSpaceOf +end notation_genWeightSpaceOf variable (M) variable [LieAlgebra.IsNilpotent R L] -theorem mem_weightSpaceOf (χ : R) (x : L) (m : M) : - m ∈ weightSpaceOf M χ x ↔ ∃ k : ℕ, ((toEnd R L M x - χ • ↑1) ^ k) m = 0 := by - simp [weightSpaceOf] +theorem mem_genWeightSpaceOf (χ : R) (x : L) (m : M) : + m ∈ genWeightSpaceOf M χ x ↔ ∃ k : ℕ, ((toEnd R L M x - χ • ↑1) ^ k) m = 0 := by + simp [genWeightSpaceOf] -theorem coe_weightSpaceOf_zero (x : L) : - ↑(weightSpaceOf M (0 : R) x) = ⨆ k, LinearMap.ker (toEnd R L M x ^ k) := by - simp [weightSpaceOf, Module.End.maxGenEigenspace] +theorem coe_genWeightSpaceOf_zero (x : L) : + ↑(genWeightSpaceOf M (0 : R) x) = ⨆ k, LinearMap.ker (toEnd R L M x ^ k) := by + simp [genWeightSpaceOf, Module.End.maxGenEigenspace_def] -/-- If `M` is a representation of a nilpotent Lie algebra `L` and `χ : L → R` is a family of -scalars, then `weightSpace M χ` is the intersection of the maximal generalized `χ x`-eigenspaces of -the action of `x` on `M` as `x` ranges over `L`. +/-- If `M` is a representation of a nilpotent Lie algebra `L` +and `χ : L → R` is a family of scalars, +then `genWeightSpace M χ` is the intersection of the maximal generalized `χ x`-eigenspaces +of the action of `x` on `M` as `x` ranges over `L`. It is a Lie submodule because `L` is nilpotent. -/ -def weightSpace (χ : L → R) : LieSubmodule R L M := - ⨅ x, weightSpaceOf M (χ x) x +def genWeightSpace (χ : L → R) : LieSubmodule R L M := + ⨅ x, genWeightSpaceOf M (χ x) x -theorem mem_weightSpace (χ : L → R) (m : M) : - m ∈ weightSpace M χ ↔ ∀ x, ∃ k : ℕ, ((toEnd R L M x - χ x • ↑1) ^ k) m = 0 := by - simp [weightSpace, mem_weightSpaceOf] +theorem mem_genWeightSpace (χ : L → R) (m : M) : + m ∈ genWeightSpace M χ ↔ ∀ x, ∃ k : ℕ, ((toEnd R L M x - χ x • ↑1) ^ k) m = 0 := by + simp [genWeightSpace, mem_genWeightSpaceOf] -lemma weightSpace_le_weightSpaceOf (x : L) (χ : L → R) : - weightSpace M χ ≤ weightSpaceOf M (χ x) x := +lemma genWeightSpace_le_genWeightSpaceOf (x : L) (χ : L → R) : + genWeightSpace M χ ≤ genWeightSpaceOf M (χ x) x := iInf_le _ x variable (R L) in @@ -190,7 +190,7 @@ non-trivial. -/ structure Weight where /-- The family of eigenvalues corresponding to a weight. -/ toFun : L → R - weightSpace_ne_bot' : weightSpace M toFun ≠ ⊥ + genWeightSpace_ne_bot' : genWeightSpace M toFun ≠ ⊥ namespace Weight @@ -202,7 +202,7 @@ instance instFunLike : FunLike (Weight R L M) L R where (↑(⟨χ, h⟩ : Weight R L M) : L → R) = χ := rfl -lemma weightSpace_ne_bot (χ : Weight R L M) : weightSpace M χ ≠ ⊥ := χ.weightSpace_ne_bot' +lemma genWeightSpace_ne_bot (χ : Weight R L M) : genWeightSpace M χ ≠ ⊥ := χ.genWeightSpace_ne_bot' variable {M} @@ -212,19 +212,19 @@ variable {M} lemma ext_iff' {χ₁ χ₂ : Weight R L M} : (χ₁ : L → R) = χ₂ ↔ χ₁ = χ₂ := by aesop lemma exists_ne_zero (χ : Weight R L M) : - ∃ x ∈ weightSpace M χ, x ≠ 0 := by - simpa [LieSubmodule.eq_bot_iff] using χ.weightSpace_ne_bot + ∃ x ∈ genWeightSpace M χ, x ≠ 0 := by + simpa [LieSubmodule.eq_bot_iff] using χ.genWeightSpace_ne_bot instance [Subsingleton M] : IsEmpty (Weight R L M) := ⟨fun h ↦ h.2 (Subsingleton.elim _ _)⟩ -instance [Nontrivial (weightSpace M (0 : L → R))] : Zero (Weight R L M) := +instance [Nontrivial (genWeightSpace M (0 : L → R))] : Zero (Weight R L M) := ⟨0, fun e ↦ not_nontrivial (⊥ : LieSubmodule R L M) (e ▸ ‹_›)⟩ @[simp] -lemma coe_zero [Nontrivial (weightSpace M (0 : L → R))] : ((0 : Weight R L M) : L → R) = 0 := rfl +lemma coe_zero [Nontrivial (genWeightSpace M (0 : L → R))] : ((0 : Weight R L M) : L → R) = 0 := rfl -lemma zero_apply [Nontrivial (weightSpace M (0 : L → R))] (x) : (0 : Weight R L M) x = 0 := rfl +lemma zero_apply [Nontrivial (genWeightSpace M (0 : L → R))] (x) : (0 : Weight R L M) x = 0 := rfl /-- The proposition that a weight of a Lie module is zero. @@ -236,28 +236,30 @@ def IsZero (χ : Weight R L M) := (χ : L → R) = 0 @[simp] lemma coe_eq_zero_iff (χ : Weight R L M) : (χ : L → R) = 0 ↔ χ.IsZero := Iff.rfl -lemma isZero_iff_eq_zero [Nontrivial (weightSpace M (0 : L → R))] {χ : Weight R L M} : +lemma isZero_iff_eq_zero [Nontrivial (genWeightSpace M (0 : L → R))] {χ : Weight R L M} : χ.IsZero ↔ χ = 0 := Weight.ext_iff' (χ₂ := 0) -lemma isZero_zero [Nontrivial (weightSpace M (0 : L → R))] : IsZero (0 : Weight R L M) := rfl +lemma isZero_zero [Nontrivial (genWeightSpace M (0 : L → R))] : IsZero (0 : Weight R L M) := rfl /-- The proposition that a weight of a Lie module is non-zero. -/ abbrev IsNonZero (χ : Weight R L M) := ¬ IsZero (χ : Weight R L M) -lemma isNonZero_iff_ne_zero [Nontrivial (weightSpace M (0 : L → R))] {χ : 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 | weightSpace M χ ≠ ⊥} where +def equivSetOf : Weight R L M ≃ {χ : L → R | genWeightSpace M χ ≠ ⊥} where toFun w := ⟨w.1, w.2⟩ invFun w := ⟨w.1, w.2⟩ left_inv w := by simp right_inv w := by simp -lemma weightSpaceOf_ne_bot (χ : Weight R L M) (x : L) : - weightSpaceOf M (χ x) x ≠ ⊥ := by - have : ⨅ x, weightSpaceOf M (χ x) x ≠ ⊥ := χ.weightSpace_ne_bot +lemma genWeightSpaceOf_ne_bot (χ : Weight R L M) (x : L) : + genWeightSpaceOf M (χ x) x ≠ ⊥ := by + have : ⨅ x, genWeightSpaceOf M (χ x) x ≠ ⊥ := χ.genWeightSpace_ne_bot contrapose! this rw [eq_bot_iff] exact le_of_le_of_eq (iInf_le _ _) this @@ -265,7 +267,7 @@ lemma weightSpaceOf_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, weightSpaceOf] using χ.weightSpaceOf_ne_bot x + simpa [genWeightSpaceOf, Module.End.maxGenEigenspace_def] using χ.genWeightSpaceOf_ne_bot x exact Module.End.hasEigenvalue_of_hasGenEigenvalue hk lemma apply_eq_zero_of_isNilpotent [NoZeroSMulDivisors R M] [IsReduced R] @@ -275,91 +277,94 @@ lemma apply_eq_zero_of_isNilpotent [NoZeroSMulDivisors R M] [IsReduced R] end Weight -/-- See also the more useful form `LieModule.zero_weightSpace_eq_top_of_nilpotent`. -/ +/-- See also the more useful form `LieModule.zero_genWeightSpace_eq_top_of_nilpotent`. -/ @[simp] -theorem zero_weightSpace_eq_top_of_nilpotent' [IsNilpotent R L M] : - weightSpace M (0 : L → R) = ⊤ := by +theorem zero_genWeightSpace_eq_top_of_nilpotent' [IsNilpotent R L M] : + genWeightSpace M (0 : L → R) = ⊤ := by ext - simp [weightSpace, weightSpaceOf] + simp [genWeightSpace, genWeightSpaceOf] -theorem coe_weightSpace_of_top (χ : L → R) : - (weightSpace M (χ ∘ (⊤ : LieSubalgebra R L).incl) : Submodule R M) = weightSpace M χ := by +theorem coe_genWeightSpace_of_top (χ : L → R) : + (genWeightSpace M (χ ∘ (⊤ : LieSubalgebra R L).incl) : Submodule R M) = genWeightSpace M χ := by ext m - simp only [mem_weightSpace, LieSubmodule.mem_coeSubmodule, Subtype.forall] + simp only [mem_genWeightSpace, LieSubmodule.mem_coeSubmodule, Subtype.forall] apply forall_congr' simp @[simp] -theorem zero_weightSpace_eq_top_of_nilpotent [IsNilpotent R L M] : - weightSpace M (0 : (⊤ : LieSubalgebra R L) → R) = ⊤ := by +theorem zero_genWeightSpace_eq_top_of_nilpotent [IsNilpotent R L M] : + genWeightSpace M (0 : (⊤ : LieSubalgebra R L) → R) = ⊤ := by ext m - simp only [mem_weightSpace, Pi.zero_apply, zero_smul, sub_zero, Subtype.forall, forall_true_left, - LieSubalgebra.toEnd_mk, LieSubalgebra.mem_top, LieSubmodule.mem_top, iff_true] + simp only [mem_genWeightSpace, Pi.zero_apply, zero_smul, sub_zero, Subtype.forall, + forall_true_left, LieSubalgebra.toEnd_mk, LieSubalgebra.mem_top, LieSubmodule.mem_top, iff_true] intro x obtain ⟨k, hk⟩ := exists_forall_pow_toEnd_eq_zero R L M exact ⟨k, by simp [hk x]⟩ -theorem exists_weightSpace_le_ker_of_isNoetherian [IsNoetherian R M] (χ : L → R) (x : L) : +theorem exists_genWeightSpace_le_ker_of_isNoetherian [IsNoetherian R M] (χ : L → R) (x : L) : ∃ k : ℕ, - weightSpace M χ ≤ LinearMap.ker ((toEnd R L M x - algebraMap R _ (χ x)) ^ k) := by + genWeightSpace M χ ≤ LinearMap.ker ((toEnd R L M x - algebraMap R _ (χ x)) ^ k) := by use (toEnd R L M x).maxGenEigenspaceIndex (χ x) intro m hm replace hm : m ∈ (toEnd R L M x).maxGenEigenspace (χ x) := - weightSpace_le_weightSpaceOf M x χ hm - rwa [Module.End.maxGenEigenspace_eq] at hm + genWeightSpace_le_genWeightSpaceOf M x χ hm + rwa [Module.End.maxGenEigenspace_eq, Module.End.genEigenspace_def] at hm variable (R) in -theorem exists_weightSpace_zero_le_ker_of_isNoetherian +theorem exists_genWeightSpace_zero_le_ker_of_isNoetherian [IsNoetherian R M] (x : L) : - ∃ k : ℕ, weightSpace M (0 : L → R) ≤ LinearMap.ker (toEnd R L M x ^ k) := by - simpa using exists_weightSpace_le_ker_of_isNoetherian M (0 : L → R) x + ∃ k : ℕ, genWeightSpace M (0 : L → R) ≤ LinearMap.ker (toEnd R L M x ^ k) := by + simpa using exists_genWeightSpace_le_ker_of_isNoetherian M (0 : L → R) x lemma isNilpotent_toEnd_sub_algebraMap [IsNoetherian R M] (χ : L → R) (x : L) : - _root_.IsNilpotent <| toEnd R L (weightSpace M χ) x - algebraMap R _ (χ x) := by - have : toEnd R L (weightSpace M χ) x - algebraMap R _ (χ x) = + _root_.IsNilpotent <| toEnd R L (genWeightSpace M χ) x - algebraMap R _ (χ x) := by + have : toEnd R L (genWeightSpace M χ) x - algebraMap R _ (χ x) = (toEnd R L M x - algebraMap R _ (χ x)).restrict (fun m hm ↦ sub_mem (LieSubmodule.lie_mem _ hm) (Submodule.smul_mem _ _ hm)) := by rfl - obtain ⟨k, hk⟩ := exists_weightSpace_le_ker_of_isNoetherian M χ x + 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. -/ -theorem isNilpotent_toEnd_weightSpace_zero [IsNoetherian R M] (x : L) : - _root_.IsNilpotent <| toEnd R L (weightSpace M (0 : L → R)) x := by +theorem isNilpotent_toEnd_genWeightSpace_zero [IsNoetherian R M] (x : L) : + _root_.IsNilpotent <| toEnd R L (genWeightSpace M (0 : L → R)) x := by simpa using isNilpotent_toEnd_sub_algebraMap M (0 : L → R) x /-- By Engel's theorem, the zero weight space of a Noetherian Lie module is nilpotent. -/ instance [IsNoetherian R M] : - IsNilpotent R L (weightSpace M (0 : L → R)) := - isNilpotent_iff_forall'.mpr <| isNilpotent_toEnd_weightSpace_zero M + IsNilpotent R L (genWeightSpace M (0 : L → R)) := + isNilpotent_iff_forall'.mpr <| isNilpotent_toEnd_genWeightSpace_zero M variable (R L) @[simp] -lemma weightSpace_zero_normalizer_eq_self : - (weightSpace M (0 : L → R)).normalizer = weightSpace M 0 := by +lemma genWeightSpace_zero_normalizer_eq_self : + (genWeightSpace M (0 : L → R)).normalizer = genWeightSpace M 0 := by refine le_antisymm ?_ (LieSubmodule.le_normalizer _) intro m hm rw [LieSubmodule.mem_normalizer] at hm - simp only [mem_weightSpace, Pi.zero_apply, zero_smul, sub_zero] at hm ⊢ + simp only [mem_genWeightSpace, Pi.zero_apply, zero_smul, sub_zero] at hm ⊢ intro y obtain ⟨k, hk⟩ := hm y y use k + 1 simpa [pow_succ, LinearMap.mul_eq_comp] -lemma iSup_ucs_le_weightSpace_zero : - ⨆ k, (⊥ : LieSubmodule R L M).ucs k ≤ weightSpace M (0 : L → R) := by - simpa using LieSubmodule.ucs_le_of_normalizer_eq_self (weightSpace_zero_normalizer_eq_self R L M) +lemma iSup_ucs_le_genWeightSpace_zero : + ⨆ k, (⊥ : LieSubmodule R L M).ucs k ≤ genWeightSpace M (0 : L → R) := by + simpa using + LieSubmodule.ucs_le_of_normalizer_eq_self (genWeightSpace_zero_normalizer_eq_self R L M) /-- See also `LieModule.iInf_lowerCentralSeries_eq_posFittingComp`. -/ -lemma iSup_ucs_eq_weightSpace_zero [IsNoetherian R M] : - ⨆ k, (⊥ : LieSubmodule R L M).ucs k = weightSpace M (0 : L → R) := by +lemma iSup_ucs_eq_genWeightSpace_zero [IsNoetherian R M] : + ⨆ k, (⊥ : LieSubmodule R L M).ucs k = genWeightSpace M (0 : L → R) := by obtain ⟨k, hk⟩ := (LieSubmodule.isNilpotent_iff_exists_self_le_ucs - <| weightSpace M (0 : L → R)).mp inferInstance - refine le_antisymm (iSup_ucs_le_weightSpace_zero R L M) (le_trans hk ?_) + <| genWeightSpace M (0 : L → R)).mp inferInstance + refine le_antisymm (iSup_ucs_le_genWeightSpace_zero R L M) (le_trans hk ?_) exact le_iSup (fun k ↦ (⊥ : LieSubmodule R L M).ucs k) k variable {L} @@ -369,7 +374,7 @@ variable {L} `range φₓ ⊇ range φₓ² ⊇ range φₓ³ ⊇ ⋯` where `φₓ : End R M := toEnd R L M x`. We call this the "positive Fitting component" because with appropriate assumptions (e.g., `R` is a field and `M` is finite-dimensional) `φₓ` induces the so-called Fitting decomposition: `M = M₀ ⊕ M₁` where -`M₀ = weightSpaceOf M 0 x` and `M₁ = posFittingCompOf R M x`. +`M₀ = genWeightSpaceOf M 0 x` and `M₁ = posFittingCompOf R M x`. It is a Lie submodule because `L` is nilpotent. -/ def posFittingCompOf (x : L) : LieSubmodule R L M := @@ -406,10 +411,11 @@ lemma mem_posFittingCompOf (x : L) (m : M) : obtain ⟨n, rfl⟩ := (mem_posFittingCompOf R x m).mp hm k exact this n k intro m l - induction' l with l ih - · simp - simp only [lowerCentralSeries_succ, pow_succ', LinearMap.mul_apply] - exact LieSubmodule.lie_mem_lie (LieSubmodule.mem_top x) ih + induction l with + | zero => simp + | succ l ih => + simp only [lowerCentralSeries_succ, pow_succ', LinearMap.mul_apply] + exact LieSubmodule.lie_mem_lie (LieSubmodule.mem_top x) ih @[simp] lemma posFittingCompOf_eq_bot_of_isNilpotent [IsNilpotent R L M] (x : L) : @@ -439,7 +445,7 @@ lemma posFittingComp_le_iInf_lowerCentralSeries : posFittingComp R L M ≤ ⨅ k, lowerCentralSeries R L M k := by simp [posFittingComp] -/-- See also `LieModule.iSup_ucs_eq_weightSpace_zero`. -/ +/-- See also `LieModule.iSup_ucs_eq_genWeightSpace_zero`. -/ @[simp] lemma iInf_lowerCentralSeries_eq_posFittingComp [IsNoetherian R M] [IsArtinian R M] : ⨅ k, lowerCentralSeries R L M k = posFittingComp R L M := by @@ -485,24 +491,24 @@ lemma map_posFittingComp_le : use f n rw [LieModule.toEnd_pow_apply_map, hn] -lemma map_weightSpace_le : - (weightSpace M χ).map f ≤ weightSpace M₂ χ := by +lemma map_genWeightSpace_le : + (genWeightSpace M χ).map f ≤ genWeightSpace M₂ χ := by rw [LieSubmodule.map_le_iff_le_comap] intro m hm - simp only [LieSubmodule.mem_comap, mem_weightSpace] + simp only [LieSubmodule.mem_comap, mem_genWeightSpace] intro x have : (toEnd R L M₂ x - χ x • ↑1) ∘ₗ f = f ∘ₗ (toEnd R L M x - χ x • ↑1) := by ext; simp - obtain ⟨k, h⟩ := (mem_weightSpace _ _ _).mp hm x + obtain ⟨k, h⟩ := (mem_genWeightSpace _ _ _).mp hm x exact ⟨k, by simpa [h] using LinearMap.congr_fun (LinearMap.commute_pow_left_of_commute this k) m⟩ variable {f} -lemma comap_weightSpace_eq_of_injective (hf : Injective f) : - (weightSpace M₂ χ).comap f = weightSpace M χ := by +lemma comap_genWeightSpace_eq_of_injective (hf : Injective f) : + (genWeightSpace M₂ χ).comap f = genWeightSpace M χ := by refine le_antisymm (fun m hm ↦ ?_) ?_ - · simp only [LieSubmodule.mem_comap, mem_weightSpace] at hm - simp only [mem_weightSpace] + · simp only [LieSubmodule.mem_comap, mem_genWeightSpace] at hm + simp only [mem_genWeightSpace] intro x have h : (toEnd R L M₂ x - χ x • ↑1) ∘ₗ f = f ∘ₗ (toEnd R L M x - χ x • ↑1) := by ext; simp @@ -512,18 +518,19 @@ lemma comap_weightSpace_eq_of_injective (hf : Injective f) : rw [← f.map_zero] at this; exact hf this simpa [hk] using (LinearMap.congr_fun (LinearMap.commute_pow_left_of_commute h k) m).symm · rw [← LieSubmodule.map_le_iff_le_comap] - exact map_weightSpace_le f + exact map_genWeightSpace_le f -lemma map_weightSpace_eq_of_injective (hf : Injective f) : - (weightSpace M χ).map f = weightSpace M₂ χ ⊓ f.range := by - refine le_antisymm (le_inf_iff.mpr ⟨map_weightSpace_le f, LieSubmodule.map_le_range f⟩) ?_ +lemma map_genWeightSpace_eq_of_injective (hf : Injective f) : + (genWeightSpace M χ).map f = genWeightSpace M₂ χ ⊓ f.range := by + refine le_antisymm (le_inf_iff.mpr ⟨map_genWeightSpace_le f, LieSubmodule.map_le_range f⟩) ?_ rintro - ⟨hm, ⟨m, rfl⟩⟩ - simp only [← comap_weightSpace_eq_of_injective hf, LieSubmodule.mem_map, LieSubmodule.mem_comap] + simp only [← comap_genWeightSpace_eq_of_injective hf, LieSubmodule.mem_map, + LieSubmodule.mem_comap] exact ⟨m, hm, rfl⟩ -lemma map_weightSpace_eq (e : M ≃ₗ⁅R,L⁆ M₂) : - (weightSpace M χ).map e = weightSpace M₂ χ := by - simp [map_weightSpace_eq_of_injective e.injective] +lemma map_genWeightSpace_eq (e : M ≃ₗ⁅R,L⁆ M₂) : + (genWeightSpace M χ).map e = genWeightSpace M₂ χ := by + simp [map_genWeightSpace_eq_of_injective e.injective] lemma map_posFittingComp_eq (e : M ≃ₗ⁅R,L⁆ M₂) : (posFittingComp R L M).map e = posFittingComp R L M₂ := by @@ -549,11 +556,11 @@ lemma posFittingComp_map_incl_sup_of_codisjoint [IsNoetherian R M] [IsArtinian R LieSubmodule.lowerCentralSeries_map_eq_lcs, ← LieSubmodule.lcs_sup, lowerCentralSeries, h.eq_top] -lemma weightSpace_weightSpaceOf_map_incl (x : L) (χ : L → R) : - (weightSpace (weightSpaceOf M (χ x) x) χ).map (weightSpaceOf M (χ x) x).incl = - weightSpace M χ := by - simpa [map_weightSpace_eq_of_injective (weightSpaceOf M (χ x) x).injective_incl] - using weightSpace_le_weightSpaceOf M x χ +lemma genWeightSpace_genWeightSpaceOf_map_incl (x : L) (χ : L → R) : + (genWeightSpace (genWeightSpaceOf M (χ x) x) χ).map (genWeightSpaceOf M (χ x) x).incl = + genWeightSpace M χ := by + simpa [map_genWeightSpace_eq_of_injective (genWeightSpaceOf M (χ x) x).injective_incl] + using genWeightSpace_le_genWeightSpaceOf M x χ end map_comap @@ -561,34 +568,35 @@ section fitting_decomposition variable [IsNoetherian R M] [IsArtinian R M] -lemma isCompl_weightSpaceOf_zero_posFittingCompOf (x : L) : - IsCompl (weightSpaceOf M 0 x) (posFittingCompOf R M x) := by +lemma isCompl_genWeightSpaceOf_zero_posFittingCompOf (x : L) : + IsCompl (genWeightSpaceOf M 0 x) (posFittingCompOf R M x) := by simpa only [isCompl_iff, codisjoint_iff, disjoint_iff, ← LieSubmodule.coe_toSubmodule_eq_iff, LieSubmodule.sup_coe_toSubmodule, LieSubmodule.inf_coe_toSubmodule, - LieSubmodule.top_coeSubmodule, LieSubmodule.bot_coeSubmodule, coe_weightSpaceOf_zero] using + LieSubmodule.top_coeSubmodule, LieSubmodule.bot_coeSubmodule, coe_genWeightSpaceOf_zero] using (toEnd R L M x).isCompl_iSup_ker_pow_iInf_range_pow /-- This lemma exists only to simplify the proof of -`LieModule.isCompl_weightSpace_zero_posFittingComp`. -/ -private lemma isCompl_weightSpace_zero_posFittingComp_aux - (h : ∀ N < (⊤ : LieSubmodule R L M), IsCompl (weightSpace N 0) (posFittingComp R L N)) : - IsCompl (weightSpace M 0) (posFittingComp R L M) := by - set M₀ := weightSpace M (0 : L → R) +`LieModule.isCompl_genWeightSpace_zero_posFittingComp`. -/ +private lemma isCompl_genWeightSpace_zero_posFittingComp_aux + (h : ∀ N < (⊤ : LieSubmodule R L M), IsCompl (genWeightSpace N 0) (posFittingComp R L N)) : + IsCompl (genWeightSpace M 0) (posFittingComp R L M) := by + set M₀ := genWeightSpace M (0 : L → R) set M₁ := posFittingComp R L M - rcases forall_or_exists_not (fun (x : L) ↦ weightSpaceOf M (0 : R) x = ⊤) - with h | ⟨x, hx : weightSpaceOf M (0 : R) x ≠ ⊤⟩ + rcases forall_or_exists_not (fun (x : L) ↦ genWeightSpaceOf M (0 : R) x = ⊤) + with h | ⟨x, hx : genWeightSpaceOf M (0 : R) x ≠ ⊤⟩ · suffices IsNilpotent R L M by simp [M₀, M₁, isCompl_top_bot] - replace h : M₀ = ⊤ := by simpa [M₀, weightSpace] + replace h : M₀ = ⊤ := by simpa [M₀, genWeightSpace] rw [← LieModule.isNilpotent_of_top_iff', ← h] infer_instance - · set M₀ₓ := weightSpaceOf M (0 : R) x + · set M₀ₓ := genWeightSpaceOf M (0 : R) x set M₁ₓ := posFittingCompOf R M x - set M₀ₓ₀ := weightSpace M₀ₓ (0 : L → R) + set M₀ₓ₀ := genWeightSpace M₀ₓ (0 : L → R) set M₀ₓ₁ := posFittingComp R L M₀ₓ - have h₁ : IsCompl M₀ₓ M₁ₓ := isCompl_weightSpaceOf_zero_posFittingCompOf R L M x + have h₁ : IsCompl M₀ₓ M₁ₓ := isCompl_genWeightSpaceOf_zero_posFittingCompOf R L M x have h₂ : IsCompl M₀ₓ₀ M₀ₓ₁ := h M₀ₓ hx.lt_top have h₃ : M₀ₓ₀.map M₀ₓ.incl = M₀ := by - rw [map_weightSpace_eq_of_injective M₀ₓ.injective_incl, inf_eq_left, LieSubmodule.range_incl] + rw [map_genWeightSpace_eq_of_injective M₀ₓ.injective_incl, inf_eq_left, + LieSubmodule.range_incl] exact iInf_le _ x have h₄ : M₀ₓ₁.map M₀ₓ.incl ⊔ M₁ₓ = M₁ := by apply le_antisymm <| sup_le_iff.mpr @@ -602,75 +610,79 @@ private lemma isCompl_weightSpace_zero_posFittingComp_aux · rwa [← LieSubmodule.map_sup, h₂.sup_eq_top, LieModuleHom.map_top, LieSubmodule.range_incl] /-- This is the Fitting decomposition of the Lie module `M`. -/ -lemma isCompl_weightSpace_zero_posFittingComp : - IsCompl (weightSpace M 0) (posFittingComp R L M) := by - let P : LieSubmodule R L M → Prop := fun N ↦ IsCompl (weightSpace N 0) (posFittingComp R L N) +lemma isCompl_genWeightSpace_zero_posFittingComp : + IsCompl (genWeightSpace M 0) (posFittingComp R L M) := by + let P : LieSubmodule R L M → Prop := fun N ↦ IsCompl (genWeightSpace N 0) (posFittingComp R L N) suffices P ⊤ by let e := LieModuleEquiv.ofTop R L M - rw [← map_weightSpace_eq e, ← map_posFittingComp_eq e] + rw [← map_genWeightSpace_eq e, ← map_posFittingComp_eq e] exact (LieSubmodule.orderIsoMapComap e).isCompl_iff.mp this - refine (LieSubmodule.wellFounded_of_isArtinian R L M).induction (C := P) _ fun N hN ↦ ?_ - refine isCompl_weightSpace_zero_posFittingComp_aux R L N fun N' hN' ↦ ?_ - suffices IsCompl (weightSpace (N'.map N.incl) 0) (posFittingComp R L (N'.map N.incl)) by + refine (LieSubmodule.wellFoundedLT_of_isArtinian R L M).induction (C := P) _ fun N hN ↦ ?_ + refine isCompl_genWeightSpace_zero_posFittingComp_aux R L N fun N' hN' ↦ ?_ + suffices IsCompl (genWeightSpace (N'.map N.incl) 0) (posFittingComp R L (N'.map N.incl)) by let e := LieSubmodule.equivMapOfInjective N' N.injective_incl - rw [← map_weightSpace_eq e, ← map_posFittingComp_eq e] at this + rw [← map_genWeightSpace_eq e, ← map_posFittingComp_eq e] at this exact (LieSubmodule.orderIsoMapComap e).isCompl_iff.mpr this exact hN _ (LieSubmodule.map_incl_lt_iff_lt_top.mpr hN') end fitting_decomposition -lemma disjoint_weightSpaceOf [NoZeroSMulDivisors R M] {x : L} {φ₁ φ₂ : R} (h : φ₁ ≠ φ₂) : - Disjoint (weightSpaceOf M φ₁ x) (weightSpaceOf M φ₂ x) := by +lemma disjoint_genWeightSpaceOf [NoZeroSMulDivisors R M] {x : L} {φ₁ φ₂ : R} (h : φ₁ ≠ φ₂) : + Disjoint (genWeightSpaceOf M φ₁ x) (genWeightSpaceOf M φ₂ x) := by rw [LieSubmodule.disjoint_iff_coe_toSubmodule] + dsimp [genWeightSpaceOf] + simp_rw [Module.End.maxGenEigenspace_def] exact Module.End.disjoint_iSup_genEigenspace _ h -lemma disjoint_weightSpace [NoZeroSMulDivisors R M] {χ₁ χ₂ : L → R} (h : χ₁ ≠ χ₂) : - Disjoint (weightSpace M χ₁) (weightSpace M χ₂) := by +lemma disjoint_genWeightSpace [NoZeroSMulDivisors R M] {χ₁ χ₂ : L → R} (h : χ₁ ≠ χ₂) : + Disjoint (genWeightSpace M χ₁) (genWeightSpace M χ₂) := by obtain ⟨x, hx⟩ : ∃ x, χ₁ x ≠ χ₂ x := Function.ne_iff.mp h - exact (disjoint_weightSpaceOf R L M hx).mono - (weightSpace_le_weightSpaceOf M x χ₁) (weightSpace_le_weightSpaceOf M x χ₂) + exact (disjoint_genWeightSpaceOf R L M hx).mono + (genWeightSpace_le_genWeightSpaceOf M x χ₁) (genWeightSpace_le_genWeightSpaceOf M x χ₂) -lemma injOn_weightSpace [NoZeroSMulDivisors R M] : - InjOn (fun (χ : L → R) ↦ weightSpace M χ) {χ | weightSpace M χ ≠ ⊥} := by - rintro χ₁ _ χ₂ hχ₂ (hχ₁₂ : weightSpace M χ₁ = weightSpace M χ₂) +lemma injOn_genWeightSpace [NoZeroSMulDivisors R M] : + InjOn (fun (χ : L → R) ↦ genWeightSpace M χ) {χ | genWeightSpace M χ ≠ ⊥} := by + rintro χ₁ _ χ₂ hχ₂ (hχ₁₂ : genWeightSpace M χ₁ = genWeightSpace M χ₂) contrapose! hχ₂ - simpa [hχ₁₂] using disjoint_weightSpace R L M hχ₂ + simpa [hχ₁₂] using disjoint_genWeightSpace R L M hχ₂ /-- Lie module weight spaces are independent. -See also `LieModule.independent_weightSpace'`. -/ -lemma independent_weightSpace [NoZeroSMulDivisors R M] : - CompleteLattice.Independent fun (χ : L → R) ↦ weightSpace M χ := by +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 (weightSpace M χ) (s.sup fun (χ : L → R) ↦ weightSpace M χ) by - simpa only [CompleteLattice.independent_iff_supIndep_of_injOn (injOn_weightSpace R L M), + 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 χ₂ s _ ih - · simp + 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 ∈ weightSpace M χ₂ by - rw [← LieSubmodule.mem_bot (R := R) (L := L), ← (disjoint_weightSpace R L M hχ₁₂).eq_bot] + 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) ∈ - weightSpace M χ₁ ⊓ Finset.sup s fun χ ↦ weightSpace M χ by - simpa only [ih.eq_bot, LieSubmodule.mem_bot, mem_weightSpace] using this + 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_weightSpace _ _ _).mp hy 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 χ ↦ weightSpace M χ : Submodule R M).map (g ^ k) ≤ - s.sup fun χ ↦ weightSpace M χ by + 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 @@ -681,29 +693,29 @@ lemma independent_weightSpace [NoZeroSMulDivisors R M] : rintro - ⟨u, hu, rfl⟩ exact LieSubmodule.mapsTo_pow_toEnd_sub_algebraMap _ hu -lemma independent_weightSpace' [NoZeroSMulDivisors R M] : - CompleteLattice.Independent fun χ : Weight R L M ↦ weightSpace M χ := - (independent_weightSpace R L M).comp <| +lemma independent_genWeightSpace' [NoZeroSMulDivisors R M] : + CompleteLattice.Independent fun χ : Weight R L M ↦ genWeightSpace M χ := + (independent_genWeightSpace R L M).comp <| Subtype.val_injective.comp (Weight.equivSetOf R L M).injective -lemma independent_weightSpaceOf [NoZeroSMulDivisors R M] (x : L) : - CompleteLattice.Independent fun (χ : R) ↦ weightSpaceOf M χ x := by +lemma independent_genWeightSpaceOf [NoZeroSMulDivisors R M] (x : L) : + CompleteLattice.Independent fun (χ : R) ↦ genWeightSpaceOf M χ x := by rw [LieSubmodule.independent_iff_coe_toSubmodule] + dsimp [genWeightSpaceOf] + simp_rw [Module.End.maxGenEigenspace_def] exact (toEnd R L M x).independent_genEigenspace -lemma finite_weightSpaceOf_ne_bot [NoZeroSMulDivisors R M] [IsNoetherian R M] (x : L) : - {χ : R | weightSpaceOf M χ x ≠ ⊥}.Finite := - CompleteLattice.WellFounded.finite_ne_bot_of_independent - (LieSubmodule.wellFounded_of_noetherian R L M) (independent_weightSpaceOf R L M x) +lemma finite_genWeightSpaceOf_ne_bot [NoZeroSMulDivisors R M] [IsNoetherian R M] (x : L) : + {χ : R | genWeightSpaceOf M χ x ≠ ⊥}.Finite := + CompleteLattice.WellFoundedGT.finite_ne_bot_of_independent (independent_genWeightSpaceOf R L M x) -lemma finite_weightSpace_ne_bot [NoZeroSMulDivisors R M] [IsNoetherian R M] : - {χ : L → R | weightSpace M χ ≠ ⊥}.Finite := - CompleteLattice.WellFounded.finite_ne_bot_of_independent - (LieSubmodule.wellFounded_of_noetherian R L M) (independent_weightSpace R L M) +lemma finite_genWeightSpace_ne_bot [NoZeroSMulDivisors R M] [IsNoetherian R M] : + {χ : L → R | genWeightSpace M χ ≠ ⊥}.Finite := + 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 - have : Finite {χ : L → R | weightSpace M χ ≠ ⊥} := finite_weightSpace_ne_bot R L M + have : Finite {χ : L → R | genWeightSpace M χ ≠ ⊥} := finite_genWeightSpace_ne_bot R L M exact Finite.of_injective (equivSetOf R L M) (equivSetOf R L M).injective noncomputable instance Weight.instFintype [NoZeroSMulDivisors R M] [IsNoetherian R M] : @@ -712,7 +724,7 @@ 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 := +class IsTriangularizable : Prop where iSup_eq_top : ∀ x, ⨆ φ, ⨆ k, (toEnd R L M x).genEigenspace φ k = ⊤ instance (L' : LieSubalgebra R L) [IsTriangularizable R L M] : IsTriangularizable R L' M where @@ -725,18 +737,20 @@ instance [IsTriangularizable R L M] : IsTriangularizable R (LieModule.toEnd R L iSup_eq_top := by rintro ⟨-, x, rfl⟩; exact IsTriangularizable.iSup_eq_top x @[simp] -lemma iSup_weightSpaceOf_eq_top [IsTriangularizable R L M] (x : L) : - ⨆ (φ : R), weightSpaceOf M φ x = ⊤ := by +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] + dsimp [genWeightSpaceOf] + simp_rw [Module.End.maxGenEigenspace_def] exact IsTriangularizable.iSup_eq_top x -open LinearMap FiniteDimensional in +open LinearMap Module in @[simp] -lemma trace_toEnd_weightSpace [IsDomain R] [IsPrincipalIdealRing R] +lemma trace_toEnd_genWeightSpace [IsDomain R] [IsPrincipalIdealRing R] [Module.Free R M] [Module.Finite R M] (χ : L → R) (x : L) : - trace R _ (toEnd R L (weightSpace M χ) x) = finrank R (weightSpace M χ) • χ x := by - suffices _root_.IsNilpotent ((toEnd R L (weightSpace M χ) x) - χ x • LinearMap.id) by + trace R _ (toEnd R L (genWeightSpace M χ) x) = finrank R (genWeightSpace M χ) • χ x := by + suffices _root_.IsNilpotent ((toEnd R L (genWeightSpace M χ) x) - χ x • LinearMap.id) by replace this := (isNilpotent_trace_of_isNilpotent this).eq_zero rwa [map_sub, map_smul, trace_id, sub_eq_zero, smul_eq_mul, mul_comm, ← nsmul_eq_mul] at this @@ -745,7 +759,7 @@ lemma trace_toEnd_weightSpace [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] @@ -761,41 +775,19 @@ instance (N : LieSubmodule K L M) [IsTriangularizable K L M] : IsTriangularizabl /-- For a triangularizable Lie module in finite dimensions, the weight spaces span the entire space. -See also `LieModule.iSup_weightSpace_eq_top'`. -/ -lemma iSup_weightSpace_eq_top [IsTriangularizable K L M] : - ⨆ χ : L → K, weightSpace M χ = ⊤ := by - induction' h_dim : finrank K M using Nat.strong_induction_on with n ih generalizing M - obtain h' | ⟨y : L, hy : ¬ ∃ φ, weightSpaceOf M φ y = ⊤⟩ := - forall_or_exists_not (fun (x : L) ↦ ∃ (φ : K), weightSpaceOf M φ x = ⊤) - · choose χ hχ using h' - replace hχ : weightSpace M χ = ⊤ := by simpa only [weightSpace, hχ] using iInf_top - exact eq_top_iff.mpr <| hχ ▸ le_iSup (weightSpace M) χ - · replace hy : ∀ φ, finrank K (weightSpaceOf 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, weightSpace (weightSpaceOf M φ y) χ = ⊤ := - fun φ ↦ ih _ (hy φ) (weightSpaceOf M φ y) rfl - replace ih : ∀ φ, ⨆ (χ : L → K) (_ : χ y = φ), weightSpace (weightSpaceOf M φ y) χ = ⊤ := by - intro φ - suffices ∀ χ : L → K, χ y ≠ φ → weightSpace (weightSpaceOf M φ y) χ = ⊥ by - specialize ih φ; rw [iSup_split, biSup_congr this] at ih; simpa using ih - intro χ hχ - rw [eq_bot_iff, ← (weightSpaceOf M φ y).ker_incl, LieModuleHom.ker, - ← LieSubmodule.map_le_iff_le_comap, map_weightSpace_eq_of_injective - (weightSpaceOf M φ y).injective_incl, LieSubmodule.range_incl, ← disjoint_iff_inf_le] - exact (disjoint_weightSpaceOf K L M hχ).mono_left (weightSpace_le_weightSpaceOf M y χ) - replace ih : ∀ φ, ⨆ (χ : L → K) (_ : χ y = φ), weightSpace M χ = weightSpaceOf M φ y := by - intro φ - have : ∀ (χ : L → K) (_ : χ y = φ), weightSpace M χ = - (weightSpace (weightSpaceOf M φ y) χ).map (weightSpaceOf M φ y).incl := fun χ hχ ↦ by - rw [← hχ, weightSpace_weightSpaceOf_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_weightSpaceOf_eq_top K L M y - -lemma iSup_weightSpace_eq_top' [IsTriangularizable K L M] : - ⨆ χ : Weight K L M, weightSpace M χ = ⊤ := by - have := iSup_weightSpace_eq_top K L M +See also `LieModule.iSup_genWeightSpace_eq_top'`. -/ +lemma iSup_genWeightSpace_eq_top [IsTriangularizable K L M] : + ⨆ χ : L → K, genWeightSpace M χ = ⊤ := by + 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) ?_ + simp_rw [Module.End.maxGenEigenspace_def] + apply IsTriangularizable.iSup_eq_top + +lemma iSup_genWeightSpace_eq_top' [IsTriangularizable K L M] : + ⨆ χ : Weight K L M, genWeightSpace M χ = ⊤ := by + have := iSup_genWeightSpace_eq_top K L M erw [← iSup_ne_bot_subtype, ← (Weight.equivSetOf K L M).iSup_comp] at this exact this diff --git a/Mathlib/Algebra/Lie/Weights/Cartan.lean b/Mathlib/Algebra/Lie/Weights/Cartan.lean index a78eaf08e3214..0ef812f460f9e 100644 --- a/Mathlib/Algebra/Lie/Weights/Cartan.lean +++ b/Mathlib/Algebra/Lie/Weights/Cartan.lean @@ -42,38 +42,39 @@ open TensorProduct.LieModule LieModule /-- Given a nilpotent Lie subalgebra `H ⊆ L`, the root space of a map `χ : H → R` is the weight space of `L` regarded as a module of `H` via the adjoint action. -/ abbrev rootSpace (χ : H → R) : LieSubmodule R H L := - weightSpace L χ + genWeightSpace L χ theorem zero_rootSpace_eq_top_of_nilpotent [IsNilpotent R L] : rootSpace (⊤ : LieSubalgebra R L) 0 = ⊤ := - zero_weightSpace_eq_top_of_nilpotent L + zero_genWeightSpace_eq_top_of_nilpotent L @[simp] -theorem rootSpace_comap_eq_weightSpace (χ : H → R) : - (rootSpace H χ).comap H.incl' = weightSpace H χ := - comap_weightSpace_eq_of_injective Subtype.coe_injective +theorem rootSpace_comap_eq_genWeightSpace (χ : H → R) : + (rootSpace H χ).comap H.incl' = genWeightSpace H χ := + comap_genWeightSpace_eq_of_injective Subtype.coe_injective variable {H} -theorem lie_mem_weightSpace_of_mem_weightSpace {χ₁ χ₂ : H → R} {x : L} {m : M} - (hx : x ∈ rootSpace H χ₁) (hm : m ∈ weightSpace M χ₂) : ⁅x, m⁆ ∈ weightSpace M (χ₁ + χ₂) := by - rw [weightSpace, LieSubmodule.mem_iInf] +theorem lie_mem_genWeightSpace_of_mem_genWeightSpace {χ₁ χ₂ : H → R} {x : L} {m : M} + (hx : x ∈ rootSpace H χ₁) (hm : m ∈ genWeightSpace M χ₂) : + ⁅x, m⁆ ∈ genWeightSpace M (χ₁ + χ₂) := by + rw [genWeightSpace, LieSubmodule.mem_iInf] intro y - replace hx : x ∈ weightSpaceOf L (χ₁ y) y := by - rw [rootSpace, weightSpace, LieSubmodule.mem_iInf] at hx; exact hx y - replace hm : m ∈ weightSpaceOf M (χ₂ y) y := by - rw [weightSpace, LieSubmodule.mem_iInf] at hm; exact hm y + replace hx : x ∈ genWeightSpaceOf L (χ₁ y) y := by + rw [rootSpace, genWeightSpace, LieSubmodule.mem_iInf] at hx; exact hx y + replace hm : m ∈ genWeightSpaceOf M (χ₂ y) y := by + rw [genWeightSpace, LieSubmodule.mem_iInf] at hm; exact hm y exact lie_mem_maxGenEigenspace_toEnd hx hm lemma toEnd_pow_apply_mem {χ₁ χ₂ : H → R} {x : L} {m : M} - (hx : x ∈ rootSpace H χ₁) (hm : m ∈ weightSpace M χ₂) (n) : - (toEnd R L M x ^ n : Module.End R M) m ∈ weightSpace M (n • χ₁ + χ₂) := by + (hx : x ∈ rootSpace H χ₁) (hm : m ∈ genWeightSpace M χ₂) (n) : + (toEnd R L M x ^ n : Module.End R M) m ∈ genWeightSpace M (n • χ₁ + χ₂) := by induction n with | zero => simpa using hm | succ n IH => simp only [pow_succ', LinearMap.mul_apply, toEnd_apply_apply, Nat.cast_add, Nat.cast_one, rootSpace] - convert lie_mem_weightSpace_of_mem_weightSpace hx IH using 2 + convert lie_mem_genWeightSpace_of_mem_genWeightSpace hx IH using 2 rw [succ_nsmul, ← add_assoc, add_comm (n • _)] variable (R L H M) @@ -82,11 +83,12 @@ variable (R L H M) which is close to the deterministic timeout limit. -/ def rootSpaceWeightSpaceProductAux {χ₁ χ₂ χ₃ : H → R} (hχ : χ₁ + χ₂ = χ₃) : - rootSpace H χ₁ →ₗ[R] weightSpace M χ₂ →ₗ[R] weightSpace M χ₃ where + rootSpace H χ₁ →ₗ[R] genWeightSpace M χ₂ →ₗ[R] genWeightSpace M χ₃ where toFun x := { toFun := fun m => - ⟨⁅(x : L), (m : M)⁆, hχ ▸ lie_mem_weightSpace_of_mem_weightSpace x.property m.property⟩ - map_add' := fun m n => by simp only [LieSubmodule.coe_add, lie_add]; rfl + ⟨⁅(x : L), (m : M)⁆, + hχ ▸ lie_mem_genWeightSpace_of_mem_genWeightSpace x.property m.property⟩ + 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 => @@ -95,8 +97,8 @@ def rootSpaceWeightSpaceProductAux {χ₁ χ₂ χ₃ : H → R} (hχ : χ₁ + rfl } map_add' x y := by ext m - simp only [AddSubmonoid.coe_add, Submodule.coe_toAddSubmonoid, add_lie, LinearMap.coe_mk, - AddHom.coe_mk, LinearMap.add_apply, AddSubmonoid.mk_add_mk] + 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] ext m @@ -108,29 +110,29 @@ def rootSpaceWeightSpaceProductAux {χ₁ χ₂ χ₃ : H → R} (hχ : χ₁ + /-- 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χ : χ₁ + χ₂ = χ₃) : - rootSpace H χ₁ ⊗[R] weightSpace M χ₂ →ₗ⁅R,H⁆ weightSpace M χ₃ := - liftLie R H (rootSpace H χ₁) (weightSpace M χ₂) (weightSpace M χ₃) + rootSpace H χ₁ ⊗[R] genWeightSpace M χ₂ →ₗ⁅R,H⁆ genWeightSpace M χ₃ := + liftLie R H (rootSpace H χ₁) (genWeightSpace M χ₂) (genWeightSpace M χ₃) { toLinearMap := rootSpaceWeightSpaceProductAux R L H M hχ map_lie' := fun {x y} => by ext m - simp only [rootSpaceWeightSpaceProductAux, LieSubmodule.coe_bracket, - LieSubalgebra.coe_bracket_of_module, lie_lie, LinearMap.coe_mk, AddHom.coe_mk, - Subtype.coe_mk, LieHom.lie_apply, LieSubmodule.coe_sub] } + simp only [rootSpaceWeightSpaceProductAux] + dsimp + simp only [LieSubalgebra.coe_bracket_of_module, lie_lie] } @[simp] theorem coe_rootSpaceWeightSpaceProduct_tmul (χ₁ χ₂ χ₃ : H → R) (hχ : χ₁ + χ₂ = χ₃) - (x : rootSpace H χ₁) (m : weightSpace M χ₂) : + (x : rootSpace H χ₁) (m : genWeightSpace M χ₂) : (rootSpaceWeightSpaceProduct R L H M χ₁ χ₂ χ₃ hχ (x ⊗ₜ m) : M) = ⁅(x : L), (m : M)⁆ := by simp only [rootSpaceWeightSpaceProduct, rootSpaceWeightSpaceProductAux, coe_liftLie_eq_lift_coe, AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, lift_apply, LinearMap.coe_mk, AddHom.coe_mk, Submodule.coe_mk] -theorem mapsTo_toEnd_weightSpace_add_of_mem_rootSpace (α χ : H → R) +theorem mapsTo_toEnd_genWeightSpace_add_of_mem_rootSpace (α χ : H → R) {x : L} (hx : x ∈ rootSpace H α) : - MapsTo (toEnd R L M x) (weightSpace M χ) (weightSpace M (α + χ)) := by + MapsTo (toEnd R L M x) (genWeightSpace M χ) (genWeightSpace M (α + χ)) := by intro m hm let x' : rootSpace H α := ⟨x, hx⟩ - let m' : weightSpace M χ := ⟨m, hm⟩ + let m' : genWeightSpace M χ := ⟨m, hm⟩ exact (rootSpaceWeightSpaceProduct R L H M α χ (α + χ) rfl (x' ⊗ₜ m')).property /-- Given a nilpotent Lie subalgebra `H ⊆ L` together with `χ₁ χ₂ : H → R`, there is a natural @@ -163,12 +165,12 @@ theorem coe_zeroRootSubalgebra : (zeroRootSubalgebra R L H : Submodule R L) = ro theorem mem_zeroRootSubalgebra (x : L) : x ∈ zeroRootSubalgebra R L H ↔ ∀ y : H, ∃ k : ℕ, (toEnd R H L y ^ k) x = 0 := by change x ∈ rootSpace H 0 ↔ _ - simp only [mem_weightSpace, Pi.zero_apply, zero_smul, sub_zero] + simp only [mem_genWeightSpace, Pi.zero_apply, zero_smul, sub_zero] theorem toLieSubmodule_le_rootSpace_zero : H.toLieSubmodule ≤ rootSpace H 0 := by intro x hx simp only [LieSubalgebra.mem_toLieSubmodule] at hx - simp only [mem_weightSpace, Pi.zero_apply, sub_zero, zero_smul] + simp only [mem_genWeightSpace, Pi.zero_apply, sub_zero, zero_smul] intro y obtain ⟨k, hk⟩ := (inferInstance : IsNilpotent R H) use k @@ -189,7 +191,7 @@ theorem toLieSubmodule_le_rootSpace_zero : H.toLieSubmodule ≤ rootSpace H 0 := exact h /-- This enables the instance `Zero (Weight R H L)`. -/ -instance [Nontrivial H] : Nontrivial (weightSpace L (0 : H → R)) := by +instance [Nontrivial H] : Nontrivial (genWeightSpace L (0 : H → R)) := by obtain ⟨⟨x, hx⟩, ⟨y, hy⟩, e⟩ := exists_pair_ne H exact ⟨⟨x, toLieSubmodule_le_rootSpace_zero R L H hx⟩, ⟨y, toLieSubmodule_le_rootSpace_zero R L H hy⟩, by simpa using e⟩ @@ -268,7 +270,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] @@ -285,13 +289,14 @@ 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⟩⟩ - convert (rootSpaceProduct R L H α (-α) 0 (add_neg_cancel α) (⟨y, hy⟩ ⊗ₜ[R] ⟨z, hz⟩)).property + convert + (rootSpaceProduct R L H α (-α) 0 (add_neg_cancel α) (⟨y, hy⟩ ⊗ₜ[R] ⟨z, hz⟩)).property using 0 simp [hyz] end LieAlgebra diff --git a/Mathlib/Algebra/Lie/Weights/Chain.lean b/Mathlib/Algebra/Lie/Weights/Chain.lean index beb8dcaeaa05e..428b6ff73884c 100644 --- a/Mathlib/Algebra/Lie/Weights/Chain.lean +++ b/Mathlib/Algebra/Lie/Weights/Chain.lean @@ -25,12 +25,12 @@ We provide basic definitions and results to support `α`-chain techniques in thi ## Main definitions / results - * `LieModule.exists₂_weightSpace_smul_add_eq_bot`: given weights `χ₁`, `χ₂` if `χ₁ ≠ 0`, we can + * `LieModule.exists₂_genWeightSpace_smul_add_eq_bot`: given weights `χ₁`, `χ₂` if `χ₁ ≠ 0`, we can find `p < 0` and `q > 0` such that the weight spaces `p • χ₁ + χ₂` and `q • χ₁ + χ₂` are both trivial. - * `LieModule.weightSpaceChain`: given weights `χ₁`, `χ₂` together with integers `p` and `q`, this - is the sum of the weight spaces `k • χ₁ + χ₂` for `p < k < q`. - * `LieModule.trace_toEnd_weightSpaceChain_eq_zero`: given a root `α` relative to a Cartan + * `LieModule.genWeightSpaceChain`: given weights `χ₁`, `χ₂` together with integers `p` and `q`, + this is the sum of the weight spaces `k • χ₁ + χ₂` for `p < k < q`. + * `LieModule.trace_toEnd_genWeightSpaceChain_eq_zero`: given a root `α` relative to a Cartan subalgebra `H`, there is a natural ideal `corootSpace α` in `H`. This lemma states that this ideal acts by trace-zero endomorphisms on the sum of root spaces of any `α`-chain, provided the weight spaces at the endpoints are both trivial. @@ -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] @@ -57,28 +57,28 @@ section variable [NoZeroSMulDivisors ℤ R] [NoZeroSMulDivisors R M] [IsNoetherian R M] (hχ₁ : χ₁ ≠ 0) include hχ₁ -lemma eventually_weightSpace_smul_add_eq_bot : - ∀ᶠ (k : ℕ) in Filter.atTop, weightSpace M (k • χ₁ + χ₂) = ⊥ := by +lemma eventually_genWeightSpace_smul_add_eq_bot : + ∀ᶠ (k : ℕ) in Filter.atTop, genWeightSpace M (k • χ₁ + χ₂) = ⊥ := by let f : ℕ → L → R := fun k ↦ k • χ₁ + χ₂ suffices Injective f by rw [← Nat.cofinite_eq_atTop, Filter.eventually_cofinite, ← finite_image_iff this.injOn] - apply (finite_weightSpace_ne_bot R L M).subset + apply (finite_genWeightSpace_ne_bot R L M).subset simp [f] intro k l hkl replace hkl : (k : ℤ) • χ₁ = (l : ℤ) • χ₁ := by simpa only [f, add_left_inj, natCast_zsmul] using hkl exact Nat.cast_inj.mp <| smul_left_injective ℤ hχ₁ hkl -lemma exists_weightSpace_smul_add_eq_bot : - ∃ k > 0, weightSpace M (k • χ₁ + χ₂) = ⊥ := - (Nat.eventually_pos.and <| eventually_weightSpace_smul_add_eq_bot M χ₁ χ₂ hχ₁).exists +lemma exists_genWeightSpace_smul_add_eq_bot : + ∃ k > 0, genWeightSpace M (k • χ₁ + χ₂) = ⊥ := + (Nat.eventually_pos.and <| eventually_genWeightSpace_smul_add_eq_bot M χ₁ χ₂ hχ₁).exists -lemma exists₂_weightSpace_smul_add_eq_bot : +lemma exists₂_genWeightSpace_smul_add_eq_bot : ∃ᵉ (p < (0 : ℤ)) (q > (0 : ℤ)), - weightSpace M (p • χ₁ + χ₂) = ⊥ ∧ - weightSpace M (q • χ₁ + χ₂) = ⊥ := by - obtain ⟨q, hq₀, hq⟩ := exists_weightSpace_smul_add_eq_bot M χ₁ χ₂ hχ₁ - obtain ⟨p, hp₀, hp⟩ := exists_weightSpace_smul_add_eq_bot M (-χ₁) χ₂ (neg_ne_zero.mpr hχ₁) + genWeightSpace M (p • χ₁ + χ₂) = ⊥ ∧ + genWeightSpace M (q • χ₁ + χ₂) = ⊥ := by + obtain ⟨q, hq₀, hq⟩ := exists_genWeightSpace_smul_add_eq_bot M χ₁ χ₂ hχ₁ + obtain ⟨p, hp₀, hp⟩ := exists_genWeightSpace_smul_add_eq_bot M (-χ₁) χ₂ (neg_ne_zero.mpr hχ₁) refine ⟨-(p : ℤ), by simpa, q, by simpa, ?_, ?_⟩ · rw [neg_smul, ← smul_neg, natCast_zsmul] exact hp @@ -90,28 +90,28 @@ end /-- Given two (potential) weights `χ₁` and `χ₂` together with integers `p` and `q`, it is often useful to study the sum of weight spaces associated to the family of weights `k • χ₁ + χ₂` for `p < k < q`. -/ -def weightSpaceChain : LieSubmodule R L M := - ⨆ k ∈ Ioo p q, weightSpace M (k • χ₁ + χ₂) +def genWeightSpaceChain : LieSubmodule R L M := + ⨆ k ∈ Ioo p q, genWeightSpace M (k • χ₁ + χ₂) -lemma weightSpaceChain_def : - weightSpaceChain M χ₁ χ₂ p q = ⨆ k ∈ Ioo p q, weightSpace M (k • χ₁ + χ₂) := +lemma genWeightSpaceChain_def : + genWeightSpaceChain M χ₁ χ₂ p q = ⨆ k ∈ Ioo p q, genWeightSpace M (k • χ₁ + χ₂) := rfl -lemma weightSpaceChain_def' : - weightSpaceChain M χ₁ χ₂ p q = ⨆ k ∈ Finset.Ioo p q, weightSpace M (k • χ₁ + χ₂) := by +lemma genWeightSpaceChain_def' : + genWeightSpaceChain M χ₁ χ₂ p q = ⨆ k ∈ Finset.Ioo p q, genWeightSpace M (k • χ₁ + χ₂) := by have : ∀ (k : ℤ), k ∈ Ioo p q ↔ k ∈ Finset.Ioo p q := by simp - simp_rw [weightSpaceChain_def, this] + simp_rw [genWeightSpaceChain_def, this] @[simp] -lemma weightSpaceChain_neg : - weightSpaceChain M (-χ₁) χ₂ (-q) (-p) = weightSpaceChain M χ₁ χ₂ p q := by +lemma genWeightSpaceChain_neg : + genWeightSpaceChain M (-χ₁) χ₂ (-q) (-p) = genWeightSpaceChain M χ₁ χ₂ p q := by let e : ℤ ≃ ℤ := neg_involutive.toPerm - simp_rw [weightSpaceChain, ← e.biSup_comp (Ioo p q)] + simp_rw [genWeightSpaceChain, ← e.biSup_comp (Ioo p q)] simp [e, -mem_Ioo, neg_mem_Ioo_iff] -lemma weightSpace_le_weightSpaceChain {k : ℤ} (hk : k ∈ Ioo p q) : - weightSpace M (k • χ₁ + χ₂) ≤ weightSpaceChain M χ₁ χ₂ p q := - le_biSup (fun i ↦ weightSpace M (i • χ₁ + χ₂)) hk +lemma genWeightSpace_le_genWeightSpaceChain {k : ℤ} (hk : k ∈ Ioo p q) : + genWeightSpace M (k • χ₁ + χ₂) ≤ genWeightSpaceChain M χ₁ χ₂ p q := + le_biSup (fun i ↦ genWeightSpace M (i • χ₁ + χ₂)) hk end IsNilpotent @@ -121,59 +121,63 @@ open LieAlgebra variable {H : LieSubalgebra R L} (α χ : H → R) (p q : ℤ) -lemma lie_mem_weightSpaceChain_of_weightSpace_eq_bot_right [LieAlgebra.IsNilpotent R H] - (hq : weightSpace M (q • α + χ) = ⊥) +lemma lie_mem_genWeightSpaceChain_of_genWeightSpace_eq_bot_right [LieAlgebra.IsNilpotent R H] + (hq : genWeightSpace M (q • α + χ) = ⊥) {x : L} (hx : x ∈ rootSpace H α) - {y : M} (hy : y ∈ weightSpaceChain M α χ p q) : - ⁅x, y⁆ ∈ weightSpaceChain M α χ p q := by - rw [weightSpaceChain, iSup_subtype'] at hy - induction' hy using LieSubmodule.iSup_induction' with k z hz z₁ z₂ _ _ hz₁ hz₂ - · obtain ⟨k, hk⟩ := k - suffices weightSpace M ((k + 1) • α + χ) ≤ weightSpaceChain M α χ p q by + {y : M} (hy : y ∈ genWeightSpaceChain M α χ p q) : + ⁅x, y⁆ ∈ genWeightSpaceChain M α χ p q := by + rw [genWeightSpaceChain, iSup_subtype'] at hy + induction hy using LieSubmodule.iSup_induction' with + | hN k z hz => + obtain ⟨k, hk⟩ := k + suffices genWeightSpace M ((k + 1) • α + χ) ≤ genWeightSpaceChain M α χ p q by apply this simpa using (rootSpaceWeightSpaceProduct R L H M α (k • α + χ) ((k + 1) • α + χ) (by rw [add_smul]; abel) (⟨x, hx⟩ ⊗ₜ ⟨z, hz⟩)).property - rw [weightSpaceChain] + rw [genWeightSpaceChain] rcases eq_or_ne (k + 1) q with rfl | hk'; · simp only [hq, bot_le] replace hk' : k + 1 ∈ Ioo p q := ⟨by linarith [hk.1], lt_of_le_of_ne hk.2 hk'⟩ - exact le_biSup (fun k ↦ weightSpace M (k • α + χ)) hk' - · simp - · rw [lie_add] - exact add_mem hz₁ hz₂ + exact le_biSup (fun k ↦ genWeightSpace M (k • α + χ)) hk' + | h0 => simp + | hadd _ _ _ _ hz₁ hz₂ => rw [lie_add]; exact add_mem hz₁ hz₂ -lemma lie_mem_weightSpaceChain_of_weightSpace_eq_bot_left [LieAlgebra.IsNilpotent R H] - (hp : weightSpace M (p • α + χ) = ⊥) +lemma lie_mem_genWeightSpaceChain_of_genWeightSpace_eq_bot_left [LieAlgebra.IsNilpotent R H] + (hp : genWeightSpace M (p • α + χ) = ⊥) {x : L} (hx : x ∈ rootSpace H (-α)) - {y : M} (hy : y ∈ weightSpaceChain M α χ p q) : - ⁅x, y⁆ ∈ weightSpaceChain M α χ p q := by - replace hp : weightSpace M ((-p) • (-α) + χ) = ⊥ := by rwa [smul_neg, neg_smul, neg_neg] - rw [← weightSpaceChain_neg] at hy ⊢ - exact lie_mem_weightSpaceChain_of_weightSpace_eq_bot_right M (-α) χ (-q) (-p) hp hx hy + {y : M} (hy : y ∈ genWeightSpaceChain M α χ p q) : + ⁅x, y⁆ ∈ genWeightSpaceChain M α χ p q := by + replace hp : genWeightSpace M ((-p) • (-α) + χ) = ⊥ := by rwa [smul_neg, neg_smul, neg_neg] + rw [← genWeightSpaceChain_neg] at hy ⊢ + exact lie_mem_genWeightSpaceChain_of_genWeightSpace_eq_bot_right M (-α) χ (-q) (-p) hp hx hy section IsCartanSubalgebra variable [H.IsCartanSubalgebra] [IsNoetherian R L] -lemma trace_toEnd_weightSpaceChain_eq_zero - (hp : weightSpace M (p • α + χ) = ⊥) - (hq : weightSpace M (q • α + χ) = ⊥) +lemma trace_toEnd_genWeightSpaceChain_eq_zero + (hp : genWeightSpace M (p • α + χ) = ⊥) + (hq : genWeightSpace M (q • α + χ) = ⊥) {x : H} (hx : x ∈ corootSpace α) : - LinearMap.trace R _ (toEnd R H (weightSpaceChain M α χ p q) x) = 0 := by + 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' · next u hu => obtain ⟨y, hy, z, hz, hyz⟩ := hu - let f : Module.End R (weightSpaceChain M α χ p q) := + let f : Module.End R (genWeightSpaceChain M α χ p q) := { toFun := fun ⟨m, hm⟩ ↦ ⟨⁅(y : L), m⁆, - lie_mem_weightSpaceChain_of_weightSpace_eq_bot_right M α χ p q hq hy hm⟩ + lie_mem_genWeightSpaceChain_of_genWeightSpace_eq_bot_right M α χ p q hq hy hm⟩ map_add' := fun _ _ ↦ by simp map_smul' := fun t m ↦ by simp } - let g : Module.End R (weightSpaceChain M α χ p q) := + let g : Module.End R (genWeightSpaceChain M α χ p q) := { toFun := fun ⟨m, hm⟩ ↦ ⟨⁅(z : L), m⁆, - lie_mem_weightSpaceChain_of_weightSpace_eq_bot_left M α χ p q hp hz hm⟩ + lie_mem_genWeightSpaceChain_of_genWeightSpace_eq_bot_left M α χ p q hp hz hm⟩ map_add' := fun _ _ ↦ by simp map_smul' := fun t m ↦ by simp } - have hfg : toEnd R H _ u = ⁅f, g⁆ := by ext; simp [f, g, ← hyz] + have hfg : toEnd R H _ u = ⁅f, g⁆ := by + ext + rw [toEnd_apply_apply, LieSubmodule.coe_bracket, LieSubalgebra.coe_bracket_of_module, ← hyz] + simp only [lie_lie, LieHom.lie_apply, LinearMap.coe_mk, AddHom.coe_mk, Module.End.lie_apply, + AddSubgroupClass.coe_sub, f, g] simp [hfg] · simp · simp_all @@ -188,30 +192,36 @@ semisimple Lie algebra form a root system. It shows that the restriction of `α` the restriction of every root to `I` vanishes (which cannot happen in a semisimple Lie algebra). -/ lemma exists_forall_mem_corootSpace_smul_add_eq_zero [IsDomain R] [IsPrincipalIdealRing R] [CharZero R] [NoZeroSMulDivisors R M] [IsNoetherian R M] - (hα : α ≠ 0) (hχ : weightSpace M χ ≠ ⊥) : + (hα : α ≠ 0) (hχ : genWeightSpace M χ ≠ ⊥) : ∃ a b : ℤ, 0 < b ∧ ∀ x ∈ corootSpace α, (a • α + b • χ) x = 0 := by - obtain ⟨p, hp₀, q, hq₀, hp, hq⟩ := exists₂_weightSpace_smul_add_eq_bot M α χ hα - let a := ∑ i ∈ Finset.Ioo p q, finrank R (weightSpace M (i • α + χ)) • i - let b := ∑ i ∈ Finset.Ioo p q, finrank R (weightSpace M (i • α + χ)) + obtain ⟨p, hp₀, q, hq₀, hp, hq⟩ := exists₂_genWeightSpace_smul_add_eq_bot M α χ hα + let a := ∑ i ∈ Finset.Ioo p q, finrank R (genWeightSpace M (i • α + χ)) • i + let b := ∑ i ∈ Finset.Ioo p q, finrank R (genWeightSpace M (i • α + χ)) have hb : 0 < b := by - replace hχ : Nontrivial (weightSpace M χ) := by rwa [LieSubmodule.nontrivial_iff_ne_bot] + replace hχ : Nontrivial (genWeightSpace M χ) := by rwa [LieSubmodule.nontrivial_iff_ne_bot] refine Finset.sum_pos' (fun _ _ ↦ zero_le _) ⟨0, Finset.mem_Ioo.mpr ⟨hp₀, hq₀⟩, ?_⟩ rw [zero_smul, zero_add] exact finrank_pos refine ⟨a, b, Int.ofNat_pos.mpr hb, fun x hx ↦ ?_⟩ - let N : ℤ → Submodule R M := fun k ↦ weightSpace M (k • α + χ) + let N : ℤ → Submodule R M := fun k ↦ genWeightSpace M (k • α + χ) have h₁ : CompleteLattice.Independent fun (i : Finset.Ioo p q) ↦ N i := by rw [← LieSubmodule.independent_iff_coe_toSubmodule] - refine (independent_weightSpace R H M).comp fun i j hij ↦ ?_ + refine (independent_genWeightSpace R H M).comp fun i j hij ↦ ?_ exact SetCoe.ext <| smul_left_injective ℤ hα <| by rwa [add_left_inj] at hij have h₂ : ∀ i, MapsTo (toEnd R H M x) ↑(N i) ↑(N i) := fun _ _ ↦ LieSubmodule.lie_mem _ - have h₃ : weightSpaceChain M α χ p q = ⨆ i ∈ Finset.Ioo p q, N i := by - simp_rw [weightSpaceChain_def', LieSubmodule.iSup_coe_toSubmodule] - rw [← trace_toEnd_weightSpaceChain_eq_zero M α χ p q hp hq hx, - ← LieSubmodule.toEnd_restrict_eq_toEnd, - LinearMap.trace_eq_sum_trace_restrict_of_eq_biSup _ h₁ h₂ (weightSpaceChain M α χ p q) h₃] - simp_rw [LieSubmodule.toEnd_restrict_eq_toEnd, - trace_toEnd_weightSpace, Pi.add_apply, Pi.smul_apply, smul_add, ← smul_assoc, + 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] + -- 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] + 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 @@ -230,8 +240,8 @@ noncomputable def chainTopCoeff : ℕ := letI := Classical.propDecidable if hα : α = 0 then 0 else - Nat.pred <| Nat.find (show ∃ n, weightSpace M (n • α + β : L → R) = ⊥ from - (eventually_weightSpace_smul_add_eq_bot M α β hα).exists) + Nat.pred <| Nat.find (show ∃ n, genWeightSpace M (n • α + β : L → R) = ⊥ from + (eventually_genWeightSpace_smul_add_eq_bot M α β hα).exists) /-- This is the largest `n : ℕ` such that `-i • α + β` is a weight for all `0 ≤ i ≤ n`. -/ noncomputable @@ -251,66 +261,66 @@ include hα lemma chainTopCoeff_add_one : letI := Classical.propDecidable chainTopCoeff α β + 1 = - Nat.find (eventually_weightSpace_smul_add_eq_bot M α β hα).exists := by + Nat.find (eventually_genWeightSpace_smul_add_eq_bot M α β hα).exists := by classical rw [chainTopCoeff, dif_neg hα] apply Nat.succ_pred_eq_of_pos rw [zero_lt_iff] intro e - have : weightSpace M (0 • α + β : L → R) = ⊥ := by + have : genWeightSpace M (0 • α + β : L → R) = ⊥ := by rw [← e] - exact Nat.find_spec (eventually_weightSpace_smul_add_eq_bot M α β hα).exists - exact β.weightSpace_ne_bot _ (by simpa only [zero_smul, zero_add] using this) + exact Nat.find_spec (eventually_genWeightSpace_smul_add_eq_bot M α β hα).exists + exact β.genWeightSpace_ne_bot _ (by simpa only [zero_smul, zero_add] using this) -lemma weightSpace_chainTopCoeff_add_one_nsmul_add : - weightSpace M ((chainTopCoeff α β + 1) • α + β : L → R) = ⊥ := by +lemma genWeightSpace_chainTopCoeff_add_one_nsmul_add : + genWeightSpace M ((chainTopCoeff α β + 1) • α + β : L → R) = ⊥ := by classical rw [chainTopCoeff_add_one _ _ hα] - exact Nat.find_spec (eventually_weightSpace_smul_add_eq_bot M α β hα).exists + exact Nat.find_spec (eventually_genWeightSpace_smul_add_eq_bot M α β hα).exists -lemma weightSpace_chainTopCoeff_add_one_zsmul_add : - weightSpace M ((chainTopCoeff α β + 1 : ℤ) • α + β : L → R) = ⊥ := by - rw [← weightSpace_chainTopCoeff_add_one_nsmul_add α β hα, ← Nat.cast_smul_eq_nsmul ℤ, +lemma genWeightSpace_chainTopCoeff_add_one_zsmul_add : + genWeightSpace M ((chainTopCoeff α β + 1 : ℤ) • α + β : L → R) = ⊥ := by + rw [← genWeightSpace_chainTopCoeff_add_one_nsmul_add α β hα, ← Nat.cast_smul_eq_nsmul ℤ, Nat.cast_add, Nat.cast_one] -lemma weightSpace_chainBotCoeff_sub_one_zsmul_sub : - weightSpace M ((-chainBotCoeff α β - 1 : ℤ) • α + β : L → R) = ⊥ := by +lemma genWeightSpace_chainBotCoeff_sub_one_zsmul_sub : + genWeightSpace M ((-chainBotCoeff α β - 1 : ℤ) • α + β : L → R) = ⊥ := by rw [sub_eq_add_neg, ← neg_add, neg_smul, ← smul_neg, chainBotCoeff, - weightSpace_chainTopCoeff_add_one_zsmul_add _ _ (by simpa using hα)] + genWeightSpace_chainTopCoeff_add_one_zsmul_add _ _ (by simpa using hα)] end -lemma weightSpace_nsmul_add_ne_bot_of_le {n} (hn : n ≤ chainTopCoeff α β) : - weightSpace M (n • α + β : L → R) ≠ ⊥ := by +lemma genWeightSpace_nsmul_add_ne_bot_of_le {n} (hn : n ≤ chainTopCoeff α β) : + genWeightSpace M (n • α + β : L → R) ≠ ⊥ := by by_cases hα : α = 0 - · rw [hα, smul_zero, zero_add]; exact β.weightSpace_ne_bot + · rw [hα, smul_zero, zero_add]; exact β.genWeightSpace_ne_bot classical rw [← Nat.lt_succ, Nat.succ_eq_add_one, chainTopCoeff_add_one _ _ hα] at hn - exact Nat.find_min (eventually_weightSpace_smul_add_eq_bot M α β hα).exists hn + exact Nat.find_min (eventually_genWeightSpace_smul_add_eq_bot M α β hα).exists hn -lemma weightSpace_zsmul_add_ne_bot {n : ℤ} +lemma genWeightSpace_zsmul_add_ne_bot {n : ℤ} (hn : -chainBotCoeff α β ≤ n) (hn' : n ≤ chainTopCoeff α β) : - weightSpace M (n • α + β : L → R) ≠ ⊥ := by + genWeightSpace M (n • α + β : L → R) ≠ ⊥ := by rcases n with (n | n) · simp only [Int.ofNat_eq_coe, Nat.cast_le, Nat.cast_smul_eq_nsmul] at hn' ⊢ - exact weightSpace_nsmul_add_ne_bot_of_le α β hn' + exact genWeightSpace_nsmul_add_ne_bot_of_le α β hn' · simp only [Int.negSucc_eq, ← Nat.cast_succ, neg_le_neg_iff, Nat.cast_le] at hn ⊢ rw [neg_smul, ← smul_neg, Nat.cast_smul_eq_nsmul] - exact weightSpace_nsmul_add_ne_bot_of_le (-α) β hn + exact genWeightSpace_nsmul_add_ne_bot_of_le (-α) β hn -lemma weightSpace_neg_zsmul_add_ne_bot {n : ℕ} (hn : n ≤ chainBotCoeff α β) : - weightSpace M ((-n : ℤ) • α + β : L → R) ≠ ⊥ := by - apply weightSpace_zsmul_add_ne_bot α β <;> omega +lemma genWeightSpace_neg_zsmul_add_ne_bot {n : ℕ} (hn : n ≤ chainBotCoeff α β) : + genWeightSpace M ((-n : ℤ) • α + β : L → R) ≠ ⊥ := by + apply genWeightSpace_zsmul_add_ne_bot α β <;> omega /-- The last weight in an `α`-chain through `β`. -/ noncomputable def chainTop (α : L → R) (β : Weight R L M) : Weight R L M := - ⟨chainTopCoeff α β • α + β, weightSpace_nsmul_add_ne_bot_of_le α β le_rfl⟩ + ⟨chainTopCoeff α β • α + β, genWeightSpace_nsmul_add_ne_bot_of_le α β le_rfl⟩ /-- The first weight in an `α`-chain through `β`. -/ noncomputable def chainBot (α : L → R) (β : Weight R L M) : Weight R L M := - ⟨(- chainBotCoeff α β : ℤ) • α + β, weightSpace_neg_zsmul_add_ne_bot α β le_rfl⟩ + ⟨(- chainBotCoeff α β : ℤ) • α + β, genWeightSpace_neg_zsmul_add_ne_bot α β le_rfl⟩ lemma coe_chainTop' : (chainTop α β : L → R) = chainTopCoeff α β • α + β := rfl @@ -328,19 +338,20 @@ section variable (hα : α ≠ 0) include hα -lemma weightSpace_add_chainTop : - weightSpace M (α + chainTop α β : L → R) = ⊥ := by - rw [coe_chainTop', ← add_assoc, ← succ_nsmul', weightSpace_chainTopCoeff_add_one_nsmul_add _ _ hα] +lemma genWeightSpace_add_chainTop : + genWeightSpace M (α + chainTop α β : L → R) = ⊥ := by + rw [coe_chainTop', ← add_assoc, ← succ_nsmul', + genWeightSpace_chainTopCoeff_add_one_nsmul_add _ _ hα] -lemma weightSpace_neg_add_chainBot : - weightSpace M (-α + chainBot α β : L → R) = ⊥ := by - rw [← chainTop_neg, weightSpace_add_chainTop _ _ (by simpa using hα)] +lemma genWeightSpace_neg_add_chainBot : + genWeightSpace M (-α + chainBot α β : L → R) = ⊥ := by + rw [← chainTop_neg, genWeightSpace_add_chainTop _ _ (by simpa using hα)] -lemma chainTop_isNonZero' (hα' : weightSpace M α ≠ ⊥) : +lemma chainTop_isNonZero' (hα' : genWeightSpace M α ≠ ⊥) : (chainTop α β).IsNonZero := by by_contra e apply hα' - rw [← add_zero (α : L → R), ← e, weightSpace_add_chainTop _ _ hα] + rw [← add_zero (α : L → R), ← e, genWeightSpace_add_chainTop _ _ hα] end diff --git a/Mathlib/Algebra/Lie/Weights/Killing.lean b/Mathlib/Algebra/Lie/Weights/Killing.lean index cee61eb9c3bc1..80e8ca2ed6bf3 100644 --- a/Mathlib/Algebra/Lie/Weights/Killing.lean +++ b/Mathlib/Algebra/Lie/Weights/Killing.lean @@ -52,7 +52,7 @@ lemma ker_restrict_eq_bot_of_isCartanSubalgebra [IsNoetherian R L] [IsArtinian R L] (H : LieSubalgebra R L) [H.IsCartanSubalgebra] : LinearMap.ker ((killingForm R L).restrict H) = ⊥ := by have h : Codisjoint (rootSpace H 0) (LieModule.posFittingComp R H L) := - (LieModule.isCompl_weightSpace_zero_posFittingComp R H L).codisjoint + (LieModule.isCompl_genWeightSpace_zero_posFittingComp R H L).codisjoint replace h : Codisjoint (H : Submodule R L) (LieModule.posFittingComp R H L : Submodule R L) := by rwa [codisjoint_iff, ← LieSubmodule.coe_toSubmodule_eq_iff, LieSubmodule.sup_coe_toSubmodule, LieSubmodule.top_coeSubmodule, rootSpace_zero_eq R L H, LieSubalgebra.coe_toLieSubmodule, @@ -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] @@ -109,12 +109,12 @@ lemma killingForm_apply_eq_zero_of_mem_rootSpace_of_add_ne_zero {α β : H → K have hσ : ∀ γ, σ γ ≠ γ := fun γ ↦ by simpa only [σ, ← add_assoc] using add_left_ne_self.mpr hαβ let f : Module.End K L := (ad K L x) ∘ₗ (ad K L y) have hf : ∀ γ, MapsTo f (rootSpace H γ) (rootSpace H (σ γ)) := fun γ ↦ - (mapsTo_toEnd_weightSpace_add_of_mem_rootSpace K L H L α (β + γ) hx).comp <| - mapsTo_toEnd_weightSpace_add_of_mem_rootSpace K L H L β γ hy + (mapsTo_toEnd_genWeightSpace_add_of_mem_rootSpace K L H L α (β + γ) hx).comp <| + mapsTo_toEnd_genWeightSpace_add_of_mem_rootSpace K L H L β γ hy classical have hds := DirectSum.isInternal_submodule_of_independent_of_iSup_eq_top - (LieSubmodule.independent_iff_coe_toSubmodule.mp <| independent_weightSpace K H L) - (LieSubmodule.iSup_eq_top_iff_coe_toSubmodule.mp <| iSup_weightSpace_eq_top K H L) + (LieSubmodule.independent_iff_coe_toSubmodule.mp <| independent_genWeightSpace K H L) + (LieSubmodule.iSup_eq_top_iff_coe_toSubmodule.mp <| iSup_genWeightSpace_eq_top K H L) exact LinearMap.trace_eq_zero_of_mapsTo_ne hds σ hσ hf /-- Elements of the `α` root space which are Killing-orthogonal to the `-α` root space are @@ -125,7 +125,7 @@ lemma mem_ker_killingForm_of_mem_rootSpace_of_forall_rootSpace_neg x ∈ LinearMap.ker (killingForm K L) := by rw [LinearMap.mem_ker] ext y - have hy : y ∈ ⨆ β, rootSpace H β := by simp [iSup_weightSpace_eq_top K H L] + have hy : y ∈ ⨆ β, rootSpace H β := by simp [iSup_genWeightSpace_eq_top K H L] induction hy using LieSubmodule.iSup_induction' with | hN β y hy => by_cases hαβ : α + β = 0 @@ -146,7 +146,9 @@ Over a perfect field a much stronger result is true, see `LieAlgebra.IsKilling.isSemisimple_ad_of_mem_isCartanSubalgebra`. -/ lemma eq_zero_of_isNilpotent_ad_of_mem_isCartanSubalgebra {x : L} (hx : x ∈ H) (hx' : _root_.IsNilpotent (ad K L x)) : x = 0 := by - suffices ⟨x, hx⟩ ∈ LinearMap.ker (traceForm K H L) by simpa using this + suffices ⟨x, hx⟩ ∈ LinearMap.ker (traceForm K H L) by + simp at this + exact (AddSubmonoid.mk_eq_zero H.toAddSubmonoid).mp this simp only [LinearMap.mem_ker] ext y have comm : Commute (toEnd K H L ⟨x, hx⟩) (toEnd K H L y) := by @@ -197,7 +199,7 @@ lemma lie_eq_killingForm_smul_of_mem_rootSpace_of_mem_rootSpace_neg_aux apply mem_ker_killingForm_of_mem_rootSpace_of_forall_rootSpace_neg (α := (0 : H → K)) · simp only [rootSpace_zero_eq, LieSubalgebra.mem_toLieSubmodule] refine sub_mem ?_ (H.smul_mem _ α'.property) - simpa using mapsTo_toEnd_weightSpace_add_of_mem_rootSpace K L H L α (-α) heα hfα + simpa using mapsTo_toEnd_genWeightSpace_add_of_mem_rootSpace K L H L α (-α) heα hfα · intro z hz replace hz : z ∈ H := by simpa using hz have he : ⁅z, e⁆ = α ⟨z, hz⟩ • e := aux ⟨z, hz⟩ @@ -211,7 +213,7 @@ assuming `K` has characteristic zero). -/ lemma cartanEquivDual_symm_apply_mem_corootSpace (α : Weight K H L) : (cartanEquivDual H).symm α ∈ corootSpace α := by obtain ⟨e : L, he₀ : e ≠ 0, he : ∀ x, ⁅x, e⁆ = α x • e⟩ := exists_forall_lie_eq_smul K H L α - have heα : e ∈ rootSpace H α := (mem_weightSpace L α e).mpr fun x ↦ ⟨1, by simp [← he x]⟩ + have heα : e ∈ rootSpace H α := (mem_genWeightSpace L α e).mpr fun x ↦ ⟨1, by simp [← he x]⟩ obtain ⟨f, hfα, hf⟩ : ∃ f ∈ rootSpace H (-α), killingForm K L e f ≠ 0 := by contrapose! he₀ simpa using mem_ker_killingForm_of_mem_rootSpace_of_forall_rootSpace_neg K L H heα he₀ @@ -264,7 +266,7 @@ lemma isSemisimple_ad_of_mem_isCartanSubalgebra {x : L} (hx : x ∈ H) : /- Note that the semisimple part `S` is just a scalar action on each root space. -/ have aux {α : H → K} {y : L} (hy : y ∈ rootSpace H α) : S y = α x' • y := by replace hy : y ∈ (ad K L x).maxGenEigenspace (α x') := - (weightSpace_le_weightSpaceOf L x' α) hy + (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] @@ -272,12 +274,12 @@ lemma isSemisimple_ad_of_mem_isCartanSubalgebra {x : L} (hx : x ∈ H) : 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 have hyz : ⁅y, z⁆ ∈ rootSpace H (α + β) := - mapsTo_toEnd_weightSpace_add_of_mem_rootSpace K L H L α β hy hz + mapsTo_toEnd_genWeightSpace_add_of_mem_rootSpace K L H L α β hy hz rw [aux hy, aux hz, aux hyz, smul_lie, lie_smul, ← add_smul, ← Pi.add_apply] /- Thus `S` is a derivation since root spaces span. -/ replace h_der (y z : L) : S ⁅y, z⁆ = ⁅S y, z⁆ + ⁅y, S z⁆ := by - have hy : y ∈ ⨆ α : H → K, rootSpace H α := by simp [iSup_weightSpace_eq_top] - have hz : z ∈ ⨆ α : H → K, rootSpace H α := by simp [iSup_weightSpace_eq_top] + have hy : y ∈ ⨆ α : H → K, rootSpace H α := by simp [iSup_genWeightSpace_eq_top] + have hz : z ∈ ⨆ α : H → K, rootSpace H α := by simp [iSup_genWeightSpace_eq_top] induction hy using LieSubmodule.iSup_induction' with | hN α y hy => induction hz using LieSubmodule.iSup_induction' with @@ -313,7 +315,7 @@ lemma isSemisimple_ad_of_mem_isCartanSubalgebra {x : L} (hx : x ∈ H) : lemma lie_eq_smul_of_mem_rootSpace {α : H → K} {x : L} (hx : x ∈ rootSpace H α) (h : H) : ⁅h, x⁆ = α h • x := by replace hx : x ∈ (ad K L h).maxGenEigenspace (α h) := - weightSpace_le_weightSpaceOf L h α hx + genWeightSpace_le_genWeightSpaceOf L h α hx rw [(isSemisimple_ad_of_mem_isCartanSubalgebra h.property).maxGenEigenspace_eq_eigenspace, Module.End.mem_eigenspace_iff] at hx simpa using hx @@ -340,7 +342,8 @@ lemma coe_corootSpace_eq_span_singleton' (α : Weight K H L) : rw [Submodule.mem_span_singleton] at this ⊢ obtain ⟨t, rfl⟩ := this use t - simp [Subtype.ext_iff] + simp only [Subtype.ext_iff] + rw [Submodule.coe_smul_of_tower] · simp only [Submodule.span_singleton_le_iff_mem, LieSubmodule.mem_coeSubmodule] exact cartanEquivDual_symm_apply_mem_corootSpace α @@ -360,7 +363,7 @@ lemma eq_zero_of_apply_eq_zero_of_mem_corootSpace replace hx : x ∈ ⨅ β : Weight K H L, β.ker := by refine (Submodule.mem_iInf _).mpr fun β ↦ ?_ obtain ⟨a, b, hb, hab⟩ := - exists_forall_mem_corootSpace_smul_add_eq_zero L α β hα β.weightSpace_ne_bot + exists_forall_mem_corootSpace_smul_add_eq_zero L α β hα β.genWeightSpace_ne_bot simpa [hαx, hb.ne'] using hab _ hx simpa using hx @@ -484,7 +487,9 @@ lemma exists_isSl2Triple_of_weight_isNonZero {α : Weight K H L} (hα : α.IsNon have hef := lie_eq_killingForm_smul_of_mem_rootSpace_of_mem_rootSpace_neg heα hfα let h : H := ⟨⁅e, f'⁆, hef ▸ Submodule.smul_mem _ _ (Submodule.coe_mem _)⟩ have hh : α h ≠ 0 := by - have : h = killingForm K L e f' • (cartanEquivDual H).symm α := by simp [Subtype.ext_iff, hef] + have : h = killingForm K L e f' • (cartanEquivDual H).symm α := by + simp only [Subtype.ext_iff, hef] + rw [Submodule.coe_smul_of_tower] rw [this, map_smul, smul_eq_mul, ne_eq, mul_eq_zero, not_or] exact ⟨hf, root_apply_cartanEquivDual_symm_ne_zero hα⟩ let f := (2 * (α h)⁻¹) • f' @@ -517,7 +522,8 @@ lemma _root_.IsSl2Triple.h_eq_coroot {α : Weight K H L} (hα : α.IsNonZero) rwa [this, one_smul] at hs set α' := (cartanEquivDual H).symm α with hα' have h_eq : h = killingForm K L e f • α' := by - simp only [hα', Subtype.ext_iff, Submodule.coe_smul_of_tower, ← ht.lie_e_f, hef] + simp only [hα', Subtype.ext_iff, ← ht.lie_e_f, hef] + rw [Submodule.coe_smul_of_tower] use (2 • (α α')⁻¹) * (killingForm K L e f)⁻¹ have hef₀ : killingForm K L e f ≠ 0 := by have := ht.h_ne_zero @@ -528,7 +534,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 α.weightSpace_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α @@ -539,7 +547,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α] @@ -548,6 +556,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 @@ -571,7 +589,7 @@ variable {α : Weight K H L} instance : InvolutiveNeg (Weight K H L) where neg α := ⟨-α, by by_cases hα : α.IsZero - · convert α.weightSpace_ne_bot; rw [hα, neg_zero] + · convert α.genWeightSpace_ne_bot; rw [hα, neg_zero] · intro e obtain ⟨x, hx, x_ne0⟩ := α.exists_ne_zero have := mem_ker_killingForm_of_mem_rootSpace_of_forall_rootSpace_neg K L H hx diff --git a/Mathlib/Algebra/Lie/Weights/Linear.lean b/Mathlib/Algebra/Lie/Weights/Linear.lean index 39d847bba73c0..741b68fdabb92 100644 --- a/Mathlib/Algebra/Lie/Weights/Linear.lean +++ b/Mathlib/Algebra/Lie/Weights/Linear.lean @@ -12,7 +12,7 @@ import Mathlib.LinearAlgebra.FreeModule.PID Given a Lie module `M` over a nilpotent Lie algebra `L` with coefficients in `R`, one frequently studies `M` via its weights. These are functions `χ : L → R` whose corresponding weight space -`LieModule.weightSpace M χ`, is non-trivial. If `L` is Abelian or if `R` has characteristic zero +`LieModule.genWeightSpace M χ`, is non-trivial. If `L` is Abelian or if `R` has characteristic zero (and `M` is finite-dimensional) then such `χ` are necessarily `R`-linear. However in general non-linear weights do exist. For example if we take: * `R`: the field with two elements (or indeed any perfect field of characteristic two), @@ -48,10 +48,10 @@ 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 := - map_add : ∀ χ : L → R, weightSpace M χ ≠ ⊥ → ∀ x y, χ (x + y) = χ x + χ y - map_smul : ∀ χ : L → R, weightSpace M χ ≠ ⊥ → ∀ (t : R) x, χ (t • x) = t • χ x - map_lie : ∀ χ : L → R, weightSpace M χ ≠ ⊥ → ∀ x y : L, χ ⁅x, y⁆ = 0 +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 namespace Weight @@ -61,22 +61,22 @@ variable [LieAlgebra.IsNilpotent R L] [LinearWeights R L M] (χ : Weight R L M) @[simps] def toLinear : L →ₗ[R] R where toFun := χ - map_add' := LinearWeights.map_add χ χ.weightSpace_ne_bot - map_smul' := LinearWeights.map_smul χ χ.weightSpace_ne_bot + map_add' := LinearWeights.map_add χ χ.genWeightSpace_ne_bot + map_smul' := LinearWeights.map_smul χ χ.genWeightSpace_ne_bot instance instCoeLinearMap : CoeOut (Weight R L M) (L →ₗ[R] R) where coe := Weight.toLinear R L M instance instLinearMapClass : LinearMapClass (Weight R L M) R L R where - map_add χ := LinearWeights.map_add χ χ.weightSpace_ne_bot - map_smulₛₗ χ := LinearWeights.map_smul χ χ.weightSpace_ne_bot + map_add χ := LinearWeights.map_add χ χ.genWeightSpace_ne_bot + map_smulₛₗ χ := LinearWeights.map_smul χ χ.genWeightSpace_ne_bot variable {R L M χ} @[simp] lemma apply_lie (x y : L) : χ ⁅x, y⁆ = 0 := - LinearWeights.map_lie χ χ.weightSpace_ne_bot x y + LinearWeights.map_lie χ χ.genWeightSpace_ne_bot x y @[simp] lemma coe_coe : (↑(χ : L →ₗ[R] R) : L → R) = (χ : L → R) := rfl @@ -93,18 +93,20 @@ end Weight /-- For an Abelian Lie algebra, the weights of any Lie module are linear. -/ instance instLinearWeightsOfIsLieAbelian [IsLieAbelian L] [NoZeroSMulDivisors R M] : LinearWeights R L M := - have aux : ∀ (χ : L → R), weightSpace M χ ≠ ⊥ → ∀ (x y : L), χ (x + y) = χ x + χ y := by + have aux : ∀ (χ : L → R), genWeightSpace M χ ≠ ⊥ → ∀ (x y : L), χ (x + y) = χ x + χ y := by have h : ∀ x y, Commute (toEnd R L M x) (toEnd R L M y) := fun x y ↦ by rw [commute_iff_lie_eq, ← LieHom.map_lie, trivial_lie_zero, LieHom.map_zero] intro χ hχ x y - simp_rw [Ne, ← LieSubmodule.coe_toSubmodule_eq_iff, weightSpace, weightSpaceOf, - LieSubmodule.iInf_coe_toSubmodule, LieSubmodule.bot_coeSubmodule] at hχ + simp_rw [Ne, ← LieSubmodule.coe_toSubmodule_eq_iff, genWeightSpace, genWeightSpaceOf, + LieSubmodule.iInf_coe_toSubmodule, LieSubmodule.bot_coeSubmodule, + Module.End.maxGenEigenspace_def] at hχ exact Module.End.map_add_of_iInf_genEigenspace_ne_bot_of_commute (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, weightSpace, weightSpaceOf, - LieSubmodule.iInf_coe_toSubmodule, LieSubmodule.bot_coeSubmodule] at hχ + simp_rw [Ne, ← LieSubmodule.coe_toSubmodule_eq_iff, genWeightSpace, genWeightSpaceOf, + LieSubmodule.iInf_coe_toSubmodule, LieSubmodule.bot_coeSubmodule, + Module.End.maxGenEigenspace_def] at hχ exact Module.End.map_smul_of_iInf_genEigenspace_ne_bot (toEnd R L M).toLinearMap χ hχ t x map_lie := fun χ hχ t x ↦ by @@ -112,28 +114,28 @@ instance instLinearWeightsOfIsLieAbelian [IsLieAbelian L] [NoZeroSMulDivisors R section FiniteDimensional -open FiniteDimensional +open Module variable [IsDomain R] [IsPrincipalIdealRing R] [Module.Free R M] [Module.Finite R M] [LieAlgebra.IsNilpotent R L] -lemma trace_comp_toEnd_weightSpace_eq (χ : L → R) : - LinearMap.trace R _ ∘ₗ (toEnd R L (weightSpace M χ)).toLinearMap = - finrank R (weightSpace M χ) • χ := by +lemma trace_comp_toEnd_genWeightSpace_eq (χ : L → R) : + LinearMap.trace R _ ∘ₗ (toEnd R L (genWeightSpace M χ)).toLinearMap = + finrank R (genWeightSpace M χ) • χ := by ext x - let n := toEnd R L (weightSpace M χ) x - χ x • LinearMap.id - have h₁ : toEnd R L (weightSpace M χ) x = n + χ x • LinearMap.id := eq_add_of_sub_eq rfl + let n := toEnd R L (genWeightSpace M χ) x - χ x • LinearMap.id + have h₁ : toEnd R L (genWeightSpace M χ) x = n + χ x • LinearMap.id := eq_add_of_sub_eq rfl have h₂ : LinearMap.trace R _ n = 0 := IsReduced.eq_zero _ <| LinearMap.isNilpotent_trace_of_isNilpotent <| isNilpotent_toEnd_sub_algebraMap M χ x rw [LinearMap.comp_apply, LieHom.coe_toLinearMap, h₁, map_add, h₂] simp [mul_comm (χ x)] @[deprecated (since := "2024-04-06")] -alias trace_comp_toEnd_weight_space_eq := trace_comp_toEnd_weightSpace_eq +alias trace_comp_toEnd_weight_space_eq := trace_comp_toEnd_genWeightSpace_eq variable {R L M} in -lemma zero_lt_finrank_weightSpace {χ : L → R} (hχ : weightSpace M χ ≠ ⊥) : - 0 < finrank R (weightSpace M χ) := by +lemma zero_lt_finrank_genWeightSpace {χ : L → R} (hχ : genWeightSpace M χ ≠ ⊥) : + 0 < finrank R (genWeightSpace M χ) := by rwa [← LieSubmodule.nontrivial_iff_ne_bot, ← rank_pos_iff_nontrivial (R := R), ← finrank_eq_rank, Nat.cast_pos] at hχ @@ -142,90 +144,106 @@ on the derived ideal. -/ instance instLinearWeightsOfCharZero [CharZero R] : LinearWeights R L M where map_add χ hχ x y := by - rw [← smul_right_inj (zero_lt_finrank_weightSpace hχ).ne', smul_add, ← Pi.smul_apply, - ← Pi.smul_apply, ← Pi.smul_apply, ← trace_comp_toEnd_weightSpace_eq, map_add] + rw [← smul_right_inj (zero_lt_finrank_genWeightSpace hχ).ne', smul_add, ← Pi.smul_apply, + ← Pi.smul_apply, ← Pi.smul_apply, ← trace_comp_toEnd_genWeightSpace_eq, map_add] map_smul χ hχ t x := by - rw [← smul_right_inj (zero_lt_finrank_weightSpace hχ).ne', smul_comm, ← Pi.smul_apply, - ← Pi.smul_apply (finrank R _), ← trace_comp_toEnd_weightSpace_eq, map_smul] + rw [← smul_right_inj (zero_lt_finrank_genWeightSpace hχ).ne', smul_comm, ← Pi.smul_apply, + ← Pi.smul_apply (finrank R _), ← trace_comp_toEnd_genWeightSpace_eq, map_smul] map_lie χ hχ x y := by - rw [← smul_right_inj (zero_lt_finrank_weightSpace hχ).ne', nsmul_zero, ← Pi.smul_apply, - ← trace_comp_toEnd_weightSpace_eq, LinearMap.comp_apply, LieHom.coe_toLinearMap, + rw [← smul_right_inj (zero_lt_finrank_genWeightSpace hχ).ne', nsmul_zero, ← Pi.smul_apply, + ← trace_comp_toEnd_genWeightSpace_eq, LinearMap.comp_apply, LieHom.coe_toLinearMap, LieHom.map_lie, Ring.lie_def, map_sub, LinearMap.trace_mul_comm, sub_self] end FiniteDimensional variable [LieAlgebra.IsNilpotent R L] (χ : L → R) -/-- A type synonym for the `χ`-weight space but with the action of `x : L` on `m : weightSpace M χ`, -shifted to act as `⁅x, m⁆ - χ x • m`. -/ -def shiftedWeightSpace := weightSpace M χ +/-- A type synonym for the `χ`-weight space but with the action of `x : L` +on `m : genWeightSpace M χ`, shifted to act as `⁅x, m⁆ - χ x • m`. -/ +def shiftedGenWeightSpace := genWeightSpace M χ -namespace shiftedWeightSpace +namespace shiftedGenWeightSpace -private lemma aux [h : Nontrivial (shiftedWeightSpace R L M χ)] : weightSpace M χ ≠ ⊥ := +private lemma aux [h : Nontrivial (shiftedGenWeightSpace R L M χ)] : genWeightSpace M χ ≠ ⊥ := (LieSubmodule.nontrivial_iff_ne_bot _ _ _).mp h variable [LinearWeights R L M] -instance : LieRingModule L (shiftedWeightSpace R L M χ) where +instance : LieRingModule L (shiftedGenWeightSpace R L M χ) where bracket x m := ⁅x, m⁆ - χ x • m add_lie x y m := by - nontriviality shiftedWeightSpace R L M χ + nontriviality shiftedGenWeightSpace R L M χ simp only [add_lie, LinearWeights.map_add χ (aux R L M χ), add_smul] abel lie_add x m n := by - nontriviality shiftedWeightSpace R L M χ + nontriviality shiftedGenWeightSpace R L M χ simp only [lie_add, LinearWeights.map_add χ (aux R L M χ), smul_add] abel leibniz_lie x y m := by - nontriviality shiftedWeightSpace R L M χ + nontriviality shiftedGenWeightSpace R L M χ simp only [lie_sub, lie_smul, lie_lie, LinearWeights.map_lie χ (aux R L M χ), zero_smul, sub_zero, smul_sub, smul_comm (χ x)] abel -@[simp] lemma coe_lie_shiftedWeightSpace_apply (x : L) (m : shiftedWeightSpace R L M χ) : +@[simp] lemma coe_lie_shiftedGenWeightSpace_apply (x : L) (m : shiftedGenWeightSpace R L M χ) : + letI : Bracket L (shiftedGenWeightSpace R L M χ) := LieRingModule.toBracket ⁅x, m⁆ = ⁅x, (m : M)⁆ - χ x • m := rfl -instance : LieModule R L (shiftedWeightSpace R L M χ) where +instance : LieModule R L (shiftedGenWeightSpace R L M χ) where smul_lie t x m := by - nontriviality shiftedWeightSpace R L M χ + nontriviality shiftedGenWeightSpace R L M χ apply Subtype.ext - simp only [coe_lie_shiftedWeightSpace_apply, smul_lie, LinearWeights.map_smul χ (aux R L M χ), - SetLike.val_smul, smul_sub, sub_right_inj, smul_assoc t] + rw [coe_lie_shiftedGenWeightSpace_apply] + simp only [smul_lie, LinearWeights.map_smul χ (aux R L M χ), smul_assoc t, SetLike.val_smul] + rw [← smul_sub] + congr lie_smul t x m := by - nontriviality shiftedWeightSpace R L M χ + nontriviality shiftedGenWeightSpace R L M χ apply Subtype.ext - simp only [coe_lie_shiftedWeightSpace_apply, lie_smul, LinearWeights.map_smul χ (aux R L M χ), - SetLike.val_smul, smul_sub, sub_right_inj, smul_comm t] + rw [coe_lie_shiftedGenWeightSpace_apply] + simp only [SetLike.val_smul, lie_smul] + rw [smul_comm (χ x), ← smul_sub] + congr -/-- Forgetting the action of `L`, the spaces `weightSpace M χ` and `shiftedWeightSpace R L M χ` are -equivalent. -/ -@[simps!] def shift : weightSpace M χ ≃ₗ[R] shiftedWeightSpace R L M χ := LinearEquiv.refl R _ +/-- Forgetting the action of `L`, +the spaces `genWeightSpace M χ` and `shiftedGenWeightSpace R L M χ` are equivalent. -/ +@[simps!] def shift : genWeightSpace M χ ≃ₗ[R] shiftedGenWeightSpace R L M χ := LinearEquiv.refl R _ lemma toEnd_eq (x : L) : - toEnd R L (shiftedWeightSpace R L M χ) x = - (shift R L M χ).conj (toEnd R L (weightSpace M χ) x - χ x • LinearMap.id) := by - ext; simp [LinearEquiv.conj_apply] + toEnd R L (shiftedGenWeightSpace R L M χ) x = + (shift R L M χ).conj (toEnd R L (genWeightSpace M χ) x - χ x • LinearMap.id) := by + ext + simp only [toEnd_apply_apply, map_sub, LinearEquiv.conj_apply, map_smul, LinearMap.comp_id, + LinearEquiv.comp_coe, LinearEquiv.symm_trans_self, LinearEquiv.refl_toLinearMap, + LinearMap.sub_apply, LinearMap.coe_comp, LinearEquiv.coe_coe, Function.comp_apply, + shift_symm_apply, shift_apply, LinearMap.smul_apply, LinearMap.id_coe, id_eq, + AddSubgroupClass.coe_sub, SetLike.val_smul] + rw [LieSubmodule.coe_bracket] + rfl /-- By Engel's theorem, if `M` is Noetherian, the shifted action `⁅x, m⁆ - χ x • m` makes the `χ`-weight space into a nilpotent Lie module. -/ -instance [IsNoetherian R M] : IsNilpotent R L (shiftedWeightSpace R L M χ) := +instance [IsNoetherian R M] : IsNilpotent R L (shiftedGenWeightSpace R L M χ) := LieModule.isNilpotent_iff_forall'.mpr fun x ↦ isNilpotent_toEnd_sub_algebraMap M χ x -end shiftedWeightSpace +end shiftedGenWeightSpace +open shiftedGenWeightSpace in /-- Given a Lie module `M` of a Lie algebra `L` with coefficients in `R`, if a function `χ : L → R` has a simultaneous generalized eigenvector for the action of `L` then it has a simultaneous true eigenvector, provided `M` is Noetherian and has linear weights. -/ lemma exists_forall_lie_eq_smul [LinearWeights R L M] [IsNoetherian R M] (χ : Weight R L M) : ∃ m : M, m ≠ 0 ∧ ∀ x : L, ⁅x, m⁆ = χ x • m := by - replace hχ : Nontrivial (shiftedWeightSpace R L M χ) := - (LieSubmodule.nontrivial_iff_ne_bot R L M).mpr χ.weightSpace_ne_bot + replace hχ : Nontrivial (shiftedGenWeightSpace R L M χ) := + (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 (shiftedWeightSpace R L M χ)) 0 - simp_rw [LieSubmodule.mem_coeSubmodule, mem_maxTrivSubmodule, Subtype.ext_iff, - shiftedWeightSpace.coe_lie_shiftedWeightSpace_apply, ZeroMemClass.coe_zero, sub_eq_zero] at hm₁ - exact ⟨m, by simpa using hm₂, hm₁⟩ + @exists_ne _ (nontrivial_max_triv_of_isNilpotent R L (shiftedGenWeightSpace R L M χ)) 0 + simp_rw [mem_maxTrivSubmodule, Subtype.ext_iff, + ZeroMemClass.coe_zero] at 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 end LieModule diff --git a/Mathlib/Algebra/Lie/Weights/RootSystem.lean b/Mathlib/Algebra/Lie/Weights/RootSystem.lean index e4cecabbee665..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 /-! @@ -50,9 +51,9 @@ private lemma chainLength_aux (hα : α.IsNonZero) {x} (hx : x ∈ rootSpace H ( obtain ⟨h, e, f, isSl2, he, hf⟩ := exists_isSl2Triple_of_weight_isNonZero hα obtain rfl := isSl2.h_eq_coroot hα he hf have : isSl2.HasPrimitiveVectorWith x (chainTop α β (coroot α)) := - have := lie_mem_weightSpace_of_mem_weightSpace he hx + have := lie_mem_genWeightSpace_of_mem_genWeightSpace he hx ⟨hx', by rw [← lie_eq_smul_of_mem_rootSpace hx]; rfl, - by rwa [weightSpace_add_chainTop α β hα] at this⟩ + by rwa [genWeightSpace_add_chainTop α β hα] at this⟩ obtain ⟨μ, hμ⟩ := this.exists_nat exact ⟨μ, by rw [← Nat.cast_smul_eq_nsmul K, ← hμ, lie_eq_smul_of_mem_rootSpace hx]⟩ @@ -101,8 +102,8 @@ lemma rootSpace_neg_nsmul_add_chainTop_of_le {n : ℕ} (hn : n ≤ chainLength obtain ⟨h, e, f, isSl2, he, hf⟩ := exists_isSl2Triple_of_weight_isNonZero hα obtain rfl := isSl2.h_eq_coroot hα he hf have prim : isSl2.HasPrimitiveVectorWith x (chainLength α β : K) := - have := lie_mem_weightSpace_of_mem_weightSpace he hx - ⟨x_ne0, (chainLength_smul _ _ hx).symm, by rwa [weightSpace_add_chainTop _ _ hα] at this⟩ + have := lie_mem_genWeightSpace_of_mem_genWeightSpace he hx + ⟨x_ne0, (chainLength_smul _ _ hx).symm, by rwa [genWeightSpace_add_chainTop _ _ hα] at this⟩ simp only [← smul_neg, ne_eq, LieSubmodule.eq_bot_iff, not_forall] exact ⟨_, toEnd_pow_apply_mem hf hx n, prim.pow_toEnd_f_ne_zero_of_eq_nat rfl hn⟩ @@ -127,14 +128,14 @@ lemma rootSpace_neg_nsmul_add_chainTop_of_lt (hα : α.IsNonZero) {n : ℕ} (hn ring have := rootSpace_neg_nsmul_add_chainTop_of_le (-α) W H₁ rw [Weight.coe_neg, ← smul_neg, neg_neg, ← Weight.coe_neg, H₂] at this - exact this (weightSpace_chainTopCoeff_add_one_nsmul_add α β hα) + exact this (genWeightSpace_chainTopCoeff_add_one_nsmul_add α β hα) lemma chainTopCoeff_le_chainLength : chainTopCoeff α β ≤ chainLength α β := by by_cases hα : α.IsZero · simp only [hα.eq, chainTopCoeff_zero, zero_le] rw [← not_lt, ← Nat.succ_le] intro e - apply weightSpace_nsmul_add_ne_bot_of_le α β + apply genWeightSpace_nsmul_add_ne_bot_of_le α β (Nat.sub_le (chainTopCoeff α β) (chainLength α β).succ) rw [← Nat.cast_smul_eq_nsmul ℤ, Nat.cast_sub e, sub_smul, sub_eq_neg_add, add_assoc, ← coe_chainTop, Nat.cast_smul_eq_nsmul] @@ -148,7 +149,7 @@ lemma chainBotCoeff_add_chainTopCoeff : · rw [← Nat.le_sub_iff_add_le (chainTopCoeff_le_chainLength α β), ← not_lt, ← Nat.succ_le, chainBotCoeff, ← Weight.coe_neg] intro e - apply weightSpace_nsmul_add_ne_bot_of_le _ _ e + apply genWeightSpace_nsmul_add_ne_bot_of_le _ _ e rw [← Nat.cast_smul_eq_nsmul ℤ, Nat.cast_succ, Nat.cast_sub (chainTopCoeff_le_chainLength α β), LieModule.Weight.coe_neg, smul_neg, ← neg_smul, neg_add_rev, neg_sub, sub_eq_neg_add, ← add_assoc, ← neg_add_rev, add_smul, add_assoc, ← coe_chainTop, neg_smul, @@ -160,7 +161,7 @@ lemma chainBotCoeff_add_chainTopCoeff : rw [← Nat.succ_add, ← Nat.cast_smul_eq_nsmul ℤ, ← neg_smul, coe_chainTop, ← add_assoc, ← add_smul, Nat.cast_add, neg_add, add_assoc, neg_add_cancel, add_zero, neg_smul, ← smul_neg, Nat.cast_smul_eq_nsmul] - exact weightSpace_chainTopCoeff_add_one_nsmul_add (-α) β (Weight.IsNonZero.neg hα) + exact genWeightSpace_chainTopCoeff_add_one_nsmul_add (-α) β (Weight.IsNonZero.neg hα) lemma chainTopCoeff_add_chainBotCoeff : chainTopCoeff α β + chainBotCoeff α β = chainLength α β := by @@ -254,13 +255,13 @@ lemma chainTopCoeff_zero_right [Nontrivial L] (hα : α.IsNonZero) : · rw [Nat.one_le_iff_ne_zero] intro e exact α.2 (by simpa [e, Weight.coe_zero] using - weightSpace_chainTopCoeff_add_one_nsmul_add α (0 : Weight K H L) hα) + genWeightSpace_chainTopCoeff_add_one_nsmul_add α (0 : Weight K H L) hα) obtain ⟨x, hx, x_ne0⟩ := (chainTop α (0 : Weight K H L)).exists_ne_zero obtain ⟨h, e, f, isSl2, he, hf⟩ := exists_isSl2Triple_of_weight_isNonZero hα obtain rfl := isSl2.h_eq_coroot hα he hf have prim : isSl2.HasPrimitiveVectorWith x (chainLength α (0 : Weight K H L) : K) := - have := lie_mem_weightSpace_of_mem_weightSpace he hx - ⟨x_ne0, (chainLength_smul _ _ hx).symm, by rwa [weightSpace_add_chainTop _ _ hα] at this⟩ + have := lie_mem_genWeightSpace_of_mem_genWeightSpace he hx + ⟨x_ne0, (chainLength_smul _ _ hx).symm, by rwa [genWeightSpace_add_chainTop _ _ hα] at this⟩ obtain ⟨k, hk⟩ : ∃ k : K, k • f = (toEnd K L L f ^ (chainTopCoeff α (0 : Weight K H L) + 1)) x := by have : (toEnd K L L f ^ (chainTopCoeff α (0 : Weight K H L) + 1)) x ∈ rootSpace H (-α) := by @@ -290,7 +291,7 @@ lemma rootSpace_two_smul (hα : α.IsNonZero) : rootSpace H (2 • α) = ⊥ := cases subsingleton_or_nontrivial L · exact IsEmpty.elim inferInstance α simpa [chainTopCoeff_zero_right α hα] using - weightSpace_chainTopCoeff_add_one_nsmul_add α (0 : Weight K H L) hα + genWeightSpace_chainTopCoeff_add_one_nsmul_add α (0 : Weight K H L) hα lemma rootSpace_one_div_two_smul (hα : α.IsNonZero) : rootSpace H ((2⁻¹ : K) • α) = ⊥ := by by_contra h @@ -298,7 +299,7 @@ lemma rootSpace_one_div_two_smul (hα : α.IsNonZero) : rootSpace H ((2⁻¹ : K have hW : 2 • (W : H → K) = α := by show 2 • (2⁻¹ : K) • (α : H → K) = α rw [← Nat.cast_smul_eq_nsmul K, smul_smul]; simp - apply α.weightSpace_ne_bot + apply α.genWeightSpace_ne_bot have := rootSpace_two_smul W (fun (e : (W : H → K) = 0) ↦ hα <| by apply_fun (2 • ·) at e; simpa [hW] using e) rwa [hW] at this @@ -353,9 +354,9 @@ lemma eq_neg_or_eq_of_eq_smul (hβ : β.IsNonZero) (k : K) (h : (β : H → K) = /-- The reflection of a root along another. -/ def reflectRoot (α β : Weight K H L) : Weight K H L where toFun := β - β (coroot α) • α - weightSpace_ne_bot' := by + genWeightSpace_ne_bot' := by by_cases hα : α.IsZero - · simpa [hα.eq] using β.weightSpace_ne_bot + · simpa [hα.eq] using β.genWeightSpace_ne_bot rw [sub_eq_neg_add, apply_coroot_eq_cast α β, ← neg_smul, ← Int.cast_neg, Int.cast_smul_eq_zsmul, rootSpace_zsmul_add_ne_bot_iff α β hα] omega @@ -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,15 +385,24 @@ 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 rootSystem_toLin_apply (f x) : (rootSystem H).toLin f x = f x := rfl +@[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")] +alias rootSystem_toLin_apply := rootSystem_toPerfectPairing_apply @[simp] lemma rootSystem_pairing_apply (α β) : (rootSystem H).pairing β α = β.1 (coroot α.1) := rfl @[simp] lemma rootSystem_root_apply (α) : (rootSystem H).root α = α := rfl @[simp] lemma rootSystem_coroot_apply (α) : (rootSystem H).coroot α = coroot α := rfl @@ -402,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/ModEq.lean b/Mathlib/Algebra/ModEq.lean index 5cd5445eab5d8..a275aad2c7254 100644 --- a/Mathlib/Algebra/ModEq.lean +++ b/Mathlib/Algebra/ModEq.lean @@ -4,7 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ import Mathlib.Data.Int.ModEq -import Mathlib.GroupTheory.QuotientGroup +import Mathlib.Algebra.Field.Basic +import Mathlib.Algebra.Order.Ring.Int +import Mathlib.GroupTheory.QuotientGroup.Basic /-! # Equality modulo an element 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 91e832b7f7568..8656e47667f24 100644 --- a/Mathlib/Algebra/Module/Basic.lean +++ b/Mathlib/Algebra/Module/Basic.lean @@ -3,11 +3,10 @@ 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.Field.Basic import Mathlib.Algebra.Group.Action.Pi import Mathlib.Algebra.Group.Indicator import Mathlib.Algebra.Module.Defs -import Mathlib.Algebra.Field.Basic -import Mathlib.GroupTheory.GroupAction.Group /-! # Further basic results about modules. @@ -102,9 +101,7 @@ section NoZeroSMulDivisors section Module -variable [Ring R] [AddCommGroup M] [Module R M] [NoZeroSMulDivisors R M] - -instance [NoZeroSMulDivisors ℤ M] : NoZeroSMulDivisors ℕ M := +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 @@ -136,7 +133,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 0799ce0c60156..d15e7274ec57a 100644 --- a/Mathlib/Algebra/Module/BigOperators.lean +++ b/Mathlib/Algebra/Module/BigOperators.lean @@ -3,9 +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, Yury Kudryashov, Yaël Dillies -/ +import Mathlib.Algebra.BigOperators.GroupWithZero.Action import Mathlib.Algebra.Module.Defs import Mathlib.Data.Fintype.BigOperators -import Mathlib.GroupTheory.GroupAction.BigOperators /-! # Finite sums over modules over a ring @@ -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 @@ -54,6 +54,6 @@ lemma sum_piFinset_apply (f : κ → α) (s : Finset κ) (i : ι) : 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/Defs.lean b/Mathlib/Algebra/Module/Defs.lean index 53aee9653932d..f810b34644f19 100644 --- a/Mathlib/Algebra/Module/Defs.lean +++ b/Mathlib/Algebra/Module/Defs.lean @@ -67,7 +67,8 @@ variable [Semiring R] [AddCommMonoid M] [Module R M] (r s : R) (x y : 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 } @@ -95,11 +96,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] -set_option linter.deprecated false in -@[deprecated (since := "2022-12-31")] -theorem two_smul' : (2 : R) • x = (2 : ℕ) • x := by - rw [two_smul, two_nsmul] - @[simp] theorem invOf_two_smul_add_invOf_two_smul [Invertible (2 : R)] (x : M) : (⅟ 2 : R) • x + (⅟ 2 : R) • x = x := @@ -355,9 +351,10 @@ def AddCommMonoid.uniqueNatModule : Unique (Module ℕ M) where uniq P := (Module.ext' P _) fun n => by convert nat_smul_eq_nsmul P n instance AddCommMonoid.nat_isScalarTower : IsScalarTower ℕ R M where - smul_assoc n x y := - Nat.recOn n (by simp only [Nat.zero_eq, zero_smul]) - fun n ih => by simp only [Nat.succ_eq_add_one, add_smul, one_smul, ih] + smul_assoc n x y := by + induction n with + | zero => simp only [zero_smul] + | succ n ih => simp only [add_smul, one_smul, ih] end AddCommMonoid @@ -575,7 +572,7 @@ theorem NoZeroSMulDivisors.int_of_charZero NoZeroSMulDivisors ℤ M := ⟨fun {z x} h ↦ by simpa [← smul_one_smul R z x] using h⟩ -/-- Only a ring of characteristic zero can can have a non-trivial module without additive or +/-- 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} ↦ ?_⟩ diff --git a/Mathlib/Algebra/Module/Equiv/Basic.lean b/Mathlib/Algebra/Module/Equiv/Basic.lean index 1197686e29602..502f5ddd8ebdf 100644 --- a/Mathlib/Algebra/Module/Equiv/Basic.lean +++ b/Mathlib/Algebra/Module/Equiv/Basic.lean @@ -122,7 +122,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 @@ -403,23 +403,23 @@ end Subsingleton section Uncurry -variable [Semiring R] [Semiring R₂] [Semiring R₃] -variable [AddCommMonoid M] [AddCommMonoid M₂] [AddCommMonoid M₃] -variable (V V₂ R) +variable [Semiring R] +variable [AddCommMonoid M] [Module R M] +variable (V V₂ R M) /-- Linear equivalence between a curried and uncurried function. Differs from `TensorProduct.curry`. -/ -protected def curry : (V × V₂ → R) ≃ₗ[R] V → V₂ → R := +protected def curry : (V × V₂ → M) ≃ₗ[R] V → V₂ → M := { Equiv.curry _ _ _ with map_add' := fun _ _ ↦ rfl map_smul' := fun _ _ ↦ rfl } @[simp] -theorem coe_curry : ⇑(LinearEquiv.curry R V V₂) = curry := +theorem coe_curry : ⇑(LinearEquiv.curry R M V V₂) = curry := rfl @[simp] -theorem coe_curry_symm : ⇑(LinearEquiv.curry R V V₂).symm = uncurry := +theorem coe_curry_symm : ⇑(LinearEquiv.curry R M V V₂).symm = uncurry := rfl end Uncurry diff --git a/Mathlib/Algebra/Module/Equiv/Defs.lean b/Mathlib/Algebra/Module/Equiv/Defs.lean index 1513cc839f617..9a5d7dcbdfd0d 100644 --- a/Mathlib/Algebra/Module/Equiv/Defs.lean +++ b/Mathlib/Algebra/Module/Equiv/Defs.lean @@ -449,9 +449,7 @@ theorem map_ne_zero_iff {x : M} : e x ≠ 0 ↔ x ≠ 0 := e.toAddEquiv.map_ne_zero_iff @[simp] -theorem symm_symm (e : M ≃ₛₗ[σ] M₂) : e.symm.symm = e := by - cases e - rfl +theorem symm_symm (e : M ≃ₛₗ[σ] M₂) : e.symm.symm = e := rfl theorem symm_bijective [Module R M] [Module S M₂] [RingHomInvPair σ' σ] [RingHomInvPair σ σ'] : Function.Bijective (symm : (M ≃ₛₗ[σ] M₂) → M₂ ≃ₛₗ[σ'] M) := @@ -462,7 +460,7 @@ theorem mk_coe' (f h₁ h₂ h₃ h₄) : (LinearEquiv.mk ⟨⟨f, h₁⟩, h₂⟩ (⇑e) h₃ h₄ : M₂ ≃ₛₗ[σ'] M) = e.symm := symm_bijective.injective <| ext fun _ ↦ rfl -/-- Auxilliary definition to avoid looping in `dsimp` with `LinearEquiv.symm_mk`. -/ +/-- Auxiliary definition to avoid looping in `dsimp` with `LinearEquiv.symm_mk`. -/ protected def symm_mk.aux (f h₁ h₂ h₃ h₄) := (⟨⟨⟨e, h₁⟩, h₂⟩, f, h₃, h₄⟩ : M ≃ₛₗ[σ] M₂).symm @[simp] diff --git a/Mathlib/Algebra/Module/FinitePresentation.lean b/Mathlib/Algebra/Module/FinitePresentation.lean index 0ea4c4bf7fa0c..024751ec3f4b5 100644 --- a/Mathlib/Algebra/Module/FinitePresentation.lean +++ b/Mathlib/Algebra/Module/FinitePresentation.lean @@ -48,6 +48,8 @@ For finitely presented algebras, see `Algebra.FinitePresentation` in file `Mathlib.RingTheory.FinitePresentation`. -/ +open Finsupp + section Semiring variable (R M) [Semiring R] [AddCommMonoid M] [Module R M] @@ -57,7 +59,7 @@ and the kernel of the presentation `Rˢ → M` is also finitely generated. -/ class Module.FinitePresentation : Prop where out : ∃ (s : Finset M), Submodule.span R (s : Set M) = ⊤ ∧ - (LinearMap.ker (Finsupp.total s M R Subtype.val)).FG + (LinearMap.ker (Finsupp.linearCombination R ((↑) : s → M))).FG instance (priority := 100) [h : Module.FinitePresentation R M] : Module.Finite R M := by obtain ⟨s, hs₁, _⟩ := h @@ -78,10 +80,10 @@ theorem Module.FinitePresentation.equiv_quotient [fp : Module.FinitePresentation Module.Free R L ∧ Module.Finite R L ∧ K.FG := by obtain ⟨ι, ⟨hι₁, hι₂⟩⟩ := fp use ι →₀ R, inferInstance, inferInstance - use LinearMap.ker (Finsupp.total { x // x ∈ ι } M R Subtype.val) + use LinearMap.ker (Finsupp.linearCombination R Subtype.val) refine ⟨(LinearMap.quotKerEquivOfSurjective _ ?_).symm, inferInstance, inferInstance, hι₂⟩ apply LinearMap.range_eq_top.mp - simpa only [Finsupp.range_total, Subtype.range_coe_subtype, Finset.setOf_mem] + simpa only [Finsupp.range_linearCombination, Subtype.range_coe_subtype, Finset.setOf_mem] -- Ideally this should be an instance but it makes mathlib much slower. lemma Module.finitePresentation_of_finite [IsNoetherianRing R] [h : Module.Finite R M] : @@ -119,12 +121,12 @@ lemma Module.finitePresentation_of_free_of_surjective [Module.Free R M] [Module. constructor · intro hx refine ⟨b.repr.symm (x.mapDomain σ), ?_, ?_⟩ - · simp [Finsupp.apply_total, hσ₂, hx] + · simp [Finsupp.apply_linearCombination, hσ₂, hx] · simp only [f, LinearMap.comp_apply, b.repr.apply_symm_apply, LinearEquiv.coe_toLinearMap, Finsupp.lmapDomain_apply] rw [← Finsupp.mapDomain_comp, hσ₁, Finsupp.mapDomain_id] · rintro ⟨y, hy, rfl⟩ - simp [f, hπ, ← Finsupp.apply_total, hy] + simp [f, hπ, ← Finsupp.apply_linearCombination, hy] -- Ideally this should be an instance but it makes mathlib much slower. variable (R M) in @@ -145,12 +147,12 @@ lemma Module.finitePresentation_of_surjective [h : Module.FinitePresentation R M classical obtain ⟨s, hs, hs'⟩ := h obtain ⟨t, ht⟩ := hl' - have H : Function.Surjective (Finsupp.total s M R Subtype.val) := - LinearMap.range_eq_top.mp (by rw [Finsupp.range_total, Subtype.range_val, ← hs]; rfl) - apply Module.finitePresentation_of_free_of_surjective (l ∘ₗ Finsupp.total s M R Subtype.val) + have H : Function.Surjective (Finsupp.linearCombination R ((↑) : s → M)) := + LinearMap.range_eq_top.mp (by rw [range_linearCombination, Subtype.range_val, ← hs]; rfl) + apply Module.finitePresentation_of_free_of_surjective (l ∘ₗ linearCombination R Subtype.val) (hl.comp H) choose σ hσ using (show _ from H) - have : Finsupp.total s M R Subtype.val '' (σ '' t) = t := by + have : Finsupp.linearCombination R Subtype.val '' (σ '' t) = t := by simp only [Set.image_image, hσ, Set.image_id'] rw [LinearMap.ker_comp, ← ht, ← this, ← Submodule.map_span, Submodule.comap_map_eq, ← Finset.coe_image] @@ -161,11 +163,11 @@ lemma Module.FinitePresentation.fg_ker [Module.Finite R M] (LinearMap.ker l).FG := by classical obtain ⟨s, hs, hs'⟩ := h - have H : Function.Surjective (Finsupp.total s N R Subtype.val) := - LinearMap.range_eq_top.mp (by rw [Finsupp.range_total, Subtype.range_val, ← hs]; rfl) - obtain ⟨f, hf⟩ : ∃ f : (s →₀ R) →ₗ[R] M, l ∘ₗ f = (Finsupp.total s N R Subtype.val) := by + have H : Function.Surjective (Finsupp.linearCombination R ((↑) : s → N)) := + LinearMap.range_eq_top.mp (by rw [range_linearCombination, Subtype.range_val, ← hs]; rfl) + obtain ⟨f, hf⟩ : ∃ f : (s →₀ R) →ₗ[R] M, l ∘ₗ f = (Finsupp.linearCombination R Subtype.val) := by choose f hf using show _ from hl - exact ⟨Finsupp.total s M R (fun i ↦ f i), by ext; simp [hf]⟩ + exact ⟨Finsupp.linearCombination R (fun i ↦ f i), by ext; simp [hf]⟩ have : (LinearMap.ker l).map (LinearMap.range f).mkQ = ⊤ := by rw [← top_le_iff] rintro x - @@ -192,9 +194,9 @@ lemma Module.finitePresentation_of_ker [Module.FinitePresentation R N] · rw [Submodule.map_top, LinearMap.range_eq_top.mpr hl]; exact Module.Finite.out · rw [top_inf_eq, ← Submodule.fg_top]; exact Module.Finite.out refine ⟨s, hs, ?_⟩ - let π := Finsupp.total s M R Subtype.val + let π := Finsupp.linearCombination R ((↑) : s → M) have H : Function.Surjective π := - LinearMap.range_eq_top.mp (by rw [Finsupp.range_total, Subtype.range_val, ← hs]; rfl) + LinearMap.range_eq_top.mp (by rw [range_linearCombination, Subtype.range_val, ← hs]; rfl) have inst : Module.Finite R (LinearMap.ker (l ∘ₗ π)) := by constructor rw [Submodule.fg_top]; exact Module.FinitePresentation.fg_ker _ (hl.comp H) @@ -227,23 +229,24 @@ lemma Module.FinitePresentation.exists_lift_of_isLocalizedModule [h : Module.FinitePresentation R M] (g : M →ₗ[R] N') : ∃ (h : M →ₗ[R] N) (s : S), f ∘ₗ h = s • g := by obtain ⟨σ, hσ, τ, hτ⟩ := h - let π := Finsupp.total σ M R Subtype.val + let π := Finsupp.linearCombination R ((↑) : σ → M) have hπ : Function.Surjective π := - LinearMap.range_eq_top.mp (by rw [Finsupp.range_total, Subtype.range_val, ← hσ]; rfl) + LinearMap.range_eq_top.mp (by rw [range_linearCombination, Subtype.range_val, ← hσ]; rfl) classical choose s hs using IsLocalizedModule.surj S f let i : σ → N := fun x ↦ (∏ j ∈ σ.erase x.1, (s (g j)).2) • (s (g x)).1 let s₀ := ∏ j ∈ σ, (s (g j)).2 - have hi : f ∘ₗ Finsupp.total σ N R i = (s₀ • g) ∘ₗ π := by + have hi : f ∘ₗ Finsupp.linearCombination R i = (s₀ • g) ∘ₗ π := by ext j - simp only [LinearMap.coe_comp, Function.comp_apply, Finsupp.lsingle_apply, Finsupp.total_single, - one_smul, LinearMap.map_smul_of_tower, ← hs, LinearMap.smul_apply, i, s₀, π] + simp only [LinearMap.coe_comp, Function.comp_apply, Finsupp.lsingle_apply, + linearCombination_single, one_smul, LinearMap.map_smul_of_tower, ← hs, LinearMap.smul_apply, + i, s₀, π] rw [← mul_smul, Finset.prod_erase_mul] exact j.prop - have : ∀ x : τ, ∃ s : S, s • (Finsupp.total σ N R i x) = 0 := by + have : ∀ x : τ, ∃ s : S, s • (Finsupp.linearCombination R i x) = 0 := by intros x - convert_to ∃ s : S, s • (Finsupp.total σ N R i x) = s • 0 + convert_to ∃ s : S, s • (Finsupp.linearCombination R i x) = s • 0 · simp only [smul_zero] apply IsLocalizedModule.exists_of_eq (S := S) (f := f) rw [← LinearMap.comp_apply, map_zero, hi, LinearMap.comp_apply] @@ -252,7 +255,7 @@ lemma Module.FinitePresentation.exists_lift_of_isLocalizedModule exact Submodule.subset_span x.prop choose s' hs' using this let s₁ := ∏ i : τ, s' i - have : LinearMap.ker π ≤ LinearMap.ker (s₁ • Finsupp.total σ N R i) := by + have : LinearMap.ker π ≤ LinearMap.ker (s₁ • Finsupp.linearCombination R i) := by rw [← hτ, Submodule.span_le] intro x hxσ simp only [s₁] diff --git a/Mathlib/Algebra/Module/Hom.lean b/Mathlib/Algebra/Module/Hom.lean index 2550ee8e60c98..19bee131fe2dd 100644 --- a/Mathlib/Algebra/Module/Hom.lean +++ b/Mathlib/Algebra/Module/Hom.lean @@ -120,7 +120,7 @@ instance applyModule [AddCommMonoid A] : Module (AddMonoid.End A) A where end AddMonoid.End -/-! ### Miscelaneous morphisms -/ +/-! ### Miscellaneous morphisms -/ namespace AddMonoidHom diff --git a/Mathlib/Algebra/Module/Injective.lean b/Mathlib/Algebra/Module/Injective.lean index 536a41a974e42..a2e077efec5f7 100644 --- a/Mathlib/Algebra/Module/Injective.lean +++ b/Mathlib/Algebra/Module/Injective.lean @@ -67,8 +67,8 @@ 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) + 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 Module.injective_iff_injective_object : @@ -249,7 +249,7 @@ variable (f) def ExtensionOfMaxAdjoin.ideal (y : N) : Ideal R := (extensionOfMax i f).domain.comap ((LinearMap.id : R →ₗ[R] R).smulRight y) -/-- A linear map `I ⟶ Q` by `x ↦ f' (x • y)` where `f'` is the maximal extension-/ +/-- A linear map `I ⟶ Q` by `x ↦ f' (x • y)` where `f'` is the maximal extension -/ def ExtensionOfMaxAdjoin.idealTo (y : N) : ExtensionOfMaxAdjoin.ideal i f y →ₗ[R] Q where toFun (z : { x // x ∈ ideal i f y }) := (extensionOfMax i f).toLinearPMap ⟨(↑z : R) • y, z.prop⟩ map_add' (z1 z2 : { x // x ∈ ideal i f y }) := by diff --git a/Mathlib/Algebra/Module/LinearMap/Basic.lean b/Mathlib/Algebra/Module/LinearMap/Basic.lean index f50429fa64814..1a68ecbd89506 100644 --- a/Mathlib/Algebra/Module/LinearMap/Basic.lean +++ b/Mathlib/Algebra/Module/LinearMap/Basic.lean @@ -21,41 +21,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 +63,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 +81,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 4d7974c2e677b..e2c0d89223846 100644 --- a/Mathlib/Algebra/Module/LinearMap/Defs.lean +++ b/Mathlib/Algebra/Module/LinearMap/Defs.lean @@ -323,7 +323,7 @@ protected theorem congr_fun (h : f = g) (x : M) : f x = g x := @[simp] theorem mk_coe (f : M →ₛₗ[σ] M₃) (h) : (LinearMap.mk f h : M →ₛₗ[σ] M₃) = f := - ext fun _ ↦ rfl + rfl variable (fₗ gₗ f g) @@ -503,11 +503,11 @@ theorem coe_comp : (f.comp g : M₁ → M₃) = f ∘ g := @[simp] theorem comp_id : f.comp id = f := - LinearMap.ext fun _ ↦ rfl + rfl @[simp] theorem id_comp : id.comp f = f := - LinearMap.ext fun _ ↦ rfl + rfl theorem comp_assoc {R₄ M₄ : Type*} [Semiring R₄] [AddCommMonoid M₄] [Module R₄ M₄] @@ -881,7 +881,7 @@ def toAddMonoidHom' : (M →ₛₗ[σ₁₂] M₂) →+ M →+ M₂ where map_zero' := by ext; rfl map_add' := by intros; ext; rfl -/-- If `M` is the zero module, then the identity map of `M` is the zero map. -/ +/-- If `M` is the zero module, then the identity map of `M` is the zero map. -/ @[simp] theorem identityMapOfZeroModuleIsZero [Subsingleton M] : id (R := R₁) (M := M) = 0 := Subsingleton.eq_zero id @@ -933,9 +933,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 +947,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 +959,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 4d09f38caa016..0c0b70a638554 100644 --- a/Mathlib/Algebra/Module/LinearMap/End.lean +++ b/Mathlib/Algebra/Module/LinearMap/End.lean @@ -138,9 +138,9 @@ theorem commute_pow_left_of_commute [Semiring R₂] [AddCommMonoid M₂] [Module R₂ M₂] {σ₁₂ : R →+* R₂} {f : M →ₛₗ[σ₁₂] M₂} {g : Module.End R M} {g₂ : Module.End R₂ M₂} (h : g₂.comp f = f.comp g) (k : ℕ) : (g₂ ^ k).comp f = f.comp (g ^ k) := by - induction' k with k ih - · simp only [Nat.zero_eq, pow_zero, one_eq_id, id_comp, comp_id] - · rw [pow_succ', pow_succ', LinearMap.mul_eq_comp, LinearMap.comp_assoc, ih, + induction k with + | zero => simp only [pow_zero, one_eq_id, id_comp, comp_id] + | succ k ih => rw [pow_succ', pow_succ', LinearMap.mul_eq_comp, LinearMap.comp_assoc, ih, ← LinearMap.comp_assoc, h, LinearMap.comp_assoc, LinearMap.mul_eq_comp] @[simp] 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/LocalizedModule.lean b/Mathlib/Algebra/Module/LocalizedModule.lean index 45ebbceedbb8a..f9a2368b9a818 100644 --- a/Mathlib/Algebra/Module/LocalizedModule.lean +++ b/Mathlib/Algebra/Module/LocalizedModule.lean @@ -402,6 +402,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₂ => _ @@ -605,7 +628,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 +648,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 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/Projective.lean b/Mathlib/Algebra/Module/Projective.lean index 3a0613a2f353f..b4387f01f63c9 100644 --- a/Mathlib/Algebra/Module/Projective.lean +++ b/Mathlib/Algebra/Module/Projective.lean @@ -72,7 +72,7 @@ open Finsupp definitions. -/ class Module.Projective (R : Type*) [Semiring R] (P : Type*) [AddCommMonoid P] [Module R P] : Prop where - out : ∃ s : P →ₗ[R] P →₀ R, Function.LeftInverse (Finsupp.total P P R id) s + out : ∃ s : P →ₗ[R] P →₀ R, Function.LeftInverse (Finsupp.linearCombination R id) s namespace Module @@ -82,11 +82,11 @@ variable {R : Type*} [Semiring R] {P : Type*} [AddCommMonoid P] [Module R P] {M [AddCommMonoid M] [Module R M] {N : Type*} [AddCommMonoid N] [Module R N] theorem projective_def : - Projective R P ↔ ∃ s : P →ₗ[R] P →₀ R, Function.LeftInverse (Finsupp.total P P R id) s := + Projective R P ↔ ∃ s : P →ₗ[R] P →₀ R, Function.LeftInverse (linearCombination R id) s := ⟨fun h => h.1, fun h => ⟨h⟩⟩ theorem projective_def' : - Projective R P ↔ ∃ s : P →ₗ[R] P →₀ R, Finsupp.total P P R id ∘ₗ s = .id := by + Projective R P ↔ ∃ s : P →ₗ[R] P →₀ R, Finsupp.linearCombination R id ∘ₗ s = .id := by simp_rw [projective_def, DFunLike.ext_iff, Function.LeftInverse, comp_apply, id_apply] /-- A projective R-module has the property that maps from it lift along surjections. -/ @@ -95,20 +95,20 @@ theorem projective_lifting_property [h : Projective R P] (f : M →ₗ[R] N) (g /- Here's the first step of the proof. Recall that `X →₀ R` is Lean's way of talking about the free `R`-module - on a type `X`. The universal property `Finsupp.total` says that to a map + on a type `X`. The universal property `Finsupp.linearCombination` says that to a map `X → N` from a type to an `R`-module, we get an associated R-module map `(X →₀ R) →ₗ N`. Apply this to a (noncomputable) map `P → M` coming from the map `P →ₗ N` and a random splitting of the surjection `M →ₗ N`, and we get a map `φ : (P →₀ R) →ₗ M`. -/ - let φ : (P →₀ R) →ₗ[R] M := Finsupp.total _ _ _ fun p => Function.surjInv hf (g p) + let φ : (P →₀ R) →ₗ[R] M := Finsupp.linearCombination _ fun p => Function.surjInv hf (g p) -- By projectivity we have a map `P →ₗ (P →₀ R)`; cases' h.out with s hs -- Compose to get `P →ₗ M`. This works. use φ.comp s ext p conv_rhs => rw [← hs p] - simp [φ, Finsupp.total_apply, Function.surjInv_eq hf, map_finsupp_sum] + simp [φ, Finsupp.linearCombination_apply, Function.surjInv_eq hf, map_finsupp_sum] /-- 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 @@ -117,8 +117,8 @@ theorem Projective.of_lifting_property'' {R : Type u} [Semiring R] {P : Type v} [Module R P] (huniv : ∀ (f : (P →₀ R) →ₗ[R] P), Function.Surjective f → ∃ h : P →ₗ[R] (P →₀ R), f.comp h = .id) : Projective R P := - projective_def'.2 <| huniv (Finsupp.total P P R (id : P → P)) - (total_surjective _ Function.surjective_id) + projective_def'.2 <| huniv (Finsupp.linearCombination R (id : P → P)) + (linearCombination_surjective _ Function.surjective_id) variable {Q : Type*} [AddCommMonoid Q] [Module R Q] @@ -140,31 +140,22 @@ 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. -- get it from `ι → (P →₀ R)` coming from `b`. use b.constr ℕ fun i => Finsupp.single (b i) (1 : R) intro m - simp only [b.constr_apply, mul_one, id, Finsupp.smul_single', Finsupp.total_single, + simp only [b.constr_apply, mul_one, id, Finsupp.smul_single', Finsupp.linearCombination_single, map_finsupp_sum] - exact b.total_repr m + exact b.linearCombination_repr m 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.total P P R id) s + obtain ⟨g, hg⟩ := projective_lifting_property (Finsupp.linearCombination R id) s (fun x ↦ ⟨Finsupp.single x 1, by simp⟩) refine ⟨g.comp i, fun x ↦ ?_⟩ rw [LinearMap.comp_apply, ← LinearMap.comp_apply, hg, @@ -174,19 +165,27 @@ 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 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) - (i : P →ₗ[R] M) (s : M →ₗ[R] P), s.comp i = LinearMap.id := - ⟨fun ⟨i, hi⟩ ↦ ⟨P →₀ R, _, _, inferInstance, i, Finsupp.total P P 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⟩ +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) + (i : P →ₗ[R] M) (s : M →ₗ[R] P), s.comp i = LinearMap.id := + ⟨fun ⟨i, hi⟩ ↦ ⟨P →₀ R, _, _, inferInstance, i, Finsupp.linearCombination R id, LinearMap.ext hi⟩, + fun ⟨_, _, _, _, i, s, 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] : @@ -197,11 +196,11 @@ instance Projective.tensorProduct [hM : Module.Projective R M] [hN : Module.Proj fapply Projective.of_split (R := R) (M := ((M →₀ R) ⊗[R₀] (N →₀ R₀))) · exact (AlgebraTensorModule.map sM (LinearMap.id (R := R₀) (M := N →₀ R₀))) · exact (AlgebraTensorModule.map - (Finsupp.total M M R id) (LinearMap.id (R := R₀) (M := N →₀ R₀))) + (Finsupp.linearCombination R id) (LinearMap.id (R := R₀) (M := N →₀ R₀))) · ext; simp [hsM _] fapply Projective.of_split (R := R) (M := (M ⊗[R₀] (N →₀ R₀))) · exact (AlgebraTensorModule.map (LinearMap.id (R := R) (M := M)) sN) - · exact (AlgebraTensorModule.map (LinearMap.id (R := R) (M := M)) (Finsupp.total N N R₀ id)) + · exact (AlgebraTensorModule.map (LinearMap.id (R := R) (M := M)) (linearCombination R₀ id)) · ext; simp [hsN _] end Ring diff --git a/Mathlib/Algebra/Module/Rat.lean b/Mathlib/Algebra/Module/Rat.lean index fa255570c0b86..c0ed84a4366ed 100644 --- a/Mathlib/Algebra/Module/Rat.lean +++ b/Mathlib/Algebra/Module/Rat.lean @@ -5,6 +5,7 @@ Authors: Nathaniel Thomas, Jeremy Avigad, Johannes Hölzl, Mario Carneiro -/ import Mathlib.Algebra.Module.Basic import Mathlib.Algebra.Field.Rat +import Mathlib.Algebra.Order.Field.Rat /-! # Basic results about modules over the rationals. @@ -14,6 +15,13 @@ universe u v variable {M M₂ : Type*} +theorem map_nnratCast_smul [AddCommMonoid M] [AddCommMonoid M₂] {F : Type*} [FunLike F M M₂] + [AddMonoidHomClass F M M₂] (f : F) (R S : Type*) [DivisionSemiring R] [DivisionSemiring S] + [Module R M] [Module S M₂] (c : ℚ≥0) (x : M) : + f ((c : R) • x) = (c : S) • f x := by + rw [NNRat.cast_def, NNRat.cast_def, div_eq_mul_inv, div_eq_mul_inv, mul_smul, mul_smul, + map_natCast_smul f R S, map_inv_natCast_smul f R S] + theorem map_ratCast_smul [AddCommGroup M] [AddCommGroup M₂] {F : Type*} [FunLike F M M₂] [AddMonoidHomClass F M M₂] (f : F) (R S : Type*) [DivisionRing R] [DivisionRing S] [Module R M] [Module S M₂] (c : ℚ) (x : M) : @@ -24,17 +32,34 @@ theorem map_ratCast_smul [AddCommGroup M] [AddCommGroup M₂] {F : Type*} [FunLi @[deprecated (since := "2024-04-17")] alias map_rat_cast_smul := map_ratCast_smul +theorem map_nnrat_smul [AddCommMonoid M] [AddCommMonoid M₂] + [_instM : Module ℚ≥0 M] [_instM₂ : Module ℚ≥0 M₂] + {F : Type*} [FunLike F M M₂] [AddMonoidHomClass F M M₂] + (f : F) (c : ℚ≥0) (x : M) : f (c • x) = c • f x := + map_nnratCast_smul f ℚ≥0 ℚ≥0 c x + theorem map_rat_smul [AddCommGroup M] [AddCommGroup M₂] [_instM : Module ℚ M] [_instM₂ : Module ℚ M₂] {F : Type*} [FunLike F M M₂] [AddMonoidHomClass F M M₂] (f : F) (c : ℚ) (x : M) : f (c • x) = c • f x := map_ratCast_smul f ℚ ℚ c x +/-- There can be at most one `Module ℚ≥0 E` structure on an additive commutative monoid. -/ +instance subsingleton_nnrat_module (E : Type*) [AddCommMonoid E] : Subsingleton (Module ℚ≥0 E) := + ⟨fun P Q => (Module.ext' P Q) fun r x => + map_nnrat_smul (_instM := P) (_instM₂ := Q) (AddMonoidHom.id E) r x⟩ + /-- There can be at most one `Module ℚ E` structure on an additive commutative group. -/ instance subsingleton_rat_module (E : Type*) [AddCommGroup E] : Subsingleton (Module ℚ E) := ⟨fun P Q => (Module.ext' P Q) fun r x => map_rat_smul (_instM := P) (_instM₂ := Q) (AddMonoidHom.id E) r x⟩ +/-- If `E` is a vector space over two division semirings `R` and `S`, then scalar multiplications +agree on non-negative rational numbers in `R` and `S`. -/ +theorem nnratCast_smul_eq {E : Type*} (R S : Type*) [AddCommMonoid E] [DivisionSemiring R] + [DivisionSemiring S] [Module R E] [Module S E] (r : ℚ≥0) (x : E) : (r : R) • x = (r : S) • x := + map_nnratCast_smul (AddMonoidHom.id E) R S r x + /-- If `E` is a vector space over two division rings `R` and `S`, then scalar multiplications agree on rational numbers in `R` and `S`. -/ theorem ratCast_smul_eq {E : Type*} (R S : Type*) [AddCommGroup E] [DivisionRing R] @@ -44,22 +69,41 @@ theorem ratCast_smul_eq {E : Type*} (R S : Type*) [AddCommGroup E] [DivisionRing @[deprecated (since := "2024-04-17")] alias rat_cast_smul_eq := ratCast_smul_eq +instance IsScalarTower.nnrat {R : Type u} {M : Type v} [Semiring R] [AddCommMonoid M] [Module R M] + [Module ℚ≥0 R] [Module ℚ≥0 M] : IsScalarTower ℚ≥0 R M where + smul_assoc r x y := map_nnrat_smul ((smulAddHom R M).flip y) r x + instance IsScalarTower.rat {R : Type u} {M : Type v} [Ring R] [AddCommGroup M] [Module R M] [Module ℚ R] [Module ℚ M] : IsScalarTower ℚ R M where smul_assoc r x y := map_rat_smul ((smulAddHom R M).flip y) r x -instance SMulCommClass.rat {R : Type u} {M : Type v} [Semiring R] [AddCommGroup M] [Module R M] - [Module ℚ M] : SMulCommClass ℚ R M where - smul_comm r x y := (map_rat_smul (smulAddHom R M x) r y).symm +section +variable {α : Type u} {M : Type v} -instance SMulCommClass.rat' {R : Type u} {M : Type v} [Semiring R] [AddCommGroup M] [Module R M] - [Module ℚ M] : SMulCommClass R ℚ M := +instance SMulCommClass.nnrat [Monoid α] [AddCommMonoid M] [DistribMulAction α M] [Module ℚ≥0 M] : + SMulCommClass ℚ≥0 α M where + smul_comm r x y := (map_nnrat_smul (DistribMulAction.toAddMonoidHom M x) r y).symm + +instance SMulCommClass.rat [Monoid α] [AddCommGroup M] [DistribMulAction α M] [Module ℚ M] : + SMulCommClass ℚ α M where + smul_comm r x y := (map_rat_smul (DistribMulAction.toAddMonoidHom M x) r y).symm + +instance SMulCommClass.nnrat' [Monoid α] [AddCommMonoid M] [DistribMulAction α M] [Module ℚ≥0 M] : + SMulCommClass α ℚ≥0 M := + SMulCommClass.symm _ _ _ + +instance SMulCommClass.rat' [Monoid α] [AddCommGroup M] [DistribMulAction α M] [Module ℚ M] : + SMulCommClass α ℚ M := SMulCommClass.symm _ _ _ +end + +-- see note [lower instance priority] +instance (priority := 100) NNRatModule.noZeroSMulDivisors [AddCommMonoid M] [Module ℚ≥0 M] : + NoZeroSMulDivisors ℕ M := + ⟨fun {k} {x : M} h => by simpa [← Nat.cast_smul_eq_nsmul ℚ≥0 k x] using h⟩ + -- see note [lower instance priority] instance (priority := 100) RatModule.noZeroSMulDivisors [AddCommGroup M] [Module ℚ M] : NoZeroSMulDivisors ℤ M := - ⟨fun {k} {x : M} h => by - simpa only [← Int.cast_smul_eq_zsmul ℚ k x, smul_eq_zero, Rat.zero_iff_num_zero] using h⟩ - -- Porting note: old proof was: - --⟨fun {k x} h => by simpa [zsmul_eq_smul_cast ℚ k x] using h⟩ + ⟨fun {k} {x : M} h => by simpa [← Int.cast_smul_eq_zsmul ℚ k x] using h⟩ diff --git a/Mathlib/Algebra/Module/Submodule/Basic.lean b/Mathlib/Algebra/Module/Submodule/Basic.lean index 6c89784c098f8..3958ed075e9fb 100644 --- a/Mathlib/Algebra/Module/Submodule/Basic.lean +++ b/Mathlib/Algebra/Module/Submodule/Basic.lean @@ -152,7 +152,7 @@ variable [Semiring R] [AddCommMonoid M] [Module R M] {A : Type*} [SetLike A M] [AddSubmonoidClass A M] [SMulMemClass A R M] (S' : A) -- Prefer subclasses of `Module` over `SMulMemClass`. -/-- A submodule of a `Module` is a `Module`. -/ +/-- A submodule of a `Module` is a `Module`. -/ instance (priority := 75) toModule : Module R S' := Subtype.coe_injective.module R (AddSubmonoidClass.subtype S') (SetLike.val_smul S') @@ -236,6 +236,7 @@ instance isCentralScalar [SMul S R] [SMul S M] [IsScalarTower S R M] [SMul Sᵐ protected theorem nonempty : (p : Set M).Nonempty := ⟨0, p.zero_mem⟩ +@[simp] theorem mk_eq_zero {x} (h : x ∈ p) : (⟨x, h⟩ : p) = 0 ↔ x = 0 := Subtype.ext_iff_val diff --git a/Mathlib/Algebra/Module/Submodule/Bilinear.lean b/Mathlib/Algebra/Module/Submodule/Bilinear.lean index 8f1e0b93e8437..d6c065576cbbf 100644 --- a/Mathlib/Algebra/Module/Submodule/Bilinear.lean +++ b/Mathlib/Algebra/Module/Submodule/Bilinear.lean @@ -37,7 +37,7 @@ variable [Module R M] [Module R N] [Module R P] /-- Map a pair of submodules under a bilinear map. -This is the submodule version of `Set.image2`. -/ +This is the submodule version of `Set.image2`. -/ def map₂ (f : M →ₗ[R] N →ₗ[R] P) (p : Submodule R M) (q : Submodule R N) : Submodule R P := ⨆ s : p, q.map (f s) @@ -56,13 +56,15 @@ theorem map₂_span_span (f : M →ₗ[R] N →ₗ[R] P) (s : Set M) (t : Set N) 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] + 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) diff --git a/Mathlib/Algebra/Module/Submodule/Equiv.lean b/Mathlib/Algebra/Module/Submodule/Equiv.lean index df3250cb70e1e..f5de6d41357b8 100644 --- a/Mathlib/Algebra/Module/Submodule/Equiv.lean +++ b/Mathlib/Algebra/Module/Submodule/Equiv.lean @@ -186,6 +186,11 @@ theorem ofBijective_symm_apply_apply [RingHomInvPair σ₁₂ σ₂₁] [RingHom (ofBijective f h).symm (f x) = x := by simp [LinearEquiv.symm_apply_eq] +@[simp] +theorem apply_ofBijective_symm_apply [RingHomInvPair σ₁₂ σ₂₁] [RingHomInvPair σ₂₁ σ₁₂] {h} + (x : M₂) : f ((ofBijective f h).symm x) = x := by + rw [← ofBijective_apply f ((ofBijective f h).symm x), apply_symm_apply] + end end AddCommMonoid diff --git a/Mathlib/Algebra/Module/Submodule/Ker.lean b/Mathlib/Algebra/Module/Submodule/Ker.lean index 6eefd47994bea..e329b35726b80 100644 --- a/Mathlib/Algebra/Module/Submodule/Ker.lean +++ b/Mathlib/Algebra/Module/Submodule/Ker.lean @@ -192,11 +192,11 @@ theorem ker_eq_bot {f : M →ₛₗ[τ₁₂] M₂} : ker f = ⊥ ↔ Injective · intro x ⟨hx, h'x⟩ have : ⟨x, hx⟩ ∈ LinearMap.ker (LinearMap.domRestrict f S) := by simpa using h'x rw [h] at this - simpa using this + simpa [mk_eq_zero] using this · rintro ⟨x, hx⟩ h'x have : x ∈ S ⊓ LinearMap.ker f := ⟨hx, h'x⟩ rw [h] at this - simpa using this + simpa [mk_eq_zero] using this @[simp] theorem injective_restrict_iff_disjoint {p : Submodule R M} {f : M →ₗ[R] M} (hf : ∀ x ∈ p, f x ∈ p) : 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/Map.lean b/Mathlib/Algebra/Module/Submodule/Map.lean index e6d75f1363cf8..0e08a969e1c07 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,14 +191,15 @@ 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 theorem le_comap_pow_of_le_comap (p : Submodule R M) {f : M →ₗ[R] M} (h : p ≤ p.comap f) (k : ℕ) : p ≤ p.comap (f ^ k) := by - induction' k with k ih - · simp [LinearMap.one_eq_id] - · simp [LinearMap.iterate_succ, comap_comp, h.trans (comap_mono ih)] + induction k with + | zero => simp [LinearMap.one_eq_id] + | succ k ih => simp [LinearMap.iterate_succ, comap_comp, h.trans (comap_mono ih)] section @@ -409,6 +415,10 @@ lemma comap_neg {f : M →ₗ[R] M₂} {p : Submodule R M₂} : p.comap (-f) = p.comap f := by ext; simp +lemma map_toAddSubgroup (f : M →ₗ[R] M₂) (p : Submodule R M) : + (p.map f).toAddSubgroup = p.toAddSubgroup.map (f : M →+ M₂) := + rfl + end AddCommGroup end Submodule @@ -620,7 +630,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 99e50eaa44e68..c8d8a18665f39 100644 --- a/Mathlib/Algebra/Module/Submodule/Pointwise.lean +++ b/Mathlib/Algebra/Module/Submodule/Pointwise.lean @@ -416,12 +416,10 @@ lemma set_smul_eq_map [SMulCommClass R R N] : apply set_smul_eq_of_le · intro r n hr hn exact ⟨Finsupp.single r ⟨n, hn⟩, Finsupp.single_mem_supported _ _ hr, by simp⟩ - · intro x hx obtain ⟨c, hc, rfl⟩ := hx - simp only [LinearMap.coe_comp, coeSubtype, Finsupp.coe_lsum, Finsupp.sum, LinearMap.coe_mk, - AddHom.coe_mk, Function.comp_apply, AddSubmonoid.coe_finset_sum, coe_toAddSubmonoid, - SetLike.val_smul] + 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 rw [mem_set_smul_def, Submodule.mem_sInf] @@ -442,10 +440,9 @@ lemma mem_set_smul (x : M) [SMulCommClass R R N] : rw [set_smul_eq_map] at h obtain ⟨c, hc, rfl⟩ := h exact ⟨c, hc, rfl⟩ - · rw [mem_set_smul_def, Submodule.mem_sInf] rintro ⟨c, hc1, rfl⟩ p hp - simp only [Finsupp.sum, AddSubmonoid.coe_finset_sum, coe_toAddSubmonoid, SetLike.val_smul] + rw [Finsupp.sum, AddSubmonoid.coe_finset_sum] exact Submodule.sum_mem _ fun r hr ↦ hp (hc1 hr) (c _).2 @[simp] lemma empty_set_smul : (∅ : Set S) • N = ⊥ := by @@ -496,8 +493,8 @@ protected def pointwiseSetMulAction [SMulCommClass R R M] : (set_smul_le _ _ _ fun r m hr hm ↦ by have : SMulCommClass R R x := ⟨fun r s m => Subtype.ext <| smul_comm _ _ _⟩ obtain ⟨c, hc1, rfl⟩ := mem_set_smul _ _ _ |>.mp hm - simp only [Finsupp.sum, AddSubmonoid.coe_finset_sum, coe_toAddSubmonoid, SetLike.val_smul, - Finset.smul_sum, smul_smul] + rw [Finsupp.sum, AddSubmonoid.coe_finset_sum] + simp only [SetLike.val_smul, Finset.smul_sum, smul_smul] exact Submodule.sum_mem _ fun r' hr' ↦ mem_set_smul_of_mem_mem (Set.mul_mem_mul hr (hc1 hr')) (c _).2) @@ -533,11 +530,12 @@ 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 r h _ _ _ _ ihr ihs r r' hr hr' - · exact mem_set_smul_of_mem_mem h hn - · rw [zero_smul]; exact Submodule.zero_mem _ - · rw [add_smul]; exact Submodule.add_mem _ ihr ihs - · rw [mem_span_set] at hr + induction hr using Submodule.span_induction' with + | mem _ h => exact mem_set_smul_of_mem_mem h hn + | zero => rw [zero_smul]; exact Submodule.zero_mem _ + | add _ _ _ _ ihr ihs => rw [add_smul]; exact Submodule.add_mem _ ihr ihs + | smul _ _ hr => + rw [mem_span_set] at hr obtain ⟨c, hc, rfl⟩ := hr rw [Finsupp.sum, Finset.smul_sum, Finset.sum_smul] refine Submodule.sum_mem _ fun i hi => ?_ diff --git a/Mathlib/Algebra/Module/Torsion.lean b/Mathlib/Algebra/Module/Torsion.lean index 4fe308cff7cb6..5be854af327cb 100644 --- a/Mathlib/Algebra/Module/Torsion.lean +++ b/Mathlib/Algebra/Module/Torsion.lean @@ -4,12 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Pierre-Alexandre Bazin -/ import Mathlib.Algebra.DirectSum.Module -import Mathlib.Algebra.Module.BigOperators -import Mathlib.LinearAlgebra.Isomorphisms +import Mathlib.Algebra.Module.ZMod import Mathlib.GroupTheory.Torsion +import Mathlib.LinearAlgebra.Isomorphisms import Mathlib.RingTheory.Coprime.Ideal -import Mathlib.RingTheory.Finiteness -import Mathlib.Data.Set.Lattice /-! # Torsion submodules @@ -363,9 +361,7 @@ theorem iSup_torsionBySet_ideal_eq_torsionBySet_iInf (hp : (S : Set ι).Pairwise fun i j => p i ⊔ p j = ⊤) : ⨆ i ∈ S, torsionBySet R M (p i) = torsionBySet R M ↑(⨅ i ∈ S, p i) := by rcases S.eq_empty_or_nonempty with h | h - · simp only [h] - -- Porting note: converts were not cooperating - convert iSup_emptyset (f := fun i => torsionBySet R M (p i)) <;> simp + · simp [h] apply le_antisymm · apply iSup_le _ intro i @@ -861,6 +857,46 @@ theorem isTorsion_iff_isTorsion_int [AddCommGroup M] : end AddMonoid +namespace AddSubgroup + +variable (A : Type*) [AddCommGroup A] (n : ℤ) + +/-- The additive `n`-torsion subgroup for an integer `n`. -/ +@[reducible] +def torsionBy : AddSubgroup A := + (Submodule.torsionBy ℤ A n).toAddSubgroup + +@[inherit_doc] +scoped notation:max (priority := high) A"["n"]" => torsionBy A n + +lemma torsionBy.neg : A[-n] = A[n] := by + ext a + simp + +variable {A} {n : ℕ} + +@[simp] +lemma torsionBy.nsmul (x : A[n]) : n • x = 0 := + Nat.cast_smul_eq_nsmul ℤ n x ▸ Submodule.smul_torsionBy .. + +lemma torsionBy.nsmul_iff {x : A} : + x ∈ A[n] ↔ n • x = 0 := + Nat.cast_smul_eq_nsmul ℤ n x ▸ Submodule.mem_torsionBy_iff .. + +lemma torsionBy.mod_self_nsmul (s : ℕ) (x : A[n]) : + s • x = (s % n) • x := + nsmul_eq_mod_nsmul s (torsionBy.nsmul x) + +lemma torsionBy.mod_self_nsmul' (s : ℕ) {x : A} (h : x ∈ A[n]) : + s • x = (s % n) • x := + nsmul_eq_mod_nsmul s (torsionBy.nsmul_iff.mp h) + +/-- For a natural number `n`, the `n`-torsion subgroup of `A` is a `ZMod n` module. -/ +def torsionBy.zmodModule : Module (ZMod n) A[n] := + AddCommGroup.zmodModule torsionBy.nsmul + +end AddSubgroup + section InfiniteRange @[simp] 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 similarity index 76% rename from Mathlib/Algebra/Module/Zlattice/Basic.lean rename to Mathlib/Algebra/Module/ZLattice/Basic.lean index c26f3cf544512..a436852b2ab88 100644 --- a/Mathlib/Algebra/Module/Zlattice/Basic.lean +++ b/Mathlib/Algebra/Module/ZLattice/Basic.lean @@ -17,27 +17,34 @@ 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. +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 -* `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 +* `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`: 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` + +## 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. + -/ noncomputable section -namespace Zspan +namespace ZSpan open MeasureTheory MeasurableSet Submodule Bornology @@ -51,7 +58,7 @@ variable (b : Basis ι K E) theorem span_top : span K (span ℤ (Set.range b) : Set E) = ⊤ := by simp [span_span_of_tower] -/-- The fundamental domain of the ℤ-lattice spanned by `b`. See `Zspan.isAddFundamentalDomain` +/-- 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} @@ -123,7 +130,7 @@ theorem ceil_eq_self_of_mem (m : E) (h : m ∈ span ℤ (Set.range b)) : (ceil b exact congr_arg (Int.cast : ℤ → K) (Int.ceil_intCast z) /-- The map that sends a vector `E` to the `fundamentalDomain` of the lattice, -see `Zspan.fract_mem_fundamentalDomain`, and `fractRestrict` for the map with the codomain +see `ZSpan.fract_mem_fundamentalDomain`, and `fractRestrict` for the map with the codomain restricted to `fundamentalDomain`. -/ def fract (m : E) : E := m - floor b m @@ -138,7 +145,7 @@ theorem fract_fract (m : E) : fract b (fract b m) = fract b m := Basis.ext_elem b fun _ => by classical simp only [repr_fract_apply, Int.fract_fract] @[simp] -theorem fract_zspan_add (m : E) {v : E} (h : v ∈ span ℤ (Set.range b)) : +theorem fract_zSpan_add (m : E) {v : E} (h : v ∈ span ℤ (Set.range b)) : fract b (v + m) = fract b m := by classical refine (Basis.ext_elem_iff b).mpr fun i => ?_ @@ -148,8 +155,8 @@ theorem fract_zspan_add (m : E) {v : E} (h : v ∈ span ℤ (Set.range b)) : ← eq_intCast (algebraMap ℤ K) _, Basis.restrictScalars_repr_apply, coe_mk] @[simp] -theorem fract_add_zspan (m : E) {v : E} (h : v ∈ span ℤ (Set.range b)) : - fract b (m + v) = fract b m := by rw [add_comm, fract_zspan_add b m h] +theorem fract_add_ZSpan (m : E) {v : E} (h : v ∈ span ℤ (Set.range b)) : + fract b (m + v) = fract b m := by rw [add_comm, fract_zSpan_add b m h] variable {b} @@ -200,11 +207,13 @@ variable [Unique ι] @[simp] theorem coe_floor_self (k : K) : (floor (Basis.singleton ι K) k : K) = ⌊k⌋ := - Basis.ext_elem _ fun _ => by rw [repr_floor_apply, Basis.singleton_repr, Basis.singleton_repr] + Basis.ext_elem (Basis.singleton ι K) fun _ => by + rw [repr_floor_apply, Basis.singleton_repr, Basis.singleton_repr] @[simp] theorem coe_fract_self (k : K) : (fract (Basis.singleton ι K) k : K) = Int.fract k := - Basis.ext_elem _ fun _ => by rw [repr_fract_apply, Basis.singleton_repr, Basis.singleton_repr] + Basis.ext_elem (Basis.singleton ι K) fun _ => by + rw [repr_fract_apply, Basis.singleton_repr, Basis.singleton_repr] end Unique @@ -220,7 +229,7 @@ theorem fundamentalDomain_isBounded [Finite ι] [HasSolidNorm K] : theorem vadd_mem_fundamentalDomain [Fintype ι] (y : span ℤ (Set.range b)) (x : E) : y +ᵥ x ∈ fundamentalDomain b ↔ y = -floor b x := by rw [Subtype.ext_iff, ← add_right_inj x, NegMemClass.coe_neg, ← sub_eq_add_neg, ← fract_apply, - ← fract_zspan_add b _ (Subtype.mem y), add_comm, ← vadd_eq_add, ← vadd_def, eq_comm, ← + ← fract_zSpan_add b _ (Subtype.mem y), add_comm, ← vadd_eq_add, ← vadd_def, eq_comm, ← fract_eq_self] theorem exist_unique_vadd_mem_fundamentalDomain [Finite ι] (x : E) : @@ -230,8 +239,8 @@ theorem exist_unique_vadd_mem_fundamentalDomain [Finite ι] (x : E) : · exact (vadd_mem_fundamentalDomain b (-floor b x) x).mpr rfl · exact (vadd_mem_fundamentalDomain b y x).mp h -/-- The map `Zspan.fractRestrict` defines an equiv map between `E ⧸ span ℤ (Set.range b)` -and `Zspan.fundamentalDomain b`. -/ +/-- The map `ZSpan.fractRestrict` defines an equiv map between `E ⧸ span ℤ (Set.range b)` +and `ZSpan.fundamentalDomain b`. -/ def quotientEquiv [Fintype ι] : E ⧸ span ℤ (Set.range b) ≃ (fundamentalDomain b) := by refine Equiv.ofBijective ?_ ⟨fun x y => ?_, fun x => ?_⟩ @@ -305,20 +314,25 @@ theorem fundamentalDomain_measurableSet [MeasurableSpace E] [OpensMeasurableSpac Set.mem_preimage, Basis.equivFun_apply, Set.mem_pi, Set.mem_univ, forall_true_left] /-- For a ℤ-lattice `Submodule.span ℤ (Set.range b)`, proves that the set defined -by `Zspan.fundamentalDomain` is a fundamental domain. -/ +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 + convert (ZSpan.isAddFundamentalDomain b μ).measure_ne_zero (NeZero.ne μ) + 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) : @@ -366,31 +380,30 @@ theorem fundamentalDomain_ae_parallelepiped [Fintype ι] [MeasurableSpace E] (μ end Real -end Zspan +end ZSpan -section Zlattice +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 +class IsZLattice (K : Type*) [NormedField K] {E : Type*} [NormedAddCommGroup E] [NormedSpace K E] + (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] +theorem _root_.ZSpan.isZLattice {E ι : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [Finite ι] (b : Basis ι ℝ E) : - IsZlattice ℝ (span ℤ (Set.range b)).toAddSubgroup where - span_top := Zspan.span_top b + IsZLattice ℝ (span ℤ (Set.range b)) where + span_top := ZSpan.span_top b 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 @@ -399,75 +412,68 @@ 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 rw [ker_mkQ, inf_of_le_right (span_le.mpr h_incl)] 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)) +theorem ZLattice.module_finite [IsZLattice K L] : Module.Finite ℤ 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 +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 +theorem ZLattice.rank [hs : IsZLattice K L] : finrank ℤ L = finrank K E := by classical have : Module.Finite ℤ L := module_finite K L have : Module.Free ℤ L := module_free K L @@ -476,10 +482,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 @@ -523,26 +529,27 @@ theorem Zlattice.rank [hs : IsZlattice K L] : finrank ℤ L = finrank K E := by linearIndependent_insert (Set.not_mem_of_mem_diff hv), not_and, not_not] intro _ -- 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)` + -- 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` @@ -551,55 +558,53 @@ theorem Zlattice.rank [hs : IsZlattice K L] : finrank ℤ L = finrank K E := by open Module -variable {ι : Type*} [hs : IsZlattice K L] (b : Basis ι ℤ L) +variable {ι : Type*} [hs : IsZLattice K L] (b : Basis ι ℤ L) /-- Any `ℤ`-basis of `L` is also a `K`-basis of `E`. -/ -def Basis.ofZlatticeBasis : +def Basis.ofZLatticeBasis : Basis ι K E := by - have : Finite ℤ L := Zlattice.module_finite K L - have : Free ℤ L := Zlattice.module_free 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] - · rw [← Fintype.card_congr e, ← finrank_eq_card_chooseBasisIndex, Zlattice.rank K L] + 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] +theorem Basis.ofZLatticeBasis_apply (i : ι) : + 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 +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 = 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] - -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] + 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))) = 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] -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 - convert Zspan.isAddFundamentalDomain (b.ofZlatticeBasis ℝ) μ - all_goals exact (b.ofZlatticeBasis_span ℝ).symm +open MeasureTheory in +theorem ZLattice.isAddFundamentalDomain {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] + [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 Zlattice +end ZLattice diff --git a/Mathlib/Algebra/Module/Zlattice/Covolume.lean b/Mathlib/Algebra/Module/ZLattice/Covolume.lean similarity index 60% rename from Mathlib/Algebra/Module/Zlattice/Covolume.lean rename to Mathlib/Algebra/Module/ZLattice/Covolume.lean index 8a3b7297b4d77..04e559d80a384 100644 --- a/Mathlib/Algebra/Module/Zlattice/Covolume.lean +++ b/Mathlib/Algebra/Module/ZLattice/Covolume.lean @@ -3,43 +3,43 @@ Copyright (c) 2024 Xavier Roblot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Xavier Roblot -/ -import Mathlib.Algebra.Module.Zlattice.Basic +import Mathlib.Algebra.Module.ZLattice.Basic /-! # Covolume of ℤ-lattices Let `E` be a finite dimensional real vector space with an inner product. -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 -* `Zlattice.covolume`: the covolume of `L` defined as the volume of an arbitrary fundamental +* `ZLattice.covolume`: the covolume of `L` defined as the volume of an arbitrary fundamental domain of `L`. -* `Zlattice.covolume_eq_measure_fundamentalDomain`: the covolume of `L` does not depend on the +* `ZLattice.covolume_eq_measure_fundamentalDomain`: the covolume of `L` does not depend on the choice of the fundamental domain of `L`. -* `Zlattice.covolume_eq_det`: if `L` is a lattice in `ℝ^n`, then its covolume is the absolute +* `ZLattice.covolume_eq_det`: if `L` is a lattice in `ℝ^n`, then its covolume is the absolute value of the determinant of any `ℤ`-basis of `L`. -/ noncomputable section -namespace Zlattice +namespace ZLattice -open Submodule MeasureTheory FiniteDimensional MeasureTheory Module +open Submodule MeasureTheory Module MeasureTheory Module 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 (L : Submodule ℤ E) [DiscreteTopology L] [IsZLattice K L] /-- 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 +`ZLattice.covolume_eq_volume` for the proof that the volume does not depend on the choice of the fundamental domain. -/ def covolume (μ : Measure E := by volume_tac) : ℝ := (addCovolume L E μ).toReal @@ -49,41 +49,44 @@ 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 ⟨ZSpan.measure_fundamentalDomain_ne_zero _, ne_of_lt ?_⟩ + exact Bornology.IsBounded.measure_lt_top (ZSpan.fundamentalDomain_isBounded _) theorem covolume_pos : 0 < covolume L μ := lt_of_le_of_ne ENNReal.toReal_nonneg (covolume_ne_zero L μ).symm 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)| * (μ (ZSpan.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, + ZSpan.measure_fundamentalDomain _ _ b₀, + measure_congr (ZSpan.fundamentalDomain_ae_parallelepiped b₀ μ), ENNReal.toReal_mul, ENNReal.toReal_ofReal (by positivity)] congr ext - exact b.ofZlatticeBasis_apply ℝ L _ + exact b.ofZLatticeBasis_apply ℝ L _ -theorem covolume_eq_det {ι : Type*} [Fintype ι] [DecidableEq ι] (L : AddSubgroup (ι → ℝ)) - [DiscreteTopology L] [IsZlattice ℝ L] (b : Basis ι ℤ L) : +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)] + ZSpan.volume_fundamentalDomain, ENNReal.toReal_ofReal (by positivity)] congr ext1 - exact b.ofZlatticeBasis_apply ℝ L _ + exact b.ofZLatticeBasis_apply ℝ L _ end Real -end Zlattice +end ZLattice 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 4022f37abb36e..c859345b543ca 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 @@ -656,7 +78,7 @@ def liftMagma [Module k A] [IsScalarTower k A A] [SMulCommClass k A A] : intros rw [← add_smul] -- Porting note: `reducible` cannot be `local` so proof gets long. - simp_rw [Finsupp.mul_sum, Finsupp.sum_mul, smul_mul_smul, ← f.map_mul, mul_def, + simp_rw [Finsupp.mul_sum, Finsupp.sum_mul, smul_mul_smul_comm, ← f.map_mul, mul_def, sum_comm a₂ a₁] rw [sum_sum_index h₁ h₂]; congr; ext rw [sum_sum_index h₁ h₂]; congr; ext @@ -678,57 +100,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)`. @@ -769,15 +142,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 +339,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 +383,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]`. @@ -1867,21 +501,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) : diff --git a/Mathlib/Algebra/MonoidAlgebra/Defs.lean b/Mathlib/Algebra/MonoidAlgebra/Defs.lean new file mode 100644 index 0000000000000..a2574ffe76219 --- /dev/null +++ b/Mathlib/Algebra/MonoidAlgebra/Defs.lean @@ -0,0 +1,1442 @@ +/- +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 := + 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; 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 + +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).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 -/ + + +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]⟩ + +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 + -- 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) + +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] + +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; 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 + +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 _ _ _ _ + +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 + -- 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 + +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 diff --git a/Mathlib/Algebra/MonoidAlgebra/Degree.lean b/Mathlib/Algebra/MonoidAlgebra/Degree.lean index b5fb1511da9ed..4546eb21d1d13 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Degree.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Degree.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa -/ import Mathlib.Algebra.MonoidAlgebra.Support +import Mathlib.Order.Filter.Extr /-! # Lemmas about the `sup` and `inf` of the support of `AddMonoidAlgebra` @@ -213,7 +214,14 @@ For an element `f : R[A]`, the element `supDegree f : B` is the supremum of all support of `f`, or `⊥` if `f` is zero. Often, the Type `B` is `WithBot A`, If, further, `A` has a linear order, then this notion coincides with the usual one, -using the maximum of the exponents. -/ +using the maximum of the exponents. + +If `A := σ →₀ ℕ` then `R[A] = MvPolynomial σ R`, and if we equip `σ` with a linear order then +the induced linear order on `Lex A` equips `MvPolynomial` ring with a +[monomial order](https://en.wikipedia.org/wiki/Monomial_order) (i.e. a linear order on `A`, the +type of (monic) monomials in `R[A]`, that respects addition). We make use of this monomial order +by taking `D := toLex`, and different monomial orders could be accessed via different type +synonyms once they are added. -/ abbrev supDegree (f : R[A]) : B := f.support.sup D @@ -256,6 +264,10 @@ theorem supDegree_withBot_some_comp {s : AddMonoidAlgebra R A} (hs : s.support.N unfold AddMonoidAlgebra.supDegree rw [← Finset.coe_sup' hs, Finset.sup'_eq_sup] +theorem supDegree_eq_of_isMaxOn {p : R[A]} {a : A} (hmem : a ∈ p.support) + (hmax : IsMaxOn D p.support a) : p.supDegree D = D a := + sup_eq_of_isMaxOn hmem hmax + variable [AddZeroClass A] {p q : R[A]} @[simp] @@ -266,6 +278,10 @@ theorem ne_zero_of_supDegree_ne_bot : p.supDegree D ≠ ⊥ → p ≠ 0 := mt (f theorem ne_zero_of_not_supDegree_le {b : B} (h : ¬ p.supDegree D ≤ b) : p ≠ 0 := ne_zero_of_supDegree_ne_bot (fun he => h <| he ▸ bot_le) +theorem supDegree_eq_of_max {b : B} (hb : b ∈ Set.range D) (hmem : D.invFun b ∈ p.support) + (hmax : ∀ a ∈ p.support, D a ≤ b) : p.supDegree D = b := + sup_eq_of_max hb hmem hmax + variable [Add B] theorem supDegree_mul_le (hadd : ∀ a1 a2, D (a1 + a2) = D a1 + D a2) @@ -309,6 +325,249 @@ theorem apply_add_of_supDegree_le (hadd : ∀ a1 a2, D (a1 + a2) = D a1 + D a2) end SupDegree +section LinearOrder + +variable [LinearOrder B] [OrderBot B] {p q : R[A]} (D : A → B) + +/-- If `D` is an injection into a linear order `B`, the leading coefficient of `f : R[A]` is the + nonzero coefficient of highest degree according to `D`, or 0 if `f = 0`. In general, it is defined + to be the coefficient at an inverse image of `supDegree f` (if such exists). -/ +noncomputable def leadingCoeff [Nonempty A] (f : R[A]) : R := + f (D.invFun <| f.supDegree D) + +/-- An element `f : R[A]` is monic if its leading coefficient is one. -/ +@[reducible] def Monic [Nonempty A] (f : R[A]) : Prop := + f.leadingCoeff D = 1 + +variable {D} + +@[simp] +theorem leadingCoeff_single [Nonempty A] (hD : D.Injective) (a : A) (r : R) : + (single a r).leadingCoeff D = r := by + classical + rw [leadingCoeff, supDegree_single] + split_ifs with hr + · simp [hr] + · rw [Function.leftInverse_invFun hD, single_apply, if_pos rfl] + +@[simp] +theorem leadingCoeff_zero [Nonempty A] : (0 : R[A]).leadingCoeff D = 0 := rfl + +lemma Monic.ne_zero [Nonempty A] [Nontrivial R] (hp : p.Monic D) : p ≠ 0 := fun h => by + simp_rw [Monic, h, leadingCoeff_zero, zero_ne_one] at hp + +@[simp] +theorem monic_one [AddZeroClass A] (hD : D.Injective) : (1 : R[A]).Monic D := by + rw [Monic, one_def, leadingCoeff_single hD] + +variable (D) in +lemma exists_supDegree_mem_support (hp : p ≠ 0) : ∃ a ∈ p.support, p.supDegree D = D a := + Finset.exists_mem_eq_sup _ (Finsupp.support_nonempty_iff.mpr hp) D + +variable (D) in +lemma supDegree_mem_range (hp : p ≠ 0) : p.supDegree D ∈ Set.range D := by + obtain ⟨a, -, he⟩ := exists_supDegree_mem_support D hp; exact ⟨a, he.symm⟩ + +variable {ι : Type*} {s : Finset ι} {i : ι} (hi : i ∈ s) {f : ι → R[A]} + +lemma supDegree_sum_lt (hs : s.Nonempty) {b : B} + (h : ∀ i ∈ s, (f i).supDegree D < b) : (∑ i ∈ s, f i).supDegree D < b := by + refine supDegree_sum_le.trans_lt ((Finset.sup_lt_iff ?_).mpr h) + obtain ⟨i, hi⟩ := hs; exact bot_le.trans_lt (h i hi) + +variable [AddZeroClass A] + +open Finsupp in +lemma supDegree_add_eq_left (h : q.supDegree D < p.supDegree D) : + (p + q).supDegree D = p.supDegree D := by + apply (supDegree_add_le.trans <| sup_le le_rfl h.le).antisymm + obtain ⟨a, ha, he⟩ := exists_supDegree_mem_support D (ne_zero_of_not_supDegree_le h.not_le) + rw [he] at h ⊢ + apply Finset.le_sup + rw [mem_support_iff, add_apply, apply_eq_zero_of_not_le_supDegree h.not_le, add_zero] + exact mem_support_iff.mp ha + +lemma supDegree_add_eq_right (h : p.supDegree D < q.supDegree D) : + (p + q).supDegree D = q.supDegree D := by + rw [add_comm, supDegree_add_eq_left h] + +lemma leadingCoeff_add_eq_left (h : q.supDegree D < p.supDegree D) : + (p + q).leadingCoeff D = p.leadingCoeff D := by + obtain ⟨a, he⟩ := supDegree_mem_range D (ne_zero_of_not_supDegree_le h.not_le) + rw [leadingCoeff, supDegree_add_eq_left h, Finsupp.add_apply, ← leadingCoeff, + apply_eq_zero_of_not_le_supDegree (D := D), add_zero] + rw [← he, Function.apply_invFun_apply (f := D), he]; exact h.not_le + +lemma leadingCoeff_add_eq_right (h : p.supDegree D < q.supDegree D) : + (p + q).leadingCoeff D = q.leadingCoeff D := by + rw [add_comm, leadingCoeff_add_eq_left h] + +lemma supDegree_mem_support (hD : D.Injective) (hp : p ≠ 0) : + D.invFun (p.supDegree D) ∈ p.support := by + obtain ⟨a, ha, he⟩ := exists_supDegree_mem_support D hp + rwa [he, Function.leftInverse_invFun hD] + +@[simp] +lemma leadingCoeff_eq_zero (hD : D.Injective) : p.leadingCoeff D = 0 ↔ p = 0 := by + refine ⟨(fun h => ?_).mtr, fun h => h ▸ leadingCoeff_zero⟩ + rw [leadingCoeff, ← Ne, ← Finsupp.mem_support_iff] + exact supDegree_mem_support hD h + +lemma supDegree_sub_lt_of_leadingCoeff_eq (hD : D.Injective) {R} [CommRing R] {p q : R[A]} + (hd : p.supDegree D = q.supDegree D) (hc : p.leadingCoeff D = q.leadingCoeff D) : + (p - q).supDegree D < p.supDegree D ∨ p = q := by + rw [or_iff_not_imp_right] + refine fun he => (supDegree_sub_le.trans ?_).lt_of_ne ?_ + · rw [hd, sup_idem] + · rw [← sub_eq_zero, ← leadingCoeff_eq_zero hD, leadingCoeff] at he + refine fun h => he ?_ + rwa [h, Finsupp.sub_apply, ← leadingCoeff, hd, ← leadingCoeff, sub_eq_zero] + +lemma supDegree_leadingCoeff_sum_eq + (hi : i ∈ s) (hmax : ∀ j ∈ s, j ≠ i → (f j).supDegree D < (f i).supDegree D) : + (∑ j ∈ s, f j).supDegree D = (f i).supDegree D ∧ + (∑ j ∈ s, f j).leadingCoeff D = (f i).leadingCoeff D := by + classical + rw [← s.add_sum_erase _ hi] + by_cases hs : s.erase i = ∅ + · rw [hs, Finset.sum_empty, add_zero]; exact ⟨rfl, rfl⟩ + suffices _ from ⟨supDegree_add_eq_left this, leadingCoeff_add_eq_left this⟩ + refine supDegree_sum_lt ?_ (fun j hj => ?_) + · rw [Finset.nonempty_iff_ne_empty]; exact hs + · rw [Finset.mem_erase] at hj; exact hmax j hj.2 hj.1 + +open Finset in +lemma sum_ne_zero_of_injOn_supDegree' (hs : ∃ i ∈ s, f i ≠ 0) + (hd : (s : Set ι).InjOn (supDegree D ∘ f)) : + ∑ i ∈ s, f i ≠ 0 := by + obtain ⟨j, hj, hne⟩ := hs + obtain ⟨i, hi, he⟩ := exists_mem_eq_sup _ ⟨j, hj⟩ (supDegree D ∘ f) + by_cases h : ∀ k ∈ s, k = i + · refine (sum_eq_single_of_mem j hj (fun k hk hne => ?_)).trans_ne hne + rw [h k hk, h j hj] at hne; exact hne.irrefl.elim + push_neg at h; obtain ⟨j, hj, hne⟩ := h + apply ne_zero_of_supDegree_ne_bot (D := D) + have (k) (hk : k ∈ s) (hne : k ≠ i) : supDegree D (f k) < supDegree D (f i) := + ((le_sup hk).trans_eq he).lt_of_ne (hd.ne hk hi hne) + rw [(supDegree_leadingCoeff_sum_eq hi this).1] + exact (this j hj hne).ne_bot + +lemma sum_ne_zero_of_injOn_supDegree (hs : s ≠ ∅) + (hf : ∀ i ∈ s, f i ≠ 0) (hd : (s : Set ι).InjOn (supDegree D ∘ f)) : + ∑ i ∈ s, f i ≠ 0 := + let ⟨i, hi⟩ := Finset.nonempty_iff_ne_empty.2 hs + sum_ne_zero_of_injOn_supDegree' ⟨i, hi, hf i hi⟩ hd + +variable [Add B] +variable [CovariantClass B B (· + ·) (· < ·)] [CovariantClass B B (Function.swap (· + ·)) (· < ·)] + +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 + obtain rfl | hp := eq_or_ne p 0 + · simp_rw [leadingCoeff_zero, zero_mul, Finsupp.coe_zero, Pi.zero_apply] + obtain rfl | hq := eq_or_ne q 0 + · simp_rw [leadingCoeff_zero, mul_zero, Finsupp.coe_zero, Pi.zero_apply] + obtain ⟨ap, -, hp⟩ := exists_supDegree_mem_support D hp + obtain ⟨aq, -, hq⟩ := exists_supDegree_mem_support D hq + simp_rw [leadingCoeff, hp, hq, ← hadd, Function.leftInverse_invFun hD _] + exact apply_add_of_supDegree_le hadd hD hp.le hq.le + +lemma supDegree_mul + (hD : D.Injective) (hadd : ∀ a1 a2, D (a1 + a2) = D a1 + D a2) + (hpq : leadingCoeff D p * leadingCoeff D q ≠ 0) + (hp : p ≠ 0) (hq : q ≠ 0) : + (p * q).supDegree D = p.supDegree D + q.supDegree D := by + cases subsingleton_or_nontrivial R; · exact (hp (Subsingleton.elim _ _)).elim + apply supDegree_eq_of_max + · rw [← AddSubsemigroup.coe_set_mk (Set.range D), ← AddHom.srange_mk _ hadd, SetLike.mem_coe] + exact add_mem (supDegree_mem_range D hp) (supDegree_mem_range D hq) + · simp_rw [Finsupp.mem_support_iff, apply_supDegree_add_supDegree hD hadd] + exact hpq + · have := covariantClass_le_of_lt B B (· + ·) + have := covariantClass_le_of_lt B B (Function.swap (· + ·)) + exact fun a ha => (Finset.le_sup ha).trans (supDegree_mul_le hadd) + +lemma Monic.supDegree_mul_of_ne_zero_left + (hD : D.Injective) (hadd : ∀ a1 a2, D (a1 + a2) = D a1 + D a2) + (hq : q.Monic D) (hp : p ≠ 0) : + (p * q).supDegree D = p.supDegree D + q.supDegree D := by + cases subsingleton_or_nontrivial R; · exact (hp (Subsingleton.elim _ _)).elim + apply supDegree_mul hD hadd ?_ hp hq.ne_zero + simp_rw [hq, mul_one, Ne, leadingCoeff_eq_zero hD, hp, not_false_eq_true] + +lemma Monic.supDegree_mul_of_ne_zero_right + (hD : D.Injective) (hadd : ∀ a1 a2, D (a1 + a2) = D a1 + D a2) + (hp : p.Monic D) (hq : q ≠ 0) : + (p * q).supDegree D = p.supDegree D + q.supDegree D := by + cases subsingleton_or_nontrivial R; · exact (hq (Subsingleton.elim _ _)).elim + apply supDegree_mul hD hadd ?_ hp.ne_zero hq + simp_rw [hp, one_mul, Ne, leadingCoeff_eq_zero hD, hq, not_false_eq_true] + +lemma Monic.supDegree_mul + (hD : D.Injective) (hadd : ∀ a1 a2, D (a1 + a2) = D a1 + D a2) + (hbot : (⊥ : B) + ⊥ = ⊥) (hp : p.Monic D) (hq : q.Monic D) : + (p * q).supDegree D = p.supDegree D + q.supDegree D := by + cases subsingleton_or_nontrivial R + · simp_rw [Subsingleton.eq_zero p, Subsingleton.eq_zero q, mul_zero, supDegree_zero, hbot] + exact hq.supDegree_mul_of_ne_zero_left hD hadd hp.ne_zero + +lemma leadingCoeff_mul [NoZeroDivisors R] + (hD : D.Injective) (hadd : ∀ a1 a2, D (a1 + a2) = D a1 + D a2) : + (p * q).leadingCoeff D = p.leadingCoeff D * q.leadingCoeff D := by + obtain rfl | hp := eq_or_ne p 0 + · simp_rw [leadingCoeff_zero, zero_mul, leadingCoeff_zero] + obtain rfl | hq := eq_or_ne q 0 + · simp_rw [leadingCoeff_zero, mul_zero, leadingCoeff_zero] + rw [← apply_supDegree_add_supDegree hD hadd, ← supDegree_mul hD hadd ?_ hp hq, leadingCoeff] + apply mul_ne_zero <;> rwa [Ne, leadingCoeff_eq_zero hD] + +lemma Monic.leadingCoeff_mul_eq_left + (hD : D.Injective) (hadd : ∀ a1 a2, D (a1 + a2) = D a1 + D a2) (hq : q.Monic D) : + (p * q).leadingCoeff D = p.leadingCoeff D := by + obtain rfl | hp := eq_or_ne p 0 + · rw [zero_mul] + rw [leadingCoeff, hq.supDegree_mul_of_ne_zero_left hD hadd hp, + apply_supDegree_add_supDegree hD hadd, hq, mul_one] + +lemma Monic.leadingCoeff_mul_eq_right + (hD : D.Injective) (hadd : ∀ a1 a2, D (a1 + a2) = D a1 + D a2) (hp : p.Monic D) : + (p * q).leadingCoeff D = q.leadingCoeff D := by + obtain rfl | hq := eq_or_ne q 0 + · rw [mul_zero] + rw [leadingCoeff, hp.supDegree_mul_of_ne_zero_right hD hadd hq, + apply_supDegree_add_supDegree hD hadd, hp, one_mul] + +lemma Monic.mul + (hD : D.Injective) (hadd : ∀ a1 a2, D (a1 + a2) = D a1 + D a2) + (hp : p.Monic D) (hq : q.Monic D) : (p * q).Monic D := by + rw [Monic, hq.leadingCoeff_mul_eq_left hD hadd]; exact hp + +section AddMonoid + +variable {A B : Type*} [AddMonoid A] [AddMonoid B] [LinearOrder B] [OrderBot B] + [CovariantClass B B (· + ·) (· < ·)] [CovariantClass B B (Function.swap (· + ·)) (· < ·)] + {D : A → B} {p : R[A]} {n : ℕ} + +lemma Monic.pow + (hadd : ∀ a1 a2, D (a1 + a2) = D a1 + D a2) (hD : D.Injective) + (hp : p.Monic D) : (p ^ n).Monic D := by + induction n with + | zero => rw [pow_zero]; exact monic_one hD + | succ n ih => rw [pow_succ']; exact hp.mul hD hadd ih + +lemma Monic.supDegree_pow + (hzero : D 0 = 0) (hadd : ∀ a1 a2, D (a1 + a2) = D a1 + D a2) (hD : D.Injective) + [Nontrivial R] (hp : p.Monic D) : + (p ^ n).supDegree D = n • p.supDegree D := by + induction n with + | zero => rw [pow_zero, zero_nsmul, one_def, supDegree_single 0 1, if_neg one_ne_zero, hzero] + | succ n ih => rw [pow_succ', (hp.pow hadd hD).supDegree_mul_of_ne_zero_left hD hadd hp.ne_zero, + ih, succ_nsmul'] + +end AddMonoid + +end LinearOrder + section InfDegree variable [SemilatticeInf T] [OrderTop T] (D : A → T) diff --git a/Mathlib/Algebra/MonoidAlgebra/Division.lean b/Mathlib/Algebra/MonoidAlgebra/Division.lean index b9e13bd2bac92..3eb1337dc2017 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 diff --git a/Mathlib/Algebra/MonoidAlgebra/Grading.lean b/Mathlib/Algebra/MonoidAlgebra/Grading.lean index 6c9381050ab49..e13d03a50b709 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` diff --git a/Mathlib/Algebra/MonoidAlgebra/Ideal.lean b/Mathlib/Algebra/MonoidAlgebra/Ideal.lean index 17cab16c6913a..65393744fc7ce 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 /-! # Lemmas about ideals of `MonoidAlgebra` and `AddMonoidAlgebra` diff --git a/Mathlib/Algebra/MonoidAlgebra/NoZeroDivisors.lean b/Mathlib/Algebra/MonoidAlgebra/NoZeroDivisors.lean index 3b849d0527597..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 +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 197cf5eb69847..aa57dcae344e6 100644 --- a/Mathlib/Algebra/MonoidAlgebra/ToDirectSum.lean +++ b/Mathlib/Algebra/MonoidAlgebra/ToDirectSum.lean @@ -8,7 +8,7 @@ import Mathlib.Algebra.MonoidAlgebra.Basic import Mathlib.Data.Finsupp.ToDFinsupp /-! -# Conversion between `AddMonoidAlgebra` and homogenous `DirectSum` +# Conversion between `AddMonoidAlgebra` and homogeneous `DirectSum` This module provides conversions between `AddMonoidAlgebra` and `DirectSum`. The latter is essentially a dependent version of the former. @@ -64,7 +64,7 @@ open DirectSum section Defs -/-- Interpret an `AddMonoidAlgebra` as a homogenous `DirectSum`. -/ +/-- Interpret an `AddMonoidAlgebra` as a homogeneous `DirectSum`. -/ def AddMonoidAlgebra.toDirectSum [Semiring M] (f : AddMonoidAlgebra M ι) : ⨁ _ : ι, M := Finsupp.toDFinsupp f @@ -79,7 +79,7 @@ theorem AddMonoidAlgebra.toDirectSum_single (i : ι) (m : M) : variable [∀ m : M, Decidable (m ≠ 0)] -/-- Interpret a homogenous `DirectSum` as an `AddMonoidAlgebra`. -/ +/-- Interpret a homogeneous `DirectSum` as an `AddMonoidAlgebra`. -/ def DirectSum.toAddMonoidAlgebra (f : ⨁ _ : ι, M) : AddMonoidAlgebra M ι := DFinsupp.toFinsupp f @@ -136,17 +136,21 @@ theorem toDirectSum_mul [DecidableEq ι] [AddMonoid ι] [Semiring M] (f g : AddM 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 @@ -191,7 +195,7 @@ def addMonoidAlgebraEquivDirectSum [DecidableEq ι] [Semiring M] [∀ m : M, Dec toFun := AddMonoidAlgebra.toDirectSum invFun := DirectSum.toAddMonoidAlgebra } -/-- The additive version of `AddMonoidAlgebra.addMonoidAlgebraEquivDirectSum`. -/ +/-- The additive version of `AddMonoidAlgebra.addMonoidAlgebraEquivDirectSum`. -/ @[simps (config := .asFn)] def addMonoidAlgebraAddEquivDirectSum [DecidableEq ι] [Semiring M] [∀ m : M, Decidable (m ≠ 0)] : AddMonoidAlgebra M ι ≃+ ⨁ _ : ι, M := @@ -200,7 +204,7 @@ def addMonoidAlgebraAddEquivDirectSum [DecidableEq ι] [Semiring M] [∀ m : M, invFun := DirectSum.toAddMonoidAlgebra map_add' := AddMonoidAlgebra.toDirectSum_add } -/-- The ring version of `AddMonoidAlgebra.addMonoidAlgebraEquivDirectSum`. -/ +/-- The ring version of `AddMonoidAlgebra.addMonoidAlgebraEquivDirectSum`. -/ @[simps (config := .asFn)] def addMonoidAlgebraRingEquivDirectSum [DecidableEq ι] [AddMonoid ι] [Semiring M] [∀ m : M, Decidable (m ≠ 0)] : AddMonoidAlgebra M ι ≃+* ⨁ _ : ι, M := diff --git a/Mathlib/Algebra/MvPolynomial/Basic.lean b/Mathlib/Algebra/MvPolynomial/Basic.lean index 90a2b3d0d0db8..722c1bdf7b69a 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 @@ -461,7 +462,7 @@ theorem linearMap_ext {M : Type*} [AddCommMonoid M] [Module R M] {f g : MvPolyno section Support -/-- The finite set of all `m : σ →₀ ℕ` such that `X^m` has a non-zero coefficient. -/ +/-- The finite set of all `m : σ →₀ ℕ` such that `X^m` has a non-zero coefficient. -/ def support (p : MvPolynomial σ R) : Finset (σ →₀ ℕ) := Finsupp.support p @@ -1356,6 +1357,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 @@ -1437,7 +1443,7 @@ variable (R) theorem _root_.Algebra.adjoin_range_eq_range_aeval : Algebra.adjoin R (Set.range f) = (MvPolynomial.aeval f).range := by simp only [← Algebra.map_top, ← MvPolynomial.adjoin_range_X, AlgHom.map_adjoin, ← Set.range_comp, - (· ∘ ·), MvPolynomial.aeval_X] + Function.comp_def, MvPolynomial.aeval_X] theorem _root_.Algebra.adjoin_eq_range (s : Set S₁) : Algebra.adjoin R s = (MvPolynomial.aeval ((↑) : s → S₁)).range := by @@ -1536,6 +1542,19 @@ 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 + +set_option linter.style.longFile 1700 diff --git a/Mathlib/Algebra/MvPolynomial/Degrees.lean b/Mathlib/Algebra/MvPolynomial/Degrees.lean index 388b7941515bf..93924cb3df6c2 100644 --- a/Mathlib/Algebra/MvPolynomial/Degrees.lean +++ b/Mathlib/Algebra/MvPolynomial/Degrees.lean @@ -435,7 +435,7 @@ theorem totalDegree_finset_sum {ι : Type*} (s : Finset ι) (f : ι → MvPolyno lemma totalDegree_finsetSum_le {ι : Type*} {s : Finset ι} {f : ι → MvPolynomial σ R} {d : ℕ} (hf : ∀ i ∈ s, (f i).totalDegree ≤ d) : (s.sum f).totalDegree ≤ d := - (totalDegree_finset_sum ..).trans $ Finset.sup_le hf + (totalDegree_finset_sum ..).trans <| Finset.sup_le hf lemma degreeOf_le_totalDegree (f : MvPolynomial σ R) (i : σ) : f.degreeOf i ≤ f.totalDegree := degreeOf_le_iff.mpr fun d hd ↦ (eq_or_ne (d i) 0).elim (·.trans_le zero_le') fun h ↦ diff --git a/Mathlib/Algebra/MvPolynomial/Division.lean b/Mathlib/Algebra/MvPolynomial/Division.lean index eafbfef36254a..7d505e900d7d2 100644 --- a/Mathlib/Algebra/MvPolynomial/Division.lean +++ b/Mathlib/Algebra/MvPolynomial/Division.lean @@ -206,19 +206,19 @@ 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 : σ} : (X i : MvPolynomial σ R) ∣ (X j : MvPolynomial σ R) ↔ i = j := by refine monomial_one_dvd_monomial_one.trans ?_ simp_rw [Finsupp.single_le_iff, Nat.one_le_iff_ne_zero, Finsupp.single_apply_ne_zero, - ne_eq, not_false_eq_true, and_true] + ne_eq, reduceCtorEq,not_false_eq_true, and_true] @[simp] 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 1e2e8a1a44450..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 @@ -377,7 +400,7 @@ theorem eval_eq_eval_mv_eval' (s : Fin n → R) (y : R) (f : MvPolynomial (Fin ( (Polynomial.aeval y).comp (φ.comp (finSuccEquiv R n).toAlgHom) f congr 2 apply MvPolynomial.algHom_ext - rw [Fin.forall_fin_succ] + rw [Fin.forall_iff_succ] simp only [φ, aeval_X, Fin.cons_zero, AlgEquiv.toAlgHom_eq_coe, AlgHom.coe_comp, Polynomial.coe_aeval_eq_eval, Polynomial.map_C, AlgHom.coe_mk, RingHom.toFun_eq_coe, Polynomial.coe_mapRingHom, comp_apply, finSuccEquiv_apply, eval₂Hom_X', diff --git a/Mathlib/Algebra/MvPolynomial/Expand.lean b/Mathlib/Algebra/MvPolynomial/Expand.lean index 142256c94fc0d..8b06a208a6ea6 100644 --- a/Mathlib/Algebra/MvPolynomial/Expand.lean +++ b/Mathlib/Algebra/MvPolynomial/Expand.lean @@ -68,7 +68,7 @@ theorem map_expand (f : R →+* S) (p : ℕ) (φ : MvPolynomial σ R) : @[simp] theorem rename_expand (f : σ → τ) (p : ℕ) (φ : MvPolynomial σ R) : rename f (expand p φ) = expand p (rename f φ) := by - simp [expand, bind₁_rename, rename_bind₁, Function.comp] + simp [expand, bind₁_rename, rename_bind₁, Function.comp_def] @[simp] theorem rename_comp_expand (f : σ → τ) (p : ℕ) : diff --git a/Mathlib/Algebra/MvPolynomial/Funext.lean b/Mathlib/Algebra/MvPolynomial/Funext.lean index 2bff666a84d66..eaf63370de40c 100644 --- a/Mathlib/Algebra/MvPolynomial/Funext.lean +++ b/Mathlib/Algebra/MvPolynomial/Funext.lean @@ -27,11 +27,13 @@ variable {R : Type*} [CommRing R] [IsDomain R] [Infinite R] private theorem funext_fin {n : ℕ} {p : MvPolynomial (Fin n) R} (h : ∀ x : Fin n → R, eval x p = 0) : p = 0 := by - induction' n with n ih - · apply (MvPolynomial.isEmptyRingEquiv R (Fin 0)).injective + induction n with + | zero => + apply (MvPolynomial.isEmptyRingEquiv R (Fin 0)).injective rw [RingEquiv.map_zero] convert h finZeroElim - · apply (finSuccEquiv R n).injective + | succ n ih => + apply (finSuccEquiv R n).injective simp only [map_zero] refine Polynomial.funext fun q => ?_ rw [Polynomial.eval_zero] diff --git a/Mathlib/Algebra/MvPolynomial/PDeriv.lean b/Mathlib/Algebra/MvPolynomial/PDeriv.lean index a4755788c2c2a..2f36da703dccd 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 _ _ @@ -115,6 +115,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 3043309529923..48bfa47e642c2 100644 --- a/Mathlib/Algebra/MvPolynomial/Rename.lean +++ b/Mathlib/Algebra/MvPolynomial/Rename.lean @@ -72,7 +72,7 @@ theorem rename_rename (f : σ → τ) (g : τ → α) (p : MvPolynomial σ R) : -- Porting note: the Lean 3 proof of this was very fragile and included a nonterminal `simp`. -- Hopefully this is less prone to breaking rw [eval₂_comp_left (eval₂Hom (algebraMap R (MvPolynomial α R)) (X ∘ g)) C (X ∘ f) p] - simp only [(· ∘ ·), eval₂Hom_X'] + simp only [comp_def, eval₂Hom_X'] refine eval₂Hom_congr ?_ rfl rfl ext1; simp only [comp_apply, RingHom.coe_comp, eval₂Hom_C] @@ -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 @@ -246,7 +245,7 @@ theorem exists_fin_rename (p : MvPolynomial σ R) : let e := Fintype.equivFin { x // x ∈ s } refine ⟨n, (↑) ∘ e.symm, Subtype.val_injective.comp e.symm.injective, rename e q, ?_⟩ rw [← rename_rename, rename_rename e] - simp only [Function.comp, Equiv.symm_apply_apply, rename_rename] + simp only [Function.comp_def, Equiv.symm_apply_apply, rename_rename] end Rename diff --git a/Mathlib/Algebra/MvPolynomial/Variables.lean b/Mathlib/Algebra/MvPolynomial/Variables.lean index f431fe8b5f796..730a6443dcfec 100644 --- a/Mathlib/Algebra/MvPolynomial/Variables.lean +++ b/Mathlib/Algebra/MvPolynomial/Variables.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, Johan Commelin, Mario Carneiro -/ +import Mathlib.Data.Finsupp.Lex import Mathlib.Algebra.MvPolynomial.Degrees /-! @@ -139,7 +140,7 @@ theorem vars_prod {ι : Type*} [DecidableEq σ] {s : Finset ι} (f : ι → MvPo section IsDomain -variable {A : Type*} [CommRing A] [IsDomain A] +variable {A : Type*} [CommRing A] [NoZeroDivisors A] theorem vars_C_mul (a : A) (ha : a ≠ 0) (φ : MvPolynomial σ A) : (C a * φ : MvPolynomial σ A).vars = φ.vars := by @@ -148,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 @@ -272,7 +273,7 @@ theorem eval₂Hom_congr' {f₁ f₂ : R →+* S} {g₁ g₂ : σ → S} {p₁ p /-- If `f₁` and `f₂` are ring homs out of the polynomial ring and `p₁` and `p₂` are polynomials, then `f₁ p₁ = f₂ p₂` if `p₁ = p₂` and `f₁` and `f₂` are equal on `R` and on the variables - of `p₁`. -/ + of `p₁`. -/ theorem hom_congr_vars {f₁ f₂ : MvPolynomial σ R →+* S} {p₁ p₂ : MvPolynomial σ R} (hC : f₁.comp C = f₂.comp C) (hv : ∀ i, i ∈ p₁.vars → i ∈ p₂.vars → f₁ (X i) = f₂ (X i)) (hp : p₁ = p₂) : f₁ p₁ = f₂ p₂ := @@ -308,6 +309,25 @@ theorem mem_vars_rename (f : σ → τ) (φ : MvPolynomial σ R) {j : τ} (h : j end EvalVars +section Lex + +variable [LinearOrder σ] + +lemma leadingCoeff_toLex : p.leadingCoeff toLex = p.coeff (ofLex <| p.supDegree toLex) := by + rw [leadingCoeff] + apply congr_arg p.coeff + apply toLex.injective + rw [Function.rightInverse_invFun toLex.surjective, toLex_ofLex] + +lemma supDegree_toLex_C (r : R) : supDegree toLex (C (σ := σ) r) = 0 := by + classical + exact (supDegree_single _ r).trans (ite_eq_iff'.mpr ⟨fun _ => rfl, fun _ => rfl⟩) + +lemma leadingCoeff_toLex_C (r : R) : leadingCoeff toLex (C (σ := σ) r) = r := + leadingCoeff_single toLex.injective _ r + +end Lex + end CommSemiring end MvPolynomial diff --git a/Mathlib/Algebra/NeZero.lean b/Mathlib/Algebra/NeZero.lean index 5851e7c4e2cef..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/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/Pi.lean b/Mathlib/Algebra/Order/Antidiag/Pi.lean index 3bbf985a82d41..fea1cd40e9b83 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 /-! @@ -75,7 +75,7 @@ where (fun ab => (aux d ab.2).1.map { toFun := Fin.cons (ab.1) inj' := Fin.cons_right_injective _ }) - (fun i _hi j _hj hij => Finset.disjoint_left.2 fun t hti htj => hij $ by + (fun i _hi j _hj hij => Finset.disjoint_left.2 fun t hti htj => hij <| by simp_rw [Finset.mem_map, Embedding.coeFn_mk] at hti htj obtain ⟨ai, hai, hij'⟩ := hti obtain ⟨aj, haj, rfl⟩ := htj @@ -106,7 +106,7 @@ choice. /-- The finset of functions `ι → μ` with support contained in `s` and sum `n`. -/ def piAntidiag (s : Finset ι) (n : μ) : Finset (ι → μ) := by - refine (Fintype.truncEquivFinOfCardEq $ Fintype.card_coe s).lift + refine (Fintype.truncEquivFinOfCardEq <| Fintype.card_coe s).lift (fun e ↦ (finAntidiagonal s.card n).map ⟨fun f i ↦ if hi : i ∈ s then f (e ⟨i, hi⟩) else 0, ?_⟩) fun e₁ e₂ ↦ ?_ · rintro f g hfg @@ -114,7 +114,7 @@ def piAntidiag (s : Finset ι) (n : μ) : Finset (ι → μ) := by simpa using congr_fun hfg (e.symm i) · ext f simp only [mem_map, mem_finAntidiagonal] - refine Equiv.exists_congr ((e₁.symm.trans e₂).arrowCongr $ .refl _) fun g ↦ ?_ + refine Equiv.exists_congr ((e₁.symm.trans e₂).arrowCongr <| .refl _) fun g ↦ ?_ have := Fintype.sum_equiv (e₂.symm.trans e₁) _ g fun _ ↦ rfl aesop @@ -162,9 +162,9 @@ lemma pairwiseDisjoint_piAntidiag_map_addRightEmbedding (hi : i ∉ s) (n : μ) simp only [ne_eq, antidiagonal_congr' hab hcd, disjoint_left, mem_map, mem_piAntidiag, addRightEmbedding_apply, not_exists, not_and, and_imp, forall_exists_index] rintro hfg _ f rfl - rfl g rfl - hgf - exact hfg $ by simpa [sum_add_distrib, hi] using congr_arg (∑ j ∈ s, · j) hgf.symm + exact hfg <| by simpa [sum_add_distrib, hi] using congr_arg (∑ j ∈ s, · j) hgf.symm -lemma piAntidiag_cons (hi : i ∉ s) (n : μ) : +lemma piAntidiag_cons (hi : i ∉ s) (n : μ) : piAntidiag (cons i s hi) n = (antidiagonal n).disjiUnion (fun p : μ × μ ↦ (piAntidiag s p.snd).map (addRightEmbedding fun t ↦ if t = i then p.fst else 0)) (pairwiseDisjoint_piAntidiag_map_addRightEmbedding hi _) := by diff --git a/Mathlib/Algebra/Order/Antidiag/Prod.lean b/Mathlib/Algebra/Order/Antidiag/Prod.lean index dde92767a53bf..6f49ffaa10635 100644 --- a/Mathlib/Algebra/Order/Antidiag/Prod.lean +++ b/Mathlib/Algebra/Order/Antidiag/Prod.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Antoine Chambert-Loir and María Inés de Frutos-Fernández. Released under Apache 2.0 license as described in the file LICENSE. Authors: Antoine Chambert-Loir, María Inés de Frutos-Fernández, Bhavik Mehta, Eric Wieser -/ +import Mathlib.Algebra.Order.Monoid.Canonical.Defs import Mathlib.Algebra.Order.Sub.Defs import Mathlib.Data.Finset.Basic import Mathlib.Order.Interval.Finset.Defs diff --git a/Mathlib/Algebra/Order/Archimedean/Basic.lean b/Mathlib/Algebra/Order/Archimedean/Basic.lean index 8bef3b5929f73..4d20bc04708f5 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 @@ -19,6 +19,8 @@ number `n` such that `x ≤ n • y`. * `Archimedean` is a typeclass for an ordered additive commutative monoid to have the archimedean property. +* `MulArchimedean` is a typeclass for an ordered commutative monoid to have the "mul-archimedean + property" where for `x` and `y > 1`, there exists a natural number `n` such that `x ≤ y ^ n`. * `Archimedean.floorRing` defines a floor function on an archimedean linearly ordered ring making it into a `floorRing`. @@ -38,74 +40,104 @@ class Archimedean (α) [OrderedAddCommMonoid α] : Prop where such that `x ≤ n • y`. -/ arch : ∀ (x : α) {y : α}, 0 < y → ∃ n : ℕ, x ≤ n • y -instance OrderDual.archimedean [OrderedAddCommGroup α] [Archimedean α] : Archimedean αᵒᵈ := - ⟨fun x y hy => - let ⟨n, hn⟩ := Archimedean.arch (-ofDual x) (neg_pos.2 hy) - ⟨n, by rwa [neg_nsmul, neg_le_neg_iff] at hn⟩⟩ +section MulArchimedean -variable {M : Type*} +/-- An ordered commutative monoid is called `MulArchimedean` if for any two elements `x`, `y` +such that `1 < y`, there exists a natural number `n` such that `x ≤ y ^ n`. -/ +@[to_additive Archimedean] +class MulArchimedean (α) [OrderedCommMonoid α] : Prop where + /-- For any two elements `x`, `y` such that `1 < y`, there exists a natural number `n` + such that `x ≤ y ^ n`. -/ + arch : ∀ (x : α) {y : α}, 1 < y → ∃ n : ℕ, x ≤ y ^ n + +end MulArchimedean + +@[to_additive] +instance OrderDual.instMulArchimedean [OrderedCommGroup α] [MulArchimedean α] : + MulArchimedean αᵒᵈ := + ⟨fun x y hy => + let ⟨n, hn⟩ := MulArchimedean.arch (ofDual x)⁻¹ (inv_lt_one_iff_one_lt.2 hy) + ⟨n, by rwa [inv_pow, inv_le_inv_iff] at hn⟩⟩ -theorem exists_lt_nsmul [OrderedAddCommMonoid M] [Archimedean M] - [CovariantClass M M (· + ·) (· < ·)] {a : M} (ha : 0 < a) (b : M) : - ∃ n : ℕ, b < n • a := - let ⟨k, hk⟩ := Archimedean.arch b ha - ⟨k + 1, hk.trans_lt <| nsmul_lt_nsmul_left ha k.lt_succ_self⟩ +instance Additive.instArchimedean [OrderedCommGroup α] [MulArchimedean α] : + Archimedean (Additive α) := + ⟨fun x _ hy ↦ MulArchimedean.arch (toMul x) hy⟩ -section LinearOrderedAddCommGroup +instance Multiplicative.instMulArchimedean [OrderedAddCommGroup α] [Archimedean α] : + MulArchimedean (Multiplicative α) := + ⟨fun x _ hy ↦ Archimedean.arch (toAdd x) hy⟩ -variable [LinearOrderedAddCommGroup α] [Archimedean α] +variable {M : Type*} -/-- An archimedean decidable linearly ordered `AddCommGroup` has a version of the floor: for -`a > 0`, any `g` in the group lies between some two consecutive multiples of `a`. -/ -theorem existsUnique_zsmul_near_of_pos {a : α} (ha : 0 < a) (g : α) : - ∃! k : ℤ, k • a ≤ g ∧ g < (k + 1) • a := by - let s : Set ℤ := { n : ℤ | n • a ≤ g } - obtain ⟨k, hk : -g ≤ k • a⟩ := Archimedean.arch (-g) ha - have h_ne : s.Nonempty := ⟨-k, by simpa [s] using neg_le_neg hk⟩ - obtain ⟨k, hk⟩ := Archimedean.arch g ha +@[to_additive] +theorem exists_lt_pow [OrderedCommMonoid M] [MulArchimedean M] + [CovariantClass M 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⟩ + +section LinearOrderedCommGroup + +variable [LinearOrderedCommGroup α] [MulArchimedean α] + +/-- An archimedean decidable linearly ordered `CommGroup` has a version of the floor: for +`a > 1`, any `g` in the group lies between some two consecutive powers of `a`. -/ +@[to_additive "An archimedean decidable linearly ordered `AddCommGroup` has a version of the floor: +for `a > 0`, any `g` in the group lies between some two consecutive multiples of `a`. -/"] +theorem existsUnique_zpow_near_of_one_lt {a : α} (ha : 1 < a) (g : α) : + ∃! k : ℤ, a ^ k ≤ g ∧ g < a ^ (k + 1) := by + let s : Set ℤ := { n : ℤ | a ^ n ≤ g } + obtain ⟨k, hk : g⁻¹ ≤ a ^ k⟩ := MulArchimedean.arch g⁻¹ ha + have h_ne : s.Nonempty := ⟨-k, by simpa [s] using inv_le_inv' hk⟩ + obtain ⟨k, hk⟩ := MulArchimedean.arch g ha have h_bdd : ∀ n ∈ s, n ≤ (k : ℤ) := by intro n hn - apply (zsmul_le_zsmul_iff ha).mp - rw [← natCast_zsmul] at hk + apply (zpow_le_zpow_iff ha).mp + rw [← zpow_natCast] at hk exact le_trans hn hk obtain ⟨m, hm, hm'⟩ := Int.exists_greatest_of_bdd ⟨k, h_bdd⟩ h_ne - have hm'' : g < (m + 1) • a := by + have hm'' : g < a ^ (m + 1) := by contrapose! hm' exact ⟨m + 1, hm', lt_add_one _⟩ refine ⟨m, ⟨hm, hm''⟩, fun n hn => (hm' n hn.1).antisymm <| Int.le_of_lt_add_one ?_⟩ - rw [← zsmul_lt_zsmul_iff ha] + rw [← zpow_lt_zpow_iff ha] exact lt_of_le_of_lt hm hn.2 -theorem existsUnique_zsmul_near_of_pos' {a : α} (ha : 0 < a) (g : α) : - ∃! k : ℤ, 0 ≤ g - k • a ∧ g - k • a < a := by - simpa only [sub_nonneg, add_zsmul, one_zsmul, sub_lt_iff_lt_add'] using - existsUnique_zsmul_near_of_pos ha g - -theorem existsUnique_sub_zsmul_mem_Ico {a : α} (ha : 0 < a) (b c : α) : - ∃! m : ℤ, b - m • a ∈ Set.Ico c (c + a) := by - simpa only [mem_Ico, le_sub_iff_add_le, zero_add, add_comm c, sub_lt_iff_lt_add', add_assoc] using - existsUnique_zsmul_near_of_pos' ha (b - c) - -theorem existsUnique_add_zsmul_mem_Ico {a : α} (ha : 0 < a) (b c : α) : - ∃! m : ℤ, b + m • a ∈ Set.Ico c (c + a) := +@[to_additive] +theorem existsUnique_zpow_near_of_one_lt' {a : α} (ha : 1 < a) (g : α) : + ∃! k : ℤ, 1 ≤ g / a ^ k ∧ g / a ^ k < a := by + simpa only [one_le_div', zpow_add_one, div_lt_iff_lt_mul'] using + existsUnique_zpow_near_of_one_lt ha g + +@[to_additive] +theorem existsUnique_div_zpow_mem_Ico {a : α} (ha : 1 < a) (b c : α) : + ∃! m : ℤ, b / a ^ m ∈ Set.Ico c (c * a) := by + simpa only [mem_Ico, le_div_iff_mul_le, one_mul, mul_comm c, div_lt_iff_lt_mul, mul_assoc] using + existsUnique_zpow_near_of_one_lt' ha (b / c) + +@[to_additive] +theorem existsUnique_mul_zpow_mem_Ico {a : α} (ha : 1 < a) (b c : α) : + ∃! m : ℤ, b * a ^ m ∈ Set.Ico c (c * a) := (Equiv.neg ℤ).bijective.existsUnique_iff.2 <| by - simpa only [Equiv.neg_apply, mem_Ico, neg_zsmul, ← sub_eq_add_neg, le_sub_iff_add_le, zero_add, - add_comm c, sub_lt_iff_lt_add', add_assoc] using existsUnique_zsmul_near_of_pos' ha (b - c) + simpa only [Equiv.neg_apply, mem_Ico, zpow_neg, ← div_eq_mul_inv, le_div_iff_mul_le, one_mul, + mul_comm c, div_lt_iff_lt_mul, mul_assoc] using existsUnique_zpow_near_of_one_lt' ha (b / c) -theorem existsUnique_add_zsmul_mem_Ioc {a : α} (ha : 0 < a) (b c : α) : - ∃! m : ℤ, b + m • a ∈ Set.Ioc c (c + a) := +@[to_additive] +theorem existsUnique_add_zpow_mem_Ioc {a : α} (ha : 1 < a) (b c : α) : + ∃! m : ℤ, b * a ^ m ∈ Set.Ioc c (c * a) := (Equiv.addRight (1 : ℤ)).bijective.existsUnique_iff.2 <| by - simpa only [add_zsmul, sub_lt_iff_lt_add', le_sub_iff_add_le', ← add_assoc, and_comm, mem_Ioc, - Equiv.coe_addRight, one_zsmul, add_le_add_iff_right] using - existsUnique_zsmul_near_of_pos ha (c - b) + simpa only [zpow_add_one, div_lt_iff_lt_mul', le_div_iff_mul_le', ← mul_assoc, and_comm, + mem_Ioc, Equiv.coe_addRight, mul_le_mul_iff_right] using + existsUnique_zpow_near_of_one_lt ha (c / b) -theorem existsUnique_sub_zsmul_mem_Ioc {a : α} (ha : 0 < a) (b c : α) : - ∃! m : ℤ, b - m • a ∈ Set.Ioc c (c + a) := +@[to_additive] +theorem existsUnique_sub_zpow_mem_Ioc {a : α} (ha : 1 < a) (b c : α) : + ∃! m : ℤ, b / a ^ m ∈ Set.Ioc c (c * a) := (Equiv.neg ℤ).bijective.existsUnique_iff.2 <| by - simpa only [Equiv.neg_apply, neg_zsmul, sub_neg_eq_add] using - existsUnique_add_zsmul_mem_Ioc ha b c + simpa only [Equiv.neg_apply, zpow_neg, div_inv_eq_mul] using + existsUnique_add_zpow_mem_Ioc ha b c -end LinearOrderedAddCommGroup +end LinearOrderedCommGroup theorem exists_nat_ge [OrderedSemiring α] [Archimedean α] (x : α) : ∃ n : ℕ, x ≤ n := by nontriviality α @@ -191,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 @@ -209,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)⟩ @@ -225,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 @@ -235,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 @@ -267,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 @@ -320,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 @@ -370,13 +402,18 @@ instance : Archimedean ℤ := instance : Archimedean ℚ := archimedean_iff_rat_le.2 fun q => ⟨q, by rw [Rat.cast_id]⟩ -instance Nonneg.archimedean [OrderedAddCommMonoid α] [Archimedean α] : +instance Nonneg.instArchimedean [OrderedAddCommMonoid α] [Archimedean α] : Archimedean { x : α // 0 ≤ x } := ⟨fun x y hy => let ⟨n, hr⟩ := Archimedean.arch (x : α) (hy : (0 : α) < y) ⟨n, show (x : α) ≤ (n • y : { x : α // 0 ≤ x }) by simp [*, -nsmul_eq_mul, nsmul_coe]⟩⟩ -instance : Archimedean NNRat := Nonneg.archimedean +instance Nonneg.instMulArchimedean [StrictOrderedCommSemiring α] [Archimedean α] [ExistsAddOfLE α] : + MulArchimedean { x : α // 0 ≤ x } := + ⟨fun x _ hy ↦ (pow_unbounded_of_one_lt x hy).imp fun _ h ↦ h.le⟩ + +instance : Archimedean NNRat := Nonneg.instArchimedean +instance : MulArchimedean NNRat := Nonneg.instMulArchimedean /-- A linear ordered archimedean ring is a floor ring. This is not an `instance` because in some cases we have a computable `floor` function. -/ @@ -390,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/Hom.lean b/Mathlib/Algebra/Order/Archimedean/Hom.lean index 92a89b61ee68e..c4e7b11c89739 100644 --- a/Mathlib/Algebra/Order/Archimedean/Hom.lean +++ b/Mathlib/Algebra/Order/Archimedean/Hom.lean @@ -23,9 +23,7 @@ instance OrderRingHom.subsingleton [LinearOrderedField α] [LinearOrderedField ⟨fun f g => by ext x by_contra! h' : f x ≠ g x - wlog h : f x < g x generalizing α β with h₂ - -- Porting note: had to add the `generalizing` as there are random variables - -- `F γ δ` flying around in context. + wlog h : f x < g x with h₂ · exact h₂ g f x (Ne.symm h') (h'.lt_or_lt.resolve_left h) obtain ⟨q, hf, hg⟩ := exists_rat_btwn h rw [← map_ratCast f] at hf 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 ce3eb2fbc4a57..d5cdc6b8f86e7 100644 --- a/Mathlib/Algebra/Order/BigOperators/Group/Finset.lean +++ b/Mathlib/Algebra/Order/BigOperators/Group/Finset.lean @@ -5,6 +5,7 @@ Authors: Johannes Hölzl -/ import Mathlib.Algebra.BigOperators.Group.Finset import Mathlib.Algebra.Order.BigOperators.Group.Multiset +import Mathlib.Data.Multiset.OrderedMonoid import Mathlib.Tactic.Bound.Attribute import Mathlib.Tactic.NormNum.Basic import Mathlib.Tactic.Positivity.Core @@ -120,7 +121,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 @@ -209,6 +210,16 @@ theorem prod_le_prod_fiberwise_of_prod_fiber_le_one' {t : Finset ι'} {g : ι 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 @@ -220,6 +231,16 @@ 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 α] [CovariantClass α α (· * ·) (· ≤ ·)] {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 β] @@ -544,7 +565,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] diff --git a/Mathlib/Algebra/Order/BigOperators/Group/List.lean b/Mathlib/Algebra/Order/BigOperators/Group/List.lean index 7872ed429ca63..94dd5a115870c 100644 --- a/Mathlib/Algebra/Order/BigOperators/Group/List.lean +++ b/Mathlib/Algebra/Order/BigOperators/Group/List.lean @@ -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] + [CovariantClass M M (· * ·) (· ≤ ·)] [CovariantClass M M (Function.swap (· * ·)) (· ≤ ·)] : + 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] [CovariantClass M M (· * ·) (· ≤ ·)] + [CovariantClass M M (Function.swap (· * ·)) (· ≤ ·)] (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 19dc75bdf2115..ad405fe75fb40 100644 --- a/Mathlib/Algebra/Order/BigOperators/Group/Multiset.lean +++ b/Mathlib/Algebra/Order/BigOperators/Group/Multiset.lean @@ -47,9 +47,10 @@ lemma all_one_of_le_one_le_of_prod_eq_one : @[to_additive] lemma prod_le_prod_of_rel_le (h : s.Rel (· ≤ ·) t) : s.prod ≤ t.prod := by - induction' h with _ _ _ _ rh _ rt - · rfl - · rw [prod_cons, prod_cons] + induction h with + | zero => rfl + | cons rh _ rt => + rw [prod_cons, prod_cons] exact mul_le_mul' rh rt @[to_additive] @@ -155,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 new file mode 100644 index 0000000000000..e38120c46d7ac --- /dev/null +++ b/Mathlib/Algebra/Order/BigOperators/GroupWithZero/List.lean @@ -0,0 +1,99 @@ +/- +Copyright (c) 2021 Stuart Presnell. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Stuart Presnell, Daniel Weber +-/ +import Mathlib.Algebra.BigOperators.Group.List +import Mathlib.Algebra.Order.GroupWithZero.Unbundled + +/-! +# Big operators on a list in ordered groups with zeros + +This file contains the results concerning the interaction of list big operators with ordered +groups with zeros. +-/ + +namespace List +variable {R : Type*} [CommMonoidWithZero R] [PartialOrder R] [ZeroLEOneClass R] [PosMulMono R] + +lemma prod_nonneg {s : List R} (h : ∀ a ∈ s, 0 ≤ a) : 0 ≤ s.prod := by + induction s with + | nil => simp + | cons head tail hind => + simp only [prod_cons] + simp only [mem_cons, forall_eq_or_imp] at h + exact mul_nonneg h.1 (hind h.2) + + +lemma one_le_prod {s : List R} (h : ∀ a ∈ s, 1 ≤ a) : 1 ≤ s.prod := by + induction s with + | nil => simp + | cons head tail hind => + simp only [prod_cons] + simp only [mem_cons, forall_eq_or_imp] at h + exact one_le_mul_of_one_le_of_one_le h.1 (hind h.2) + +theorem prod_map_le_prod_map₀ {ι : Type*} {s : List ι} (f : ι → R) (g : ι → R) + (h0 : ∀ i ∈ s, 0 ≤ f i) (h : ∀ i ∈ s, f i ≤ g i) : + (map f s).prod ≤ (map g s).prod := by + induction s with + | nil => simp + | cons a s hind => + simp only [map_cons, prod_cons] + have := posMulMono_iff_mulPosMono.1 ‹PosMulMono R› + apply mul_le_mul + · apply h + simp + · apply hind + · intro i hi + apply h0 + simp [hi] + · intro i hi + apply h + simp [hi] + · 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 + +omit [PosMulMono R] +variable [PosMulStrictMono R] [NeZero (1 : R)] + +lemma prod_pos {s : List R} (h : ∀ a ∈ s, 0 < a) : 0 < s.prod := by + induction s with + | nil => simp + | cons a s hind => + simp only [prod_cons] + simp only [mem_cons, forall_eq_or_imp] at h + exact mul_pos h.1 (hind h.2) + +theorem prod_map_lt_prod_map {ι : Type*} {s : List ι} (hs : s ≠ []) + (f : ι → R) (g : ι → R) (h0 : ∀ i ∈ s, 0 < f i) (h : ∀ i ∈ s, f i < g i) : + (map f s).prod < (map g s).prod := by + match s with + | [] => contradiction + | a :: s => + simp only [map_cons, prod_cons] + have := posMulStrictMono_iff_mulPosStrictMono.1 ‹PosMulStrictMono R› + apply mul_lt_mul + · apply h + simp + · apply prod_map_le_prod_map₀ + · intro i hi + apply le_of_lt + apply h0 + simp [hi] + · intro i hi + 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₂] + intro a ha + apply h0 + simp [ha] + · apply le_of_lt ((h0 _ _).trans (h _ _)) <;> simp + +end List diff --git a/Mathlib/Algebra/Order/BigOperators/GroupWithZero/Multiset.lean b/Mathlib/Algebra/Order/BigOperators/GroupWithZero/Multiset.lean new file mode 100644 index 0000000000000..7115296a5745e --- /dev/null +++ b/Mathlib/Algebra/Order/BigOperators/GroupWithZero/Multiset.lean @@ -0,0 +1,51 @@ +/- +Copyright (c) 2021 Ruben Van de Velde. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Ruben Van de Velde, Daniel Weber +-/ +import Mathlib.Algebra.Order.BigOperators.GroupWithZero.List +import Mathlib.Algebra.BigOperators.Group.Multiset + +/-! +# Big operators on a multiset in ordered groups with zeros + +This file contains the results concerning the interaction of multiset big operators with ordered +groups with zeros. +-/ + +namespace Multiset +variable {R : Type*} [CommMonoidWithZero R] [PartialOrder R] [ZeroLEOneClass R] [PosMulMono R] + +lemma prod_nonneg {s : Multiset R} (h : ∀ a ∈ s, 0 ≤ a) : 0 ≤ s.prod := by + cases s using Quotient.ind + simp only [quot_mk_to_coe, mem_coe, prod_coe] at * + apply List.prod_nonneg h + +lemma one_le_prod {s : Multiset R} (h : ∀ a ∈ s, 1 ≤ a) : 1 ≤ s.prod := by + cases s using Quotient.ind + simp only [quot_mk_to_coe, mem_coe, prod_coe] at * + apply List.one_le_prod h + +theorem prod_map_le_prod_map₀ {ι : Type*} {s : Multiset ι} (f : ι → R) (g : ι → R) + (h0 : ∀ i ∈ s, 0 ≤ f i) (h : ∀ i ∈ s, f i ≤ g i) : + (map f s).prod ≤ (map g s).prod := by + cases s using Quotient.ind + simp only [quot_mk_to_coe, mem_coe, map_coe, prod_coe] at * + apply List.prod_map_le_prod_map₀ f g h0 h + +omit [PosMulMono R] +variable [PosMulStrictMono R] [NeZero (1 : R)] + +lemma prod_pos {s : Multiset R} (h : ∀ a ∈ s, 0 < a) : 0 < s.prod := by + cases s using Quotient.ind + simp only [quot_mk_to_coe, mem_coe, map_coe, prod_coe] at * + apply List.prod_pos h + +theorem prod_map_lt_prod_map {ι : Type*} {s : Multiset ι} (hs : s ≠ 0) + (f : ι → R) (g : ι → R) (h0 : ∀ i ∈ s, 0 < f i) (h : ∀ i ∈ s, f i < g i) : + (map f s).prod < (map g s).prod := by + cases s using Quotient.ind + simp only [quot_mk_to_coe, mem_coe, map_coe, prod_coe, ne_eq, coe_eq_zero] at * + apply List.prod_map_lt_prod_map hs f g h0 h + +end Multiset diff --git a/Mathlib/Algebra/Order/BigOperators/Ring/Finset.lean b/Mathlib/Algebra/Order/BigOperators/Ring/Finset.lean index f0d1340dfdcd1..9f305603865f6 100644 --- a/Mathlib/Algebra/Order/BigOperators/Ring/Finset.lean +++ b/Mathlib/Algebra/Order/BigOperators/Ring/Finset.lean @@ -82,6 +82,22 @@ lemma prod_lt_prod_of_nonempty (hf : ∀ i ∈ s, 0 < f i) (hfg : ∀ i ∈ s, f end PosMulStrictMono end CommMonoidWithZero +section OrderedSemiring + +variable [OrderedSemiring R] {f : ι → R} {s : Finset ι} + +lemma sum_sq_le_sq_sum_of_nonneg (hf : ∀ i ∈ s, 0 ≤ f i) : + ∑ i ∈ s, f i ^ 2 ≤ (∑ i ∈ s, f i) ^ 2 := by + simp only [sq, sum_mul_sum] + refine sum_le_sum fun i hi ↦ ?_ + rw [← mul_sum] + gcongr + · exact hf i hi + · exact single_le_sum hf hi + + +end OrderedSemiring + section OrderedCommSemiring variable [OrderedCommSemiring R] {f g : ι → R} {s t : Finset ι} diff --git a/Mathlib/Algebra/Order/BigOperators/Ring/List.lean b/Mathlib/Algebra/Order/BigOperators/Ring/List.lean index 2a108cb55955b..d728f2a6a84bf 100644 --- a/Mathlib/Algebra/Order/BigOperators/Ring/List.lean +++ b/Mathlib/Algebra/Order/BigOperators/Ring/List.lean @@ -14,23 +14,10 @@ This file contains the results concerning the interaction of list big operators variable {R : Type*} -namespace List - -/-- The product of a list of positive natural numbers is positive, -and likewise for any nontrivial ordered semiring. -/ -lemma prod_pos [StrictOrderedSemiring R] (l : List R) (h : ∀ a ∈ l, (0 : R) < a) : - 0 < l.prod := by - induction' l with a l ih - · simp - · rw [prod_cons] - exact mul_pos (h _ <| mem_cons_self _ _) (ih fun a ha => h a <| mem_cons_of_mem _ ha) - /-- A variant of `List.prod_pos` for `CanonicallyOrderedCommSemiring`. -/ -@[simp] lemma _root_.CanonicallyOrderedCommSemiring.list_prod_pos +@[simp] lemma CanonicallyOrderedCommSemiring.list_prod_pos {α : Type*} [CanonicallyOrderedCommSemiring α] [Nontrivial α] : ∀ {l : List α}, 0 < l.prod ↔ (∀ x ∈ l, (0 : α) < x) | [] => by simp - | (x :: xs) => by simp_rw [prod_cons, forall_mem_cons, CanonicallyOrderedCommSemiring.mul_pos, - list_prod_pos] - -end List + | (x :: xs) => by simp_rw [List.prod_cons, List.forall_mem_cons, + CanonicallyOrderedCommSemiring.mul_pos, list_prod_pos] diff --git a/Mathlib/Algebra/Order/BigOperators/Ring/Multiset.lean b/Mathlib/Algebra/Order/BigOperators/Ring/Multiset.lean index 3ca2b1b7c918c..0b91673c65582 100644 --- a/Mathlib/Algebra/Order/BigOperators/Ring/Multiset.lean +++ b/Mathlib/Algebra/Order/BigOperators/Ring/Multiset.lean @@ -13,26 +13,10 @@ This file contains the results concerning the interaction of multiset big operat rings. -/ -namespace Multiset -variable {R : Type*} - -section OrderedCommSemiring -variable [OrderedCommSemiring R] {s : Multiset R} - -lemma prod_nonneg (h : ∀ a ∈ s, 0 ≤ a) : 0 ≤ s.prod := by - revert h - refine s.induction_on ?_ fun a s hs ih ↦ ?_ - · simp - · rw [prod_cons] - exact mul_nonneg (ih _ <| mem_cons_self _ _) (hs fun a ha ↦ ih _ <| mem_cons_of_mem ha) - -end OrderedCommSemiring - @[simp] -lemma _root_.CanonicallyOrderedCommSemiring.multiset_prod_pos [CanonicallyOrderedCommSemiring R] - [Nontrivial R] {m : Multiset R} : 0 < m.prod ↔ ∀ x ∈ m, 0 < x := by +lemma CanonicallyOrderedCommSemiring.multiset_prod_pos {R : Type*} + [CanonicallyOrderedCommSemiring R] [Nontrivial R] {m : Multiset R} : + 0 < m.prod ↔ ∀ x ∈ m, 0 < x := by rcases m with ⟨l⟩ rw [Multiset.quot_mk_to_coe'', Multiset.prod_coe] exact CanonicallyOrderedCommSemiring.list_prod_pos - -end Multiset diff --git a/Mathlib/Algebra/Order/CauSeq/Basic.lean b/Mathlib/Algebra/Order/CauSeq/Basic.lean index abb991002f5a5..b390f7b8dceaf 100644 --- a/Mathlib/Algebra/Order/CauSeq/Basic.lean +++ b/Mathlib/Algebra/Order/CauSeq/Basic.lean @@ -116,7 +116,7 @@ lemma bounded (hf : IsCauSeq abv f) : ∃ r, ∀ i, abv (f i) < r := by refine ⟨R i + 1, fun j ↦ ?_⟩ obtain hji | hij := le_total j i · exact (this i _ hji).trans_lt (lt_add_one _) - · simpa using (abv_add abv _ _).trans_lt $ add_lt_add_of_le_of_lt (this i _ le_rfl) (h _ hij) + · simpa using (abv_add abv _ _).trans_lt <| add_lt_add_of_le_of_lt (this i _ le_rfl) (h _ hij) lemma bounded' (hf : IsCauSeq abv f) (x : α) : ∃ r > x, ∀ i, abv (f i) < r := let ⟨r, h⟩ := hf.bounded @@ -518,7 +518,7 @@ theorem smul_equiv_smul {G : Type*} [SMul G β] [IsScalarTower G β β] {f1 f2 : theorem pow_equiv_pow {f1 f2 : CauSeq β abv} (hf : f1 ≈ f2) (n : ℕ) : f1 ^ n ≈ f2 ^ n := by induction n with - | zero => simp only [Nat.zero_eq, pow_zero, Setoid.refl] + | zero => simp only [pow_zero, Setoid.refl] | succ n ih => simpa only [pow_succ'] using mul_equiv_mul hf ih end Ring @@ -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 := diff --git a/Mathlib/Algebra/Order/CauSeq/BigOperators.lean b/Mathlib/Algebra/Order/CauSeq/BigOperators.lean index 129e4899f3ace..99ac7eb6f4dd3 100644 --- a/Mathlib/Algebra/Order/CauSeq/BigOperators.lean +++ b/Mathlib/Algebra/Order/CauSeq/BigOperators.lean @@ -94,7 +94,7 @@ theorem _root_.cauchy_product (ha : IsCauSeq abs fun m ↦ ∑ n ∈ range m, ab abv (f i) * abv ((∑ k ∈ range (K - i), g k) - ∑ k ∈ range K, g k)) ≤ ∑ i ∈ range (max N M + 1), abv (f i) * (ε / (2 * P)) := by gcongr with m hmJ - refine le_of_lt $ hN (K - m) (le_tsub_of_add_le_left $ hK.trans' ?_) K hKN.le + refine le_of_lt <| hN (K - m) (le_tsub_of_add_le_left <| hK.trans' ?_) K hKN.le rw [two_mul] gcongr · exact (mem_range.1 hmJ).le @@ -133,8 +133,9 @@ theorem _root_.cauchy_product (ha : IsCauSeq abs fun m ↦ ∑ n ∈ range m, ab rw [← sum_mul, ← sum_range_sub_sum_range (le_of_lt hNMK)] have := lt_of_le_of_lt (abv_nonneg _ _) (hQ 0) gcongr - exact (le_abs_self _).trans_lt $ hM _ ((Nat.le_succ_of_le (le_max_right _ _)).trans hNMK.le) - _ $ Nat.le_succ_of_le $ le_max_right _ _ + exact (le_abs_self _).trans_lt <| + hM _ ((Nat.le_succ_of_le (le_max_right _ _)).trans hNMK.le) _ <| + Nat.le_succ_of_le <| le_max_right _ _ variable [Archimedean α] @@ -172,7 +173,7 @@ lemma of_decreasing_bounded (f : ℕ → α) {a : α} {m : ℕ} (ham : ∀ n ≥ lemma of_mono_bounded (f : ℕ → α) {a : α} {m : ℕ} (ham : ∀ n ≥ m, |f n| ≤ a) (hnm : ∀ n ≥ m, f n ≤ f n.succ) : IsCauSeq abs f := - (of_decreasing_bounded (-f) (a := a) (m := m) (by simpa using ham) $ by simpa using hnm).of_neg + (of_decreasing_bounded (-f) (a := a) (m := m) (by simpa using ham) <| by simpa using hnm).of_neg lemma geo_series [Nontrivial β] (x : β) (hx1 : abv x < 1) : IsCauSeq abv fun n ↦ ∑ m ∈ range n, x ^ m := by @@ -187,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 @@ -212,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/Chebyshev.lean b/Mathlib/Algebra/Order/Chebyshev.lean index ebbe5643ee00c..439d79b0c4e2b 100644 --- a/Mathlib/Algebra/Order/Chebyshev.lean +++ b/Mathlib/Algebra/Order/Chebyshev.lean @@ -4,9 +4,12 @@ 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 @@ -44,28 +47,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.card • ∑ 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.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 _ /-- **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.card • ∑ 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 +74,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 +94,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.card * ∑ i ∈ s, f i * g i := by rw [← nsmul_eq_mul] exact hfg.sum_smul_sum_le_card_smul_sum @@ -108,10 +108,26 @@ 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.card : α) * ∑ i ∈ s, f i * g i ≤ (∑ i ∈ s, f i) * ∑ i ∈ s, g i := by rw [← nsmul_eq_mul] exact hfg.card_smul_sum_le_sum_smul_sum +/-- Special case of **Jensen's inequality** for sums of powers. -/ +lemma pow_sum_le_card_mul_sum_pow (hf : ∀ i ∈ s, 0 ≤ f i) : + ∀ n, (∑ i ∈ s, f i) ^ (n + 1) ≤ (s.card : α) ^ n * ∑ i ∈ s, f i ^ (n + 1) + | 0 => by simp + | n + 1 => + calc + _ = (∑ i ∈ s, f i) ^ (n + 1) * ∑ i ∈ s, f i := by rw [pow_succ] + _ ≤ (s.card ^ n * ∑ i ∈ s, f i ^ (n + 1)) * ∑ i ∈ s, f i := by + gcongr + exacts [sum_nonneg hf, pow_sum_le_card_mul_sum_pow hf _] + _ = s.card ^ n * ((∑ i ∈ s, f i ^ (n + 1)) * ∑ i ∈ s, f i) := by rw [mul_assoc] + _ ≤ s.card ^ n * (s.card * ∑ i ∈ s, f i ^ (n + 1) * f i) := by + 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 @@ -124,25 +140,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.card ^ 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 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.card : α), 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..680ebceb3f631 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 /-! diff --git a/Mathlib/Algebra/Order/Field/Basic.lean b/Mathlib/Algebra/Order/Field/Basic.lean index 2dee94a512441..4e76076e79d17 100644 --- a/Mathlib/Algebra/Order/Field/Basic.lean +++ b/Mathlib/Algebra/Order/Field/Basic.lean @@ -5,11 +5,10 @@ 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 -import Mathlib.Algebra.Order.Field.Unbundled.Basic /-! # Lemmas about linear ordered (semi)fields @@ -24,201 +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. -/ +@[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 le_div_iff (hc : 0 < c) : a ≤ b / c ↔ a * c ≤ b := - ⟨fun h => div_mul_cancel₀ b (ne_of_lt hc).symm ▸ mul_le_mul_of_nonneg_right h hc.le, fun h => - calc - a = a * c * (1 / c) := mul_mul_div a (ne_of_lt hc).symm - _ ≤ b * (1 / c) := mul_le_mul_of_nonneg_right h (one_div_pos (α := α) |>.2 hc).le - _ = b / c := (div_eq_mul_one_div b c).symm - ⟩ - -theorem le_div_iff' (hc : 0 < c) : a ≤ b / c ↔ c * a ≤ b := by rw [mul_comm, le_div_iff hc] - -theorem div_le_iff (hb : 0 < b) : a / b ≤ c ↔ a ≤ c * b := - ⟨fun h => - calc - a = a / b * b := by rw [div_mul_cancel₀ _ (ne_of_lt hb).symm] - _ ≤ c * b := mul_le_mul_of_nonneg_right h hb.le - , - fun h => - calc - a / b = a * (1 / b) := div_eq_mul_one_div a b - _ ≤ c * b * (1 / b) := mul_le_mul_of_nonneg_right h (one_div_pos (α := α) |>.2 hb).le - _ = c * b / b := (div_eq_mul_one_div (c * b) b).symm - _ = c := by refine (div_eq_iff (ne_of_gt hb)).mpr rfl - ⟩ - -theorem div_le_iff' (hb : 0 < b) : a / b ≤ c ↔ a ≤ b * c := by rw [mul_comm, div_le_iff hb] - -lemma div_le_comm₀ (hb : 0 < b) (hc : 0 < c) : a / b ≤ c ↔ a / c ≤ b := by - rw [div_le_iff hb, div_le_iff' hc] - -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 ↔ c * a < 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 div_lt_iff₀ (since := "2024-10-02")] +theorem div_lt_iff (hc : 0 < c) : b / c < a ↔ b < a * c := div_lt_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 < c * a := 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 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 ≤ 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 ≤ c * b := 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 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 ≤ 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 ≤ c * b := 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 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 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 < c * b := 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 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 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 < c * b := 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 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 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 ≤ a * b := 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_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_le_iff_one_le_mul' (ha : 0 < a) : a⁻¹ ≤ b ↔ 1 ≤ a * b := by - rw [inv_eq_one_div] - exact div_le_iff' 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. @@ -228,22 +169,22 @@ theorem one_le_inv_iff : 1 ≤ a⁻¹ ↔ 0 < a ∧ a ≤ 1 := @[mono, gcongr, bound] lemma div_le_div_of_nonneg_right (hab : a ≤ b) (hc : 0 ≤ c) : a / c ≤ b / c := by rw [div_eq_mul_one_div a c, div_eq_mul_one_div b c] - exact mul_le_mul_of_nonneg_right hab (one_div_nonneg (α := α) |>.2 hc) + exact mul_le_mul_of_nonneg_right hab (one_div_nonneg.2 hc) @[gcongr, bound] lemma div_lt_div_of_pos_right (h : a < b) (hc : 0 < c) : a / c < b / c := by rw [div_eq_mul_one_div a c, div_eq_mul_one_div b c] - exact mul_lt_mul_of_pos_right h (one_div_pos (α := α) |>.2 hc) + exact mul_lt_mul_of_pos_right h (one_div_pos.2 hc) -- Not a `mono` lemma b/c `div_le_div` is strictly more general @[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 @@ -262,16 +203,16 @@ 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] + rw [le_div_iff₀ d0, div_mul_eq_mul_div, div_le_iff₀ b0] @[mono, gcongr, bound] theorem div_le_div (hc : 0 ≤ c) (hac : a ≤ c) (hd : 0 < d) (hbd : d ≤ b) : a / b ≤ c / d := by @@ -302,21 +243,25 @@ theorem div_lt_self (ha : 0 < a) (hb : 1 < b) : a / b < a := by theorem le_div_self (ha : 0 ≤ a) (hb₀ : 0 < b) (hb₁ : b ≤ 1) : a ≤ a / b := by simpa only [div_one] using div_le_div_of_nonneg_left ha hb₀ hb₁ -theorem one_le_div (hb : 0 < b) : 1 ≤ a / b ↔ b ≤ a := by rw [le_div_iff hb, one_mul] +theorem one_le_div (hb : 0 < b) : 1 ≤ a / b ↔ b ≤ a := by rw [le_div_iff₀ hb, one_mul] -theorem div_le_one (hb : 0 < b) : a / b ≤ 1 ↔ a ≤ b := by rw [div_le_iff hb, one_mul] +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 @@ -328,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 @@ -368,11 +313,11 @@ theorem one_half_pos : (0 : α) < 1 / 2 := @[simp] theorem half_le_self_iff : a / 2 ≤ a ↔ 0 ≤ a := by - rw [div_le_iff (zero_lt_two' α), mul_two, le_add_iff_nonneg_left] + rw [div_le_iff₀ (zero_lt_two' α), mul_two, le_add_iff_nonneg_left] @[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 @@ -386,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, @@ -402,26 +347,26 @@ theorem add_thirds (a : α) : a / 3 + a / 3 + a / 3 = a := by simp only [div_eq_mul_inv, mul_pos_iff_of_pos_left ha, inv_pos] @[simp] lemma div_pos_iff_of_pos_right (hb : 0 < b) : 0 < a / b ↔ 0 < a := by - simp only [div_eq_mul_inv, mul_pos_iff_of_pos_right (inv_pos (α := α) |>.2 hb)] + simp only [div_eq_mul_inv, mul_pos_iff_of_pos_right (inv_pos.2 hb)] theorem mul_le_mul_of_mul_div_le (h : a * (b / c) ≤ d) (hc : 0 < c) : b * a ≤ d * c := by rw [← mul_div_assoc] at h - rwa [mul_comm b, ← div_le_iff hc] + rwa [mul_comm b, ← div_le_iff₀ hc] theorem div_mul_le_div_mul_of_div_le_div (h : a / b ≤ c / d) (he : 0 ≤ e) : a / (b * e) ≤ c / (d * e) := by rw [div_mul_eq_div_mul_one_div, div_mul_eq_div_mul_one_div] - exact mul_le_mul_of_nonneg_right h (one_div_nonneg (α := α) |>.2 he) + exact mul_le_mul_of_nonneg_right h (one_div_nonneg.2 he) 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 @@ -434,7 +379,7 @@ theorem Monotone.div_const {β : Type*} [Preorder β] {f : β → α} (hf : Mono theorem StrictMono.div_const {β : Type*} [Preorder β] {f : β → α} (hf : StrictMono f) {c : α} (hc : 0 < c) : StrictMono fun x => f x / c := by - simpa only [div_eq_mul_inv] using hf.mul_const (inv_pos (α := α) |>.2 hc) + simpa only [div_eq_mul_inv] using hf.mul_const (inv_pos.2 hc) -- see Note [lower instance priority] instance (priority := 100) LinearOrderedSemiField.toDenselyOrdered : DenselyOrdered α where @@ -460,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) : @@ -475,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 @@ -543,7 +488,7 @@ theorem div_le_iff_of_neg (hc : c < 0) : b / c ≤ a ↔ a * c ≤ b := ⟨fun h => div_mul_cancel₀ b (ne_of_lt hc) ▸ mul_le_mul_of_nonpos_right h hc.le, fun h => calc a = a * c * (1 / c) := mul_mul_div a (ne_of_lt hc) - _ ≥ b * (1 / c) := mul_le_mul_of_nonpos_right h (one_div_neg (α := α) |>.2 hc).le + _ ≥ b * (1 / c) := mul_le_mul_of_nonpos_right h (one_div_neg.2 hc).le _ = b / c := (div_eq_mul_one_div b c).symm ⟩ @@ -551,7 +496,7 @@ theorem div_le_iff_of_neg' (hc : c < 0) : b / c ≤ a ↔ c * a ≤ b := by rw [mul_comm, div_le_iff_of_neg hc] theorem le_div_iff_of_neg (hc : c < 0) : a ≤ b / c ↔ b ≤ a * c := by - rw [← neg_neg c, mul_neg, div_neg, le_neg, div_le_iff (neg_pos.2 hc), neg_mul] + rw [← neg_neg c, mul_neg, div_neg, le_neg, div_le_iff₀ (neg_pos.2 hc), neg_mul] theorem le_div_iff_of_neg' (hc : c < 0) : a ≤ b / c ↔ b ≤ c * a := by rw [mul_comm, le_div_iff_of_neg hc] @@ -569,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 -/ @@ -578,10 +523,10 @@ theorem inv_le_inv_of_neg (ha : a < 0) (hb : b < 0) : a⁻¹ ≤ b⁻¹ ↔ b rw [← one_div, div_le_iff_of_neg ha, ← div_eq_inv_mul, div_le_iff_of_neg hb, one_mul] theorem inv_le_of_neg (ha : a < 0) (hb : b < 0) : a⁻¹ ≤ b ↔ b⁻¹ ≤ a := by - rw [← inv_le_inv_of_neg hb (inv_lt_zero (α := α) |>.2 ha), inv_inv] + rw [← inv_le_inv_of_neg hb (inv_lt_zero.2 ha), inv_inv] theorem le_inv_of_neg (ha : a < 0) (hb : b < 0) : a ≤ b⁻¹ ↔ b ≤ a⁻¹ := by - rw [← inv_le_inv_of_neg (inv_lt_zero (α := α) |>.2 hb) ha, inv_inv] + rw [← inv_le_inv_of_neg (inv_lt_zero.2 hb) ha, inv_inv] theorem inv_lt_inv_of_neg (ha : a < 0) (hb : b < 0) : a⁻¹ < b⁻¹ ↔ b < a := lt_iff_lt_of_le_iff_le (inv_le_inv_of_neg hb ha) @@ -600,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) := @@ -644,11 +589,11 @@ theorem inv_antitoneOn_Icc_left (hb : b < 0) : theorem div_le_div_of_nonpos_of_le (hc : c ≤ 0) (h : b ≤ a) : a / c ≤ b / c := by rw [div_eq_mul_one_div a c, div_eq_mul_one_div b c] - exact mul_le_mul_of_nonpos_right h (one_div_nonpos (α := α) |>.2 hc) + exact mul_le_mul_of_nonpos_right h (one_div_nonpos.2 hc) theorem div_lt_div_of_neg_of_lt (hc : c < 0) (h : b < a) : a / c < b / c := by rw [div_eq_mul_one_div a c, div_eq_mul_one_div b c] - exact mul_lt_mul_of_neg_right h (one_div_neg (α := α) |>.2 hc) + exact mul_lt_mul_of_neg_right h (one_div_neg.2 hc) theorem div_le_div_right_of_neg (hc : c < 0) : a / c ≤ b / c ↔ b ≤ a := ⟨le_imp_le_of_lt_imp_lt <| div_lt_div_of_neg_of_lt hc, div_le_div_of_nonpos_of_le <| hc.le⟩ @@ -754,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/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/Pi.lean b/Mathlib/Algebra/Order/Field/Pi.lean index c0765788d3056..7100886df9c3c 100644 --- a/Mathlib/Algebra/Order/Field/Pi.lean +++ b/Mathlib/Algebra/Order/Field/Pi.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Yaël Dillies. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ +import Mathlib.Algebra.Order.Monoid.Defs import Mathlib.Data.Finset.Lattice import Mathlib.Data.Fintype.Card 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 8cb0dc8de386a..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 @@ -133,7 +121,7 @@ protected lemma Odd.zpow_nonneg_iff (hn : Odd n) : 0 ≤ a ^ n ↔ 0 ≤ a := theorem Odd.zpow_nonpos_iff (hn : Odd n) : a ^ n ≤ 0 ↔ a ≤ 0 := by rw [le_iff_lt_or_eq, le_iff_lt_or_eq, hn.zpow_neg_iff, zpow_eq_zero_iff] rintro rfl - exact Int.odd_iff_not_even.1 hn even_zero + exact Int.not_even_iff_odd.2 hn even_zero lemma Odd.zpow_pos_iff (hn : Odd n) : 0 < a ^ n ↔ 0 < a := lt_iff_lt_of_le_iff_le hn.zpow_nonpos_iff @@ -148,7 +136,7 @@ theorem Even.zpow_abs {p : ℤ} (hp : Even p) (a : α) : |a| ^ p = a ^ p := by /-- Bernoulli's inequality reformulated to estimate `(n : α)`. -/ theorem Nat.cast_le_pow_sub_div_sub (H : 1 < a) (n : ℕ) : (n : α) ≤ (a ^ n - 1) / (a - 1) := - (le_div_iff (sub_pos.2 H)).2 <| + (le_div_iff₀ (sub_pos.2 H)).2 <| le_sub_left_of_add_le <| one_add_mul_sub_le_pow ((neg_le_self zero_le_one).trans H.le) _ /-- For any `a > 1` and a natural `n` we have `n ≤ a ^ n / (a - 1)`. See also @@ -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/Unbundled/Basic.lean b/Mathlib/Algebra/Order/Field/Unbundled/Basic.lean deleted file mode 100644 index 19f180e9e1699..0000000000000 --- a/Mathlib/Algebra/Order/Field/Unbundled/Basic.lean +++ /dev/null @@ -1,63 +0,0 @@ -/- -Copyright (c) 2014 Robert Y. Lewis. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Robert Y. Lewis, Leonardo de Moura, Mario Carneiro, Floris van Doorn --/ -import Mathlib.Algebra.Field.Defs -import Mathlib.Algebra.GroupWithZero.Basic -import Mathlib.Algebra.Order.Ring.Unbundled.Basic - -/-! -# Basic facts for unbundled linear ordered (semi)fields - --/ - --- Guard against import creep. -assert_not_exists OrderedCommMonoid -assert_not_exists MonoidHom - -variable {α : Type*} - -variable [Semifield α] [LinearOrder α] [PosMulReflectLT α] [ZeroLEOneClass α] {a b : α} - -@[simp] lemma inv_pos : 0 < a⁻¹ ↔ 0 < a := - suffices ∀ a : α, 0 < a → 0 < a⁻¹ from ⟨fun h ↦ inv_inv a ▸ this _ h, this a⟩ - fun a ha ↦ flip lt_of_mul_lt_mul_left ha.le <| by simp [ne_of_gt ha, zero_lt_one] - -alias ⟨_, inv_pos_of_pos⟩ := inv_pos - -@[simp] lemma inv_nonneg : 0 ≤ a⁻¹ ↔ 0 ≤ a := by simp only [le_iff_eq_or_lt, inv_pos, zero_eq_inv] - -alias ⟨_, inv_nonneg_of_nonneg⟩ := inv_nonneg - -@[simp] lemma inv_lt_zero : 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] - -lemma one_div_pos : 0 < 1 / a ↔ 0 < a := inv_eq_one_div a ▸ inv_pos - -lemma one_div_neg : 1 / a < 0 ↔ a < 0 := inv_eq_one_div a ▸ inv_lt_zero - -lemma one_div_nonneg : 0 ≤ 1 / a ↔ 0 ≤ a := inv_eq_one_div a ▸ inv_nonneg - -lemma one_div_nonpos : 1 / a ≤ 0 ↔ a ≤ 0 := inv_eq_one_div a ▸ inv_nonpos - -lemma div_pos [PosMulStrictMono α] (ha : 0 < a) (hb : 0 < b) : 0 < a / b := by - rw [div_eq_mul_inv]; exact mul_pos ha (inv_pos.2 hb) - -lemma div_nonneg [PosMulMono α] (ha : 0 ≤ a) (hb : 0 ≤ b) : 0 ≤ a / b := by - rw [div_eq_mul_inv]; exact mul_nonneg ha (inv_nonneg.2 hb) - -lemma div_nonpos_of_nonpos_of_nonneg [MulPosMono α] (ha : a ≤ 0) (hb : 0 ≤ b) : a / b ≤ 0 := by - rw [div_eq_mul_inv]; exact mul_nonpos_of_nonpos_of_nonneg ha (inv_nonneg.2 hb) - -lemma div_nonpos_of_nonneg_of_nonpos [PosMulMono α] (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 zpow_nonneg [PosMulMono α] (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 α] (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 _ diff --git a/Mathlib/Algebra/Order/Floor.lean b/Mathlib/Algebra/Order/Floor.lean index 517130d8d4219..09bdb68063e38 100644 --- a/Mathlib/Algebra/Order/Floor.lean +++ b/Mathlib/Algebra/Order/Floor.lean @@ -9,9 +9,9 @@ import Mathlib.Algebra.Group.Int import Mathlib.Data.Int.Lemmas import Mathlib.Data.Nat.Cast.Order.Field import Mathlib.Data.Set.Subsingleton -import Mathlib.Init.Data.Nat.Lemmas import Mathlib.Order.GaloisConnection import Mathlib.Tactic.Abel +import Mathlib.Tactic.FieldSimp import Mathlib.Tactic.Linarith import Mathlib.Tactic.Positivity @@ -54,7 +54,6 @@ many lemmas. rounding, floor, ceil -/ - open Set variable {F α β : Type*} @@ -116,18 +115,25 @@ notation "⌊" a "⌋₊" => Nat.floor a @[inherit_doc] notation "⌈" a "⌉₊" => Nat.ceil a -end OrderedSemiring - -section LinearOrderedSemiring - -variable [LinearOrderedSemiring α] [FloorSemiring α] {a : α} {n : ℕ} - theorem le_floor_iff (ha : 0 ≤ a) : n ≤ ⌊a⌋₊ ↔ (n : α) ≤ a := FloorSemiring.gc_floor ha theorem le_floor (h : (n : α) ≤ a) : n ≤ ⌊a⌋₊ := (le_floor_iff <| n.cast_nonneg.trans h).2 h +theorem gc_ceil_coe : GaloisConnection (ceil : α → ℕ) (↑) := + FloorSemiring.gc_ceil + +@[simp] +theorem ceil_le : ⌈a⌉₊ ≤ n ↔ a ≤ n := + gc_ceil_coe _ _ + +end OrderedSemiring + +section LinearOrderedSemiring + +variable [LinearOrderedSemiring α] [FloorSemiring α] {a b : α} {n : ℕ} + theorem floor_lt (ha : 0 ≤ a) : ⌊a⌋₊ < n ↔ a < n := lt_iff_lt_of_le_iff_le <| le_floor_iff ha @@ -145,6 +151,7 @@ theorem floor_le (ha : 0 ≤ a) : (⌊a⌋₊ : α) ≤ a := theorem lt_succ_floor (a : α) : a < ⌊a⌋₊.succ := lt_of_floor_lt <| Nat.lt_succ_self _ +@[bound] theorem lt_floor_add_one (a : α) : a < ⌊a⌋₊ + 1 := by simpa using lt_succ_floor a @[simp] @@ -177,8 +184,7 @@ theorem floor_mono : Monotone (floor : α → ℕ) := fun a b h => by exact Nat.zero_le _ · exact le_floor ((floor_le ha).trans h) -@[gcongr] -theorem floor_le_floor : ∀ x y : α, x ≤ y → ⌊x⌋₊ ≤ ⌊y⌋₊ := floor_mono +@[gcongr, bound] lemma floor_le_floor (hab : a ≤ b) : ⌊a⌋₊ ≤ ⌊b⌋₊ := floor_mono hab theorem le_floor_iff' (hn : n ≠ 0) : n ≤ ⌊a⌋₊ ↔ (n : α) ≤ a := by obtain ha | ha := le_total a 0 @@ -242,14 +248,6 @@ theorem preimage_floor_of_ne_zero {n : ℕ} (hn : n ≠ 0) : /-! #### Ceil -/ - -theorem gc_ceil_coe : GaloisConnection (ceil : α → ℕ) (↑) := - FloorSemiring.gc_ceil - -@[simp] -theorem ceil_le : ⌈a⌉₊ ≤ n ↔ a ≤ n := - gc_ceil_coe _ _ - theorem lt_ceil : n < ⌈a⌉₊ ↔ (n : α) < a := lt_iff_lt_of_le_iff_le ceil_le @@ -262,10 +260,12 @@ theorem add_one_le_ceil_iff : n + 1 ≤ ⌈a⌉₊ ↔ (n : α) < a := by theorem one_le_ceil_iff : 1 ≤ ⌈a⌉₊ ↔ 0 < a := by rw [← zero_add 1, Nat.add_one_le_ceil_iff, Nat.cast_zero] +@[bound] theorem ceil_le_floor_add_one (a : α) : ⌈a⌉₊ ≤ ⌊a⌋₊ + 1 := by rw [ceil_le, Nat.cast_add, Nat.cast_one] exact (lt_floor_add_one a).le +@[bound] theorem le_ceil (a : α) : a ≤ ⌈a⌉₊ := ceil_le.1 le_rfl @@ -283,8 +283,7 @@ theorem ceil_natCast (n : ℕ) : ⌈(n : α)⌉₊ = n := theorem ceil_mono : Monotone (ceil : α → ℕ) := gc_ceil_coe.monotone_l -@[gcongr] -theorem ceil_le_ceil : ∀ x y : α, x ≤ y → ⌈x⌉₊ ≤ ⌈y⌉₊ := ceil_mono +@[gcongr, bound] lemma ceil_le_ceil (hab : a ≤ b) : ⌈a⌉₊ ≤ ⌈b⌉₊ := ceil_mono hab @[simp] theorem ceil_zero : ⌈(0 : α)⌉₊ = 0 := by rw [← Nat.cast_zero, ceil_natCast] @@ -308,6 +307,7 @@ theorem lt_of_ceil_lt (h : ⌈a⌉₊ < n) : a < n := theorem le_of_ceil_le (h : ⌈a⌉₊ ≤ n) : a ≤ n := (le_ceil a).trans (Nat.cast_le.2 h) +@[bound] theorem floor_le_ceil (a : α) : ⌊a⌋₊ ≤ ⌈a⌉₊ := by obtain ha | ha := le_total a 0 · rw [floor_of_nonpos ha] @@ -450,6 +450,7 @@ theorem ceil_add_ofNat (ha : 0 ≤ a) (n : ℕ) [n.AtLeastTwo] : theorem ceil_lt_add_one (ha : 0 ≤ a) : (⌈a⌉₊ : α) < a + 1 := lt_ceil.1 <| (Nat.lt_succ_self _).trans_le (ceil_add_one ha).ge +@[bound] theorem ceil_add_le (a b : α) : ⌈a + b⌉₊ ≤ ⌈a⌉₊ + ⌈b⌉₊ := by rw [ceil_le, Nat.cast_add] exact _root_.add_le_add (le_ceil _) (le_ceil _) @@ -460,6 +461,7 @@ section LinearOrderedRing variable [LinearOrderedRing α] [FloorSemiring α] +@[bound] theorem sub_one_lt_floor (a : α) : a - 1 < ⌊a⌋₊ := sub_lt_iff_lt_add.2 <| lt_floor_add_one a @@ -482,7 +484,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 @@ -498,6 +500,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. -/ @@ -558,7 +600,7 @@ def FloorRing.ofCeil (α) [LinearOrderedRing α] (ceil : α → ℤ) namespace Int -variable [LinearOrderedRing α] [FloorRing α] {z : ℤ} {a : α} +variable [LinearOrderedRing α] [FloorRing α] {z : ℤ} {a b : α} /-- `Int.floor a` is the greatest integer `z` such that `z ≤ a`. It is denoted with `⌊a⌋`. -/ def floor : α → ℤ := @@ -611,6 +653,7 @@ theorem le_floor : z ≤ ⌊a⌋ ↔ (z : α) ≤ a := theorem floor_lt : ⌊a⌋ < z ↔ a < z := lt_iff_lt_of_le_iff_le le_floor +@[bound] theorem floor_le (a : α) : (⌊a⌋ : α) ≤ a := gc_coe_floor.l_u_le a @@ -623,6 +666,7 @@ theorem floor_le_sub_one_iff : ⌊a⌋ ≤ z - 1 ↔ a < z := by rw [← floor_l theorem floor_le_neg_one_iff : ⌊a⌋ ≤ -1 ↔ a < 0 := by rw [← zero_sub (1 : ℤ), floor_le_sub_one_iff, cast_zero] +@[bound] theorem floor_nonpos (ha : a ≤ 0) : ⌊a⌋ ≤ 0 := by rw [← @cast_le α, Int.cast_zero] exact (floor_le a).trans ha @@ -630,11 +674,11 @@ theorem floor_nonpos (ha : a ≤ 0) : ⌊a⌋ ≤ 0 := by theorem lt_succ_floor (a : α) : a < ⌊a⌋.succ := floor_lt.1 <| Int.lt_succ_self _ -@[simp] +@[simp, bound] theorem lt_floor_add_one (a : α) : a < ⌊a⌋ + 1 := by simpa only [Int.succ, Int.cast_add, Int.cast_one] using lt_succ_floor a -@[simp] +@[simp, bound] theorem sub_one_lt_floor (a : α) : a - 1 < ⌊a⌋ := sub_lt_iff_lt_add.2 (lt_floor_add_one a) @@ -660,8 +704,7 @@ theorem floor_one : ⌊(1 : α)⌋ = 1 := by rw [← cast_one, floor_intCast] theorem floor_mono : Monotone (floor : α → ℤ) := gc_coe_floor.monotone_u -@[gcongr] -theorem floor_le_floor : ∀ x y : α, x ≤ y → ⌊x⌋ ≤ ⌊y⌋ := floor_mono +@[gcongr, bound] lemma floor_le_floor (hab : a ≤ b) : ⌊a⌋ ≤ ⌊b⌋ := floor_mono hab theorem floor_pos : 0 < ⌊a⌋ ↔ 1 ≤ a := by -- Porting note: broken `convert le_floor` @@ -677,10 +720,12 @@ theorem floor_add_one (a : α) : ⌊a + 1⌋ = ⌊a⌋ + 1 := by -- Porting note: broken `convert floor_add_int a 1` rw [← cast_one, floor_add_int] +@[bound] theorem le_floor_add (a b : α) : ⌊a⌋ + ⌊b⌋ ≤ ⌊a + b⌋ := by rw [le_floor, Int.cast_add] exact add_le_add (floor_le _) (floor_le _) +@[bound] theorem le_floor_add_floor (a b : α) : ⌊a + b⌋ - 1 ≤ ⌊a⌋ + ⌊b⌋ := by rw [← sub_le_iff_le_add, le_floor, Int.cast_sub, sub_le_comm, Int.cast_sub, Int.cast_one] refine le_trans ?_ (sub_one_lt_floor _).le @@ -932,7 +977,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 @@ -977,12 +1022,12 @@ theorem fract_div_mul_self_add_zsmul_eq (a b : k) (ha : a ≠ 0) : rw [zsmul_eq_mul, ← add_mul, fract_add_floor, div_mul_cancel₀ b ha] theorem sub_floor_div_mul_nonneg (a : k) (hb : 0 < b) : 0 ≤ a - ⌊a / b⌋ * b := - sub_nonneg_of_le <| (le_div_iff hb).1 <| floor_le _ + sub_nonneg_of_le <| (le_div_iff₀ hb).1 <| floor_le _ 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 @@ -1009,13 +1054,13 @@ 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)⌉ let m₁ := q * ↑n - (↑m₀ : ℤ) have hm₁ : 0 ≤ m₁ := by - simpa [m₁, ← @cast_le k, ← div_le_iff hn] using FloorRing.gc_ceil_coe.le_u_l _ + simpa [m₁, ← @cast_le k, ← div_le_iff₀ hn] using FloorRing.gc_ceil_coe.le_u_l _ calc fract ((Int.cast (-(m₀ : ℤ)) : k) / (n : k)) -- Porting note: the `rw [cast_neg, cast_natCast]` was `push_cast` @@ -1057,6 +1102,7 @@ theorem add_one_le_ceil_iff : z + 1 ≤ ⌈a⌉ ↔ (z : α) < a := by rw [← l theorem one_le_ceil_iff : 1 ≤ ⌈a⌉ ↔ 0 < a := by rw [← zero_add (1 : ℤ), add_one_le_ceil_iff, cast_zero] +@[bound] theorem ceil_le_floor_add_one (a : α) : ⌈a⌉ ≤ ⌊a⌋ + 1 := by rw [ceil_le, Int.cast_add, Int.cast_one] exact (lt_floor_add_one a).le @@ -1065,6 +1111,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] @@ -1080,8 +1129,7 @@ theorem ceil_ofNat (n : ℕ) [n.AtLeastTwo] : ⌈(no_index (OfNat.ofNat n : α)) theorem ceil_mono : Monotone (ceil : α → ℤ) := gc_ceil_coe.monotone_l -@[gcongr] -theorem ceil_le_ceil : ∀ x y : α, x ≤ y → ⌈x⌉ ≤ ⌈y⌉ := ceil_mono +@[gcongr, bound] lemma ceil_le_ceil (hab : a ≤ b) : ⌈a⌉ ≤ ⌈b⌉ := ceil_mono hab @[simp] theorem ceil_add_int (a : α) (z : ℤ) : ⌈a + z⌉ = ⌈a⌉ + z := by @@ -1120,14 +1168,17 @@ theorem ceil_sub_ofNat (a : α) (n : ℕ) [n.AtLeastTwo] : ⌈a - (no_index (OfNat.ofNat n))⌉ = ⌈a⌉ - OfNat.ofNat n := ceil_sub_nat a n +@[bound] theorem ceil_lt_add_one (a : α) : (⌈a⌉ : α) < a + 1 := by rw [← lt_ceil, ← Int.cast_one, ceil_add_int] apply lt_add_one +@[bound] theorem ceil_add_le (a b : α) : ⌈a + b⌉ ≤ ⌈a⌉ + ⌈b⌉ := by rw [ceil_le, Int.cast_add] exact add_le_add (le_ceil _) (le_ceil _) +@[bound] theorem ceil_add_ceil_le (a b : α) : ⌈a⌉ + ⌈b⌉ ≤ ⌈a + b⌉ + 1 := by rw [← le_sub_iff_add_le, ceil_le, Int.cast_sub, Int.cast_add, Int.cast_one, le_sub_comm] refine (ceil_lt_add_one _).le.trans ?_ @@ -1143,6 +1194,7 @@ theorem ceil_zero : ⌈(0 : α)⌉ = 0 := by rw [← cast_zero, ceil_intCast] @[simp] theorem ceil_one : ⌈(1 : α)⌉ = 1 := by rw [← cast_one, ceil_intCast] +@[bound] theorem ceil_nonneg (ha : 0 ≤ a) : 0 ≤ ⌈a⌉ := mod_cast ha.trans (le_ceil a) theorem ceil_eq_iff : ⌈a⌉ = z ↔ ↑z - 1 < a ∧ a ≤ z := by @@ -1158,9 +1210,11 @@ theorem ceil_eq_on_Ioc (z : ℤ) : ∀ a ∈ Set.Ioc (z - 1 : α) z, ⌈a⌉ = z theorem ceil_eq_on_Ioc' (z : ℤ) : ∀ a ∈ Set.Ioc (z - 1 : α) z, (⌈a⌉ : α) = z := fun a ha => mod_cast ceil_eq_on_Ioc z a ha +@[bound] theorem floor_le_ceil (a : α) : ⌊a⌋ ≤ ⌈a⌉ := cast_le.1 <| (floor_le _).trans <| le_ceil _ +@[bound] theorem floor_lt_ceil_of_lt {a b : α} (h : a < b) : ⌊a⌋ < ⌈b⌉ := cast_lt.1 <| (floor_le a).trans_lt <| h.trans_le <| le_ceil b @@ -1190,6 +1244,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] @@ -1349,7 +1453,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] @@ -1397,10 +1501,12 @@ theorem abs_sub_round_div_natCast_eq {m n : ℕ} : rw [abs_sub_round_eq_min, Nat.cast_min, ← min_div_div_right hn'.le, fract_div_natCast_eq_div_natCast_mod, Nat.cast_sub (m.mod_lt hn).le, sub_div, div_self hn'.ne'] +@[bound] theorem sub_half_lt_round (x : α) : x - 1 / 2 < round x := by rw [round_eq x, show x - 1 / 2 = x + 1 / 2 - 1 by nlinarith] exact Int.sub_one_lt_floor (x + 1 / 2) +@[bound] theorem round_le_add_half (x : α) : round x ≤ x + 1 / 2 := by rw [round_eq x] exact Int.floor_le (x + 1 / 2) @@ -1498,26 +1604,20 @@ theorem Nat.ceil_int : (Nat.ceil : ℤ → ℕ) = Int.toNat := variable {a : α} -theorem Int.ofNat_floor_eq_floor (ha : 0 ≤ a) : (⌊a⌋₊ : ℤ) = ⌊a⌋ := by +theorem Int.natCast_floor_eq_floor (ha : 0 ≤ a) : (⌊a⌋₊ : ℤ) = ⌊a⌋ := by rw [← Int.floor_toNat, Int.toNat_of_nonneg (Int.floor_nonneg.2 ha)] -theorem Int.ofNat_ceil_eq_ceil (ha : 0 ≤ a) : (⌈a⌉₊ : ℤ) = ⌈a⌉ := by +theorem Int.natCast_ceil_eq_ceil (ha : 0 ≤ a) : (⌈a⌉₊ : ℤ) = ⌈a⌉ := by rw [← Int.ceil_toNat, Int.toNat_of_nonneg (Int.ceil_nonneg ha)] theorem natCast_floor_eq_intCast_floor (ha : 0 ≤ a) : (⌊a⌋₊ : α) = ⌊a⌋ := by - rw [← Int.ofNat_floor_eq_floor ha, Int.cast_natCast] - -theorem natCast_ceil_eq_intCast_ceil (ha : 0 ≤ a) : (⌈a⌉₊ : α) = ⌈a⌉ := by - rw [← Int.ofNat_ceil_eq_ceil ha, Int.cast_natCast] + rw [← Int.natCast_floor_eq_floor ha, Int.cast_natCast] -@[deprecated (since := "2024-02-14")] alias Nat.cast_floor_eq_int_floor := Int.ofNat_floor_eq_floor -@[deprecated (since := "2024-02-14")] alias Nat.cast_ceil_eq_int_ceil := Int.ofNat_ceil_eq_ceil +theorem natCast_ceil_eq_intCast_ceil (ha : 0 ≤ a) : (⌈a⌉₊ : α) = ⌈a⌉ := by + rw [← Int.natCast_ceil_eq_ceil ha, Int.cast_natCast] -@[deprecated (since := "2024-02-14")] -alias Nat.cast_floor_eq_cast_int_floor := natCast_floor_eq_intCast_floor - -@[deprecated (since := "2024-02-14")] -alias Nat.cast_ceil_eq_cast_int_ceil := natCast_ceil_eq_intCast_ceil +@[deprecated (since := "2024-08-20")] alias Int.ofNat_floor_eq_floor := natCast_floor_eq_floor +@[deprecated (since := "2024-08-20")] alias Int.ofNat_ceil_eq_ceil := natCast_ceil_eq_ceil end FloorRingToSemiring @@ -1593,3 +1693,5 @@ def evalIntCeil : PositivityExt where eval {u α} _zα _pα e := do | _, _, _ => throwError "failed to match on Int.ceil application" end Mathlib.Meta.Positivity + +set_option linter.style.longFile 1800 diff --git a/Mathlib/Algebra/Order/Floor/Div.lean b/Mathlib/Algebra/Order/Floor/Div.lean index 33bc2b55c54a5..20b853e6e5f94 100644 --- a/Mathlib/Algebra/Order/Floor/Div.lean +++ b/Mathlib/Algebra/Order/Floor/Div.lean @@ -119,12 +119,12 @@ 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 · simp [ha] - · exact le_of_smul_le_smul_left ((smul_floorDiv_le ha).trans $ le_smul_ceilDiv ha) ha + · exact le_of_smul_le_smul_left ((smul_floorDiv_le ha).trans <| le_smul_ceilDiv ha) ha end LinearOrderedAddCommMonoid @@ -135,11 +135,11 @@ section FloorDiv variable [FloorDiv α β] {a : α} @[simp] lemma floorDiv_one [Nontrivial α] (b : β) : b ⌊/⌋ (1 : α) = b := - eq_of_forall_le_iff $ fun c ↦ by simp [zero_lt_one' α] + eq_of_forall_le_iff <| fun c ↦ by simp [zero_lt_one' α] @[simp] lemma smul_floorDiv [PosSMulMono α β] [PosSMulReflectLE α β] (ha : 0 < a) (b : β) : a • b ⌊/⌋ a = b := - eq_of_forall_le_iff $ by simp [smul_le_smul_iff_of_pos_left, ha] + eq_of_forall_le_iff <| by simp [smul_le_smul_iff_of_pos_left, ha] end FloorDiv @@ -147,11 +147,11 @@ section CeilDiv variable [CeilDiv α β] {a : α} @[simp] lemma ceilDiv_one [Nontrivial α] (b : β) : b ⌈/⌉ (1 : α) = b := - eq_of_forall_ge_iff $ fun c ↦ by simp [zero_lt_one' α] + eq_of_forall_ge_iff <| fun c ↦ by simp [zero_lt_one' α] @[simp] lemma smul_ceilDiv [PosSMulMono α β] [PosSMulReflectLE α β] (ha : 0 < a) (b : β) : a • b ⌈/⌉ a = b := - eq_of_forall_ge_iff $ by simp [smul_le_smul_iff_of_pos_left, ha] + eq_of_forall_ge_iff <| by simp [smul_le_smul_iff_of_pos_left, ha] end CeilDiv @@ -177,14 +177,14 @@ namespace Nat instance instFloorDiv : FloorDiv ℕ ℕ where floorDiv := HDiv.hDiv floorDiv_gc a ha := by simpa [mul_comm] using Nat.galoisConnection_mul_div ha - floorDiv_nonpos a ha b := by rw [ha.antisymm $ zero_le _, Nat.div_zero] + floorDiv_nonpos a ha b := by rw [ha.antisymm <| zero_le _, Nat.div_zero] zero_floorDiv := Nat.zero_div instance instCeilDiv : CeilDiv ℕ ℕ where ceilDiv a b := (a + b - 1) / b ceilDiv_gc a ha b c := by - simp [div_le_iff_le_mul_add_pred ha, add_assoc, tsub_add_cancel_of_le $ succ_le_iff.2 ha] - ceilDiv_nonpos a ha b := by simp_rw [ha.antisymm $ zero_le _, Nat.div_zero] + simp [div_le_iff_le_mul_add_pred ha, add_assoc, tsub_add_cancel_of_le <| succ_le_iff.2 ha] + ceilDiv_nonpos a ha b := by simp_rw [ha.antisymm <| zero_le _, Nat.div_zero] zero_ceilDiv a := by cases a <;> simp [Nat.div_eq_zero_iff] @[simp] lemma floorDiv_eq_div (a b : ℕ) : a ⌊/⌋ b = a / b := rfl diff --git a/Mathlib/Algebra/Order/Floor/Prime.lean b/Mathlib/Algebra/Order/Floor/Prime.lean index 6c418d3d3d34b..f3545648ae511 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.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..9693c189cfb6c 100644 --- a/Mathlib/Algebra/Order/Group/Abs.lean +++ b/Mathlib/Algebra/Order/Group/Abs.lean @@ -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/Action/Synonym.lean b/Mathlib/Algebra/Order/Group/Action/Synonym.lean new file mode 100644 index 0000000000000..9a2ab42258ab9 --- /dev/null +++ b/Mathlib/Algebra/Order/Group/Action/Synonym.lean @@ -0,0 +1,88 @@ +/- +Copyright (c) 2021 Yaël Dillies. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yaël Dillies +-/ +import Mathlib.Algebra.Group.Action.Defs +import Mathlib.Algebra.Order.Group.Synonym + +/-! +# Actions by and on order synonyms + +This PR transfers group action instances from a type `α` to `αᵒᵈ` and `Lex α`. + +## See also + +* `Mathlib.Algebra.Order.GroupWithZero.Action.Synonym` +* `Mathlib.Algebra.Order.Module.Synonym` +-/ + +variable {M N α : Type*} + +namespace OrderDual + +@[to_additive] +instance instMulAction [Monoid M] [MulAction M α] : MulAction Mᵒᵈ α := ‹MulAction M α› + +@[to_additive] +instance instMulAction' [Monoid M] [MulAction M α] : MulAction M αᵒᵈ := ‹MulAction M α› + +@[to_additive] +instance instSMulCommClass [SMul M α] [SMul N α] [SMulCommClass M N α] : SMulCommClass Mᵒᵈ N α := + ‹SMulCommClass M N α› + +@[to_additive] +instance instSMulCommClass' [SMul M α] [SMul N α] [SMulCommClass M N α] : SMulCommClass M Nᵒᵈ α := + ‹SMulCommClass M N α› + +@[to_additive] +instance instSMulCommClass'' [SMul M α] [SMul N α] [SMulCommClass M N α] : SMulCommClass M N αᵒᵈ := + ‹SMulCommClass M N α› + +@[to_additive instVAddAssocClass] +instance instIsScalarTower [SMul M N] [SMul M α] [SMul N α] [IsScalarTower M N α] : + IsScalarTower Mᵒᵈ N α := ‹IsScalarTower M N α› + +@[to_additive instVAddAssocClass'] +instance instIsScalarTower' [SMul M N] [SMul M α] [SMul N α] [IsScalarTower M N α] : + IsScalarTower M Nᵒᵈ α := ‹IsScalarTower M N α› + +@[to_additive instVAddAssocClass''] +instance instIsScalarTower'' [SMul M N] [SMul M α] [SMul N α] [IsScalarTower M N α] : + IsScalarTower M N αᵒᵈ := ‹IsScalarTower M N α› + +end OrderDual + +namespace Lex + +@[to_additive] +instance instMulAction [Monoid M] [MulAction M α] : MulAction (Lex M) α := ‹MulAction M α› + +@[to_additive] +instance instMulAction' [Monoid M] [MulAction M α] : MulAction M (Lex α) := ‹MulAction M α› + +@[to_additive] +instance instSMulCommClass [SMul M α] [SMul N α] [SMulCommClass M N α] : + SMulCommClass (Lex M) N α := ‹SMulCommClass M N α› + +@[to_additive] +instance instSMulCommClass' [SMul M α] [SMul N α] [SMulCommClass M N α] : + SMulCommClass M (Lex N) α := ‹SMulCommClass M N α› + +@[to_additive] +instance instSMulCommClass'' [SMul M α] [SMul N α] [SMulCommClass M N α] : + SMulCommClass M N (Lex α) := ‹SMulCommClass M N α› + +@[to_additive instVAddAssocClass] +instance instIsScalarTower [SMul M N] [SMul M α] [SMul N α] [IsScalarTower M N α] : + IsScalarTower (Lex M) N α := ‹IsScalarTower M N α› + +@[to_additive instVAddAssocClass'] +instance instIsScalarTower' [SMul M N] [SMul M α] [SMul N α] [IsScalarTower M N α] : + IsScalarTower M (Lex N) α := ‹IsScalarTower M N α› + +@[to_additive instVAddAssocClass''] +instance instIsScalarTower'' [SMul M N] [SMul M α] [SMul N α] [IsScalarTower M N α] : + IsScalarTower M N (Lex α) := ‹IsScalarTower M N α› + +end Lex diff --git a/Mathlib/Algebra/Order/Group/Basic.lean b/Mathlib/Algebra/Order/Group/Basic.lean index 09aeb718a03a4..bc99b34b1b895 100644 --- a/Mathlib/Algebra/Order/Group/Basic.lean +++ b/Mathlib/Algebra/Order/Group/Basic.lean @@ -20,26 +20,32 @@ variable {α M R : 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 @@ -89,7 +95,7 @@ that here because importing that definition would create import cycles."] lemma zpow_left_injective (hn : n ≠ 0) : Injective ((· ^ n) : α → α) := by obtain hn | hn := hn.lt_or_lt · refine fun a b (hab : a ^ n = b ^ n) ↦ - (zpow_strictMono_left _ $ Int.neg_pos_of_neg hn).injective ?_ + (zpow_strictMono_left _ <| Int.neg_pos_of_neg hn).injective ?_ rw [zpow_neg, zpow_neg, hab] · exact (zpow_strictMono_left _ hn).injective @@ -102,4 +108,26 @@ lemma zpow_left_inj (hn : n ≠ 0) : a ^ n = b ^ n ↔ a = b := (zpow_left_injec `zsmul_lt_zsmul_iff'`."] lemma zpow_eq_zpow_iff' (hn : n ≠ 0) : a ^ n = b ^ n ↔ a = b := zpow_left_inj hn +variable (α) in +/-- A nontrivial densely linear ordered commutative group can't be a cyclic group. -/ +@[to_additive + "A nontrivial densely linear ordered additive commutative group can't be a cyclic group."] +theorem not_isCyclic_of_denselyOrdered [DenselyOrdered α] [Nontrivial α] : ¬IsCyclic α := by + intro h + rcases exists_zpow_surjective α with ⟨a, ha⟩ + rcases lt_trichotomy a 1 with hlt | rfl | hlt + · rcases exists_between hlt with ⟨b, hab, hb⟩ + rcases ha b with ⟨k, rfl⟩ + suffices 0 < k ∧ k < 1 by omega + rw [← one_lt_inv'] at hlt + simp_rw [← zpow_lt_zpow_iff hlt] + simp_all + · rcases exists_ne (1 : α) with ⟨b, hb⟩ + simpa [hb.symm] using ha b + · rcases exists_between hlt with ⟨b, hb, hba⟩ + rcases ha b with ⟨k, rfl⟩ + suffices 0 < k ∧ k < 1 by omega + simp_rw [← zpow_lt_zpow_iff hlt] + simp_all + end LinearOrderedCommGroup diff --git a/Mathlib/Algebra/Order/Group/CompleteLattice.lean b/Mathlib/Algebra/Order/Group/CompleteLattice.lean new file mode 100644 index 0000000000000..19c8f5fda8e68 --- /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.Basic + +/-! +# Distributivity of group operations over supremum/infimum +-/ + +open Function Set + +variable {ι G : Type*} [Group G] [ConditionallyCompleteLattice G] [Nonempty ι] {f : ι → G} + +section Right +variable [CovariantClass G G (swap (· * ·)) (· ≤ ·)] + +@[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 [CovariantClass G 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 fd0738f924ca8..6d794594f08df 100644 --- a/Mathlib/Algebra/Order/Group/Cone.lean +++ b/Mathlib/Algebra/Order/Group/Cone.lean @@ -1,85 +1,120 @@ /- 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 +Authors: Mario Carneiro, Kim Morrison, Artie Khovanov -/ import Mathlib.Algebra.Order.Group.Defs +import Mathlib.Algebra.Order.Monoid.Submonoid /-! -# Construct ordered groups from positive cones +# Construct ordered groups from groups with a specified positive cone. -In this file we provide structures `PositiveCone` and `TotalPositiveCone` -that encode axioms of `OrderedAddCommGroup` and `LinearOrderedAddCommGroup` -in terms of the `(0 ≤ ·)` predicate. +In this file we provide the structure `GroupCone` and the predicate `IsMaxCone` +that encode axioms of `OrderedCommGroup` and `LinearOrderedCommGroup` +in terms of the subset of non-negative elements. -We also provide two constructors, -`OrderedAddCommGroup.mkOfPositiveCone` and `LinearOrderedAddCommGroup.mkOfPositiveCone`, -that turn these structures into instances of the corresponding typeclasses. +We also provide constructors that convert between +cones in groups and the corresponding ordered groups. -/ -namespace AddCommGroup - -/-- A collection of elements in an `AddCommGroup` designated as "non-negative". -This is useful for constructing an `OrderedAddCommGroup` -by choosing a positive cone in an existing `AddCommGroup`. -/ --- Porting note(#5171): @[nolint has_nonempty_instance] -structure PositiveCone (α : Type*) [AddCommGroup α] where - /-- The characteristic predicate of a positive cone. `nonneg a` means that `0 ≤ a` according to - the cone. -/ - nonneg : α → Prop - /-- The characteristic predicate of a positive cone. `pos a` means that `0 < a` according to - the cone. -/ - pos : α → Prop := fun a => nonneg a ∧ ¬nonneg (-a) - pos_iff : ∀ a, pos a ↔ nonneg a ∧ ¬nonneg (-a) := by intros; rfl - zero_nonneg : nonneg 0 - add_nonneg : ∀ {a b}, nonneg a → nonneg b → nonneg (a + b) - nonneg_antisymm : ∀ {a}, nonneg a → nonneg (-a) → a = 0 - -/-- A positive cone in an `AddCommGroup` induces a linear order if -for every `a`, either `a` or `-a` is non-negative. -/ --- Porting note(#5171): @[nolint has_nonempty_instance] -structure TotalPositiveCone (α : Type*) [AddCommGroup α] extends PositiveCone α where - /-- For any `a` the proposition `nonneg a` is decidable -/ - nonnegDecidable : DecidablePred nonneg - /-- Either `a` or `-a` is `nonneg` -/ - nonneg_total : ∀ a : α, nonneg a ∨ nonneg (-a) - -/-- Forget that a `TotalPositiveCone` is total. -/ -add_decl_doc TotalPositiveCone.toPositiveCone - -end AddCommGroup - -namespace OrderedAddCommGroup - -open AddCommGroup - -/-- Construct an `OrderedAddCommGroup` by -designating a positive cone in an existing `AddCommGroup`. -/ -def mkOfPositiveCone {α : Type*} [AddCommGroup α] (C : PositiveCone α) : OrderedAddCommGroup α := - { ‹AddCommGroup α› with - le := fun a b => C.nonneg (b - a), - lt := fun a b => C.pos (b - a), - lt_iff_le_not_le := fun a b => by simp [C.pos_iff], - le_refl := fun a => by simp [C.zero_nonneg], - le_trans := fun a b c nab nbc => by simpa using C.add_nonneg nbc nab, - le_antisymm := fun a b nab nba => - eq_of_sub_eq_zero <| C.nonneg_antisymm nba (by rwa [neg_sub]), - add_le_add_left := fun a b nab c => by simpa using nab } - -end OrderedAddCommGroup - -namespace LinearOrderedAddCommGroup - -open AddCommGroup - -/-- Construct a `LinearOrderedAddCommGroup` by -designating a positive cone in an existing `AddCommGroup` -such that for every `a`, either `a` or `-a` is non-negative. -/ -def mkOfPositiveCone {α : Type*} [AddCommGroup α] (C : TotalPositiveCone α) : - LinearOrderedAddCommGroup α := - { OrderedAddCommGroup.mkOfPositiveCone C.toPositiveCone with - -- Porting note: was `C.nonneg_total (b - a)` - le_total := fun a b => by simpa [neg_sub] using C.nonneg_total (b - a) - decidableLE := fun a b => C.nonnegDecidable _ } - -end LinearOrderedAddCommGroup +/-- `AddGroupConeClass S G` says that `S` is a type of cones in `G`. -/ +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 : 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 + +export GroupConeClass (eq_one_of_mem_of_inv_mem) +export AddGroupConeClass (eq_zero_of_mem_of_neg_mem) + +/-- A (positive) cone in an abelian group is a submonoid that +does not contain both `a` and `-a` for any nonzero `a`. +This is equivalent to being the set of non-negative elements of +some order making the group into a partially ordered group. -/ +structure AddGroupCone (G : Type*) [AddCommGroup G] extends AddSubmonoid G where + eq_zero_of_mem_of_neg_mem' {a} : a ∈ carrier → -a ∈ carrier → a = 0 + +/-- A (positive) cone in an abelian group is a submonoid that +does not contain both `a` and `a⁻¹` for any non-identity `a`. +This is equivalent to being the set of elements that are at least 1 in +some order making the group into a partially ordered group. -/ +@[to_additive] +structure GroupCone (G : Type*) [CommGroup G] extends Submonoid G where + eq_one_of_mem_of_inv_mem' {a} : a ∈ carrier → a⁻¹ ∈ carrier → a = 1 + +@[to_additive] +instance GroupCone.instSetLike (G : Type*) [CommGroup G] : SetLike (GroupCone G) G where + coe C := C.carrier + coe_injective' p q h := by cases p; cases q; congr; exact SetLike.ext' h + +@[to_additive] +instance GroupCone.instGroupConeClass (G : Type*) [CommGroup G] : + GroupConeClass (GroupCone G) G where + mul_mem {C} := C.mul_mem' + one_mem {C} := C.one_mem' + eq_one_of_mem_of_inv_mem {C} := C.eq_one_of_mem_of_inv_mem' + +/-- Typeclass for maximal additive cones. -/ +class IsMaxCone {S G : Type*} [AddCommGroup G] [SetLike S G] (C : S) : Prop where + mem_or_neg_mem (a : G) : a ∈ C ∨ -a ∈ C + +/-- Typeclass for maximal multiplicative cones. -/ +@[to_additive IsMaxCone] +class IsMaxMulCone {S G : Type*} [CommGroup G] [SetLike S G] (C : S) : Prop where + mem_or_inv_mem (a : G) : a ∈ C ∨ a⁻¹ ∈ C + +export IsMaxCone (mem_or_neg_mem) +export IsMaxMulCone (mem_or_inv_mem) + +namespace GroupCone +variable {H : Type*} [OrderedCommGroup H] {a : H} + +variable (H) in +/-- Construct a cone from the set of elements of +a partially ordered abelian group that are at least 1. -/ +@[to_additive nonneg +"Construct a cone from the set of non-negative elements of a partially ordered abelian group."] +def oneLE : GroupCone H where + __ := Submonoid.oneLE H + eq_one_of_mem_of_inv_mem' {a} := by simpa using ge_antisymm + +@[to_additive (attr := simp) nonneg_toAddSubmonoid] +lemma oneLE_toSubmonoid : (oneLE H).toSubmonoid = .oneLE H := rfl +@[to_additive (attr := simp) mem_nonneg] +lemma mem_oneLE : a ∈ oneLE H ↔ 1 ≤ a := Iff.rfl +@[to_additive (attr := simp, norm_cast) coe_nonneg] +lemma coe_oneLE : oneLE H = {x : H | 1 ≤ x} := rfl + +@[to_additive nonneg.isMaxCone] +instance oneLE.isMaxMulCone {H : Type*} [LinearOrderedCommGroup H] : IsMaxMulCone (oneLE H) where + mem_or_inv_mem := by simpa using le_total 1 + +end GroupCone + +variable {S G : Type*} [CommGroup G] [SetLike S G] (C : S) + +/-- Construct a partially ordered abelian group by designating a cone in an abelian group. -/ +@[to_additive (attr := reducible) +"Construct a partially ordered abelian group by designating a cone in an abelian group."] +def OrderedCommGroup.mkOfCone [GroupConeClass S G] : + OrderedCommGroup G where + le a b := b / a ∈ C + le_refl a := by simp [one_mem] + le_trans a b c nab nbc := by simpa using mul_mem nbc nab + le_antisymm a b nab nba := by + simpa [div_eq_one, eq_comm] using eq_one_of_mem_of_inv_mem nab (by simpa using nba) + mul_le_mul_left a b nab c := by simpa using nab + +/-- Construct a linearly ordered abelian group by designating a maximal cone in an abelian group. -/ +@[to_additive (attr := reducible) +"Construct a linearly ordered abelian group by designating a maximal cone in an abelian group."] +def LinearOrderedCommGroup.mkOfCone + [GroupConeClass S G] [IsMaxMulCone C] (dec : DecidablePred (· ∈ C)) : + LinearOrderedCommGroup G where + __ := OrderedCommGroup.mkOfCone C + le_total a b := by simpa using mem_or_inv_mem (b / a) + decidableLE a b := dec _ diff --git a/Mathlib/Algebra/Order/Group/Defs.lean b/Mathlib/Algebra/Order/Group/Defs.lean index c486a4984cd8a..53b53337c45d3 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 @@ -170,18 +170,16 @@ end LinearOrderedCommGroup section NormNumLemmas /- The following lemmas are stated so that the `norm_num` tactic can use them with the -expected signatures. -/ +expected signatures. -/ 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..2e25d60a9f7e1 100644 --- a/Mathlib/Algebra/Order/Group/DenselyOrdered.lean +++ b/Mathlib/Algebra/Order/Group/DenselyOrdered.lean @@ -18,7 +18,7 @@ section DenselyOrdered variable [Group α] [LinearOrder α] variable [CovariantClass α α (· * ·) (· ≤ ·)] -variable [DenselyOrdered α] {a b c : α} +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 85070045eaeab..a8e229c800374 100644 --- a/Mathlib/Algebra/Order/Group/Indicator.lean +++ b/Mathlib/Algebra/Order/Group/Indicator.lean @@ -102,17 +102,29 @@ lemma mulIndicator_le_one (h : ∀ a ∈ s, f a ≤ 1) (a : α) : mulIndicator s mulIndicator_apply_le_one (h a) @[to_additive] +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 (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 := @@ -169,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/MinMax.lean b/Mathlib/Algebra/Order/Group/MinMax.lean index 4e53be43c3ca4..adf6af1c4b904 100644 --- a/Mathlib/Algebra/Order/Group/MinMax.lean +++ b/Mathlib/Algebra/Order/Group/MinMax.lean @@ -30,7 +30,7 @@ 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)⁻¹ := @@ -64,7 +64,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/Pointwise/Bounds.lean b/Mathlib/Algebra/Order/Group/Pointwise/Bounds.lean new file mode 100644 index 0000000000000..1b1e0d3b70882 --- /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] [CovariantClass M M (· * ·) (· ≤ ·)] + [CovariantClass M M (swap (· * ·)) (· ≤ ·)] {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] [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 diff --git a/Mathlib/Algebra/Order/Group/Pointwise/CompleteLattice.lean b/Mathlib/Algebra/Order/Group/Pointwise/CompleteLattice.lean new file mode 100644 index 0000000000000..6f09d373cffd4 --- /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.Basic + +/-! +# 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] [CovariantClass M M (· * ·) (· ≤ ·)] [CovariantClass M M (swap (· * ·)) (· ≤ ·)] + {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] [CovariantClass M M (· * ·) (· ≤ ·)] [CovariantClass M M (swap (· * ·)) (· ≤ ·)] + (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 8afd1f0c6ea35..8374c0a8ed405 100644 --- a/Mathlib/Algebra/Order/Group/PosPart.lean +++ b/Mathlib/Algebra/Order/Group/PosPart.lean @@ -49,7 +49,7 @@ 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 @@ -130,6 +130,16 @@ lemma leOnePart_eq_one : a⁻ᵐ = 1 ↔ 1 ≤ a := by simp [leOnePart_eq_one'] @[to_additive (attr := simp)] lemma leOnePart_div_oneLePart (a : α) : a⁻ᵐ / a⁺ᵐ = a⁻¹ := by rw [← inv_div, oneLePart_div_leOnePart] +@[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 covariantmulop variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)] @@ -200,18 +210,20 @@ 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] @[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 + 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 +@[to_additive (attr := simp)] lemma oneLePart_lt : a⁺ᵐ < b ↔ a < b ∧ 1 < b := sup_lt_iff + section covariantmul variable [CovariantClass α α (· * ·) (· ≤ ·)] @@ -219,18 +231,23 @@ variable [CovariantClass α α (· * ·) (· ≤ ·)] simp_rw [← one_le_inv']; rw [leOnePart, ← 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 + lt_iff_lt_of_le_iff_le <| (one_le_leOnePart _).le_iff_eq.trans leOnePart_eq_one + +variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)] + +@[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/Synonym.lean b/Mathlib/Algebra/Order/Group/Synonym.lean index 9a7dede0c96ec..03750731b0ab9 100644 --- a/Mathlib/Algebra/Order/Group/Synonym.lean +++ b/Mathlib/Algebra/Order/Group/Synonym.lean @@ -86,7 +86,7 @@ instance [h : InvolutiveInv α] : InvolutiveInv αᵒᵈ := h @[to_additive] instance [h : DivInvMonoid α] : DivInvMonoid αᵒᵈ := h -@[to_additive OrderDual.subtractionMonoid] +@[to_additive] instance [h : DivisionMonoid α] : DivisionMonoid αᵒᵈ := h @[to_additive OrderDual.subtractionCommMonoid] @@ -194,7 +194,7 @@ instance [h : InvolutiveInv α] : InvolutiveInv (Lex α) := h @[to_additive] instance [h : DivInvMonoid α] : DivInvMonoid (Lex α) := h -@[to_additive existing OrderDual.subtractionMonoid] +@[to_additive] instance [h : DivisionMonoid α] : DivisionMonoid (Lex α) := h @[to_additive existing OrderDual.subtractionCommMonoid] diff --git a/Mathlib/Algebra/Order/Group/Unbundled/Basic.lean b/Mathlib/Algebra/Order/Group/Unbundled/Basic.lean index f0e95176dbb3d..4d59951456a6e 100644 --- a/Mathlib/Algebra/Order/Group/Unbundled/Basic.lean +++ b/Mathlib/Algebra/Order/Group/Unbundled/Basic.lean @@ -33,7 +33,7 @@ variable [Group α] section TypeclassesLeftLE -variable [LE α] [CovariantClass α α (· * ·) (· ≤ ·)] {a b c d : α} +variable [LE α] [CovariantClass α α (· * ·) (· ≤ ·)] {a b c : α} /-- Uses `left` co(ntra)variant. -/ @[to_additive (attr := simp) "Uses `left` co(ntra)variant."] @@ -471,7 +471,7 @@ variable [Group α] [LE α] section Right -variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c d : α} +variable [CovariantClass α α (swap (· * ·)) (· ≤ ·)] {a b c : α} @[to_additive] theorem div_le_div_iff_right (c : α) : a / c ≤ b / c ↔ a ≤ b := by @@ -594,7 +594,7 @@ variable [Group α] [LT α] section Right -variable [CovariantClass α α (swap (· * ·)) (· < ·)] {a b c d : α} +variable [CovariantClass α α (swap (· * ·)) (· < ·)] {a b c : α} @[to_additive (attr := simp)] theorem div_lt_div_iff_right (c : α) : a / c < b / c ↔ a < b := by @@ -722,7 +722,7 @@ variable [CovariantClass α α (· * ·) (· ≤ ·)] 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 := 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..af674406ea62a 100644 --- a/Mathlib/Algebra/Order/Group/Units.lean +++ b/Mathlib/Algebra/Order/Group/Units.lean @@ -25,3 +25,11 @@ instance Units.orderedCommGroup [OrderedCommMonoid α] : OrderedCommGroup αˣ : -- 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/Action/Synonym.lean b/Mathlib/Algebra/Order/GroupWithZero/Action/Synonym.lean new file mode 100644 index 0000000000000..bd2d126a778f8 --- /dev/null +++ b/Mathlib/Algebra/Order/GroupWithZero/Action/Synonym.lean @@ -0,0 +1,78 @@ +/- +Copyright (c) 2021 Yaël Dillies. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yaël Dillies +-/ +import Mathlib.Algebra.Order.GroupWithZero.Synonym +import Mathlib.Algebra.SMulWithZero +import Mathlib.Tactic.Common + +/-! +# Actions by and on order synonyms + +This PR transfers group action with zero instances from a type `α` to `αᵒᵈ` and `Lex α`. Note that +the `SMul` instances are already defined in `Mathlib.Algebra.Order.Group.Synonym`. + +## See also + +* `Mathlib.Algebra.Order.Group.Action.Synonym` +* `Mathlib.Algebra.Order.Module.Synonym` +-/ + +variable {G₀ M₀ : Type*} + +namespace OrderDual + +instance instSMulWithZero [Zero G₀] [Zero M₀] [SMulWithZero G₀ M₀] : SMulWithZero G₀ᵒᵈ M₀ := + ‹SMulWithZero G₀ M₀› + +instance instSMulWithZero' [Zero G₀] [Zero M₀] [SMulWithZero G₀ M₀] : SMulWithZero G₀ M₀ᵒᵈ := + ‹SMulWithZero G₀ M₀› + +instance instDistribSMul [AddZeroClass M₀] [DistribSMul G₀ M₀] : DistribSMul G₀ᵒᵈ M₀ := + ‹DistribSMul G₀ M₀› + +instance instDistribSMul' [AddZeroClass M₀] [DistribSMul G₀ M₀] : DistribSMul G₀ M₀ᵒᵈ := + ‹DistribSMul G₀ M₀› + +instance instDistribMulAction [Monoid G₀] [AddMonoid M₀] [DistribMulAction G₀ M₀] : + DistribMulAction G₀ᵒᵈ M₀ := ‹DistribMulAction G₀ M₀› + +instance instDistribMulAction' [Monoid G₀] [AddMonoid M₀] [DistribMulAction G₀ M₀] : + DistribMulAction G₀ M₀ᵒᵈ := ‹DistribMulAction G₀ M₀› + +instance instMulActionWithZero [MonoidWithZero G₀] [AddMonoid M₀] [MulActionWithZero G₀ M₀] : + MulActionWithZero G₀ᵒᵈ M₀ := ‹MulActionWithZero G₀ M₀› + +instance instMulActionWithZero' [MonoidWithZero G₀] [AddMonoid M₀] [MulActionWithZero G₀ M₀] : + MulActionWithZero G₀ M₀ᵒᵈ := ‹MulActionWithZero G₀ M₀› + +end OrderDual + +namespace Lex + +instance instSMulWithZero [Zero G₀] [Zero M₀] [SMulWithZero G₀ M₀] : SMulWithZero (Lex G₀) M₀ := + ‹SMulWithZero G₀ M₀› + +instance instSMulWithZero' [Zero G₀] [Zero M₀] [SMulWithZero G₀ M₀] : SMulWithZero G₀ (Lex M₀) := + ‹SMulWithZero G₀ M₀› + +instance instDistribSMul [AddZeroClass M₀] [DistribSMul G₀ M₀] : DistribSMul (Lex G₀) M₀ := + ‹DistribSMul G₀ M₀› + +instance instDistribSMul' [AddZeroClass M₀] [DistribSMul G₀ M₀] : DistribSMul G₀ (Lex M₀) := + ‹DistribSMul G₀ M₀› + +instance instDistribMulAction [Monoid G₀] [AddMonoid M₀] [DistribMulAction G₀ M₀] : + DistribMulAction (Lex G₀) M₀ := ‹DistribMulAction G₀ M₀› + +instance instDistribMulAction' [Monoid G₀] [AddMonoid M₀] [DistribMulAction G₀ M₀] : + DistribMulAction G₀ (Lex M₀) := ‹DistribMulAction G₀ M₀› + +instance instMulActionWithZero [MonoidWithZero G₀] [AddMonoid M₀] [MulActionWithZero G₀ M₀] : + MulActionWithZero (Lex G₀) M₀ := ‹MulActionWithZero G₀ M₀› + +instance instMulActionWithZero' [MonoidWithZero G₀] [AddMonoid M₀] [MulActionWithZero G₀ M₀] : + MulActionWithZero G₀ (Lex M₀) := ‹MulActionWithZero G₀ M₀› + +end Lex diff --git a/Mathlib/Algebra/Order/GroupWithZero/Canonical.lean b/Mathlib/Algebra/Order/GroupWithZero/Canonical.lean index 3984c64e8056f..1808690367f6d 100644 --- a/Mathlib/Algebra/Order/GroupWithZero/Canonical.lean +++ b/Mathlib/Algebra/Order/GroupWithZero/Canonical.lean @@ -3,17 +3,16 @@ Copyright (c) 2020 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Johan Commelin, Patrick Massot -/ -import Mathlib.Algebra.Group.WithOne.Defs import Mathlib.Algebra.GroupWithZero.InjSurj import Mathlib.Algebra.GroupWithZero.Units.Equiv import Mathlib.Algebra.GroupWithZero.WithZero +import Mathlib.Algebra.Order.AddGroupWithTop import Mathlib.Algebra.Order.Group.Units import Mathlib.Algebra.Order.GroupWithZero.Synonym +import Mathlib.Algebra.Order.GroupWithZero.Unbundled import Mathlib.Algebra.Order.Monoid.Basic -import Mathlib.Algebra.Order.AddGroupWithTop import Mathlib.Algebra.Order.Monoid.OrderDual import Mathlib.Algebra.Order.Monoid.TypeTags -import Mathlib.Algebra.Order.ZeroLEOne /-! # Linearly ordered commutative groups and monoids with a zero element adjoined @@ -99,41 +98,55 @@ end LinearOrderedCommMonoidWithZero section LinearOrderedCommGroupWithZero variable [LinearOrderedCommGroupWithZero α] {a b c d : α} {m n : ℕ} --- TODO: Do we really need the following two? -/-- Alias of `mul_le_one'` for unification. -/ -theorem mul_le_one₀ (ha : a ≤ 1) (hb : b ≤ 1) : a * b ≤ 1 := - mul_le_one' ha hb +-- See note [lower instance priority] +instance (priority := 100) LinearOrderedCommGroupWithZero.toMulPosMono : MulPosMono α where + elim _a _b _c hbc := mul_le_mul_right' hbc _ + +-- See note [lower instance priority] +instance (priority := 100) LinearOrderedCommGroupWithZero.toPosMulMono : PosMulMono α where + elim _a _b _c hbc := mul_le_mul_left' hbc _ + +-- See note [lower instance priority] +instance (priority := 100) LinearOrderedCommGroupWithZero.toPosMulReflectLE : + PosMulReflectLE α where + elim a b c hbc := by simpa [a.2.ne'] using mul_le_mul_left' hbc a⁻¹ + +-- See note [lower instance priority] +instance (priority := 100) LinearOrderedCommGroupWithZero.toMulPosReflectLE : + MulPosReflectLE α where + elim a b c hbc := by simpa [a.2.ne'] using mul_le_mul_right' hbc a⁻¹ + +-- See note [lower instance priority] +instance (priority := 100) LinearOrderedCommGroupWithZero.toPosMulReflectLT : + PosMulReflectLT α where elim _a _b _c := lt_of_mul_lt_mul_left' + +-- See note [lower instance priority] +instance (priority := 100) LinearOrderedCommGroupWithZero.toPosMulStrictMono : + PosMulStrictMono α where + elim a b c hbc := by by_contra! h; exact hbc.not_le <| (mul_le_mul_left a.2).1 h + +-- See note [lower instance priority] +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 `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 := one_le_mul ha hb -theorem le_of_le_mul_right (h : c ≠ 0) (hab : a * c ≤ b * c) : a ≤ b := by - simpa only [mul_inv_cancel_right₀ h] using mul_le_mul_right' hab c⁻¹ +@[deprecated mul_le_mul_right (since := "2024-08-21")] +theorem le_of_le_mul_right (h : c ≠ 0) (hab : a * c ≤ b * c) : a ≤ b := + (mul_le_mul_right (zero_lt_iff.2 h)).1 hab +@[deprecated le_mul_inv_iff₀ (since := "2024-08-21")] theorem le_mul_inv_of_mul_le (h : c ≠ 0) (hab : a * c ≤ b) : a ≤ b * c⁻¹ := - le_of_le_mul_right h (by simpa [h] using hab) + (le_mul_inv_iff₀ (zero_lt_iff.2 h)).2 hab theorem mul_inv_le_of_le_mul (hab : a ≤ b * c) : a * c⁻¹ ≤ b := by by_cases h : c = 0 · simp [h] - · exact le_of_le_mul_right h (by simpa [h] using hab) - -theorem inv_le_one₀ (ha : a ≠ 0) : a⁻¹ ≤ 1 ↔ 1 ≤ a := - inv_le_one' (a := Units.mk0 a ha) - -theorem one_le_inv₀ (ha : a ≠ 0) : 1 ≤ a⁻¹ ↔ a ≤ 1 := - one_le_inv' (a := Units.mk0 a ha) - -theorem le_mul_inv_iff₀ (hc : c ≠ 0) : a ≤ b * c⁻¹ ↔ a * c ≤ b := - ⟨fun h ↦ inv_inv c ▸ mul_inv_le_of_le_mul h, le_mul_inv_of_mul_le hc⟩ - -theorem mul_inv_le_iff₀ (hc : c ≠ 0) : a * c⁻¹ ≤ b ↔ a ≤ b * c := - ⟨fun h ↦ inv_inv c ▸ le_mul_inv_of_mul_le (inv_ne_zero hc) h, mul_inv_le_of_le_mul⟩ - -theorem div_le_div₀ (a b c d : α) (hb : b ≠ 0) (hd : d ≠ 0) : - a * b⁻¹ ≤ c * d⁻¹ ↔ a * d ≤ c * b := by - rw [mul_inv_le_iff₀ hb, mul_right_comm, le_mul_inv_iff₀ hd] + · exact (mul_le_mul_right (zero_lt_iff.2 h)).1 (by simpa [h] using hab) @[simp] theorem Units.zero_lt (u : αˣ) : (0 : α) < u := @@ -163,57 +176,37 @@ theorem inv_mul_lt_of_lt_mul₀ (h : a < b * c) : b⁻¹ * a < c := by rw [mul_comm] at * exact mul_inv_lt_of_lt_mul₀ h -theorem mul_lt_right₀ (c : α) (h : a < b) (hc : c ≠ 0) : a * c < b * c := by - contrapose! h - exact le_of_le_mul_right hc h - -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 +@[deprecated mul_lt_mul_of_pos_right (since := "2024-08-21")] +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 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 +@[deprecated mul_le_mul_right (since := "2024-08-21")] theorem mul_le_mul_right₀ (hc : c ≠ 0) : a * c ≤ b * c ↔ a ≤ b := - ⟨le_of_le_mul_right hc, fun hab ↦ mul_le_mul_right' hab _⟩ + mul_le_mul_right (zero_lt_iff.2 hc) -theorem mul_le_mul_left₀ (ha : a ≠ 0) : a * b ≤ a * c ↔ b ≤ c := by - simp only [mul_comm a] - exact mul_le_mul_right₀ ha +@[deprecated mul_le_mul_left (since := "2024-08-21")] +theorem mul_le_mul_left₀ (ha : a ≠ 0) : a * b ≤ a * c ↔ b ≤ c := + mul_le_mul_left (zero_lt_iff.2 ha) 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₀ (inv_ne_zero hc)] + 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₀ ha, inv_le_inv₀ hb hc] - -theorem le_div_iff₀ (hc : c ≠ 0) : a ≤ b / c ↔ a * c ≤ b := by - rw [div_eq_mul_inv, le_mul_inv_iff₀ hc] - -theorem div_le_iff₀ (hc : c ≠ 0) : a / c ≤ b ↔ a ≤ b * c := by - rw [div_eq_mul_inv, mul_inv_le_iff₀ 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.`. Note that `OrderIso.mulLeft₀` refers to the `LinearOrderedField` version. -/ @[simps! (config := { simpRhs := true }) apply toEquiv] def OrderIso.mulLeft₀' {a : α} (ha : a ≠ 0) : α ≃o α := - { Equiv.mulLeft₀ a ha with map_rel_iff' := mul_le_mul_left₀ ha } + { Equiv.mulLeft₀ a ha with map_rel_iff' := mul_le_mul_left (zero_lt_iff.2 ha) } theorem OrderIso.mulLeft₀'_symm {a : α} (ha : a ≠ 0) : (OrderIso.mulLeft₀' ha).symm = OrderIso.mulLeft₀' (inv_ne_zero ha) := by @@ -225,7 +218,7 @@ theorem OrderIso.mulLeft₀'_symm {a : α} (ha : a ≠ 0) : Note that `OrderIso.mulRight₀` refers to the `LinearOrderedField` version. -/ @[simps! (config := { simpRhs := true }) apply toEquiv] def OrderIso.mulRight₀' {a : α} (ha : a ≠ 0) : α ≃o α := - { Equiv.mulRight₀ a ha with map_rel_iff' := mul_le_mul_right₀ ha } + { Equiv.mulRight₀ a ha with map_rel_iff' := mul_le_mul_right (zero_lt_iff.2 ha) } theorem OrderIso.mulRight₀'_symm {a : α} (ha : a ≠ 0) : (OrderIso.mulRight₀' ha).symm = OrderIso.mulRight₀' (inv_ne_zero ha) := by @@ -245,13 +238,11 @@ instance : LinearOrderedAddCommGroupWithTop (Additive αᵒᵈ) := lemma pow_lt_pow_succ (ha : 1 < a) : a ^ n < a ^ n.succ := by rw [← one_mul (a ^ n), pow_succ'] - exact mul_lt_right₀ _ ha (pow_ne_zero _ (zero_lt_one.trans ha).ne') + exact mul_lt_mul_of_pos_right ha (pow_pos (zero_lt_one.trans ha) _) 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 @@ -418,3 +409,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 new file mode 100644 index 0000000000000..c3b553bb0ca38 --- /dev/null +++ b/Mathlib/Algebra/Order/GroupWithZero/Submonoid.lean @@ -0,0 +1,27 @@ +/- +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.Order.GroupWithZero.Unbundled + +/-! +# The submonoid of positive elements +-/ + +namespace Submonoid +variable (α) [MulZeroOneClass α] [PartialOrder α] [PosMulStrictMono α] [ZeroLEOneClass α] + [NeZero (1 : α)] {a : α} + +/-- The submonoid of positive elements. -/ +@[simps] def pos : Submonoid α where + carrier := Set.Ioi 0 + one_mem' := zero_lt_one + mul_mem' := mul_pos + +variable {α} + +@[simp] lemma mem_pos : a ∈ pos α ↔ 0 < a := Iff.rfl + +end Submonoid diff --git a/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean b/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean index 3fdf5f2d9d810..b238cd2ab171e 100644 --- a/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean +++ b/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean @@ -3,9 +3,13 @@ Copyright (c) 2022 Damiano Testa. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa, Yuyang Zhao -/ -import Mathlib.Algebra.GroupWithZero.Defs +import Mathlib.Algebra.Group.Pi.Basic +import Mathlib.Algebra.GroupWithZero.Units.Basic import Mathlib.Algebra.Order.Monoid.Unbundled.Defs -import Mathlib.Tactic.GCongr.Core +import Mathlib.Algebra.Order.ZeroLEOne +import Mathlib.Tactic.Bound.Attribute +import Mathlib.Tactic.GCongr.CoreAttrs +import Mathlib.Tactic.Nontriviality /-! # Monotonicity of multiplication by positive elements @@ -80,7 +84,9 @@ for a discussion about this notation, and whether to enable it globally (note th currently global but broken, hence actually only works locally). -/ -variable (α : Type*) +open Function + +variable {M₀ G₀ : Type*} (α : Type*) set_option quotPrecheck false in /-- Local notation for the nonnegative elements of a type `α`. TODO: actually make local. -/ @@ -617,6 +623,17 @@ variable [Preorder α] /-! Lemmas of the form `a ≤ a * b ↔ 1 ≤ b` and `a * b ≤ a ↔ b ≤ 1`, which assume left covariance. -/ +lemma one_lt_of_lt_mul_left₀ [PosMulReflectLT α] (ha : 0 ≤ a) (h : a < a * b) : 1 < b := + lt_of_mul_lt_mul_left (by simpa) ha + +lemma one_lt_of_lt_mul_right₀ [MulPosReflectLT α] (hb : 0 ≤ b) (h : b < a * b) : 1 < a := + lt_of_mul_lt_mul_right (by simpa) hb + +lemma one_le_of_le_mul_left₀ [PosMulReflectLE α] (ha : 0 < a) (h : a ≤ a * b) : 1 ≤ b := + le_of_mul_le_mul_left (by simpa) ha + +lemma one_le_of_le_mul_right₀ [MulPosReflectLE α] (hb : 0 < b) (h : b ≤ a * b) : 1 ≤ a := + le_of_mul_le_mul_right (by simpa) hb @[simp] lemma le_mul_iff_one_le_right [PosMulMono α] [PosMulReflectLE α] (a0 : 0 < a) : a ≤ a * b ↔ 1 ≤ b := @@ -917,6 +934,182 @@ end LinearOrder end MulOneClass +section MonoidWithZero +variable [MonoidWithZero M₀] + +section Preorder +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 + | _, _, Nat.le.step h => by + rw [pow_succ'] + exact (mul_le_of_le_one_left (pow_nonneg ha₀ _) ha₁).trans <| pow_le_pow_of_le_one ha₀ ha₁ h + +lemma pow_le_of_le_one [ZeroLEOneClass M₀] [PosMulMono M₀] [MulPosMono M₀] (h₀ : 0 ≤ a) (h₁ : a ≤ 1) + (hn : n ≠ 0) : a ^ n ≤ a := + (pow_one a).subst (pow_le_pow_of_le_one h₀ h₁ (Nat.pos_of_ne_zero hn)) + +lemma sq_le [ZeroLEOneClass M₀] [PosMulMono M₀] [MulPosMono M₀] (h₀ : 0 ≤ a) (h₁ : a ≤ 1) : + a ^ 2 ≤ a := pow_le_of_le_one h₀ h₁ two_ne_zero + +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 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 + +lemma one_lt_mul_of_lt_of_le [ZeroLEOneClass M₀] [PosMulMono M₀] (ha : 1 < a) (hb : 1 ≤ b) : + 1 < a * b := ha.trans_le <| le_mul_of_one_le_right (zero_le_one.trans ha.le) hb + +alias one_lt_mul := one_lt_mul_of_le_of_lt + +lemma mul_lt_one_of_nonneg_of_lt_one_left [PosMulMono M₀] (ha₀ : 0 ≤ a) (ha : a < 1) (hb : b ≤ 1) : + a * b < 1 := (mul_le_of_le_one_right ha₀ hb).trans_lt ha + +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 := + fun _ _ h ↦ mul_le_mul_of_nonneg_left h ha + +lemma monotone_mul_right_of_nonneg [MulPosMono M₀] (ha : 0 ≤ a) : Monotone fun x ↦ x * a := + fun _ _ h ↦ mul_le_mul_of_nonneg_right h ha + +lemma Monotone.mul_const [MulPosMono M₀] (hf : Monotone f) (ha : 0 ≤ a) : + Monotone fun x ↦ f x * a := (monotone_mul_right_of_nonneg ha).comp hf + +lemma Monotone.const_mul [PosMulMono M₀] (hf : Monotone f) (ha : 0 ≤ a) : + Monotone fun x ↦ a * f x := (monotone_mul_left_of_nonneg ha).comp hf + +lemma Antitone.mul_const [MulPosMono M₀] (hf : Antitone f) (ha : 0 ≤ a) : + Antitone fun x ↦ f x * a := (monotone_mul_right_of_nonneg ha).comp_antitone hf + +lemma Antitone.const_mul [PosMulMono M₀] (hf : Antitone f) (ha : 0 ≤ a) : + Antitone fun x ↦ a * f x := (monotone_mul_left_of_nonneg ha).comp_antitone hf + +lemma Monotone.mul [PosMulMono M₀] [MulPosMono M₀] (hf : Monotone f) (hg : Monotone g) + (hf₀ : ∀ x, 0 ≤ f x) (hg₀ : ∀ x, 0 ≤ g x) : Monotone (f * g) := + fun _ _ h ↦ mul_le_mul (hf h) (hg h) (hg₀ _) (hf₀ _) + +end Preorder + + +section PartialOrder +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 + +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 + +-- In the next lemma, we used to write `Set.Ici 0` instead of `{x | 0 ≤ x}`. +-- As this lemma is not used outside this file, +-- and the import for `Set.Ici` is not otherwise needed until later, +-- we choose not to use it here. +lemma strictMonoOn_mul_self [PosMulStrictMono M₀] [MulPosMono M₀] : + StrictMonoOn (fun x ↦ x * x) {x : M₀ | 0 ≤ x} := fun _ hx _ _ hxy ↦ mul_self_lt_mul_self hx hxy + +-- See Note [decidable namespace] +protected lemma Decidable.mul_lt_mul'' [PosMulMono M₀] [PosMulStrictMono M₀] [MulPosStrictMono M₀] + [@DecidableRel M₀ (· ≤ ·)] (h1 : a < c) (h2 : b < d) + (h3 : 0 ≤ a) (h4 : 0 ≤ b) : a * b < c * d := + h4.lt_or_eq_dec.elim (fun b0 ↦ mul_lt_mul h1 h2.le b0 <| h3.trans h1.le) fun b0 ↦ by + rw [← b0, mul_zero]; exact mul_pos (h3.trans_lt h1) (h4.trans_lt h2) + +lemma lt_mul_left [MulPosStrictMono M₀] (ha : 0 < a) (hb : 1 < b) : a < b * a := by + simpa using mul_lt_mul_of_pos_right hb ha + +lemma lt_mul_right [PosMulStrictMono M₀] (ha : 0 < a) (hb : 1 < b) : a < a * b := by + simpa using mul_lt_mul_of_pos_left hb ha + +lemma lt_mul_self [ZeroLEOneClass M₀] [MulPosStrictMono M₀] (ha : 1 < a) : a < a * a := + lt_mul_left (ha.trans_le' zero_le_one) ha + +variable [Preorder α] {f g : α → M₀} + +lemma strictMono_mul_left_of_pos [PosMulStrictMono M₀] (ha : 0 < a) : + StrictMono fun x ↦ a * x := fun _ _ b_lt_c ↦ mul_lt_mul_of_pos_left b_lt_c ha + +lemma strictMono_mul_right_of_pos [MulPosStrictMono M₀] (ha : 0 < a) : + StrictMono fun x ↦ x * a := fun _ _ b_lt_c ↦ mul_lt_mul_of_pos_right b_lt_c ha + +lemma StrictMono.mul_const [MulPosStrictMono M₀] (hf : StrictMono f) (ha : 0 < a) : + StrictMono fun x ↦ f x * a := (strictMono_mul_right_of_pos ha).comp hf + +lemma StrictMono.const_mul [PosMulStrictMono M₀] (hf : StrictMono f) (ha : 0 < a) : + StrictMono fun x ↦ a * f x := (strictMono_mul_left_of_pos ha).comp hf + +lemma StrictAnti.mul_const [MulPosStrictMono M₀] (hf : StrictAnti f) (ha : 0 < a) : + StrictAnti fun x ↦ f x * a := (strictMono_mul_right_of_pos ha).comp_strictAnti hf + +lemma StrictAnti.const_mul [PosMulStrictMono M₀] (hf : StrictAnti f) (ha : 0 < a) : + StrictAnti fun x ↦ a * f x := (strictMono_mul_left_of_pos ha).comp_strictAnti hf + +lemma StrictMono.mul_monotone [PosMulMono M₀] [MulPosStrictMono M₀] (hf : StrictMono f) + (hg : Monotone g) (hf₀ : ∀ x, 0 ≤ f x) (hg₀ : ∀ x, 0 < g x) : + StrictMono (f * g) := fun _ _ h ↦ mul_lt_mul (hf h) (hg h.le) (hg₀ _) (hf₀ _) + +lemma Monotone.mul_strictMono [PosMulStrictMono M₀] [MulPosMono M₀] (hf : Monotone f) + (hg : StrictMono g) (hf₀ : ∀ x, 0 < f x) (hg₀ : ∀ x, 0 ≤ g x) : + StrictMono (f * g) := fun _ _ h ↦ mul_lt_mul' (hf h.le) (hg h) (hg₀ _) (hf₀ _) + +lemma StrictMono.mul [PosMulStrictMono M₀] [MulPosStrictMono M₀] (hf : StrictMono f) + (hg : StrictMono g) (hf₀ : ∀ x, 0 ≤ f x) (hg₀ : ∀ x, 0 ≤ g x) : + StrictMono (f * g) := fun _ _ h ↦ mul_lt_mul'' (hf h) (hg h) (hf₀ _) (hg₀ _) + +end MonoidWithZero.PartialOrder + section CancelMonoidWithZero variable [CancelMonoidWithZero α] @@ -958,20 +1151,480 @@ end PartialOrder 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 : 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⟩ + fun a ha ↦ flip lt_of_mul_lt_mul_left ha.le <| by simp [ne_of_gt ha, zero_lt_one] + +alias ⟨_, inv_pos_of_pos⟩ := inv_pos + +@[simp] lemma inv_nonneg : 0 ≤ a⁻¹ ↔ 0 ≤ a := by simp only [le_iff_eq_or_lt, inv_pos, zero_eq_inv] + +alias ⟨_, inv_nonneg_of_nonneg⟩ := inv_nonneg + +lemma one_div_pos : 0 < 1 / a ↔ 0 < a := one_div a ▸ inv_pos +lemma one_div_nonneg : 0 ≤ 1 / a ↔ 0 ≤ a := one_div a ▸ inv_nonneg + +lemma div_pos [PosMulStrictMono G₀] (ha : 0 < a) (hb : 0 < b) : 0 < a / b := by + rw [div_eq_mul_inv]; exact mul_pos ha (inv_pos.2 hb) + +lemma div_nonneg [PosMulMono G₀] (ha : 0 ≤ a) (hb : 0 ≤ b) : 0 ≤ a / b := by + rw [div_eq_mul_inv]; exact mul_nonneg ha (inv_nonneg.2 hb) + +lemma div_nonpos_of_nonpos_of_nonneg [MulPosMono G₀] (ha : a ≤ 0) (hb : 0 ≤ b) : a / b ≤ 0 := by + rw [div_eq_mul_inv]; exact mul_nonpos_of_nonpos_of_nonneg ha (inv_nonneg.2 hb) + +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 [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₀] {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) + +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_anti₀ 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 + +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 : 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] + +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 + rw [div_eq_mul_inv]; exact mul_nonpos_of_nonneg_of_nonpos ha (inv_nonpos.2 hb) + +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 + +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₀] + +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] + +/-- 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..edc0cb47b953d --- /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 b c d : 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/Hom/Basic.lean b/Mathlib/Algebra/Order/Hom/Basic.lean index 983b87c6868e5..b97b19b03d22d 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) @@ -122,18 +126,16 @@ theorem le_map_mul_map_div [Group α] [CommSemigroup β] [LE β] [Submultiplicat theorem le_map_add_map_div [Group α] [AddCommSemigroup β] [LE β] [MulLEAddHomClass F α β] (f : F) (a b : α) : f a ≤ f b + f (a / b) := by simpa only [add_comm, div_mul_cancel] using map_mul_le_add f (a / b) b --- Porting note (#11215): TODO: `to_additive` clashes @[to_additive] theorem le_map_div_mul_map_div [Group α] [CommSemigroup β] [LE β] [SubmultiplicativeHomClass F α β] (f : F) (a b c : α) : f (a / c) ≤ f (a / b) * f (b / c) := by - simpa only [div_mul_div_cancel'] using map_mul_le_mul f (a / b) (b / c) + simpa only [div_mul_div_cancel] using map_mul_le_mul f (a / b) (b / c) @[to_additive existing] theorem le_map_div_add_map_div [Group α] [AddCommSemigroup β] [LE β] [MulLEAddHomClass F α β] (f : F) (a b c : α) : f (a / c) ≤ f (a / b) + f (b / c) := by - simpa only [div_mul_div_cancel'] using map_mul_le_add f (a / b) (b / c) --- Porting note (#11215): TODO: `to_additive` clashes + simpa only [div_mul_div_cancel] using map_mul_le_add f (a / b) (b / c) namespace Mathlib.Meta.Positivity @@ -156,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 @@ -167,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 @@ -178,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 @@ -187,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 @@ -277,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. @@ -301,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] diff --git a/Mathlib/Algebra/Order/Hom/Monoid.lean b/Mathlib/Algebra/Order/Hom/Monoid.lean index d212b514c3cc4..89356b58c0ecf 100644 --- a/Mathlib/Algebra/Order/Hom/Monoid.lean +++ b/Mathlib/Algebra/Order/Hom/Monoid.lean @@ -18,12 +18,17 @@ This file defines morphisms between (additive) ordered monoids. * `OrderAddMonoidHom`: Ordered additive monoid homomorphisms. * `OrderMonoidHom`: Ordered monoid homomorphisms. * `OrderMonoidWithZeroHom`: Ordered monoid with zero homomorphisms. +* `OrderAddMonoidIso`: Ordered additive monoid isomorphisms. +* `OrderMonoidIso`: Ordered monoid isomorphisms. ## Notation -* `→+o`: Bundled ordered additive monoid homs. Also use for additive groups homs. -* `→*o`: Bundled ordered monoid homs. Also use for groups homs. -* `→*₀o`: Bundled ordered monoid with zero homs. Also use for groups with zero homs. +* `→+o`: Bundled ordered additive monoid homs. Also use for additive group homs. +* `→*o`: Bundled ordered monoid homs. Also use for group homs. +* `→*₀o`: Bundled ordered monoid with zero homs. Also use for group with zero homs. +* `≃+o`: Bundled ordered additive monoid isos. Also use for additive group isos. +* `≃*o`: Bundled ordered monoid isos. Also use for group isos. +* `≃*₀o`: Bundled ordered monoid with zero isos. Also use for group with zero isos. ## Implementation notes @@ -66,9 +71,8 @@ structure. `OrderAddMonoidHom` is also used for ordered group homomorphisms. When possible, instead of parametrizing results over `(f : α →+o β)`, -you should parametrize over `(F : Type*) [OrderAddMonoidHomClass F α β] (f : F)`. - -When you extend this structure, make sure to extend `OrderAddMonoidHomClass`. -/ +you should parametrize over +`(F : Type*) [FunLike F M N] [MonoidHomClass F M N] [OrderHomClass F M N] (f : F)`. -/ structure OrderAddMonoidHom (α β : Type*) [Preorder α] [Preorder β] [AddZeroClass α] [AddZeroClass β] extends α →+ β where /-- An `OrderAddMonoidHom` is a monotone function. -/ @@ -77,6 +81,22 @@ structure OrderAddMonoidHom (α β : Type*) [Preorder α] [Preorder β] [AddZero /-- Infix notation for `OrderAddMonoidHom`. -/ infixr:25 " →+o " => OrderAddMonoidHom +/-- `α ≃+o β` is the type of monotone isomorphisms `α ≃ β` that preserve the `OrderedAddCommMonoid` +structure. + +`OrderAddMonoidIso` is also used for ordered group isomorphisms. + +When possible, instead of parametrizing results over `(f : α ≃+o β)`, +you should parametrize over +`(F : Type*) [FunLike F M N] [AddEquivClass F M N] [OrderIsoClass F M N] (f : F)`. -/ +structure OrderAddMonoidIso (α β : Type*) [Preorder α] [Preorder β] [AddZeroClass α] + [AddZeroClass β] extends α ≃+ β where + /-- An `OrderAddMonoidIso` respects `≤`. -/ + map_le_map_iff' {a b : α} : toFun a ≤ toFun b ↔ a ≤ b + +/-- Infix notation for `OrderAddMonoidIso`. -/ +infixr:25 " ≃+o " => OrderAddMonoidIso + -- Instances and lemmas are defined below through `@[to_additive]`. end AddMonoid @@ -87,9 +107,8 @@ section Monoid `OrderMonoidHom` is also used for ordered group homomorphisms. When possible, instead of parametrizing results over `(f : α →*o β)`, -you should parametrize over `(F : Type*) [OrderMonoidHomClass F α β] (f : F)`. - -When you extend this structure, make sure to extend `OrderMonoidHomClass`. -/ +you should parametrize over +`(F : Type*) [FunLike F M N] [MonoidHomClass F M N] [OrderHomClass F M N] (f : F)`. -/ @[to_additive] structure OrderMonoidHom (α β : Type*) [Preorder α] [Preorder β] [MulOneClass α] [MulOneClass β] extends α →* β where @@ -104,8 +123,9 @@ variable [Preorder α] [Preorder β] [MulOneClass α] [MulOneClass β] [FunLike /-- Turn an element of a type `F` satisfying `OrderHomClass F α β` and `MonoidHomClass F α β` into an actual `OrderMonoidHom`. This is declared as the default coercion from `F` to `α →*o β`. -/ @[to_additive (attr := coe) - "Turn an element of a type `F` satisfying `OrderAddMonoidHomClass F α β` into an actual - `OrderAddMonoidHom`. This is declared as the default coercion from `F` to `α →+o β`."] + "Turn an element of a type `F` satisfying `OrderHomClass F α β` and `AddMonoidHomClass F α β` + into an actual `OrderAddMonoidHom`. + This is declared as the default coercion from `F` to `α →+o β`."] def OrderMonoidHomClass.toOrderMonoidHom [OrderHomClass F α β] [MonoidHomClass F α β] (f : F) : α →*o β := { (f : α →* β) with monotone' := OrderHomClass.monotone f } @@ -117,6 +137,49 @@ def OrderMonoidHomClass.toOrderMonoidHom [OrderHomClass F α β] [MonoidHomClass instance [OrderHomClass F α β] [MonoidHomClass F α β] : CoeTC F (α →*o β) := ⟨OrderMonoidHomClass.toOrderMonoidHom⟩ +/-- `α ≃*o β` is the type of isomorphisms `α ≃ β` that preserve the `OrderedCommMonoid` structure. + +`OrderMonoidIso` is also used for ordered group isomorphisms. + +When possible, instead of parametrizing results over `(f : α ≃*o β)`, +you should parametrize over +`(F : Type*) [FunLike F M N] [MulEquivClass F M N] [OrderIsoClass F M N] (f : F)`. -/ +@[to_additive] +structure OrderMonoidIso (α β : Type*) [Preorder α] [Preorder β] [MulOneClass α] + [MulOneClass β] extends α ≃* β where + /-- An `OrderMonoidIso` respects `≤`. -/ + map_le_map_iff' {a b : α} : toFun a ≤ toFun b ↔ a ≤ b + +/-- Infix notation for `OrderMonoidIso`. -/ +infixr:25 " ≃*o " => OrderMonoidIso + +variable [Preorder α] [Preorder β] [MulOneClass α] [MulOneClass β] [FunLike F α β] + +/-- Turn an element of a type `F` satisfying `OrderIsoClass F α β` and `MulEquivClass F α β` +into an actual `OrderMonoidIso`. This is declared as the default coercion from `F` to `α ≃*o β`. -/ +@[to_additive (attr := coe) + "Turn an element of a type `F` satisfying `OrderIsoClass F α β` and `AddEquivClass F α β` + into an actual `OrderAddMonoidIso`. + This is declared as the default coercion from `F` to `α ≃+o β`."] +def OrderMonoidIsoClass.toOrderMonoidIso [EquivLike F α β] [OrderIsoClass F α β] + [MulEquivClass F α β] (f : F) : + α ≃*o β := + { (f : α ≃* β) with map_le_map_iff' := OrderIsoClass.map_le_map_iff f } + +/-- Any type satisfying `OrderMonoidHomClass` can be cast into `OrderMonoidHom` via + `OrderMonoidHomClass.toOrderMonoidHom`. -/ +@[to_additive "Any type satisfying `OrderAddMonoidHomClass` can be cast into `OrderAddMonoidHom` via + `OrderAddMonoidHomClass.toOrderAddMonoidHom`"] +instance [OrderHomClass F α β] [MonoidHomClass F α β] : CoeTC F (α →*o β) := + ⟨OrderMonoidHomClass.toOrderMonoidHom⟩ + +/-- Any type satisfying `OrderMonoidIsoClass` can be cast into `OrderMonoidIso` via + `OrderMonoidIsoClass.toOrderMonoidIso`. -/ +@[to_additive "Any type satisfying `OrderAddMonoidIsoClass` can be cast into `OrderAddMonoidIso` via + `OrderAddMonoidIsoClass.toOrderAddMonoidIso`"] +instance [EquivLike F α β] [OrderIsoClass F α β] [MulEquivClass F α β] : CoeTC F (α ≃*o β) := + ⟨OrderMonoidIsoClass.toOrderMonoidIso⟩ + end Monoid section MonoidWithZero @@ -129,9 +192,8 @@ the `MonoidWithZero` structure. `OrderMonoidWithZeroHom` is also used for group homomorphisms. When possible, instead of parametrizing results over `(f : α →+ β)`, -you should parametrize over `(F : Type*) [OrderMonoidWithZeroHomClass F α β] (f : F)`. - -When you extend this structure, make sure to extend `OrderMonoidWithZeroHomClass`. -/ +you should parameterize over +`(F : Type*) [FunLike F M N] [MonoidWithZeroHomClass F M N] [OrderHomClass F M N] (f : F)`. -/ structure OrderMonoidWithZeroHom (α β : Type*) [Preorder α] [Preorder β] [MulZeroOneClass α] [MulZeroOneClass β] extends α →*₀ β where /-- An `OrderMonoidWithZeroHom` is a monotone function. -/ @@ -446,6 +508,172 @@ end OrderedCommGroup end OrderMonoidHom +namespace OrderMonoidIso + +section Preorder + +variable [Preorder α] [Preorder β] [Preorder γ] [Preorder δ] [MulOneClass α] [MulOneClass β] + [MulOneClass γ] [MulOneClass δ] {f g : α ≃*o β} + +@[to_additive] +instance : EquivLike (α ≃*o β) α β 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 + obtain ⟨⟨⟨_, _⟩⟩, _⟩ := f + obtain ⟨⟨⟨_, _⟩⟩, _⟩ := g + congr + +@[to_additive] +instance : OrderIsoClass (α ≃*o β) α β where + map_le_map_iff f := f.map_le_map_iff' + +@[to_additive] +instance : MulEquivClass (α ≃*o β) α β where + map_mul f := map_mul f.toMulEquiv + +-- Other lemmas should be accessed through the `FunLike` API +@[to_additive (attr := ext)] +theorem ext (h : ∀ a, f a = g a) : f = g := + DFunLike.ext f g h + +@[to_additive] +theorem toFun_eq_coe (f : α ≃*o β) : f.toFun = (f : α → β) := + rfl + +@[to_additive (attr := simp)] +theorem coe_mk (f : α ≃* β) (h) : (OrderMonoidIso.mk f h : α → β) = f := + rfl + +@[to_additive (attr := simp)] +theorem mk_coe (f : α ≃*o β) (h) : OrderMonoidIso.mk (f : α ≃* β) h = f := rfl + +/-- Reinterpret an ordered monoid isomorphism as an order isomorphism. -/ +@[to_additive "Reinterpret an ordered additive monoid isomomorphism as an order isomomorphism."] +def toOrderIso (f : α ≃*o β) : α ≃o β := + { f with + map_rel_iff' := map_le_map_iff f } + +@[to_additive (attr := simp)] +theorem coe_mulEquiv (f : α ≃*o β) : ((f : α ≃* β) : α → β) = f := + rfl + +@[to_additive (attr := simp)] +theorem coe_orderIso (f : α ≃*o β) : ((f : α →o β) : α → β) = f := + rfl + +@[to_additive] +theorem toMulEquiv_injective : Injective (toMulEquiv : _ → α ≃* β) := fun f g h => + ext <| by convert DFunLike.ext_iff.1 h using 0 + +@[to_additive] +theorem toOrderIso_injective : Injective (toOrderIso : _ → α ≃o β) := fun f g h => + ext <| by convert DFunLike.ext_iff.1 h using 0 + +variable (α) + +/-- The identity map as an ordered monoid isomorphism. -/ +@[to_additive "The identity map as an ordered additive monoid isomorphism."] +protected def refl : α ≃*o α := + { MulEquiv.refl α with map_le_map_iff' := by simp } + +@[to_additive (attr := simp)] +theorem coe_refl : ⇑(OrderMonoidIso.refl α) = id := + rfl + +@[to_additive] +instance : Inhabited (α ≃*o α) := + ⟨OrderMonoidIso.refl α⟩ + +variable {α} + +/-- Transitivity of multiplication-preserving order isomorphisms -/ +@[to_additive (attr := trans) "Transitivity of addition-preserving order isomorphisms"] +def trans (f : α ≃*o β) (g : β ≃*o γ) : α ≃*o γ := + { (f : α ≃* β).trans g with map_le_map_iff' := by simp } + +@[to_additive (attr := simp)] +theorem coe_trans (f : α ≃*o β) (g : β ≃*o γ) : (f.trans g : α → γ) = g ∘ f := + rfl + +@[to_additive (attr := simp)] +theorem trans_apply (f : α ≃*o β) (g : β ≃*o γ) (a : α) : (f.trans g) a = g (f a) := + rfl + +@[to_additive] +theorem coe_trans_mulEquiv (f : α ≃*o β) (g : β ≃*o γ) : + (f.trans g : α ≃* γ) = (f : α ≃* β).trans g := + rfl + +@[to_additive] +theorem coe_trans_orderIso (f : α ≃*o β) (g : β ≃*o γ) : + (f.trans g : α ≃o γ) = (f : α ≃o β).trans g := + rfl + +@[to_additive (attr := simp)] +theorem trans_assoc (f : α ≃*o β) (g : β ≃*o γ) (h : γ ≃*o δ) : + (f.trans g).trans h = f.trans (g.trans h) := + rfl + +@[to_additive (attr := simp)] +theorem trans_refl (f : α ≃*o β) : f.trans (OrderMonoidIso.refl β) = f := + rfl + +@[to_additive (attr := simp)] +theorem refl_trans (f : α ≃*o β) : (OrderMonoidIso.refl α).trans f = f := + rfl + +@[to_additive (attr := simp)] +theorem cancel_right {g₁ g₂ : α ≃*o β} {f : β ≃*o γ} (hf : Function.Injective f) : + g₁.trans f = g₂.trans f ↔ g₁ = g₂ := + ⟨fun h => ext fun a => hf <| by rw [← trans_apply, h, trans_apply], by rintro rfl; rfl⟩ + +@[to_additive (attr := simp)] +theorem cancel_left {g : α ≃*o β} {f₁ f₂ : β ≃*o γ} (hg : Function.Surjective g) : + g.trans f₁ = g.trans f₂ ↔ f₁ = f₂ := + ⟨fun h => ext <| hg.forall.2 <| DFunLike.ext_iff.1 h, fun _ => by congr⟩ + +@[to_additive (attr := simp)] +theorem toMulEquiv_eq_coe (f : α ≃*o β) : f.toMulEquiv = f := + rfl + +@[to_additive (attr := simp)] +theorem toOrderIso_eq_coe (f : α ≃*o β) : f.toOrderIso = f := + rfl + +variable (f) + +@[to_additive] +protected lemma strictMono : StrictMono f := + strictMono_of_le_iff_le fun _ _ ↦ (map_le_map_iff _).symm + +@[to_additive] +protected lemma strictMono_symm : StrictMono f.symm := + strictMono_of_le_iff_le <| fun a b ↦ by + rw [← map_le_map_iff f] + convert Iff.rfl <;> + exact f.toEquiv.apply_symm_apply _ + +end Preorder + +section OrderedCommGroup + +variable {hα : OrderedCommGroup α} {hβ : OrderedCommGroup β} + +/-- Makes an ordered group isomorphism from a proof that the map preserves multiplication. -/ +@[to_additive + "Makes an ordered additive group isomorphism from a proof that the map preserves + addition."] +def mk' (f : α ≃ β) (hf : ∀ {a b}, f a ≤ f b ↔ a ≤ b) (map_mul : ∀ a b : α, f (a * b) = f a * f b) : + α ≃*o β := + { MulEquiv.mk' f map_mul with map_le_map_iff' := hf } + +end OrderedCommGroup + +end OrderMonoidIso + namespace OrderMonoidWithZeroHom section Preorder diff --git a/Mathlib/Algebra/Order/Hom/Ring.lean b/Mathlib/Algebra/Order/Hom/Ring.lean index 72c23ef5ca89e..fd1d21c0b1a1f 100644 --- a/Mathlib/Algebra/Order/Hom/Ring.lean +++ b/Mathlib/Algebra/Order/Hom/Ring.lean @@ -388,8 +388,7 @@ def Simps.symm_apply (e : α ≃+*o β) : β → α := e.symm @[simp] -theorem symm_symm (e : α ≃+*o β) : e.symm.symm = e := - ext fun _ => rfl +theorem symm_symm (e : α ≃+*o β) : e.symm.symm = e := rfl /-- Composition of `OrderRingIso`s as an `OrderRingIso`. -/ @[trans] diff --git a/Mathlib/Algebra/Order/Interval/Basic.lean b/Mathlib/Algebra/Order/Interval/Basic.lean index 005379a7fa950..dcd8a5d261e09 100644 --- a/Mathlib/Algebra/Order/Interval/Basic.lean +++ b/Mathlib/Algebra/Order/Interval/Basic.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.Pointwise.Set.Basic import Mathlib.Algebra.Order.BigOperators.Group.Finset -import Mathlib.Data.Set.Pointwise.Basic import Mathlib.Order.Interval.Basic /-! 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 4a57e54379465..08c772b601a9e 100644 --- a/Mathlib/Algebra/Order/Kleene.lean +++ b/Mathlib/Algebra/Order/Kleene.lean @@ -4,11 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Siddhartha Prasad, Yaël Dillies -/ import Mathlib.Algebra.Order.Monoid.Canonical.Defs -import Mathlib.Algebra.Ring.Pi import Mathlib.Algebra.Ring.InjSurj -import Mathlib.Tactic.Monotonicity.Attr +import Mathlib.Algebra.Ring.Pi import Mathlib.Algebra.Ring.Prod -import Mathlib.Algebra.Order.Monoid.Canonical.Defs +import Mathlib.Tactic.Monotonicity.Attr /-! # Kleene Algebras @@ -322,7 +321,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 } @@ -348,25 +347,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/Algebra.lean b/Mathlib/Algebra/Order/Module/Algebra.lean index 079e1ce13f6fa..083743a9ceaa4 100644 --- a/Mathlib/Algebra/Order/Module/Algebra.lean +++ b/Mathlib/Algebra/Order/Module/Algebra.lean @@ -91,7 +91,7 @@ def evalAlgebraMap : PositivityExt where eval {u β} _zβ _pβ e := do let _instβring ← synthInstanceQ q(OrderedSemiring $β) let _instαβsmul ← synthInstanceQ q(SMulPosMono $α $β) assertInstancesCommute - return .nonnegative q(algebraMap_nonneg $β $ le_of_lt $pa) + return .nonnegative q(algebraMap_nonneg $β <| le_of_lt $pa) | .nonnegative pa => let _instαring ← synthInstanceQ q(OrderedCommSemiring $α) let _instβring ← synthInstanceQ q(OrderedSemiring $β) diff --git a/Mathlib/Algebra/Order/Module/Defs.lean b/Mathlib/Algebra/Order/Module/Defs.lean index 00394f272ebbe..8323669b29434 100644 --- a/Mathlib/Algebra/Order/Module/Defs.lean +++ b/Mathlib/Algebra/Order/Module/Defs.lean @@ -3,12 +3,11 @@ 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.Order.Field.Defs -import Mathlib.Algebra.Order.GroupWithZero.Unbundled -import Mathlib.Algebra.Order.Module.Synonym -import Mathlib.GroupTheory.GroupAction.Group +import Mathlib.Algebra.Order.GroupWithZero.Action.Synonym +import Mathlib.Tactic.GCongr import Mathlib.Tactic.Positivity.Core -import Mathlib.Algebra.Order.Field.Unbundled.Basic /-! # Monotonicity of scalar multiplication by positive elements @@ -771,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 @@ -796,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 α] @@ -866,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 @@ -954,13 +959,13 @@ variable [LinearOrderedSemifield α] [AddCommGroup β] [PartialOrder β] instance (priority := 100) PosSMulMono.toPosSMulReflectLE [MulAction α β] [PosSMulMono α β] : PosSMulReflectLE α β where elim _a ha b₁ b₂ h := by - simpa [ha.ne'] using smul_le_smul_of_nonneg_left h <| inv_nonneg (α := α) |>.2 ha.le + simpa [ha.ne'] using smul_le_smul_of_nonneg_left h <| inv_nonneg.2 ha.le -- See note [lower instance priority] instance (priority := 100) PosSMulStrictMono.toPosSMulReflectLT [MulActionWithZero α β] [PosSMulStrictMono α β] : PosSMulReflectLT α β := PosSMulReflectLT.of_pos fun a ha b₁ b₂ h ↦ by - simpa [ha.ne'] using smul_lt_smul_of_pos_left h <| inv_pos (α := α) |>.2 ha + simpa [ha.ne'] using smul_lt_smul_of_pos_left h <| inv_pos.2 ha end LinearOrderedSemifield @@ -1165,7 +1170,7 @@ end NoZeroSMulDivisors open Lean.Meta Qq -/-- Positivity extension for HSMul, i.e. (_ • _). -/ +/-- Positivity extension for HSMul, i.e. (_ • _). -/ @[positivity HSMul.hSMul _ _] def evalHSMul : PositivityExt where eval {_u α} zα pα (e : Q($α)) := do let .app (.app (.app (.app (.app (.app @@ -1193,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 92fdcb6c87df6..ff7892c724901 100644 --- a/Mathlib/Algebra/Order/Module/OrderedSMul.lean +++ b/Mathlib/Algebra/Order/Module/OrderedSMul.lean @@ -3,12 +3,13 @@ Copyright (c) 2020 Frédéric Dupuis. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Frédéric Dupuis -/ +import Mathlib.Algebra.Group.Action.Basic import Mathlib.Algebra.Module.Pi import Mathlib.Algebra.Module.Prod import Mathlib.Algebra.Order.Module.Defs import Mathlib.Algebra.Order.Monoid.Prod import Mathlib.Algebra.Order.Pi -import Mathlib.Tactic.GCongr.Core +import Mathlib.Tactic.GCongr.CoreAttrs /-! # Ordered scalar product 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 4837629b8c8b4..0368ae68efa89 100644 --- a/Mathlib/Algebra/Order/Module/Rat.lean +++ b/Mathlib/Algebra/Order/Module/Rat.lean @@ -33,7 +33,7 @@ variable [LinearOrderedSemifield α] instance LinearOrderedSemifield.toPosSMulStrictMono_rat : PosSMulStrictMono ℚ≥0 α where elim q hq a b hab := by - rw [NNRat.smul_def, NNRat.smul_def]; exact mul_lt_mul_of_pos_left hab $ NNRat.cast_pos.2 hq + rw [NNRat.smul_def, NNRat.smul_def]; exact mul_lt_mul_of_pos_left hab <| NNRat.cast_pos.2 hq end LinearOrderedSemifield @@ -42,6 +42,6 @@ variable [LinearOrderedField α] instance LinearOrderedField.toPosSMulStrictMono_rat : PosSMulStrictMono ℚ α where elim q hq a b hab := by - rw [Rat.smul_def, Rat.smul_def]; exact mul_lt_mul_of_pos_left hab $ Rat.cast_pos.2 hq + rw [Rat.smul_def, Rat.smul_def]; exact mul_lt_mul_of_pos_left hab <| Rat.cast_pos.2 hq end LinearOrderedField diff --git a/Mathlib/Algebra/Order/Module/Synonym.lean b/Mathlib/Algebra/Order/Module/Synonym.lean index 543be50af4709..bca6dfe28edc1 100644 --- a/Mathlib/Algebra/Order/Module/Synonym.lean +++ b/Mathlib/Algebra/Order/Module/Synonym.lean @@ -4,83 +4,25 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ import Mathlib.Algebra.Module.Defs -import Mathlib.Algebra.Order.GroupWithZero.Synonym +import Mathlib.Algebra.Order.GroupWithZero.Action.Synonym import Mathlib.Algebra.Order.Ring.Synonym /-! # Action instances for `OrderDual` -This file provides instances of algebraic actions for `OrderDual`. Note that the `SMul` instances -are already defined in `Mathlib.Algebra.Order.Group.Synonym`. + +This PR transfers group action with zero instances from a type `α` to `αᵒᵈ` and `Lex α`. Note that +the `SMul` instances are already defined in `Mathlib.Algebra.Order.Group.Synonym`. ## See also -* `Mathlib.Algebra.Order.Group.Synonym` -* `Mathlib.Algebra.Order.Ring.Synonym` +* `Mathlib.Algebra.Order.Group.Action.Synonym` +* `Mathlib.Algebra.Order.GroupWithZero.Action.Synonym` -/ -namespace OrderDual -variable {α β γ : Type*} - -instance instSMulWithZero [Zero α] [Zero β] [SMulWithZero α β] : SMulWithZero αᵒᵈ β where - zero_smul := zero_smul α - smul_zero := smul_zero (M := α) - -instance instSMulWithZero' [Zero α] [Zero β] [SMulWithZero α β] : SMulWithZero α βᵒᵈ where - zero_smul := zero_smul _ (M := β) - smul_zero := smul_zero (A := β) - -@[to_additive] -instance instMulAction [Monoid α] [MulAction α β] : MulAction αᵒᵈ β where - one_smul := one_smul α - mul_smul := mul_smul (α := α) - -@[to_additive] -instance instMulAction' [Monoid α] [MulAction α β] : MulAction α βᵒᵈ where - one_smul := one_smul _ (α := β) - mul_smul := mul_smul (β := β) - -@[to_additive] -instance instSMulCommClass [SMul β γ] [SMul α γ] [SMulCommClass α β γ] : SMulCommClass αᵒᵈ β γ := - ‹SMulCommClass α β γ› - -@[to_additive] -instance instSMulCommClass' [SMul β γ] [SMul α γ] [SMulCommClass α β γ] : SMulCommClass α βᵒᵈ γ := - ‹SMulCommClass α β γ› - -@[to_additive] -instance instSMulCommClass'' [SMul β γ] [SMul α γ] [SMulCommClass α β γ] : SMulCommClass α β γᵒᵈ := - ‹SMulCommClass α β γ› - -@[to_additive instVAddAssocClass] -instance instIsScalarTower [SMul α β] [SMul β γ] [SMul α γ] [IsScalarTower α β γ] : - IsScalarTower αᵒᵈ β γ := ‹IsScalarTower α β γ› +variable {α β : Type*} -@[to_additive instVAddAssocClass'] -instance instIsScalarTower' [SMul α β] [SMul β γ] [SMul α γ] [IsScalarTower α β γ] : - IsScalarTower α βᵒᵈ γ := ‹IsScalarTower α β γ› - -@[to_additive instVAddAssocClass''] -instance instIsScalarTower'' [SMul α β] [SMul β γ] [SMul α γ] [IsScalarTower α β γ] : - IsScalarTower α β γᵒᵈ := ‹IsScalarTower α β γ› - -instance instMulActionWithZero [MonoidWithZero α] [AddMonoid β] [MulActionWithZero α β] : - MulActionWithZero αᵒᵈ β := - { OrderDual.instMulAction, OrderDual.instSMulWithZero with } - -instance instMulActionWithZero' [MonoidWithZero α] [AddMonoid β] [MulActionWithZero α β] : - MulActionWithZero α βᵒᵈ := - { OrderDual.instMulAction', OrderDual.instSMulWithZero' with } - -instance instDistribMulAction [MonoidWithZero α] [AddMonoid β] [DistribMulAction α β] : - DistribMulAction αᵒᵈ β where - smul_add := smul_add (M := α) - smul_zero := smul_zero (M := α) - -instance instDistribMulAction' [MonoidWithZero α] [AddMonoid β] [DistribMulAction α β] : - DistribMulAction α βᵒᵈ where - smul_add := smul_add (A := β) - smul_zero := smul_zero (A := β) +namespace OrderDual instance instModule [Semiring α] [AddCommMonoid β] [Module α β] : Module αᵒᵈ β where add_smul := add_smul (R := α) @@ -91,3 +33,13 @@ instance instModule' [Semiring α] [AddCommMonoid β] [Module α β] : Module α zero_smul := zero_smul _ end OrderDual + +namespace Lex + +instance instModule [Semiring α] [AddCommMonoid β] [Module α β] : Module (Lex α) β := + ‹Module α β› + +instance instModule' [Semiring α] [AddCommMonoid β] [Module α β] : Module α (Lex β) := + ‹Module α β› + +end Lex 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 0646b0b825b56..7cf5e1c4143ca 100644 --- a/Mathlib/Algebra/Order/Monoid/Canonical/Defs.lean +++ b/Mathlib/Algebra/Order/Monoid/Canonical/Defs.lean @@ -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 := @@ -112,7 +112,7 @@ theorem bot_eq_one : (⊥ : α) = 1 := le_antisymm bot_le (one_le ⊥) @[to_additive] instance CanonicallyOrderedCommMonoid.toUniqueUnits : Unique αˣ where - uniq a := Units.ext ((mul_eq_one_iff_of_one_le (α := α) (one_le _) $ one_le _).1 a.mul_inv).1 + uniq a := Units.ext ((mul_eq_one_iff_of_one_le (α := α) (one_le _) <| one_le _).1 a.mul_inv).1 @[deprecated (since := "2024-07-24")] alias mul_eq_one_iff := mul_eq_one @[deprecated (since := "2024-07-24")] alias add_eq_zero_iff := add_eq_zero @@ -128,6 +128,10 @@ theorem one_lt_iff_ne_one : 1 < a ↔ a ≠ 1 := @[to_additive] theorem eq_one_or_one_lt (a : α) : a = 1 ∨ 1 < a := (one_le a).eq_or_lt.imp_left Eq.symm +@[to_additive] +lemma one_not_mem_iff {s : Set α} : 1 ∉ s ↔ ∀ x ∈ s, 1 < x := + bot_eq_one (α := α) ▸ bot_not_mem_iff + @[to_additive (attr := simp) add_pos_iff] theorem one_lt_mul_iff : 1 < a * b ↔ 1 < a ∨ 1 < b := by simp only [one_lt_iff_ne_one, Ne, mul_eq_one, not_and_or] diff --git a/Mathlib/Algebra/Order/Monoid/Defs.lean b/Mathlib/Algebra/Order/Monoid/Defs.lean index 3e9fcaaa3a139..61e8c9e8a30d9 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. -/ diff --git a/Mathlib/Algebra/Order/Monoid/OrderDual.lean b/Mathlib/Algebra/Order/Monoid/OrderDual.lean index 065c6ee564a2d..6c9ac68a97316 100644 --- a/Mathlib/Algebra/Order/Monoid/OrderDual.lean +++ b/Mathlib/Algebra/Order/Monoid/OrderDual.lean @@ -9,7 +9,6 @@ import Mathlib.Algebra.Order.Monoid.Defs /-! # Ordered monoid structures on the order dual. -/ - universe u variable {α : Type u} diff --git a/Mathlib/Algebra/Order/Monoid/Prod.lean b/Mathlib/Algebra/Order/Monoid/Prod.lean index c6998f304353c..e3d9ab5369849 100644 --- a/Mathlib/Algebra/Order/Monoid/Prod.lean +++ b/Mathlib/Algebra/Order/Monoid/Prod.lean @@ -40,7 +40,7 @@ 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 diff --git a/Mathlib/Algebra/Order/Monoid/Submonoid.lean b/Mathlib/Algebra/Order/Monoid/Submonoid.lean index 6aa9c7927f6b2..d88dd033520c1 100644 --- a/Mathlib/Algebra/Order/Monoid/Submonoid.lean +++ b/Mathlib/Algebra/Order/Monoid/Submonoid.lean @@ -3,16 +3,15 @@ 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.GroupWithZero.Unbundled import Mathlib.Algebra.Order.Monoid.Basic -import Mathlib.Algebra.Order.ZeroLEOne /-! # Ordered instances on submonoids -/ +assert_not_exists MonoidWithZero + namespace SubmonoidClass variable {M S : Type*} [SetLike S M] @@ -103,21 +102,4 @@ variable {M} @[to_additive (attr := simp) mem_nonneg] lemma mem_oneLE : a ∈ oneLE M ↔ 1 ≤ a := Iff.rfl end Preorder - -section MulZeroClass -variable (α) [MulZeroOneClass α] [PartialOrder α] [PosMulStrictMono α] [ZeroLEOneClass α] - [NeZero (1 : α)] {a : α} - -/-- The submonoid of positive elements. -/ -@[simps] def pos : Submonoid α where - carrier := Set.Ioi 0 - one_mem' := zero_lt_one - mul_mem' := mul_pos - -variable {α} - -@[simp] lemma mem_pos : a ∈ pos α ↔ 0 < a := Iff.rfl - -end MulZeroClass - end Submonoid diff --git a/Mathlib/Algebra/Order/Monoid/Unbundled/Basic.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/Basic.lean index 05333081038c7..f33502550e3da 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/Basic.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/Basic.lean @@ -965,9 +965,6 @@ theorem mul_eq_one_iff_of_one_le [CovariantClass α α (· * ·) (· ≤ ·)] have : b = 1 := le_antisymm this hb And.intro ‹a = 1› ‹b = 1›) (by rintro ⟨rfl, rfl⟩; rw [mul_one]) - -- Porting note: original proof of the second implication, - -- `fun ⟨ha', hb'⟩ => by rw [ha', hb', mul_one]`, - -- had its `to_additive`-ization fail due to some bug @[deprecated (since := "2024-07-24")] alias mul_eq_one_iff' := mul_eq_one_iff_of_one_le @[deprecated (since := "2024-07-24")] alias add_eq_zero_iff' := add_eq_zero_iff_of_nonneg @@ -1292,7 +1289,7 @@ theorem Contravariant.MulLECancellable [Mul α] [LE α] [ContravariantClass α 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 @@ -1309,12 +1306,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 @@ -1327,9 +1324,9 @@ protected theorem mul_le_mul_iff_left [Mul α] [CovariantClass α α (· * ·) ( ⟨fun h => ha h, fun h => mul_le_mul_left' h a⟩ @[to_additive] -protected theorem mul_le_mul_iff_right [Mul α] [i : IsSymmOp α α (· * ·)] +protected theorem mul_le_mul_iff_right [Mul α] [i : @Std.Commutative α (· * ·)] [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] + 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 α α (· * ·) (· ≤ ·)] @@ -1344,13 +1341,29 @@ protected theorem mul_le_iff_le_one_right [MulOneClass α] [CovariantClass α α 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 α α (· * ·)] +protected theorem le_mul_iff_one_le_left [MulOneClass α] [i : @Std.Commutative α (· * ·)] [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} (ha : MulLECancellable a) : - a ≤ b * a ↔ 1 ≤ b := by rw [i.symm_op, ha.le_mul_iff_one_le_right] + 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 α α (· * ·)] +protected theorem mul_le_iff_le_one_left [MulOneClass α] [i : @Std.Commutative α (· * ·)] [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} (ha : MulLECancellable a) : - b * a ≤ a ↔ b ≤ 1 := by rw [i.symm_op, ha.mul_le_iff_le_one_right] + b * a ≤ a ↔ b ≤ 1 := by rw [i.comm, ha.mul_le_iff_le_one_right] + +@[to_additive] lemma mul [Semigroup α] {a b : α} (ha : MulLECancellable a) + (hb : MulLECancellable b) : MulLECancellable (a * b) := + fun c d hcd ↦ hb <| ha <| by rwa [← mul_assoc, ← mul_assoc] + +@[to_additive] lemma of_mul_right [Semigroup α] [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} + (h : MulLECancellable (a * b)) : MulLECancellable b := + fun c d hcd ↦ h <| by rw [mul_assoc, mul_assoc]; exact mul_le_mul_left' hcd _ + +@[to_additive] lemma of_mul_left [CommSemigroup α] [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} + (h : MulLECancellable (a * b)) : MulLECancellable a := (mul_comm a b ▸ h).of_mul_right end MulLECancellable + +@[to_additive (attr := simp)] +lemma mulLECancellable_mul [LE α] [CommSemigroup α] [CovariantClass α α (· * ·) (· ≤ ·)] {a b : α} : + 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 4cd50c3dca94c..6418be782db5c 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/Defs.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/Defs.lean @@ -117,6 +117,142 @@ class ContravariantClass : Prop where `r` also holds for the pair `(n₁, n₂)`. -/ protected elim : Contravariant M N μ r +/-- Typeclass for monotonicity of multiplication on the left, +namely `b₁ ≤ b₂ → a * b₁ ≤ a * b₂`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedCommMonoid`. -/ +abbrev MulLeftMono [Mul M] [LE M] : Prop := + CovariantClass M M (· * ·) (· ≤ ·) + +/-- Typeclass for monotonicity of multiplication on the right, +namely `a₁ ≤ a₂ → a₁ * b ≤ a₂ * b`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedCommMonoid`. -/ +abbrev MulRightMono [Mul M] [LE M] : Prop := + CovariantClass M M (swap (· * ·)) (· ≤ ·) + +/-- Typeclass for monotonicity of addition on the left, +namely `b₁ ≤ b₂ → a + b₁ ≤ a + b₂`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedAddCommMonoid`. -/ +abbrev AddLeftMono [Add M] [LE M] : Prop := + CovariantClass M M (· + ·) (· ≤ ·) + +/-- Typeclass for monotonicity of addition on the right, +namely `a₁ ≤ a₂ → a₁ + b ≤ a₂ + b`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedAddCommMonoid`. -/ +abbrev AddRightMono [Add M] [LE M] : Prop := + CovariantClass M M (swap (· + ·)) (· ≤ ·) + +attribute [to_additive existing] MulLeftMono MulRightMono + +/-- Typeclass for monotonicity of multiplication on the left, +namely `b₁ < b₂ → a * b₁ < a * b₂`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedCommGroup`. -/ +abbrev MulLeftStrictMono [Mul M] [LT M] : Prop := + CovariantClass M M (· * ·) (· < ·) + +/-- Typeclass for monotonicity of multiplication on the right, +namely `a₁ < a₂ → a₁ * b < a₂ * b`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedCommGroup`. -/ +abbrev MulRightStrictMono [Mul M] [LT M] : Prop := + CovariantClass M M (swap (· * ·)) (· < ·) + +/-- Typeclass for monotonicity of addition on the left, +namely `b₁ < b₂ → a + b₁ < a + b₂`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedAddCommGroup`. -/ +abbrev AddLeftStrictMono [Add M] [LT M] : Prop := + CovariantClass M M (· + ·) (· < ·) + +/-- Typeclass for monotonicity of addition on the right, +namely `a₁ < a₂ → a₁ + b < a₂ + b`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedAddCommGroup`. -/ +abbrev AddRightStrictMono [Add M] [LT M] : Prop := + CovariantClass M M (swap (· + ·)) (· < ·) + +attribute [to_additive existing] MulLeftStrictMono MulRightStrictMono + +/-- Typeclass for strict reverse monotonicity of multiplication on the left, +namely `a * b₁ < a * b₂ → b₁ < b₂`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedCommGroup`. -/ +abbrev MulLeftReflectLT [Mul M] [LT M] : Prop := + ContravariantClass M M (· * ·) (· < ·) + +/-- Typeclass for strict reverse monotonicity of multiplication on the right, +namely `a₁ * b < a₂ * b → a₁ < a₂`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedCommGroup`. -/ +abbrev MulRightReflectLT [Mul M] [LT M] : Prop := + ContravariantClass M M (swap (· * ·)) (· < ·) + +/-- Typeclass for strict reverse monotonicity of addition on the left, +namely `a + b₁ < a + b₂ → b₁ < b₂`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedAddCommGroup`. -/ +abbrev AddLeftReflectLT [Add M] [LT M] : Prop := + ContravariantClass M M (· + ·) (· < ·) + +/-- Typeclass for strict reverse monotonicity of addition on the right, +namely `a₁ * b < a₂ * b → a₁ < a₂`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedAddCommGroup`. -/ +abbrev AddRightReflectLT [Add M] [LT M] : Prop := + ContravariantClass M M (swap (· + ·)) (· < ·) + +attribute [to_additive existing] MulLeftReflectLT MulRightReflectLT + +/-- Typeclass for reverse monotonicity of multiplication on the left, +namely `a * b₁ ≤ a * b₂ → b₁ ≤ b₂`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedCancelCommMonoid`. -/ +abbrev MulLeftReflectLE [Mul M] [LE M] : Prop := + ContravariantClass M M (· * ·) (· ≤ ·) + +/-- Typeclass for reverse monotonicity of multiplication on the right, +namely `a₁ * b ≤ a₂ * b → a₁ ≤ a₂`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedCancelCommMonoid`. -/ +abbrev MulRightReflectLE [Mul M] [LE M] : Prop := + ContravariantClass M M (swap (· * ·)) (· ≤ ·) + +/-- Typeclass for reverse monotonicity of addition on the left, +namely `a + b₁ ≤ a + b₂ → b₁ ≤ b₂`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedCancelAddCommMonoid`. -/ +abbrev AddLeftReflectLE [Add M] [LE M] : Prop := + ContravariantClass M M (· + ·) (· ≤ ·) + +/-- Typeclass for reverse monotonicity of addition on the right, +namely `a₁ + b ≤ a₂ + b → a₁ ≤ a₂`. + +You should usually not use this very granular typeclass directly, but rather a typeclass like +`OrderedCancelAddCommMonoid`. -/ +abbrev AddRightReflectLE [Add M] [LE M] : Prop := + ContravariantClass M M (swap (· + ·)) (· ≤ ·) + +attribute [to_additive existing] MulLeftReflectLE MulRightReflectLE + theorem rel_iff_cov [CovariantClass M N μ r] [ContravariantClass M N μ r] (m : M) {a b : N} : r (μ m a) (μ m b) ↔ r a b := ⟨ContravariantClass.elim _, CovariantClass.elim _⟩ @@ -154,6 +290,16 @@ instance (priority := 100) Group.covconv [Group N] [CovariantClass N N (· * ·) ContravariantClass N N (· * ·) r := ⟨Group.covariant_iff_contravariant.mp CovariantClass.elim⟩ +@[to_additive] +theorem Group.mulLeftReflectLE_of_mulLeftMono [Group N] [LE N] + [MulLeftMono N] : MulLeftReflectLE N := + inferInstance + +@[to_additive] +theorem Group.mulLeftReflectLT_of_mulLeftStrictMono [Group N] [LT N] + [MulLeftStrictMono N] : MulLeftReflectLT N := + inferInstance + @[to_additive] theorem Group.covariant_swap_iff_contravariant_swap [Group N] : Covariant N N (swap (· * ·)) r ↔ Contravariant N N (swap (· * ·)) r := by @@ -169,10 +315,20 @@ instance (priority := 100) Group.covconv_swap [Group N] [CovariantClass N N (swa ContravariantClass N N (swap (· * ·)) r := ⟨Group.covariant_swap_iff_contravariant_swap.mp CovariantClass.elim⟩ +@[to_additive] +theorem Group.mulRightReflectLE_of_mulRightMono [Group N] [LE N] + [MulRightMono N] : MulRightReflectLE N := + inferInstance + +@[to_additive] +theorem Group.mulRightReflectLT_of_mulRightStrictMono [Group N] [LT N] + [MulRightStrictMono N] : MulRightReflectLT N := + inferInstance + 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 := @@ -205,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)) : @@ -263,6 +419,14 @@ theorem covariant_le_of_covariant_lt [PartialOrder N] : theorem covariantClass_le_of_lt [PartialOrder N] [CovariantClass M N μ (· < ·)] : CovariantClass M N μ (· ≤ ·) := ⟨covariant_le_of_covariant_lt _ _ _ CovariantClass.elim⟩ +@[to_additive] +theorem mulLeftMono_of_mulLeftStrictMono (M) [Mul M] [PartialOrder M] [MulLeftStrictMono M] : + MulLeftMono M := covariantClass_le_of_lt _ _ _ + +@[to_additive] +theorem mulRightMono_of_mulRightStrictMono (M) [Mul M] [PartialOrder M] [MulRightStrictMono M] : + MulRightMono M := covariantClass_le_of_lt _ _ _ + theorem contravariant_le_iff_contravariant_lt_and_eq [PartialOrder N] : Contravariant M N μ (· ≤ ·) ↔ Contravariant M N μ (· < ·) ∧ Contravariant M N μ (· = ·) := by refine ⟨fun h ↦ ⟨fun a b c bc ↦ ?_, fun a b c bc ↦ ?_⟩, fun h ↦ fun a b c bc ↦ ?_⟩ @@ -286,30 +450,70 @@ 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 elim := (covariant_le_iff_contravariant_lt N N mu).mp CovariantClass.elim +@[to_additive] +theorem mulLeftReflectLT_of_mulLeftMono [Mul N] [LinearOrder N] [MulLeftMono N] : + MulLeftReflectLT N := + inferInstance + +@[to_additive] +theorem mulRightReflectLT_of_mulRightMono [Mul N] [LinearOrder N] [MulRightMono N] : + MulRightReflectLT N := + inferInstance + instance covariant_lt_of_contravariant_le [LinearOrder N] [ContravariantClass N N mu (· ≤ ·)] : CovariantClass N N mu (· < ·) where elim := (covariant_lt_iff_contravariant_le N N mu).mpr ContravariantClass.elim +@[to_additive] +theorem mulLeftStrictMono_of_mulLeftReflectLE [Mul N] [LinearOrder N] [MulLeftReflectLE N] : + MulLeftStrictMono N := + inferInstance + +@[to_additive] +theorem mulRightStrictMono_of_mulRightReflectLE [Mul N] [LinearOrder N] [MulRightReflectLE N] : + MulRightStrictMono N := + inferInstance + @[to_additive] instance covariant_swap_mul_of_covariant_mul [CommSemigroup N] [CovariantClass N N (· * ·) r] : CovariantClass N N (swap (· * ·)) r where elim := (covariant_flip_iff N r (· * ·)).mpr CovariantClass.elim +@[to_additive] +theorem mulRightMono_of_mulLeftMono [CommSemigroup N] [LE N] [MulLeftMono N] : + MulRightMono N := + inferInstance + +@[to_additive] +theorem mulRightStrictMono_of_mulLeftStrictMono [CommSemigroup N] [LT N] [MulLeftStrictMono N] : + MulRightStrictMono N := + inferInstance + @[to_additive] instance contravariant_swap_mul_of_contravariant_mul [CommSemigroup N] [ContravariantClass N N (· * ·) r] : ContravariantClass N N (swap (· * ·)) r where elim := (contravariant_flip_iff N r (· * ·)).mpr ContravariantClass.elim +@[to_additive] +theorem mulRightReflectLE_of_mulLeftReflectLE [CommSemigroup N] [LE N] [MulLeftReflectLE N] : + MulRightReflectLE N := + inferInstance + +@[to_additive] +theorem mulRightReflectLT_of_mulLeftReflectLT [CommSemigroup N] [LT N] [MulLeftReflectLT N] : + MulRightReflectLT N := + inferInstance + theorem covariant_lt_of_covariant_le_of_contravariant_eq [ContravariantClass M N μ (· = ·)] [PartialOrder N] [CovariantClass M N μ (· ≤ ·)] : CovariantClass M N μ (· < ·) where elim a _ _ bc := (CovariantClass.elim a bc.le).lt_of_ne (bc.ne ∘ ContravariantClass.elim _) diff --git a/Mathlib/Algebra/Order/Monoid/Unbundled/ExistsOfLE.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/ExistsOfLE.lean index 6823941784225..da6e069dc2d22 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/ExistsOfLE.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/ExistsOfLE.lean @@ -1,27 +1,23 @@ /- -Copyright (c) 2016 Jeremy Avigad. All rights reserved. +Copyright (c) 2021 Peter Nelson. 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 +Authors: Peter Nelson, Yaël Dillies -/ import Mathlib.Algebra.Order.Monoid.Unbundled.Basic import Mathlib.Order.MinMax /-! # Unbundled and weaker forms of canonically ordered monoids + +This file provides a Prop-valued mixin for monoids satisfying a one-sided cancellativity property, +namely that there is some `c` such that `b = a + c` if `a ≤ b`. This is particularly useful for +generalising statements from groups/rings/fields that don't mention negation or subtraction to +monoids/semirings/semifields. -/ universe u - - variable {α : Type u} -/-- An `OrderedCommMonoid` with one-sided 'division' in the sense that -if `a ≤ b`, there is some `c` for which `a * c = b`. This is a weaker version -of the condition on canonical orderings defined by `CanonicallyOrderedCommMonoid`. -/ -class ExistsMulOfLE (α : Type u) [Mul α] [LE α] : Prop where - /-- For `a ≤ b`, `a` left divides `b` -/ - exists_mul_of_le : ∀ {a b : α}, a ≤ b → ∃ c : α, b = a * c - /-- An `OrderedAddCommMonoid` with one-sided 'subtraction' in the sense that if `a ≤ b`, then there is some `c` for which `a + c = b`. This is a weaker version of the condition on canonical orderings defined by `CanonicallyOrderedAddCommMonoid`. -/ @@ -29,10 +25,15 @@ class ExistsAddOfLE (α : Type u) [Add α] [LE α] : Prop where /-- For `a ≤ b`, there is a `c` so `b = a + c`. -/ exists_add_of_le : ∀ {a b : α}, a ≤ b → ∃ c : α, b = a + c -attribute [to_additive] ExistsMulOfLE +/-- An `OrderedCommMonoid` with one-sided 'division' in the sense that +if `a ≤ b`, there is some `c` for which `a * c = b`. This is a weaker version +of the condition on canonical orderings defined by `CanonicallyOrderedCommMonoid`. -/ +@[to_additive] +class ExistsMulOfLE (α : Type u) [Mul α] [LE α] : Prop where + /-- For `a ≤ b`, `a` left divides `b` -/ + exists_mul_of_le : ∀ {a b : α}, a ≤ b → ∃ c : α, b = a * c export ExistsMulOfLE (exists_mul_of_le) - export ExistsAddOfLE (exists_add_of_le) -- See note [lower instance priority] @@ -41,14 +42,23 @@ instance (priority := 100) Group.existsMulOfLE (α : Type u) [Group α] [LE α] ⟨fun {a b} _ => ⟨a⁻¹ * b, (mul_inv_cancel_left _ _).symm⟩⟩ section MulOneClass +variable [MulOneClass α] [Preorder α] [ExistsMulOfLE α] {a b : α} -variable [MulOneClass α] [Preorder α] [ContravariantClass α α (· * ·) (· < ·)] [ExistsMulOfLE α] - {a b : α} +@[to_additive] lemma exists_one_le_mul_of_le [ContravariantClass α α (· * ·) (· ≤ ·)] (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] -theorem exists_one_lt_mul_of_lt' (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 exists_one_lt_mul_of_lt' [ContravariantClass α α (· * ·) (· < ·)] (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 := + ⟨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 := + ⟨exists_one_lt_mul_of_lt', by rintro ⟨c, hc, rfl⟩; exact lt_mul_of_one_lt_right' _ hc⟩ end MulOneClass @@ -72,5 +82,3 @@ theorem le_iff_forall_one_lt_lt_mul' : 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 35fb12d567968..b509125489cc7 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/MinMax.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/MinMax.lean @@ -21,7 +21,7 @@ section CommSemigroup variable [LinearOrder α] [CommSemigroup β] @[to_additive] -lemma fn_min_mul_fn_max (f : α → β) (a b : α) : f (min a b) * f (max a b) = f a * f b := by +lemma fn_min_mul_fn_max (f : α → β) (a b : α) : f (min a b) * f (max a b) = f a * f b := by obtain h | h := le_total a b <;> simp [h, mul_comm] @[to_additive] @@ -108,7 +108,7 @@ theorem mul_lt_mul_iff_of_le_of_le [CovariantClass α α (· * ·) (· ≤ ·)] [CovariantClass α α (Function.swap (· * ·)) (· < ·)] {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 => ?_⟩ - cases' h with ha' hb' + rcases h with ha' | hb' · exact mul_lt_mul_of_lt_of_le ha' hb · exact mul_lt_mul_of_le_of_lt ha hb' diff --git a/Mathlib/Algebra/Order/Monoid/Unbundled/OrderDual.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/OrderDual.lean index c1dc58f5a86f8..7a9819c7230f1 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/OrderDual.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/OrderDual.lean @@ -8,7 +8,6 @@ import Mathlib.Algebra.Order.Monoid.Unbundled.Defs /-! # Unbundled ordered monoid structures on the order dual. -/ - universe u variable {α : Type u} @@ -61,4 +60,4 @@ instance covariantClass_swap_mul_lt [LT α] [Mul α] CovariantClass αᵒᵈ αᵒᵈ (swap (· * ·)) (· < ·) := ⟨c.1.flip⟩ - +end OrderDual diff --git a/Mathlib/Algebra/Order/Monoid/Unbundled/Pow.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/Pow.lean index ca33dfd14cedd..eb892cfeda6b8 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/Pow.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/Pow.lean @@ -24,97 +24,100 @@ 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 [CovariantClass M 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 [CovariantClass M 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 l IH - · rw [pow_succ]; simpa using ha - · 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 [CovariantClass M 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} -@[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 @@ -145,6 +148,13 @@ section CovariantLESwap variable [Preorder β] [CovariantClass M M (· * ·) (· ≤ ·)] [CovariantClass M M (swap (· * ·)) (· ≤ ·)] +@[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 | 0 => by simpa using monotone_const @@ -157,24 +167,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 @@ -207,6 +199,10 @@ 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] +end CovariantLE + +section CovariantLT + variable [CovariantClass M M (· * ·) (· < ·)] {a : M} {m n : ℕ} @[to_additive nsmul_le_nsmul_iff_left] @@ -217,7 +213,7 @@ 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 @@ -267,11 +263,8 @@ theorem Left.pow_lt_one_iff [CovariantClass M M (· * ·) (· < ·)] {n : ℕ} { @[to_additive] theorem Right.pow_lt_one_iff [CovariantClass M M (swap (· * ·)) (· < ·)] {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 := covariantClass_le_of_lt M M (swap (· * ·)) + ⟨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 @@ -288,39 +281,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/WithTop.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/WithTop.lean index ff3e96790de20..0b75be72f5aaf 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₂ (· + ·)⟩ @@ -305,9 +305,9 @@ instance addMonoidWithOne : AddMonoidWithOne (WithTop α) := @[simp, norm_cast] lemma coe_natCast (n : ℕ) : ((n : α) : WithTop α) = n := rfl -@[simp] lemma natCast_ne_top (n : ℕ) : (n : WithTop α) ≠ ⊤ := coe_ne_top - @[simp] lemma top_ne_natCast (n : ℕ) : (⊤ : WithTop α) ≠ n := top_ne_coe +@[simp] lemma natCast_ne_top (n : ℕ) : (n : WithTop α) ≠ ⊤ := coe_ne_top +@[simp] lemma natCast_lt_top [LT α] (n : ℕ) : (n : WithTop α) < ⊤ := coe_lt_top _ @[deprecated (since := "2024-04-05")] alias coe_nat := coe_natCast @[deprecated (since := "2024-04-05")] alias nat_ne_top := natCast_ne_top diff --git a/Mathlib/Algebra/Order/Monovary.lean b/Mathlib/Algebra/Order/Monovary.lean index ae10daf0e8d58..e085b565b3140 100644 --- a/Mathlib/Algebra/Order/Monovary.lean +++ b/Mathlib/Algebra/Order/Monovary.lean @@ -6,6 +6,7 @@ Authors: Yaël Dillies import Mathlib.Algebra.Order.Field.Basic import Mathlib.Algebra.Order.Group.Instances import Mathlib.Algebra.Order.Module.OrderedSMul +import Mathlib.Algebra.Order.Module.Synonym import Mathlib.Algebra.Order.Monoid.Unbundled.MinMax import Mathlib.Order.Monotone.Monovary @@ -237,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 @@ -259,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] diff --git a/Mathlib/Algebra/Order/Nonneg/Field.lean b/Mathlib/Algebra/Order/Nonneg/Field.lean index ccefe4dce40fa..d69aaf2a8dc28 100644 --- a/Mathlib/Algebra/Order/Nonneg/Field.lean +++ b/Mathlib/Algebra/Order/Nonneg/Field.lean @@ -6,7 +6,6 @@ Authors: Floris van Doorn import Mathlib.Algebra.Order.Field.Canonical.Defs import Mathlib.Algebra.Order.Field.InjSurj import Mathlib.Algebra.Order.Nonneg.Ring -import Mathlib.Algebra.Order.Field.Unbundled.Basic import Mathlib.Data.Nat.Cast.Order.Ring /-! @@ -46,7 +45,7 @@ section LinearOrderedSemifield variable [LinearOrderedSemifield α] {x y : α} instance inv : Inv { x : α // 0 ≤ x } := - ⟨fun x => ⟨x⁻¹, inv_nonneg (α := α) |>.2 x.2⟩⟩ + ⟨fun x => ⟨x⁻¹, inv_nonneg.2 x.2⟩⟩ @[simp, norm_cast] protected theorem coe_inv (a : { x : α // 0 ≤ x }) : ((a⁻¹ : { x : α // 0 ≤ x }) : α) = (a : α)⁻¹ := @@ -54,7 +53,7 @@ protected theorem coe_inv (a : { x : α // 0 ≤ x }) : ((a⁻¹ : { x : α // 0 @[simp] theorem inv_mk (hx : 0 ≤ x) : - (⟨x, hx⟩ : { x : α // 0 ≤ x })⁻¹ = ⟨x⁻¹, inv_nonneg (α := α) |>.2 hx⟩ := + (⟨x, hx⟩ : { x : α // 0 ≤ x })⁻¹ = ⟨x⁻¹, inv_nonneg.2 hx⟩ := rfl instance div : Div { x : α // 0 ≤ x } := diff --git a/Mathlib/Algebra/Order/Nonneg/Ring.lean b/Mathlib/Algebra/Order/Nonneg/Ring.lean index 46375d95d4a1d..87af067c65378 100644 --- a/Mathlib/Algebra/Order/Nonneg/Ring.lean +++ b/Mathlib/Algebra/Order/Nonneg/Ring.lean @@ -78,12 +78,24 @@ instance orderedCommSemiring [OrderedCommSemiring α] : OrderedCommSemiring { x (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) fun _ => rfl +instance orderedCommMonoid [OrderedCommSemiring α] : OrderedCommMonoid { x : α // 0 ≤ x } where + mul_le_mul_left a _ h c := mul_le_mul le_rfl h a.prop c.prop + instance strictOrderedCommSemiring [StrictOrderedCommSemiring α] : StrictOrderedCommSemiring { x : α // 0 ≤ x } := Subtype.coe_injective.strictOrderedCommSemiring _ Nonneg.coe_zero Nonneg.coe_one (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) fun _ => rfl +instance existsAddOfLE [StrictOrderedCommSemiring α] [ExistsAddOfLE α] : + ExistsAddOfLE { x : α // 0 ≤ x } := + ⟨fun {a b} h ↦ by + rw [← Subtype.coe_le_coe] at h + obtain ⟨c, hc⟩ := exists_add_of_le h + refine ⟨⟨c, ?_⟩, by simp [Subtype.ext_iff, hc]⟩ + rw [← add_zero a.val, hc] at h + exact le_of_add_le_add_left h⟩ + instance nontrivial [LinearOrderedSemiring α] : Nontrivial { x : α // 0 ≤ x } := ⟨⟨0, 1, fun h => zero_ne_one (congr_arg Subtype.val h)⟩⟩ @@ -93,7 +105,7 @@ instance linearOrderedSemiring [LinearOrderedSemiring α] : (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) fun _ _ => rfl -instance linearOrderedCommMonoidWithZero [LinearOrderedCommRing α] : +instance linearOrderedCommMonoidWithZero [LinearOrderedCommSemiring α] : LinearOrderedCommMonoidWithZero { x : α // 0 ≤ x } := { Nonneg.linearOrderedSemiring, Nonneg.orderedCommSemiring with mul_le_mul_left := fun _ _ h c ↦ mul_le_mul_of_nonneg_left h c.prop } diff --git a/Mathlib/Algebra/Order/Pi.lean b/Mathlib/Algebra/Order/Pi.lean index b89f80e5f895b..9710857e2382b 100644 --- a/Mathlib/Algebra/Order/Pi.lean +++ b/Mathlib/Algebra/Order/Pi.lean @@ -6,7 +6,6 @@ Authors: Simon Hudon, Patrick Massot import Mathlib.Algebra.Order.Monoid.Canonical.Defs import Mathlib.Algebra.Order.Ring.Defs import Mathlib.Algebra.Ring.Pi -import Mathlib.Algebra.Order.Monoid.Canonical.Defs /-! # Pi instances for ordered groups and monoids @@ -129,6 +128,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 2bda973451012..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 8178078ac60be..5d1fc0b381760 100644 --- a/Mathlib/Algebra/Order/Positive/Field.lean +++ b/Mathlib/Algebra/Order/Positive/Field.lean @@ -5,7 +5,6 @@ Authors: Yury Kudryashov -/ import Mathlib.Algebra.Order.Field.Defs import Mathlib.Algebra.Order.Positive.Ring -import Mathlib.Algebra.Order.Field.Unbundled.Basic /-! # Algebraic structures on the set of positive numbers @@ -19,15 +18,14 @@ variable {K : Type*} [LinearOrderedField K] namespace Positive -instance Subtype.inv : Inv { x : K // 0 < x } := - ⟨fun x => ⟨x⁻¹, inv_pos (α := K)|>.2 x.2⟩⟩ +instance Subtype.inv : Inv { x : K // 0 < x } := ⟨fun x => ⟨x⁻¹, inv_pos.2 x.2⟩⟩ @[simp] 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/Rearrangement.lean b/Mathlib/Algebra/Order/Rearrangement.lean index 4966d47669fd9..f69acca4d99d3 100644 --- a/Mathlib/Algebra/Order/Rearrangement.lean +++ b/Mathlib/Algebra/Order/Rearrangement.lean @@ -5,7 +5,7 @@ Authors: Mantas Bakšys -/ import Mathlib.Algebra.BigOperators.Group.Finset import Mathlib.Algebra.Order.Module.OrderedSMul -import Mathlib.Algebra.Order.Group.Instances +import Mathlib.Algebra.Order.Module.Synonym import Mathlib.Data.Prod.Lex import Mathlib.Data.Set.Image import Mathlib.GroupTheory.Perm.Support @@ -40,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 @@ -105,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 @@ -133,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 @@ -163,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 @@ -235,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`. -/ @@ -255,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`. -/ @@ -275,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`. -/ @@ -298,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`. -/ @@ -321,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 /-! @@ -329,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 := @@ -419,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 f834a11db01cb..e61b8d4297a31 100644 --- a/Mathlib/Algebra/Order/Ring/Abs.lean +++ b/Mathlib/Algebra/Order/Ring/Abs.lean @@ -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`. -/ @@ -111,13 +111,13 @@ lemma abs_lt_of_sq_lt_sq (h : a ^ 2 < b ^ 2) (hb : 0 ≤ b) : |a| < b := by rwa [← abs_of_nonneg hb, ← sq_lt_sq] lemma abs_lt_of_sq_lt_sq' (h : a ^ 2 < b ^ 2) (hb : 0 ≤ b) : -b < a ∧ a < b := - abs_lt.1 $ abs_lt_of_sq_lt_sq h hb + abs_lt.1 <| abs_lt_of_sq_lt_sq h hb lemma abs_le_of_sq_le_sq (h : a ^ 2 ≤ b ^ 2) (hb : 0 ≤ b) : |a| ≤ b := by rwa [← abs_of_nonneg hb, ← sq_le_sq] lemma abs_le_of_sq_le_sq' (h : a ^ 2 ≤ b ^ 2) (hb : 0 ≤ b) : -b ≤ a ∧ a ≤ b := - abs_le.1 $ abs_le_of_sq_le_sq h hb + abs_le.1 <| abs_le_of_sq_le_sq h hb lemma sq_eq_sq_iff_abs_eq_abs (a b : α) : a ^ 2 = b ^ 2 ↔ |a| = |b| := by simp only [le_antisymm_iff, sq_le_sq] @@ -196,7 +196,7 @@ lemma pow_eq_one_iff_cases : a ^ n = 1 ↔ n = 0 ∨ a = 1 ∨ a = -1 ∧ Even n lemma pow_eq_neg_pow_iff (hb : b ≠ 0) : a ^ n = -b ^ n ↔ a = -b ∧ Odd n := match n.even_or_odd with | .inl he => - suffices a ^ n > -b ^ n by simpa [he] using this.ne' + suffices a ^ n > -b ^ n by simpa [he, not_odd_iff_even.2 he] using this.ne' lt_of_lt_of_le (by simp [he.pow_pos hb]) (he.pow_nonneg _) | .inr ho => by simp only [ho, and_true, ← ho.neg_pow, (ho.strictMono_pow (R := R)).injective.eq_iff] @@ -226,7 +226,7 @@ lemma Even.mod_even (hn : Even n) (ha : Even a) : Even (n % a) := (Even.mod_even_iff ha).mpr hn lemma Odd.of_dvd_nat (hn : Odd n) (hm : m ∣ n) : Odd m := - odd_iff_not_even.2 <| mt hm.even (odd_iff_not_even.1 hn) + not_even_iff_odd.1 <| mt hm.even (not_even_iff_odd.2 hn) /-- `2` is not a factor of an odd natural number. -/ lemma Odd.ne_two_of_dvd_nat {m n : ℕ} (hn : Odd n) (hm : m ∣ n) : m ≠ 2 := by diff --git a/Mathlib/Algebra/Order/Ring/Basic.lean b/Mathlib/Algebra/Order/Ring/Basic.lean index a4780f5c89c08..5e64f73cc40ea 100644 --- a/Mathlib/Algebra/Order/Ring/Basic.lean +++ b/Mathlib/Algebra/Order/Ring/Basic.lean @@ -37,15 +37,12 @@ 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 k ih - · simp only [zero_add, pow_one, le_refl] - · let n := k.succ + induction k with + | zero => simp only [zero_add, pow_one, le_refl] + | succ k ih => + let n := k.succ have h1 := add_nonneg (mul_nonneg hx (pow_nonneg hy n)) (mul_nonneg hy (pow_nonneg hx n)) have h2 := add_nonneg hx hy calc @@ -59,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 @@ -100,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) _) @@ -116,11 +88,19 @@ 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 +-- See note [reducible non instances] +/-- Turn an ordered domain into a strict ordered ring. -/ +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') + section StrictOrderedSemiring variable [StrictOrderedSemiring R] {a x y : R} {n m : ℕ} @@ -269,12 +249,12 @@ lemma add_pow_le (ha : 0 ≤ a) (hb : 0 ≤ b) : ∀ n, (a + b) ^ n ≤ 2 ^ (n - rw [pow_succ] calc _ ≤ 2 ^ n * (a ^ (n + 1) + b ^ (n + 1)) * (a + b) := - mul_le_mul_of_nonneg_right (add_pow_le ha hb (n + 1)) $ add_nonneg ha hb + mul_le_mul_of_nonneg_right (add_pow_le ha hb (n + 1)) <| add_nonneg ha hb _ = 2 ^ n * (a ^ (n + 2) + b ^ (n + 2) + (a ^ (n + 1) * b + b ^ (n + 1) * a)) := by rw [mul_assoc, mul_add, add_mul, add_mul, ← pow_succ, ← pow_succ, add_comm _ (b ^ _), add_add_add_comm, add_comm (_ * a)] _ ≤ 2 ^ n * (a ^ (n + 2) + b ^ (n + 2) + (a ^ (n + 1) * a + b ^ (n + 1) * b)) := - mul_le_mul_of_nonneg_left (add_le_add_left ?_ _) $ pow_nonneg (zero_le_two (α := R)) _ + mul_le_mul_of_nonneg_left (add_le_add_left ?_ _) <| pow_nonneg (zero_le_two (α := R)) _ _ = _ := by simp only [← pow_succ, ← two_mul, ← mul_assoc]; rfl · obtain hab | hba := le_total a b · exact mul_add_mul_le_mul_add_mul (pow_le_pow_left ha hab _) hab @@ -289,7 +269,7 @@ protected lemma Even.add_pow_le (hn : Even n) : _ = 2 ^ n * (a ^ 2 + b ^ 2) ^ n := by -- TODO: Should be `Nat.cast_commute` rw [Commute.mul_pow]; simp [Commute, SemiconjBy, two_mul, mul_two] _ ≤ 2 ^ n * (2 ^ (n - 1) * ((a ^ 2) ^ n + (b ^ 2) ^ n)) := mul_le_mul_of_nonneg_left - (add_pow_le (sq_nonneg _) (sq_nonneg _) _) $ pow_nonneg (zero_le_two (α := R)) _ + (add_pow_le (sq_nonneg _) (sq_nonneg _) _) <| pow_nonneg (zero_le_two (α := R)) _ _ = _ := by simp only [← mul_assoc, ← pow_add, ← pow_mul] cases n @@ -352,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 432f79a5c6202..1f64f689d1e79 100644 --- a/Mathlib/Algebra/Order/Ring/Canonical.lean +++ b/Mathlib/Algebra/Order/Ring/Canonical.lean @@ -3,8 +3,9 @@ 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 -/ +import Mathlib.Algebra.Order.Monoid.Canonical.Defs import Mathlib.Algebra.Order.Ring.Defs -import Mathlib.Algebra.Order.Sub.Canonical +import Mathlib.Algebra.Order.Sub.Basic import Mathlib.Algebra.Ring.Parity /-! diff --git a/Mathlib/Algebra/Order/Ring/Cast.lean b/Mathlib/Algebra/Order/Ring/Cast.lean index 98e9a362cfbdd..bd47e1f894415 100644 --- a/Mathlib/Algebra/Order/Ring/Cast.lean +++ b/Mathlib/Algebra/Order/Ring/Cast.lean @@ -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 8789ad725e530..71c21076f0093 100644 --- a/Mathlib/Algebra/Order/Ring/Cone.lean +++ b/Mathlib/Algebra/Order/Ring/Cone.lean @@ -1,68 +1,86 @@ /- 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 +Authors: Jeremy Avigad, Leonardo de Moura, Mario Carneiro, Artie Khovanov -/ import Mathlib.Algebra.Order.Group.Cone -import Mathlib.Algebra.Order.Ring.Defs +import Mathlib.Algebra.Order.Ring.Basic +import Mathlib.Algebra.Ring.Subsemiring.Order /-! -# Constructing an ordered ring from a ring with a specified positive cone. +# Construct ordered rings from rings with a specified positive cone. --/ - - -/-! ### Positive cones -/ - - -variable {α : Type*} [Ring α] [Nontrivial α] - -namespace Ring - -/-- A positive cone in a ring consists of a positive cone in underlying `AddCommGroup`, -which contains `1` and such that the positive elements are closed under multiplication. -/ -structure PositiveCone (α : Type*) [Ring α] extends AddCommGroup.PositiveCone α where - /-- In a positive cone, `1` is `nonneg` -/ - one_nonneg : nonneg 1 - /-- In a positive cone, if `a` and `b` are `pos` then so is `a * b` -/ - mul_pos : ∀ a b, pos a → pos b → pos (a * b) - -/-- Forget that a positive cone in a ring respects the multiplicative structure. -/ -add_decl_doc PositiveCone.toPositiveCone +In this file we provide the structure `RingCone` +that encodes axioms of `OrderedRing` and `LinearOrderedRing` +in terms of the subset of non-negative elements. -/-- A total positive cone in a nontrivial ring induces a linear order. -/ -structure TotalPositiveCone (α : Type*) [Ring α] extends PositiveCone α, - AddCommGroup.TotalPositiveCone α - -/-- Forget that a `TotalPositiveCone` in a ring is total. -/ -add_decl_doc TotalPositiveCone.toPositiveCone_1 - -/-- Forget that a `TotalPositiveCone` in a ring respects the multiplicative structure. -/ -add_decl_doc TotalPositiveCone.toTotalPositiveCone - -theorem PositiveCone.one_pos (C : PositiveCone α) : C.pos 1 := - (C.pos_iff _).2 ⟨C.one_nonneg, fun h => one_ne_zero <| C.nonneg_antisymm C.one_nonneg h⟩ - -end Ring - -open Ring - -/-- Construct a `StrictOrderedRing` by designating a positive cone in an existing `Ring`. -/ -def StrictOrderedRing.mkOfPositiveCone (C : PositiveCone α) : StrictOrderedRing α := - { ‹Ring α›, OrderedAddCommGroup.mkOfPositiveCone C.toPositiveCone with - exists_pair_ne := ⟨0, 1, fun h => by simpa [← h, C.pos_iff] using C.one_pos⟩, - zero_le_one := by - change C.nonneg (1 - 0) - convert C.one_nonneg - simp, - mul_pos := fun x y xp yp => by - change C.pos (x * y - 0) - -- Porting note: used to be convert, but it relied on unfolding definitions - rw [sub_zero] - exact C.mul_pos x y (by rwa [← sub_zero x]) (by rwa [← sub_zero y]) } +We also provide constructors that convert between +cones in rings and the corresponding ordered rings. +-/ -/-- Construct a `LinearOrderedRing` by -designating a positive cone in an existing `Ring`. -/ -def LinearOrderedRing.mkOfPositiveCone (C : TotalPositiveCone α) : LinearOrderedRing α := - { LinearOrderedAddCommGroup.mkOfPositiveCone C.toTotalPositiveCone, - StrictOrderedRing.mkOfPositiveCone C.toPositiveCone_1 with } +/-- `RingConeClass S R` says that `S` is a type of cones in `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 +does not contain both `a` and `-a` for any nonzero `a`. +This is equivalent to being the set of non-negative elements of +some order making the ring into a partially ordered ring. -/ +structure RingCone (R : Type*) [Ring R] extends Subsemiring R, AddGroupCone R + +/-- Interpret a cone in a ring as a cone in the underlying additive group. -/ +add_decl_doc RingCone.toAddGroupCone + +instance RingCone.instSetLike (R : Type*) [Ring R] : SetLike (RingCone R) R where + coe C := C.carrier + coe_injective' p q h := by cases p; cases q; congr; exact SetLike.ext' h + +instance RingCone.instRingConeClass (R : Type*) [Ring R] : + RingConeClass (RingCone R) R where + add_mem {C} := C.add_mem' + zero_mem {C} := C.zero_mem' + mul_mem {C} := C.mul_mem' + one_mem {C} := C.one_mem' + eq_zero_of_mem_of_neg_mem {C} := C.eq_zero_of_mem_of_neg_mem' + +namespace RingCone + +variable {T : Type*} [OrderedRing T] {a : T} + +variable (T) in +/-- Construct a cone from the set of non-negative elements of a partially ordered ring. -/ +def nonneg : RingCone T where + __ := Subsemiring.nonneg T + eq_zero_of_mem_of_neg_mem' {a} := by simpa using ge_antisymm + +@[simp] lemma nonneg_toSubsemiring : (nonneg T).toSubsemiring = .nonneg T := rfl +@[simp] lemma nonneg_toAddGroupCone : (nonneg T).toAddGroupCone = .nonneg T := rfl +@[simp] lemma mem_nonneg : a ∈ nonneg T ↔ 0 ≤ a := Iff.rfl +@[simp, norm_cast] lemma coe_nonneg : nonneg T = {x : T | 0 ≤ x} := rfl + +instance nonneg.isMaxCone {T : Type*} [LinearOrderedRing T] : IsMaxCone (nonneg T) where + mem_or_neg_mem := mem_or_neg_mem (C := AddGroupCone.nonneg T) + +end RingCone + +variable {S R : Type*} [Ring R] [SetLike S R] (C : S) + +/-- Construct a partially ordered ring by designating a cone in a ring. +Warning: using this def as a constructor in an instance can lead to diamonds +due to non-customisable field: `lt`. -/ +@[reducible] def OrderedRing.mkOfCone [RingConeClass S R] : OrderedRing R where + __ := ‹Ring R› + __ := OrderedAddCommGroup.mkOfCone C + zero_le_one := show _ ∈ C by simpa using one_mem C + mul_nonneg x y xnn ynn := show _ ∈ C by simpa using mul_mem xnn ynn + +/-- Construct a linearly ordered domain by designating a maximal cone in a domain. +Warning: using this def as a constructor in an instance can lead to diamonds +due to non-customisable fields: `lt`, `decidableLT`, `decidableEq`, `compare`. -/ +@[reducible] def LinearOrderedRing.mkOfCone + [IsDomain R] [RingConeClass S R] [IsMaxCone C] + (dec : DecidablePred (· ∈ C)) : LinearOrderedRing R where + __ := OrderedRing.mkOfCone C + __ := OrderedRing.toStrictOrderedRing R + le_total a b := by simpa using mem_or_neg_mem (b - a) + decidableLE a b := dec _ diff --git a/Mathlib/Algebra/Order/Ring/Defs.lean b/Mathlib/Algebra/Order/Ring/Defs.lean index 61fcecb798dbf..2a1301cc48fc2 100644 --- a/Mathlib/Algebra/Order/Ring/Defs.lean +++ b/Mathlib/Algebra/Order/Ring/Defs.lean @@ -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 @@ -389,16 +405,11 @@ instance (priority := 100) LinearOrderedRing.isDomain : IsDomain α where obtain ha | ha := ha.lt_or_lt exacts [(strictAnti_mul_right ha).injective h, (strictMono_mul_right_of_pos ha).injective h] -end LinearOrderedSemiring - -section LinearOrderedCommSemiring -variable [LinearOrderedCommSemiring α] {a b c d : α} - -- See note [lower instance priority] -instance (priority := 100) LinearOrderedCommSemiring.toLinearOrderedCancelAddCommMonoid : - LinearOrderedCancelAddCommMonoid α where __ := ‹LinearOrderedCommSemiring α› +instance (priority := 100) LinearOrderedSemiring.toLinearOrderedCancelAddCommMonoid : + LinearOrderedCancelAddCommMonoid α where __ := ‹LinearOrderedSemiring α› -end LinearOrderedCommSemiring +end LinearOrderedSemiring section LinearOrderedRing variable [LinearOrderedRing α] {a b c : α} diff --git a/Mathlib/Algebra/Order/Ring/Int.lean b/Mathlib/Algebra/Order/Ring/Int.lean index 19de25e7f6877..6cebdbab75355 100644 --- a/Mathlib/Algebra/Order/Ring/Int.lean +++ b/Mathlib/Algebra/Order/Ring/Int.lean @@ -51,7 +51,7 @@ instance instOrderedRing : OrderedRing ℤ := StrictOrderedRing.toOrderedRing' /-! ### Miscellaneous lemmas -/ lemma isCompl_even_odd : IsCompl { n : ℤ | Even n } { n | Odd n } := by - simp [← Set.compl_setOf, isCompl_compl] + simp [← not_even_iff_odd, ← Set.compl_setOf, isCompl_compl] lemma _root_.Nat.cast_natAbs {α : Type*} [AddGroupWithOne α] (n : ℤ) : (n.natAbs : α) = |n| := by rw [← natCast_natAbs, Int.cast_natCast] diff --git a/Mathlib/Algebra/Order/Ring/Nat.lean b/Mathlib/Algebra/Order/Ring/Nat.lean index ed74130a665a2..3b3be2c922c0a 100644 --- a/Mathlib/Algebra/Order/Ring/Nat.lean +++ b/Mathlib/Algebra/Order/Ring/Nat.lean @@ -8,7 +8,6 @@ import Mathlib.Algebra.Order.GroupWithZero.Canonical import Mathlib.Algebra.Order.Ring.Canonical import Mathlib.Algebra.Ring.Nat import Mathlib.Data.Set.Basic -import Mathlib.Init.Data.Nat.Lemmas /-! # The natural numbers form an ordered semiring @@ -41,7 +40,7 @@ instance instCanonicallyOrderedCommSemiring : CanonicallyOrderedCommSemiring ℕ __ := instLinearOrderedCommSemiring exists_add_of_le h := (Nat.le.dest h).imp fun _ => Eq.symm le_self_add := Nat.le_add_right - eq_zero_or_eq_zero_of_mul_eq_zero := Nat.eq_zero_of_mul_eq_zero + eq_zero_or_eq_zero_of_mul_eq_zero := Nat.mul_eq_zero.mp /-! ### Extra instances to short-circuit type class resolution @@ -59,6 +58,6 @@ instance instOrderedCommSemiring : OrderedCommSemiring ℕ := /-! ### Miscellaneous lemmas -/ lemma isCompl_even_odd : IsCompl { n : ℕ | Even n } { n | Odd n } := by - simp only [← Set.compl_setOf, isCompl_compl, odd_iff_not_even] + simp only [← Set.compl_setOf, isCompl_compl, ← not_even_iff_odd] end Nat 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 00c5c90fcde79..88cca6d79229f 100644 --- a/Mathlib/Algebra/Order/Ring/Rat.lean +++ b/Mathlib/Algebra/Order/Ring/Rat.lean @@ -3,8 +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, Mario Carneiro -/ -import Mathlib.Algebra.Order.Ring.Int -import Mathlib.Algebra.Ring.Rat +import Mathlib.Algebra.Order.Ring.Defs +import Mathlib.Algebra.Order.Ring.Unbundled.Rat /-! # The rational numbers form a linear ordered field @@ -27,168 +27,6 @@ assert_not_exists GaloisConnection namespace Rat -variable {a b c 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 - rw [mk'_eq_divInt, divInt_eq_iff hb.ne' (mod_cast hd)] at hab - rw [← num_nonneg, ← mul_nonneg_iff_of_pos_right hb, ← hab, - mul_nonneg_iff_of_pos_right (mod_cast Nat.pos_of_ne_zero hd)] - -@[simp] lemma divInt_nonneg {a b : ℤ} (ha : 0 ≤ a) (hb : 0 ≤ b) : 0 ≤ a /. b := by - obtain rfl | hb := hb.eq_or_lt - · simp - rfl - rwa [divInt_nonneg_iff_of_pos_right hb] - -@[simp] lemma mkRat_nonneg {a : ℤ} (ha : 0 ≤ a) (b : ℕ) : 0 ≤ mkRat a b := by - simpa using divInt_nonneg ha (Int.natCast_nonneg _) - -theorem ofScientific_nonneg (m : ℕ) (s : Bool) (e : ℕ) : - 0 ≤ Rat.ofScientific m s e := by - rw [Rat.ofScientific] - cases s - · rw [if_neg (by decide)] - refine num_nonneg.mp ?_ - rw [num_natCast] - exact Int.natCast_nonneg _ - · rw [if_pos rfl, normalize_eq_mkRat] - exact Rat.mkRat_nonneg (Int.natCast_nonneg _) _ - -instance _root_.NNRatCast.toOfScientific {K} [NNRatCast K] : OfScientific K where - ofScientific (m : ℕ) (b : Bool) (d : ℕ) := - NNRat.cast ⟨Rat.ofScientific m b d, ofScientific_nonneg m b d⟩ - -/-- Casting a scientific literal via `ℚ≥0` is the same as casting directly. -/ -@[simp, norm_cast] -theorem _root_.NNRat.cast_ofScientific {K} [NNRatCast K] (m : ℕ) (s : Bool) (e : ℕ) : - (OfScientific.ofScientific m s e : ℚ≥0) = (OfScientific.ofScientific m s e : K) := - rfl - -protected lemma add_nonneg : 0 ≤ a → 0 ≤ b → 0 ≤ a + b := - numDenCasesOn' a fun n₁ d₁ h₁ ↦ numDenCasesOn' b fun n₂ d₂ h₂ ↦ by - have d₁0 : 0 < (d₁ : ℤ) := mod_cast Nat.pos_of_ne_zero h₁ - have d₂0 : 0 < (d₂ : ℤ) := mod_cast Nat.pos_of_ne_zero h₂ - simp only [d₁0, d₂0, h₁, h₂, mul_pos, divInt_nonneg_iff_of_pos_right, divInt_add_divInt, Ne, - Nat.cast_eq_zero, not_false_iff] - intro n₁0 n₂0 - apply add_nonneg <;> apply mul_nonneg <;> · first |assumption|apply Int.ofNat_zero_le - -protected lemma mul_nonneg : 0 ≤ a → 0 ≤ b → 0 ≤ a * b := - numDenCasesOn' a fun n₁ d₁ h₁ => - numDenCasesOn' b fun n₂ d₂ h₂ => by - have d₁0 : 0 < (d₁ : ℤ) := mod_cast Nat.pos_of_ne_zero h₁ - have d₂0 : 0 < (d₂ : ℤ) := mod_cast Nat.pos_of_ne_zero h₂ - simp only [d₁0, d₂0, mul_pos, divInt_nonneg_iff_of_pos_right, - divInt_mul_divInt _ _ d₁0.ne' d₂0.ne'] - apply mul_nonneg - --- Porting note (#11215): TODO can this be shortened? -protected theorem le_iff_sub_nonneg (a b : ℚ) : a ≤ b ↔ 0 ≤ b - a := - numDenCasesOn'' a fun na da ha hared => - numDenCasesOn'' b fun nb db hb hbred => by - change Rat.blt _ _ = false ↔ _ - unfold Rat.blt - simp only [Bool.and_eq_true, decide_eq_true_eq, Bool.ite_eq_false_distrib, - decide_eq_false_iff_not, not_lt, ite_eq_left_iff, not_and, not_le, ← num_nonneg] - split_ifs with h h' - · rw [Rat.sub_def] - simp only [false_iff, not_le] - simp only [normalize_eq] - apply Int.ediv_neg' - · rw [sub_neg] - apply lt_of_lt_of_le - · apply mul_neg_of_neg_of_pos h.1 - rwa [Int.natCast_pos, Nat.pos_iff_ne_zero] - · apply mul_nonneg h.2 (Int.natCast_nonneg _) - · simp only [Int.natCast_pos, Nat.pos_iff_ne_zero] - exact Nat.gcd_ne_zero_right (Nat.mul_ne_zero hb ha) - · simp only [divInt_ofNat, ← zero_iff_num_zero, mkRat_eq_zero hb] at h' - simp [h'] - · simp only [Rat.sub_def, normalize_eq] - refine ⟨fun H => ?_, fun H _ => ?_⟩ - · refine Int.ediv_nonneg ?_ (Int.natCast_nonneg _) - rw [sub_nonneg] - push_neg at h - obtain hb|hb := Ne.lt_or_lt h' - · apply H - intro H' - exact (hb.trans H').false.elim - · obtain ha|ha := le_or_lt na 0 - · apply le_trans <| mul_nonpos_of_nonpos_of_nonneg ha (Int.natCast_nonneg _) - exact mul_nonneg hb.le (Int.natCast_nonneg _) - · exact H (fun _ => ha) - · rw [← sub_nonneg] - contrapose! H - apply Int.ediv_neg' H - simp only [Int.natCast_pos, Nat.pos_iff_ne_zero] - exact Nat.gcd_ne_zero_right (Nat.mul_ne_zero hb ha) - -protected lemma divInt_le_divInt {a b c d : ℤ} (b0 : 0 < b) (d0 : 0 < d) : - a /. b ≤ c /. d ↔ a * d ≤ c * b := by - rw [Rat.le_iff_sub_nonneg, ← sub_nonneg (α := ℤ)] - simp [sub_eq_add_neg, ne_of_gt b0, ne_of_gt d0, mul_pos d0 b0] - -protected lemma le_total : a ≤ b ∨ b ≤ a := by - simpa only [← Rat.le_iff_sub_nonneg, neg_sub] using Rat.nonneg_total (b - a) - -protected theorem not_le {a b : ℚ} : ¬a ≤ b ↔ b < a := (Bool.not_eq_false _).to_iff - -instance linearOrder : LinearOrder ℚ where - le_refl a := by rw [Rat.le_iff_sub_nonneg, ← num_nonneg]; simp - le_trans a b c hab hbc := by - rw [Rat.le_iff_sub_nonneg] at hab hbc - have := Rat.add_nonneg hab hbc - simp_rw [sub_eq_add_neg, add_left_comm (b + -a) c (-b), add_comm (b + -a) (-b), - add_left_comm (-b) b (-a), add_comm (-b) (-a), add_neg_cancel_comm_assoc, - ← sub_eq_add_neg] at this - rwa [Rat.le_iff_sub_nonneg] - le_antisymm a b hab hba := by - rw [Rat.le_iff_sub_nonneg] at hab hba - rw [sub_eq_add_neg] at hba - rw [← neg_sub, sub_eq_add_neg] at hab - have := eq_neg_of_add_eq_zero_left (Rat.nonneg_antisymm hba hab) - rwa [neg_neg] at this - le_total _ _ := Rat.le_total - decidableEq := inferInstance - decidableLE := inferInstance - decidableLT := inferInstance - lt_iff_le_not_le _ _ := by rw [← Rat.not_le, and_iff_right_of_imp Rat.le_total.resolve_left] - -/-! -### Extra instances to short-circuit type class resolution - -These also prevent non-computable instances being used to construct these instances non-computably. --/ - -instance instDistribLattice : DistribLattice ℚ := inferInstance -instance instLattice : Lattice ℚ := inferInstance -instance instSemilatticeInf : SemilatticeInf ℚ := inferInstance -instance instSemilatticeSup : SemilatticeSup ℚ := inferInstance -instance instInf : Inf ℚ := inferInstance -instance instSup : Sup ℚ := inferInstance -instance instPartialOrder : PartialOrder ℚ := inferInstance -instance instPreorder : Preorder ℚ := inferInstance - -/-! ### Miscellaneous lemmas -/ - -protected lemma le_def : p ≤ q ↔ p.num * q.den ≤ q.num * p.den := by - rw [← num_divInt_den q, ← num_divInt_den p] - conv_rhs => simp only [num_divInt_den] - exact Rat.divInt_le_divInt (mod_cast p.pos) (mod_cast q.pos) - -protected lemma lt_def : p < q ↔ p.num * q.den < q.num * p.den := by - rw [lt_iff_le_and_ne, Rat.le_def] - suffices p ≠ q ↔ p.num * q.den ≠ q.num * p.den by - constructor <;> intro h - · exact lt_iff_le_and_ne.mpr ⟨h.left, this.mp h.right⟩ - · have tmp := lt_iff_le_and_ne.mp h - exact ⟨tmp.left, this.mpr tmp.right⟩ - exact not_iff_not.mpr eq_iff_mul_eq_mul - -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 instLinearOrderedCommRing : LinearOrderedCommRing ℚ where __ := Rat.linearOrder __ := Rat.commRing @@ -213,32 +51,4 @@ instance : OrderedCancelAddCommMonoid ℚ := by infer_instance instance : OrderedAddCommMonoid ℚ := by infer_instance -@[simp] lemma num_nonpos {a : ℚ} : a.num ≤ 0 ↔ a ≤ 0 := by simpa using @num_nonneg (-a) -@[simp] lemma num_pos {a : ℚ} : 0 < a.num ↔ 0 < a := lt_iff_lt_of_le_iff_le num_nonpos -@[simp] lemma num_neg {a : ℚ} : a.num < 0 ↔ a < 0 := lt_iff_lt_of_le_iff_le num_nonneg - -@[deprecated (since := "2024-02-16")] alias num_nonneg_iff_zero_le := num_nonneg -@[deprecated (since := "2024-02-16")] alias num_pos_iff_pos := num_pos - -theorem div_lt_div_iff_mul_lt_mul {a b c d : ℤ} (b_pos : 0 < b) (d_pos : 0 < d) : - (a : ℚ) / b < c / d ↔ a * d < c * b := by - simp only [lt_iff_le_not_le] - apply and_congr - · simp [div_def', Rat.divInt_le_divInt b_pos d_pos] - · apply not_congr - simp [div_def', Rat.divInt_le_divInt d_pos b_pos] - -theorem lt_one_iff_num_lt_denom {q : ℚ} : q < 1 ↔ q.num < q.den := by simp [Rat.lt_def] - -theorem abs_def (q : ℚ) : |q| = q.num.natAbs /. q.den := by - rcases le_total q 0 with hq | hq - · rw [abs_of_nonpos hq] - rw [← num_divInt_den q, ← zero_divInt, Rat.divInt_le_divInt (mod_cast q.pos) zero_lt_one, - mul_one, zero_mul] at hq - rw [Int.ofNat_natAbs_of_nonpos hq, ← neg_def] - · rw [abs_of_nonneg hq] - rw [← num_divInt_den q, ← zero_divInt, Rat.divInt_le_divInt zero_lt_one (mod_cast q.pos), - mul_one, zero_mul] at hq - rw [Int.natAbs_of_nonneg hq, num_divInt_den] - end Rat diff --git a/Mathlib/Algebra/Order/Ring/Star.lean b/Mathlib/Algebra/Order/Ring/Star.lean index da189507528bc..06f3ffa17e0cc 100644 --- a/Mathlib/Algebra/Order/Ring/Star.lean +++ b/Mathlib/Algebra/Order/Ring/Star.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jireh Loreaux -/ import Mathlib.Algebra.Order.Ring.Defs -import Mathlib.Algebra.Star.Order +import Mathlib.Algebra.Order.Star.Basic /-! # Commutative star-ordered rings are ordered rings @@ -23,7 +23,7 @@ namespace StarOrderedRing /- This example shows that nonnegative elements in a ordered semiring which is also star-ordered must commute. We provide this only as an example as opposed to a lemma because we never expect the -type class assumptions to be satisfied without a `CommSemiring` intance already in scope; not that +type class assumptions to be satisfied without a `CommSemiring` instance already in scope; not that it is impossible, only that it shouldn't occur in practice. -/ example {R : Type*} [OrderedSemiring R] [StarRing R] [StarOrderedRing R] {x y : R} (hx : 0 ≤ x) (hy : 0 ≤ y) : x * y = y * x := by diff --git a/Mathlib/Algebra/Order/Ring/Unbundled/Basic.lean b/Mathlib/Algebra/Order/Ring/Unbundled/Basic.lean index 738f12558d80d..ea150bfb7d6fe 100644 --- a/Mathlib/Algebra/Order/Ring/Unbundled/Basic.lean +++ b/Mathlib/Algebra/Order/Ring/Unbundled/Basic.lean @@ -136,31 +136,6 @@ section OrderedSemiring variable [Semiring α] [Preorder α] {a b c d : α} -@[simp] -theorem pow_nonneg [ZeroLEOneClass α] [PosMulMono α] - (H : 0 ≤ a) : ∀ n : ℕ, 0 ≤ a ^ n - | 0 => by - rw [pow_zero] - exact zero_le_one - | n + 1 => by - rw [pow_succ] - exact mul_nonneg (pow_nonneg H _) H - -lemma pow_le_pow_of_le_one [ZeroLEOneClass α] [PosMulMono α] [MulPosMono α] - (ha₀ : 0 ≤ a) (ha₁ : a ≤ 1) : ∀ {m n : ℕ}, m ≤ n → a ^ n ≤ a ^ m - | _, _, Nat.le.refl => le_rfl - | _, _, Nat.le.step h => by - rw [pow_succ'] - exact (mul_le_of_le_one_left (pow_nonneg ha₀ _) ha₁).trans $ pow_le_pow_of_le_one ha₀ ha₁ h - -lemma pow_le_of_le_one [ZeroLEOneClass α] [PosMulMono α] [MulPosMono α] - (h₀ : 0 ≤ a) (h₁ : a ≤ 1) {n : ℕ} (hn : n ≠ 0) : a ^ n ≤ a := - (pow_one a).subst (pow_le_pow_of_le_one h₀ h₁ (Nat.pos_of_ne_zero hn)) - -lemma sq_le [ZeroLEOneClass α] [PosMulMono α] [MulPosMono α] - (h₀ : 0 ≤ a) (h₁ : a ≤ 1) : a ^ 2 ≤ a := - pow_le_of_le_one h₀ h₁ two_ne_zero - -- Porting note: it's unfortunate we need to write `(@one_le_two α)` here. theorem add_le_mul_two_add [ZeroLEOneClass α] [MulPosMono α] [CovariantClass α α (· + ·) (· ≤ ·)] (a2 : 2 ≤ a) (b0 : 0 ≤ b) : a + (2 + b) ≤ a * (2 + b) := @@ -169,68 +144,6 @@ theorem add_le_mul_two_add [ZeroLEOneClass α] [MulPosMono α] [CovariantClass add_le_add_left (add_le_add a2 <| le_mul_of_one_le_left b0 <| (@one_le_two α).trans a2) a _ ≤ a * (2 + b) := by rw [mul_add, mul_two, add_assoc] -theorem one_le_mul_of_one_le_of_one_le [ZeroLEOneClass α] [PosMulMono α] - (ha : 1 ≤ a) (hb : 1 ≤ b) : (1 : α) ≤ a * b := - Left.one_le_mul_of_le_of_le ha hb <| zero_le_one.trans ha - -section Monotone - -variable [Preorder β] {f g : β → α} - -theorem monotone_mul_left_of_nonneg [PosMulMono α] - (ha : 0 ≤ a) : Monotone fun x => a * x := fun _ _ h => - mul_le_mul_of_nonneg_left h ha - -theorem monotone_mul_right_of_nonneg [MulPosMono α] - (ha : 0 ≤ a) : Monotone fun x => x * a := fun _ _ h => - mul_le_mul_of_nonneg_right h ha - -theorem Monotone.mul_const [MulPosMono α] - (hf : Monotone f) (ha : 0 ≤ a) : Monotone fun x => f x * a := - (monotone_mul_right_of_nonneg ha).comp hf - -theorem Monotone.const_mul [PosMulMono α] - (hf : Monotone f) (ha : 0 ≤ a) : Monotone fun x => a * f x := - (monotone_mul_left_of_nonneg ha).comp hf - -theorem Antitone.mul_const [MulPosMono α] - (hf : Antitone f) (ha : 0 ≤ a) : Antitone fun x => f x * a := - (monotone_mul_right_of_nonneg ha).comp_antitone hf - -theorem Antitone.const_mul [PosMulMono α] - (hf : Antitone f) (ha : 0 ≤ a) : Antitone fun x => a * f x := - (monotone_mul_left_of_nonneg ha).comp_antitone hf - -theorem Monotone.mul [PosMulMono α] [MulPosMono α] - (hf : Monotone f) (hg : Monotone g) (hf₀ : ∀ x, 0 ≤ f x) (hg₀ : ∀ x, 0 ≤ g x) : - Monotone (f * g) := - fun _ _ h => mul_le_mul (hf h) (hg h) (hg₀ _) (hf₀ _) - -end Monotone - -theorem mul_le_one [ZeroLEOneClass α] [PosMulMono α] [MulPosMono α] - (ha : a ≤ 1) (hb' : 0 ≤ b) (hb : b ≤ 1) : a * b ≤ 1 := - one_mul (1 : α) ▸ mul_le_mul ha hb hb' zero_le_one - -theorem one_lt_mul_of_le_of_lt [ZeroLEOneClass α] [MulPosMono α] - (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 - -theorem one_lt_mul_of_lt_of_le [ZeroLEOneClass α] [PosMulMono α] - (ha : 1 < a) (hb : 1 ≤ b) : 1 < a * b := - ha.trans_le <| le_mul_of_one_le_right (zero_le_one.trans ha.le) hb - -alias one_lt_mul := one_lt_mul_of_le_of_lt - -theorem mul_lt_one_of_nonneg_of_lt_one_left [PosMulMono α] - (ha₀ : 0 ≤ a) (ha : a < 1) (hb : b ≤ 1) : a * b < 1 := - (mul_le_of_le_one_right ha₀ hb).trans_lt ha - -theorem mul_lt_one_of_nonneg_of_lt_one_right [MulPosMono α] - (ha : a ≤ 1) (hb₀ : 0 ≤ b) (hb : b < 1) : a * b < 1 := - (mul_le_of_le_one_left hb₀ ha).trans_lt hb - - theorem mul_le_mul_of_nonpos_left [ExistsAddOfLE α] [PosMulMono α] [CovariantClass α α (swap (· + ·)) (· ≤ ·)] [ContravariantClass α α (swap (· + ·)) (· ≤ ·)] (h : b ≤ a) (hc : c ≤ 0) : c * a ≤ c * b := by @@ -286,7 +199,7 @@ theorem mul_le_mul_of_nonpos_of_nonpos' [ExistsAddOfLE α] [PosMulMono α] [MulP (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. -/ +/-- 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 (· + ·)) (· ≤ ·)] (hb : b ≤ 0) (h : a ≤ 1) : b ≤ a * b := by @@ -362,16 +275,6 @@ theorem Antitone.mul [ExistsAddOfLE α] [PosMulMono α] [MulPosMono α] Monotone (f * g) := fun _ _ h => mul_le_mul_of_nonpos_of_nonpos (hf h) (hg h) (hf₀ _) (hg₀ _) end Monotone - -lemma le_iff_exists_nonneg_add - [ExistsAddOfLE α] [ContravariantClass α α (· + ·) (· ≤ ·)] [CovariantClass α α (· + ·) (· ≤ ·)] - (a b : α) : a ≤ b ↔ ∃ c ≥ 0, b = a + c := by - refine ⟨fun h ↦ ?_, ?_⟩ - · obtain ⟨c, rfl⟩ := exists_add_of_le h - exact ⟨c, nonneg_of_le_add_right h, rfl⟩ - · rintro ⟨c, hc, rfl⟩ - exact le_add_of_nonneg_right hc - end OrderedSemiring section OrderedCommRing @@ -380,95 +283,6 @@ section StrictOrderedSemiring variable [Semiring α] [PartialOrder α] {a b c d : α} -@[simp] -theorem pow_pos [ZeroLEOneClass α] [PosMulStrictMono α] - (H : 0 < a) : ∀ n : ℕ, 0 < a ^ n - | 0 => by - nontriviality - rw [pow_zero] - exact zero_lt_one - | n + 1 => by - rw [pow_succ] - exact mul_pos (pow_pos H _) H - -theorem mul_self_lt_mul_self [PosMulStrictMono α] [MulPosMono α] - (h1 : 0 ≤ a) (h2 : a < b) : a * a < b * b := - mul_lt_mul' h2.le h2 h1 <| h1.trans_lt h2 - --- In the next lemma, we used to write `Set.Ici 0` instead of `{x | 0 ≤ x}`. --- As this lemma is not used outside this file, --- and the import for `Set.Ici` is not otherwise needed until later, --- we choose not to use it here. -theorem strictMonoOn_mul_self [PosMulStrictMono α] [MulPosMono α] : - StrictMonoOn (fun x : α => x * x) { x | 0 ≤ x } := - fun _ hx _ _ hxy => mul_self_lt_mul_self hx hxy - --- See Note [decidable namespace] -protected theorem Decidable.mul_lt_mul'' [PosMulMono α] [PosMulStrictMono α] [MulPosStrictMono α] - [@DecidableRel α (· ≤ ·)] (h1 : a < c) (h2 : b < d) - (h3 : 0 ≤ a) (h4 : 0 ≤ b) : a * b < c * d := - h4.lt_or_eq_dec.elim (fun b0 => mul_lt_mul h1 h2.le b0 <| h3.trans h1.le) fun b0 => by - rw [← b0, mul_zero]; exact mul_pos (h3.trans_lt h1) (h4.trans_lt h2) - -theorem lt_mul_left [MulPosStrictMono α] - (hn : 0 < a) (hm : 1 < b) : a < b * a := by - convert mul_lt_mul_of_pos_right hm hn - rw [one_mul] - -theorem lt_mul_right [PosMulStrictMono α] - (hn : 0 < a) (hm : 1 < b) : a < a * b := by - convert mul_lt_mul_of_pos_left hm hn - rw [mul_one] - -theorem lt_mul_self [ZeroLEOneClass α] [MulPosStrictMono α] - (hn : 1 < a) : a < a * a := - lt_mul_left (hn.trans_le' zero_le_one) hn - -section Monotone - -variable [Preorder β] {f g : β → α} - -theorem strictMono_mul_left_of_pos [PosMulStrictMono α] - (ha : 0 < a) : StrictMono fun x => a * x := fun _ _ b_lt_c => - mul_lt_mul_of_pos_left b_lt_c ha - -theorem strictMono_mul_right_of_pos [MulPosStrictMono α] - (ha : 0 < a) : StrictMono fun x => x * a := fun _ _ b_lt_c => - mul_lt_mul_of_pos_right b_lt_c ha - -theorem StrictMono.mul_const [MulPosStrictMono α] - (hf : StrictMono f) (ha : 0 < a) : StrictMono fun x => f x * a := - (strictMono_mul_right_of_pos ha).comp hf - -theorem StrictMono.const_mul [PosMulStrictMono α] - (hf : StrictMono f) (ha : 0 < a) : StrictMono fun x => a * f x := - (strictMono_mul_left_of_pos ha).comp hf - -theorem StrictAnti.mul_const [MulPosStrictMono α] - (hf : StrictAnti f) (ha : 0 < a) : StrictAnti fun x => f x * a := - (strictMono_mul_right_of_pos ha).comp_strictAnti hf - -theorem StrictAnti.const_mul [PosMulStrictMono α] - (hf : StrictAnti f) (ha : 0 < a) : StrictAnti fun x => a * f x := - (strictMono_mul_left_of_pos ha).comp_strictAnti hf - -theorem StrictMono.mul_monotone [PosMulMono α] [MulPosStrictMono α] - (hf : StrictMono f) (hg : Monotone g) (hf₀ : ∀ x, 0 ≤ f x) - (hg₀ : ∀ x, 0 < g x) : StrictMono (f * g) := fun _ _ h => - mul_lt_mul (hf h) (hg h.le) (hg₀ _) (hf₀ _) - -theorem Monotone.mul_strictMono [PosMulStrictMono α] [MulPosMono α] - (hf : Monotone f) (hg : StrictMono g) (hf₀ : ∀ x, 0 < f x) - (hg₀ : ∀ x, 0 ≤ g x) : StrictMono (f * g) := fun _ _ h => - mul_lt_mul' (hf h.le) (hg h) (hg₀ _) (hf₀ _) - -theorem StrictMono.mul [PosMulStrictMono α] [MulPosStrictMono α] - (hf : StrictMono f) (hg : StrictMono g) (hf₀ : ∀ x, 0 ≤ f x) - (hg₀ : ∀ x, 0 ≤ g x) : StrictMono (f * g) := fun _ _ h => - mul_lt_mul'' (hf h) (hg h) (hf₀ _) (hg₀ _) - -end Monotone - theorem lt_two_mul_self [ZeroLEOneClass α] [MulPosStrictMono α] [NeZero (R := α) 1] [CovariantClass α α (· + ·) (· < ·)] (ha : 0 < a) : a < 2 * a := lt_mul_of_one_lt_left ha one_lt_two @@ -563,9 +377,9 @@ lemma mul_add_mul_le_mul_add_mul [ExistsAddOfLE α] [MulPosMono α] [CovariantClass α α (· + ·) (· ≤ ·)] [ContravariantClass α α (· + ·) (· ≤ ·)] (hab : a ≤ b) (hcd : c ≤ d) : a * d + b * c ≤ a * c + b * d := by obtain ⟨b, rfl⟩ := exists_add_of_le hab - obtain ⟨d, rfl⟩ := exists_add_of_le hcd + obtain ⟨d, hd, rfl⟩ := exists_nonneg_add_of_le hcd rw [mul_add, add_right_comm, mul_add, ← add_assoc] - exact add_le_add_left (mul_le_mul_of_nonneg_right hab <| (le_add_iff_nonneg_right _).1 hcd) _ + exact add_le_add_left (mul_le_mul_of_nonneg_right hab hd) _ /-- Binary **rearrangement inequality**. -/ lemma mul_add_mul_le_mul_add_mul' [ExistsAddOfLE α] [MulPosMono α] @@ -580,9 +394,9 @@ lemma mul_add_mul_lt_mul_add_mul [ExistsAddOfLE α] [MulPosStrictMono α] [CovariantClass α α (· + ·) (· < ·)] (hab : a < b) (hcd : c < d) : a * d + b * c < a * c + b * d := by obtain ⟨b, rfl⟩ := exists_add_of_le hab.le - obtain ⟨d, rfl⟩ := exists_add_of_le hcd.le + obtain ⟨d, hd, rfl⟩ := exists_pos_add_of_lt' hcd rw [mul_add, add_right_comm, mul_add, ← add_assoc] - exact add_lt_add_left (mul_lt_mul_of_pos_right hab <| (lt_add_iff_pos_right _).1 hcd) _ + exact add_lt_add_left (mul_lt_mul_of_pos_right hab hd) _ /-- Binary **rearrangement inequality**. -/ lemma mul_add_mul_lt_mul_add_mul' [ExistsAddOfLE α] [MulPosStrictMono α] @@ -856,7 +670,7 @@ theorem mul_self_pos [ExistsAddOfLE α] [PosMulStrictMono α] [MulPosStrictMono rw [mul_zero] at h exact h.false · intro h - cases' h.lt_or_lt with h h + rcases h.lt_or_lt with h | h exacts [mul_pos_of_neg_of_neg h h, mul_pos h h] theorem nonneg_of_mul_nonpos_left [ExistsAddOfLE α] [MulPosStrictMono α] @@ -999,8 +813,4 @@ lemma mul_self_le_mul_self_of_le_of_neg_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/Rat.lean b/Mathlib/Algebra/Order/Ring/Unbundled/Rat.lean new file mode 100644 index 0000000000000..b2ad2a602b376 --- /dev/null +++ b/Mathlib/Algebra/Order/Ring/Unbundled/Rat.lean @@ -0,0 +1,226 @@ +/- +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.Group.Unbundled.Abs +import Mathlib.Algebra.Order.Group.Unbundled.Basic +import Mathlib.Algebra.Ring.Rat +import Mathlib.Data.Int.Order.Basic + +/-! +# The rational numbers possess a linear order + +This file constructs the order on `ℚ` and proves various facts relating the order to +ring structure on `ℚ`. This only uses unbundled type classes, eg `CovariantClass`, +relating the order structure and algebra structure on `ℚ`. +For the bundled `LinearOrderedCommRing` instance on `ℚ`, see `Algebra.Order.Ring.Rat`. + +## Tags + +rat, rationals, field, ℚ, numerator, denominator, num, denom, order, ordering +-/ + +assert_not_exists OrderedCommMonoid +assert_not_exists Field +assert_not_exists Finset +assert_not_exists Set.Icc +assert_not_exists GaloisConnection + +namespace Rat + +variable {a b c 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 + rw [mk'_eq_divInt, divInt_eq_iff hb.ne' (mod_cast hd)] at hab + rw [← num_nonneg, ← Int.mul_nonneg_iff_of_pos_right hb, ← hab, + Int.mul_nonneg_iff_of_pos_right (mod_cast Nat.pos_of_ne_zero hd)] + +@[simp] lemma divInt_nonneg {a b : ℤ} (ha : 0 ≤ a) (hb : 0 ≤ b) : 0 ≤ a /. b := by + obtain rfl | hb := hb.eq_or_lt + · simp + rfl + rwa [divInt_nonneg_iff_of_pos_right hb] + +@[simp] lemma mkRat_nonneg {a : ℤ} (ha : 0 ≤ a) (b : ℕ) : 0 ≤ mkRat a b := by + simpa using divInt_nonneg ha (Int.natCast_nonneg _) + +theorem ofScientific_nonneg (m : ℕ) (s : Bool) (e : ℕ) : + 0 ≤ Rat.ofScientific m s e := by + rw [Rat.ofScientific] + cases s + · rw [if_neg (by decide)] + refine num_nonneg.mp ?_ + rw [num_natCast] + exact Int.natCast_nonneg _ + · rw [if_pos rfl, normalize_eq_mkRat] + exact Rat.mkRat_nonneg (Int.natCast_nonneg _) _ + +instance _root_.NNRatCast.toOfScientific {K} [NNRatCast K] : OfScientific K where + ofScientific (m : ℕ) (b : Bool) (d : ℕ) := + NNRat.cast ⟨Rat.ofScientific m b d, ofScientific_nonneg m b d⟩ + +/-- Casting a scientific literal via `ℚ≥0` is the same as casting directly. -/ +@[simp, norm_cast] +theorem _root_.NNRat.cast_ofScientific {K} [NNRatCast K] (m : ℕ) (s : Bool) (e : ℕ) : + (OfScientific.ofScientific m s e : ℚ≥0) = (OfScientific.ofScientific m s e : K) := + rfl + +protected lemma add_nonneg : 0 ≤ a → 0 ≤ b → 0 ≤ a + b := + numDenCasesOn' a fun n₁ d₁ h₁ ↦ numDenCasesOn' b fun n₂ d₂ h₂ ↦ by + have d₁0 : 0 < (d₁ : ℤ) := mod_cast Nat.pos_of_ne_zero h₁ + have d₂0 : 0 < (d₂ : ℤ) := mod_cast Nat.pos_of_ne_zero h₂ + simp only [d₁0, d₂0, h₁, h₂, Int.mul_pos, divInt_nonneg_iff_of_pos_right, divInt_add_divInt, Ne, + Nat.cast_eq_zero, not_false_iff] + intro n₁0 n₂0 + apply Int.add_nonneg <;> apply Int.mul_nonneg <;> · first | assumption | apply Int.ofNat_zero_le + +protected lemma mul_nonneg : 0 ≤ a → 0 ≤ b → 0 ≤ a * b := + numDenCasesOn' a fun n₁ d₁ h₁ => + numDenCasesOn' b fun n₂ d₂ h₂ => by + have d₁0 : 0 < (d₁ : ℤ) := mod_cast Nat.pos_of_ne_zero h₁ + have d₂0 : 0 < (d₂ : ℤ) := mod_cast Nat.pos_of_ne_zero h₂ + simp only [d₁0, d₂0, Int.mul_pos, divInt_nonneg_iff_of_pos_right, + divInt_mul_divInt _ _ d₁0.ne' d₂0.ne'] + apply Int.mul_nonneg + +-- Porting note (#11215): TODO can this be shortened? +protected theorem le_iff_sub_nonneg (a b : ℚ) : a ≤ b ↔ 0 ≤ b - a := + numDenCasesOn'' a fun na da ha hared => + numDenCasesOn'' b fun nb db hb hbred => by + change Rat.blt _ _ = false ↔ _ + unfold Rat.blt + simp only [Bool.and_eq_true, decide_eq_true_eq, Bool.ite_eq_false_distrib, + decide_eq_false_iff_not, not_lt, ite_eq_left_iff, not_and, not_le, ← num_nonneg] + split_ifs with h h' + · rw [Rat.sub_def] + simp only [false_iff, not_le, reduceCtorEq] + simp only [normalize_eq] + apply Int.ediv_neg' + · rw [sub_neg] + apply lt_of_lt_of_le + · apply Int.mul_neg_of_neg_of_pos h.1 + rwa [Int.natCast_pos, Nat.pos_iff_ne_zero] + · apply Int.mul_nonneg h.2 (Int.natCast_nonneg _) + · simp only [Int.natCast_pos, Nat.pos_iff_ne_zero] + exact Nat.gcd_ne_zero_right (Nat.mul_ne_zero hb ha) + · simp only [divInt_ofNat, ← zero_iff_num_zero, mkRat_eq_zero hb] at h' + simp [h'] + · simp only [Rat.sub_def, normalize_eq] + refine ⟨fun H => ?_, fun H _ => ?_⟩ + · refine Int.ediv_nonneg ?_ (Int.natCast_nonneg _) + rw [Int.sub_nonneg] + push_neg at h + obtain hb|hb := Ne.lt_or_lt h' + · apply H + intro H' + exact (hb.trans H').false.elim + · obtain ha|ha := le_or_lt na 0 + · apply le_trans <| Int.mul_nonpos_of_nonpos_of_nonneg ha (Int.natCast_nonneg _) + exact Int.mul_nonneg hb.le (Int.natCast_nonneg _) + · exact H (fun _ => ha) + · rw [← Int.sub_nonneg] + contrapose! H + apply Int.ediv_neg' H + simp only [Int.natCast_pos, Nat.pos_iff_ne_zero] + exact Nat.gcd_ne_zero_right (Nat.mul_ne_zero hb ha) + +protected lemma divInt_le_divInt {a b c d : ℤ} (b0 : 0 < b) (d0 : 0 < d) : + a /. b ≤ c /. d ↔ a * d ≤ c * b := by + rw [Rat.le_iff_sub_nonneg, ← Int.sub_nonneg] + simp [sub_eq_add_neg, ne_of_gt b0, ne_of_gt d0, Int.mul_pos d0 b0] + +protected lemma le_total : a ≤ b ∨ b ≤ a := by + simpa only [← Rat.le_iff_sub_nonneg, neg_sub] using Rat.nonneg_total (b - a) + +protected theorem not_le {a b : ℚ} : ¬a ≤ b ↔ b < a := (Bool.not_eq_false _).to_iff + +instance linearOrder : LinearOrder ℚ where + le_refl a := by rw [Rat.le_iff_sub_nonneg, ← num_nonneg]; simp + le_trans a b c hab hbc := by + rw [Rat.le_iff_sub_nonneg] at hab hbc + have := Rat.add_nonneg hab hbc + simp_rw [sub_eq_add_neg, add_left_comm (b + -a) c (-b), add_comm (b + -a) (-b), + add_left_comm (-b) b (-a), add_comm (-b) (-a), add_neg_cancel_comm_assoc, + ← sub_eq_add_neg] at this + rwa [Rat.le_iff_sub_nonneg] + le_antisymm a b hab hba := by + rw [Rat.le_iff_sub_nonneg] at hab hba + rw [sub_eq_add_neg] at hba + rw [← neg_sub, sub_eq_add_neg] at hab + have := eq_neg_of_add_eq_zero_left (Rat.nonneg_antisymm hba hab) + rwa [neg_neg] at this + le_total _ _ := Rat.le_total + decidableEq := inferInstance + decidableLE := inferInstance + decidableLT := inferInstance + lt_iff_le_not_le _ _ := by rw [← Rat.not_le, and_iff_right_of_imp Rat.le_total.resolve_left] + +/-! +### Extra instances to short-circuit type class resolution + +These also prevent non-computable instances being used to construct these instances non-computably. +-/ + +instance instDistribLattice : DistribLattice ℚ := inferInstance +instance instLattice : Lattice ℚ := inferInstance +instance instSemilatticeInf : SemilatticeInf ℚ := inferInstance +instance instSemilatticeSup : SemilatticeSup ℚ := inferInstance +instance instInf : Inf ℚ := inferInstance +instance instSup : Sup ℚ := inferInstance +instance instPartialOrder : PartialOrder ℚ := inferInstance +instance instPreorder : Preorder ℚ := inferInstance + +/-! ### Miscellaneous lemmas -/ + +protected lemma le_def : p ≤ q ↔ p.num * q.den ≤ q.num * p.den := by + rw [← num_divInt_den q, ← num_divInt_den p] + conv_rhs => simp only [num_divInt_den] + exact Rat.divInt_le_divInt (mod_cast p.pos) (mod_cast q.pos) + +protected lemma lt_def : p < q ↔ p.num * q.den < q.num * p.den := by + rw [lt_iff_le_and_ne, Rat.le_def] + suffices p ≠ q ↔ p.num * q.den ≠ q.num * p.den by + constructor <;> intro h + · exact lt_iff_le_and_ne.mpr ⟨h.left, this.mp h.right⟩ + · have tmp := lt_iff_le_and_ne.mp h + exact ⟨tmp.left, this.mpr tmp.right⟩ + exact not_iff_not.mpr eq_iff_mul_eq_mul + +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 + elim := fun _ _ _ h => Rat.add_le_add_left.2 h + +@[simp] lemma num_nonpos {a : ℚ} : a.num ≤ 0 ↔ a ≤ 0 := by + simp [Int.le_iff_lt_or_eq, instLE, Rat.blt, Int.not_lt] +@[simp] lemma num_pos {a : ℚ} : 0 < a.num ↔ 0 < a := lt_iff_lt_of_le_iff_le num_nonpos +@[simp] lemma num_neg {a : ℚ} : a.num < 0 ↔ a < 0 := lt_iff_lt_of_le_iff_le num_nonneg + +@[deprecated (since := "2024-02-16")] alias num_nonneg_iff_zero_le := num_nonneg +@[deprecated (since := "2024-02-16")] alias num_pos_iff_pos := num_pos + +theorem div_lt_div_iff_mul_lt_mul {a b c d : ℤ} (b_pos : 0 < b) (d_pos : 0 < d) : + (a : ℚ) / b < c / d ↔ a * d < c * b := by + simp only [lt_iff_le_not_le] + apply and_congr + · simp [div_def', Rat.divInt_le_divInt b_pos d_pos] + · apply not_congr + simp [div_def', Rat.divInt_le_divInt d_pos b_pos] + +theorem lt_one_iff_num_lt_denom {q : ℚ} : q < 1 ↔ q.num < q.den := by simp [Rat.lt_def] + +theorem abs_def (q : ℚ) : |q| = q.num.natAbs /. q.den := by + rcases le_total q 0 with hq | hq + · rw [abs_of_nonpos hq] + rw [← num_divInt_den q, ← zero_divInt, Rat.divInt_le_divInt (mod_cast q.pos) Int.zero_lt_one, + mul_one, zero_mul] at hq + rw [Int.ofNat_natAbs_of_nonpos hq, ← neg_def] + · rw [abs_of_nonneg hq] + rw [← num_divInt_den q, ← zero_divInt, Rat.divInt_le_divInt Int.zero_lt_one (mod_cast q.pos), + mul_one, zero_mul] at hq + rw [Int.natAbs_of_nonneg hq, num_divInt_den] + +end Rat diff --git a/Mathlib/Algebra/Order/Ring/WithTop.lean b/Mathlib/Algebra/Order/Ring/WithTop.lean index bcea8dcf42272..6ac933856d0ad 100644 --- a/Mathlib/Algebra/Order/Ring/WithTop.lean +++ b/Mathlib/Algebra/Order/Ring/WithTop.lean @@ -30,10 +30,10 @@ instance instMulZeroClass : MulZeroClass (WithTop α) where | ⊤, (b : α) => if b = 0 then 0 else ⊤ | ⊤, ⊤ => ⊤ mul_zero a := match a with - | (a : α) => congr_arg some $ mul_zero _ + | (a : α) => congr_arg some <| mul_zero _ | ⊤ => if_pos rfl zero_mul b := match b with - | (b : α) => congr_arg some $ zero_mul _ + | (b : α) => congr_arg some <| zero_mul _ | ⊤ => if_pos rfl @[simp, norm_cast] lemma coe_mul (a b : α) : (↑(a * b) : WithTop α) = a * b := rfl @@ -73,15 +73,17 @@ lemma coe_mul_eq_bind {a : α} (ha : a ≠ 0) : ∀ b, (a * b : WithTop α) = b. induction b; · rw [mul_top ha, untop'_top, mul_zero] rw [← coe_mul, untop'_coe, untop'_coe, untop'_coe] -theorem mul_lt_top' [LT α] {a b : WithTop α} (ha : a < ⊤) (hb : b < ⊤) : a * b < ⊤ := by +theorem mul_ne_top {a b : WithTop α} (ha : a ≠ ⊤) (hb : b ≠ ⊤) : a * b ≠ ⊤ := by + simp [mul_eq_top_iff, *] + +theorem mul_lt_top [LT α] {a b : WithTop α} (ha : a < ⊤) (hb : b < ⊤) : a * b < ⊤ := by rw [WithTop.lt_top_iff_ne_top] at * - simp only [Ne, mul_eq_top_iff, *, and_false, false_and, or_self, not_false_eq_true] + exact mul_ne_top ha hb -theorem mul_lt_top [LT α] {a b : WithTop α} (ha : a ≠ ⊤) (hb : b ≠ ⊤) : a * b < ⊤ := - mul_lt_top' (WithTop.lt_top_iff_ne_top.2 ha) (WithTop.lt_top_iff_ne_top.2 hb) +@[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)) @@ -242,12 +244,14 @@ lemma unbot'_zero_mul (a b : WithBot α) : (a * b).unbot' 0 = a.unbot' 0 * b.unb induction b; · rw [mul_bot ha, unbot'_bot, mul_zero] rw [← coe_mul, unbot'_coe, unbot'_coe, unbot'_coe] -theorem bot_lt_mul' [LT α] {a b : WithBot α} (ha : ⊥ < a) (hb : ⊥ < b) : ⊥ < a * b := - WithTop.mul_lt_top' (α := αᵒᵈ) ha hb +theorem mul_ne_bot {a b : WithBot α} (ha : a ≠ ⊥) (hb : b ≠ ⊥) : a * b ≠ ⊥ := + WithTop.mul_ne_top (α := αᵒᵈ) ha hb -theorem bot_lt_mul [LT α] {a b : WithBot α} (ha : a ≠ ⊥) (hb : b ≠ ⊥) : ⊥ < a * b := +theorem bot_lt_mul [LT α] {a b : WithBot α} (ha : ⊥ < a) (hb : ⊥ < b) : ⊥ < a * b := WithTop.mul_lt_top (α := αᵒᵈ) ha hb +@[deprecated (since := "2024-08-25")] alias bot_lt_mul' := bot_lt_mul + instance instNoZeroDivisors [NoZeroDivisors α] : NoZeroDivisors (WithBot α) := WithTop.instNoZeroDivisors diff --git a/Mathlib/Algebra/Star/Order.lean b/Mathlib/Algebra/Order/Star/Basic.lean similarity index 93% rename from Mathlib/Algebra/Star/Order.lean rename to Mathlib/Algebra/Order/Star/Basic.lean index 3d1200121de45..b07145ac25911 100644 --- a/Mathlib/Algebra/Star/Order.lean +++ b/Mathlib/Algebra/Order/Star/Basic.lean @@ -1,12 +1,13 @@ /- -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.Star.SelfAdjoint import Mathlib.Algebra.Star.StarRingHom import Mathlib.Algebra.Regular.Basic +import Mathlib.Tactic.ContinuousFunctionalCalculus /-! # Star ordered rings @@ -137,12 +138,26 @@ section NonUnitalSemiring variable [NonUnitalSemiring R] [PartialOrder R] [StarRing R] [StarOrderedRing R] +lemma IsSelfAdjoint.mono {x y : R} (h : x ≤ y) (hx : IsSelfAdjoint x) : IsSelfAdjoint y := by + rw [StarOrderedRing.le_iff] at h + obtain ⟨d, hd, rfl⟩ := h + rw [IsSelfAdjoint, star_add, hx.star_eq] + congr + refine AddMonoidHom.eqOn_closureM (f := starAddEquiv (R := R)) (g := .id R) ?_ hd + rintro - ⟨s, rfl⟩ + simp + +@[aesop 10% apply] +lemma IsSelfAdjoint.of_nonneg {x : R} (hx : 0 ≤ x) : IsSelfAdjoint x := + .mono hx <| .zero R + theorem star_mul_self_nonneg (r : R) : 0 ≤ star r * r := StarOrderedRing.nonneg_iff.mpr <| AddSubmonoid.subset_closure ⟨r, rfl⟩ theorem mul_star_self_nonneg (r : R) : 0 ≤ r * star r := by simpa only [star_star] using star_mul_self_nonneg (star r) +@[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 => ?_) @@ -155,9 +170,19 @@ theorem conjugate_nonneg {a : R} (ha : 0 ≤ a) (c : R) : 0 ≤ star c * a * c : _ ≤ star c * x * c + star c * y * c := add_le_add_left hy _ _ ≤ _ := by rw [mul_add, add_mul] +@[aesop safe apply] theorem conjugate_nonneg' {a : R} (ha : 0 ≤ a) (c : R) : 0 ≤ c * a * star c := by simpa only [star_star] using conjugate_nonneg ha (star c) +@[aesop 90% apply (rule_sets := [CStarAlgebra])] +protected theorem IsSelfAdjoint.conjugate_nonneg {a : R} (ha : 0 ≤ a) {c : R} + (hc : IsSelfAdjoint c) : 0 ≤ c * a * c := by + nth_rewrite 2 [← hc]; exact conjugate_nonneg' ha c + +theorem conjugate_nonneg_of_nonneg {a : R} (ha : 0 ≤ a) {c : R} (hc : 0 ≤ c) : + 0 ≤ c * a * c := + IsSelfAdjoint.of_nonneg hc |>.conjugate_nonneg ha + theorem conjugate_le_conjugate {a b : R} (hab : a ≤ b) (c : R) : star c * a * c ≤ star c * b * c := by rw [StarOrderedRing.le_iff] at hab ⊢ @@ -169,6 +194,14 @@ theorem conjugate_le_conjugate' {a b : R} (hab : a ≤ b) (c : R) : c * a * star c ≤ c * b * star c := by simpa only [star_star] using conjugate_le_conjugate hab (star c) +protected theorem IsSelfAdjoint.conjugate_le_conjugate {a b : R} (hab : a ≤ b) {c : R} + (hc : IsSelfAdjoint c) : c * a * c ≤ c * b * c := by + simpa only [hc.star_eq] using conjugate_le_conjugate hab c + +theorem conjugate_le_conjugate_of_nonneg {a b : R} (hab : a ≤ b) {c : R} (hc : 0 ≤ c) : + c * a * c ≤ c * b * c := + IsSelfAdjoint.of_nonneg hc |>.conjugate_le_conjugate hab + @[simp] lemma star_le_star_iff {x y : R} : star x ≤ star y ↔ x ≤ y := by suffices ∀ x y, x ≤ y → star x ≤ star y from @@ -207,19 +240,6 @@ lemma star_pos_iff {x : R} : 0 < star x ↔ 0 < x := by lemma star_neg_iff {x : R} : star x < 0 ↔ x < 0 := by simpa using star_lt_star_iff (x := x) (y := 0) -lemma IsSelfAdjoint.mono {x y : R} (h : x ≤ y) (hx : IsSelfAdjoint x) : IsSelfAdjoint y := by - rw [StarOrderedRing.le_iff] at h - obtain ⟨d, hd, rfl⟩ := h - rw [IsSelfAdjoint, star_add, hx.star_eq] - congr - refine AddMonoidHom.eqOn_closureM (f := starAddEquiv (R := R)) (g := .id R) ?_ hd - rintro - ⟨s, rfl⟩ - simp - -@[aesop 10% apply] -lemma IsSelfAdjoint.of_nonneg {x : R} (hx : 0 ≤ x) : IsSelfAdjoint x := - .mono hx <| .zero R - theorem conjugate_lt_conjugate {a b : R} (hab : a < b) {c : R} (hc : IsRegular c) : star c * a * c < star c * b * c := by rw [(conjugate_le_conjugate hab.le _).lt_iff_ne, hc.right.ne_iff, hc.star.left.ne_iff] @@ -294,7 +314,7 @@ lemma StarModule.smul_lt_smul_of_pos {a b : A} {c : R} (hab : a < b) (hc : 0 < c obtain ⟨y, hy⟩ := hx apply AddSubmonoid.subset_closure refine ⟨z • y, ?_⟩ - simp only [star_smul, smul_mul_smul, hz, hy] + 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 zero => simpa only [smul_zero] using zero_mem _ diff --git a/Mathlib/Algebra/Order/Star/Conjneg.lean b/Mathlib/Algebra/Order/Star/Conjneg.lean new file mode 100644 index 0000000000000..e3a93e2c3e500 --- /dev/null +++ b/Mathlib/Algebra/Order/Star/Conjneg.lean @@ -0,0 +1,38 @@ +/- +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.Pi +import Mathlib.Algebra.Order.Star.Basic +import Mathlib.Algebra.Star.Conjneg + +/-! +# Order properties of conjugation-negation +-/ + +open scoped ComplexConjugate + +variable {G R : Type*} [AddGroup G] + +section OrderedCommSemiring +variable [OrderedCommSemiring R] [StarRing R] [StarOrderedRing R] {f : G → R} + +@[simp] lemma conjneg_nonneg : 0 ≤ conjneg f ↔ 0 ≤ f := + (Equiv.neg _).forall_congr' <| by simp [starRingEnd_apply] + +@[simp] lemma conjneg_pos : 0 < conjneg f ↔ 0 < f := by + simp_rw [lt_iff_le_and_ne, ne_comm, conjneg_nonneg, conjneg_ne_zero] + +end OrderedCommSemiring + +section OrderedCommRing +variable [OrderedCommRing R] [StarRing R] [StarOrderedRing R] {f : G → R} + +@[simp] lemma conjneg_nonpos : conjneg f ≤ 0 ↔ f ≤ 0 := by + simp_rw [← neg_nonneg, ← conjneg_neg, conjneg_nonneg] + +@[simp] lemma conjneg_neg' : conjneg f < 0 ↔ f < 0 := by + simp_rw [← neg_pos, ← conjneg_neg, conjneg_pos] + +end OrderedCommRing diff --git a/Mathlib/Algebra/Order/Sub/Basic.lean b/Mathlib/Algebra/Order/Sub/Basic.lean index dbd995c294236..79046c54164c0 100644 --- a/Mathlib/Algebra/Order/Sub/Basic.lean +++ b/Mathlib/Algebra/Order/Sub/Basic.lean @@ -3,58 +3,199 @@ 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.Algebra.Order.Monoid.Unbundled.ExistsOfLE +import Mathlib.Algebra.Order.Monoid.Canonical.Defs +import Mathlib.Algebra.Order.Sub.Unbundled.Basic import Mathlib.Algebra.Group.Equiv.Basic -import Mathlib.Algebra.Ring.Basic -import Mathlib.Algebra.Order.Sub.Defs -import Mathlib.Order.Hom.Basic - +import Mathlib.Algebra.Group.Even /-! -# Additional results about ordered Subtraction - +# Lemmas about subtraction in unbundled canonically ordered monoids -/ +variable {α : Type*} + +section CanonicallyOrderedAddCommMonoid + +variable [CanonicallyOrderedAddCommMonoid α] [Sub α] [OrderedSub α] {a b c d : α} + +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⟩ + +theorem tsub_add_cancel_iff_le : b - a + a = b ↔ a ≤ b := by + rw [add_comm] + exact add_tsub_cancel_iff_le + +-- This was previously a `@[simp]` lemma, but it is not necessarily a good idea, e.g. in +-- `example (h : n - m = 0) : a + (n - m) = a := by simp_all` +theorem tsub_eq_zero_iff_le : a - b = 0 ↔ a ≤ b := by + rw [← nonpos_iff_eq_zero, tsub_le_iff_left, add_zero] + +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 + +theorem tsub_le_self : a - b ≤ a := + tsub_le_iff_left.mpr <| le_add_left le_rfl + +theorem zero_tsub (a : α) : 0 - a = 0 := + tsub_eq_zero_of_le <| zero_le a + +theorem tsub_self_add (a b : α) : a - (a + b) = 0 := + tsub_eq_zero_of_le <| self_le_add_right _ _ + +theorem tsub_pos_iff_not_le : 0 < a - b ↔ ¬a ≤ b := by + rw [pos_iff_ne_zero, Ne, tsub_eq_zero_iff_le] + +theorem tsub_pos_of_lt (h : a < b) : 0 < b - a := + tsub_pos_iff_not_le.mpr h.not_le + +theorem tsub_lt_of_lt (h : a < b) : a - c < b := + lt_of_le_of_lt tsub_le_self h + +namespace AddLECancellable + +protected theorem tsub_le_tsub_iff_left (ha : AddLECancellable a) (hc : AddLECancellable c) + (h : c ≤ a) : a - b ≤ a - c ↔ c ≤ b := by + refine ⟨?_, fun h => tsub_le_tsub_left h a⟩ + rw [tsub_le_iff_left, ← hc.add_tsub_assoc_of_le h, hc.le_tsub_iff_right (h.trans le_add_self), + add_comm b] + apply ha + +protected theorem tsub_right_inj (ha : AddLECancellable a) (hb : AddLECancellable b) + (hc : AddLECancellable c) (hba : b ≤ a) (hca : c ≤ a) : a - b = a - c ↔ b = c := by + simp_rw [le_antisymm_iff, ha.tsub_le_tsub_iff_left hb hba, ha.tsub_le_tsub_iff_left hc hca, + and_comm] + +end AddLECancellable + +/-! #### Lemmas where addition is order-reflecting. -/ + + +section Contra + +variable [ContravariantClass α α (· + ·) (· ≤ ·)] + +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 + +theorem tsub_right_inj (hba : b ≤ a) (hca : c ≤ a) : a - b = a - c ↔ b = c := + Contravariant.AddLECancellable.tsub_right_inj Contravariant.AddLECancellable + Contravariant.AddLECancellable hba hca + +variable (α) + +/-- A `CanonicallyOrderedAddCommMonoid` with ordered subtraction and order-reflecting addition is +cancellative. This is not an instance as it would form a typeclass loop. + +See note [reducible non-instances]. -/ +abbrev CanonicallyOrderedAddCommMonoid.toAddCancelCommMonoid : AddCancelCommMonoid α := + { (by infer_instance : AddCommMonoid α) with + add_left_cancel := fun a b c h => by + simpa only [add_tsub_cancel_left] using congr_arg (fun x => x - a) h } + +end Contra + +end CanonicallyOrderedAddCommMonoid + +/-! ### Lemmas in a linearly canonically ordered monoid. -/ + + +section CanonicallyLinearOrderedAddCommMonoid + +variable [CanonicallyLinearOrderedAddCommMonoid α] [Sub α] [OrderedSub α] {a b c d : α} + +@[simp] +theorem tsub_pos_iff_lt : 0 < a - b ↔ b < a := by rw [tsub_pos_iff_not_le, not_le] + +theorem tsub_eq_tsub_min (a b : α) : a - b = a - min a b := by + rcases le_total a b with h | h + · rw [min_eq_left h, tsub_self, tsub_eq_zero_of_le h] + · rw [min_eq_right h] + +namespace AddLECancellable + +protected theorem lt_tsub_iff_right (hc : AddLECancellable c) : a < b - c ↔ a + c < b := + ⟨lt_imp_lt_of_le_imp_le tsub_le_iff_right.mpr, hc.lt_tsub_of_add_lt_right⟩ + +protected theorem lt_tsub_iff_left (hc : AddLECancellable c) : a < b - c ↔ c + a < b := + ⟨lt_imp_lt_of_le_imp_le tsub_le_iff_left.mpr, hc.lt_tsub_of_add_lt_left⟩ + +protected theorem tsub_lt_tsub_iff_right (hc : AddLECancellable c) (h : c ≤ a) : + a - c < b - c ↔ a < b := by rw [hc.lt_tsub_iff_left, add_tsub_cancel_of_le h] + +protected theorem tsub_lt_self (ha : AddLECancellable a) (h₁ : 0 < a) (h₂ : 0 < b) : a - b < a := by + refine tsub_le_self.lt_of_ne fun h => ?_ + rw [← h, tsub_pos_iff_lt] at h₁ + exact h₂.not_le (ha.add_le_iff_nonpos_left.1 <| add_le_of_le_tsub_left_of_le h₁.le h.ge) + +protected theorem tsub_lt_self_iff (ha : AddLECancellable a) : a - b < a ↔ 0 < a ∧ 0 < b := by + refine + ⟨fun h => ⟨(zero_le _).trans_lt h, (zero_le b).lt_of_ne ?_⟩, fun h => ha.tsub_lt_self h.1 h.2⟩ + rintro rfl + rw [tsub_zero] at h + exact h.false + +/-- See `lt_tsub_iff_left_of_le_of_le` for a weaker statement in a partial order. -/ +protected theorem tsub_lt_tsub_iff_left_of_le (ha : AddLECancellable a) (hb : AddLECancellable b) + (h : b ≤ a) : a - b < a - c ↔ c < b := + lt_iff_lt_of_le_iff_le <| ha.tsub_le_tsub_iff_left hb h + +end AddLECancellable + +section Contra + +variable [ContravariantClass α α (· + ·) (· ≤ ·)] -variable {α β : Type*} +/-- 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 := + Contravariant.AddLECancellable.tsub_lt_tsub_iff_right h -section Add +theorem tsub_lt_self : 0 < a → 0 < b → a - b < a := + Contravariant.AddLECancellable.tsub_lt_self -variable [Preorder α] [Add α] [Sub α] [OrderedSub α] {a b c d : α} +@[simp] theorem tsub_lt_self_iff : a - b < a ↔ 0 < a ∧ 0 < b := + Contravariant.AddLECancellable.tsub_lt_self_iff -theorem AddHom.le_map_tsub [Preorder β] [Add β] [Sub β] [OrderedSub β] (f : AddHom α β) - (hf : Monotone f) (a b : α) : f a - f b ≤ f (a - b) := by - rw [tsub_le_iff_right, ← f.map_add] - exact hf le_tsub_add +/-- See `lt_tsub_iff_left_of_le_of_le` for a weaker statement in a partial order. -/ +theorem tsub_lt_tsub_iff_left_of_le (h : b ≤ a) : a - b < a - c ↔ c < b := + Contravariant.AddLECancellable.tsub_lt_tsub_iff_left_of_le Contravariant.AddLECancellable h -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) := - (AddHom.mulLeft a).le_map_tsub (monotone_id.const_mul' a) _ _ +lemma tsub_tsub_eq_min (a b : α) : a - (a - b) = min a b := by + rw [tsub_eq_tsub_min _ b, tsub_tsub_cancel_of_le (min_le_left 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 - simpa only [mul_comm _ c] using le_mul_tsub +end Contra -end Add +/-! ### Lemmas about `max` and `min`. -/ -/-- An order isomorphism between types with ordered subtraction preserves subtraction provided that -it preserves addition. -/ -theorem OrderIso.map_tsub {M N : Type*} [Preorder M] [Add M] [Sub M] [OrderedSub M] - [PartialOrder N] [Add N] [Sub N] [OrderedSub N] (e : M ≃o N) - (h_add : ∀ a b, e (a + b) = e a + e b) (a b : M) : e (a - b) = e a - e b := by - let e_add : M ≃+ N := { e with map_add' := h_add } - refine le_antisymm ?_ (e_add.toAddHom.le_map_tsub e.monotone a b) - suffices e (e.symm (e a) - e.symm (e b)) ≤ e (e.symm (e a - e b)) by simpa - exact e.monotone (e_add.symm.toAddHom.le_map_tsub e.symm.monotone _ _) -/-! ### Preorder -/ +theorem tsub_add_eq_max : a - b + b = max a b := by + rcases le_total a b with h | h + · rw [max_eq_right h, tsub_eq_zero_of_le h, zero_add] + · rw [max_eq_left h, tsub_add_cancel_of_le h] +theorem add_tsub_eq_max : a + (b - a) = max a b := by rw [add_comm, max_comm, tsub_add_eq_max] -section Preorder +theorem tsub_min : a - min a b = a - b := by + rcases le_total a b with h | h + · rw [min_eq_left h, tsub_self, tsub_eq_zero_of_le h] + · rw [min_eq_right h] -variable [Preorder α] -variable [AddCommMonoid α] [Sub α] [OrderedSub α] {a b c d : α} +theorem tsub_add_min : a - b + min a b = a := by + rw [← tsub_min, @tsub_add_cancel_of_le] + apply min_le_left -theorem AddMonoidHom.le_map_tsub [Preorder β] [AddCommMonoid β] [Sub β] [OrderedSub β] (f : α →+ β) - (hf : Monotone f) (a b : α) : f a - f b ≤ f (a - b) := - f.toAddHom.le_map_tsub hf a b +-- `Odd.tsub` requires `CanonicallyLinearOrderedSemiring`, which we don't have +lemma Even.tsub + [ContravariantClass α α (· + ·) (· ≤ ·)] {m n : α} (hm : Even m) (hn : Even n) : + Even (m - n) := by + obtain ⟨a, rfl⟩ := hm + obtain ⟨b, rfl⟩ := hn + refine ⟨a - b, ?_⟩ + obtain h | h := le_total a b + · rw [tsub_eq_zero_of_le h, tsub_eq_zero_of_le (add_le_add h h), add_zero] + · exact (tsub_add_tsub_comm h h).symm -end Preorder +end CanonicallyLinearOrderedAddCommMonoid diff --git a/Mathlib/Algebra/Order/Sub/Defs.lean b/Mathlib/Algebra/Order/Sub/Defs.lean index eff553b812467..9966239cd270f 100644 --- a/Mathlib/Algebra/Order/Sub/Defs.lean +++ b/Mathlib/Algebra/Order/Sub/Defs.lean @@ -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,7 +60,7 @@ 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 α α (+) (≤)`. -/ theorem add_tsub_le_right : a + b - b ≤ a := @@ -83,7 +83,7 @@ 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] @@ -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' [CovariantClass α α (· + ·) (· ≤ ·)] (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' [CovariantClass α α (· + ·) (· ≤ ·)] (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' [CovariantClass α α (· + ·) (· ≤ ·)] + (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] @@ -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 := 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/Canonical.lean b/Mathlib/Algebra/Order/Sub/Unbundled/Basic.lean similarity index 60% rename from Mathlib/Algebra/Order/Sub/Canonical.lean rename to Mathlib/Algebra/Order/Sub/Unbundled/Basic.lean index f8591c56f68d8..979e4903eb48f 100644 --- a/Mathlib/Algebra/Order/Sub/Canonical.lean +++ b/Mathlib/Algebra/Order/Sub/Unbundled/Basic.lean @@ -3,14 +3,15 @@ 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.Algebra.Group.Even -import Mathlib.Algebra.Order.Monoid.Canonical.Defs import Mathlib.Algebra.Order.Sub.Defs +import Mathlib.Algebra.Order.Monoid.Unbundled.ExistsOfLE /-! -# Lemmas about subtraction in canonically ordered monoids +# Lemmas about subtraction in an unbundled canonically ordered monoids -/ +-- These are about *unbundled* canonically ordered monoids +assert_not_exists OrderedCommMonoid variable {α : Type*} @@ -255,192 +256,3 @@ theorem tsub_tsub_eq_add_tsub_of_le end Contra end ExistsAddOfLE - -/-! ### Lemmas in a canonically ordered monoid. -/ - - -section CanonicallyOrderedAddCommMonoid - -variable [CanonicallyOrderedAddCommMonoid α] [Sub α] [OrderedSub α] {a b c d : α} - -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⟩ - -theorem tsub_add_cancel_iff_le : b - a + a = b ↔ a ≤ b := by - rw [add_comm] - exact add_tsub_cancel_iff_le - --- This was previously a `@[simp]` lemma, but it is not necessarily a good idea, e.g. in --- `example (h : n - m = 0) : a + (n - m) = a := by simp_all` -theorem tsub_eq_zero_iff_le : a - b = 0 ↔ a ≤ b := by - rw [← nonpos_iff_eq_zero, tsub_le_iff_left, add_zero] - -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 - -theorem tsub_le_self : a - b ≤ a := - tsub_le_iff_left.mpr <| le_add_left le_rfl - -theorem zero_tsub (a : α) : 0 - a = 0 := - tsub_eq_zero_of_le <| zero_le a - -theorem tsub_self_add (a b : α) : a - (a + b) = 0 := - tsub_eq_zero_of_le <| self_le_add_right _ _ - -theorem tsub_pos_iff_not_le : 0 < a - b ↔ ¬a ≤ b := by - rw [pos_iff_ne_zero, Ne, tsub_eq_zero_iff_le] - -theorem tsub_pos_of_lt (h : a < b) : 0 < b - a := - tsub_pos_iff_not_le.mpr h.not_le - -theorem tsub_lt_of_lt (h : a < b) : a - c < b := - lt_of_le_of_lt tsub_le_self h - -namespace AddLECancellable - -protected theorem tsub_le_tsub_iff_left (ha : AddLECancellable a) (hc : AddLECancellable c) - (h : c ≤ a) : a - b ≤ a - c ↔ c ≤ b := by - refine ⟨?_, fun h => tsub_le_tsub_left h a⟩ - rw [tsub_le_iff_left, ← hc.add_tsub_assoc_of_le h, hc.le_tsub_iff_right (h.trans le_add_self), - add_comm b] - apply ha - -protected theorem tsub_right_inj (ha : AddLECancellable a) (hb : AddLECancellable b) - (hc : AddLECancellable c) (hba : b ≤ a) (hca : c ≤ a) : a - b = a - c ↔ b = c := by - simp_rw [le_antisymm_iff, ha.tsub_le_tsub_iff_left hb hba, ha.tsub_le_tsub_iff_left hc hca, - and_comm] - -end AddLECancellable - -/-! #### Lemmas where addition is order-reflecting. -/ - - -section Contra - -variable [ContravariantClass α α (· + ·) (· ≤ ·)] - -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 - -theorem tsub_right_inj (hba : b ≤ a) (hca : c ≤ a) : a - b = a - c ↔ b = c := - Contravariant.AddLECancellable.tsub_right_inj Contravariant.AddLECancellable - Contravariant.AddLECancellable hba hca - -variable (α) - -/-- A `CanonicallyOrderedAddCommMonoid` with ordered subtraction and order-reflecting addition is -cancellative. This is not an instance as it would form a typeclass loop. - -See note [reducible non-instances]. -/ -abbrev CanonicallyOrderedAddCommMonoid.toAddCancelCommMonoid : AddCancelCommMonoid α := - { (by infer_instance : AddCommMonoid α) with - add_left_cancel := fun a b c h => by - simpa only [add_tsub_cancel_left] using congr_arg (fun x => x - a) h } - -end Contra - -end CanonicallyOrderedAddCommMonoid - -/-! ### Lemmas in a linearly canonically ordered monoid. -/ - - -section CanonicallyLinearOrderedAddCommMonoid - -variable [CanonicallyLinearOrderedAddCommMonoid α] [Sub α] [OrderedSub α] {a b c d : α} - -@[simp] -theorem tsub_pos_iff_lt : 0 < a - b ↔ b < a := by rw [tsub_pos_iff_not_le, not_le] - -theorem tsub_eq_tsub_min (a b : α) : a - b = a - min a b := by - rcases le_total a b with h | h - · rw [min_eq_left h, tsub_self, tsub_eq_zero_of_le h] - · rw [min_eq_right h] - -namespace AddLECancellable - -protected theorem lt_tsub_iff_right (hc : AddLECancellable c) : a < b - c ↔ a + c < b := - ⟨lt_imp_lt_of_le_imp_le tsub_le_iff_right.mpr, hc.lt_tsub_of_add_lt_right⟩ - -protected theorem lt_tsub_iff_left (hc : AddLECancellable c) : a < b - c ↔ c + a < b := - ⟨lt_imp_lt_of_le_imp_le tsub_le_iff_left.mpr, hc.lt_tsub_of_add_lt_left⟩ - -protected theorem tsub_lt_tsub_iff_right (hc : AddLECancellable c) (h : c ≤ a) : - a - c < b - c ↔ a < b := by rw [hc.lt_tsub_iff_left, add_tsub_cancel_of_le h] - -protected theorem tsub_lt_self (ha : AddLECancellable a) (h₁ : 0 < a) (h₂ : 0 < b) : a - b < a := by - refine tsub_le_self.lt_of_ne fun h => ?_ - rw [← h, tsub_pos_iff_lt] at h₁ - exact h₂.not_le (ha.add_le_iff_nonpos_left.1 <| add_le_of_le_tsub_left_of_le h₁.le h.ge) - -protected theorem tsub_lt_self_iff (ha : AddLECancellable a) : a - b < a ↔ 0 < a ∧ 0 < b := by - refine - ⟨fun h => ⟨(zero_le _).trans_lt h, (zero_le b).lt_of_ne ?_⟩, fun h => ha.tsub_lt_self h.1 h.2⟩ - rintro rfl - rw [tsub_zero] at h - exact h.false - -/-- See `lt_tsub_iff_left_of_le_of_le` for a weaker statement in a partial order. -/ -protected theorem tsub_lt_tsub_iff_left_of_le (ha : AddLECancellable a) (hb : AddLECancellable b) - (h : b ≤ a) : a - b < a - c ↔ c < b := - lt_iff_lt_of_le_iff_le <| ha.tsub_le_tsub_iff_left hb h - -end AddLECancellable - -section Contra - -variable [ContravariantClass α α (· + ·) (· ≤ ·)] - -/-- 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 := - Contravariant.AddLECancellable.tsub_lt_tsub_iff_right h - -theorem tsub_lt_self : 0 < a → 0 < b → a - b < a := - Contravariant.AddLECancellable.tsub_lt_self - -@[simp] theorem tsub_lt_self_iff : a - b < a ↔ 0 < a ∧ 0 < b := - Contravariant.AddLECancellable.tsub_lt_self_iff - -/-- See `lt_tsub_iff_left_of_le_of_le` for a weaker statement in a partial order. -/ -theorem tsub_lt_tsub_iff_left_of_le (h : b ≤ a) : a - b < a - c ↔ c < b := - Contravariant.AddLECancellable.tsub_lt_tsub_iff_left_of_le Contravariant.AddLECancellable h - -lemma tsub_tsub_eq_min (a b : α) : a - (a - b) = min a b := by - rw [tsub_eq_tsub_min _ b, tsub_tsub_cancel_of_le (min_le_left a _)] - -end Contra - -/-! ### Lemmas about `max` and `min`. -/ - - -theorem tsub_add_eq_max : a - b + b = max a b := by - rcases le_total a b with h | h - · rw [max_eq_right h, tsub_eq_zero_of_le h, zero_add] - · rw [max_eq_left h, tsub_add_cancel_of_le h] - -theorem add_tsub_eq_max : a + (b - a) = max a b := by rw [add_comm, max_comm, tsub_add_eq_max] - -theorem tsub_min : a - min a b = a - b := by - rcases le_total a b with h | h - · rw [min_eq_left h, tsub_self, tsub_eq_zero_of_le h] - · rw [min_eq_right h] - -theorem tsub_add_min : a - b + min a b = a := by - rw [← tsub_min, @tsub_add_cancel_of_le] - 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) : - Even (m - n) := by - obtain ⟨a, rfl⟩ := hm - obtain ⟨b, rfl⟩ := hn - refine ⟨a - b, ?_⟩ - obtain h | h := le_total a b - · rw [tsub_eq_zero_of_le h, tsub_eq_zero_of_le (add_le_add h h), add_zero] - · exact (tsub_add_tsub_comm h h).symm - -end CanonicallyLinearOrderedAddCommMonoid diff --git a/Mathlib/Algebra/Order/Sub/Unbundled/Hom.lean b/Mathlib/Algebra/Order/Sub/Unbundled/Hom.lean new file mode 100644 index 0000000000000..fedfe17b0c39c --- /dev/null +++ b/Mathlib/Algebra/Order/Sub/Unbundled/Hom.lean @@ -0,0 +1,58 @@ +/- +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.Algebra.Order.Sub.Defs +import Mathlib.Algebra.Group.Equiv.Basic +import Mathlib.Algebra.Ring.Basic +import Mathlib.Order.Hom.Basic +/-! +# Lemmas about subtraction in unbundled canonically ordered monoids +-/ + + +variable {α β : Type*} + +section Add + +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 + rw [tsub_le_iff_right, ← f.map_add] + 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) := + (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 + simpa only [mul_comm _ c] using le_mul_tsub + +end Add + +/-- An order isomorphism between types with ordered subtraction preserves subtraction provided that +it preserves addition. -/ +theorem OrderIso.map_tsub {M N : Type*} [Preorder M] [Add M] [Sub M] [OrderedSub M] + [PartialOrder N] [Add N] [Sub N] [OrderedSub N] (e : M ≃o N) + (h_add : ∀ a b, e (a + b) = e a + e b) (a b : M) : e (a - b) = e a - e b := by + let e_add : M ≃+ N := { e with map_add' := h_add } + refine le_antisymm ?_ (e_add.toAddHom.le_map_tsub e.monotone a b) + suffices e (e.symm (e a) - e.symm (e b)) ≤ e (e.symm (e a - e b)) by simpa + exact e.monotone (e_add.symm.toAddHom.le_map_tsub e.symm.monotone _ _) + +/-! ### Preorder -/ + + +section Preorder + +variable [Preorder α] +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) := + f.toAddHom.le_map_tsub hf a b + +end Preorder diff --git a/Mathlib/Algebra/Order/SuccPred.lean b/Mathlib/Algebra/Order/SuccPred.lean new file mode 100644 index 0000000000000..9ef68870ecd16 --- /dev/null +++ b/Mathlib/Algebra/Order/SuccPred.lean @@ -0,0 +1,185 @@ +/- +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, Yaël Dillies +-/ +import Mathlib.Algebra.Group.Basic +import Mathlib.Algebra.Order.ZeroLEOne +import Mathlib.Data.Int.Cast.Defs +import Mathlib.Order.SuccPred.Basic + +/-! +# Interaction between successors and arithmetic + +We define the `SuccAddOrder` and `PredSubOrder` typeclasses, for orders satisfying `succ x = x + 1` +and `pred x = x - 1` respectively. This allows us to transfer the API for successors and +predecessors into these common arithmetical forms. + +## Todo + +In the future, we will make `x + 1` and `x - 1` the `simp`-normal forms for `succ x` and `pred x` +respectively. This will require a refactor of `Ordinal` first, as the `simp`-normal form is +currently set the other way around. +-/ + +/-- A typeclass for `succ x = x + 1`. -/ +class SuccAddOrder (α : Type*) [Preorder α] [Add α] [One α] extends SuccOrder α where + succ_eq_add_one (x : α) : succ x = x + 1 + +/-- A typeclass for `pred x = x - 1`. -/ +class PredSubOrder (α : Type*) [Preorder α] [Sub α] [One α] extends PredOrder α where + pred_eq_sub_one (x : α) : pred x = x - 1 + +variable {α : Type*} {x y : α} + +namespace Order + +section Preorder + +variable [Preorder α] + +section Add + +variable [Add α] [One α] [SuccAddOrder α] + +theorem succ_eq_add_one (x : α) : succ x = x + 1 := + SuccAddOrder.succ_eq_add_one x + +theorem add_one_le_of_lt (h : x < y) : x + 1 ≤ y := by + rw [← succ_eq_add_one] + exact succ_le_of_lt h + +theorem add_one_le_iff_of_not_isMax (hx : ¬ IsMax x) : x + 1 ≤ y ↔ x < y := by + rw [← succ_eq_add_one, succ_le_iff_of_not_isMax hx] + +theorem add_one_le_iff [NoMaxOrder α] : x + 1 ≤ y ↔ x < y := + add_one_le_iff_of_not_isMax (not_isMax x) + +@[simp] +theorem wcovBy_add_one (x : α) : x ⩿ x + 1 := by + rw [← succ_eq_add_one] + exact wcovBy_succ x + +@[simp] +theorem covBy_add_one [NoMaxOrder α] (x : α) : x ⋖ x + 1 := by + rw [← succ_eq_add_one] + exact covBy_succ x + +end Add + +section Sub + +variable [Sub α] [One α] [PredSubOrder α] + +theorem pred_eq_sub_one (x : α) : pred x = x - 1 := + PredSubOrder.pred_eq_sub_one x + +theorem le_sub_one_of_lt (h : x < y) : x ≤ y - 1 := by + rw [← pred_eq_sub_one] + exact le_pred_of_lt h + +theorem le_sub_one_iff_of_not_isMin (hy : ¬ IsMin y) : x ≤ y - 1 ↔ x < y := by + rw [← pred_eq_sub_one, le_pred_iff_of_not_isMin hy] + +theorem le_sub_one_iff [NoMinOrder α] : x ≤ y - 1 ↔ x < y := + le_sub_one_iff_of_not_isMin (not_isMin y) + +@[simp] +theorem sub_one_wcovBy (x : α) : x - 1 ⩿ x := by + rw [← pred_eq_sub_one] + exact pred_wcovBy x + +@[simp] +theorem sub_one_covBy [NoMinOrder α] (x : α) : x - 1 ⋖ x := by + rw [← pred_eq_sub_one] + exact pred_covBy x + +end Sub + +@[simp] +theorem succ_iterate [AddMonoidWithOne α] [SuccAddOrder α] (x : α) (n : ℕ) : + succ^[n] x = x + n := by + induction n with + | zero => + rw [Function.iterate_zero_apply, Nat.cast_zero, add_zero] + | succ n IH => + rw [Function.iterate_succ_apply', IH, Nat.cast_add, succ_eq_add_one, Nat.cast_one, add_assoc] + +@[simp] +theorem pred_iterate [AddCommGroupWithOne α] [PredSubOrder α] (x : α) (n : ℕ) : + pred^[n] x = x - n := by + induction n with + | zero => + rw [Function.iterate_zero_apply, Nat.cast_zero, sub_zero] + | succ n IH => + rw [Function.iterate_succ_apply', IH, Nat.cast_add, pred_eq_sub_one, Nat.cast_one, sub_sub] + +end Preorder + +section PartialOrder + +variable [PartialOrder α] + +theorem not_isMax_zero [Zero α] [One α] [ZeroLEOneClass α] [NeZero (1 : α)] : ¬ IsMax (0 : α) := by + rw [not_isMax_iff] + exact ⟨1, one_pos⟩ + +theorem one_le_iff_pos [AddMonoidWithOne α] [ZeroLEOneClass α] [NeZero (1 : α)] + [SuccAddOrder α] : 1 ≤ x ↔ 0 < x := by + rw [← succ_le_iff_of_not_isMax not_isMax_zero, succ_eq_add_one, zero_add] + +theorem covBy_iff_add_one_eq [Add α] [One α] [SuccAddOrder α] [NoMaxOrder α] : + x ⋖ y ↔ x + 1 = y := by + rw [← succ_eq_add_one] + exact succ_eq_iff_covBy.symm + +theorem covBy_iff_sub_one_eq [Sub α] [One α] [PredSubOrder α] [NoMinOrder α] : + x ⋖ y ↔ y - 1 = x := by + rw [← pred_eq_sub_one] + exact pred_eq_iff_covBy.symm + +end PartialOrder + +section LinearOrder + +variable [LinearOrder α] + +section Add + +variable [Add α] [One α] [SuccAddOrder α] + +theorem le_of_lt_add_one (h : x < y + 1) : x ≤ y := by + rw [← succ_eq_add_one] at h + exact le_of_lt_succ h + +theorem lt_add_one_iff_of_not_isMax (hy : ¬ IsMax y) : x < y + 1 ↔ x ≤ y := by + rw [← succ_eq_add_one, lt_succ_iff_of_not_isMax hy] + +theorem lt_add_one_iff [NoMaxOrder α] : x < y + 1 ↔ x ≤ y := + lt_add_one_iff_of_not_isMax (not_isMax y) + +end Add + +section Sub + +variable [Sub α] [One α] [PredSubOrder α] + +theorem le_of_sub_one_lt (h : x - 1 < y) : x ≤ y := by + rw [← pred_eq_sub_one] at h + exact le_of_pred_lt h + +theorem sub_one_lt_iff_of_not_isMin (hx : ¬ IsMin x) : x - 1 < y ↔ x ≤ y := by + rw [← pred_eq_sub_one, pred_lt_iff_of_not_isMin hx] + +theorem sub_one_lt_iff [NoMinOrder α] : x - 1 < y ↔ x ≤ y := + sub_one_lt_iff_of_not_isMin (not_isMin x) + +end Sub + +theorem lt_one_iff_nonpos [AddMonoidWithOne α] [ZeroLEOneClass α] [NeZero (1 : α)] + [SuccAddOrder α] : x < 1 ↔ x ≤ 0 := by + rw [← lt_succ_iff_of_not_isMax not_isMax_zero, succ_eq_add_one, zero_add] + +end LinearOrder + +end Order diff --git a/Mathlib/Algebra/Order/SuccPred/TypeTags.lean b/Mathlib/Algebra/Order/SuccPred/TypeTags.lean new file mode 100644 index 0000000000000..4293cd851694a --- /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.Algebra.Order.Monoid.TypeTags +import Mathlib.Order.SuccPred.Archimedean + +/-! +# 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 1f303379050ac..260764b5fe69c 100644 --- a/Mathlib/Algebra/Order/ToIntervalMod.lean +++ b/Mathlib/Algebra/Order/ToIntervalMod.lean @@ -8,7 +8,6 @@ import Mathlib.Algebra.Module.Defs import Mathlib.Algebra.Order.Archimedean.Basic import Mathlib.Algebra.Periodic import Mathlib.Data.Int.SuccPred -import Mathlib.GroupTheory.QuotientGroup import Mathlib.Order.Circular import Mathlib.Data.List.TFAE import Mathlib.Data.Set.Lattice @@ -518,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 @@ -558,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 @@ -596,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 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/Periodic.lean b/Mathlib/Algebra/Periodic.lean index 2a4c1ad2350fe..995e7e734029d 100644 --- a/Mathlib/Algebra/Periodic.lean +++ b/Mathlib/Algebra/Periodic.lean @@ -8,7 +8,7 @@ import Mathlib.Algebra.Group.Subgroup.ZPowers import Mathlib.Algebra.Group.Submonoid.Membership import Mathlib.Algebra.Ring.NegOnePow import Mathlib.Algebra.Order.Archimedean.Basic -import Mathlib.GroupTheory.Coset +import Mathlib.GroupTheory.Coset.Card /-! # Periodicity @@ -66,9 +66,10 @@ protected theorem Periodic.div [Add α] [Div β] (hf : Periodic f c) (hg : Perio @[to_additive] theorem _root_.List.periodic_prod [Add α] [Monoid β] (l : List (α → β)) (hl : ∀ f ∈ l, Periodic f c) : Periodic l.prod c := by - induction' l with g l ih hl - · simp - · rw [List.forall_mem_cons] at hl + induction l with + | nil => simp + | cons g l ih => + rw [List.forall_mem_cons] at hl simpa only [List.prod_cons] using hl.1.mul (ih hl.2) @[to_additive] @@ -182,7 +183,7 @@ theorem Periodic.nat_mul_sub_eq [Ring α] (h : Periodic f c) (n : ℕ) : f (n * simpa only [sub_eq_neg_add] using h.nat_mul n (-x) protected theorem Periodic.zsmul [AddGroup α] (h : Periodic f c) (n : ℤ) : Periodic f (n • c) := by - cases' n with n n + rcases n with n | n · simpa only [Int.ofNat_eq_coe, natCast_zsmul] using h.nsmul n · simpa only [negSucc_zsmul] using (h.nsmul (n + 1)).neg diff --git a/Mathlib/Algebra/Pointwise/Stabilizer.lean b/Mathlib/Algebra/Pointwise/Stabilizer.lean index a63e174396fa1..de0ffac8e167c 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 +import Mathlib.Algebra.Group.Pointwise.Finset.Basic +import Mathlib.GroupTheory.QuotientGroup.Basic /-! # Stabilizer of a set under a pointwise action diff --git a/Mathlib/Algebra/Polynomial/AlgebraMap.lean b/Mathlib/Algebra/Polynomial/AlgebraMap.lean index 488fbdbe25fad..29c855d09a69b 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] @@ -384,7 +385,7 @@ instance instCommSemiringAdjoinSingleton : { mul_comm := fun ⟨p, hp⟩ ⟨q, hq⟩ ↦ by obtain ⟨p', rfl⟩ := Algebra.adjoin_singleton_eq_range_aeval R x ▸ hp obtain ⟨q', rfl⟩ := Algebra.adjoin_singleton_eq_range_aeval R x ▸ hq - simp only [AlgHom.toRingHom_eq_coe, RingHom.coe_coe, Submonoid.mk_mul_mk, ← map_mul, + simp only [AlgHom.toRingHom_eq_coe, RingHom.coe_coe, MulMemClass.mk_mul_mk, ← map_mul, mul_comm p' q'] } instance instCommRingAdjoinSingleton {R A : Type*} [CommRing R] [Ring A] [Algebra R A] (x : A) : @@ -526,7 +527,7 @@ 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 diff --git a/Mathlib/Algebra/Polynomial/Basic.lean b/Mathlib/Algebra/Polynomial/Basic.lean index fdb174e68d4da..b1d85a96da4bd 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 @@ -49,8 +49,6 @@ equivalence is also registered as a ring equiv in `Polynomial.toFinsuppIso`. The in general not be used once the basic API for polynomials is constructed. -/ - - noncomputable section /-- `Polynomial R` is the type of univariate polynomials over `R`. @@ -66,8 +64,6 @@ open AddMonoidAlgebra open Finsupp hiding single open Function hiding Commute -open Polynomial - namespace Polynomial universe u @@ -402,9 +398,9 @@ theorem monomial_mul_monomial (n m : ℕ) (r s : R) : @[simp] theorem monomial_pow (n : ℕ) (r : R) (k : ℕ) : monomial n r ^ k = monomial (n * k) (r ^ k) := by - induction' k with k ih - · simp [pow_zero, monomial_zero_one] - · simp [pow_succ, ih, monomial_mul_monomial, mul_add, add_comm] + induction k with + | zero => simp [pow_zero, monomial_zero_one] + | succ k ih => simp [pow_succ, ih, monomial_mul_monomial, mul_add, add_comm] theorem smul_monomial {S} [SMulZeroClass S R] (a : S) (n : ℕ) (b : R) : a • monomial n b = monomial n (a • b) := @@ -417,6 +413,10 @@ theorem monomial_injective (n : ℕ) : Function.Injective (monomial n : R → R[ theorem monomial_eq_zero_iff (t : R) (n : ℕ) : monomial n t = 0 ↔ t = 0 := LinearMap.map_eq_zero_iff _ (Polynomial.monomial_injective n) +theorem monomial_eq_monomial_iff {m n : ℕ} {a b : R} : + monomial m a = monomial n b ↔ m = n ∧ a = b ∨ a = 0 ∧ b = 0 := by + rw [← toFinsupp_inj, toFinsupp_monomial, toFinsupp_monomial, Finsupp.single_eq_single_iff] + theorem support_add : (p + q).support ⊆ p.support ∪ q.support := by simpa [support] using Finsupp.support_add @@ -486,6 +486,10 @@ theorem monomial_one_right_eq_X_pow (n : ℕ) : monomial n (1 : R) = X ^ n := by theorem toFinsupp_X : X.toFinsupp = Finsupp.single 1 (1 : R) := rfl +theorem X_ne_C [Nontrivial R] (a : R) : X ≠ C a := by + intro he + simpa using monomial_eq_monomial_iff.1 he + /-- `X` commutes with everything, even when the coefficients are noncommutative. -/ theorem X_mul : X * p = p * X := by rcases p with ⟨⟩ @@ -539,9 +543,9 @@ theorem monomial_mul_X (n : ℕ) (r : R) : monomial n r * X = monomial (n + 1) r @[simp] theorem monomial_mul_X_pow (n : ℕ) (r : R) (k : ℕ) : monomial n r * X ^ k = monomial (n + k) r := by - induction' k with k ih - · simp - · simp [ih, pow_succ, ← mul_assoc, add_assoc] + induction k with + | zero => simp + | succ k ih => simp [ih, pow_succ, ← mul_assoc, add_assoc] @[simp] theorem X_mul_monomial (n : ℕ) (r : R) : X * monomial n r = monomial (n + 1) r := by @@ -575,6 +579,13 @@ theorem toFinsupp_apply (f : R[X]) (i) : f.toFinsupp i = f.coeff i := by cases f theorem coeff_monomial : coeff (monomial n a) m = if n = m then a else 0 := by simp [coeff, Finsupp.single_apply] +@[simp] +theorem coeff_monomial_same (n : ℕ) (c : R) : (monomial n c).coeff n = c := + Finsupp.single_eq_same + +theorem coeff_monomial_of_ne {m n : ℕ} (c : R) (h : n ≠ m) : (monomial n c).coeff m = 0 := + Finsupp.single_eq_of_ne h + @[simp] theorem coeff_zero (n : ℕ) : coeff (0 : R[X]) n = 0 := rfl @@ -934,7 +945,7 @@ section Update /-- Replace the coefficient of a `p : R[X]` at a given degree `n : ℕ` by a given value `a : R`. If `a = 0`, this is equal to `p.erase n` -If `p.natDegree < n` and `a ≠ 0`, this increases the degree to `n`. -/ +If `p.natDegree < n` and `a ≠ 0`, this increases the degree to `n`. -/ def update (p : R[X]) (n : ℕ) (a : R) : R[X] := Polynomial.ofFinsupp (p.toFinsupp.update n a) diff --git a/Mathlib/Algebra/Polynomial/BigOperators.lean b/Mathlib/Algebra/Polynomial/BigOperators.lean index ffa4e0a8e9d60..cef12c507490a 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,7 +186,7 @@ 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 diff --git a/Mathlib/Algebra/Polynomial/Bivariate.lean b/Mathlib/Algebra/Polynomial/Bivariate.lean index 24034be6c2820..a78e8ffa4e2c8 100644 --- a/Mathlib/Algebra/Polynomial/Bivariate.lean +++ b/Mathlib/Algebra/Polynomial/Bivariate.lean @@ -41,15 +41,96 @@ abbrev CC (r : R) : R[X][Y] := C (C r) lemma evalEval_C (x y : R) (p : R[X]) : (C p).evalEval x y = p.eval x := by rw [evalEval, eval_C] +@[simp] +lemma evalEval_CC (x y : R) (p : R) : (CC p).evalEval x y = p := by + rw [evalEval_C, eval_C] + +@[simp] +lemma evalEval_zero (x y : R) : (0 : R[X][Y]).evalEval x y = 0 := by + simp only [evalEval, eval_zero] + +@[simp] +lemma evalEval_one (x y : R) : (1 : R[X][Y]).evalEval x y = 1 := by + simp only [evalEval, eval_one] + +@[simp] +lemma evalEval_natCast (x y : R) (n : ℕ) : (n : R[X][Y]).evalEval x y = n := by + simp only [evalEval, eval_natCast] + +@[simp] lemma evalEval_X (x y : R) : X.evalEval x y = y := by rw [evalEval, eval_X, eval_C] +@[simp] +lemma evalEval_add (x y : R) (p q : R[X][Y]) : + (p + q).evalEval x y = p.evalEval x y + q.evalEval x y := by + simp only [evalEval, eval_add] + +lemma evalEval_sum (x y : R) (p : R[X]) (f : ℕ → R → R[X][Y]) : + (p.sum f).evalEval x y = p.sum fun n a => (f n a).evalEval x y := by + simp only [evalEval, eval, eval₂_sum] + +lemma evalEval_finset_sum {ι : Type*} (s : Finset ι) (x y : R) (f : ι → R[X][Y]) : + (∑ i ∈ s, f i).evalEval x y = ∑ i ∈ s, (f i).evalEval x y := by + simp only [evalEval, eval_finset_sum] + +@[simp] +lemma evalEval_smul [Monoid S] [DistribMulAction S R] [IsScalarTower S R R] (x y : R) (s : S) + (p : R[X][Y]) : (s • p).evalEval x y = s • p.evalEval x y := by + simp only [evalEval, eval_smul] + +lemma evalEval_surjective (x y : R) : Function.Surjective <| evalEval x y := + fun y => ⟨CC y, evalEval_CC ..⟩ + end Semiring +section Ring + +variable [Ring R] + +@[simp] +lemma evalEval_neg (x y : R) (p : R[X][Y]) : (-p).evalEval x y = -p.evalEval x y := by + simp only [evalEval, eval_neg] + +@[simp] +lemma evalEval_sub (x y : R) (p q : R[X][Y]) : + (p - q).evalEval x y = p.evalEval x y - q.evalEval x y := by + simp only [evalEval, eval_sub] + +@[simp] +lemma evalEval_intCast (x y : R) (n : ℤ) : (n : R[X][Y]).evalEval x y = n := by + simp only [evalEval, eval_intCast] + +end Ring + section CommSemiring variable [CommSemiring R] +@[simp] +lemma evalEval_mul (x y : R) (p q : R[X][Y]) : + (p * q).evalEval x y = p.evalEval x y * q.evalEval x y := by + simp only [evalEval, eval_mul] + +lemma evalEval_prod {ι : Type*} (s : Finset ι) (x y : R) (p : ι → R[X][Y]) : + (∏ j ∈ s, p j).evalEval x y = ∏ j ∈ s, (p j).evalEval x y := by + simp only [evalEval, eval_prod] + +lemma evalEval_list_prod (x y : R) (l : List R[X][Y]) : + l.prod.evalEval x y = (l.map <| evalEval x y).prod := by + simpa only [evalEval, eval_list_prod, List.map_map] using by rfl + +lemma evalEval_multiset_prod (x y : R) (l : Multiset R[X][Y]) : + l.prod.evalEval x y = (l.map <| evalEval x y).prod := by + simpa only [evalEval, eval_multiset_prod, Multiset.map_map] using by rfl + +@[simp] +lemma evalEval_pow (x y : R) (p : R[X][Y]) (n : ℕ) : (p ^ n).evalEval x y = p.evalEval x y ^ n := by + simp only [evalEval, eval_pow] + +lemma evalEval_dvd (x y : R) {p q : R[X][Y]} : p ∣ q → p.evalEval x y ∣ q.evalEval x y := + eval_dvd ∘ eval_dvd + lemma coe_algebraMap_eq_CC : algebraMap R R[X][Y] = CC (R := R) := rfl /-- `evalEval x y` as a ring homomorphism. -/ @@ -58,12 +139,10 @@ lemma coe_algebraMap_eq_CC : algebraMap R R[X][Y] = CC (R := R) := rfl lemma coe_evalEvalRingHom (x y : R) : evalEvalRingHom x y = evalEval x y := rfl -lemma evalEvalRingHom_eq (x : R) : - evalEvalRingHom x = eval₂RingHom (evalRingHom x) := by +lemma evalEvalRingHom_eq (x : R) : evalEvalRingHom x = eval₂RingHom (evalRingHom x) := by ext <;> simp -lemma eval₂_evalRingHom (x : R) : - eval₂ (evalRingHom x) = evalEval x := by +lemma eval₂_evalRingHom (x : R) : eval₂ (evalRingHom x) = evalEval x := by ext1; rw [← coe_evalEvalRingHom, evalEvalRingHom_eq, coe_eval₂RingHom] lemma map_evalRingHom_eval (x y : R) (p : R[X][Y]) : diff --git a/Mathlib/Algebra/Polynomial/Coeff.lean b/Mathlib/Algebra/Polynomial/Coeff.lean index 78b1608e661ac..a0550adae74d1 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 @@ -99,7 +99,7 @@ lemma coeff_list_sum (l : List R[X]) (n : ℕ) : lemma coeff_list_sum_map {ι : Type*} (l : List ι) (f : ι → R[X]) (n : ℕ) : (l.map f).sum.coeff n = (l.map (fun a => (f a).coeff n)).sum := by - simp_rw [coeff_list_sum, List.map_map, Function.comp, lcoeff_apply] + simp_rw [coeff_list_sum, List.map_map, Function.comp_def, lcoeff_apply] 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 @@ -119,6 +119,11 @@ theorem coeff_mul (p q : R[X]) (n : ℕ) : @[simp] theorem mul_coeff_zero (p q : R[X]) : coeff (p * q) 0 = coeff p 0 * coeff q 0 := by simp [coeff_mul] +theorem mul_coeff_one (p q : R[X]) : + coeff (p * q) 1 = coeff p 0 * coeff q 1 + coeff p 1 * coeff q 0 := by + rw [coeff_mul, Nat.antidiagonal_eq_map] + simp [sum_range_succ] + /-- `constantCoeff p` returns the constant term of the polynomial `p`, defined as `coeff p 0`. This is a ring homomorphism. -/ @[simps] @@ -215,7 +220,7 @@ theorem card_support_trinomial {k m n : ℕ} (hkm : k < m) (hmn : m < n) {x y z (hy : y ≠ 0) (hz : z ≠ 0) : card (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 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 3a4e2fc353d1c..3a3fe3f22832f 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")] @@ -614,13 +620,21 @@ theorem degree_add_eq_left_of_degree_lt (h : degree q < degree p) : degree (p + theorem degree_add_eq_right_of_degree_lt (h : degree p < degree q) : degree (p + q) = degree q := by rw [add_comm, degree_add_eq_left_of_degree_lt h] +theorem natDegree_add_eq_left_of_degree_lt (h : degree q < degree p) : + natDegree (p + q) = natDegree p := + natDegree_eq_of_degree_eq (degree_add_eq_left_of_degree_lt h) + theorem natDegree_add_eq_left_of_natDegree_lt (h : natDegree q < natDegree p) : natDegree (p + q) = natDegree p := - natDegree_eq_of_degree_eq (degree_add_eq_left_of_degree_lt (degree_lt_degree h)) + natDegree_add_eq_left_of_degree_lt (degree_lt_degree h) + +theorem natDegree_add_eq_right_of_degree_lt (h : degree p < degree q) : + natDegree (p + q) = natDegree q := + natDegree_eq_of_degree_eq (degree_add_eq_right_of_degree_lt h) theorem natDegree_add_eq_right_of_natDegree_lt (h : natDegree p < natDegree q) : natDegree (p + q) = natDegree q := - natDegree_eq_of_degree_eq (degree_add_eq_right_of_degree_lt (degree_lt_degree h)) + natDegree_add_eq_right_of_degree_lt (degree_lt_degree h) theorem degree_add_C (hp : 0 < degree p) : degree (p + C a) = degree p := add_comm (C a) p ▸ degree_add_eq_right_of_degree_lt <| lt_of_le_of_lt degree_C_le hp @@ -945,11 +959,11 @@ theorem natDegree_mul_le_of_le (hp : natDegree p ≤ m) (hg : natDegree q ≤ n) natDegree_mul_le.trans <| add_le_add ‹_› ‹_› theorem natDegree_pow_le {p : R[X]} {n : ℕ} : (p ^ n).natDegree ≤ n * p.natDegree := by - induction' n with i hi - · simp - · rw [pow_succ, Nat.succ_mul] - apply le_trans natDegree_mul_le - exact add_le_add_right hi _ + induction n with + | zero => simp + | succ i hi => + rw [pow_succ, Nat.succ_mul] + apply le_trans natDegree_mul_le (add_le_add_right hi _) theorem natDegree_pow_le_of_le (n : ℕ) (hp : natDegree p ≤ m) : natDegree (p ^ n) ≤ n * m := @@ -958,9 +972,10 @@ theorem natDegree_pow_le_of_le (n : ℕ) (hp : natDegree p ≤ m) : @[simp] theorem coeff_pow_mul_natDegree (p : R[X]) (n : ℕ) : (p ^ n).coeff (n * p.natDegree) = p.leadingCoeff ^ n := by - induction' n with i hi - · simp - · rw [pow_succ, pow_succ, Nat.succ_mul] + induction n with + | zero => simp + | succ i hi => + rw [pow_succ, pow_succ, Nat.succ_mul] by_cases hp1 : p.leadingCoeff ^ i = 0 · rw [hp1, zero_mul] by_cases hp2 : p ^ i = 0 diff --git a/Mathlib/Algebra/Polynomial/Degree/Lemmas.lean b/Mathlib/Algebra/Polynomial/Degree/Lemmas.lean index 9683ab124fc69..649bab3a13526 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 @@ -58,6 +58,13 @@ theorem natDegree_comp_le : natDegree (p.comp q) ≤ natDegree p * natDegree q : mul_le_mul_of_nonneg_right (le_natDegree_of_ne_zero (mem_support_iff.1 hn)) (Nat.zero_le _) +theorem natDegree_comp_eq_of_mul_ne_zero (h : p.leadingCoeff * q.leadingCoeff ^ p.natDegree ≠ 0) : + natDegree (p.comp q) = natDegree p * natDegree q := by + by_cases hq : natDegree q = 0 + · exact le_antisymm natDegree_comp_le (by simp [hq]) + apply natDegree_eq_of_le_of_coeff_ne_zero natDegree_comp_le + rwa [coeff_comp_degree_mul_degree hq] + theorem degree_pos_of_root {p : R[X]} (hp : p ≠ 0) (h : IsRoot p a) : 0 < degree p := lt_of_not_ge fun hlt => by have := eq_C_of_degree_le_zero hlt @@ -345,16 +352,15 @@ theorem natDegree_comp : natDegree (p.comp q) = natDegree p * natDegree q := by natDegree_C, mul_zero] · by_cases p0 : p = 0 · simp only [p0, zero_comp, natDegree_zero, zero_mul] - refine le_antisymm natDegree_comp_le (le_natDegree_of_ne_zero ?_) - simp only [coeff_comp_degree_mul_degree q0, p0, mul_eq_zero, leadingCoeff_eq_zero, or_self_iff, - ne_zero_of_natDegree_gt (Nat.pos_of_ne_zero q0), pow_ne_zero, Ne, not_false_iff] + · simp only [Ne, mul_eq_zero, leadingCoeff_eq_zero, p0, natDegree_comp_eq_of_mul_ne_zero, + ne_zero_of_natDegree_gt (Nat.pos_of_ne_zero q0), not_false_eq_true, pow_ne_zero, or_self] @[simp] theorem natDegree_iterate_comp (k : ℕ) : (p.comp^[k] q).natDegree = p.natDegree ^ k * q.natDegree := by - induction' k with k IH - · simp - · rw [Function.iterate_succ_apply', natDegree_comp, IH, pow_succ', mul_assoc] + induction k with + | zero => simp + | succ k IH => rw [Function.iterate_succ_apply', natDegree_comp, IH, pow_succ', mul_assoc] theorem leadingCoeff_comp (hq : natDegree q ≠ 0) : leadingCoeff (p.comp q) = leadingCoeff p * leadingCoeff q ^ natDegree p := by diff --git a/Mathlib/Algebra/Polynomial/Degree/TrailingDegree.lean b/Mathlib/Algebra/Polynomial/Degree/TrailingDegree.lean index af0a168b4849f..78ee6ce26e4a0 100644 --- a/Mathlib/Algebra/Polynomial/Degree/TrailingDegree.lean +++ b/Mathlib/Algebra/Polynomial/Degree/TrailingDegree.lean @@ -122,7 +122,7 @@ theorem natTrailingDegree_le_of_ne_zero (h : coeff p n ≠ 0) : natTrailingDegre constructor · rintro h by_contra hp - obtain ⟨n, hpn, hn⟩ := by simpa using min_mem_image_coe $ support_nonempty.2 hp + obtain ⟨n, hpn, hn⟩ := by simpa using min_mem_image_coe <| support_nonempty.2 hp obtain rfl := (trailingDegree_eq_iff_natTrailingDegree_eq hp).1 hn.symm exact hpn h · rintro rfl @@ -139,7 +139,7 @@ lemma trailingDegree_eq_zero : trailingDegree p = 0 ↔ coeff p 0 ≠ 0 := simp [natTrailingDegree, or_comm] lemma natTrailingDegree_ne_zero : natTrailingDegree p ≠ 0 ↔ p ≠ 0 ∧ coeff p 0 = 0 := - natTrailingDegree_eq_zero.not.trans $ by rw [not_or, not_ne_iff] + natTrailingDegree_eq_zero.not.trans <| by rw [not_or, not_ne_iff] lemma trailingDegree_ne_zero : trailingDegree p ≠ 0 ↔ coeff p 0 = 0 := trailingDegree_eq_zero.not_left 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 b80dbfa008b96..9f22f0fa03689 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 @@ -134,9 +134,9 @@ theorem derivative_smul {S : Type*} [Monoid S] [DistribMulAction S R] [IsScalarT @[simp] theorem iterate_derivative_smul {S : Type*} [Monoid S] [DistribMulAction S R] [IsScalarTower S R R] (s : S) (p : R[X]) (k : ℕ) : derivative^[k] (s • p) = s • derivative^[k] p := by - induction' k with k ih generalizing p - · simp - · simp [ih] + induction k generalizing p with + | zero => simp + | succ k ih => simp [ih] @[simp] theorem iterate_derivative_C_mul (a : R) (p : R[X]) (k : ℕ) : @@ -295,7 +295,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) : @@ -333,44 +333,46 @@ theorem coeff_iterate_derivative {k} (p : R[X]) (m : ℕ) : 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 - induction' n with n IH - · simp [Finset.range] - calc - derivative^[n + 1] (p * q) = - derivative (∑ k ∈ range n.succ, - n.choose k • (derivative^[n - k] p * derivative^[k] q)) := by - rw [Function.iterate_succ_apply', IH] - _ = (∑ k ∈ range n.succ, - n.choose k • (derivative^[n - k + 1] p * derivative^[k] q)) + - ∑ k ∈ range n.succ, - n.choose k • (derivative^[n - k] p * derivative^[k + 1] q) := by - simp_rw [derivative_sum, derivative_smul, derivative_mul, Function.iterate_succ_apply', - smul_add, sum_add_distrib] - _ = (∑ k ∈ range n.succ, - n.choose k.succ • (derivative^[n - k] p * derivative^[k + 1] q)) + - 1 • (derivative^[n + 1] p * derivative^[0] q) + - ∑ k ∈ range n.succ, n.choose k • (derivative^[n - k] p * derivative^[k + 1] q) := - ?_ - _ = ((∑ k ∈ range n.succ, n.choose k • (derivative^[n - k] p * derivative^[k + 1] q)) + - ∑ k ∈ range n.succ, - n.choose k.succ • (derivative^[n - k] p * derivative^[k + 1] q)) + - 1 • (derivative^[n + 1] p * derivative^[0] q) := by - rw [add_comm, add_assoc] - _ = (∑ i ∈ range n.succ, - (n + 1).choose (i + 1) • (derivative^[n + 1 - (i + 1)] p * derivative^[i + 1] q)) + - 1 • (derivative^[n + 1] p * derivative^[0] q) := by - simp_rw [Nat.choose_succ_succ, Nat.succ_sub_succ, add_smul, sum_add_distrib] - _ = ∑ k ∈ range n.succ.succ, - n.succ.choose k • (derivative^[n.succ - k] p * derivative^[k] q) := by - rw [sum_range_succ' _ n.succ, Nat.choose_zero_right, tsub_zero] - congr - refine (sum_range_succ' _ _).trans (congr_arg₂ (· + ·) ?_ ?_) - · rw [sum_range_succ, Nat.choose_succ_self, zero_smul, add_zero] - refine sum_congr rfl fun k hk => ?_ - rw [mem_range] at hk + induction n with + | zero => + simp [Finset.range] + | succ n IH => + calc + derivative^[n + 1] (p * q) = + derivative (∑ k ∈ range n.succ, + n.choose k • (derivative^[n - k] p * derivative^[k] q)) := by + rw [Function.iterate_succ_apply', IH] + _ = (∑ k ∈ range n.succ, + n.choose k • (derivative^[n - k + 1] p * derivative^[k] q)) + + ∑ k ∈ range n.succ, + n.choose k • (derivative^[n - k] p * derivative^[k + 1] q) := by + simp_rw [derivative_sum, derivative_smul, derivative_mul, Function.iterate_succ_apply', + smul_add, sum_add_distrib] + _ = (∑ k ∈ range n.succ, + n.choose k.succ • (derivative^[n - k] p * derivative^[k + 1] q)) + + 1 • (derivative^[n + 1] p * derivative^[0] q) + + ∑ k ∈ range n.succ, n.choose k • (derivative^[n - k] p * derivative^[k + 1] q) := + ?_ + _ = ((∑ k ∈ range n.succ, n.choose k • (derivative^[n - k] p * derivative^[k + 1] q)) + + ∑ k ∈ range n.succ, + n.choose k.succ • (derivative^[n - k] p * derivative^[k + 1] q)) + + 1 • (derivative^[n + 1] p * derivative^[0] q) := by + rw [add_comm, add_assoc] + _ = (∑ i ∈ range n.succ, + (n + 1).choose (i + 1) • (derivative^[n + 1 - (i + 1)] p * derivative^[i + 1] q)) + + 1 • (derivative^[n + 1] p * derivative^[0] q) := by + simp_rw [Nat.choose_succ_succ, Nat.succ_sub_succ, add_smul, sum_add_distrib] + _ = ∑ k ∈ range n.succ.succ, + n.succ.choose k • (derivative^[n.succ - k] p * derivative^[k] q) := by + rw [sum_range_succ' _ n.succ, Nat.choose_zero_right, tsub_zero] congr - omega - · rw [Nat.choose_zero_right, tsub_zero] + refine (sum_range_succ' _ _).trans (congr_arg₂ (· + ·) ?_ ?_) + · rw [sum_range_succ, Nat.choose_succ_self, zero_smul, add_zero] + refine sum_congr rfl fun k hk => ?_ + rw [mem_range] at hk + congr + omega + · rw [Nat.choose_zero_right, tsub_zero] end Semiring @@ -418,9 +420,11 @@ theorem dvd_iterate_derivative_pow (f : R[X]) (n : ℕ) {m : ℕ} (c : R) (hm : 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 k ih - · erw [Function.iterate_zero_apply, tsub_zero, Nat.descFactorial_zero, Nat.cast_one, one_mul] - · rw [Function.iterate_succ_apply', ih, derivative_natCast_mul, derivative_X_pow, C_eq_natCast, + induction k with + | zero => + 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] simp [mul_comm, mul_assoc, mul_left_comm] diff --git a/Mathlib/Algebra/Polynomial/Div.lean b/Mathlib/Algebra/Polynomial/Div.lean index 61c5825557e4d..7ac2f94a0beb8 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 @@ -167,7 +167,7 @@ theorem zero_modByMonic (p : R[X]) : 0 %ₘ p = 0 := by unfold modByMonic divModByMonicAux dsimp by_cases hp : Monic p - · rw [dif_pos hp, if_neg (mt And.right (not_not_intro rfl))] + · rw [dif_pos hp, if_neg (mt And.right (not_not_intro rfl)), Prod.snd_zero] · rw [dif_neg hp] @[simp] @@ -176,7 +176,7 @@ theorem zero_divByMonic (p : R[X]) : 0 /ₘ p = 0 := by unfold divByMonic divModByMonicAux dsimp by_cases hp : Monic p - · rw [dif_pos hp, if_neg (mt And.right (not_not_intro rfl))] + · rw [dif_pos hp, if_neg (mt And.right (not_not_intro rfl)), Prod.fst_zero] · rw [dif_neg hp] @[simp] @@ -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,7 +495,8 @@ 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) diff --git a/Mathlib/Algebra/Polynomial/EraseLead.lean b/Mathlib/Algebra/Polynomial/EraseLead.lean index 56246cc180cc6..7f0f5dd10d6e4 100644 --- a/Mathlib/Algebra/Polynomial/EraseLead.lean +++ b/Mathlib/Algebra/Polynomial/EraseLead.lean @@ -150,29 +150,40 @@ theorem eraseLead_C_mul_X_pow (r : R) (n : ℕ) : eraseLead (C r * X ^ n) = 0 := @[simp] lemma eraseLead_C_mul_X (r : R) : eraseLead (C r * X) = 0 := by simpa using eraseLead_C_mul_X_pow _ 1 -theorem eraseLead_add_of_natDegree_lt_left {p q : R[X]} (pq : q.natDegree < p.natDegree) : +theorem eraseLead_add_of_degree_lt_left {p q : R[X]} (pq : q.degree < p.degree) : (p + q).eraseLead = p.eraseLead + q := by ext n by_cases nd : n = p.natDegree - · rw [nd, eraseLead_coeff, if_pos (natDegree_add_eq_left_of_natDegree_lt pq).symm] - simpa using (coeff_eq_zero_of_natDegree_lt pq).symm + · rw [nd, eraseLead_coeff, if_pos (natDegree_add_eq_left_of_degree_lt pq).symm] + simpa using (coeff_eq_zero_of_degree_lt (lt_of_lt_of_le pq degree_le_natDegree)).symm · rw [eraseLead_coeff, coeff_add, coeff_add, eraseLead_coeff, if_neg, if_neg nd] rintro rfl - exact nd (natDegree_add_eq_left_of_natDegree_lt pq) + exact nd (natDegree_add_eq_left_of_degree_lt pq) -theorem eraseLead_add_of_natDegree_lt_right {p q : R[X]} (pq : p.natDegree < q.natDegree) : +theorem eraseLead_add_of_natDegree_lt_left {p q : R[X]} (pq : q.natDegree < p.natDegree) : + (p + q).eraseLead = p.eraseLead + q := + eraseLead_add_of_degree_lt_left (degree_lt_degree pq) + +theorem eraseLead_add_of_degree_lt_right {p q : R[X]} (pq : p.degree < q.degree) : (p + q).eraseLead = p + q.eraseLead := by ext n by_cases nd : n = q.natDegree - · rw [nd, eraseLead_coeff, if_pos (natDegree_add_eq_right_of_natDegree_lt pq).symm] - simpa using (coeff_eq_zero_of_natDegree_lt pq).symm + · rw [nd, eraseLead_coeff, if_pos (natDegree_add_eq_right_of_degree_lt pq).symm] + simpa using (coeff_eq_zero_of_degree_lt (lt_of_lt_of_le pq degree_le_natDegree)).symm · rw [eraseLead_coeff, coeff_add, coeff_add, eraseLead_coeff, if_neg, if_neg nd] rintro rfl - exact nd (natDegree_add_eq_right_of_natDegree_lt pq) + exact nd (natDegree_add_eq_right_of_degree_lt pq) + +theorem eraseLead_add_of_natDegree_lt_right {p q : R[X]} (pq : p.natDegree < q.natDegree) : + (p + q).eraseLead = p + q.eraseLead := + eraseLead_add_of_degree_lt_right (degree_lt_degree pq) theorem eraseLead_degree_le : (eraseLead f).degree ≤ f.degree := f.degree_erase_le _ +theorem degree_eraseLead_lt (hf : f ≠ 0) : (eraseLead f).degree < f.degree := + f.degree_erase_lt hf + theorem eraseLead_natDegree_le_aux : (eraseLead f).natDegree ≤ f.natDegree := natDegree_le_natDegree eraseLead_degree_le @@ -202,7 +213,7 @@ theorem eraseLead_natDegree_le (f : R[X]) : (eraseLead f).natDegree ≤ f.natDeg lemma natDegree_eraseLead (h : f.nextCoeff ≠ 0) : f.eraseLead.natDegree = f.natDegree - 1 := by have := natDegree_pos_of_nextCoeff_ne_zero h - refine f.eraseLead_natDegree_le.antisymm $ le_natDegree_of_ne_zero ?_ + refine f.eraseLead_natDegree_le.antisymm <| le_natDegree_of_ne_zero ?_ rwa [eraseLead_coeff_of_ne _ (tsub_lt_self _ _).ne, ← nextCoeff_of_natDegree_pos] all_goals positivity @@ -339,9 +350,10 @@ theorem card_support_eq {n : ℕ} : ∃ (k : Fin n → ℕ) (x : Fin n → R) (hk : StrictMono k) (hx : ∀ 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 with n hn generalizing f - · exact fun hf => ⟨0, 0, fun x => x.elim0, fun x => x.elim0, card_support_eq_zero.mp hf⟩ - · intro h + induction n generalizing f with + | zero => exact fun hf => ⟨0, 0, fun x => x.elim0, fun x => x.elim0, card_support_eq_zero.mp hf⟩ + | succ n hn => + intro h obtain ⟨k, x, hk, hx, hf⟩ := hn (card_support_eraseLead' h) have H : ¬∃ k : Fin n, Fin.castSucc k = Fin.last n := by rintro ⟨i, hi⟩ diff --git a/Mathlib/Algebra/Polynomial/Eval.lean b/Mathlib/Algebra/Polynomial/Eval.lean index 47cf7b8a57706..e6b4d34e657aa 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 @@ -400,9 +403,9 @@ theorem eval_mul_X : (p * X).eval x = p.eval x * x := by @[simp] theorem eval_mul_X_pow {k : ℕ} : (p * X ^ k).eval x = p.eval x * x ^ k := by - induction' k with k ih - · simp - · simp [pow_succ, ← mul_assoc, ih] + induction k with + | zero => simp + | succ k ih => simp [pow_succ, ← mul_assoc, ih] theorem eval_sum (p : R[X]) (f : ℕ → R → R[X]) (x : R) : (p.sum f).eval x = p.sum fun n a => (f n a).eval x := @@ -511,15 +514,15 @@ theorem mul_X_comp : (p * X).comp r = p.comp r * r := by @[simp] theorem X_pow_comp {k : ℕ} : (X ^ k).comp p = p ^ k := by - induction' k with k ih - · simp - · simp [pow_succ, mul_X_comp, ih] + induction k with + | zero => simp + | succ k ih => simp [pow_succ, mul_X_comp, ih] @[simp] theorem mul_X_pow_comp {k : ℕ} : (p * X ^ k).comp r = p.comp r * r ^ k := by - induction' k with k ih - · simp - · simp [ih, pow_succ, ← mul_assoc, mul_X_comp] + induction k with + | zero => simp + | succ k ih => simp [ih, pow_succ, ← mul_assoc, mul_X_comp] @[simp] theorem C_mul_comp : (C a * p).comp r = C a * p.comp r := by @@ -898,9 +901,9 @@ theorem eval₂_comp {x : S} : eval₂ f x (p.comp q) = eval₂ f (eval₂ f x q @[simp] theorem iterate_comp_eval₂ (k : ℕ) (t : S) : eval₂ f t (p.comp^[k] q) = (fun x => eval₂ f x p)^[k] (eval₂ f t q) := by - induction' k with k IH - · simp - · rw [Function.iterate_succ_apply', Function.iterate_succ_apply', eval₂_comp, IH] + induction k with + | zero => simp + | succ k IH => rw [Function.iterate_succ_apply', Function.iterate_succ_apply', eval₂_comp, IH] end @@ -917,7 +920,7 @@ theorem eval₂_mul' : theorem eval₂_pow' (n : ℕ) : (p ^ n).eval₂ (algebraMap R S) x = (p.eval₂ (algebraMap R S) x) ^ n := by induction n with - | zero => simp only [Nat.zero_eq, pow_zero, eval₂_one] + | zero => simp only [pow_zero, eval₂_one] | succ n ih => rw [pow_succ, pow_succ, eval₂_mul', ih] @[simp] diff --git a/Mathlib/Algebra/Polynomial/Expand.lean b/Mathlib/Algebra/Polynomial/Expand.lean index d31b700d20a34..ae212d4a08496 100644 --- a/Mathlib/Algebra/Polynomial/Expand.lean +++ b/Mathlib/Algebra/Polynomial/Expand.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau -/ 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ⁿᵖ`. @@ -235,11 +234,12 @@ theorem expand_char (f : R[X]) : map (frobenius R p) (expand R p f) = f ^ p := b theorem map_expand_pow_char (f : R[X]) (n : ℕ) : map (frobenius R p ^ n) (expand R (p ^ n) f) = f ^ p ^ n := by - induction' n with _ n_ih - · simp [RingHom.one_def] - symm - rw [pow_succ, pow_mul, ← n_ih, ← expand_char, pow_succ', RingHom.mul_def, ← map_map, mul_comm, - expand_mul, ← map_expand] + induction n with + | zero => simp [RingHom.one_def] + | succ _ n_ih => + symm + rw [pow_succ, pow_mul, ← n_ih, ← expand_char, pow_succ', RingHom.mul_def, ← map_map, mul_comm, + expand_mul, ← map_expand] end ExpChar @@ -268,9 +268,8 @@ 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 isLocalRingHom_expand {p : ℕ} (hp : 0 < p) : IsLocalRingHom (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] @@ -280,7 +279,7 @@ 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 + 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 955c34ceffb85..06134da2f5675 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 @@ -95,7 +95,7 @@ theorem lt_rootMultiplicity_of_isRoot_iterate_derivative_of_mem_nonZeroDivisors' clear hroot induction n with | zero => - simp only [Nat.zero_eq, Nat.factorial_zero, Nat.cast_one] + simp only [Nat.factorial_zero, Nat.cast_one] exact Submonoid.one_mem _ | succ n ih => rw [Nat.factorial_succ, Nat.cast_mul, mul_mem_nonZeroDivisors] @@ -334,7 +334,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 +382,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 diff --git a/Mathlib/Algebra/Polynomial/GroupRingAction.lean b/Mathlib/Algebra/Polynomial/GroupRingAction.lean index 30813c8edd473..586acacc30c03 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] 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 31c9429ead2ad..a4fc244b867ab 100644 --- a/Mathlib/Algebra/Polynomial/Induction.lean +++ b/Mathlib/Algebra/Polynomial/Induction.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 import Mathlib.RingTheory.Ideal.Basic @@ -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)) @@ -39,9 +38,9 @@ protected theorem induction_on {M : R[X] → Prop} (p : R[X]) (h_C : ∀ a, M (C (h_monomial : ∀ (n : ℕ) (a : R), M (C a * X ^ n) → M (C a * X ^ (n + 1))) : M p := by have A : ∀ {n : ℕ} {a}, M (C a * X ^ n) := by intro n a - induction' n with n ih - · rw [pow_zero, mul_one]; exact h_C a - · exact h_monomial _ _ ih + induction n with + | zero => rw [pow_zero, mul_one]; exact h_C a + | succ n ih => exact h_monomial _ _ ih have B : ∀ s : Finset ℕ, M (s.sum fun n : ℕ => C (p.coeff n) * X ^ n) := by apply Finset.induction · convert h_C 0 @@ -75,7 +74,7 @@ theorem span_le_of_C_coeff_mem (cf : ∀ i : ℕ, C (f.coeff i) ∈ I) : theorem mem_span_C_coeff : f ∈ Ideal.span { g : R[X] | ∃ i : ℕ, g = C (coeff f i) } := by let p := Ideal.span { g : R[X] | ∃ i : ℕ, g = C (coeff f i) } - nth_rw 1 [(sum_C_mul_X_pow_eq f).symm] + nth_rw 2 [(sum_C_mul_X_pow_eq f).symm] refine Submodule.sum_mem _ fun n _hn => ?_ dsimp have : C (coeff f n) ∈ p := by 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 99365bbe5de8b..c5523266588fe 100644 --- a/Mathlib/Algebra/Polynomial/Laurent.lean +++ b/Mathlib/Algebra/Polynomial/Laurent.lean @@ -366,7 +366,7 @@ theorem reduce_to_polynomial_of_mul_T (f : R[T;T⁻¹]) {Q : R[T;T⁻¹] → Pro (Qf : ∀ f : R[X], Q (toLaurent f)) (QT : ∀ f, Q (f * T 1) → Q f) : Q f := by induction' f using LaurentPolynomial.induction_on_mul_T with f n induction n with - | zero => simpa only [Nat.zero_eq, Nat.cast_zero, neg_zero, T_zero, mul_one] using Qf _ + | zero => simpa only [Nat.cast_zero, neg_zero, T_zero, mul_one] using Qf _ | succ n hn => convert QT _ _; simpa using hn section Support @@ -542,10 +542,10 @@ lemma involutive_invert : Involutive (invert (R := R)) := fun _ ↦ by ext; simp lemma toLaurent_reverse (p : R[X]) : toLaurent p.reverse = invert (toLaurent p) * (T p.natDegree) := by nontriviality R - induction' p using Polynomial.recOnHorner with p t _ _ ih p hp ih - · simp - · simp [add_mul, ← ih] - · simpa [natDegree_mul_X hp] + induction p using Polynomial.recOnHorner with + | M0 => simp + | MC _ _ _ _ ih => simp [add_mul, ← ih] + | MX _ hp => simpa [natDegree_mul_X hp] end Inversion diff --git a/Mathlib/Algebra/Polynomial/Lifts.lean b/Mathlib/Algebra/Polynomial/Lifts.lean index d4a1f5911b893..9ec024df1967a 100644 --- a/Mathlib/Algebra/Polynomial/Lifts.lean +++ b/Mathlib/Algebra/Polynomial/Lifts.lean @@ -130,8 +130,7 @@ theorem monomial_mem_lifts_and_degree_eq {s : S} {n : ℕ} (hl : monomial n s obtain ⟨q, hq⟩ := hl replace hq := (ext_iff.1 hq) n have hcoeff : f (q.coeff n) = s := by - simp? [coeff_monomial] at hq says simp only [coeff_map, coeff_monomial, ↓reduceIte] at hq - exact hq + rwa [coeff_map, coeff_monomial_same] at hq use monomial n (q.coeff n) constructor · simp only [hcoeff, map_monomial] @@ -139,8 +138,7 @@ theorem monomial_mem_lifts_and_degree_eq {s : S} {n : ℕ} (hl : monomial n s intro habs simp only [habs, RingHom.map_zero] at hcoeff exact hzero hcoeff.symm - rw [← C_mul_X_pow_eq_monomial] - rw [← C_mul_X_pow_eq_monomial] + rw [← C_mul_X_pow_eq_monomial, ← C_mul_X_pow_eq_monomial] simp only [hzero, hqzero, Ne, not_false_iff, degree_C_mul_X_pow] /-- A polynomial lifts if and only if it can be lifted to a polynomial of the same degree. -/ diff --git a/Mathlib/Algebra/Polynomial/Module/AEval.lean b/Mathlib/Algebra/Polynomial/Module/AEval.lean index 101d2de77a9a8..17b934cb8564e 100644 --- a/Mathlib/Algebra/Polynomial/Module/AEval.lean +++ b/Mathlib/Algebra/Polynomial/Module/AEval.lean @@ -46,7 +46,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 +80,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`. -/ @@ -110,8 +111,7 @@ lemma annihilator_top_eq_ker_aeval [FaithfulSMul A M] : section Submodule -variable {p : Submodule R M} (hp : p ≤ p.comap (Algebra.lsmul R R M a)) - {q : Submodule R[X] <| AEval R M a} +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`. -/ @@ -132,7 +132,7 @@ def comapSubmodule : /-- An `R`-submodule which is stable under the action of `a` can be promoted to an `R[X]`-submodule. -/ -def mapSubmodule : Submodule R[X] <| AEval R M a := +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⟩ @@ -140,6 +140,8 @@ def mapSubmodule : Submodule R[X] <| AEval R M a := 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 := ⟨fun ⟨_, hm, hm'⟩ ↦ hm'.symm ▸ hm, fun hm ↦ ⟨(of R M a).symm m, hm, rfl⟩⟩ @@ -192,6 +194,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 4beded12152cd..43595606fd85c 100644 --- a/Mathlib/Algebra/Polynomial/Module/Basic.lean +++ b/Mathlib/Algebra/Polynomial/Module/Basic.lean @@ -66,7 +66,7 @@ theorem add_apply (g₁ g₂ : PolynomialModule R M) (a : ℕ) : (g₁ + g₂) a Finsupp.add_apply g₁ g₂ a /-- The monomial `m * x ^ i`. This is defeq to `Finsupp.singleAddHom`, and is redefined here -so that it has the desired type signature. -/ +so that it has the desired type signature. -/ noncomputable def single (i : ℕ) : M →+ PolynomialModule R M := Finsupp.singleAddHom i @@ -177,10 +177,11 @@ noncomputable def equivPolynomialSelf : PolynomialModule R R ≃ₗ[R[X]] R[X] : map_smul' := fun r x => by dsimp rw [← RingEquiv.coe_toEquiv_symm, RingEquiv.coe_toEquiv] - induction' x using induction_linear with _ _ hp hq n a - · rw [smul_zero, map_zero, mul_zero] - · rw [smul_add, map_add, map_add, mul_add, hp, hq] - · ext i + induction x using induction_linear with + | h0 => rw [smul_zero, map_zero, mul_zero] + | hadd _ _ hp hq => rw [smul_add, map_add, map_add, mul_add, hp, hq] + | hsingle n a => + ext i simp only [coeff_ofFinsupp, smul_single_apply, toFinsuppIso_symm_apply, coeff_ofFinsupp, single_apply, smul_eq_mul, Polynomial.coeff_mul, mul_ite, mul_zero] split_ifs with hn @@ -240,10 +241,10 @@ theorem map_smul (f : M →ₗ[R] M') (p : R[X]) (q : PolynomialModule R M) : · intro f g e₁ e₂ rw [smul_add, map_add, e₁, e₂, map_add, smul_add] intro i m - induction' p using Polynomial.induction_on' with _ _ e₁ e₂ - · rw [add_smul, map_add, e₁, e₂, Polynomial.map_add, add_smul] - · rw [monomial_smul_single, map_single, Polynomial.map_monomial, map_single, monomial_smul_single, - f.map_smul, algebraMap_smul] + induction p using Polynomial.induction_on' with + | h_add _ _ e₁ e₂ => rw [add_smul, map_add, e₁, e₂, Polynomial.map_add, add_smul] + | h_monomial => rw [monomial_smul_single, map_single, Polynomial.map_monomial, map_single, + monomial_smul_single, f.map_smul, algebraMap_smul] /-- Evaluate a polynomial `p : PolynomialModule R M` at `r : R`. -/ @[simps! (config := .lemmasOnly)] @@ -273,10 +274,9 @@ theorem eval_smul (p : R[X]) (q : PolynomialModule R M) (r : R) : · intro f g e₁ e₂ rw [smul_add, map_add, e₁, e₂, map_add, smul_add] intro i m - induction' p using Polynomial.induction_on' with _ _ e₁ e₂ - · rw [add_smul, map_add, Polynomial.eval_add, e₁, e₂, add_smul] - · rw [monomial_smul_single, eval_single, Polynomial.eval_monomial, eval_single, smul_comm, ← - smul_smul, pow_add, mul_smul] + 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 => 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) : @@ -286,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) : @@ -305,14 +306,13 @@ lemma aeval_equivPolynomial {S : Type*} [CommRing S] [Algebra S R] rw [equivPolynomial_single, aeval_monomial, mul_comm, map_single, Algebra.linearMap_apply, eval_single, smul_eq_mul] -/-- `comp p q` is the composition of `p : R[X]` and `q : M[X]` as `q(p(x))`. -/ +/-- `comp p q` is the composition of `p : R[X]` and `q : M[X]` as `q(p(x))`. -/ @[simps!] noncomputable def comp (p : R[X]) : PolynomialModule R M →ₗ[R] PolynomialModule R M := 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) : @@ -323,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 60c51bbad7bce..eb0f0cf67b6b0 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 @@ -83,16 +83,15 @@ theorem monic_of_degree_le (n : ℕ) (H1 : degree p ≤ n) (H2 : coeff p n = 1) fun H : ¬degree p < n => by rwa [Monic, Polynomial.leadingCoeff, natDegree, (lt_or_eq_of_le H1).resolve_left H] -theorem monic_X_pow_add {n : ℕ} (H : degree p ≤ n) : Monic (X ^ (n + 1) + p) := - have H1 : degree p < (n + 1 : ℕ) := lt_of_le_of_lt H (WithBot.coe_lt_coe.2 (Nat.lt_succ_self n)) - monic_of_degree_le (n + 1) - (le_trans (degree_add_le _ _) (max_le (degree_X_pow_le _) (le_of_lt H1))) - (by rw [coeff_add, coeff_X_pow, if_pos rfl, coeff_eq_zero_of_degree_lt H1, add_zero]) +theorem monic_X_pow_add {n : ℕ} (H : degree p < n) : Monic (X ^ n + p) := + monic_of_degree_le n + (le_trans (degree_add_le _ _) (max_le (degree_X_pow_le _) (le_of_lt H))) + (by rw [coeff_add, coeff_X_pow, if_pos rfl, coeff_eq_zero_of_degree_lt H, add_zero]) variable (a) in -theorem monic_X_pow_add_C {n : ℕ} (h : n ≠ 0) : (X ^ n + C a).Monic := by - obtain ⟨k, rfl⟩ := Nat.exists_eq_succ_of_ne_zero h - exact monic_X_pow_add <| degree_C_le.trans Nat.WithBot.coe_nonneg +theorem monic_X_pow_add_C {n : ℕ} (h : n ≠ 0) : (X ^ n + C a).Monic := + monic_X_pow_add <| (lt_of_le_of_lt degree_C_le + (by simp only [Nat.cast_pos, Nat.pos_iff_ne_zero, ne_eq, h, not_false_eq_true])) theorem monic_X_add_C (x : R) : Monic (X + C x) := pow_one (X : R[X]) ▸ monic_X_pow_add_C x one_ne_zero @@ -184,9 +183,7 @@ theorem nextCoeff_mul (hp : Monic p) (hq : Monic q) : nextCoeff (p * q) = nextCoeff p + nextCoeff q := by nontriviality simp only [← coeff_one_reverse] - rw [reverse_mul] <;> - simp [coeff_mul, antidiagonal, hp.leadingCoeff, hq.leadingCoeff, add_comm, - show Nat.succ 0 = 1 from rfl] + rw [reverse_mul] <;> simp [hp.leadingCoeff, hq.leadingCoeff, mul_coeff_one, add_comm] theorem nextCoeff_pow (hp : p.Monic) (n : ℕ) : (p ^ n).nextCoeff = n • p.nextCoeff := by induction n with @@ -340,8 +337,8 @@ variable [Ring R] {p : R[X]} theorem monic_X_sub_C (x : R) : Monic (X - C x) := by simpa only [sub_eq_add_neg, C_neg] using monic_X_add_C (-x) -theorem monic_X_pow_sub {n : ℕ} (H : degree p ≤ n) : Monic (X ^ (n + 1) - p) := by - simpa [sub_eq_add_neg] using monic_X_pow_add (show degree (-p) ≤ n by rwa [← degree_neg p] at H) +theorem monic_X_pow_sub {n : ℕ} (H : degree p < n) : Monic (X ^ n - p) := by + simpa [sub_eq_add_neg] using monic_X_pow_add (show degree (-p) < n by rwa [← degree_neg p] at H) /-- `X ^ n - a` is monic. -/ theorem monic_X_pow_sub_C {R : Type u} [Ring R] (a : R) {n : ℕ} (h : n ≠ 0) : diff --git a/Mathlib/Algebra/Polynomial/Monomial.lean b/Mathlib/Algebra/Polynomial/Monomial.lean index e96bdc18024b0..29b15cda6f45e 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 diff --git a/Mathlib/Algebra/Polynomial/Reverse.lean b/Mathlib/Algebra/Polynomial/Reverse.lean index 6b21c7277e1c1..2dba679853097 100644 --- a/Mathlib/Algebra/Polynomial/Reverse.lean +++ b/Mathlib/Algebra/Polynomial/Reverse.lean @@ -86,7 +86,7 @@ In other words, the terms with exponent `[0, ..., N]` now have exponent `[N, ... In practice, `reflect` is only used when `N` is at least as large as the degree of `f`. -Eventually, it will be used with `N` exactly equal to the degree of `f`. -/ +Eventually, it will be used with `N` exactly equal to the degree of `f`. -/ noncomputable def reflect (N : ℕ) : R[X] → R[X] | ⟨f⟩ => ⟨Finsupp.embDomain (revAt N) f⟩ @@ -313,9 +313,9 @@ theorem coeff_one_reverse (f : R[X]) : coeff (reverse f) 1 = nextCoeff f := by rw [commute_X p, reverse_mul_X] @[simp] lemma reverse_mul_X_pow (p : R[X]) (n : ℕ) : reverse (p * X ^ n) = reverse p := by - induction' n with n ih - · simp - rw [pow_succ, ← mul_assoc, reverse_mul_X, ih] + induction n with + | zero => simp + | succ n ih => rw [pow_succ, ← mul_assoc, reverse_mul_X, ih] @[simp] lemma reverse_X_pow_mul (p : R[X]) (n : ℕ) : reverse (X ^ n * p) = reverse p := by rw [commute_X_pow p, reverse_mul_X_pow] diff --git a/Mathlib/Algebra/Polynomial/RingDivision.lean b/Mathlib/Algebra/Polynomial/RingDivision.lean index 5732a7c7bd649..87a240f259415 100644 --- a/Mathlib/Algebra/Polynomial/RingDivision.lean +++ b/Mathlib/Algebra/Polynomial/RingDivision.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, Johan Commelin +Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker, Johan Commelin -/ import Mathlib.Algebra.Polynomial.AlgebraMap import Mathlib.Algebra.Polynomial.BigOperators @@ -27,6 +27,26 @@ 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]} @@ -130,7 +150,7 @@ theorem natDegree_pow (p : R[X]) (n : ℕ) : natDegree (p ^ n) = n * natDegree p classical obtain rfl | hp := eq_or_ne p 0 · obtain rfl | hn := eq_or_ne n 0 <;> simp [*] - exact natDegree_pow' $ by + 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 @@ -210,8 +230,6 @@ 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) -variable [CharZero R] - end NoZeroDivisors section NoZeroDivisors @@ -527,6 +545,29 @@ theorem rootMultiplicity_mul' {p q : R[X]} {x : R} simp_rw [eval_divByMonic_eq_trailingCoeff_comp] at hpq simp_rw [rootMultiplicity_eq_natTrailingDegree, mul_comp, natTrailingDegree_mul' hpq] +theorem Monic.comp_X_sub_C {p : R[X]} (hp : p.Monic) (r : R) : (p.comp (X - C r)).Monic := by + simpa using hp.comp_X_add_C (-r) + +@[simp] +theorem comp_neg_X_leadingCoeff_eq (p : R[X]) : + (p.comp (-X)).leadingCoeff = (-1) ^ p.natDegree * p.leadingCoeff := by + nontriviality R + by_cases h : p = 0 + · simp [h] + rw [Polynomial.leadingCoeff, natDegree_comp_eq_of_mul_ne_zero, coeff_comp_degree_mul_degree] <;> + simp [mul_comm, h] + +theorem Monic.neg_one_pow_natDegree_mul_comp_neg_X {p : R[X]} (hp : p.Monic) : + ((-1) ^ p.natDegree * p.comp (-X)).Monic := by + simp only [Monic] + 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] @@ -654,17 +695,6 @@ theorem natDegree_multiset_prod_X_sub_C_eq_card (s : Multiset R) : mul_one] · exact Multiset.forall_mem_map_iff.2 fun a _ => monic_X_sub_C a -theorem Monic.comp (hp : p.Monic) (hq : q.Monic) (h : q.natDegree ≠ 0) : (p.comp q).Monic := by - rw [Monic.def, leadingCoeff_comp h, Monic.def.1 hp, Monic.def.1 hq, one_pow, one_mul] - -theorem Monic.comp_X_add_C (hp : p.Monic) (r : R) : (p.comp (X + C r)).Monic := by - refine hp.comp (monic_X_add_C _) fun ha => ?_ - rw [natDegree_X_add_C] at ha - exact one_ne_zero ha - -theorem Monic.comp_X_sub_C (hp : p.Monic) (r : R) : (p.comp (X - C r)).Monic := by - simpa using hp.comp_X_add_C (-r) - 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)] diff --git a/Mathlib/Algebra/Polynomial/Roots.lean b/Mathlib/Algebra/Polynomial/Roots.lean index 06b3d6fd29716..59f7f94c78993 100644 --- a/Mathlib/Algebra/Polynomial/Roots.lean +++ b/Mathlib/Algebra/Polynomial/Roots.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, Johan Commelin +Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker, Johan Commelin -/ import Mathlib.Algebra.Polynomial.RingDivision @@ -108,10 +108,13 @@ 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 := @@ -206,9 +209,10 @@ theorem roots_prod {ι : Type*} (f : ι → R[X]) (s : Finset ι) : @[simp] theorem roots_pow (p : R[X]) (n : ℕ) : (p ^ n).roots = n • p.roots := by - induction' n with n ihn - · rw [pow_zero, roots_one, zero_smul, empty_eq_zero] - · rcases eq_or_ne p 0 with (rfl | hp) + induction n with + | zero => rw [pow_zero, roots_one, zero_smul, empty_eq_zero] + | succ n ihn => + rcases eq_or_ne p 0 with (rfl | hp) · rw [zero_pow n.succ_ne_zero, roots_zero, smul_zero] · rw [pow_succ, roots_mul (mul_ne_zero (pow_ne_zero _ hp) hp), ihn, add_smul, one_smul] @@ -311,7 +315,7 @@ theorem mul_mem_nthRootsFinset η₁ * η₂ ∈ nthRootsFinset n R := by cases n with | zero => - simp only [Nat.zero_eq, nthRootsFinset_zero, not_mem_empty] at hη₁ + simp only [nthRootsFinset_zero, not_mem_empty] at hη₁ | succ n => rw [mem_nthRootsFinset n.succ_pos] at hη₁ hη₂ ⊢ rw [mul_pow, hη₁, hη₂, one_mul] @@ -321,7 +325,7 @@ theorem ne_zero_of_mem_nthRootsFinset {η : R} (hη : η ∈ nthRootsFinset n R) rintro rfl cases n with | zero => - simp only [Nat.zero_eq, nthRootsFinset_zero, not_mem_empty] at hη + simp only [nthRootsFinset_zero, not_mem_empty] at hη | succ n => rw [mem_nthRootsFinset n.succ_pos, zero_pow n.succ_ne_zero] at hη exact zero_ne_one hη @@ -433,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 @@ -524,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] diff --git a/Mathlib/Algebra/Polynomial/Smeval.lean b/Mathlib/Algebra/Polynomial/Smeval.lean index 657e2d1b19d52..d24a7089bfc93 100644 --- a/Mathlib/Algebra/Polynomial/Smeval.lean +++ b/Mathlib/Algebra/Polynomial/Smeval.lean @@ -108,7 +108,7 @@ theorem smeval_add : (p + q).smeval x = p.smeval x + q.smeval x := by theorem smeval_natCast (n : ℕ) : (n : R[X]).smeval x = n • x ^ 0 := by induction n with - | zero => simp only [smeval_zero, Nat.cast_zero, Nat.zero_eq, zero_smul] + | zero => simp only [smeval_zero, Nat.cast_zero, zero_smul] | succ n ih => rw [n.cast_succ, smeval_add, ih, smeval_one, ← add_nsmul] @[deprecated (since := "2024-04-17")] @@ -180,7 +180,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 @@ -210,7 +210,7 @@ theorem smeval_at_zero : p.smeval (0 : S) = (p.coeff 0) • (1 : S) := by simp_all only [smeval_add, coeff_add, add_smul] | h_monomial n a => cases n with - | zero => simp only [Nat.zero_eq, monomial_zero_left, smeval_C, npow_zero, coeff_C_zero] + | zero => simp only [monomial_zero_left, smeval_C, npow_zero, coeff_C_zero] | succ n => rw [coeff_monomial_succ, smeval_monomial, npow_add, npow_one, mul_zero, zero_smul, smul_zero] diff --git a/Mathlib/Algebra/Polynomial/Splits.lean b/Mathlib/Algebra/Polynomial/Splits.lean index c30726a113d9c..3b0f053ebb0ea 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 @@ -300,11 +301,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 @@ -414,7 +437,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 +449,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/Taylor.lean b/Mathlib/Algebra/Polynomial/Taylor.lean index 6f9f0e82544ef..4a89d16c0bea7 100644 --- a/Mathlib/Algebra/Polynomial/Taylor.lean +++ b/Mathlib/Algebra/Polynomial/Taylor.lean @@ -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..c21059979dbcf 100644 --- a/Mathlib/Algebra/Polynomial/UnitTrinomial.lean +++ b/Mathlib/Algebra/Polynomial/UnitTrinomial.lean @@ -178,7 +178,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/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 aa9218bc51e55..f037884dabe10 100644 --- a/Mathlib/Algebra/Quandle.lean +++ b/Mathlib/Algebra/Quandle.lean @@ -93,16 +93,16 @@ The binary operation is regarded as a left action of the type on itself. class Shelf (α : Type u) where /-- The action of the `Shelf` over `α`-/ act : α → α → α - /-- A verification that `act` is self-distributive-/ + /-- A verification that `act` is self-distributive -/ self_distrib : ∀ {x y z : α}, act x (act y z) = act (act x y) (act x z) /-- 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. @@ -111,7 +111,7 @@ This is also the notion of rack and quandle homomorphisms. structure ShelfHom (S₁ : Type*) (S₂ : Type*) [Shelf S₁] [Shelf S₂] where /-- The function under the Shelf Homomorphism -/ toFun : S₁ → S₂ - /-- The homomorphism property of a Shelf Homomorphism-/ + /-- The homomorphism property of a Shelf Homomorphism -/ map_act' : ∀ {x y : S₁}, toFun (Shelf.act x y) = Shelf.act (toFun x) (toFun y) /-- A *rack* is an automorphic set (a set with an action on itself by @@ -129,13 +129,13 @@ class Rack (α : Type u) extends Shelf α where /-- Proof of right inverse -/ right_inv : ∀ x, Function.RightInverse (invAct x) (act x) -/-- Action of a Shelf-/ +/-- Action of a Shelf -/ scoped[Quandles] infixr:65 " ◃ " => Shelf.act -/-- Inverse Action of a Rack-/ +/-- Inverse Action of a Rack -/ scoped[Quandles] infixr:65 " ◃⁻¹ " => Rack.invAct -/-- Shelf Homomorphism-/ +/-- Shelf Homomorphism -/ scoped[Quandles] infixr:25 " →◃ " => ShelfHom open Quandles @@ -372,7 +372,7 @@ theorem fix_inv {x : Q} : x ◃⁻¹ x = x := by instance oppositeQuandle : Quandle Qᵐᵒᵖ where fix := by intro x - induction' x + induction x simp /-- The conjugation quandle of a group. Each element of the group acts by @@ -679,16 +679,18 @@ def toEnvelGroup.map {R : Type*} [Rack R] {G : Type*} [Group G] : right_inv F := MonoidHom.ext fun x => Quotient.inductionOn x fun x => by - induction' x with _ x y ih_x ih_y x ih_x - · exact F.map_one.symm - · rfl - · have hm : ⟦x.mul y⟧ = @Mul.mul (EnvelGroup R) _ ⟦x⟧ ⟦y⟧ := rfl + induction x with + | unit => exact F.map_one.symm + | incl => rfl + | mul x y ih_x ih_y => + have hm : ⟦x.mul y⟧ = @Mul.mul (EnvelGroup R) _ ⟦x⟧ ⟦y⟧ := rfl simp only [MonoidHom.coe_mk, OneHom.coe_mk, Quotient.lift_mk] suffices ∀ x y, F (Mul.mul x y) = F (x) * F (y) by simp_all only [MonoidHom.coe_mk, OneHom.coe_mk, Quotient.lift_mk, hm] rw [← ih_x, ← ih_y, mapAux] exact F.map_mul - · have hm : ⟦x.inv⟧ = @Inv.inv (EnvelGroup R) _ ⟦x⟧ := rfl + | inv x ih_x => + have hm : ⟦x.inv⟧ = @Inv.inv (EnvelGroup R) _ ⟦x⟧ := rfl rw [hm, F.map_inv, MonoidHom.map_inv, ih_x] /-- Given a homomorphism from a rack to a group, it factors through the enveloping group. diff --git a/Mathlib/Algebra/Quaternion.lean b/Mathlib/Algebra/Quaternion.lean index 97126ffd2f19d..05c61e0d4e530 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 @@ -55,8 +55,11 @@ Implemented as a structure with four fields: `re`, `imI`, `imJ`, and `imK`. -/ structure QuaternionAlgebra (R : Type*) (a b : R) where /-- Real part of a quaternion. -/ re : R + /-- First imaginary part (i) of a quaternion. -/ imI : R + /-- Second imaginary part (j) of a quaternion. -/ imJ : R + /-- Third imaginary part (k) of a quaternion. -/ imK : R @[inherit_doc] @@ -293,7 +296,7 @@ variable [Ring R] * `i * j = k`, `j * i = -k`; * `k * k = -c₁ * c₂`; * `i * k = c₁ * j`, `k * i = -c₁ * j`; -* `j * k = -c₂ * i`, `k * j = c₂ * i`. -/ +* `j * k = -c₂ * i`, `k * j = c₂ * i`. -/ instance : Mul ℍ[R,c₁,c₂] := ⟨fun a b => ⟨a.1 * b.1 + c₁ * a.2 * b.2 + c₂ * a.3 * b.3 - c₁ * c₂ * a.4 * b.4, @@ -566,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] @@ -1021,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 diff --git a/Mathlib/Algebra/Ring/Action/Basic.lean b/Mathlib/Algebra/Ring/Action/Basic.lean index 25558ac78f579..8466b8daf17c7 100644 --- a/Mathlib/Algebra/Ring/Action/Basic.lean +++ b/Mathlib/Algebra/Ring/Action/Basic.lean @@ -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/Group.lean b/Mathlib/Algebra/Ring/Action/Group.lean index 4317fba7f1f4a..428c3c34e2ae9 100644 --- a/Mathlib/Algebra/Ring/Action/Group.lean +++ b/Mathlib/Algebra/Ring/Action/Group.lean @@ -11,7 +11,7 @@ import Mathlib.Algebra.Ring.Equiv # If a group acts multiplicatively on a semiring, each group element acts by a ring automorphism. This result is split out from `Mathlib.Algebra.Ring.Action.Basic` -to avoid needing the import of `Mathlib.GroupTheory.GroupAction.Group`. +to avoid needing the import of `Mathlib.Algebra.GroupWithZero.Action.Basic`. -/ section Semiring diff --git a/Mathlib/Algebra/Ring/Aut.lean b/Mathlib/Algebra/Ring/Aut.lean index 881e53ba2eaeb..79289b53c66ec 100644 --- a/Mathlib/Algebra/Ring/Aut.lean +++ b/Mathlib/Algebra/Ring/Aut.lean @@ -18,7 +18,7 @@ The definition of multiplication in the automorphism group agrees with function multiplication in `Equiv.Perm`, and multiplication in `CategoryTheory.End`, but not with `CategoryTheory.comp`. -This file is kept separate from `Data/Equiv/Ring` so that `GroupTheory.Perm` is free to use +This file is kept separate from `Algebra/Ring/Equiv.lean` so that `GroupTheory.Perm` is free to use equivalences (and other files that use them) before the group structure is defined. ## Tags 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/CentroidHom.lean b/Mathlib/Algebra/Ring/CentroidHom.lean index 111c5f47148d5..37a70431efb16 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. -/ @@ -270,16 +270,17 @@ instance hasNPowNat : Pow (CentroidHom α) ℕ := ⟨fun f n ↦ { toAddMonoidHom := (f.toEnd ^ n : AddMonoid.End α) map_mul_left' := fun a b ↦ by - induction' n with n ih - · exact rfl - · rw [pow_succ'] + induction n with + | zero => rfl + | succ n ih => + rw [pow_succ'] exact (congr_arg f.toEnd ih).trans (f.map_mul_left' _ _) map_mul_right' := fun a b ↦ by - induction' n with n ih - · exact rfl - · rw [pow_succ'] - exact (congr_arg f.toEnd ih).trans (f.map_mul_right' _ _) - }⟩ + induction n with + | zero => rfl + | succ n ih => + rw [pow_succ'] + exact (congr_arg f.toEnd ih).trans (f.map_mul_right' _ _)}⟩ @[simp, norm_cast] theorem coe_zero : ⇑(0 : CentroidHom α) = 0 := @@ -474,8 +475,9 @@ def centerToCentroidCenter : simp only [ZeroMemClass.coe_zero, map_zero] exact rfl map_add' := fun _ _ => by - simp only [AddSubmonoid.coe_add, NonUnitalSubsemiring.coe_toAddSubmonoid, map_add] - exact rfl + dsimp + simp only [map_add] + rfl map_mul' z₁ z₂ := by ext a; exact (z₁.prop.left_assoc z₂ a).symm instance : FunLike (Subsemiring.center (CentroidHom α)) α α where diff --git a/Mathlib/Algebra/Ring/Commute.lean b/Mathlib/Algebra/Ring/Commute.lean index 6793e2df1e30d..27887a07dc5bb 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,7 +75,7 @@ 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] @@ -147,7 +147,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 4a9a7a943c8b9..e6fce8299f6a4 100644 --- a/Mathlib/Algebra/Ring/CompTypeclasses.lean +++ b/Mathlib/Algebra/Ring/CompTypeclasses.lean @@ -122,7 +122,7 @@ theorem of_ringEquiv (e : R₁ ≃+* R₂) : RingHomInvPair (↑e : R₁ →+* R /-- Swap the direction of a `RingHomInvPair`. This is not an instance as it would loop, and better -instances are often available and may often be preferrable to using this one. Indeed, this +instances are often available and may often be preferable to using this one. Indeed, this declaration is not currently used in mathlib. -/ theorem symm (σ₁₂ : R₁ →+* R₂) (σ₂₁ : R₂ →+* R₁) [RingHomInvPair σ₁₂ σ₂₁] : diff --git a/Mathlib/Algebra/Ring/Defs.lean b/Mathlib/Algebra/Ring/Defs.lean index 18b144825141a..8ff6a13b2f8f9 100644 --- a/Mathlib/Algebra/Ring/Defs.lean +++ b/Mathlib/Algebra/Ring/Defs.lean @@ -24,6 +24,9 @@ the present file is about their interaction. addition, for example `Units`. * `(NonUnital)(NonAssoc)(Semi)Ring`: Typeclasses for possibly non-unital or non-associative rings and semirings. Some combinations are not defined yet because they haven't found use. + For Lie Rings, there is a type synonym `CommutatorRing` defined in + `Mathlib/Algebra/Algebra/NonUnitalHom.lean` turning the bracket into a multiplication so that the + instance `instNonUnitalNonAssocSemiringCommutatorRing` can be defined. ## Tags @@ -42,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 @@ -109,7 +112,9 @@ that `Semiring -> NonAssocSemiring` is tried before `NonAssocRing -> NonAssocSem TODO: clean this once lean4#2115 is fixed -/ -/-- A not-necessarily-unital, not-necessarily-associative semiring. -/ +/-- A not-necessarily-unital, not-necessarily-associative semiring. See `CommutatorRing` and the + documentation thereof in case you need a `NonUnitalNonAssocSemiring` instance on a Lie ring + or a Lie algebra. -/ class NonUnitalNonAssocSemiring (α : Type u) extends AddCommMonoid α, Distrib α, MulZeroClass α /-- An associative but not-necessarily unital semiring. -/ @@ -245,7 +250,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] @@ -366,7 +371,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/Equiv.lean b/Mathlib/Algebra/Ring/Equiv.lean index f08987f2fa38f..51c833ecb1d78 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,37 +239,23 @@ 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 @[simp] -theorem symm_symm (e : R ≃+* S) : e.symm.symm = e := - ext fun _ => 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_symm (e : R ≃+* S) : e.symm.symm = e := rfl theorem symm_bijective : Function.Bijective (RingEquiv.symm : (R ≃+* S) → S ≃+* R) := Function.bijective_iff_has_inverse.mpr ⟨_, symm_symm, symm_symm⟩ @@ -265,7 +265,7 @@ theorem mk_coe' (e : R ≃+* S) (f h₁ h₂ h₃ h₄) : (⟨⟨f, ⇑e, h₁, h₂⟩, h₃, h₄⟩ : S ≃+* R) = e.symm := symm_bijective.injective <| ext fun _ => rfl -/-- Auxilliary definition to avoid looping in `dsimp` with `RingEquiv.symm_mk`. -/ +/-- Auxiliary definition to avoid looping in `dsimp` with `RingEquiv.symm_mk`. -/ protected def symm_mk.aux (f : R → S) (g h₁ h₂ h₃ h₄) := (mk ⟨f, g, h₁, h₂⟩ h₃ h₄).symm @[simp] @@ -276,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 @@ -316,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₂ := @@ -326,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 @@ -380,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 := @@ -504,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 := @@ -575,7 +603,7 @@ 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 theorem map_neg_one : f (-1) = -1 := @@ -776,9 +804,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 @@ -815,6 +840,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/Defs.lean b/Mathlib/Algebra/Ring/Hom/Defs.lean index 8b6d0d07f6d18..86672a2bb1c98 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 : α →ₙ+* β) : @@ -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 @@ -598,8 +596,8 @@ instance instMonoid : Monoid (α →+* α) where mul_one := comp_id one_mul := id_comp mul_assoc f g h := 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 n f := (npowRec n f).copy f^[n] <| by induction n <;> simp [npowRec, *] + npow_succ n f := DFunLike.coe_injective <| Function.iterate_succ _ _ @[simp, norm_cast] lemma coe_pow (f : α →+* α) (n : ℕ) : ⇑(f ^ n) = f^[n] := rfl 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 f299cce6dcf91..8fb0dd29430dc 100644 --- a/Mathlib/Algebra/Ring/Int.lean +++ b/Mathlib/Algebra/Ring/Int.lean @@ -97,66 +97,68 @@ 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] + +@[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] -@[simp] lemma odd_iff_not_even : Odd n ↔ ¬Even n := by rw [not_even_iff, odd_iff] +@[deprecated not_even_iff_odd (since := "2024-08-21")] +lemma odd_iff_not_even : Odd n ↔ ¬Even n := by rw [not_even_iff, odd_iff] -lemma even_or_odd (n : ℤ) : Even n ∨ Odd n := Or.imp_right odd_iff_not_even.2 <| em <| Even n +lemma even_or_odd (n : ℤ) : Even n ∨ Odd n := Or.imp_right not_even_iff_odd.1 <| em <| Even n lemma even_or_odd' (n : ℤ) : ∃ k, n = 2 * k ∨ n = 2 * k + 1 := by simpa only [two_mul, exists_or, Odd, Even] using even_or_odd n lemma even_xor'_odd (n : ℤ) : Xor' (Even n) (Odd n) := by cases even_or_odd n with - | inl h => exact Or.inl ⟨h, even_iff_not_odd.mp h⟩ - | inr h => exact Or.inr ⟨h, odd_iff_not_even.mp h⟩ + | inl h => exact Or.inl ⟨h, not_odd_iff_even.2 h⟩ + | inr h => exact Or.inr ⟨h, not_even_iff_odd.2 h⟩ 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 _ odd_iff_not_even.symm +instance : DecidablePred (Odd : ℤ → Prop) := fun _ => decidable_of_iff _ not_even_iff_odd lemma even_add' : Even (m + n) ↔ (Odd m ↔ Odd n) := by - rw [even_add, even_iff_not_odd, even_iff_not_odd, not_iff_not] - -set_option linter.deprecated false in - -@[simp, deprecated (since := "2023-01-26")] -lemma not_even_bit1 (n : ℤ) : ¬Even (2 * n + 1) := by simp [parity_simps] + rw [even_add, ← not_odd_iff_even, ← not_odd_iff_even, not_iff_not] lemma not_even_two_mul_add_one (n : ℤ) : ¬ Even (2 * n + 1) := - odd_iff_not_even.1 <| odd_two_mul_add_one n + not_even_iff_odd.2 <| odd_two_mul_add_one n lemma even_sub' : Even (m - n) ↔ (Odd m ↔ Odd n) := by - rw [even_sub, even_iff_not_odd, even_iff_not_odd, not_iff_not] + rw [even_sub, ← not_odd_iff_even, ← not_odd_iff_even, not_iff_not] -lemma odd_mul : Odd (m * n) ↔ Odd m ∧ Odd n := by simp [not_or, parity_simps] +lemma odd_mul : Odd (m * n) ↔ Odd m ∧ Odd n := by simp [← not_even_iff_odd, not_or, parity_simps] lemma Odd.of_mul_left (h : Odd (m * n)) : Odd m := (odd_mul.mp h).1 lemma Odd.of_mul_right (h : Odd (m * n)) : Odd n := (odd_mul.mp h).2 @[parity_simps] lemma odd_pow {n : ℕ} : Odd (m ^ n) ↔ Odd m ∨ n = 0 := by - rw [← not_iff_not, ← even_iff_not_odd, not_or, ← even_iff_not_odd, even_pow] + rw [← not_iff_not, not_odd_iff_even, not_or, not_odd_iff_even, even_pow] lemma odd_pow' {n : ℕ} (h : n ≠ 0) : Odd (m ^ n) ↔ Odd m := odd_pow.trans <| or_iff_left h @[parity_simps] lemma odd_add : Odd (m + n) ↔ (Odd m ↔ Even n) := by - rw [odd_iff_not_even, even_add, not_iff, odd_iff_not_even] + rw [← not_even_iff_odd, even_add, not_iff, ← not_even_iff_odd] lemma odd_add' : Odd (m + n) ↔ (Odd n ↔ Even m) := by rw [add_comm, odd_add] -lemma ne_of_odd_add (h : Odd (m + n)) : m ≠ n := fun hnot ↦ by simp [hnot, parity_simps] at h +lemma ne_of_odd_add (h : Odd (m + n)) : m ≠ n := by rintro rfl; simp [← not_even_iff_odd] at h @[parity_simps] lemma odd_sub : Odd (m - n) ↔ (Odd m ↔ Even n) := by - rw [odd_iff_not_even, even_sub, not_iff, odd_iff_not_even] + rw [← not_even_iff_odd, even_sub, not_iff, ← not_even_iff_odd] lemma odd_sub' : Odd (m - n) ↔ (Odd n ↔ Even m) := by - rw [odd_iff_not_even, even_sub, not_iff, not_iff_comm, odd_iff_not_even] + rw [← not_even_iff_odd, even_sub, not_iff, not_iff_comm, ← not_even_iff_odd] lemma even_mul_succ_self (n : ℤ) : Even (n * (n + 1)) := by simpa [even_mul, parity_simps] using n.even_or_odd @@ -166,7 +168,7 @@ lemma even_mul_pred_self (n : ℤ) : Even (n * (n - 1)) := by -- Porting note (#10618): was simp. simp can prove this. @[norm_cast] lemma odd_coe_nat (n : ℕ) : Odd (n : ℤ) ↔ Odd n := by - rw [odd_iff_not_even, Nat.odd_iff_not_even, even_coe_nat] + 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] @@ -174,7 +176,7 @@ lemma even_mul_pred_self (n : ℤ) : Even (n * (n - 1)) := by -- Porting note (#10618): was simp. simp can prove this. --@[simp] lemma natAbs_odd : Odd n.natAbs ↔ Odd n := by - rw [odd_iff_not_even, Nat.odd_iff_not_even, natAbs_even] + rw [← not_even_iff_odd, ← Nat.not_even_iff_odd, natAbs_even] alias ⟨_, _root_.Even.natAbs⟩ := natAbs_even diff --git a/Mathlib/Algebra/Ring/Invertible.lean b/Mathlib/Algebra/Ring/Invertible.lean index a976fefc4ff53..67c2be22dc0da 100644 --- a/Mathlib/Algebra/Ring/Invertible.lean +++ b/Mathlib/Algebra/Ring/Invertible.lean @@ -33,7 +33,7 @@ theorem invOf_two_add_invOf_two [NonAssocSemiring α] [Invertible (2 : α)] : (⅟ 2 : α) + (⅟ 2 : α) = 1 := by rw [← two_mul, mul_invOf_self] theorem pos_of_invertible_cast [Semiring α] [Nontrivial α] (n : ℕ) [Invertible (n : α)] : 0 < n := - Nat.zero_lt_of_ne_zero fun h => nonzero_of_invertible (n : α) (h ▸ Nat.cast_zero) + Nat.zero_lt_of_ne_zero fun h => Invertible.ne_zero (n : α) (h ▸ Nat.cast_zero) theorem invOf_add_invOf [Semiring α] (a b : α) [Invertible a] [Invertible b] : ⅟a + ⅟b = ⅟a * (a + b) * ⅟b := by diff --git a/Mathlib/Algebra/Ring/NegOnePow.lean b/Mathlib/Algebra/Ring/NegOnePow.lean index 0ad5c85f38899..6696881dcbf2e 100644 --- a/Mathlib/Algebra/Ring/NegOnePow.lean +++ b/Mathlib/Algebra/Ring/NegOnePow.lean @@ -55,7 +55,7 @@ lemma negOnePow_two_mul_add_one (n : ℤ) : (2 * n + 1).negOnePow = -1 := lemma negOnePow_eq_one_iff (n : ℤ) : n.negOnePow = 1 ↔ Even n := by constructor · intro h - rw [Int.even_iff_not_odd] + rw [← Int.not_odd_iff_even] intro h' simp only [negOnePow_odd _ h'] at h contradiction @@ -64,7 +64,7 @@ lemma negOnePow_eq_one_iff (n : ℤ) : n.negOnePow = 1 ↔ Even n := by lemma negOnePow_eq_neg_one_iff (n : ℤ) : n.negOnePow = -1 ↔ Odd n := by constructor · intro h - rw [Int.odd_iff_not_even] + rw [← Int.not_even_iff_odd] intro h' rw [negOnePow_even _ h'] at h contradiction @@ -92,9 +92,9 @@ lemma negOnePow_eq_iff (n₁ n₂ : ℤ) : by_cases h₂ : Even n₂ · rw [negOnePow_even _ h₂, Int.even_sub, negOnePow_eq_one_iff] tauto - · rw [← Int.odd_iff_not_even] at h₂ + · rw [Int.not_even_iff_odd] at h₂ rw [negOnePow_odd _ h₂, Int.even_sub, negOnePow_eq_neg_one_iff, - Int.even_iff_not_odd, Int.even_iff_not_odd] + ← Int.not_odd_iff_even, ← Int.not_odd_iff_even] tauto @[simp] diff --git a/Mathlib/Algebra/Ring/Parity.lean b/Mathlib/Algebra/Ring/Parity.lean index 3efcda0789876..9205b9aeff65a 100644 --- a/Mathlib/Algebra/Ring/Parity.lean +++ b/Mathlib/Algebra/Ring/Parity.lean @@ -5,7 +5,7 @@ Authors: Damiano Testa -/ import Mathlib.Data.Nat.Cast.Basic import Mathlib.Data.Nat.Cast.Commute -import Mathlib.Data.Set.Defs +import Mathlib.Data.Set.Operations import Mathlib.Logic.Function.Iterate /-! @@ -143,7 +143,7 @@ lemma Odd.pow_add_pow_eq_zero [IsCancelAdd α] (hn : Odd n) (hab : a + b = 0) : obtain ⟨k, rfl⟩ := hn induction' k with k ih · simpa - have : a ^ 2 = b ^ 2 := add_right_cancel $ + have : a ^ 2 = b ^ 2 := add_right_cancel <| calc a ^ 2 + a * b = 0 := by rw [sq, ← mul_add, hab, mul_zero] _ = b ^ 2 + a * b := by rw [sq, ← add_mul, add_comm, hab, zero_mul] @@ -211,15 +211,22 @@ instance : DecidablePred (Odd : ℕ → Prop) := fun _ ↦ decidable_of_iff _ od 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] -@[simp] lemma odd_iff_not_even : Odd n ↔ ¬Even n := by rw [not_even_iff, odd_iff] +@[deprecated not_even_iff_odd (since := "2024-08-21")] +lemma odd_iff_not_even : Odd n ↔ ¬Even n := by rw [not_even_iff, odd_iff] lemma _root_.Odd.not_two_dvd_nat (h : Odd n) : ¬(2 ∣ n) := by - rwa [← even_iff_two_dvd, ← odd_iff_not_even] + rwa [← even_iff_two_dvd, not_even_iff_odd] lemma even_xor_odd (n : ℕ) : Xor' (Even n) (Odd n) := by - simp [Xor', odd_iff_not_even, Decidable.em (Even n)] + simp [Xor', ← not_even_iff_odd, Decidable.em (Even n)] lemma even_or_odd (n : ℕ) : Even n ∨ Odd n := (even_xor_odd n).or @@ -242,16 +249,16 @@ lemma mod_two_add_add_odd_mod_two (m : ℕ) {n : ℕ} (hn : Odd n) : m % 2 + (m rw [add_comm, mod_two_add_succ_mod_two] lemma even_add' : Even (m + n) ↔ (Odd m ↔ Odd n) := by - rw [even_add, even_iff_not_odd, even_iff_not_odd, not_iff_not] + rw [even_add, ← not_odd_iff_even, ← not_odd_iff_even, not_iff_not] set_option linter.deprecated false in @[simp] lemma not_even_bit1 (n : ℕ) : ¬Even (2 * n + 1) := by simp [parity_simps] lemma not_even_two_mul_add_one (n : ℕ) : ¬ Even (2 * n + 1) := - odd_iff_not_even.1 <| odd_two_mul_add_one n + not_even_iff_odd.2 <| odd_two_mul_add_one n lemma even_sub' (h : n ≤ m) : Even (m - n) ↔ (Odd m ↔ Odd n) := by - rw [even_sub h, even_iff_not_odd, even_iff_not_odd, not_iff_not] + rw [even_sub h, ← not_odd_iff_even, ← not_odd_iff_even, not_iff_not] lemma Odd.sub_odd (hm : Odd m) (hn : Odd n) : Even (m - n) := (le_total n m).elim (fun h ↦ by simp only [even_sub' h, *]) fun h ↦ by @@ -259,7 +266,7 @@ lemma Odd.sub_odd (hm : Odd m) (hn : Odd n) : Even (m - n) := alias _root_.Odd.tsub_odd := Nat.Odd.sub_odd -lemma odd_mul : Odd (m * n) ↔ Odd m ∧ Odd n := by simp [not_or, even_mul] +lemma odd_mul : Odd (m * n) ↔ Odd m ∧ Odd n := by simp [not_or, even_mul, ← not_even_iff_odd] lemma Odd.of_mul_left (h : Odd (m * n)) : Odd m := (odd_mul.mp h).1 @@ -271,20 +278,20 @@ lemma even_div : Even (m / n) ↔ m % (2 * n) / n = 0 := by rw [even_iff_two_dvd, dvd_iff_mod_eq_zero, ← Nat.mod_mul_right_div_self, mul_comm] @[parity_simps] lemma odd_add : Odd (m + n) ↔ (Odd m ↔ Even n) := by - rw [odd_iff_not_even, even_add, not_iff, odd_iff_not_even] + rw [← not_even_iff_odd, even_add, not_iff, ← not_even_iff_odd] lemma odd_add' : Odd (m + n) ↔ (Odd n ↔ Even m) := by rw [add_comm, odd_add] -lemma ne_of_odd_add (h : Odd (m + n)) : m ≠ n := fun hnot ↦ by simp [hnot] at h +lemma ne_of_odd_add (h : Odd (m + n)) : m ≠ n := by rintro rfl; simp [← not_even_iff_odd] at h @[parity_simps] lemma odd_sub (h : n ≤ m) : Odd (m - n) ↔ (Odd m ↔ Even n) := by - rw [odd_iff_not_even, even_sub h, not_iff, odd_iff_not_even] + rw [← not_even_iff_odd, even_sub h, not_iff, ← not_even_iff_odd] lemma Odd.sub_even (h : n ≤ m) (hm : Odd m) (hn : Even n) : Odd (m - n) := (odd_sub h).mpr <| iff_of_true hm hn lemma odd_sub' (h : n ≤ m) : Odd (m - n) ↔ (Odd n ↔ Even m) := by - rw [odd_iff_not_even, even_sub h, not_iff, not_iff_comm, odd_iff_not_even] + rw [← not_even_iff_odd, even_sub h, not_iff, not_iff_comm, ← not_even_iff_odd] lemma Even.sub_odd (h : n ≤ m) (hm : Even m) (hn : Odd n) : Odd (m - n) := (odd_sub' h).mpr <| iff_of_true hn hm @@ -319,7 +326,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 @@ -342,16 +348,16 @@ lemma iterate_odd (hf : Involutive f) (hn : Odd n) : f^[n] = f := by rw [iterate_add, hf.iterate_two_mul, id_comp, iterate_one] lemma iterate_eq_self (hf : Involutive f) (hne : f ≠ id) : f^[n] = f ↔ Odd n := - ⟨fun H ↦ odd_iff_not_even.2 fun hn ↦ hne <| by rwa [hf.iterate_even hn, eq_comm] at H, + ⟨fun H ↦ not_even_iff_odd.1 fun hn ↦ hne <| by rwa [hf.iterate_even hn, eq_comm] at H, hf.iterate_odd⟩ lemma iterate_eq_id (hf : Involutive f) (hne : f ≠ id) : f^[n] = id ↔ Even n := - ⟨fun H ↦ even_iff_not_odd.2 fun hn ↦ hne <| by rwa [hf.iterate_odd hn] at H, hf.iterate_even⟩ + ⟨fun H ↦ not_odd_iff_even.1 fun hn ↦ hne <| by rwa [hf.iterate_odd hn] at H, hf.iterate_even⟩ end Involutive end Function 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 <| (Odd.neg_one_pow <| odd_iff_not_even.mpr hn).symm.trans h' + 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 diff --git a/Mathlib/Algebra/Ring/Pointwise/Set.lean b/Mathlib/Algebra/Ring/Pointwise/Set.lean new file mode 100644 index 0000000000000..5ec371a33579c --- /dev/null +++ b/Mathlib/Algebra/Ring/Pointwise/Set.lean @@ -0,0 +1,49 @@ +/- +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.Basic +import Mathlib.Algebra.Ring.Defs + +/-! +# 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 +-/ + +assert_not_exists OrderedAddCommMonoid + +open Function +open scoped Pointwise + +variable {F α β γ : Type*} + +namespace Set + +/-- `Set α` has distributive negation if `α` has. -/ +protected noncomputable def hasDistribNeg [Mul α] [HasDistribNeg α] : HasDistribNeg (Set α) where + __ := Set.involutiveNeg + 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.hasDistribNeg + +section Distrib +variable [Distrib α] (s t u : Set α) + +/-! +Note that `Set α` is not a `Distrib` because `s * t + s * u` has cross terms that `s * (t + u)` +lacks. +-/ + +lemma mul_add_subset : s * (t + u) ⊆ s * t + s * u := image2_distrib_subset_left mul_add +lemma add_mul_subset : (s + t) * u ⊆ s * u + t * u := image2_distrib_subset_right add_mul + +end Distrib +end Set 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/Semireal/Defs.lean b/Mathlib/Algebra/Ring/Semireal/Defs.lean index 7e26be34cfffb..7b16914e15ab1 100644 --- a/Mathlib/Algebra/Ring/Semireal/Defs.lean +++ b/Mathlib/Algebra/Ring/Semireal/Defs.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Florent Schaffhauser -/ import Mathlib.Algebra.Ring.SumsOfSquares -import Mathlib.Algebra.Order.Field.Defs /-! # Semireal rings @@ -42,6 +41,6 @@ class IsSemireal [AddMonoid R] [Mul R] [One R] [Neg R] : Prop where @[deprecated (since := "2024-08-09")] alias isSemireal.neg_one_not_SumSq := IsSemireal.not_isSumSq_neg_one -instance [LinearOrderedField R] : IsSemireal R where +instance [LinearOrderedRing R] : IsSemireal R where non_trivial := zero_ne_one not_isSumSq_neg_one := fun h ↦ (not_le (α := R)).2 neg_one_lt_zero h.nonneg diff --git a/Mathlib/Algebra/Ring/Subring/Basic.lean b/Mathlib/Algebra/Ring/Subring/Basic.lean index 365272a227add..4d2d0317d2fcf 100644 --- a/Mathlib/Algebra/Ring/Subring/Basic.lean +++ b/Mathlib/Algebra/Ring/Subring/Basic.lean @@ -72,7 +72,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] @@ -433,6 +433,9 @@ theorem coe_top : ((⊤ : Subring R) : Set R) = Set.univ := def topEquiv : (⊤ : Subring R) ≃+* R := Subsemiring.topEquiv +instance {R : Type*} [Ring R] [Fintype R] : Fintype (⊤ : Subring R) := + inferInstanceAs (Fintype (⊤ : Set R)) + theorem card_top (R) [Ring R] [Fintype R] : Fintype.card (⊤ : Subring R) = Fintype.card R := Fintype.card_congr topEquiv.toEquiv @@ -819,7 +822,7 @@ theorem mem_closure_iff {s : Set R} {x} : mul_mem hx hy) (zero_mem _) (fun x y hx hy => add_mem hx hy) fun x hx => neg_mem hx⟩ -/-- If all elements of `s : Set A` commute pairwise, then `closure s` is a commutative ring. -/ +/-- 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 @@ -894,6 +897,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 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 0d8ca74d4eab5..3234c63eecfab 100644 --- a/Mathlib/Algebra/Ring/Subring/MulOpposite.lean +++ b/Mathlib/Algebra/Ring/Subring/MulOpposite.lean @@ -73,17 +73,34 @@ def opEquiv : Subring R ≃o Subring Rᵐᵒᵖ where right_inv := op_unop map_rel_iff' := op_le_op_iff +theorem op_injective : (@Subring.op R _).Injective := opEquiv.injective +theorem unop_injective : (@Subring.unop R _).Injective := opEquiv.symm.injective +@[simp] theorem op_inj {S T : Subring R} : S.op = T.op ↔ S = T := opEquiv.eq_iff_eq +@[simp] theorem unop_inj {S T : Subring Rᵐᵒᵖ} : S.unop = T.unop ↔ S = T := opEquiv.symm.eq_iff_eq + @[simp] theorem op_bot : (⊥ : Subring R).op = ⊥ := opEquiv.map_bot +@[simp] +theorem op_eq_bot {S : Subring R} : S.op = ⊥ ↔ S = ⊥ := op_injective.eq_iff' op_bot + @[simp] theorem unop_bot : (⊥ : Subring Rᵐᵒᵖ).unop = ⊥ := opEquiv.symm.map_bot @[simp] -theorem op_top : (⊤ : Subring R).op = ⊤ := opEquiv.map_top +theorem unop_eq_bot {S : Subring Rᵐᵒᵖ} : S.unop = ⊥ ↔ S = ⊥ := unop_injective.eq_iff' unop_bot + +@[simp] +theorem op_top : (⊤ : Subring R).op = ⊤ := rfl @[simp] -theorem unop_top : (⊤ : Subring Rᵐᵒᵖ).unop = ⊤ := opEquiv.symm.map_top +theorem op_eq_top {S : Subring R} : S.op = ⊤ ↔ S = ⊤ := op_injective.eq_iff' op_top + +@[simp] +theorem unop_top : (⊤ : Subring Rᵐᵒᵖ).unop = ⊤ := rfl + +@[simp] +theorem unop_eq_top {S : Subring Rᵐᵒᵖ} : S.unop = ⊤ ↔ S = ⊤ := unop_injective.eq_iff' unop_top theorem op_sup (S₁ S₂ : Subring R) : (S₁ ⊔ S₂).op = S₁.op ⊔ S₂.op := opEquiv.map_sup _ _ @@ -91,10 +108,9 @@ theorem op_sup (S₁ S₂ : Subring R) : (S₁ ⊔ S₂).op = S₁.op ⊔ S₂.o theorem unop_sup (S₁ S₂ : Subring Rᵐᵒᵖ) : (S₁ ⊔ S₂).unop = S₁.unop ⊔ S₂.unop := opEquiv.symm.map_sup _ _ -theorem op_inf (S₁ S₂ : Subring R) : (S₁ ⊓ S₂).op = S₁.op ⊓ S₂.op := opEquiv.map_inf _ _ +theorem op_inf (S₁ S₂ : Subring R) : (S₁ ⊓ S₂).op = S₁.op ⊓ S₂.op := rfl -theorem unop_inf (S₁ S₂ : Subring Rᵐᵒᵖ) : (S₁ ⊓ S₂).unop = S₁.unop ⊓ S₂.unop := - opEquiv.symm.map_inf _ _ +theorem unop_inf (S₁ S₂ : Subring Rᵐᵒᵖ) : (S₁ ⊓ S₂).unop = S₁.unop ⊓ S₂.unop := rfl theorem op_sSup (S : Set (Subring R)) : (sSup S).op = sSup (.unop ⁻¹' S) := opEquiv.map_sSup_eq_sSup_symm_preimage _ @@ -124,9 +140,8 @@ theorem op_closure (s : Set R) : (closure s).op = closure (MulOpposite.unop ⁻ exact MulOpposite.unop_surjective.forall theorem unop_closure (s : Set Rᵐᵒᵖ) : (closure s).unop = closure (MulOpposite.op ⁻¹' s) := by - simp_rw [closure, unop_sInf, Set.preimage_setOf_eq, op_coe] - congr with a - exact MulOpposite.op_surjective.forall + rw [← op_inj, op_unop, op_closure] + 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/Pointwise.lean b/Mathlib/Algebra/Ring/Subring/Pointwise.lean index 8dd52f6efdb1b..b472910f34900 100644 --- a/Mathlib/Algebra/Ring/Subring/Pointwise.lean +++ b/Mathlib/Algebra/Ring/Subring/Pointwise.lean @@ -6,7 +6,6 @@ Authors: Eric Wieser import Mathlib.Algebra.Group.Subgroup.Pointwise import Mathlib.Algebra.Ring.Subring.Basic import Mathlib.Algebra.Ring.Subsemiring.Pointwise -import Mathlib.Data.Set.Pointwise.Basic /-! # Pointwise instances on `Subring`s diff --git a/Mathlib/Algebra/Ring/Subring/Units.lean b/Mathlib/Algebra/Ring/Subring/Units.lean index 76b3f05824db9..157cdab1d1c19 100644 --- a/Mathlib/Algebra/Ring/Subring/Units.lean +++ b/Mathlib/Algebra/Ring/Subring/Units.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Birkbeck -/ import Mathlib.Algebra.Group.Subgroup.Basic -import Mathlib.Algebra.Order.Monoid.Submonoid +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 545f71d03475b..3fd3c93c9cef4 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,12 +59,12 @@ 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 } @@ -102,9 +102,9 @@ instance (priority := 75) toSemiring {R} [Semiring R] [SetLike S R] [Subsemiring @[simp, norm_cast] theorem coe_pow {R} [Semiring R] [SetLike S R] [SubsemiringClass S R] (x : s) (n : ℕ) : ((x ^ n : s) : R) = (x : R) ^ n := by - induction' n with n ih - · simp - · simp [pow_succ, ih] + induction n with + | zero => simp + | succ n ih => simp [pow_succ, ih] /-- A subsemiring of a `CommSemiring` is a `CommSemiring`. -/ instance toCommSemiring {R} [CommSemiring R] [SetLike S R] [SubsemiringClass S R] : @@ -314,9 +314,9 @@ instance toSemiring {R} [Semiring R] (s : Subsemiring R) : Semiring s := @[simp, norm_cast] theorem coe_pow {R} [Semiring R] (s : Subsemiring R) (x : s) (n : ℕ) : ((x ^ n : s) : R) = (x : R) ^ n := by - induction' n with n ih - · simp - · simp [pow_succ, ih] + induction n with + | zero => simp + | succ n ih => simp [pow_succ, ih] /-- A subsemiring of a `CommSemiring` is a `CommSemiring`. -/ instance toCommSemiring {R} [CommSemiring R] (s : Subsemiring R) : CommSemiring s := @@ -500,6 +500,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 := @@ -784,7 +791,7 @@ theorem mem_closure_iff_exists_list {R} [Semiring R] {s : Set R} {x} : ⟨[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⟩) + (fun x hx => ⟨[x], List.forall_mem_singleton.2 hx, List.prod_singleton⟩) ⟨[], List.forall_mem_nil _, rfl⟩ fun x y ⟨t, ht1, ht2⟩ ⟨u, hu1, hu2⟩ => ⟨t ++ u, List.forall_mem_append.2 ⟨ht1, hu1⟩, by rw [List.prod_append, ht2, hu2]⟩) ⟨[], List.forall_mem_nil _, rfl⟩ fun x y ⟨L, HL1, HL2⟩ ⟨M, HM1, HM2⟩ => @@ -835,6 +842,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 diff --git a/Mathlib/Algebra/Ring/Subsemiring/MulOpposite.lean b/Mathlib/Algebra/Ring/Subsemiring/MulOpposite.lean index d6a315451f032..f709792084761 100644 --- a/Mathlib/Algebra/Ring/Subsemiring/MulOpposite.lean +++ b/Mathlib/Algebra/Ring/Subsemiring/MulOpposite.lean @@ -76,17 +76,37 @@ def opEquiv : Subsemiring R ≃o Subsemiring Rᵐᵒᵖ where right_inv := op_unop map_rel_iff' := op_le_op_iff +theorem op_injective : (@Subsemiring.op R _).Injective := opEquiv.injective +theorem unop_injective : (@Subsemiring.unop R _).Injective := opEquiv.symm.injective + +@[simp] theorem op_inj {S T : Subsemiring R} : S.op = T.op ↔ S = T := opEquiv.eq_iff_eq + +@[simp] +theorem unop_inj {S T : Subsemiring Rᵐᵒᵖ} : S.unop = T.unop ↔ S = T := opEquiv.symm.eq_iff_eq + @[simp] theorem op_bot : (⊥ : Subsemiring R).op = ⊥ := opEquiv.map_bot +@[simp] +theorem op_eq_bot {S : Subsemiring R} : S.op = ⊥ ↔ S = ⊥ := op_injective.eq_iff' op_bot + @[simp] theorem unop_bot : (⊥ : Subsemiring Rᵐᵒᵖ).unop = ⊥ := opEquiv.symm.map_bot @[simp] -theorem op_top : (⊤ : Subsemiring R).op = ⊤ := opEquiv.map_top +theorem unop_eq_bot {S : Subsemiring Rᵐᵒᵖ} : S.unop = ⊥ ↔ S = ⊥ := unop_injective.eq_iff' unop_bot @[simp] -theorem unop_top : (⊤ : Subsemiring Rᵐᵒᵖ).unop = ⊤ := opEquiv.symm.map_top +theorem op_top : (⊤ : Subsemiring R).op = ⊤ := rfl + +@[simp] +theorem op_eq_top {S : Subsemiring R} : S.op = ⊤ ↔ S = ⊤ := op_injective.eq_iff' op_top + +@[simp] +theorem unop_top : (⊤ : Subsemiring Rᵐᵒᵖ).unop = ⊤ := rfl + +@[simp] +theorem unop_eq_top {S : Subsemiring Rᵐᵒᵖ} : S.unop = ⊤ ↔ S = ⊤ := unop_injective.eq_iff' unop_top theorem op_sup (S₁ S₂ : Subsemiring R) : (S₁ ⊔ S₂).op = S₁.op ⊔ S₂.op := opEquiv.map_sup _ _ @@ -94,10 +114,9 @@ theorem op_sup (S₁ S₂ : Subsemiring R) : (S₁ ⊔ S₂).op = S₁.op ⊔ S theorem unop_sup (S₁ S₂ : Subsemiring Rᵐᵒᵖ) : (S₁ ⊔ S₂).unop = S₁.unop ⊔ S₂.unop := opEquiv.symm.map_sup _ _ -theorem op_inf (S₁ S₂ : Subsemiring R) : (S₁ ⊓ S₂).op = S₁.op ⊓ S₂.op := opEquiv.map_inf _ _ +theorem op_inf (S₁ S₂ : Subsemiring R) : (S₁ ⊓ S₂).op = S₁.op ⊓ S₂.op := rfl -theorem unop_inf (S₁ S₂ : Subsemiring Rᵐᵒᵖ) : (S₁ ⊓ S₂).unop = S₁.unop ⊓ S₂.unop := - opEquiv.symm.map_inf _ _ +theorem unop_inf (S₁ S₂ : Subsemiring Rᵐᵒᵖ) : (S₁ ⊓ S₂).unop = S₁.unop ⊓ S₂.unop := rfl theorem op_sSup (S : Set (Subsemiring R)) : (sSup S).op = sSup (.unop ⁻¹' S) := opEquiv.map_sSup_eq_sSup_symm_preimage _ @@ -127,9 +146,8 @@ theorem op_closure (s : Set R) : (closure s).op = closure (MulOpposite.unop ⁻ exact MulOpposite.unop_surjective.forall theorem unop_closure (s : Set Rᵐᵒᵖ) : (closure s).unop = closure (MulOpposite.op ⁻¹' s) := by - simp_rw [closure, unop_sInf, Set.preimage_setOf_eq, op_coe] - congr with a - exact MulOpposite.op_surjective.forall + rw [← op_inj, op_unop, op_closure] + 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/Subsemiring/Pointwise.lean b/Mathlib/Algebra/Ring/Subsemiring/Pointwise.lean index 842883e8a4b0b..250d388ca8b0a 100644 --- a/Mathlib/Algebra/Ring/Subsemiring/Pointwise.lean +++ b/Mathlib/Algebra/Ring/Subsemiring/Pointwise.lean @@ -6,7 +6,6 @@ Authors: Eric Wieser import Mathlib.Algebra.Group.Submonoid.Pointwise import Mathlib.Algebra.Ring.Action.Basic import Mathlib.Algebra.Ring.Subsemiring.Basic -import Mathlib.Data.Set.Pointwise.Basic /-! # Pointwise instances on `Subsemiring`s 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/RingQuot.lean b/Mathlib/Algebra/RingQuot.lean index f0e0f3bcd667b..1da65c2031d8e 100644 --- a/Mathlib/Algebra/RingQuot.lean +++ b/Mathlib/Algebra/RingQuot.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.Hom import Mathlib.RingTheory.Ideal.Quotient @@ -75,42 +75,42 @@ theorem Rel.smul {r : A → A → Prop} (k : S) ⦃a b : A⦄ (h : Rel r a b) : /-- `EqvGen (RingQuot.Rel r)` is a ring congruence. -/ def ringCon (r : R → R → Prop) : RingCon R where - r := EqvGen (Rel r) - iseqv := EqvGen.is_equivalence _ + r := Relation.EqvGen (Rel r) + iseqv := Relation.EqvGen.is_equivalence _ add' {a b c d} hab hcd := by induction hab generalizing c d with | rel _ _ hab => - refine (EqvGen.rel _ _ hab.add_left).trans _ _ _ ?_ + refine (Relation.EqvGen.rel _ _ hab.add_left).trans _ _ _ ?_ induction hcd with - | rel _ _ hcd => exact EqvGen.rel _ _ hcd.add_right - | refl => exact EqvGen.refl _ + | rel _ _ hcd => exact Relation.EqvGen.rel _ _ hcd.add_right + | refl => exact Relation.EqvGen.refl _ | symm _ _ _ h => exact h.symm _ _ | trans _ _ _ _ _ h h' => exact h.trans _ _ _ h' | refl => induction hcd with - | rel _ _ hcd => exact EqvGen.rel _ _ hcd.add_right - | refl => exact EqvGen.refl _ + | rel _ _ hcd => exact Relation.EqvGen.rel _ _ hcd.add_right + | refl => exact Relation.EqvGen.refl _ | symm _ _ _ h => exact h.symm _ _ | trans _ _ _ _ _ h h' => exact h.trans _ _ _ h' | symm x y _ hxy => exact (hxy hcd.symm).symm - | trans x y z _ _ h h' => exact (h hcd).trans _ _ _ (h' <| EqvGen.refl _) + | trans x y z _ _ h h' => exact (h hcd).trans _ _ _ (h' <| Relation.EqvGen.refl _) mul' {a b c d} hab hcd := by induction hab generalizing c d with | rel _ _ hab => - refine (EqvGen.rel _ _ hab.mul_left).trans _ _ _ ?_ + refine (Relation.EqvGen.rel _ _ hab.mul_left).trans _ _ _ ?_ induction hcd with - | rel _ _ hcd => exact EqvGen.rel _ _ hcd.mul_right - | refl => exact EqvGen.refl _ + | rel _ _ hcd => exact Relation.EqvGen.rel _ _ hcd.mul_right + | refl => exact Relation.EqvGen.refl _ | symm _ _ _ h => exact h.symm _ _ | trans _ _ _ _ _ h h' => exact h.trans _ _ _ h' | refl => induction hcd with - | rel _ _ hcd => exact EqvGen.rel _ _ hcd.mul_right - | refl => exact EqvGen.refl _ + | rel _ _ hcd => exact Relation.EqvGen.rel _ _ hcd.mul_right + | refl => exact Relation.EqvGen.refl _ | symm _ _ _ h => exact h.symm _ _ | trans _ _ _ _ _ h h' => exact h.trans _ _ _ h' | symm x y _ hxy => exact (hxy hcd.symm).symm - | trans x y z _ _ h h' => exact (h hcd).trans _ _ _ (h' <| EqvGen.refl _) + | trans x y z _ _ h h' => exact (h hcd).trans _ _ _ (h' <| Relation.EqvGen.refl _) -theorem eqvGen_rel_eq (r : R → R → Prop) : EqvGen (Rel r) = RingConGen.Rel r := by +theorem eqvGen_rel_eq (r : R → R → Prop) : Relation.EqvGen (Rel r) = RingConGen.Rel r := by ext x₁ x₂ constructor · intro h @@ -125,7 +125,7 @@ theorem eqvGen_rel_eq (r : R → R → Prop) : EqvGen (Rel r) = RingConGen.Rel r | trans => exact RingConGen.Rel.trans ‹_› ‹_› · intro h induction h with - | of => exact EqvGen.rel _ _ (Rel.of ‹_›) + | of => exact Relation.EqvGen.rel _ _ (Rel.of ‹_›) | refl => exact (RingQuot.ringCon r).refl _ | symm => exact (RingQuot.ringCon r).symm ‹_› | trans => exact (RingQuot.ringCon r).trans ‹_› ‹_› diff --git a/Mathlib/Algebra/SMulWithZero.lean b/Mathlib/Algebra/SMulWithZero.lean index 3ef4bb96b5b9f..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 } @@ -196,11 +196,6 @@ theorem smul_inv₀ [SMulCommClass α β β] [IsScalarTower α β β] (c : α) ( obtain rfl | hx := eq_or_ne x 0 · simp only [inv_zero, smul_zero] · refine inv_eq_of_mul_eq_one_left ?_ - rw [smul_mul_smul, inv_mul_cancel₀ hc, inv_mul_cancel₀ hx, one_smul] + 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..2ae3fd080cb05 100644 --- a/Mathlib/Algebra/Squarefree/Basic.lean +++ b/Mathlib/Algebra/Squarefree/Basic.lean @@ -153,7 +153,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 diff --git a/Mathlib/Algebra/Star/Basic.lean b/Mathlib/Algebra/Star/Basic.lean index c592e1abb4297..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 @@ -111,7 +111,7 @@ theorem star_eq_iff_star_eq [InvolutiveStar R] {r s : R} : star r = s ↔ star s /-- Typeclass for a trivial star operation. This is mostly meant for `ℝ`. -/ class TrivialStar (R : Type u) [Star R] : Prop where - /-- Condition that star is trivial-/ + /-- Condition that star is trivial -/ star_trivial : ∀ r : R, star r = r export TrivialStar (star_trivial) @@ -221,7 +221,7 @@ theorem star_id_of_comm {R : Type*} [CommSemiring R] {x : R} : star x = x := end /-- A `*`-additive monoid `R` is an additive monoid with an involutive `star` operation which -preserves addition. -/ +preserves addition. -/ class StarAddMonoid (R : Type u) [AddMonoid R] extends InvolutiveStar R where /-- `star` commutes with addition -/ star_add : ∀ r s : R, star (r + s) = star r + star s @@ -261,16 +261,16 @@ theorem star_sub [AddGroup R] [StarAddMonoid R] (r s : R) : star (r - s) = star (starAddEquiv : R ≃+ R).map_sub _ _ @[simp] -theorem star_nsmul [AddMonoid R] [StarAddMonoid R] (x : R) (n : ℕ) : star (n • x) = n • star x := +theorem star_nsmul [AddMonoid R] [StarAddMonoid R] (n : ℕ) (x : R) : star (n • x) = n • star x := (starAddEquiv : R ≃+ R).toAddMonoidHom.map_nsmul _ _ @[simp] -theorem star_zsmul [AddGroup R] [StarAddMonoid R] (x : R) (n : ℤ) : star (n • x) = n • star x := +theorem star_zsmul [AddGroup R] [StarAddMonoid R] (n : ℤ) (x : R) : star (n • x) = n • star x := (starAddEquiv : R ≃+ R).toAddMonoidHom.map_zsmul _ _ /-- A `*`-ring `R` is a non-unital, non-associative (semi)ring with an involutive `star` operation which is additive which makes `R` with its multiplicative structure into a `*`-multiplication -(i.e. `star (r * s) = star s * star r`). -/ +(i.e. `star (r * s) = star s * star r`). -/ class StarRing (R : Type u) [NonUnitalNonAssocSemiring R] extends StarMul R where /-- `star` commutes with addition -/ star_add : ∀ r s : R, star (r + s) = star r + star s @@ -415,13 +415,16 @@ attribute [simp] star_smul instance StarMul.toStarModule [CommMonoid R] [StarMul R] : StarModule R R := ⟨star_mul'⟩ -instance StarAddMonoid.toStarModuleNat {α} [AddCommMonoid α] [StarAddMonoid α] : StarModule ℕ α := - ⟨fun n a ↦ by rw [star_nsmul, star_trivial n]⟩ +instance StarAddMonoid.toStarModuleNat {α} [AddCommMonoid α] [StarAddMonoid α] : + StarModule ℕ α where star_smul := star_nsmul + +instance StarAddMonoid.toStarModuleInt {α} [AddCommGroup α] [StarAddMonoid α] : StarModule ℤ α where + star_smul := star_zsmul namespace RingHomInvPair /-- Instance needed to define star-linear maps over a commutative star ring -(ex: conjugate-linear maps when R = ℂ). -/ +(ex: conjugate-linear maps when R = ℂ). -/ instance [CommSemiring R] [StarRing R] : RingHomInvPair (starRingEnd R) (starRingEnd R) := ⟨RingHom.ext star_star, RingHom.ext star_star⟩ diff --git a/Mathlib/Algebra/Star/CHSH.lean b/Mathlib/Algebra/Star/CHSH.lean index 72b30f5ea9329..26fc0b59288bb 100644 --- a/Mathlib/Algebra/Star/CHSH.lean +++ b/Mathlib/Algebra/Star/CHSH.lean @@ -1,10 +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.Algebra.CharP.Invertible -import Mathlib.Algebra.Star.Order +import Mathlib.Algebra.Order.Star.Basic import Mathlib.Data.Real.Sqrt import Mathlib.Tactic.Polyrith diff --git a/Mathlib/Algebra/Star/Conjneg.lean b/Mathlib/Algebra/Star/Conjneg.lean new file mode 100644 index 0000000000000..9b9c3b54defe4 --- /dev/null +++ b/Mathlib/Algebra/Star/Conjneg.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.BigOperators.Pi +import Mathlib.Algebra.Group.Pointwise.Set.Basic +import Mathlib.Algebra.Star.Pi + +/-! +# Conjugation-negation operator + +This file defines the conjugation-negation operator, useful in Fourier analysis. + +The way this operator enters the picture is that the adjoint of convolution with a function `f` is +convolution with `conjneg f`. +-/ + +open Function +open scoped ComplexConjugate + +variable {ι G R : Type*} [AddGroup G] + +section CommSemiring +variable [CommSemiring R] [StarRing R] {f g : G → R} + +/-- Conjugation-negation. Sends `f` to `fun x ↦ conj (f (-x))`. -/ +def conjneg (f : G → R) : G → R := conj fun x ↦ f (-x) + +@[simp] lemma conjneg_apply (f : G → R) (x : G) : conjneg f x = conj (f (-x)) := rfl +@[simp] lemma conjneg_conjneg (f : G → R) : conjneg (conjneg f) = f := by ext; simp + +lemma conjneg_involutive : Involutive (conjneg : (G → R) → G → R) := conjneg_conjneg +lemma conjneg_bijective : Bijective (conjneg : (G → R) → G → R) := conjneg_involutive.bijective +lemma conjneg_injective : Injective (conjneg : (G → R) → G → R) := conjneg_involutive.injective +lemma conjneg_surjective : Surjective (conjneg : (G → R) → G → R) := conjneg_involutive.surjective + +@[simp] lemma conjneg_inj : conjneg f = conjneg g ↔ f = g := conjneg_injective.eq_iff +lemma conjneg_ne_conjneg : conjneg f ≠ conjneg g ↔ f ≠ g := conjneg_injective.ne_iff + +@[simp] lemma conjneg_conj (f : G → R) : conjneg (conj f) = conj (conjneg f) := rfl + +@[simp] lemma conjneg_zero : conjneg (0 : G → R) = 0 := by ext; simp +@[simp] lemma conjneg_one : conjneg (1 : G → R) = 1 := by ext; simp +@[simp] lemma conjneg_add (f g : G → R) : conjneg (f + g) = conjneg f + conjneg g := by ext; simp +@[simp] lemma conjneg_mul (f g : G → R) : conjneg (f * g) = conjneg f * conjneg g := by ext; simp + +@[simp] lemma conjneg_sum (s : Finset ι) (f : ι → G → R) : + conjneg (∑ i ∈ s, f i) = ∑ i ∈ s, conjneg (f i) := by ext; simp + +@[simp] lemma conjneg_prod (s : Finset ι) (f : ι → G → R) : + conjneg (∏ i ∈ s, f i) = ∏ i ∈ s, conjneg (f i) := by ext; simp + +@[simp] lemma conjneg_eq_zero : conjneg f = 0 ↔ f = 0 := by + rw [← conjneg_inj, conjneg_conjneg, conjneg_zero] + +@[simp] lemma conjneg_eq_one : conjneg f = 1 ↔ f = 1 := by + rw [← conjneg_inj, conjneg_conjneg, conjneg_one] + +lemma conjneg_ne_zero : conjneg f ≠ 0 ↔ f ≠ 0 := conjneg_eq_zero.not +lemma conjneg_ne_one : conjneg f ≠ 1 ↔ f ≠ 1 := conjneg_eq_one.not + +lemma sum_conjneg [Fintype G] (f : G → R) : ∑ a, conjneg f a = ∑ a, conj (f a) := + Fintype.sum_equiv (Equiv.neg _) _ _ fun _ ↦ rfl + +@[simp] lemma support_conjneg (f : G → R) : support (conjneg f) = -support f := by + ext; simp [starRingEnd_apply] + +/-- `conjneg` bundled as a ring homomorphism. -/ +@[simps] def conjnegRingHom : (G → R) →+* (G → R) where + toFun := conjneg + map_zero' := conjneg_zero + map_one' := conjneg_one + map_add' := conjneg_add + map_mul' := conjneg_mul + +end CommSemiring + +section CommRing +variable [CommRing R] [StarRing R] + +@[simp] lemma conjneg_sub (f g : G → R) : conjneg (f - g) = conjneg f - conjneg g := by ext; simp +@[simp] lemma conjneg_neg (f : G → R) : conjneg (-f) = -conjneg f := by ext; simp + +end CommRing 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..61e7ac629195f 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. @@ -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 @@ -733,6 +733,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 +771,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 +798,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 +843,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 7594743c491d5..6c37067eee6ab 100644 --- a/Mathlib/Algebra/Star/Pointwise.lean +++ b/Mathlib/Algebra/Star/Pointwise.lean @@ -3,9 +3,9 @@ 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.Basic import Mathlib.Algebra.Star.Basic import Mathlib.Data.Set.Finite -import Mathlib.Data.Set.Pointwise.Basic /-! # Pointwise star operation on sets diff --git a/Mathlib/Algebra/Star/SelfAdjoint.lean b/Mathlib/Algebra/Star/SelfAdjoint.lean index f123298542131..32776d896fc45 100644 --- a/Mathlib/Algebra/Star/SelfAdjoint.lean +++ b/Mathlib/Algebra/Star/SelfAdjoint.lean @@ -91,15 +91,20 @@ 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. -/ -theorem starHom_apply {F R S : Type*} [Star R] [Star S] [FunLike F R S] [StarHomClass F R S] +@[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 +@[deprecated (since := "2024-09-07")] alias starHom_apply := map + /- note: this lemma is *not* marked as `simp` so that Lean doesn't look for a `[TrivialStar R]` instance every time it sees `⊢ IsSelfAdjoint (f x)`, which will likely occur relatively often. -/ -theorem _root_.isSelfAdjoint_starHom_apply {F R S : Type*} [Star R] [Star S] [FunLike F R S] +theorem _root_.isSelfAdjoint_map {F R S : Type*} [Star R] [Star S] [FunLike F R S] [StarHomClass F R S] [TrivialStar R] (f : F) (x : R) : IsSelfAdjoint (f x) := - (IsSelfAdjoint.all x).starHom_apply f + (IsSelfAdjoint.all x).map f + +@[deprecated (since := "2024-09-07")] alias _root_.isSelfAdjoint_starHom_apply := isSelfAdjoint_map section AddMonoid @@ -156,6 +161,10 @@ theorem conjugate {x : R} (hx : IsSelfAdjoint x) (z : R) : IsSelfAdjoint (z * x theorem conjugate' {x : R} (hx : IsSelfAdjoint x) (z : R) : IsSelfAdjoint (star z * x * z) := by simp only [isSelfAdjoint_iff, star_mul, star_star, mul_assoc, hx.star_eq] +@[aesop 90% apply] +theorem conjugate_self {x : R} (hx : IsSelfAdjoint x) {z : R} (hz : IsSelfAdjoint z) : + IsSelfAdjoint (z * x * z) := by nth_rewrite 2 [← hz]; exact conjugate hx z + @[aesop 10% apply] theorem isStarNormal {x : R} (hx : IsSelfAdjoint x) : IsStarNormal x := ⟨by simp only [Commute, SemiconjBy, hx.star_eq]⟩ diff --git a/Mathlib/Algebra/Star/StarAlgHom.lean b/Mathlib/Algebra/Star/StarAlgHom.lean index b8748b3c4d8b7..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] @@ -263,7 +265,7 @@ variable (R : Type*) {S A B : Type*} [Monoid R] [Monoid S] [Star A] [Star B] [IsScalarTower R S A] [IsScalarTower R S B] /-- If a monoid `R` acts on another monoid `S`, then a non-unital star algebra homomorphism -over `S` can be viewed as a non-unital star algebra homomorphism over `R`. -/ +over `S` can be viewed as a non-unital star algebra homomorphism over `R`. -/ def restrictScalars (f : A →⋆ₙₐ[S] B) : A →⋆ₙₐ[R] B := { (f : A →ₙₐ[S] B).restrictScalars R with map_star' := map_star f } @@ -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. -/ @@ -807,9 +771,7 @@ theorem invFun_eq_symm {e : A ≃⋆ₐ[R] B} : EquivLike.inv e = e.symm := rfl @[simp] -theorem symm_symm (e : A ≃⋆ₐ[R] B) : e.symm.symm = e := by - ext - rfl +theorem symm_symm (e : A ≃⋆ₐ[R] B) : e.symm.symm = e := rfl theorem symm_bijective : Function.Bijective (symm : (A ≃⋆ₐ[R] B) → B ≃⋆ₐ[R] A) := Function.bijective_iff_has_inverse.mpr ⟨_, symm_symm, symm_symm⟩ @@ -821,7 +783,7 @@ theorem coe_mk (e h₁ h₂) : ⇑(⟨e, h₁, h₂⟩ : A ≃⋆ₐ[R] B) = e : theorem mk_coe (e : A ≃⋆ₐ[R] B) (e' h₁ h₂ h₃ h₄ h₅ h₆) : (⟨⟨⟨e, e', h₁, h₂⟩, h₃, h₄⟩, h₅, h₆⟩ : A ≃⋆ₐ[R] B) = e := ext fun _ => rfl -/-- Auxilliary definition to avoid looping in `dsimp` with `StarAlgEquiv.symm_mk`. -/ +/-- Auxiliary definition to avoid looping in `dsimp` with `StarAlgEquiv.symm_mk`. -/ protected def symm_mk.aux (f f') (h₁ h₂ h₃ h₄ h₅ h₆) := (⟨⟨⟨f, f', h₁, h₂⟩, h₃, h₄⟩, h₅, h₆⟩ : A ≃⋆ₐ[R] B).symm @@ -891,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/StarRingHom.lean b/Mathlib/Algebra/Star/StarRingHom.lean index cdf64f59320dc..8d5fac3954d7d 100644 --- a/Mathlib/Algebra/Star/StarRingHom.lean +++ b/Mathlib/Algebra/Star/StarRingHom.lean @@ -354,9 +354,7 @@ theorem invFun_eq_symm {e : A ≃⋆+* B} : EquivLike.inv e = e.symm := rfl @[simp] -theorem symm_symm (e : A ≃⋆+* B) : e.symm.symm = e := by - ext - rfl +theorem symm_symm (e : A ≃⋆+* B) : e.symm.symm = e := rfl theorem symm_bijective : Function.Bijective (symm : (A ≃⋆+* B) → B ≃⋆+* A) := Function.bijective_iff_has_inverse.mpr ⟨_, symm_symm, symm_symm⟩ @@ -367,7 +365,7 @@ theorem coe_mk (e h₁) : ⇑(⟨e, h₁⟩ : A ≃⋆+* B) = e := rfl theorem mk_coe (e : A ≃⋆+* B) (e' h₁ h₂ h₃ h₄ h₅) : (⟨⟨⟨e, e', h₁, h₂⟩, h₃, h₄⟩, h₅⟩ : A ≃⋆+* B) = e := ext fun _ => rfl -/-- Auxilliary definition to avoid looping in `dsimp` with `StarRingEquiv.symm_mk`. -/ +/-- Auxiliary definition to avoid looping in `dsimp` with `StarRingEquiv.symm_mk`. -/ protected def symm_mk.aux (f f') (h₁ h₂ h₃ h₄ h₅) := (⟨⟨⟨f, f', h₁, h₂⟩, h₃, h₄⟩, h₅⟩ : A ≃⋆+* B).symm diff --git a/Mathlib/Algebra/Star/Subalgebra.lean b/Mathlib/Algebra/Star/Subalgebra.lean index 380f87763c95d..7d0b23cd8f043 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 @@ -594,6 +594,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 +630,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,7 +665,7 @@ 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 => ?_) @@ -669,7 +677,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,7 +685,7 @@ 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 := diff --git a/Mathlib/Algebra/Symmetrized.lean b/Mathlib/Algebra/Symmetrized.lean index a99928f48d53c..f4dea0e4e8345 100644 --- a/Mathlib/Algebra/Symmetrized.lean +++ b/Mathlib/Algebra/Symmetrized.lean @@ -255,9 +255,9 @@ instance nonAssocSemiring [Semiring α] [Invertible (2 : α)] : NonAssocSemiring rw [mul_def, unsym_zero, zero_mul, mul_zero, add_zero, mul_zero, sym_zero] mul_one := fun _ => by - rw [mul_def, unsym_one, mul_one, one_mul, ← two_mul, invOf_mul_self_assoc, sym_unsym] + rw [mul_def, unsym_one, mul_one, one_mul, ← two_mul, invOf_mul_cancel_left, sym_unsym] one_mul := fun _ => by - rw [mul_def, unsym_one, mul_one, one_mul, ← two_mul, invOf_mul_self_assoc, sym_unsym] + rw [mul_def, unsym_one, mul_one, one_mul, ← two_mul, invOf_mul_cancel_left, sym_unsym] left_distrib := fun a b c => by -- Porting note: rewrote previous proof which used `match` in a way that seems unsupported. rw [mul_def, mul_def, mul_def, ← sym_add, ← mul_add, unsym_add, add_mul] @@ -279,10 +279,11 @@ instance [Ring α] [Invertible (2 : α)] : NonAssocRing αˢʸᵐ := theorem unsym_mul_self [Semiring α] [Invertible (2 : α)] (a : αˢʸᵐ) : - unsym (a * a) = unsym a * unsym a := by rw [mul_def, unsym_sym, ← two_mul, invOf_mul_self_assoc] + unsym (a * a) = unsym a * unsym a := by + rw [mul_def, unsym_sym, ← two_mul, invOf_mul_cancel_left] theorem sym_mul_self [Semiring α] [Invertible (2 : α)] (a : α) : sym (a * a) = sym a * sym a := by - rw [sym_mul_sym, ← two_mul, invOf_mul_self_assoc] + rw [sym_mul_sym, ← two_mul, invOf_mul_cancel_left] theorem mul_comm [Mul α] [AddCommSemigroup α] [One α] [OfNat α 2] [Invertible (2 : α)] (a b : αˢʸᵐ) : diff --git a/Mathlib/Algebra/TrivSqZeroExt.lean b/Mathlib/Algebra/TrivSqZeroExt.lean index ed6277acc897f..c40ab975c18d7 100644 --- a/Mathlib/Algebra/TrivSqZeroExt.lean +++ b/Mathlib/Algebra/TrivSqZeroExt.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Eric Wieser -/ import Mathlib.Algebra.Algebra.Defs -import Mathlib.GroupTheory.GroupAction.BigOperators +import Mathlib.Algebra.BigOperators.GroupWithZero.Action import Mathlib.LinearAlgebra.Prod /-! @@ -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 @@ -624,7 +640,7 @@ instance monoid [Monoid R] [AddMonoid M] [DistribMulAction R M] [DistribMulActio · simp [List.range_succ] rw [List.sum_range_succ'] simp only [pow_zero, op_one, Nat.sub_zero, one_smul, Nat.succ_sub_succ_eq_sub, fst_pow, - Nat.pred_succ, List.smul_sum, List.map_map, Function.comp] + Nat.pred_succ, List.smul_sum, List.map_map, Function.comp_def] simp_rw [← smul_comm (_ : R) (_ : Rᵐᵒᵖ), smul_smul, pow_succ] rfl) } @@ -643,12 +659,13 @@ theorem snd_list_prod [Semiring R] [AddCommMonoid M] [Module R M] [Module Rᵐ l.prod.snd = (l.enum.map fun x : ℕ × tsze R M => ((l.map fst).take x.1).prod •> x.snd.snd <• ((l.map fst).drop x.1.succ).prod).sum := by - induction' l with x xs ih - · simp - · rw [List.enum_cons, ← List.map_fst_add_enum_eq_enumFrom] - simp_rw [List.map_cons, List.map_map, Function.comp, Prod.map_snd, Prod.map_fst, id, - List.take_zero, List.take_cons, List.prod_nil, List.prod_cons, snd_mul, one_smul, List.drop, - mul_smul, List.sum_cons, fst_list_prod, ih, List.smul_sum, List.map_map, + induction l with + | nil => simp + | cons x xs ih => + rw [List.enum_cons, ← List.map_fst_add_enum_eq_enumFrom] + simp_rw [List.map_cons, List.map_map, Function.comp_def, Prod.map_snd, Prod.map_fst, id, + List.take_zero, List.take_succ_cons, List.prod_nil, List.prod_cons, snd_mul, one_smul, + List.drop, mul_smul, List.sum_cons, fst_list_prod, ih, List.smul_sum, List.map_map, ← smul_comm (_ : R) (_ : Rᵐᵒᵖ)] exact add_comm _ _ @@ -689,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⁻¹))⟩ @@ -701,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] @@ -726,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 @@ -762,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 @@ -872,7 +965,7 @@ def lift (f : R →ₐ[S] A) (g : M →ₗ[S] A) (TrivSqZeroExt.ind fun r₁ m₁ => TrivSqZeroExt.ind fun r₂ m₂ => by dsimp - simp only [add_zero, zero_add, add_mul, mul_add, smul_mul_smul, hg, smul_zero, + simp only [add_zero, zero_add, add_mul, mul_add, smul_mul_smul_comm, hg, smul_zero, op_smul_eq_smul] rw [← map_mul, LinearMap.map_add, add_comm (g _), add_assoc, hfg, hgf]) diff --git a/Mathlib/Algebra/Tropical/Basic.lean b/Mathlib/Algebra/Tropical/Basic.lean index 7d620bea68f04..5454363d36711 100644 --- a/Mathlib/Algebra/Tropical/Basic.lean +++ b/Mathlib/Algebra/Tropical/Basic.lean @@ -489,9 +489,9 @@ instance : CommSemiring (Tropical R) := @[simp] theorem succ_nsmul {R} [LinearOrder R] [OrderTop R] (x : Tropical R) (n : ℕ) : (n + 1) • x = x := by - induction' n with n IH - · simp - · rw [add_nsmul, IH, one_nsmul, add_self] + induction n with + | zero => simp + | succ n IH => rw [add_nsmul, IH, one_nsmul, add_self] -- TODO: find/create the right classes to make this hold (for enat, ennreal, etc) -- Requires `zero_eq_bot` to be true diff --git a/Mathlib/AlgebraicGeometry/AffineScheme.lean b/Mathlib/AlgebraicGeometry/AffineScheme.lean index 9e2cd3513685e..121a41fc2382f 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 @@ -31,7 +32,7 @@ We also define predicates about affine schemes and affine open sets. -/ --- Explicit universe annotations were used in this file to improve perfomance #12737 +-- Explicit universe annotations were used in this file to improve performance #12737 noncomputable section @@ -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,13 @@ 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 + namespace AffineScheme /-- The `Spec` functor into the category of affine schemes. -/ @@ -228,7 +238,7 @@ theorem iSup_affineOpens_eq_top (X : Scheme) : ⨆ i : X.affineOpens, (i : X.Ope theorem Scheme.map_PrimeSpectrum_basicOpen_of_affine (X : Scheme) [IsAffine X] (f : Scheme.Γ.obj (op 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 @@ -240,10 +250,10 @@ theorem isBasis_basicOpen (X : Scheme) [IsAffine X] : 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 namespace IsAffineOpen @@ -265,7 +275,7 @@ instance isOpenImmersion_fromSpec : 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] + rw [Function.comp_assoc, 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 infer_instance @@ -312,7 +322,7 @@ theorem _root_.AlgebraicGeometry.Scheme.Hom.isAffineOpen_iff_of_isOpenImmersion (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 - dsimp [Opens.coe_inclusion, Scheme.restrict] + dsimp [Opens.coe_inclusion', Scheme.restrict] erw [Subtype.range_coe, Subtype.range_coe] -- now `erw` after #13170 rfl · infer_instance @@ -356,10 +366,9 @@ theorem SpecΓIdentity_hom_app_fromSpec : (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, + ΓSpecIso_obj_hom, Scheme.Opens.topIso_inv, Opens.map_top, Scheme.Opens.topIso_hom, + Scheme.comp_app, Scheme.Opens.ι_app_self, unop_op, Category.assoc, ← Functor.map_comp_assoc, ← + op_comp, eqToHom_trans, Scheme.Opens.eq_presheaf_map_eqToHom, Scheme.Hom.naturality_assoc, Scheme.inv_app_top, IsIso.hom_inv_id_assoc] simp only [eqToHom_op, eqToHom_map, Spec.map_eqToHom, eqToHom_unop, Scheme.Spec_map_presheaf_map_eqToHom, eqToHom_trans] @@ -417,8 +426,8 @@ theorem exists_basicOpen_le {V : X.Opens} (x : V) (h : ↑x ∈ U) : ∃ f : Γ(X, U), X.basicOpen f ≤ V ∧ ↑x ∈ X.basicOpen f := by have : IsAffine _ := hU obtain ⟨_, ⟨_, ⟨r, rfl⟩, rfl⟩, h₁, h₂⟩ := - (isBasis_basicOpen U).exists_subset_of_mem_open (x.2 : ⟨x, h⟩ ∈ _) - ((Opens.map U.inclusion).obj V).isOpen + (isBasis_basicOpen U).exists_subset_of_mem_open (x.2 : (⟨x, h⟩ : 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 @@ -441,7 +450,7 @@ def basicOpenSectionsToAffine : instance basicOpenSectionsToAffine_isIso : IsIso (basicOpenSectionsToAffine hU f) := by delta basicOpenSectionsToAffine - apply (config := { allowSynthFailures := true }) IsIso.comp_isIso + refine IsIso.comp_isIso' ?_ inferInstance apply PresheafedSpace.IsOpenImmersion.isIso_of_subset rw [hU.range_fromSpec] exact RingedSpace.basicOpen_le _ _ @@ -555,8 +564,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 @@ -578,7 +587,7 @@ def _root_.AlgebraicGeometry.Scheme.affineBasicOpen include hU in /-- In an affine open set `U`, a family of basic open covers `U` iff the sections span `Γ(X, U)`. -See `iSup_basicOpen_of_span_eq_top` for the inverse direction without the affine-ness assuption. +See `iSup_basicOpen_of_span_eq_top` for the inverse direction without the affine-ness assumption. -/ theorem basicOpen_union_eq_self_iff (s : Set Γ(X, U)) : ⨆ f : s, X.basicOpen (f : Γ(X, U)) = U ↔ Ideal.span s = ⊤ := by @@ -683,7 +692,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Γ.val.base ⁻¹' PrimeSpectrum.zeroLocus s = X.zeroLocus s := LocallyRingedSpace.toΓSpec_preimage_zeroLocus_eq s open ConcreteCategory @@ -712,6 +721,109 @@ lemma Scheme.eq_zeroLocus_of_isClosed_of_isAffine (X : Scheme.{u}) [IsAffine X] 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 20acd2442916a..c137272d6c0ce 100644 --- a/Mathlib/AlgebraicGeometry/Cover/Open.lean +++ b/Mathlib/AlgebraicGeometry/Cover/Open.lean @@ -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 @@ -92,7 +92,7 @@ theorem OpenCover.iSup_opensRange {X : Scheme.{u}} (𝒰 : X.OpenCover) : Opens.ext <| by rw [Opens.coe_iSup]; exact 𝒰.iUnion_range /-- Given an open cover `{ Uᵢ }` of `X`, and for each `Uᵢ` an open cover, we may combine these -open covers to form an open cover of `X`. -/ +open covers to form an open cover of `X`. -/ @[simps! J obj map] def OpenCover.bind (f : ∀ x : 𝒰.J, OpenCover (𝒰.obj x)) : OpenCover X where J := Σ i : 𝒰.J, (f i).J @@ -136,7 +136,7 @@ def OpenCover.copy {X : Scheme.{u}} (𝒰 : OpenCover X) (J : Type*) (obj : J rw [e₂, Scheme.comp_val_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 _ _ } @@ -503,7 +503,7 @@ theorem affineBasisCover_is_basis (X : Scheme.{u}) : ((X.affineCover.map (X.affineCover.f a)).1.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..fc127a34958cc 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 diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/Group.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/Group.lean index c87f5ce1c0540..d81a89407576b 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/Group.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Group.lean @@ -179,8 +179,9 @@ lemma smul_basis_mul_Y (p q : R[X]) : (p • (1 : W.CoordinateRing) + q • mk W /-- The ring homomorphism `R[W] →+* S[W.map f]` induced by a ring homomorphism `f : R →+* S`. -/ noncomputable def map : W.CoordinateRing →+* (W.map f).toAffine.CoordinateRing := - AdjoinRoot.lift ((AdjoinRoot.of _).comp <| mapRingHom f) _ <| by - rw [← eval₂_map, ← map_polynomial, AdjoinRoot.eval₂_root] + AdjoinRoot.lift ((AdjoinRoot.of _).comp <| mapRingHom f) + ((AdjoinRoot.root (WeierstrassCurve.map W f).toAffine.polynomial)) <| by + rw [← eval₂_map, ← map_polynomial, AdjoinRoot.eval₂_root] lemma map_mk (x : R[X][Y]) : map W f (mk W x) = mk (W.map f) (x.map <| mapRingHom f) := by rw [map, AdjoinRoot.lift_mk, ← eval₂_map] @@ -212,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 @@ -221,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 @@ -234,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} @@ -386,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)ˣ := @@ -517,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 @@ -544,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/Jacobian.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/Jacobian.lean index 6042ae7f510d6..d0976e216dd81 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 @@ -359,8 +360,8 @@ variable (W') in /-- The proposition that a point representative $(x, y, z)$ in `W'` is nonsingular. In other words, either $W_X(x, y, z) \ne 0$, $W_Y(x, y, z) \ne 0$, or $W_Z(x, y, z) \ne 0$. -Note that this definition is only mathematically accurate for fields. -TODO: generalise this definition to be mathematically accurate for a larger class of rings. -/ +Note that this definition is only mathematically accurate for fields. -/ +-- TODO: generalise this definition to be mathematically accurate for a larger class of rings. def Nonsingular (P : Fin 3 → R) : Prop := W'.Equation P ∧ (eval P W'.polynomialX ≠ 0 ∨ eval P W'.polynomialY ≠ 0 ∨ eval P W'.polynomialZ ≠ 0) @@ -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 @@ -1619,3 +1620,5 @@ end WeierstrassCurve.Jacobian abbrev WeierstrassCurve.Affine.Point.toJacobian {R : Type u} [CommRing R] [Nontrivial R] {W : Affine R} (P : W.Point) : W.toJacobian.Point := Jacobian.Point.fromAffine P + +set_option linter.style.longFile 1700 diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/NormalForms.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/NormalForms.lean new file mode 100644 index 0000000000000..565f29a05b7f1 --- /dev/null +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/NormalForms.lean @@ -0,0 +1,706 @@ +/- +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 [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⟩ + +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 [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⟩ + +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₃⟩ + +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₂ + +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⟩ + +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 + +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 + +/-- 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⟩ + +end VariableChange + +end WeierstrassCurve diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/Projective.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/Projective.lean index f1314e4735540..3d4ea8337acc9 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/Projective.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Projective.lean @@ -3,9 +3,11 @@ Copyright (c) 2023 David Kurniadi Angdinata. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: David Kurniadi Angdinata -/ -import Mathlib.AlgebraicGeometry.EllipticCurve.Affine 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 @@ -18,7 +20,7 @@ condition. Let `W` be a Weierstrass curve over a field `F`. A point on the projective plane is an equivalence class of triples $[x:y:z]$ with coordinates in `F` such that $(x, y, z) \sim (x', y', z')$ precisely -if there is some unit $u$ of `F` such that $(x, y, z) = (ux', uy', uz')$, with an extra condition +if there is some unit `u` of `F` such that $(x, y, z) = (ux', uy', uz')$, with an extra condition that $(x, y, z) \ne (0, 0, 0)$. As described in `Mathlib.AlgebraicGeometry.EllipticCurve.Affine`, a rational point is a point on the projective plane satisfying a homogeneous Weierstrass equation, and being nonsingular means the partial derivatives $W_X(X, Y, Z)$, $W_Y(X, Y, Z)$, and $W_Z(X, Y, Z)$ @@ -27,6 +29,10 @@ 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. + ## Main definitions * `WeierstrassCurve.Projective.PointClass`: the equivalence class of a point representative. @@ -42,11 +48,11 @@ given by a tuple consisting of $[x:y:z]$ and the nonsingular condition on any re A point representative is implemented as a term `P` of type `Fin 3 → R`, which allows for the vector notation `![x, y, z]`. However, `P` is not definitionally equivalent to the expanded vector -`![P x, P y, P z]`, so the auxiliary lemma `fin3_def` can be used to convert between the two forms. -The equivalence of two point representatives `P` and `Q` is implemented as an equivalence of orbits -of the action of `Rˣ`, or equivalently that there is some unit `u` of `R` such that `P = u • Q`. -However, `u • Q` is again not definitionally equal to `![u * Q x, u * Q y, u * Q z]`, so the -auxiliary lemmas `smul_fin3` and `smul_fin3_ext` can be used to convert between the two forms. +`![P x, P y, P z]`, so the lemmas `fin3_def` and `fin3_def_ext` can be used to convert between the +two forms. The equivalence of two point representatives `P` and `Q` is implemented as an equivalence +of orbits of the action of `Rˣ`, or equivalently that there is some unit `u` of `R` such that +`P = u • Q`. However, `u • Q` is not definitionally equal to `![u * Q x, u * Q y, u * Q z]`, so the +lemmas `smul_fin3` and `smul_fin3_ext` can be used to convert between the two forms. ## References @@ -57,23 +63,27 @@ auxiliary lemmas `smul_fin3` and `smul_fin3_ext` can be used to convert between elliptic curve, rational point, projective coordinates -/ -local notation "x" => 0 +local notation3 "x" => (0 : Fin 3) -local notation "y" => 1 +local notation3 "y" => (1 : Fin 3) -local notation "z" => 2 +local notation3 "z" => (2 : Fin 3) local macro "matrix_simp" : tactic => `(tactic| simp only [Matrix.head_cons, Matrix.tail_cons, Matrix.smul_empty, Matrix.smul_cons, Matrix.cons_val_zero, Matrix.cons_val_one, Matrix.cons_val_two]) -universe u +universe u v /-! ## Weierstrass curves -/ /-- An abbreviation for a Weierstrass curve in projective coordinates. -/ -abbrev WeierstrassCurve.Projective := - WeierstrassCurve +abbrev WeierstrassCurve.Projective (R : Type u) : Type u := + WeierstrassCurve R + +/-- The coercion to a Weierstrass curve in projective coordinates. -/ +abbrev WeierstrassCurve.toProjective {R : Type u} (W : WeierstrassCurve R) : Projective R := + W namespace WeierstrassCurve.Projective @@ -85,231 +95,1072 @@ local macro "eval_simp" : tactic => local macro "pderiv_simp" : tactic => `(tactic| simp only [map_ofNat, map_neg, map_add, map_sub, map_mul, pderiv_mul, pderiv_pow, pderiv_C, pderiv_X_self, pderiv_X_of_ne one_ne_zero, pderiv_X_of_ne one_ne_zero.symm, - pderiv_X_of_ne (by decide : (2 : Fin 3) ≠ 0), pderiv_X_of_ne (by decide : (0 : Fin 3) ≠ 2), - pderiv_X_of_ne (by decide : (2 : Fin 3) ≠ 1), pderiv_X_of_ne (by decide : (1 : Fin 3) ≠ 2)]) + pderiv_X_of_ne (by decide : z ≠ x), pderiv_X_of_ne (by decide : x ≠ z), + pderiv_X_of_ne (by decide : z ≠ y), pderiv_X_of_ne (by decide : y ≠ z)]) -variable {R : Type u} [CommRing R] (W : Projective R) +variable {R : Type u} {W' : Projective R} {F : Type v} [Field F] {W : Projective F} -lemma fin3_def {R : Type u} (P : Fin 3 → R) : P = ![P x, P y, P z] := by +section Projective + +/-! ### Projective coordinates -/ + +lemma fin3_def (P : Fin 3 → R) : ![P x, P y, P z] = P := by ext n; fin_cases n <;> rfl -lemma smul_fin3 {R : Type u} [CommRing R] (P : Fin 3 → R) (u : Rˣ) : - u • P = ![u * P x, u * P y, u * P z] := by - rw [fin3_def P] - matrix_simp - simp only [Units.smul_def, smul_eq_mul] +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 : 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] := by + simp [← List.ofFn_inj] -lemma smul_fin3_ext {R : Type u} [CommRing R] (P : Fin 3 → R) (u : Rˣ) : - (u • P) x = u * P x ∧ (u • P) y = u * P y ∧ (u • P) z = u * P z := by - refine ⟨?_, ?_, ?_⟩ <;> simp only [Units.smul_def, Pi.smul_apply, smul_eq_mul] +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 := + ⟨rfl, rfl, rfl⟩ /-- The equivalence setoid for a point representative. -/ scoped instance instSetoidPoint : Setoid <| Fin 3 → R := MulAction.orbitRel Rˣ <| Fin 3 → R +variable (R) in /-- The equivalence class of a point representative. -/ -abbrev PointClass (R : Type u) [CommRing R] : Type u := +abbrev PointClass : Type u := MulAction.orbitRel.Quotient Rˣ <| Fin 3 → R +lemma smul_equiv (P : Fin 3 → R) {u : R} (hu : IsUnit u) : u • P ≈ P := + ⟨hu.unit, rfl⟩ + +@[simp] +lemma smul_eq (P : Fin 3 → R) {u : R} (hu : IsUnit u) : (⟦u • P⟧ : PointClass R) = ⟦P⟧ := + Quotient.eq.mpr <| smul_equiv P hu + +variable (W') in /-- The coercion to a Weierstrass curve in affine coordinates. -/ abbrev toAffine : Affine R := - W + W' + +lemma equiv_iff_eq_of_Z_eq' {P Q : Fin 3 → R} (hz : P z = Q z) (mem : Q z ∈ nonZeroDivisors R) : + P ≈ Q ↔ P = Q := by + refine ⟨?_, by rintro rfl; exact Setoid.refl _⟩ + rintro ⟨u, rfl⟩ + rw [← one_mul (Q z)] at hz + simp_rw [Units.smul_def, (mul_cancel_right_mem_nonZeroDivisors mem).mp hz, one_smul] + +lemma equiv_iff_eq_of_Z_eq [NoZeroDivisors R] {P Q : Fin 3 → R} (hz : P z = Q z) (hQz : Q z ≠ 0) : + P ≈ Q ↔ P = Q := + equiv_iff_eq_of_Z_eq' hz (mem_nonZeroDivisors_of_ne_zero hQz) + +lemma Z_eq_zero_of_equiv {P Q : Fin 3 → R} (h : P ≈ Q) : P z = 0 ↔ Q z = 0 := by + rcases h with ⟨_, rfl⟩ + simp only [Units.smul_def, smul_fin3_ext, Units.mul_right_eq_zero] + +lemma X_eq_of_equiv {P Q : Fin 3 → R} (h : P ≈ Q) : P x * Q z = Q x * P z := by + rcases h with ⟨u, rfl⟩ + simp only [Units.smul_def, smul_fin3_ext] + ring1 + +lemma Y_eq_of_equiv {P Q : Fin 3 → R} (h : P ≈ Q) : P y * Q z = Q y * P z := by + rcases h with ⟨u, rfl⟩ + simp only [Units.smul_def, smul_fin3_ext] + ring1 + +lemma not_equiv_of_Z_eq_zero_left {P Q : Fin 3 → R} (hPz : P z = 0) (hQz : Q z ≠ 0) : ¬P ≈ Q := + fun h => hQz <| (Z_eq_zero_of_equiv h).mp hPz + +lemma not_equiv_of_Z_eq_zero_right {P Q : Fin 3 → R} (hPz : P z ≠ 0) (hQz : Q z = 0) : ¬P ≈ Q := + fun h => hPz <| (Z_eq_zero_of_equiv h).mpr hQz + +lemma not_equiv_of_X_ne {P Q : Fin 3 → R} (hx : P x * Q z ≠ Q x * P z) : ¬P ≈ Q := + hx.comp X_eq_of_equiv + +lemma not_equiv_of_Y_ne {P Q : Fin 3 → R} (hy : P y * Q z ≠ Q y * P z) : ¬P ≈ Q := + hy.comp Y_eq_of_equiv + +lemma equiv_of_X_eq_of_Y_eq {P Q : Fin 3 → F} (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 ≈ Q := by + use Units.mk0 _ hPz / Units.mk0 _ hQz + simp only [Units.smul_def, smul_fin3, Units.val_div_eq_div_val, Units.val_mk0, mul_comm, mul_div, + ← hx, ← hy, mul_div_cancel_right₀ _ hQz, fin3_def] + +lemma equiv_some_of_Z_ne_zero {P : Fin 3 → F} (hPz : P z ≠ 0) : P ≈ ![P x / P z, P y / P z, 1] := + equiv_of_X_eq_of_Y_eq hPz one_ne_zero + (by linear_combination (norm := (matrix_simp; ring1)) -P x * div_self hPz) + (by linear_combination (norm := (matrix_simp; ring1)) -P y * div_self hPz) + +lemma X_eq_iff {P Q : Fin 3 → F} (hPz : P z ≠ 0) (hQz : Q z ≠ 0) : + P x * Q z = Q x * P z ↔ P x / P z = Q x / Q z := + (div_eq_div_iff hPz hQz).symm + +lemma Y_eq_iff {P Q : Fin 3 → F} (hPz : P z ≠ 0) (hQz : Q z ≠ 0) : + P y * Q z = Q y * P z ↔ P y / P z = Q y / Q z := + (div_eq_div_iff hPz hQz).symm + +end Projective + +variable [CommRing R] section Equation -/-! ### Equations and nonsingularity -/ +/-! ### Weierstrass equations -/ +variable (W') in /-- The polynomial $W(X, Y, Z) := Y^2Z + a_1XYZ + a_3YZ^2 - (X^3 + a_2X^2Z + a_4XZ^2 + a_6Z^3)$ -associated to a Weierstrass curve `W` over `R`. This is represented as a term of type +associated to a Weierstrass curve `W'` over `R`. This is represented as a term of type `MvPolynomial (Fin 3) R`, where `X 0`, `X 1`, and `X 2` represent $X$, $Y$, and $Z$ respectively. -/ noncomputable def polynomial : MvPolynomial (Fin 3) R := - X 1 ^ 2 * X 2 + C W.a₁ * X 0 * X 1 * X 2 + C W.a₃ * X 1 * X 2 ^ 2 - - (X 0 ^ 3 + C W.a₂ * X 0 ^ 2 * X 2 + C W.a₄ * X 0 * X 2 ^ 2 + C W.a₆ * X 2 ^ 3) + X 1 ^ 2 * X 2 + C W'.a₁ * X 0 * X 1 * X 2 + C W'.a₃ * X 1 * X 2 ^ 2 + - (X 0 ^ 3 + C W'.a₂ * X 0 ^ 2 * X 2 + C W'.a₄ * X 0 * X 2 ^ 2 + C W'.a₆ * X 2 ^ 3) -lemma eval_polynomial (P : Fin 3 → R) : eval P W.polynomial = - P y ^ 2 * P z + W.a₁ * P x * P y * P z + W.a₃ * P y * P z ^ 2 - - (P x ^ 3 + W.a₂ * P x ^ 2 * P z + W.a₄ * P x * P z ^ 2 + W.a₆ * P z ^ 3) := by +lemma eval_polynomial (P : Fin 3 → R) : eval P W'.polynomial = + P y ^ 2 * P z + W'.a₁ * P x * P y * P z + W'.a₃ * P y * P z ^ 2 + - (P x ^ 3 + W'.a₂ * P x ^ 2 * P z + W'.a₄ * P x * P z ^ 2 + W'.a₆ * P z ^ 3) := by rw [polynomial] eval_simp -/-- The proposition that a point representative $(x, y, z)$ lies in `W`. +lemma eval_polynomial_of_Z_ne_zero {P : Fin 3 → F} (hPz : P z ≠ 0) : eval P W.polynomial / P z ^ 3 = + W.toAffine.polynomial.evalEval (P x / P z) (P y / P z) := by + linear_combination (norm := (rw [eval_polynomial, Affine.evalEval_polynomial]; ring1)) + P y ^ 2 / P z ^ 2 * div_self hPz + W.a₁ * P x * P y / P z ^ 2 * div_self hPz + + W.a₃ * P y / P z * div_self (pow_ne_zero 2 hPz) - W.a₂ * P x ^ 2 / P z ^ 2 * div_self hPz + - W.a₄ * P x / P z * div_self (pow_ne_zero 2 hPz) - W.a₆ * div_self (pow_ne_zero 3 hPz) + +variable (W') in +/-- The proposition that a point representative $(x, y, z)$ lies in `W'`. In other words, $W(x, y, z) = 0$. -/ def Equation (P : Fin 3 → R) : Prop := - eval P W.polynomial = 0 + eval P W'.polynomial = 0 -lemma equation_iff (P : Fin 3 → R) : W.Equation P ↔ - P y ^ 2 * P z + W.a₁ * P x * P y * P z + W.a₃ * P y * P z ^ 2 - = P x ^ 3 + W.a₂ * P x ^ 2 * P z + W.a₄ * P x * P z ^ 2 + W.a₆ * P z ^ 3 := by +lemma equation_iff (P : Fin 3 → R) : W'.Equation P ↔ + P y ^ 2 * P z + W'.a₁ * P x * P y * P z + W'.a₃ * P y * P z ^ 2 + - (P x ^ 3 + W'.a₂ * P x ^ 2 * P z + W'.a₄ * P x * P z ^ 2 + W'.a₆ * P z ^ 3) = 0 := by rw [Equation, eval_polynomial, sub_eq_zero] -lemma equation_zero (Y : R) : W.Equation ![0, Y, 0] := - (W.equation_iff ![0, Y, 0]).mpr <| by matrix_simp; ring1 +lemma equation_smul (P : Fin 3 → R) {u : R} (hu : IsUnit u) : W'.Equation (u • P) ↔ W'.Equation P := + 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 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⟩ + exact equation_smul Q u.isUnit + +lemma equation_of_Z_eq_zero {P : Fin 3 → R} (hPz : P z = 0) : W'.Equation P ↔ P x ^ 3 = 0 := by + simp only [equation_iff, hPz, add_zero, zero_sub, mul_zero, zero_pow <| OfNat.ofNat_ne_zero _, + neg_eq_zero] -lemma equation_some (X Y : R) : W.Equation ![X, Y, 1] ↔ W.toAffine.Equation X Y := by - rw [equation_iff, W.toAffine.equation_iff] - congr! 1 <;> matrix_simp <;> ring1 +lemma equation_zero : W'.Equation ![0, 1, 0] := by + simp only [equation_of_Z_eq_zero, fin3_def_ext, zero_pow three_ne_zero] -lemma equation_smul_iff (P : Fin 3 → R) (u : Rˣ) : W.Equation (u • P) ↔ W.Equation P := - have (u : Rˣ) {P : Fin 3 → R} (h : W.Equation P) : W.Equation <| u • P := by - rw [equation_iff] at h ⊢ - linear_combination (norm := (simp only [smul_fin3_ext]; ring1)) (u : R) ^ 3 * h - ⟨fun h => by convert this u⁻¹ h; rw [inv_smul_smul], this u⟩ +lemma equation_some (X Y : R) : W'.Equation ![X, Y, 1] ↔ W'.toAffine.Equation X Y := by + simp only [equation_iff, Affine.equation_iff', fin3_def_ext, one_pow, mul_one] +lemma equation_of_Z_ne_zero {P : Fin 3 → F} (hPz : P z ≠ 0) : + W.Equation P ↔ W.toAffine.Equation (P x / P z) (P y / P z) := + (equation_of_equiv <| equiv_some_of_Z_ne_zero hPz).trans <| equation_some .. + +lemma X_eq_zero_of_Z_eq_zero [NoZeroDivisors R] {P : Fin 3 → R} (hP : W'.Equation P) + (hPz : P z = 0) : P x = 0 := + pow_eq_zero <| (equation_of_Z_eq_zero hPz).mp hP + +end Equation + +section Nonsingular + +/-! ### Nonsingular Weierstrass equations -/ + +variable (W') in /-- The partial derivative $W_X(X, Y, Z)$ of $W(X, Y, Z)$ with respect to $X$. -/ noncomputable def polynomialX : MvPolynomial (Fin 3) R := - pderiv x W.polynomial + pderiv x W'.polynomial -lemma polynomialX_eq : W.polynomialX = - C W.a₁ * X 1 * X 2 - (C 3 * X 0 ^ 2 + C (2 * W.a₂) * X 0 * X 2 + C W.a₄ * X 2 ^ 2) := by +lemma polynomialX_eq : W'.polynomialX = + C W'.a₁ * X 1 * X 2 - (C 3 * X 0 ^ 2 + C (2 * W'.a₂) * X 0 * X 2 + C W'.a₄ * X 2 ^ 2) := by rw [polynomialX, polynomial] pderiv_simp ring1 -lemma eval_polynomialX (P : Fin 3 → R) : eval P W.polynomialX = - W.a₁ * P y * P z - (3 * P x ^ 2 + 2 * W.a₂ * P x * P z + W.a₄ * P z ^ 2) := by +lemma eval_polynomialX (P : Fin 3 → R) : eval P W'.polynomialX = + W'.a₁ * P y * P z - (3 * P x ^ 2 + 2 * W'.a₂ * P x * P z + W'.a₄ * P z ^ 2) := by rw [polynomialX_eq] eval_simp +lemma eval_polynomialX_of_Z_ne_zero {P : Fin 3 → F} (hPz : P z ≠ 0) : + eval P W.polynomialX / P z ^ 2 = W.toAffine.polynomialX.evalEval (P x / P z) (P y / P z) := by + linear_combination (norm := (rw [eval_polynomialX, Affine.evalEval_polynomialX]; ring1)) + W.a₁ * P y / P z * div_self hPz - 2 * W.a₂ * P x / P z * div_self hPz + - W.a₄ * div_self (pow_ne_zero 2 hPz) + +variable (W') in /-- The partial derivative $W_Y(X, Y, Z)$ of $W(X, Y, Z)$ with respect to $Y$. -/ noncomputable def polynomialY : MvPolynomial (Fin 3) R := - pderiv y W.polynomial + pderiv y W'.polynomial -lemma polynomialY_eq : W.polynomialY = - C 2 * X 1 * X 2 + C W.a₁ * X 0 * X 2 + C W.a₃ * X 2 ^ 2 := by +lemma polynomialY_eq : W'.polynomialY = + C 2 * X 1 * X 2 + C W'.a₁ * X 0 * X 2 + C W'.a₃ * X 2 ^ 2 := by rw [polynomialY, polynomial] pderiv_simp ring1 lemma eval_polynomialY (P : Fin 3 → R) : - eval P W.polynomialY = 2 * P y * P z + W.a₁ * P x * P z + W.a₃ * P z ^ 2 := by + eval P W'.polynomialY = 2 * P y * P z + W'.a₁ * P x * P z + W'.a₃ * P z ^ 2 := by rw [polynomialY_eq] eval_simp +lemma eval_polynomialY_of_Z_ne_zero {P : Fin 3 → F} (hPz : P z ≠ 0) : + eval P W.polynomialY / P z ^ 2 = W.toAffine.polynomialY.evalEval (P x / P z) (P y / P z) := by + linear_combination (norm := (rw [eval_polynomialY, Affine.evalEval_polynomialY]; ring1)) + 2 * P y / P z * div_self hPz + W.a₁ * P x / P z * div_self hPz + + W.a₃ * div_self (pow_ne_zero 2 hPz) + +variable (W') in /-- The partial derivative $W_Z(X, Y, Z)$ of $W(X, Y, Z)$ with respect to $Z$. -/ noncomputable def polynomialZ : MvPolynomial (Fin 3) R := - pderiv z W.polynomial + pderiv z W'.polynomial -lemma polynomialZ_eq : W.polynomialZ = - X 1 ^ 2 + C W.a₁ * X 0 * X 1 + C (2 * W.a₃) * X 1 * X 2 - - (C W.a₂ * X 0 ^ 2 + C (2 * W.a₄) * X 0 * X 2 + C (3 * W.a₆) * X 2 ^ 2) := by +lemma polynomialZ_eq : W'.polynomialZ = + X 1 ^ 2 + C W'.a₁ * X 0 * X 1 + C (2 * W'.a₃) * X 1 * X 2 + - (C W'.a₂ * X 0 ^ 2 + C (2 * W'.a₄) * X 0 * X 2 + C (3 * W'.a₆) * X 2 ^ 2) := by rw [polynomialZ, polynomial] pderiv_simp ring1 -lemma eval_polynomialZ (P : Fin 3 → R) : eval P W.polynomialZ = - P y ^ 2 + W.a₁ * P x * P y + 2 * W.a₃ * P y * P z - - (W.a₂ * P x ^ 2 + 2 * W.a₄ * P x * P z + 3 * W.a₆ * P z ^ 2) := by +lemma eval_polynomialZ (P : Fin 3 → R) : eval P W'.polynomialZ = + P y ^ 2 + W'.a₁ * P x * P y + 2 * W'.a₃ * P y * P z + - (W'.a₂ * P x ^ 2 + 2 * W'.a₄ * P x * P z + 3 * W'.a₆ * P z ^ 2) := by rw [polynomialZ_eq] eval_simp /-- Euler's homogeneous function theorem. -/ -theorem polynomial_relation (P : Fin 3 → R) : 3 * eval P W.polynomial = - P x * eval P W.polynomialX + P y * eval P W.polynomialY + P z * eval P W.polynomialZ := by +theorem polynomial_relation (P : Fin 3 → R) : 3 * eval P W'.polynomial = + P x * eval P W'.polynomialX + P y * eval P W'.polynomialY + P z * eval P W'.polynomialZ := by rw [eval_polynomial, eval_polynomialX, eval_polynomialY, eval_polynomialZ] ring1 -/-- The proposition that a point representative $(x, y, z)$ in `W` is nonsingular. -In other words, either $W_X(x, y, z) \ne 0$, $W_Y(x, y, z) \ne 0$, or $W_Z(x, y, z) \ne 0$. -/ +variable (W') in +/-- The proposition that a point representative $(x, y, z)$ in `W'` is nonsingular. +In other words, either $W_X(x, y, z) \ne 0$, $W_Y(x, y, z) \ne 0$, or $W_Z(x, y, z) \ne 0$. + +Note that this definition is only mathematically accurate for fields. -/ +-- TODO: generalise this definition to be mathematically accurate for a larger class of rings. def Nonsingular (P : Fin 3 → R) : Prop := - W.Equation P ∧ (eval P W.polynomialX ≠ 0 ∨ eval P W.polynomialY ≠ 0 ∨ eval P W.polynomialZ ≠ 0) + W'.Equation P ∧ + (eval P W'.polynomialX ≠ 0 ∨ eval P W'.polynomialY ≠ 0 ∨ eval P W'.polynomialZ ≠ 0) + +lemma nonsingular_iff (P : Fin 3 → R) : W'.Nonsingular P ↔ W'.Equation P ∧ + (W'.a₁ * P y * P z - (3 * P x ^ 2 + 2 * W'.a₂ * P x * P z + W'.a₄ * P z ^ 2) ≠ 0 ∨ + 2 * P y * P z + W'.a₁ * P x * P z + W'.a₃ * P z ^ 2 ≠ 0 ∨ + P y ^ 2 + W'.a₁ * P x * P y + 2 * W'.a₃ * P y * P z + - (W'.a₂ * P x ^ 2 + 2 * W'.a₄ * P x * P z + 3 * W'.a₆ * P z ^ 2) ≠ 0) := by + rw [Nonsingular, eval_polynomialX, eval_polynomialY, eval_polynomialZ] + +lemma nonsingular_smul (P : Fin 3 → R) {u : R} (hu : IsUnit u) : + W'.Nonsingular (u • P) ↔ W'.Nonsingular 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, ?_⟩ + contrapose! hP' + simp only [smul_fin3_ext] + 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⟩ + ⟨hP hu, fun h => hP hu.unit⁻¹.isUnit <| by rwa [smul_smul, hu.val_inv_mul, one_smul]⟩ -lemma nonsingular_iff (P : Fin 3 → R) : W.Nonsingular P ↔ W.Equation P ∧ - (W.a₁ * P y * P z ≠ 3 * P x ^ 2 + 2 * W.a₂ * P x * P z + W.a₄ * P z ^ 2 ∨ - P y * P z ≠ -P y * P z - W.a₁ * P x * P z - W.a₃ * P z ^ 2 ∨ - P y ^ 2 + W.a₁ * P x * P y + 2 * W.a₃ * P y * P z - ≠ W.a₂ * P x ^ 2 + 2 * W.a₄ * P x * P z + 3 * W.a₆ * P z ^ 2) := by - rw [Nonsingular, eval_polynomialX, eval_polynomialY, eval_polynomialZ, sub_ne_zero, sub_ne_zero, - ← sub_ne_zero (a := P y * P z)] - congr! 4 - ring1 +lemma nonsingular_of_equiv {P Q : Fin 3 → R} (h : P ≈ Q) : W'.Nonsingular P ↔ W'.Nonsingular Q := by + rcases h with ⟨u, rfl⟩ + exact nonsingular_smul Q u.isUnit + +lemma nonsingular_of_Z_eq_zero {P : Fin 3 → R} (hPz : P z = 0) : + W'.Nonsingular P ↔ + W'.Equation P ∧ (3 * P x ^ 2 ≠ 0 ∨ P y ^ 2 + W'.a₁ * P x * P y - W'.a₂ * P x ^ 2 ≠ 0) := by + simp only [nonsingular_iff, hPz, add_zero, sub_zero, zero_sub, mul_zero, + zero_pow <| OfNat.ofNat_ne_zero _, neg_ne_zero, ne_self_iff_false, false_or] + +lemma nonsingular_zero [Nontrivial R] : W'.Nonsingular ![0, 1, 0] := by + simp only [nonsingular_of_Z_eq_zero, equation_zero, true_and, fin3_def_ext, ← not_and_or] + exact fun h => one_ne_zero <| by linear_combination (norm := ring1) h.right + +lemma nonsingular_some (X Y : R) : W'.Nonsingular ![X, Y, 1] ↔ W'.toAffine.Nonsingular X Y := by + simp_rw [nonsingular_iff, equation_some, fin3_def_ext, Affine.nonsingular_iff', + Affine.equation_iff', and_congr_right_iff, ← not_and_or, not_iff_not, one_pow, mul_one, + and_congr_right_iff, Iff.comm, iff_self_and] + intro h hX hY + linear_combination (norm := ring1) 3 * h - X * hX - Y * hY -lemma nonsingular_zero [Nontrivial R] : W.Nonsingular ![0, 1, 0] := - (W.nonsingular_iff ![0, 1, 0]).mpr ⟨W.equation_zero 1, by simp⟩ +lemma nonsingular_of_Z_ne_zero {P : Fin 3 → F} (hPz : P z ≠ 0) : + W.Nonsingular P ↔ W.toAffine.Nonsingular (P x / P z) (P y / P z) := + (nonsingular_of_equiv <| equiv_some_of_Z_ne_zero hPz).trans <| nonsingular_some .. -lemma nonsingular_zero' [NoZeroDivisors R] {Y : R} (hy : Y ≠ 0) : W.Nonsingular ![0, Y, 0] := - (W.nonsingular_iff ![0, Y, 0]).mpr ⟨W.equation_zero Y, by simpa⟩ +lemma nonsingular_iff_of_Z_ne_zero {P : Fin 3 → F} (hPz : P z ≠ 0) : + W.Nonsingular P ↔ W.Equation P ∧ (eval P W.polynomialX ≠ 0 ∨ eval P W.polynomialY ≠ 0) := by + rw [nonsingular_of_Z_ne_zero hPz, Affine.Nonsingular, ← equation_of_Z_ne_zero hPz, + ← eval_polynomialX_of_Z_ne_zero hPz, div_ne_zero_iff, and_iff_left <| pow_ne_zero 2 hPz, + ← eval_polynomialY_of_Z_ne_zero hPz, div_ne_zero_iff, and_iff_left <| pow_ne_zero 2 hPz] -lemma nonsingular_some (X Y : R) : W.Nonsingular ![X, Y, 1] ↔ W.toAffine.Nonsingular X Y := by - rw [nonsingular_iff] - matrix_simp - simp only [W.toAffine.nonsingular_iff, equation_some, and_congr_right_iff, - W.toAffine.equation_iff, ← not_and_or, not_iff_not, one_pow, mul_one, Iff.comm, iff_self_and] - intro h hX hY - linear_combination (norm := ring1) 3 * h - X * hX - Y * hY +lemma Y_ne_zero_of_Z_eq_zero [NoZeroDivisors R] {P : Fin 3 → R} (hP : W'.Nonsingular P) + (hPz : P z = 0) : P y ≠ 0 := by + intro hPy + simp only [nonsingular_of_Z_eq_zero hPz, X_eq_zero_of_Z_eq_zero hP.left hPz, hPy, add_zero, + sub_zero, mul_zero, zero_pow two_ne_zero, or_self, ne_self_iff_false, and_false] at hP -lemma nonsingular_smul_iff (P : Fin 3 → R) (u : Rˣ) : W.Nonsingular (u • P) ↔ W.Nonsingular P := - have (u : Rˣ) {P : Fin 3 → R} (h : W.Nonsingular <| u • P) : W.Nonsingular P := by - rcases (W.nonsingular_iff _).mp h with ⟨h, h'⟩ - refine (W.nonsingular_iff P).mpr ⟨(W.equation_smul_iff P u).mp h, ?_⟩ - contrapose! h' - simp only [smul_fin3_ext] - exact ⟨by linear_combination (norm := ring1) (u : R) ^ 2 * h'.left, - by linear_combination (norm := ring1) (u : R) ^ 2 * h'.right.left, - by linear_combination (norm := ring1) (u : R) ^ 2 * h'.right.right⟩ - ⟨this u, fun h => this u⁻¹ <| by rwa [inv_smul_smul]⟩ +lemma isUnit_Y_of_Z_eq_zero {P : Fin 3 → F} (hP : W.Nonsingular P) (hPz : P z = 0) : IsUnit (P y) := + (Y_ne_zero_of_Z_eq_zero hP hPz).isUnit -lemma nonsingular_of_equiv {P Q : Fin 3 → R} (h : P ≈ Q) : W.Nonsingular P ↔ W.Nonsingular Q := by - rcases h with ⟨u, rfl⟩ - exact W.nonsingular_smul_iff Q u +lemma equiv_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) : P ≈ Q := by + use (isUnit_Y_of_Z_eq_zero hP hPz).unit / (isUnit_Y_of_Z_eq_zero hQ hQz).unit + simp only [Units.smul_def, smul_fin3, X_eq_zero_of_Z_eq_zero hQ.left hQz, hQz, mul_zero, + Units.val_div_eq_div_val, IsUnit.unit_spec, (isUnit_Y_of_Z_eq_zero hQ hQz).div_mul_cancel] + conv_rhs => rw [← fin3_def P, X_eq_zero_of_Z_eq_zero hP.left hPz, hPz] -/-- The proposition that a point class on `W` is nonsingular. If `P` is a point representative, +lemma equiv_zero_of_Z_eq_zero {P : Fin 3 → F} (hP : W.Nonsingular P) (hPz : P z = 0) : + P ≈ ![0, 1, 0] := + equiv_of_Z_eq_zero hP nonsingular_zero hPz rfl + +variable (W') in +/-- The proposition that a point class on `W'` is nonsingular. If `P` is a point representative, then `W.NonsingularLift ⟦P⟧` is definitionally equivalent to `W.Nonsingular P`. -/ def NonsingularLift (P : PointClass R) : Prop := - P.lift W.Nonsingular fun _ _ => propext ∘ W.nonsingular_of_equiv + P.lift W'.Nonsingular fun _ _ => propext ∘ nonsingular_of_equiv -@[simp] -lemma nonsingularLift_iff (P : Fin 3 → R) : W.NonsingularLift ⟦P⟧ ↔ W.Nonsingular P := +lemma nonsingularLift_iff (P : Fin 3 → R) : W'.NonsingularLift ⟦P⟧ ↔ W'.Nonsingular P := Iff.rfl -lemma nonsingularLift_zero [Nontrivial R] : W.NonsingularLift ⟦![0, 1, 0]⟧ := - W.nonsingular_zero - -lemma nonsingularLift_zero' [NoZeroDivisors R] {Y : R} (hy : Y ≠ 0) : - W.NonsingularLift ⟦![0, Y, 0]⟧ := - W.nonsingular_zero' hy +lemma nonsingularLift_zero [Nontrivial R] : W'.NonsingularLift ⟦![0, 1, 0]⟧ := + nonsingular_zero lemma nonsingularLift_some (X Y : R) : - W.NonsingularLift ⟦![X, Y, 1]⟧ ↔ W.toAffine.Nonsingular X Y := - W.nonsingular_some X Y + W'.NonsingularLift ⟦![X, Y, 1]⟧ ↔ W'.toAffine.Nonsingular X Y := + nonsingular_some X Y -variable {F : Type u} [Field F] {W : Projective F} +end Nonsingular -lemma equiv_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) : P ≈ Q := by - rw [fin3_def P, hPz] at hP ⊢ - rw [fin3_def Q, hQz] at hQ ⊢ - simp? [nonsingular_iff, equation_iff] at hP hQ says - simp only [Nat.succ_eq_add_one, Nat.reduceAdd, Fin.isValue, nonsingular_iff, - equation_iff, Matrix.cons_val_one, Matrix.head_cons, Matrix.cons_val_two, Matrix.tail_cons, - mul_zero, Matrix.cons_val_zero, add_zero, ne_eq, OfNat.ofNat_ne_zero, not_false_eq_true, - zero_pow, zero_eq_mul, pow_eq_zero_iff, not_or, sub_self, not_true_eq_false, false_or] - at hP hQ - simp? [pow_eq_zero hP.left.symm, pow_eq_zero hQ.left.symm] at * says - simp only [Fin.isValue, pow_eq_zero hP.left.symm, ne_eq, OfNat.ofNat_ne_zero, - not_false_eq_true, zero_pow, not_true_eq_false, and_false, mul_zero, zero_mul, add_zero, - pow_eq_zero_iff, false_or, true_and, pow_eq_zero hQ.left.symm, Nat.succ_eq_add_one, - Nat.reduceAdd] at * - exact ⟨Units.mk0 (P y / Q y) <| div_ne_zero hP hQ, by simp [div_mul_cancel₀ _ hQ]⟩ - -lemma equiv_zero_of_Z_eq_zero {P : Fin 3 → F} (h : W.Nonsingular P) (hPz : P z = 0) : - P ≈ ![0, 1, 0] := - equiv_of_Z_eq_zero h W.nonsingular_zero hPz rfl +@[deprecated (since := "2024-08-27")] alias equation_smul_iff := equation_smul +@[deprecated (since := "2024-08-27")] alias nonsingularLift_zero' := nonsingularLift_zero +@[deprecated (since := "2024-08-27")] +alias nonsingular_affine_of_Z_ne_zero := nonsingular_of_Z_ne_zero +@[deprecated (since := "2024-08-27")] +alias nonsingular_iff_affine_of_Z_ne_zero := nonsingular_of_Z_ne_zero +@[deprecated (since := "2024-08-27")] +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 -lemma equiv_some_of_Z_ne_zero {P : Fin 3 → F} (hPz : P z ≠ 0) : P ≈ ![P x / P z, P y / P z, 1] := - ⟨Units.mk0 _ hPz, by simp [← fin3_def P, mul_div_cancel₀ _ hPz]⟩ +section Negation -lemma nonsingular_iff_affine_of_Z_ne_zero {P : Fin 3 → F} (hPz : P z ≠ 0) : - W.Nonsingular P ↔ W.toAffine.Nonsingular (P x / P z) (P y / P z) := - (W.nonsingular_of_equiv <| equiv_some_of_Z_ne_zero hPz).trans <| W.nonsingular_some .. +/-! ### Negation formulae -/ -lemma nonsingular_of_affine_of_Z_ne_zero {P : Fin 3 → F} - (h : W.toAffine.Nonsingular (P x / P z) (P y / P z)) (hPz : P z ≠ 0) : W.Nonsingular P := - (nonsingular_iff_affine_of_Z_ne_zero hPz).mpr h +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 nonsingular_affine_of_Z_ne_zero {P : Fin 3 → F} (h : W.Nonsingular P) (hPz : P z ≠ 0) : - W.toAffine.Nonsingular (P x / P z) (P y / P z) := - (nonsingular_iff_affine_of_Z_ne_zero hPz).mp h +lemma negY_eq (X Y Z : R) : W'.negY ![X, Y, Z] = -Y - W'.a₁ * X - W'.a₃ * Z := + rfl -end Equation +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 end WeierstrassCurve.Projective diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/VariableChange.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/VariableChange.lean new file mode 100644 index 0000000000000..8f77cea60aaad --- /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' 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 91aaaac6fed72..c58bde48fa4db 100644 --- a/Mathlib/AlgebraicGeometry/FunctionField.lean +++ b/Mathlib/AlgebraicGeometry/FunctionField.lean @@ -17,7 +17,7 @@ This is a field when the scheme is integral. function field. This map is injective. -/ --- Explicit universe annotations were used in this file to improve perfomance #12737 +-- Explicit universe annotations were used in this file to improve performance #12737 universe u v @@ -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,7 +47,7 @@ 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 @@ -56,22 +56,22 @@ noncomputable instance [IsIntegral X] : Field X.functionField := by · 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] : @@ -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] : @@ -148,7 +148,8 @@ theorem functionField_isFractionRing_of_isAffineOpen [IsIntegral X] (U : X.Opens @isIntegral_of_isAffine_of_isDomain _ _ _ (by rw [Scheme.Opens.toScheme_presheaf_obj, Opens.openEmbedding_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 298135400e8a8..c046a874c7a02 100644 --- a/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean +++ b/Mathlib/AlgebraicGeometry/GammaSpecAdjunction.lean @@ -30,7 +30,7 @@ case the unit and the counit would switch to each other. -/ --- Explicit universe annotations were used in this file to improve perfomance #12737 +-- Explicit universe annotations were used in this file to improve performance #12737 noncomputable section @@ -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,16 +184,13 @@ 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] @@ -254,9 +254,8 @@ theorem comp_ring_hom_ext {X : LocallyRingedSpace.{u}} {R : CommRingCat.{u}} {f /-- `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 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,24 +268,15 @@ 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.val.c.app (op ⊤)) (X.toΓSpecFun x) = Y.toΓSpecFun (f.val.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), ← + -- TODO: this instance was found automatically before #6045 + have := @AlgebraicGeometry.LocallyRingedSpace.isLocalRingHomStalkMap X Y + 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] @@ -314,22 +304,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 @@ -375,14 +364,15 @@ lemma toOpen_comp_locallyRingedSpaceAdjunction_homEquiv_app rfl /-- 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 } - counit := (NatIso.op Scheme.SpecΓIdentity.{u}).inv - homEquiv_unit := rfl - homEquiv_counit := rfl +def adjunction : Scheme.Γ.rightOp ⊣ Scheme.Spec.{u} := + Adjunction.mk' { + homEquiv := fun X Y ↦ locallyRingedSpaceAdjunction.{u}.homEquiv X.toLocallyRingedSpace Y + unit := + { app := fun X ↦ locallyRingedSpaceAdjunction.{u}.unit.app X.toLocallyRingedSpace + naturality := fun _ _ f ↦ locallyRingedSpaceAdjunction.{u}.unit.naturality f } + counit := (NatIso.op Scheme.SpecΓIdentity.{u}).inv + homEquiv_unit := rfl + homEquiv_counit := rfl } theorem adjunction_homEquiv_apply {X : Scheme} {R : CommRingCatᵒᵖ} (f : (op <| Scheme.Γ.obj <| op X) ⟶ R) : @@ -403,14 +393,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 +411,72 @@ instance isIso_adjunction_counit : IsIso ΓSpec.adjunction.counit := by rw [adjunction_counit_app] infer_instance +end ΓSpec + +@[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..a2543e35ee753 100644 --- a/Mathlib/AlgebraicGeometry/Gluing.lean +++ b/Mathlib/AlgebraicGeometry/Gluing.lean @@ -239,7 +239,7 @@ theorem isOpen_iff (U : Set D.glued.carrier) : IsOpen U ↔ ∀ i, IsOpen ((D.ι rw [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. -/ diff --git a/Mathlib/AlgebraicGeometry/Modules/Tilde.lean b/Mathlib/AlgebraicGeometry/Modules/Tilde.lean index 39f6878821861..d4c07982358ac 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,9 +20,15 @@ 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. +## 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`. + -/ universe u @@ -136,39 +144,114 @@ def tildeInType : Sheaf (Type u) (PrimeSpectrum.Top R) := instance (U : (Opens (PrimeSpectrum.Top R))ᵒᵖ) : AddCommGroup (M.tildeInType.1.obj U) := - inferInstanceAs $ AddCommGroup (Tilde.sectionsSubmodule M 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 + +end Tilde end ModuleCat diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Affine.lean b/Mathlib/AlgebraicGeometry/Morphisms/Affine.lean index e4979dd055a15..c990b0ee818d7 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Affine.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Affine.lean @@ -122,12 +122,11 @@ 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] - apply (config := { allowSynthFailures := true }) IsIso.comp_isIso + 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] diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean b/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean index e92624a6197d0..9b5b16f7d5f16 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Basic.lean @@ -108,7 +108,7 @@ Also see `IsLocalAtTarget.mk'` for a convenient constructor. class IsLocalAtTarget (P : MorphismProperty Scheme) : Prop where /-- `P` respects isomorphisms. -/ respectsIso : P.RespectsIso := by infer_instance - /-- `P` holds for `f ∣_ U` for an open cover `U` of `Y` if and only if `P` holds for `f`. -/ + /-- `P` holds for `f ∣_ U` for an open cover `U` of `Y` if and only if `P` holds for `f`. -/ iff_of_openCover' : ∀ {X Y : Scheme.{u}} (f : X ⟶ Y) (𝒰 : Scheme.OpenCover.{u} Y), P f ↔ ∀ i, P (𝒰.pullbackHom f i) @@ -186,7 +186,7 @@ Also see `IsLocalAtSource.mk'` for a convenient constructor. class IsLocalAtSource (P : MorphismProperty Scheme) : Prop where /-- `P` respects isomorphisms. -/ respectsIso : P.RespectsIso := by infer_instance - /-- `P` holds for `f ∣_ U` for an open cover `U` of `Y` if and only if `P` holds for `f`. -/ + /-- `P` holds for `f ∣_ U` for an open cover `U` of `Y` if and only if `P` holds for `f`. -/ iff_of_openCover' : ∀ {X Y : Scheme.{u}} (f : X ⟶ Y) (𝒰 : Scheme.OpenCover.{u} X), P f ↔ ∀ i, P (𝒰.map i ≫ f) @@ -326,7 +326,7 @@ theorem respectsIso_mk {P : AffineTargetMorphismProperty} (h₂ : ∀ {X Y Z} (e : Y ≅ Z) (f : X ⟶ Y) [h : 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 +398,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 diff --git a/Mathlib/AlgebraicGeometry/Morphisms/ClosedImmersion.lean b/Mathlib/AlgebraicGeometry/Morphisms/ClosedImmersion.lean index 4affb2c6194ba..e0f201805fa3b 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/ClosedImmersion.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/ClosedImmersion.lean @@ -84,7 +84,7 @@ 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 @@ -95,11 +95,11 @@ theorem spec_of_surjective {R S : CommRingCat} (f : R ⟶ S) (h : Function.Surje 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. -/ diff --git a/Mathlib/AlgebraicGeometry/Morphisms/Constructors.lean b/Mathlib/AlgebraicGeometry/Morphisms/Constructors.lean index 91b9cb9c05db1..878d9b451bd27 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Constructors.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Constructors.lean @@ -251,12 +251,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.val.base x) + postcomp {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] diff --git a/Mathlib/AlgebraicGeometry/Morphisms/FinitePresentation.lean b/Mathlib/AlgebraicGeometry/Morphisms/FinitePresentation.lean new file mode 100644 index 0000000000000..d6dee82946a83 --- /dev/null +++ b/Mathlib/AlgebraicGeometry/Morphisms/FinitePresentation.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.AlgebraicGeometry.Morphisms.RingHomProperties +import Mathlib.RingTheory.RingHom.FinitePresentation + +/-! + +# Morphisms of finite presentation + +A morphism of schemes `f : X ⟶ Y` is locally of finite presentation if for each affine `U ⊆ Y` and +`V ⊆ f ⁻¹' U`, The induced map `Γ(Y, U) ⟶ Γ(X, V)` is of finite presentation. + +A morphism of schemes is of finite presentation if it is both locally of finite presentation and +quasi-compact. We do not provide a separate declaration for this, instead simply assume both +conditions. + +We show that these properties are local, and are stable under compositions. + +-/ + + +noncomputable section + +open CategoryTheory + +universe v u + +namespace AlgebraicGeometry + +variable {X Y : Scheme.{u}} (f : X ⟶ Y) + +/-- A morphism of schemes `f : X ⟶ Y` is locally of finite presentation if for each affine `U ⊆ Y` +and `V ⊆ f ⁻¹' U`, The induced map `Γ(Y, U) ⟶ Γ(X, V)` is of finite presentation. -/ +@[mk_iff] +class LocallyOfFinitePresentation : Prop where + finitePresentation_of_affine_subset : + ∀ (U : Y.affineOpens) (V : X.affineOpens) (e : V.1 ≤ f ⁻¹ᵁ U.1), + (f.appLE U V e).FinitePresentation + +instance : HasRingHomProperty @LocallyOfFinitePresentation RingHom.FinitePresentation where + isLocal_ringHomProperty := RingHom.finitePresentation_isLocal + eq_affineLocally' := by + ext X Y f + rw [locallyOfFinitePresentation_iff, affineLocally_iff_affineOpens_le] + +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] : + LocallyOfFinitePresentation (f ≫ g) := + MorphismProperty.comp_mem _ f g hf hg + +lemma locallyOfFinitePresentation_stableUnderBaseChange : + MorphismProperty.StableUnderBaseChange @LocallyOfFinitePresentation := + HasRingHomProperty.stableUnderBaseChange RingHom.finitePresentation_stableUnderBaseChange + +end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Morphisms/FiniteType.lean b/Mathlib/AlgebraicGeometry/Morphisms/FiniteType.lean index ffc351acd412a..4424a0eed0994 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) := diff --git a/Mathlib/AlgebraicGeometry/Morphisms/OpenImmersion.lean b/Mathlib/AlgebraicGeometry/Morphisms/OpenImmersion.lean index 8c02123e45620..3fc310d18e207 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/OpenImmersion.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/OpenImmersion.lean @@ -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..b9472fc3ea550 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/Preimmersion.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/Preimmersion.lean @@ -4,7 +4,7 @@ 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 /-! @@ -52,7 +52,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 diff --git a/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean b/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean index 211a07cc5edf0..cf3a6124cc51f 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean @@ -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 diff --git a/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean b/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean index 83373737cbce2..e9ffc71cd889f 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean @@ -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 @@ -353,7 +353,7 @@ 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 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 +361,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 855fcc83a8aa2..1a867be2b4d2a 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.lean @@ -4,7 +4,7 @@ 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 /-! @@ -55,7 +55,7 @@ We also provide the instances `P.IsMultiplicative`, `P.IsStableUnderComposition` -/ --- Explicit universe annotations were used in this file to improve perfomance #12737 +-- Explicit universe annotations were used in this file to improve performance #12737 universe u @@ -228,9 +228,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 @@ -281,18 +280,18 @@ instance : IsLocalAtSource P := by simp_rw [← HasAffineProperty.iff_of_isAffine (P := P), iff_of_source_openCover 𝒰.affineRefinement.openCover, fun i ↦ iff_of_source_openCover (P := P) (f := 𝒰.map i ≫ f) (𝒰.obj i).affineCover] - simp [Scheme.OpenCover.affineRefinement] + 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 +310,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 +338,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 diff --git a/Mathlib/AlgebraicGeometry/OpenImmersion.lean b/Mathlib/AlgebraicGeometry/OpenImmersion.lean index 17d4f6c368e33..70d24f7442e9b 100644 --- a/Mathlib/AlgebraicGeometry/OpenImmersion.lean +++ b/Mathlib/AlgebraicGeometry/OpenImmersion.lean @@ -12,7 +12,7 @@ import Mathlib.CategoryTheory.Limits.Shapes.Pullback.CommSq -/ --- Explicit universe annotations were used in this file to improve perfomance #12737 +-- Explicit universe annotations were used in this file to improve performance #12737 noncomputable section @@ -105,6 +105,12 @@ lemma preimage_image_eq (U : X.Opens) : f ⁻¹ᵁ f ''ᵁ U = U := by apply Opens.ext simp [Set.preimage_image_eq _ f.openEmbedding.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] @@ -209,7 +215,7 @@ theorem exists_affine_mem_range_and_range_subset ∃ (R : CommRingCat) (f : Spec R ⟶ X), IsOpenImmersion f ∧ x ∈ Set.range f.1.base ∧ Set.range f.1.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 := + 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 obtain ⟨_, ⟨_, ⟨r : R, rfl⟩, rfl⟩, hr, hr'⟩ := PrimeSpectrum.isBasis_basic_opens.exists_subset_of_mem_open this (Opens.is_open' _) @@ -431,7 +437,7 @@ 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 +445,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 diff --git a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean index a9bd9774ad781..f3fa7a4fbdf4a 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 @@ -207,21 +207,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,12 +237,10 @@ 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) @@ -266,29 +257,16 @@ theorem localization_comap_inducing [Algebra R S] (M : Submonoid R) [IsLocalizat exact ⟨_, rfl⟩ 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_embedding [Algebra R S] (M : Submonoid R) [IsLocalization M S] : Embedding (comap (algebraMap R S)) := ⟨localization_comap_inducing S M, localization_comap_injective S M⟩ theorem localization_comap_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 @@ -336,28 +314,12 @@ 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 @@ -391,7 +353,7 @@ def primeSpectrumProdHomeo : refine ((primeSpectrumProd R S).symm.toHomeomorphOfInducing ?_).symm refine (closedEmbedding_of_continuous_injective_closed ?_ (Equiv.injective _) ?_).toInducing · rw [continuous_sum_dom] - simp only [Function.comp, primeSpectrumProd_symm_inl, primeSpectrumProd_symm_inr] + simp only [Function.comp_def, primeSpectrumProd_symm_inl, primeSpectrumProd_symm_inr] exact ⟨(comap _).2, (comap _).2⟩ · rw [isClosedMap_sum] constructor @@ -693,3 +655,12 @@ 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 diff --git a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Noetherian.lean b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Noetherian.lean index 8e58796b933e2..7522a16f45dbe 100644 --- a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Noetherian.lean +++ b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Noetherian.lean @@ -19,11 +19,8 @@ open TopologicalSpace variable (R : Type u) [CommRing R] [IsNoetherianRing R] -instance : NoetherianSpace (PrimeSpectrum R) := by - apply ((noetherianSpace_TFAE <| PrimeSpectrum R).out 0 1).mpr - have H := ‹IsNoetherianRing R› - rw [isNoetherianRing_iff, isNoetherian_iff_wellFounded] at H - exact (closedsEmbedding R).dual.wellFounded H +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 diff --git a/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean index 5785868dc943e..567d07ccb66d0 100644 --- a/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean +++ b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Scheme.lean @@ -68,7 +68,7 @@ For a homogeneous element `f` of degree `m` defined by sending `x : Proj| (pbo f)` to `A⁰_f ∩ span {g / 1 | g ∈ x}`. We also denote this map as `ψ`. * `ProjIsoSpecTopComponent.ToSpec.preimage_eq`: for any `a: A`, if `a/f^m` has degree zero, - then the preimage of `sbo a/f^m` under `to_Spec f` is `pbo f ∩ pbo a`. + then the preimage of `sbo a/f^m` under `toSpec f` is `pbo f ∩ pbo a`. If we further assume `m` is positive * `ProjIsoSpecTopComponent.fromSpec`: the continuous map between `Spec.T A⁰_f` and `Proj.T| pbo f` @@ -88,7 +88,6 @@ Finally, * [Robin Hartshorne, *Algebraic Geometry*][Har77]: Chapter II.2 Proposition 2.5 -/ - noncomputable section @@ -160,7 +159,7 @@ open Ideal -- So for any `x` in `Proj| (pbo f)`, we need some point in `Spec A⁰_f`, i.e. a prime ideal, -- and we need this correspondence to be continuous in their Zariski topology. variable {𝒜} -variable {f : A} {m : ℕ} (f_deg : f ∈ 𝒜 m) (x : Proj| (pbo f)) +variable {f : A} {m : ℕ} (x : Proj| (pbo f)) /-- For any `x` in `Proj| (pbo f)`, the corresponding ideal in `Spec A⁰_f`. This fact that this ideal @@ -264,12 +263,13 @@ The set `{a | aᵢᵐ/fⁱ ∈ q}` * is prime, as proved in `carrier.asIdeal.prime`; * is relevant, as proved in `carrier.relevant`. -/ -def carrier (q : Spec.T A⁰_ f) : Set A := - {a | ∀ i, (HomogeneousLocalization.mk ⟨m * i, ⟨proj 𝒜 i a ^ m, by mem_tac⟩, +def carrier (f_deg : f ∈ 𝒜 m) (q : Spec.T A⁰_ f) : Set A := + {a | ∀ i, (HomogeneousLocalization.mk ⟨m * i, ⟨proj 𝒜 i a ^ m, by rw [← smul_eq_mul]; mem_tac⟩, ⟨f ^ i, by rw [mul_comm]; mem_tac⟩, ⟨_, rfl⟩⟩ : A⁰_ f) ∈ q.1} theorem mem_carrier_iff (q : Spec.T A⁰_ f) (a : A) : - a ∈ carrier f_deg q ↔ ∀ i, (HomogeneousLocalization.mk ⟨m * i, ⟨proj 𝒜 i a ^ m, by mem_tac⟩, + a ∈ carrier f_deg q ↔ ∀ i, (HomogeneousLocalization.mk ⟨m * i, ⟨proj 𝒜 i a ^ m, by + rw [← smul_eq_mul]; mem_tac⟩, ⟨f ^ i, by rw [mul_comm]; mem_tac⟩, ⟨_, rfl⟩⟩ : A⁰_ f) ∈ q.1 := Iff.rfl @@ -291,7 +291,7 @@ theorem mem_carrier_iff_of_mem (hm : 0 < m) (q : Spec.T A⁰_ f) (a : A) {n} (hn a ∈ carrier f_deg q ↔ (HomogeneousLocalization.mk ⟨m * n, ⟨a ^ m, pow_mem_graded m hn⟩, ⟨f ^ n, by rw [mul_comm]; mem_tac⟩, ⟨_, rfl⟩⟩ : A⁰_ f) ∈ q.asIdeal := by - trans (HomogeneousLocalization.mk ⟨m * n, ⟨proj 𝒜 n a ^ m, by mem_tac⟩, + trans (HomogeneousLocalization.mk ⟨m * n, ⟨proj 𝒜 n a ^ m, by rw [← smul_eq_mul]; mem_tac⟩, ⟨f ^ n, by rw [mul_comm]; mem_tac⟩, ⟨_, rfl⟩⟩ : A⁰_ f) ∈ q.asIdeal · refine ⟨fun h ↦ h n, fun h i ↦ if hi : i = n then hi ▸ h else ?_⟩ convert zero_mem q.asIdeal @@ -338,12 +338,12 @@ theorem carrier.add_mem (q : Spec.T A⁰_ f) {a b : A} (ha : a ∈ carrier f_deg ⟨m * i, ⟨proj 𝒜 i a ^ j * proj 𝒜 i b ^ (m - j), ?_⟩, ⟨_, by rw [mul_comm]; mem_tac⟩, ⟨i, rfl⟩⟩ letI r : A⁰_ f := HomogeneousLocalization.mk - ⟨m * i, ⟨proj 𝒜 i b ^ m, by mem_tac⟩, + ⟨m * i, ⟨proj 𝒜 i b ^ m, by rw [← smul_eq_mul]; mem_tac⟩, ⟨_, by rw [mul_comm]; mem_tac⟩, ⟨i, rfl⟩⟩ l * r else letI l : A⁰_ f := HomogeneousLocalization.mk - ⟨m * i, ⟨proj 𝒜 i a ^ m, by mem_tac⟩, + ⟨m * i, ⟨proj 𝒜 i a ^ m, by rw [← smul_eq_mul]; mem_tac⟩, ⟨_, by rw [mul_comm]; mem_tac⟩, ⟨i, rfl⟩⟩ letI r : A⁰_ f := HomogeneousLocalization.mk ⟨m * i, ⟨proj 𝒜 i a ^ (j - m) * proj 𝒜 i b ^ (m + m - j), ?_⟩, @@ -402,7 +402,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 @@ -523,14 +523,15 @@ end fromSpecToSpec namespace toSpec variable {f : A} {m : ℕ} (f_deg : f ∈ 𝒜 m) (hm : 0 < m) -include hm +include hm f_deg variable {𝒜} in lemma image_basicOpen_eq_basicOpen (a : A) (i : ℕ) : toSpec 𝒜 f '' (Subtype.val ⁻¹' (pbo (decompose 𝒜 a i) : Set (ProjectiveSpectrum 𝒜))) = (PrimeSpectrum.basicOpen (R := A⁰_ f) <| HomogeneousLocalization.mk - ⟨m * i, ⟨decompose 𝒜 a i ^ m, SetLike.pow_mem_graded _ (Submodule.coe_mem _)⟩, + ⟨m * i, ⟨decompose 𝒜 a i ^ m, + (smul_eq_mul ℕ) ▸ SetLike.pow_mem_graded _ (Submodule.coe_mem _)⟩, ⟨f^i, by rw [mul_comm]; exact SetLike.pow_mem_graded _ f_deg⟩, ⟨i, rfl⟩⟩).1 := Set.preimage_injective.mpr (toSpec_surjective 𝒜 f_deg hm) <| Set.preimage_image_eq _ (toSpec_injective 𝒜 f_deg hm) ▸ by @@ -593,9 +594,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 @@ -684,9 +685,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 /-- @@ -805,7 +806,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..e6fe728b2d042 100644 --- a/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/StructureSheaf.lean +++ b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/StructureSheaf.lean @@ -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/ProjectiveSpectrum/Topology.lean b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Topology.lean index 85a2d1adb6373..634828aaafdef 100644 --- a/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Topology.lean +++ b/Mathlib/AlgebraicGeometry/ProjectiveSpectrum/Topology.lean @@ -11,7 +11,7 @@ import Mathlib.Data.Set.Subsingleton /-! # Projective spectrum of a graded ring -The projective spectrum of a graded commutative ring is the subtype of all homogenous ideals that +The projective spectrum of a graded commutative ring is the subtype of all homogeneous ideals that are prime and do not contain the irrelevant ideal. It is naturally endowed with a topology: the Zariski topology. @@ -45,7 +45,7 @@ variable [CommSemiring R] [CommRing A] [Algebra R A] variable (𝒜 : ℕ → Submodule R A) [GradedAlgebra 𝒜] -- porting note (#5171): removed @[nolint has_nonempty_instance] -/-- The projective spectrum of a graded commutative ring is the subtype of all homogenous ideals +/-- The projective spectrum of a graded commutative ring is the subtype of all homogeneous ideals that are prime and do not contain the irrelevant ideal. -/ @[ext] structure ProjectiveSpectrum where @@ -126,7 +126,7 @@ theorem gc_set : @GaloisConnection (Set A) (Set (ProjectiveSpectrum 𝒜))ᵒᵈ _ _ (fun s => zeroLocus 𝒜 s) fun t => vanishingIdeal t := by have ideal_gc : GaloisConnection Ideal.span _ := (Submodule.gi A _).gc - simpa [zeroLocus_span, Function.comp] using GaloisConnection.compose ideal_gc (gc_ideal 𝒜) + simpa [zeroLocus_span, Function.comp_def] using GaloisConnection.compose ideal_gc (gc_ideal 𝒜) theorem gc_homogeneousIdeal : @GaloisConnection (HomogeneousIdeal 𝒜) (Set (ProjectiveSpectrum 𝒜))ᵒᵈ _ _ diff --git a/Mathlib/AlgebraicGeometry/Properties.lean b/Mathlib/AlgebraicGeometry/Properties.lean index 472fdb1fdecb5..626ba8ab0aecf 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 @@ -22,7 +19,7 @@ We provide some basic properties of schemes -/ --- Explicit universe annotations were used in this file to improve perfomance #12737 +-- Explicit universe annotations were used in this file to improve performance #12737 universe u @@ -59,9 +56,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 +66,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 +113,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 @@ -144,28 +139,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 +235,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..1b43cf9c18bfd 100644 --- a/Mathlib/AlgebraicGeometry/Pullbacks.lean +++ b/Mathlib/AlgebraicGeometry/Pullbacks.lean @@ -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`. -/ @@ -507,7 +507,7 @@ def openCoverOfBase' (𝒰 : OpenCover Z) (f : X ⟶ Z) (g : Y ⟶ Z) : OpenCove pasteVertIsPullback rfl (pullbackIsPullback g (𝒰.map i)) (pullbackIsPullback (pullback.snd g (𝒰.map i)) (pullback.snd f (𝒰.map i))) refine - @openCoverOfIsIso + @openCoverOfIsIso _ _ (f := (pullbackSymmetry _ _).hom ≫ (limit.isoLimitCone ⟨_, this⟩).inv ≫ pullback.map _ _ _ _ (𝟙 _) (𝟙 _) (𝟙 _) ?_ ?_) inferInstance · simp [← pullback.condition] @@ -583,7 +583,8 @@ 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 diff --git a/Mathlib/AlgebraicGeometry/ResidueField.lean b/Mathlib/AlgebraicGeometry/ResidueField.lean new file mode 100644 index 0000000000000..1649e31a1b5e3 --- /dev/null +++ b/Mathlib/AlgebraicGeometry/ResidueField.lean @@ -0,0 +1,187 @@ +/- +Copyright (c) 2024 Andrew Yang. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Andrew Yang +-/ +import Mathlib.Geometry.RingedSpace.LocallyRingedSpace.ResidueField +import Mathlib.AlgebraicGeometry.Stalk + +/-! + +# 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`. + +-/ + +universe u + +open CategoryTheory TopologicalSpace Opposite + +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 _ + +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 `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 + +variable {X Y : Scheme.{u}} (f : X ⟶ Y) + + +-- TODO: This instance is found before #6045. +-- We need this strange instance for `residueFieldMap`, the type of `F` must be fixed +-- like this. The instance `IsLocalRingHom (f.stalkMap x)` already exists, but does not work for +-- `residueFieldMap`. +instance (x): IsLocalRingHom (F := Y.presheaf.stalk (f.val.base x) →+* X.presheaf.stalk x) + (f.stalkMap x) := + f.2 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 Hom.residueFieldMap (f : X.Hom Y) (x : X) : + Y.residueField (f.val.base x) ⟶ X.residueField x := + LocalRing.ResidueField.map (f.stalkMap x) + +@[reassoc] +lemma residue_residueFieldMap (x : X) : + Y.residue (f.val.base x) ≫ f.residueFieldMap x = f.stalkMap x ≫ X.residue x := by + 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.val.base x) ≫ f.residueFieldMap x := + LocallyRingedSpace.residueFieldMap_comp _ _ _ + +@[reassoc] +lemma evaluation_naturality {V : Opens Y} (x : X) (hx : f.val.base x ∈ V) : + Y.evaluation V (f.val.base x) hx ≫ f.residueFieldMap x = + f.app V ≫ X.evaluation (f ⁻¹ᵁ V) x hx := + LocallyRingedSpace.evaluation_naturality f ⟨x, hx⟩ + +lemma evaluation_naturality_apply {V : Opens Y} (x : X) (hx : f.val.base x ∈ V) (s) : + f.residueFieldMap x (Y.evaluation V (f.val.base x) hx s) = + X.evaluation (f ⁻¹ᵁ V) x hx (f.app V s) := + LocallyRingedSpace.evaluation_naturality_apply f ⟨x, hx⟩ s + +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 + +end congr + +section fromResidueField + +/-- The canonical map `Spec κ(x) ⟶ X`. -/ +def fromSpecResidueField (X : Scheme) (x : X) : + Spec (X.residueField x) ⟶ X := + Spec.map (CommRingCat.ofHom (X.residue x)) ≫ X.fromSpecStalk x + +@[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 + +end fromResidueField + +end Scheme + +end AlgebraicGeometry diff --git a/Mathlib/AlgebraicGeometry/Restrict.lean b/Mathlib/AlgebraicGeometry/Restrict.lean index f1bb6aca5465c..d4c45b8f826f4 100644 --- a/Mathlib/AlgebraicGeometry/Restrict.lean +++ b/Mathlib/AlgebraicGeometry/Restrict.lean @@ -17,7 +17,7 @@ import Mathlib.AlgebraicGeometry.Cover.Open -/ --- Explicit universe annotations were used in this file to improve perfomance #12737 +-- Explicit universe annotations were used in this file to improve performance #12737 noncomputable section @@ -69,7 +69,7 @@ lemma ι_appLE (V W e) : U.ι.appLE V W e = X.presheaf.map (homOfLE (x := U.ι ''ᵁ W) (Set.image_subset_iff.mpr ‹_›)).op := by simp only [Hom.appLE, ι_app, Functor.op_obj, Opens.carrier_eq_coe, toScheme_presheaf_map, - Quiver.Hom.unop_op, Hom.opensFunctor_map_homOfLE, Opens.coe_inclusion, ← Functor.map_comp] + Quiver.Hom.unop_op, Hom.opensFunctor_map_homOfLE, Opens.coe_inclusion', ← Functor.map_comp] rfl @[simp] @@ -87,9 +87,13 @@ lemma range_ι : Set.range U.ι.val.base = U := lemma ι_image_top : U.ι ''ᵁ ⊤ = U := U.openEmbedding_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 = ⊤ := - Opens.inclusion_map_eq_top _ + Opens.inclusion'_map_eq_top _ instance ι_appLE_isIso : IsIso (U.ι.appLE U ⊤ U.ι_preimage_self.ge) := by @@ -121,22 +125,15 @@ def stalkIso {X : Scheme.{u}} (U : X.Opens) (x : U) : @[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⟩⟩ := + {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.openEmbedding _ _ _ -@[simp, reassoc] +@[reassoc] lemma germ_stalkIso_inv {X : Scheme.{u}} (U : X.Opens) (V : U.toScheme.Opens) (x : U) - (hx : x ∈ V) : X.presheaf.germ ⟨x.val, show x.val ∈ U.ι ''ᵁ V from ⟨x, hx, rfl⟩⟩ ≫ - (U.stalkIso x).inv = U.toScheme.presheaf.germ ⟨x, hx⟩ := + (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.openEmbedding V x hx end Scheme.Opens @@ -173,7 +170,7 @@ 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] + rw [← Scheme.basicOpen_res_eq _ _ (eqToHom U.openEmbedding_obj_top).op] rw [← comp_apply, ← CategoryTheory.Functor.map_comp, ← op_comp, eqToHom_trans, eqToHom_refl, op_id, CategoryTheory.Functor.map_id] congr @@ -216,8 +213,10 @@ 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 +/-- This is not a `simp` lemma, as `(X.restricFunctor.map i).left` is used as the `simp` +normal-form for the induced morphism `U.toScheme ⟶ V.toScheme`. -/ +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] @@ -234,7 +233,7 @@ theorem Scheme.restrictFunctor_map_base {U V : X.Opens} (i : U ⟶ V) : 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] + Scheme.restrictFunctor_map_base, Opens.map_coe, Opens.inclusion'_apply] rintro _ h exact ⟨_, h, rfl⟩ @@ -258,7 +257,7 @@ def Scheme.restrictFunctorΓ : X.restrictFunctor.op ⋙ (Over.forget X).op ⋙ S (fun U => X.presheaf.mapIso ((eqToIso (unop U).openEmbedding_obj_top).symm.op : _)) (by intro U V i - dsimp [-Scheme.restrictFunctor_map_left] + dsimp rw [X.restrictFunctor_map_app, ← Functor.map_comp, ← Functor.map_comp] congr 1) @@ -466,7 +465,7 @@ def morphismRestrictRestrict {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) (V : refine Arrow.isoMk' _ _ (Scheme.restrictRestrict _ _ _ ≪≫ Scheme.restrictIsoOfEq _ ?_) (Scheme.restrictRestrict _ _ _) ?_ · ext x - simp only [IsOpenMap.functor_obj_coe, Opens.coe_inclusion, + simp only [IsOpenMap.functor_obj_coe, Opens.coe_inclusion', Opens.map_coe, Set.mem_image, Set.mem_preimage, SetLike.mem_coe, morphismRestrict_val_base] constructor · rintro ⟨⟨a, h₁⟩, h₂, rfl⟩ @@ -480,7 +479,7 @@ def morphismRestrictRestrict {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) (V : Scheme.restrictRestrict_hom_restrict, morphismRestrict_ι_assoc, morphismRestrict_ι] -/-- Restricting a morphism twice onto a basic open set is isomorphic to one restriction. -/ +/-- 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)) ≅ @@ -488,7 +487,7 @@ def morphismRestrictRestrictBasicOpen {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Op refine morphismRestrictRestrict _ _ _ ≪≫ morphismRestrictEq _ ?_ have e := Scheme.preimage_basicOpen U.ι r rw [Scheme.Opens.ι_app] at e - rw [← U.toScheme.basicOpen_res_eq _ (eqToHom U.inclusion_map_eq_top).op] + rw [← U.toScheme.basicOpen_res_eq _ (eqToHom U.inclusion'_map_eq_top).op] erw [← comp_apply] erw [← Y.presheaf.map_comp] rw [eqToHom_op, eqToHom_op, eqToHom_map, eqToHom_trans] @@ -508,13 +507,87 @@ def morphismRestrictStalkMap {X Y : Scheme.{u}} (f : X ⟶ Y) (U : Y.Opens) (x) 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.restrictFunctor.map (homOfLE e)).left ≫ f ∣_ U + +variable (f : X ⟶ Y) {U U' : Y.Opens} {V V' : X.Opens} (e : V ≤ f ⁻¹ᵁ U) + +lemma resLE_eq_morphismRestrict : f.resLE U (f ⁻¹ᵁ U) le_rfl = f ∣_ U := by + simp [Scheme.Hom.resLE] + +lemma resLE_id (i : V ⟶ V') : resLE (𝟙 X) V' V i.le = (X.restrictFunctor.map i).left := by + simp only [resLE, id_val_base, morphismRestrict_id, Category.comp_id] + rfl + +@[reassoc (attr := simp)] +lemma resLE_comp_ι : f.resLE U V e ≫ U.ι = V.ι ≫ f := by + simp [resLE, restrictFunctor_map_ofRestrict_assoc] + +@[reassoc] +lemma resLE_comp_resLE {Z : Scheme.{u}} (g : Y ⟶ Z) {W : Z.Opens} (e') : + f.resLE U V e ≫ g.resLE W U e' = (f ≫ g).resLE W V + (e.trans ((Opens.map f.val.base).map (homOfLE e')).le) := by + simp [← cancel_mono W.ι] + +@[reassoc (attr := simp)] +lemma map_resLE (i : V' ⟶ V) : + (X.restrictFunctor.map i).left ≫ f.resLE U V e = f.resLE U V' (i.le.trans e) := by + simp_rw [← resLE_id, resLE_comp_resLE, Category.id_comp] + +@[reassoc (attr := simp)] +lemma resLE_map (i : U ⟶ U') : + f.resLE U V e ≫ (Y.restrictFunctor.map i).left = + f.resLE U' V (e.trans ((Opens.map f.1.base).map i).le) := by + 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 [Scheme.Hom.appLE, Scheme.Hom.resLE, Scheme.restrictFunctor_map_left, Opens.map_coe, + id_eq, Scheme.comp_app, morphismRestrict_app', Category.assoc, IsOpenImmersion.lift_app, + Scheme.Opens.ι_appIso, Scheme.Opens.ι_app, Scheme.Opens.toScheme_presheaf_map, Category.assoc] + rw [← X.presheaf.map_comp, ← X.presheaf.map_comp] + erw [Category.id_comp] + rw [← 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 +604,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 93d4ae918f332..7714e1f80579c 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 @@ -18,7 +18,7 @@ A morphism of schemes is just a morphism of the underlying locally ringed spaces -/ --- Explicit universe annotations were used in this file to improve perfomance #12737 +-- Explicit universe annotations were used in this file to improve performance #12737 universe u @@ -165,6 +165,10 @@ lemma preimage_iSup {ι} (U : ι → Opens Y) : f ⁻¹ᵁ iSup U = ⨆ i, f ⁻ 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] @@ -446,22 +450,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 := @@ -554,7 +560,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)) @@ -664,28 +670,17 @@ lemma stalkMap_inv_hom_apply (e : X ≅ Y) (x : 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.val.base x ∈ U) : + Y.presheaf.germ U (f.val.base x) hx ≫ f.stalkMap x = + f.app U ≫ X.presheaf.germ (f ⁻¹ᵁ U) x hx := + PresheafedSpace.stalkMap_germ f.val 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.val.base x ∈ U) (y) : + f.stalkMap x (Y.presheaf.germ _ (f.val.base x) hx y) = + X.presheaf.germ (f ⁻¹ᵁ U) x hx (f.app U y) := + PresheafedSpace.stalkMap_germ_apply f.val U x hx y end Scheme diff --git a/Mathlib/AlgebraicGeometry/Spec.lean b/Mathlib/AlgebraicGeometry/Spec.lean index a18add389dda1..1defa7db8f0e8 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 @@ -33,7 +33,7 @@ The adjunction `Γ ⊣ Spec` is constructed in `Mathlib/AlgebraicGeometry/GammaS -/ --- Explicit universe annotations were used in this file to improve perfomance #12737 +-- Explicit universe annotations were used in this file to improve performance #12737 noncomputable section @@ -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 @@ -236,6 +238,8 @@ def Spec.locallyRingedSpaceMap {R S : CommRingCat.{u}} (f : R ⟶ S) : #adaptation_note /-- nightly-2024-04-01 It's this `erw` that is blowing up. The implicit arguments differ significantly. -/ erw [← localRingHom_comp_stalkIso_apply] at ha + -- TODO: this instance was found automatically before #6045 + haveI : IsLocalRingHom (stalkIso (↑S) p).inv := isLocalRingHom_of_isIso _ replace ha := (isUnit_map_iff (stalkIso S p).inv _).mp ha -- Porting note: `f` had to be made explicit replace ha := IsLocalRingHom.map_nonunit @@ -269,7 +273,7 @@ section SpecΓ open AlgebraicGeometry.LocallyRingedSpace -/-- The counit morphism `R ⟶ Γ(Spec R)` given by `AlgebraicGeometry.StructureSheaf.toOpen`. -/ +/-- The counit morphism `R ⟶ Γ(Spec R)` given by `AlgebraicGeometry.StructureSheaf.toOpen`. -/ @[simps!] def toSpecΓ (R : CommRingCat.{u}) : R ⟶ Γ.obj (op (Spec.toLocallyRingedSpace.obj (op R))) := StructureSheaf.toOpen R ⊤ @@ -306,8 +310,7 @@ theorem Spec_map_localization_isIso (R : CommRingCat.{u}) (M : Submonoid R) erw [← localRingHom_comp_stalkIso] -- Porting note: replaced `apply (config := { instances := false })`. -- See https://github.com/leanprover/lean4/issues/2273 - refine @IsIso.comp_isIso _ _ _ _ _ _ _ _ (?_) - refine @IsIso.comp_isIso _ _ _ _ _ _ _ (?_) _ + refine IsIso.comp_isIso' inferInstance (IsIso.comp_isIso' ?_ inferInstance) /- I do not know why this is defeq to the goal, but I'm happy to accept that it is. -/ show IsIso (IsLocalization.localizationLocalizationAtPrimeIsoLocalization M @@ -323,16 +326,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) := @@ -365,9 +366,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⟩ := @@ -378,10 +379,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 @@ -401,7 +402,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/Stalk.lean b/Mathlib/AlgebraicGeometry/Stalk.lean index 00a1dd8d05033..8865ed5e23d8f 100644 --- a/Mathlib/AlgebraicGeometry/Stalk.lean +++ b/Mathlib/AlgebraicGeometry/Stalk.lean @@ -24,7 +24,7 @@ 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 @@ -37,13 +37,13 @@ theorem IsAffineOpen.fromSpecStalk_eq {X : Scheme} (x : X) {U V : X.Opens} 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] + 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] 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] + 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] rw [← Functor.map_comp_assoc, ← op_comp, TopCat.Presheaf.germ_res, Scheme.Spec_map, Quiver.Hom.unop_op] diff --git a/Mathlib/AlgebraicGeometry/StructureSheaf.lean b/Mathlib/AlgebraicGeometry/StructureSheaf.lean index a145948515d7c..fcd5788d01906 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 @@ -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 @@ -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)) @@ -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) : IsLocalRingHom (stalkToFiberRingHom R x) := + isLocalRingHom_of_isIso _ + instance (x : PrimeSpectrum R) : IsIso (localizationToStalk R x) := (stalkIso R x).isIso_inv +instance (x : PrimeSpectrum R) : IsLocalRingHom (localizationToStalk R x) := + isLocalRingHom_of_isIso _ + @[simp, reassoc] theorem stalkToFiberRingHom_localizationToStalk (x : PrimeSpectrum.Top R) : stalkToFiberRingHom R x ≫ localizationToStalk R x = 𝟙 _ := @@ -567,8 +572,7 @@ 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 := (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⟩ @@ -799,9 +801,9 @@ theorem toBasicOpen_surjective (f : R) : Function.Surjective (toBasicOpen R f) : apply PrimeSpectrum.vanishingIdeal_anti_mono ht_cover exact PrimeSpectrum.subset_vanishingIdeal_zeroLocus {f} (Set.mem_singleton f) replace hn := Ideal.mul_mem_right f _ hn - erw [← pow_succ, Finsupp.mem_span_image_iff_total] at hn + erw [← pow_succ, Finsupp.mem_span_image_iff_linearCombination] at hn rcases hn with ⟨b, b_supp, hb⟩ - rw [Finsupp.total_apply_of_mem_supported R b_supp] at hb + rw [Finsupp.linearCombination_apply_of_mem_supported R b_supp] at hb dsimp at hb -- Finally, we have all the ingredients. -- We claim that our preimage is given by `(∑ (i : ι) ∈ t, b i * a i) / f ^ (n+1)` @@ -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. @@ -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..de7b73ca2ffc3 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 diff --git a/Mathlib/AlgebraicTopology/CechNerve.lean b/Mathlib/AlgebraicTopology/CechNerve.lean index 0f3fe3235d5db..5f4b8181e1ed0 100644 --- a/Mathlib/AlgebraicTopology/CechNerve.lean +++ b/Mathlib/AlgebraicTopology/CechNerve.lean @@ -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] @@ -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 _ diff --git a/Mathlib/AlgebraicTopology/DoldKan/Decomposition.lean b/Mathlib/AlgebraicTopology/DoldKan/Decomposition.lean index 768a35876f499..670d14d17f25a 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/Decomposition.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/Decomposition.lean @@ -52,7 +52,7 @@ theorem decomposition_Q (n q : ℕ) : ∑ i ∈ Finset.filter (fun i : Fin (n + 1) => (i : ℕ) < q) Finset.univ, (P i).f (n + 1) ≫ X.δ i.rev.succ ≫ X.σ (Fin.rev i) := by induction' q with q hq - · simp only [Nat.zero_eq, Q_zero, HomologicalComplex.zero_f_apply, Nat.not_lt_zero, + · simp only [Q_zero, HomologicalComplex.zero_f_apply, Nat.not_lt_zero, Finset.filter_False, Finset.sum_empty] · by_cases hqn : q + 1 ≤ n + 1 swap diff --git a/Mathlib/AlgebraicTopology/DoldKan/Degeneracies.lean b/Mathlib/AlgebraicTopology/DoldKan/Degeneracies.lean index dd949cbd7cb71..dde1b3dea55c9 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/Degeneracies.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/Degeneracies.lean @@ -49,7 +49,7 @@ theorem HigherFacesVanish.comp_σ {Y : C} {X : SimplicialObject C} {n b q : ℕ} linarith · intro hj' simp only [hnbq, add_comm b, add_assoc, hj', Fin.val_zero, zero_add, add_le_iff_nonpos_right, - nonpos_iff_eq_zero, add_eq_zero, false_and] at hj + nonpos_iff_eq_zero, add_eq_zero, false_and, reduceCtorEq] at hj theorem σ_comp_P_eq_zero (X : SimplicialObject C) {n q : ℕ} (i : Fin (n + 1)) (hi : n + 1 ≤ i + q) : X.σ i ≫ (P q).f (n + 1) = 0 := by @@ -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/Equivalence.lean b/Mathlib/AlgebraicTopology/DoldKan/Equivalence.lean index 59cf4f6cf84aa..72a3b619b766a 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/Equivalence.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/Equivalence.lean @@ -62,7 +62,7 @@ we define the functor in the other direction extension of a functor `Γ₀ : ChainComplex C ℕ ⥤ SimplicialObject C` which is defined similarly as in [*Simplicial Homotopy Theory* by Goerss-Jardine][goerss-jardine-2009]. In `Degeneracies.lean`, we show that `PInfty` vanishes on the image of degeneracy -operators, which is one of the key properties that makes it possible to contruct +operators, which is one of the key properties that makes it possible to construct the isomorphism `N₂Γ₂ : Γ₂ ⋙ N₂ ≅ 𝟭 (Karoubi (ChainComplex C ℕ))`. The rest of the proof follows the strategy in the [original paper by Dold][dold1958]. We show diff --git a/Mathlib/AlgebraicTopology/DoldKan/Faces.lean b/Mathlib/AlgebraicTopology/DoldKan/Faces.lean index a232a8b12caaf..845dd32f779d1 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/Faces.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/Faces.lean @@ -155,7 +155,7 @@ theorem comp_Hσ_eq_zero {Y : C} {n q : ℕ} {φ : Y ⟶ X _[n + 1]} (v : Higher omega · intro h simp only [Fin.pred, Fin.subNat, Fin.ext_iff, Nat.succ_add_sub_one, - Fin.val_zero, add_eq_zero, false_and] at h + Fin.val_zero, add_eq_zero, false_and, reduceCtorEq] at h · simp only [Fin.pred, Fin.subNat, Nat.pred_eq_sub_one, Nat.succ_add_sub_one] omega diff --git a/Mathlib/AlgebraicTopology/DoldKan/FunctorGamma.lean b/Mathlib/AlgebraicTopology/DoldKan/FunctorGamma.lean index 72511e140c0f6..67d99a2628ff5 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/FunctorGamma.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/FunctorGamma.lean @@ -148,7 +148,7 @@ theorem mapMono_comp (i' : Δ'' ⟶ Δ') (i : Δ' ⟶ Δ) [Mono i'] [Mono i] : have eq : Δ.len = Δ''.len + (k + k' + 2) := by omega rw [mapMono_eq_zero K (i' ≫ i) _ _]; rotate_left · by_contra h - simp only [self_eq_add_right, h, add_eq_zero, and_false] at eq + simp only [self_eq_add_right, h, add_eq_zero, and_false, reduceCtorEq] at eq · by_contra h simp only [h.1, add_right_inj] at eq omega diff --git a/Mathlib/AlgebraicTopology/DoldKan/HomotopyEquivalence.lean b/Mathlib/AlgebraicTopology/DoldKan/HomotopyEquivalence.lean index 08e001f128c59..ef91e2c166c8a 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/HomotopyEquivalence.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/HomotopyEquivalence.lean @@ -60,9 +60,9 @@ def homotopyPInftyToId : Homotopy (PInfty : K[X] ⟶ _) (𝟙 _) where comm n := by rcases n with _|n · simpa only [Homotopy.dNext_zero_chainComplex, Homotopy.prevD_chainComplex, - PInfty_f, Nat.zero_eq, P_f_0_eq, zero_add] using (homotopyPToId X 2).comm 0 + PInfty_f, P_f_0_eq, zero_add] using (homotopyPToId X 2).comm 0 · simp only [Homotopy.dNext_succ_chainComplex, Homotopy.prevD_chainComplex, - HomologicalComplex.id_f, PInfty_f, ← P_is_eventually_constant (rfl.le : n + 1 ≤ n + 1)] + HomologicalComplex.id_f, PInfty_f, ← P_is_eventually_constant (le_refl <| n + 1)] -- Porting note(lean4/2146): remaining proof was -- `simpa only [homotopyPToId_eventually_constant X (lt_add_one (Nat.succ n))] -- using (homotopyPToId X (n + 2)).comm (n + 1)`; diff --git a/Mathlib/AlgebraicTopology/DoldKan/NReflectsIso.lean b/Mathlib/AlgebraicTopology/DoldKan/NReflectsIso.lean index 45f68a713e024..ff1f2cf7b3dbd 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/NReflectsIso.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/NReflectsIso.lean @@ -48,15 +48,17 @@ instance : (N₁ : SimplicialObject C ⥤ Karoubi (ChainComplex C ℕ)).Reflects AlternatingFaceMapComplex.map_f, N₁_obj_p, Karoubi.id_f, assoc] at h₁ h₂ h₃ -- we have to construct an inverse to f in degree n, by induction on n intro n - induction' n with n hn + induction n with -- degree 0 - · use (inv (N₁.map f)).f.f 0 + | zero => + use (inv (N₁.map f)).f.f 0 have h₁₀ := h₁ 0 have h₂₀ := h₂ 0 dsimp at h₁₀ h₂₀ simp only [id_comp, comp_id] at h₁₀ h₂₀ tauto - · haveI := hn + | succ n hn => + haveI := hn use φ { a := PInfty.f (n + 1) ≫ (inv (N₁.map f)).f.f (n + 1) b := fun i => inv (f.app (op [n])) ≫ X.σ i } simp only [MorphComponents.id, ← id_φ, ← preComp_φ, preComp, ← postComp_φ, postComp, diff --git a/Mathlib/AlgebraicTopology/DoldKan/Normalized.lean b/Mathlib/AlgebraicTopology/DoldKan/Normalized.lean index d458777633750..cff0ffb6de103 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/Normalized.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/Normalized.lean @@ -124,10 +124,13 @@ def N₁_iso_normalizedMooreComplex_comp_toKaroubi : N₁ ≅ normalizedMooreCom comm := by erw [inclusionOfMooreComplexMap_comp_PInfty, id_comp] } naturality := fun X Y f => by ext - simp only [Functor.comp_map, normalizedMooreComplex_map, Karoubi.comp_f, toKaroubi_map_f, - HomologicalComplex.comp_f, NormalizedMooreComplex.map_f, - inclusionOfMooreComplexMap_f, factorThru_arrow, N₁_map_f, - inclusionOfMooreComplexMap_comp_PInfty_assoc, AlternatingFaceMapComplex.map_f] } + simp only [Functor.comp_obj, normalizedMooreComplex_obj, toKaroubi_obj_X, + NormalizedMooreComplex.obj_X, N₁_obj_X, AlternatingFaceMapComplex.obj_X, Functor.comp_map, + normalizedMooreComplex_map, Karoubi.comp_f, toKaroubi_map_f, HomologicalComplex.comp_f, + NormalizedMooreComplex.map_f, inclusionOfMooreComplexMap_f, NormalizedMooreComplex.objX, + factorThru_arrow, N₁_map_f, inclusionOfMooreComplexMap_comp_PInfty_assoc, + AlternatingFaceMapComplex.map_f] + } hom_inv_id := by ext X : 3 simp only [PInftyToNormalizedMooreComplex_comp_inclusionOfMooreComplexMap, @@ -139,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 b17a90763626e..1640f26ee2f41 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/PInfty.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/PInfty.lean @@ -33,10 +33,11 @@ variable {C : Type*} [Category C] [Preadditive C] {X : SimplicialObject C} theorem P_is_eventually_constant {q n : ℕ} (hqn : n ≤ q) : ((P (q + 1)).f n : X _[n] ⟶ _) = (P q).f n := by - rcases n with (_|n) - · simp only [Nat.zero_eq, P_f_0_eq] - · simp only [P_succ, add_right_eq_self, comp_add, HomologicalComplex.comp_f, - HomologicalComplex.add_f_apply, comp_id] + cases n with + | zero => simp only [P_f_0_eq] + | succ n => + simp only [P_succ, comp_add, comp_id, HomologicalComplex.add_f_apply, HomologicalComplex.comp_f, + add_right_eq_self] exact (HigherFacesVanish.of_P q n).comp_Hσ_eq_zero (Nat.succ_le_iff.mp hqn) theorem Q_is_eventually_constant {q n : ℕ} (hqn : n ≤ q) : @@ -178,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/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 4c1705a39ed6d..478287d6c7e9c 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 @@ -153,7 +153,7 @@ theorem shiftFun_succ {n : ℕ} {X : Type*} [Zero X] (f : Fin n → X) (i : Fin dsimp [shiftFun] split_ifs with h · exfalso - simp only [Fin.ext_iff, Fin.val_succ, Fin.val_zero, add_eq_zero, and_false] at h + simp only [Fin.ext_iff, Fin.val_succ, Fin.val_zero, add_eq_zero, and_false, reduceCtorEq] at h · simp only [Fin.pred_succ] /-- The shift of a morphism `f : [n] → Δ` in `SimplexCategory` corresponds to @@ -282,7 +282,7 @@ theorem ExtraDegeneracy.s_comp_π_succ (n : ℕ) (i : Fin (n + 1)) : dsimp [ExtraDegeneracy.s] simp only [WidePullback.lift_π] split_ifs with h - · simp only [Fin.ext_iff, Fin.val_succ, Fin.val_zero, add_eq_zero, and_false] at h + · simp only [Fin.ext_iff, Fin.val_succ, Fin.val_zero, add_eq_zero, and_false, reduceCtorEq] at h · simp only [Fin.pred_succ] -- Porting note (#11119): @[simp] removed as the linter complains the LHS is not in normal form diff --git a/Mathlib/AlgebraicTopology/FundamentalGroupoid/Basic.lean b/Mathlib/AlgebraicTopology/FundamentalGroupoid/Basic.lean index 84980eaca3178..2a8bb0c418f7e 100644 --- a/Mathlib/AlgebraicTopology/FundamentalGroupoid/Basic.lean +++ b/Mathlib/AlgebraicTopology/FundamentalGroupoid/Basic.lean @@ -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] 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/PUnit.lean b/Mathlib/AlgebraicTopology/FundamentalGroupoid/PUnit.lean index 8dbe4c0998411..354d877aad6f4 100644 --- a/Mathlib/AlgebraicTopology/FundamentalGroupoid/PUnit.lean +++ b/Mathlib/AlgebraicTopology/FundamentalGroupoid/PUnit.lean @@ -33,12 +33,11 @@ instance {x y : FundamentalGroupoid PUnit} : Subsingleton (x ⟶ y) := by apply Quotient.instSubsingletonQuotient /-- Equivalence of groupoids between fundamental groupoid of punit and punit -/ -def punitEquivDiscretePUnit : FundamentalGroupoid PUnit.{u + 1} ≌ Discrete PUnit.{v + 1} := - CategoryTheory.Equivalence.mk - (Functor.star _) - ((CategoryTheory.Functor.const _).obj ⟨PUnit.unit⟩) - -- Porting note: was `by decide` - (NatIso.ofComponents fun _ => eqToIso (by simp)) - (Functor.punitExt _ _) +@[simps] +def punitEquivDiscretePUnit : FundamentalGroupoid PUnit.{u + 1} ≌ Discrete PUnit.{v + 1} where + functor := Functor.star _ + inverse := (CategoryTheory.Functor.const _).obj ⟨PUnit.unit⟩ + unitIso := NatIso.ofComponents (fun _ => Iso.refl _) + counitIso := Iso.refl _ end FundamentalGroupoid diff --git a/Mathlib/AlgebraicTopology/MooreComplex.lean b/Mathlib/AlgebraicTopology/MooreComplex.lean index 62e4f9ca124ea..5ab0ded88a8b6 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 diff --git a/Mathlib/AlgebraicTopology/SimplexCategory.lean b/Mathlib/AlgebraicTopology/SimplexCategory.lean index a9402e71c3a01..38c94b643e51d 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 @@ -165,6 +165,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 +210,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 +467,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 +591,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 @@ -520,7 +631,7 @@ theorem epi_iff_surjective {n m : SimplexCategory} {f : n ⟶ m} : simp only [skeletalFunctor_obj, skeletalFunctor_map, NonemptyFinLinOrd.epi_iff_surjective, NonemptyFinLinOrd.coe_of] -/-- A monomorphism in `SimplexCategory` must increase lengths-/ +/-- A monomorphism in `SimplexCategory` must increase lengths -/ theorem len_le_of_mono {x y : SimplexCategory} {f : x ⟶ y} : Mono f → x.len ≤ y.len := by intro hyp_f_mono have f_inj : Function.Injective f.toOrderHom.toFun := mono_iff_injective.1 hyp_f_mono @@ -529,7 +640,7 @@ theorem len_le_of_mono {x y : SimplexCategory} {f : x ⟶ y} : Mono f → x.len theorem le_of_mono {n m : ℕ} {f : ([n] : SimplexCategory) ⟶ [m]} : CategoryTheory.Mono f → n ≤ m := len_le_of_mono -/-- An epimorphism in `SimplexCategory` must decrease lengths-/ +/-- An epimorphism in `SimplexCategory` must decrease lengths -/ theorem len_le_of_epi {x y : SimplexCategory} {f : x ⟶ y} : Epi f → y.len ≤ x.len := by intro hyp_f_epi have f_surj : Function.Surjective f.toOrderHom.toFun := epi_iff_surjective.1 hyp_f_epi @@ -628,7 +739,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,16 +754,16 @@ 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 cases c · exfalso - simp only [Nat.zero_eq, add_zero, len_mk, Fin.coe_pred] at hc + simp only [add_zero, len_mk, Fin.coe_pred] at hc rw [hc] at h'' exact h'' rfl · rw [← hc] @@ -691,18 +802,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 +835,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 +845,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/SimplicialObject.lean b/Mathlib/AlgebraicTopology/SimplicialCategory/SimplicialObject.lean new file mode 100644 index 0000000000000..966e00873375e --- /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 K L := 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 ac55809d6b622..c15da7cf1c35d 100644 --- a/Mathlib/AlgebraicTopology/SimplicialObject.lean +++ b/Mathlib/AlgebraicTopology/SimplicialObject.lean @@ -1,11 +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: 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.Limits.FunctorCategory +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) @@ -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) @@ -776,14 +868,15 @@ def cosimplicialToSimplicialAugmented : objects and augmented cosimplicial objects in the opposite category. -/ @[simps! functor inverse] def simplicialCosimplicialAugmentedEquiv : - (SimplicialObject.Augmented C)ᵒᵖ ≌ CosimplicialObject.Augmented Cᵒᵖ := - Equivalence.mk (simplicialToCosimplicialAugmented _) (cosimplicialToSimplicialAugmented _) - (NatIso.ofComponents (fun X => X.unop.rightOpLeftOpIso.op) fun f => by + (SimplicialObject.Augmented C)ᵒᵖ ≌ CosimplicialObject.Augmented Cᵒᵖ where + functor := simplicialToCosimplicialAugmented _ + inverse := cosimplicialToSimplicialAugmented _ + unitIso := NatIso.ofComponents (fun X => X.unop.rightOpLeftOpIso.op) fun f => by dsimp rw [← f.op_unop] simp_rw [← op_comp] congr 1 - aesop_cat) - (NatIso.ofComponents fun X => X.leftOpRightOpIso) + aesop_cat + counitIso := NatIso.ofComponents fun X => X.leftOpRightOpIso end CategoryTheory diff --git a/Mathlib/AlgebraicTopology/SimplicialSet.lean b/Mathlib/AlgebraicTopology/SimplicialSet/Basic.lean similarity index 82% rename from Mathlib/AlgebraicTopology/SimplicialSet.lean rename to Mathlib/AlgebraicTopology/SimplicialSet/Basic.lean index e20ccf4e006ff..2a21c558b5ebb 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 @@ -303,7 +303,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 +335,91 @@ instance Truncated.hasColimits {n : ℕ} : HasColimits (Truncated n) := by dsimp only [Truncated] infer_instance +/-- 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} + -- Porting note (#5229): added an `ext` lemma. @[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. -/ 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 96% rename from Mathlib/AlgebraicTopology/Nerve.lean rename to Mathlib/AlgebraicTopology/SimplicialSet/Nerve.lean index 611b1fea9cd22..9e299bd44fc83 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 /-! 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 f7da42f37d939..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 @@ -11,7 +11,7 @@ import Mathlib.Topology.Category.TopCat.Limits.Basic /-! # The singular simplicial set of a topological space and geometric realization of a simplicial set -The *singular simplicial set* `TopCat.to_SSet.obj X` of a topological space `X` +The *singular simplicial set* `TopCat.toSSet.obj X` of a topological space `X` has as `n`-simplices the continuous maps `[n].toTop → X`. Here, `[n].toTop` is the standard topological `n`-simplex, defined as `{ f : Fin (n+1) → ℝ≥0 // ∑ i, f i = 1 }` with its subspace topology. diff --git a/Mathlib/AlgebraicTopology/SplitSimplicialObject.lean b/Mathlib/AlgebraicTopology/SplitSimplicialObject.lean index c3a4875c7d176..156266bbc5e76 100644 --- a/Mathlib/AlgebraicTopology/SplitSimplicialObject.lean +++ b/Mathlib/AlgebraicTopology/SplitSimplicialObject.lean @@ -208,14 +208,14 @@ structure Splitting (X : SimplicialObject C) where /-- The "inclusion" `N n ⟶ X _[n]` for all `n : ℕ`. -/ ι : ∀ n, N n ⟶ X _[n] /-- For each `Δ`, `X.obj Δ` identifies to the coproduct of the objects `N A.1.unop.len` - for all `A : IndexSet Δ`. -/ + for all `A : IndexSet Δ`. -/ isColimit' : ∀ Δ : SimplexCategoryᵒᵖ, IsColimit (Splitting.cofan' N X ι Δ) namespace Splitting variable {X Y : SimplicialObject C} (s : Splitting X) -/-- The cofan for `summand s.N Δ` induced by a splitting of a simplicial object. -/ +/-- The cofan for `summand s.N Δ` induced by a splitting of a simplicial object. -/ def cofan (Δ : SimplexCategoryᵒᵖ) : Cofan (summand s.N Δ) := Cofan.mk (X.obj Δ) (fun A => s.ι A.1.unop.len ≫ X.map A.e.op) @@ -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 := @@ -383,7 +383,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 cce923522de40..cd994fb7364b8 100644 --- a/Mathlib/Analysis/Analytic/Basic.lean +++ b/Mathlib/Analysis/Analytic/Basic.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, Yury Kudryashov -/ -import Mathlib.Algebra.Star.Order +import Mathlib.Algebra.Order.Star.Basic import Mathlib.Analysis.Calculus.FormalMultilinearSeries import Mathlib.Analysis.SpecificLimits.Normed import Mathlib.Logic.Equiv.Fin @@ -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 @@ -223,20 +218,20 @@ theorem lt_radius_of_isBigO (h₀ : r ≠ 0) {a : ℝ} (ha : a ∈ Ioo (-1 : ℝ norm_cast at this rw [← ENNReal.coe_lt_coe] at this refine this.trans_le (p.le_radius_of_bound C fun n => ?_) - rw [NNReal.coe_div, div_pow, ← mul_div_assoc, div_le_iff (pow_pos ha.1 n)] + rw [NNReal.coe_div, div_pow, ← mul_div_assoc, div_le_iff₀ (pow_pos ha.1 n)] exact (le_abs_self _).trans (hp n) /-- For `r` strictly smaller than the radius of `p`, then `‖pₙ‖ rⁿ` is bounded. -/ 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} (h0 : 0 < r) (h : (r : ℝ≥0∞) < p.radius) : ∃ C > 0, ∀ n, ‖p n‖ ≤ C / (r : ℝ) ^ n := let ⟨C, hC, hp⟩ := p.norm_mul_pow_le_of_lt_radius h - ⟨C, hC, fun n => Iff.mpr (le_div_iff (pow_pos h0 _)) (hp n)⟩ + ⟨C, hC, fun n => Iff.mpr (le_div_iff₀ (pow_pos h0 _)) (hp n)⟩ /-- For `r` strictly smaller than the radius of `p`, then `‖pₙ‖ rⁿ` is bounded. -/ theorem nnnorm_mul_pow_le_of_lt_radius (p : FormalMultilinearSeries 𝕜 E F) {r : ℝ≥0} @@ -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 @@ -330,7 +337,7 @@ theorem radius_le_radius_continuousLinearMap_comp (p : FormalMultilinearSeries apply le_radius_of_isBigO apply (IsBigO.trans_isLittleO _ (p.isLittleO_one_of_lt_radius hr)).isBigO refine IsBigO.mul (@IsBigOWith.isBigO _ _ _ _ _ ‖f‖ _ _ _ ?_) (isBigO_refl _ _) - refine IsBigOWith.of_bound (eventually_of_forall fun n => ?_) + refine IsBigOWith.of_bound (Eventually.of_forall fun n => ?_) simpa only [norm_norm] using f.norm_compContinuousMultilinearMap_le (p n) end FormalMultilinearSeries @@ -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 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 (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 + 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 [(· ∘ ·)] - · 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 => + 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 + 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 `Nat.zero_eq, zero_add, pow_one` - -- removed `zero_pow, Ne.def, Nat.one_ne_zero, not_false_iff` - simpa only [Nat.zero_eq, 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 (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 := by - let a := ContinuousMultilinearMap.curryFinFinset 𝕜 E F hs - (by erw [Finset.card_compl, Fintype.card_fin, hs, add_tsub_cancel_right]) - exact 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 0fab892e09d2e..9576f0b22c613 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,24 +29,26 @@ 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] [NormedAddCommGroup F] [NormedSpace 𝕜 F] [NormedAddCommGroup G] [NormedSpace 𝕜 G] -open scoped Classical -open Topology NNReal Filter ENNReal - -open Set Filter Asymptotics +open scoped Classical Topology +open Set Filter Asymptotics NNReal ENNReal variable {f g : E → F} {p pf pg : FormalMultilinearSeries 𝕜 E F} {x : E} {r r' : ℝ≥0∞} {n m : ℕ} @@ -113,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⟩ @@ -332,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 @@ -347,7 +357,8 @@ protected theorem FormalMultilinearSeries.sum_of_finite (p : FormalMultilinearSe protected theorem FormalMultilinearSeries.hasSum_of_finite (p : FormalMultilinearSeries 𝕜 E F) {n : ℕ} (hn : ∀ m, n ≤ m → p m = 0) (x : E) : HasSum (fun n : ℕ => p n fun _ => x) (p.sum x) := - summable_of_ne_finset_zero (fun m hm ↦ by rw [Finset.mem_range, not_lt] at hm; rw [hn m hm]; rfl) + summable_of_ne_finset_zero (s := .range n) + (fun m hm ↦ by rw [Finset.mem_range, not_lt] at hm; rw [hn m hm]; rfl) |>.hasSum /-- The sum of a finite power series `p` admits `p` as a power series. -/ @@ -382,7 +393,7 @@ main point is that the new series `p.changeOrigin x` is still finite, with the s variable (p : FormalMultilinearSeries 𝕜 E F) {x y : E} {r R : ℝ≥0} /-- If `p` is a formal multilinear series such that `p m = 0` for `n ≤ m`, then -`p.changeOriginSeriesTerm k l = 0` for `n ≤ k + l`. -/ +`p.changeOriginSeriesTerm k l = 0` for `n ≤ k + l`. -/ lemma changeOriginSeriesTerm_bound (p : FormalMultilinearSeries 𝕜 E F) {n : ℕ} (hn : ∀ (m : ℕ), n ≤ m → p m = 0) (k l : ℕ) {s : Finset (Fin (k + l))} (hs : s.card = l) (hkl : n ≤ k + l) : @@ -394,7 +405,7 @@ lemma changeOriginSeriesTerm_bound (p : FormalMultilinearSeries 𝕜 E F) {n : /-- If `p` is a finite formal multilinear series, then so is `p.changeOriginSeries k` for every `k` in `ℕ`. More precisely, if `p m = 0` for `n ≤ m`, then `p.changeOriginSeries k m = 0` for -`n ≤ k + m`. -/ +`n ≤ k + m`. -/ lemma changeOriginSeries_finite_of_finite (p : FormalMultilinearSeries 𝕜 E F) {n : ℕ} (hn : ∀ (m : ℕ), n ≤ m → p m = 0) (k : ℕ) : ∀ {m : ℕ}, n ≤ k + m → p.changeOriginSeries k m = 0 := by @@ -414,7 +425,7 @@ lemma changeOriginSeries_sum_eq_partialSum_of_finite (p : FormalMultilinearSerie ContinuousMultilinearMap.zero_apply] /-- If `p` is a formal multilinear series such that `p m = 0` for `n ≤ m`, then -`p.changeOrigin x k = 0` for `n ≤ k`. -/ +`p.changeOrigin x k = 0` for `n ≤ k`. -/ lemma changeOrigin_finite_of_finite (p : FormalMultilinearSeries 𝕜 E F) {n : ℕ} (hn : ∀ (m : ℕ), n ≤ m → p m = 0) {k : ℕ} (hk : n ≤ k) : p.changeOrigin x k = 0 := by @@ -540,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 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 + +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 5cf9bd1117d0b..c73176c9a5ec5 100644 --- a/Mathlib/Analysis/Analytic/Composition.lean +++ b/Mathlib/Analysis/Analytic/Composition.lean @@ -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,51 +380,61 @@ 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 -/-! ### Summability properties of the composition of formal power series-/ +/-- 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 -/ section @@ -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 @@ -856,7 +936,7 @@ where `v' = (v_l, v_{l+1}, ..., v_{m-1})`. Therefore, we get r.comp (q.comp p) n v = ∑_{c : Composition n} ∑_{d₀ : Composition (c.blocksFun 0), ..., d_{c.length - 1} : Composition (c.blocksFun (c.length - 1))} - r c.length (λ i, q dᵢ.length (applyComposition p dᵢ v'ᵢ)) + r c.length (fun i ↦ q dᵢ.length (applyComposition p dᵢ v'ᵢ)) ``` To show that these terms coincide, we need to explain how to reindex the sums to put them in bijection (and then the terms we are summing will correspond to each other). Suppose we have a @@ -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 @@ -1086,7 +1166,7 @@ def sigmaEquivSigmaPi (n : ℕ) : -- but we need to massage it to take care of the dependent setting. rintro ⟨c, d⟩ have : map List.sum (ofFn fun i : Fin (Composition.length c) => (d i).blocks) = c.blocks := by - simp [map_ofFn, (· ∘ ·), Composition.blocks_sum, Composition.ofFn_blocksFun] + simp [map_ofFn, Function.comp_def, Composition.blocks_sum, Composition.ofFn_blocksFun] rw [sigma_pi_composition_eq_iff] dsimp congr! 1 @@ -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 daa0f2c5172fc..42de038a5780f 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 @@ -19,10 +20,8 @@ We show that the following are analytic: noncomputable section -open scoped Classical -open Topology NNReal Filter ENNReal - -open Set Filter Asymptotics +open scoped Classical Topology +open Filter Asymptotics ENNReal NNReal variable {α : Type*} variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] @@ -33,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.zero_lt_top, 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 -/ @@ -65,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) : @@ -88,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) : @@ -96,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) @@ -109,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 {y} 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 @@ -156,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) : @@ -163,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 [Nat.zero_eq, pow_zero] - apply analyticAt_const + simp only [pow_zero] + 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 @@ -221,7 +748,7 @@ lemma formalMultilinearSeries_geometric_radius (𝕜) [NontriviallyNormedField simp_rw [IsLittleO, IsBigOWith, not_forall, norm_one, mul_one, not_eventually] refine ⟨1, one_pos, ?_⟩ - refine ((eventually_ne_atTop 0).mp (eventually_of_forall ?_)).frequently + refine ((eventually_ne_atTop 0).mp (Eventually.of_forall ?_)).frequently intro n hn push_neg rwa [norm_pow, one_lt_pow_iff_of_nonneg (norm_nonneg _) hn, @@ -233,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 := @@ -257,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) : @@ -297,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 704910afccb1c..eadc577c91124 100644 --- a/Mathlib/Analysis/Analytic/Inverse.lean +++ b/Mathlib/Analysis/Analytic/Inverse.lean @@ -4,36 +4,43 @@ 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 /-! # 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 +58,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 +94,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 +119,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 +136,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, @@ -137,7 +145,7 @@ theorem leftInv_comp (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] F) ext c congr ext k - simp [h, Function.comp] + simp [h, Function.comp_def] simp [FormalMultilinearSeries.comp, show n + 2 ≠ 1 by omega, A, Finset.sum_union B, applyComposition_ones, C, D, -Set.toFinset_setOf] @@ -157,26 +165,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 +224,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 +240,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 +258,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) @@ -267,26 +278,15 @@ theorem rightInv_coeff (p : FormalMultilinearSeries 𝕜 E F) (i : E ≃L[𝕜] /-! ### 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 +423,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 +505,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 +533,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 x ↦ 0) ∈ v := by + simpa using hy (v_open.mem_nhds hv) + refine ⟨a₀, fun a ha ↦ ?_⟩ + have : Tendsto (fun b ↦ q.partialSum a (p.partialSum b y - (p 0) fun x ↦ 0)) atTop + (𝓝 (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 45a5d24651d57..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`. -/ @@ -77,9 +77,9 @@ theorem has_fpower_series_dslope_fslope (hp : HasFPowerSeriesAt f p z₀) : theorem has_fpower_series_iterate_dslope_fslope (n : ℕ) (hp : HasFPowerSeriesAt f p z₀) : HasFPowerSeriesAt ((swap dslope z₀)^[n] f) (fslope^[n] p) z₀ := by - induction' n with n ih generalizing f p - · exact hp - · simpa using ih (has_fpower_series_dslope_fslope hp) + induction n generalizing f p with + | zero => exact hp + | succ n ih => simpa using ih (has_fpower_series_dslope_fslope hp) theorem iterate_dslope_fslope_ne_zero (hp : HasFPowerSeriesAt f p z₀) (h : p ≠ 0) : (swap dslope z₀)^[p.order] f z₀ ≠ 0 := by @@ -105,7 +105,7 @@ theorem locally_ne_zero (hp : HasFPowerSeriesAt f p z₀) (h : p ≠ 0) : ∀ᶠ simpa [e1, e2, e3] using pow_ne_zero p.order (sub_ne_zero.mpr e3) theorem locally_zero_iff (hp : HasFPowerSeriesAt f p z₀) : (∀ᶠ z in 𝓝 z₀, f z = 0) ↔ p = 0 := - ⟨fun hf => hp.eq_zero_of_eventually hf, fun h => eventually_eq_zero (by rwa [h] at hp)⟩ + ⟨fun hf => hp.eq_zero_of_eventually hf, fun h => eventually_eq_zero (𝕜 := 𝕜) (by rwa [h] at hp)⟩ end HasFPowerSeriesAt @@ -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 f7afb9b160fc2..e527cda45057c 100644 --- a/Mathlib/Analysis/Analytic/Linear.lean +++ b/Mathlib/Analysis/Analytic/Linear.lean @@ -9,9 +9,11 @@ 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] [NormedSpace 𝕜 E] {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] {G : Type*} @@ -42,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 @@ -58,13 +72,13 @@ 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 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 theorem fpowerSeriesBilinear_apply_one (f : E →L[𝕜] F →L[𝕜] G) (x : E × F) : @@ -110,29 +124,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 e2dd5221e27e3..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' @@ -133,14 +133,31 @@ lemma div {f g : 𝕜 → 𝕜} {x : 𝕜} (hf : MeromorphicAt f x) (hg : Meromo (div_eq_mul_inv f g).symm ▸ (hf.mul hg.inv) lemma pow {f : 𝕜 → 𝕜} {x : 𝕜} (hf : MeromorphicAt f x) (n : ℕ) : MeromorphicAt (f ^ n) x := by - induction' n with m hm - · simpa only [Nat.zero_eq, pow_zero] using MeromorphicAt.const 1 x - · simpa only [pow_succ] using hm.mul hf + induction n with + | zero => simpa only [pow_zero] using MeromorphicAt.const 1 x + | succ m hm => simpa only [pow_succ] using hm.mul hf lemma zpow {f : 𝕜 → 𝕜} {x : 𝕜} (hf : MeromorphicAt f x) (n : ℤ) : MeromorphicAt (f ^ n) x := by - induction' n with m m - · simpa only [Int.ofNat_eq_coe, zpow_natCast] using hf.pow m - · simpa only [zpow_negSucc, inv_iff] using hf.pow (m + 1) + induction n with + | ofNat m => simpa only [Int.ofNat_eq_coe, zpow_natCast] using hf.pow m + | negSucc m => simpa only [zpow_negSucc, inv_iff] using hf.pow (m + 1) + +theorem eventually_analyticAt [CompleteSpace E] {f : 𝕜 → E} {x : 𝕜} + (h : MeromorphicAt f x) : ∀ᶠ y in 𝓝[≠] x, AnalyticAt 𝕜 f y := by + rw [MeromorphicAt] at h + obtain ⟨n, h⟩ := h + apply AnalyticAt.eventually_analyticAt at h + refine (h.filter_mono ?_).mp ?_ + · simp [nhdsWithin] + · rw [eventually_nhdsWithin_iff] + apply Filter.Eventually.of_forall + intro y hy hf + rw [Set.mem_compl_iff, Set.mem_singleton_iff] at hy + 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 + simp [smul_smul, hz, sub_eq_zero] /-- The order of vanishing of a meromorphic function, as an element of `ℤ ∪ ∞` (to include the case of functions identically 0 near `x`). -/ @@ -210,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 @@ -220,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 @@ -281,4 +300,14 @@ lemma congr (h_eq : Set.EqOn f g U) (hu : IsOpen U) : MeromorphicOn g U := by refine fun x hx ↦ (hf x hx).congr (EventuallyEq.filter_mono ?_ nhdsWithin_le_nhds) exact eventually_of_mem (hu.mem_nhds hx) h_eq +theorem eventually_codiscreteWithin_analyticAt + [CompleteSpace E] (f : 𝕜 → E) (h : MeromorphicOn f U) : + ∀ᶠ (y : 𝕜) in codiscreteWithin U, AnalyticAt 𝕜 f y := by + rw [eventually_iff, mem_codiscreteWithin] + intro x hx + rw [disjoint_principal_right] + apply Filter.mem_of_superset ((h x hx).eventually_analyticAt) + intro x hx + simp [hx] + end MeromorphicOn 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 a35cbce9538cf..7703eb9524ef0 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 definitons +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,16 +95,21 @@ 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. -/ @@ -165,11 +117,11 @@ be stitched together. 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 +138,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 +150,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 +171,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 1689aea70b8ce..42aba8ff24d51 100644 --- a/Mathlib/Analysis/Asymptotics/AsymptoticEquivalent.lean +++ b/Mathlib/Analysis/Asymptotics/AsymptoticEquivalent.lean @@ -195,7 +195,7 @@ theorem isEquivalent_of_tendsto_one (hz : ∀ᶠ x in l, v x = 0 → u x = 0) theorem isEquivalent_of_tendsto_one' (hz : ∀ x, v x = 0 → u x = 0) (huv : Tendsto (u / v) l (𝓝 1)) : u ~[l] v := - isEquivalent_of_tendsto_one (eventually_of_forall hz) huv + isEquivalent_of_tendsto_one (Eventually.of_forall hz) huv theorem isEquivalent_iff_tendsto_one (hz : ∀ᶠ x in l, v x ≠ 0) : u ~[l] v ↔ Tendsto (u / v) l (𝓝 1) := by diff --git a/Mathlib/Analysis/Asymptotics/Asymptotics.lean b/Mathlib/Analysis/Asymptotics/Asymptotics.lean index 945fbda42c7d1..15ae960d1d41e 100644 --- a/Mathlib/Analysis/Asymptotics/Asymptotics.lean +++ b/Mathlib/Analysis/Asymptotics/Asymptotics.lean @@ -3,6 +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, Yury Kudryashov -/ +import Mathlib.Analysis.Normed.Group.Bounded import Mathlib.Analysis.Normed.Group.InfiniteSum import Mathlib.Analysis.Normed.MulAction import Mathlib.Topology.Algebra.Order.LiminfLimsup @@ -44,11 +45,8 @@ it suffices to assume that `f` is zero wherever `g` is. (This generalization is the Fréchet derivative.) -/ - -open Filter Set - open scoped Classical -open Topology Filter NNReal +open Set Topology Filter NNReal namespace Asymptotics @@ -130,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⟩ @@ -236,7 +234,7 @@ theorem IsBigO.exists_mem_basis {ι} {p : ι → Prop} {s : ι → Set α} (h : simpa only [isBigOWith_iff, hb.eventually_iff, exists_prop] using h theorem isBigOWith_inv (hc : 0 < c) : IsBigOWith c⁻¹ l f g ↔ ∀ᶠ x in l, c * ‖f x‖ ≤ ‖g x‖ := by - simp only [IsBigOWith_def, ← div_eq_inv_mul, le_div_iff' hc] + simp only [IsBigOWith_def, ← div_eq_inv_mul, le_div_iff₀' hc] -- We prove this lemma with strange assumptions to get two lemmas below automatically theorem isLittleO_iff_nat_mul_le_aux (h₀ : (∀ x, 0 ≤ ‖f x‖) ∨ ∀ x, 0 ≤ ‖g x‖) : @@ -253,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₀ @@ -595,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‖) : @@ -823,6 +821,46 @@ theorem IsLittleO.prod_rightr (h : f =o[l] g') : f =o[l] fun x => (f' x, g' x) : end +section + +variable {f : α × β → E} {g : α × β → F} {l' : Filter β} + +protected theorem IsBigO.fiberwise_right : + f =O[l ×ˢ l'] g → ∀ᶠ a in l, (f ⟨a, ·⟩) =O[l'] (g ⟨a, ·⟩) := by + simp only [isBigO_iff, eventually_iff, mem_prod_iff] + rintro ⟨c, t₁, ht₁, t₂, ht₂, ht⟩ + exact mem_of_superset ht₁ fun _ ha ↦ ⟨c, mem_of_superset ht₂ fun _ hb ↦ ht ⟨ha, hb⟩⟩ + +protected theorem IsBigO.fiberwise_left : + f =O[l ×ˢ l'] g → ∀ᶠ b in l', (f ⟨·, b⟩) =O[l] (g ⟨·, b⟩) := by + simp only [isBigO_iff, eventually_iff, mem_prod_iff] + rintro ⟨c, t₁, ht₁, t₂, ht₂, ht⟩ + exact mem_of_superset ht₂ fun _ hb ↦ ⟨c, mem_of_superset ht₁ fun _ ha ↦ ht ⟨ha, hb⟩⟩ + +end + +section + +variable (l' : Filter β) + +protected theorem IsBigO.comp_fst : f =O[l] g → (f ∘ Prod.fst) =O[l ×ˢ l'] (g ∘ Prod.fst) := by + simp only [isBigO_iff, eventually_prod_iff] + exact fun ⟨c, hc⟩ ↦ ⟨c, _, hc, fun _ ↦ True, eventually_true l', fun {_} h {_} _ ↦ h⟩ + +protected theorem IsBigO.comp_snd : f =O[l] g → (f ∘ Prod.snd) =O[l' ×ˢ l] (g ∘ Prod.snd) := by + simp only [isBigO_iff, eventually_prod_iff] + exact fun ⟨c, hc⟩ ↦ ⟨c, fun _ ↦ True, eventually_true l', _, hc, fun _ ↦ id⟩ + +protected theorem IsLittleO.comp_fst : f =o[l] g → (f ∘ Prod.fst) =o[l ×ˢ l'] (g ∘ Prod.fst) := by + simp only [isLittleO_iff, eventually_prod_iff] + exact fun h _ hc ↦ ⟨_, h hc, fun _ ↦ True, eventually_true l', fun {_} h {_} _ ↦ h⟩ + +protected theorem IsLittleO.comp_snd : f =o[l] g → (f ∘ Prod.snd) =o[l' ×ˢ l] (g ∘ Prod.snd) := by + simp only [isLittleO_iff, eventually_prod_iff] + exact fun h _ hc ↦ ⟨fun _ ↦ True, eventually_true l', _, h hc, fun _ ↦ id⟩ + +end + theorem IsBigOWith.prod_left_same (hf : IsBigOWith c l f' k') (hg : IsBigOWith c l g' k') : IsBigOWith c l (fun x => (f' x, g' x)) k' := by rw [isBigOWith_iff] at *; filter_upwards [hf, hg] with x using max_le @@ -1021,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] @@ -1077,7 +1115,7 @@ theorem isLittleO_principal {s : Set α} : f'' =o[𝓟 s] g' ↔ ∀ x ∈ s, f' ((continuous_id.mul continuous_const).tendsto' _ _ (zero_mul _)).mono_left inf_le_left apply le_of_tendsto_of_tendsto tendsto_const_nhds this - apply eventually_nhdsWithin_iff.2 (eventually_of_forall (fun c hc ↦ ?_)) + apply eventually_nhdsWithin_iff.2 (Eventually.of_forall (fun c hc ↦ ?_)) exact eventually_principal.1 (h hc) x hx · apply (isLittleO_zero g' _).congr' ?_ EventuallyEq.rfl exact fun x hx ↦ (h x hx).symm @@ -1190,7 +1228,7 @@ theorem isBigO_iff_isBoundedUnder_le_div (h : ∀ᶠ x in l, g'' x ≠ 0) : simp only [isBigO_iff, IsBoundedUnder, IsBounded, eventually_map] exact exists_congr fun c => - eventually_congr <| h.mono fun x hx => (div_le_iff <| norm_pos_iff.2 hx).symm + eventually_congr <| h.mono fun x hx => (div_le_iff₀ <| norm_pos_iff.2 hx).symm /-- `(fun x ↦ c) =O[l] f` if and only if `f` is bounded away from zero. -/ theorem isBigO_const_left_iff_pos_le_norm {c : E''} (hc : c ≠ 0) : @@ -1199,7 +1237,7 @@ theorem isBigO_const_left_iff_pos_le_norm {c : E''} (hc : c ≠ 0) : · intro h rcases h.exists_pos with ⟨C, hC₀, hC⟩ refine ⟨‖c‖ / C, div_pos (norm_pos_iff.2 hc) hC₀, ?_⟩ - exact hC.bound.mono fun x => (div_le_iff' hC₀).2 + exact hC.bound.mono fun x => (div_le_iff₀' hC₀).2 · rintro ⟨b, hb₀, hb⟩ refine IsBigO.of_bound (‖c‖ / b) (hb.mono fun x hx => ?_) rw [div_mul_eq_mul_div, mul_div_assoc] @@ -1213,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 -/ @@ -1393,9 +1434,9 @@ theorem IsBigO.of_pow {f : α → 𝕜} {g : α → R} {n : ℕ} (hn : n ≠ 0) theorem IsLittleO.pow {f : α → R} {g : α → 𝕜} (h : f =o[l] g) {n : ℕ} (hn : 0 < n) : (fun x => f x ^ n) =o[l] fun x => g x ^ n := by obtain ⟨n, rfl⟩ := Nat.exists_eq_succ_of_ne_zero hn.ne'; clear hn - induction' n with n ihn - · simpa only [Nat.zero_eq, ← Nat.one_eq_succ_zero, pow_one] - · convert ihn.mul h <;> simp [pow_succ] + induction n with + | zero => simpa only [pow_one] + | succ n ihn => convert ihn.mul h <;> simp [pow_succ] theorem IsLittleO.of_pow {f : α → 𝕜} {g : α → R} {n : ℕ} (h : (f ^ n) =o[l] (g ^ n)) (hn : n ≠ 0) : f =o[l] g := @@ -1403,15 +1444,14 @@ theorem IsLittleO.of_pow {f : α → 𝕜} {g : α → R} {n : ℕ} (h : (f ^ n) /-! ### Inverse -/ - theorem IsBigOWith.inv_rev {f : α → 𝕜} {g : α → 𝕜'} (h : IsBigOWith c l f g) (h₀ : ∀ᶠ x in l, f x = 0 → g x = 0) : IsBigOWith c l (fun x => (g x)⁻¹) fun x => (f x)⁻¹ := by refine IsBigOWith.of_bound (h.bound.mp (h₀.mono fun x h₀ hle => ?_)) 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 - simpa only [norm_inv, mul_inv, ← div_eq_inv_mul, div_le_iff hc] using 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) (h₀ : ∀ᶠ x in l, f x = 0 → g x = 0) : (fun x => (g x)⁻¹) =O[l] fun x => (f x)⁻¹ := @@ -1565,11 +1605,11 @@ theorem isLittleO_iff_tendsto' {f g : α → 𝕜} (hgf : ∀ᶠ x in l, g x = 0 f =o[l] g ↔ Tendsto (fun x => f x / g x) l (𝓝 0) := ⟨IsLittleO.tendsto_div_nhds_zero, fun h => (((isLittleO_one_iff _).mpr h).mul_isBigO (isBigO_refl g l)).congr' - (hgf.mono fun _x => div_mul_cancel_of_imp) (eventually_of_forall fun _x => one_mul _)⟩ + (hgf.mono fun _x => div_mul_cancel_of_imp) (Eventually.of_forall fun _x => one_mul _)⟩ theorem isLittleO_iff_tendsto {f g : α → 𝕜} (hgf : ∀ x, g x = 0 → f x = 0) : f =o[l] g ↔ Tendsto (fun x => f x / g x) l (𝓝 0) := - isLittleO_iff_tendsto' (eventually_of_forall hgf) + isLittleO_iff_tendsto' (Eventually.of_forall hgf) alias ⟨_, isLittleO_of_tendsto'⟩ := isLittleO_iff_tendsto' @@ -1585,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''} : @@ -1663,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 @@ -1704,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) : @@ -1715,7 +1755,7 @@ theorem isBigO_iff_div_isBoundedUnder {α : Type*} {l : Filter α} {f g : α → refine IsBigO.of_bound c (hc.mp <| hgf.mono fun x hx₁ hx₂ => ?_) by_cases hgx : g x = 0 · simp [hx₁ hgx, hgx] - · exact (div_le_iff (norm_pos_iff.2 hgx)).mp hx₂ + · exact (div_le_iff₀ (norm_pos_iff.2 hgx)).mp hx₂ theorem isBigO_of_div_tendsto_nhds {α : Type*} {l : Filter α} {f g : α → 𝕜} (hgf : ∀ᶠ x in l, g x = 0 → f x = 0) (c : 𝕜) (H : Filter.Tendsto (f / g) l (𝓝 c)) : @@ -1776,7 +1816,7 @@ theorem IsBigOWith.right_le_sub_of_lt_one {f₁ f₂ : α → E'} (h : IsBigOWit IsBigOWith.of_bound <| mem_of_superset h.bound fun x hx => by simp only [mem_setOf_eq] at hx ⊢ - rw [mul_comm, one_div, ← div_eq_mul_inv, _root_.le_div_iff, mul_sub, mul_one, mul_comm] + rw [mul_comm, one_div, ← div_eq_mul_inv, le_div_iff₀, mul_sub, mul_one, mul_comm] · exact le_trans (sub_le_sub_left hx _) (norm_sub_norm_le _ _) · exact sub_pos.2 hc @@ -1813,7 +1853,7 @@ theorem bound_of_isBigO_cofinite (h : f =O[cofinite] g'') : have : ∀ x, C * ‖g'' x‖ < ‖f x‖ → ‖f x‖ / ‖g'' x‖ ≤ C' := by simpa using hC' refine ⟨max C C', lt_max_iff.2 (Or.inl C₀), fun x h₀ => ?_⟩ rw [max_mul_of_nonneg _ _ (norm_nonneg _), le_max_iff, or_iff_not_imp_left, not_le] - exact fun hx => (div_le_iff (norm_pos_iff.2 h₀)).1 (this _ hx) + exact fun hx => (div_le_iff₀ (norm_pos_iff.2 h₀)).1 (this _ hx) theorem isBigO_cofinite_iff (h : ∀ x, g'' x = 0 → f'' x = 0) : f'' =O[cofinite] g'' ↔ ∃ C, ∀ x, ‖f'' x‖ ≤ C * ‖g'' x‖ := @@ -1878,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 @@ -1953,3 +2000,52 @@ theorem isLittleO_congr (e : α ≃ₜ β) {b : β} {f : β → E} {g : β → F exact forall₂_congr fun c _hc => e.isBigOWith_congr end Homeomorph + +namespace ContinuousOn + +variable {α E F : Type*} [TopologicalSpace α] {s : Set α} {f : α → E} {c : F} + +section IsBigO + +variable [SeminormedAddGroup E] [Norm F] + +protected theorem isBigOWith_principal + (hf : ContinuousOn f s) (hs : IsCompact s) (hc : ‖c‖ ≠ 0) : + IsBigOWith (sSup (Norm.norm '' (f '' s)) / ‖c‖) (𝓟 s) f fun _ => c := by + rw [isBigOWith_principal, div_mul_cancel₀ _ hc] + exact fun x hx ↦ hs.image_of_continuousOn hf |>.image continuous_norm + |>.isLUB_sSup (Set.image_nonempty.mpr <| Set.image_nonempty.mpr ⟨x, hx⟩) + |>.left <| Set.mem_image_of_mem _ <| Set.mem_image_of_mem _ hx + +protected theorem isBigO_principal (hf : ContinuousOn f s) (hs : IsCompact s) + (hc : ‖c‖ ≠ 0) : f =O[𝓟 s] fun _ => c := + (hf.isBigOWith_principal hs hc).isBigO + +end IsBigO + +section IsBigORev + +variable [NormedAddGroup E] [SeminormedAddGroup F] + +protected theorem isBigOWith_rev_principal + (hf : ContinuousOn f s) (hs : IsCompact s) (hC : ∀ i ∈ s, f i ≠ 0) (c : F) : + IsBigOWith (‖c‖ / sInf (Norm.norm '' (f '' s))) (𝓟 s) (fun _ => c) f := by + refine isBigOWith_principal.mpr fun x hx ↦ ?_ + rw [mul_comm_div] + replace hs := hs.image_of_continuousOn hf |>.image continuous_norm + have h_sInf := hs.isGLB_sInf <| Set.image_nonempty.mpr <| Set.image_nonempty.mpr ⟨x, hx⟩ + refine le_mul_of_one_le_right (norm_nonneg c) <| (one_le_div ?_).mpr <| + h_sInf.1 <| Set.mem_image_of_mem _ <| Set.mem_image_of_mem _ hx + obtain ⟨_, ⟨x, hx, hCx⟩, hnormCx⟩ := hs.sInf_mem h_sInf.nonempty + rw [← hnormCx, ← hCx] + exact (norm_ne_zero_iff.mpr (hC x hx)).symm.lt_of_le (norm_nonneg _) + +protected theorem isBigO_rev_principal (hf : ContinuousOn f s) + (hs : IsCompact s) (hC : ∀ i ∈ s, f i ≠ 0) (c : F) : (fun _ => c) =O[𝓟 s] f := + (hf.isBigOWith_rev_principal hs hC c).isBigO + +end IsBigORev + +end ContinuousOn + +set_option linter.style.longFile 2200 diff --git a/Mathlib/Analysis/Asymptotics/SpecificAsymptotics.lean b/Mathlib/Analysis/Asymptotics/SpecificAsymptotics.lean index a0281a8808ecb..72724bc1976ef 100644 --- a/Mathlib/Analysis/Asymptotics/SpecificAsymptotics.lean +++ b/Mathlib/Analysis/Asymptotics/SpecificAsymptotics.lean @@ -27,7 +27,7 @@ theorem Filter.IsBoundedUnder.isLittleO_sub_self_inv {𝕜 E : Type*} [NormedFie {f : 𝕜 → E} (h : IsBoundedUnder (· ≤ ·) (𝓝[≠] a) (norm ∘ f)) : f =o[𝓝[≠] a] fun x => (x - a)⁻¹ := by refine (h.isBigO_const (one_ne_zero' ℝ)).trans_isLittleO (isLittleO_const_left.2 <| Or.inr ?_) - simp only [(· ∘ ·), norm_inv] + simp only [Function.comp_def, norm_inv] exact (tendsto_norm_sub_self_punctured_nhds a).inv_tendsto_zero end NormedField @@ -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/SuperpolynomialDecay.lean b/Mathlib/Analysis/Asymptotics/SuperpolynomialDecay.lean index 45672ad5d7b49..6068e8fe71de4 100644 --- a/Mathlib/Analysis/Asymptotics/SuperpolynomialDecay.lean +++ b/Mathlib/Analysis/Asymptotics/SuperpolynomialDecay.lean @@ -104,7 +104,7 @@ theorem SuperpolynomialDecay.mul_param (hf : SuperpolynomialDecay l k f) : theorem SuperpolynomialDecay.param_pow_mul (hf : SuperpolynomialDecay l k f) (n : ℕ) : SuperpolynomialDecay l k (k ^ n * f) := by induction n with - | zero => simpa only [Nat.zero_eq, one_mul, pow_zero] using hf + | zero => simpa only [one_mul, pow_zero] using hf | succ n hn => simpa only [pow_succ', mul_assoc] using hn.param_mul theorem SuperpolynomialDecay.mul_param_pow (hf : SuperpolynomialDecay l k f) (n : ℕ) : @@ -159,7 +159,7 @@ theorem SuperpolynomialDecay.trans_eventually_abs_le (hf : SuperpolynomialDecay rw [superpolynomialDecay_iff_abs_tendsto_zero] at hf ⊢ refine fun z => tendsto_of_tendsto_of_tendsto_of_le_of_le' tendsto_const_nhds (hf z) - (eventually_of_forall fun x => abs_nonneg _) (hfg.mono fun x hx => ?_) + (Eventually.of_forall fun x => abs_nonneg _) (hfg.mono fun x hx => ?_) calc |k x ^ z * g x| = |k x ^ z| * |g x| := abs_mul (k x ^ z) (g x) _ ≤ |k x ^ z| * |f x| := by gcongr _ * ?_; exact hx @@ -167,7 +167,7 @@ theorem SuperpolynomialDecay.trans_eventually_abs_le (hf : SuperpolynomialDecay theorem SuperpolynomialDecay.trans_abs_le (hf : SuperpolynomialDecay l k f) (hfg : ∀ x, |g x| ≤ |f x|) : SuperpolynomialDecay l k g := - hf.trans_eventually_abs_le (eventually_of_forall hfg) + hf.trans_eventually_abs_le (Eventually.of_forall hfg) end LinearOrderedCommRing @@ -206,7 +206,7 @@ theorem superpolynomialDecay_iff_abs_isBoundedUnder (hk : Tendsto k l atTop) : zero_mul m ▸ Tendsto.mul_const m ((tendsto_zero_iff_abs_tendsto_zero _).1 hk.inv_tendsto_atTop) refine - tendsto_of_tendsto_of_tendsto_of_le_of_le' h1 h2 (eventually_of_forall fun x => abs_nonneg _) + tendsto_of_tendsto_of_tendsto_of_le_of_le' h1 h2 (Eventually.of_forall fun x => abs_nonneg _) ((eventually_map.1 hm).mp ?_) refine (hk.eventually_ne_atTop 0).mono fun x hk0 hx => ?_ refine Eq.trans_le ?_ (mul_le_mul_of_nonneg_left hx <| abs_nonneg (k x)⁻¹) diff --git a/Mathlib/Analysis/Asymptotics/Theta.lean b/Mathlib/Analysis/Asymptotics/Theta.lean index ab9b0e2af090e..bf570aafef4e4 100644 --- a/Mathlib/Analysis/Asymptotics/Theta.lean +++ b/Mathlib/Analysis/Asymptotics/Theta.lean @@ -131,6 +131,9 @@ instance : Trans (α := α → E) (β := α → E) (γ := α → F) (EventuallyE lemma _root_.Filter.EventuallyEq.isTheta {f g : α → E} (h : f =ᶠ[l] g) : f =Θ[l] g := h.trans_isTheta isTheta_rfl +@[simp] +theorem isTheta_bot : f =Θ[⊥] g := by simp [IsTheta] + @[simp] theorem isTheta_norm_left : (fun x ↦ ‖f' x‖) =Θ[l] g ↔ f' =Θ[l] g := by simp [IsTheta] @@ -185,7 +188,8 @@ theorem IsTheta.tendsto_zero_iff (h : f'' =Θ[l] g'') : theorem IsTheta.tendsto_norm_atTop_iff (h : f' =Θ[l] g') : Tendsto (norm ∘ f') l atTop ↔ Tendsto (norm ∘ g') l atTop := by - simp only [Function.comp, ← isLittleO_const_left_of_ne (one_ne_zero' ℝ), h.isLittleO_congr_right] + simp only [Function.comp_def, ← isLittleO_const_left_of_ne (one_ne_zero' ℝ), + h.isLittleO_congr_right] theorem IsTheta.isBoundedUnder_le_iff (h : f' =Θ[l] g') : IsBoundedUnder (· ≤ ·) l (norm ∘ f') ↔ IsBoundedUnder (· ≤ ·) l (norm ∘ g') := by @@ -234,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 := @@ -280,4 +284,46 @@ lemma IsLittleO.add_isTheta {f₁ f₂ : α → E'} {g : α → F} (ho : f₁ =o[l] g) (hΘ : f₂ =Θ[l] g) : (f₁ + f₂) =Θ[l] g := add_comm f₁ f₂ ▸ hΘ.add_isLittleO ho +section + +variable {f : α × β → E} {g : α × β → F} {l' : Filter β} + +protected theorem IsTheta.fiberwise_right : + f =Θ[l ×ˢ l'] g → ∀ᶠ x in l, (f ⟨x, ·⟩) =Θ[l'] (g ⟨x, ·⟩) := by + simp only [IsTheta, eventually_and] + exact fun ⟨h₁, h₂⟩ ↦ ⟨h₁.fiberwise_right, h₂.fiberwise_right⟩ + +protected theorem IsTheta.fiberwise_left : + f =Θ[l ×ˢ l'] g → ∀ᶠ y in l', (f ⟨·, y⟩) =Θ[l] (g ⟨·, y⟩) := by + simp only [IsTheta, eventually_and] + exact fun ⟨h₁, h₂⟩ ↦ ⟨h₁.fiberwise_left, h₂.fiberwise_left⟩ + +end + +section + +variable (l' : Filter β) + +protected theorem IsTheta.comp_fst : f =Θ[l] g → (f ∘ Prod.fst) =Θ[l ×ˢ l'] (g ∘ Prod.fst) := by + simp only [IsTheta, eventually_and] + exact fun ⟨h₁, h₂⟩ ↦ ⟨h₁.comp_fst l', h₂.comp_fst l'⟩ + +protected theorem IsTheta.comp_snd : f =Θ[l] g → (f ∘ Prod.snd) =Θ[l' ×ˢ l] (g ∘ Prod.snd) := by + simp only [IsTheta, eventually_and] + exact fun ⟨h₁, h₂⟩ ↦ ⟨h₁.comp_snd l', h₂.comp_snd l'⟩ + +end + end Asymptotics + +namespace ContinuousOn + +variable {α E F : Type*} [NormedAddGroup E] [SeminormedAddGroup F] [TopologicalSpace α] + {s : Set α} {f : α → E} {c : F} + +protected theorem isTheta_principal + (hf : ContinuousOn f s) (hs : IsCompact s) (hc : ‖c‖ ≠ 0) (hC : ∀ i ∈ s, f i ≠ 0) : + f =Θ[𝓟 s] fun _ => c := + ⟨hf.isBigO_principal hs hc, hf.isBigO_rev_principal hs hC c⟩ + +end ContinuousOn diff --git a/Mathlib/Analysis/BoundedVariation.lean b/Mathlib/Analysis/BoundedVariation.lean index fb2d9051dd7aa..4f281d9bfca6d 100644 --- a/Mathlib/Analysis/BoundedVariation.lean +++ b/Mathlib/Analysis/BoundedVariation.lean @@ -192,7 +192,7 @@ protected theorem lowerSemicontinuous (s : Set α) : simpa only [UniformOnFun.tendsto_iff_tendstoUniformlyOn, mem_image, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂, tendstoUniformlyOn_singleton_iff_tendsto] using @tendsto_id _ (𝓝 f) -/-- The map `(eVariationOn · s)` is lower semicontinuous for uniform convergence on `s`. -/ +/-- The map `(eVariationOn · s)` is lower semicontinuous for uniform convergence on `s`. -/ theorem lowerSemicontinuous_uniformOn (s : Set α) : LowerSemicontinuous fun f : α →ᵤ[{s}] E => eVariationOn f s := fun f ↦ by apply @lowerSemicontinuous_aux _ _ _ _ (UniformOnFun α E {s}) id (𝓝 f) f s _ @@ -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 @@ -766,12 +766,12 @@ theorem LipschitzOnWith.comp_locallyBoundedVariationOn {f : E → F} {C : ℝ≥ theorem LipschitzWith.comp_boundedVariationOn {f : E → F} {C : ℝ≥0} (hf : LipschitzWith C f) {g : α → E} {s : Set α} (h : BoundedVariationOn g s) : BoundedVariationOn (f ∘ g) s := - (hf.lipschitzOnWith univ).comp_boundedVariationOn (mapsTo_univ _ _) h + hf.lipschitzOnWith.comp_boundedVariationOn (mapsTo_univ _ _) h theorem LipschitzWith.comp_locallyBoundedVariationOn {f : E → F} {C : ℝ≥0} (hf : LipschitzWith C f) {g : α → E} {s : Set α} (h : LocallyBoundedVariationOn g s) : LocallyBoundedVariationOn (f ∘ g) s := - (hf.lipschitzOnWith univ).comp_locallyBoundedVariationOn (mapsTo_univ _ _) h + hf.lipschitzOnWith.comp_locallyBoundedVariationOn (mapsTo_univ _ _) h theorem LipschitzOnWith.locallyBoundedVariationOn {f : ℝ → E} {C : ℝ≥0} {s : Set ℝ} (hf : LipschitzOnWith C f s) : LocallyBoundedVariationOn f s := @@ -780,7 +780,7 @@ theorem LipschitzOnWith.locallyBoundedVariationOn {f : ℝ → E} {C : ℝ≥0} theorem LipschitzWith.locallyBoundedVariationOn {f : ℝ → E} {C : ℝ≥0} (hf : LipschitzWith C f) (s : Set ℝ) : LocallyBoundedVariationOn f s := - (hf.lipschitzOnWith s).locallyBoundedVariationOn + hf.lipschitzOnWith.locallyBoundedVariationOn end LipschitzOnWith diff --git a/Mathlib/Analysis/BoxIntegral/Basic.lean b/Mathlib/Analysis/BoxIntegral/Basic.lean index 1cb018280092e..e9d54c402baef 100644 --- a/Mathlib/Analysis/BoxIntegral/Basic.lean +++ b/Mathlib/Analysis/BoxIntegral/Basic.lean @@ -184,7 +184,7 @@ theorem hasIntegral_iff : HasIntegral I l f vol y ↔ simp [@forall_swap ℝ≥0 (TaggedPrepartition I)] /-- Quite often it is more natural to prove an estimate of the form `a * ε`, not `ε` in the RHS of -`BoxIntegral.hasIntegral_iff`, so we provide this auxiliary lemma. -/ +`BoxIntegral.hasIntegral_iff`, so we provide this auxiliary lemma. -/ theorem HasIntegral.of_mul (a : ℝ) (h : ∀ ε : ℝ, 0 < ε → ∃ r : ℝ≥0 → ℝⁿ → Ioi (0 : ℝ), (∀ c, l.RCond (r c)) ∧ ∀ c π, l.MemBaseSet I c (r c) π → IsPartition π → dist (integralSum f vol π) y ≤ a * ε) : @@ -391,7 +391,7 @@ additional distortion estimates if `BoxIntegral.IntegrationParams.bDistortion l corresponding integral sum is `ε`-close to the integral. If `BoxIntegral.IntegrationParams.bRiemann = true`, then `r c x` does not depend on `x`. If -`ε ≤ 0`, then we use `r c x = 1`. -/ +`ε ≤ 0`, then we use `r c x = 1`. -/ def convergenceR (h : Integrable I l f vol) (ε : ℝ) : ℝ≥0 → ℝⁿ → Ioi (0 : ℝ) := if hε : 0 < ε then (hasIntegral_iff.1 h.hasIntegral ε hε).choose else fun _ _ => ⟨1, Set.mem_Ioi.2 zero_lt_one⟩ @@ -447,7 +447,7 @@ theorem dist_integralSum_le_of_memBaseSet (h : Integrable I l f vol) (hpos₁ : /-- If `f` is integrable on `I` along `l`, then for two sufficiently fine tagged prepartitions (in the sense of the filter `BoxIntegral.IntegrationParams.toFilter l I`) such that they cover -the same part of `I`, the integral sums of `f` over `π₁` and `π₂` are very close to each other. -/ +the same part of `I`, the integral sums of `f` over `π₁` and `π₂` are very close to each other. -/ theorem tendsto_integralSum_toFilter_prod_self_inf_iUnion_eq_uniformity (h : Integrable I l f vol) : Tendsto (fun π : TaggedPrepartition I × TaggedPrepartition I => (integralSum f vol π.1, integralSum f vol π.2)) @@ -779,7 +779,7 @@ theorem HasIntegral.of_bRiemann_eq_false_of_forall_isLittleO (hl : l.bRiemann = choose! δ₂ Hδ₂ using H₂ have ε0' := half_pos ε0; have H0 : 0 < (2 : ℝ) ^ Fintype.card ι := pow_pos zero_lt_two _ rcases hs.exists_pos_forall_sum_le (div_pos ε0' H0) with ⟨εs, hεs0, hεs⟩ - simp only [le_div_iff' H0, mul_sum] at hεs + simp only [le_div_iff₀' H0, mul_sum] at hεs rcases exists_pos_mul_lt ε0' (B I) with ⟨ε', ε'0, hεI⟩ classical set δ : ℝ≥0 → ℝⁿ → Ioi (0 : ℝ) := fun c x => if x ∈ s then δ₁ c x (εs x) else (δ₂ c) x ε' diff --git a/Mathlib/Analysis/BoxIntegral/Box/Basic.lean b/Mathlib/Analysis/BoxIntegral/Box/Basic.lean index 4561dd670d380..551320c2187d8 100644 --- a/Mathlib/Analysis/BoxIntegral/Box/Basic.lean +++ b/Mathlib/Analysis/BoxIntegral/Box/Basic.lean @@ -8,7 +8,7 @@ import Mathlib.Order.Interval.Set.Monotone import Mathlib.Topology.MetricSpace.Basic import Mathlib.Topology.MetricSpace.Bounded import Mathlib.Topology.Order.MonotoneConvergence -import Mathlib.Topology.MetricSpace.Pseudo.Lemmas +import Mathlib.Topology.MetricSpace.Pseudo.Real /-! # Rectangular boxes in `ℝⁿ` @@ -51,13 +51,11 @@ that returns the box `⟨l, u, _⟩` if it is nonempty and `⊥` otherwise. rectangular box -/ - open Set Function Metric Filter noncomputable section -open scoped Classical -open NNReal Topology +open scoped Classical NNReal Topology namespace BoxIntegral @@ -92,7 +90,7 @@ theorem lower_ne_upper (i) : I.lower i ≠ I.upper i := (I.lower_lt_upper i).ne instance : Membership (ι → ℝ) (Box ι) := - ⟨fun x I ↦ ∀ i, x i ∈ Ioc (I.lower i) (I.upper i)⟩ + ⟨fun I x ↦ ∀ i, x i ∈ Ioc (I.lower i) (I.upper i)⟩ -- Porting note: added /-- The set of points in this box: this is the product of half-open intervals `(lower i, upper i]`, @@ -142,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} @@ -277,7 +272,7 @@ theorem withBotCoe_inj {I J : WithBot (Box ι)} : (I : Set (ι → ℝ)) = J ↔ /-- Make a `WithBot (Box ι)` from a pair of corners `l u : ι → ℝ`. If `l i < u i` for all `i`, then the result is `⟨l, u, _⟩ : Box ι`, otherwise it is `⊥`. In any case, the result interpreted -as a set in `ι → ℝ` is the set `{x : ι → ℝ | ∀ i, x i ∈ Ioc (l i) (u i)}`. -/ +as a set in `ι → ℝ` is the set `{x : ι → ℝ | ∀ i, x i ∈ Ioc (l i) (u i)}`. -/ def mk' (l u : ι → ℝ) : WithBot (Box ι) := if h : ∀ i, l i < u i then ↑(⟨l, u, h⟩ : Box ι) else ⊥ @@ -453,7 +448,7 @@ theorem distortion_eq_of_sub_eq_div {I J : Box ι} {r : ℝ} rw [← h] at this exact this.not_lt (sub_pos.2 <| I.lower_lt_upper i) have hn0 := (map_ne_zero Real.nnabs).2 this.ne' - simp_rw [NNReal.finset_sup_div, div_div_div_cancel_right _ hn0] + simp_rw [NNReal.finset_sup_div, div_div_div_cancel_right₀ hn0] theorem nndist_le_distortion_mul (I : Box ι) (i : ι) : nndist I.lower I.upper ≤ I.distortion * nndist (I.lower i) (I.upper i) := diff --git a/Mathlib/Analysis/BoxIntegral/Box/SubboxInduction.lean b/Mathlib/Analysis/BoxIntegral/Box/SubboxInduction.lean index d5bc8119aefce..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⟩, @@ -130,7 +130,7 @@ theorem subbox_induction_on' {p : Box ι → Prop} (I : Box ι) have hJsub : ∀ m i, (J m).upper i - (J m).lower i = (I.upper i - I.lower i) / 2 ^ m := by intro m i induction' m with m ihm - · simp [J, Nat.zero_eq] + · simp [J] simp only [pow_succ, J_succ, upper_sub_lower_splitCenterBox, ihm, div_div] have h0 : J 0 = I := rfl clear_value J @@ -151,9 +151,9 @@ theorem subbox_induction_on' {p : Box ι → Prop} (I : Box ι) simpa [hJsub] using tendsto_const_nhds.div_atTop (tendsto_pow_atTop_atTop_of_one_lt _root_.one_lt_two) replace hJlz : Tendsto (fun m ↦ (J m).lower) atTop (𝓝[Icc I.lower I.upper] z) := - tendsto_nhdsWithin_of_tendsto_nhds_of_eventually_within _ hJlz (eventually_of_forall hJl_mem) + tendsto_nhdsWithin_of_tendsto_nhds_of_eventually_within _ hJlz (Eventually.of_forall hJl_mem) replace hJuz : Tendsto (fun m ↦ (J m).upper) atTop (𝓝[Icc I.lower I.upper] z) := - tendsto_nhdsWithin_of_tendsto_nhds_of_eventually_within _ hJuz (eventually_of_forall hJu_mem) + tendsto_nhdsWithin_of_tendsto_nhds_of_eventually_within _ hJuz (Eventually.of_forall hJu_mem) rcases H_nhds z (h0 ▸ hzJ 0) with ⟨U, hUz, hU⟩ rcases (tendsto_lift'.1 (hJlz.Icc hJuz) U hUz).exists with ⟨m, hUm⟩ exact hJp m (hU (J m) (hJle m) m (hzJ m) hUm (hJsub m)) diff --git a/Mathlib/Analysis/BoxIntegral/DivergenceTheorem.lean b/Mathlib/Analysis/BoxIntegral/DivergenceTheorem.lean index 79429fdb79725..9c979a7202bd1 100644 --- a/Mathlib/Analysis/BoxIntegral/DivergenceTheorem.lean +++ b/Mathlib/Analysis/BoxIntegral/DivergenceTheorem.lean @@ -77,7 +77,7 @@ theorem norm_volume_sub_integral_face_upper_sub_lower_smul_le {f : (Fin (n + 1) `f y - a - f' (y - x)` over each of these faces is less than or equal to `ε * c * vol I`. We integrate a function of the norm `≤ ε * diam I.Icc` over a box of volume `∏ j ≠ i, (I.upper j - I.lower j)`. Since `diam I.Icc ≤ c * (I.upper i - I.lower i)`, we get the - required estimate. -/ + required estimate. -/ have Hl : I.lower i ∈ Icc (I.lower i) (I.upper i) := Set.left_mem_Icc.2 (I.lower_le_upper i) have Hu : I.upper i ∈ Icc (I.lower i) (I.upper i) := Set.right_mem_Icc.2 (I.lower_le_upper i) have Hi : ∀ x ∈ Icc (I.lower i) (I.upper i), diff --git a/Mathlib/Analysis/BoxIntegral/Integrability.lean b/Mathlib/Analysis/BoxIntegral/Integrability.lean index 8de8af41da9e9..eaf2f17700f98 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'] @@ -152,7 +152,7 @@ theorem HasIntegral.of_aeEq_zero {l : IntegrationParams} {I : Box ι} {f : (ι exact (mul_le_mul_left' this.le _).trans ENNReal.mul_div_le /-- If `f` has integral `y` on a box `I` with respect to a locally finite measure `μ` and `g` is -a.e. equal to `f` on `I`, then `g` has the same integral on `I`. -/ +a.e. equal to `f` on `I`, then `g` has the same integral on `I`. -/ theorem HasIntegral.congr_ae {l : IntegrationParams} {I : Box ι} {y : E} {f g : (ι → ℝ) → E} {μ : Measure (ι → ℝ)} [IsLocallyFiniteMeasure μ] (hf : HasIntegral.{u, v, v} I l f μ.toBoxAdditive.toSMul y) (hfg : f =ᵐ[μ.restrict I] g) @@ -191,7 +191,7 @@ end SimpleFunc open TopologicalSpace /-- If `f : ℝⁿ → E` is Bochner integrable w.r.t. a locally finite measure `μ` on a rectangular box -`I`, then it is McShane integrable on `I` with the same integral. -/ +`I`, then it is McShane integrable on `I` with the same integral. -/ theorem IntegrableOn.hasBoxIntegral [CompleteSpace E] {f : (ι → ℝ) → E} {μ : Measure (ι → ℝ)} [IsLocallyFiniteMeasure μ] {I : Box ι} (hf : IntegrableOn f I μ) (l : IntegrationParams) (hl : l.bRiemann = false) : @@ -294,7 +294,7 @@ theorem IntegrableOn.hasBoxIntegral [CompleteSpace E] {f : (ι → ℝ) → E} { integral_finset_biUnion π.boxes (fun J _ => J.measurableSet_coe) π.pairwiseDisjoint (hfgi _)] refine dist_sum_sum_le_of_le _ fun J hJ => ?_ rw [dist_eq_norm, ← integral_sub (hfi _ J hJ) (hgi J hJ)] - refine norm_integral_le_of_norm_le (hfgi _ J hJ) (eventually_of_forall fun x => ?_) + refine norm_integral_le_of_norm_le (hfgi _ J hJ) (Eventually.of_forall fun x => ?_) exact hfg_mono x (hNx (π.tag J)) /-- If `f : ℝⁿ → E` is continuous on a rectangular box `I`, then it is Box integrable on `I` diff --git a/Mathlib/Analysis/BoxIntegral/Partition/Additive.lean b/Mathlib/Analysis/BoxIntegral/Partition/Additive.lean index e7a53933badbc..a82e54fd54bb5 100644 --- a/Mathlib/Analysis/BoxIntegral/Partition/Additive.lean +++ b/Mathlib/Analysis/BoxIntegral/Partition/Additive.lean @@ -26,7 +26,6 @@ In this file we define box-additive functions and prove that a function such tha rectangular box, additive function -/ - noncomputable section open scoped Classical @@ -191,7 +190,7 @@ def upperSubLower.{u} {G : Type u} [AddCommGroup G] (I₀ : Box (Fin (n + 1))) ( rw [WithTop.coe_le_coe] at hJ refine i.succAboveCases (fun hx => ?_) (fun j hx => ?_) j · simp only [Box.splitLower_def hx, Box.splitUpper_def hx, update_same, ← WithBot.some_eq_coe, - Option.elim', Box.face, (· ∘ ·), update_noteq (Fin.succAbove_ne _ _)] + Option.elim', Box.face, Function.comp_def, update_noteq (Fin.succAbove_ne _ _)] abel · have : (J.face i : WithTop (Box (Fin n))) ≤ I₀.face i := WithTop.coe_le_coe.2 (face_mono hJ i) diff --git a/Mathlib/Analysis/BoxIntegral/Partition/Basic.lean b/Mathlib/Analysis/BoxIntegral/Partition/Basic.lean index f9b75b2ded3d5..788c55499703d 100644 --- a/Mathlib/Analysis/BoxIntegral/Partition/Basic.lean +++ b/Mathlib/Analysis/BoxIntegral/Partition/Basic.lean @@ -36,11 +36,8 @@ We also define a `SemilatticeInf` structure on `BoxIntegral.Prepartition I` for rectangular box, partition -/ - open Set Finset Function - -open scoped Classical -open NNReal +open scoped Classical NNReal noncomputable section @@ -63,7 +60,7 @@ namespace Prepartition variable {I J J₁ J₂ : Box ι} (π : Prepartition I) {π₁ π₂ : Prepartition I} {x : ι → ℝ} instance : Membership (Box ι) (Prepartition I) := - ⟨fun J π => J ∈ π.boxes⟩ + ⟨fun π J => J ∈ π.boxes⟩ @[simp] theorem mem_boxes : J ∈ π.boxes ↔ J ∈ π := Iff.rfl @@ -544,7 +541,8 @@ theorem filter_true : (π.filter fun _ => True) = π := theorem iUnion_filter_not (π : Prepartition I) (p : Box ι → Prop) : (π.filter fun J => ¬p J).iUnion = π.iUnion \ (π.filter p).iUnion := by simp only [Prepartition.iUnion] - convert (@Set.biUnion_diff_biUnion_eq (ι → ℝ) (Box ι) π.boxes (π.filter p).boxes (↑) _).symm + convert + (@Set.biUnion_diff_biUnion_eq (ι → ℝ) (Box ι) π.boxes (π.filter p).boxes (↑) _).symm using 4 · simp (config := { contextual := true }) · rw [Set.PairwiseDisjoint] convert π.pairwiseDisjoint @@ -625,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 caa6545c2bab8..c1b1d7ea49571 100644 --- a/Mathlib/Analysis/BoxIntegral/Partition/Filter.lean +++ b/Mathlib/Analysis/BoxIntegral/Partition/Filter.lean @@ -163,11 +163,8 @@ prepartition (and consider the special case `π = ⊥` separately if needed). integral, rectangular box, partition, filter -/ - open Set Function Filter Metric Finset Bool - -open scoped Classical -open Topology Filter NNReal +open scoped Classical Topology Filter NNReal noncomputable section @@ -226,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 @@ -518,7 +515,7 @@ theorem eventually_isPartition (l : IntegrationParams) (I : Box ι) : ∀ᶠ π in l.toFilteriUnion I ⊤, TaggedPrepartition.IsPartition π := eventually_iSup.2 fun _ => eventually_inf_principal.2 <| - eventually_of_forall fun π h => + Eventually.of_forall fun π h => π.isPartition_iff_iUnion_eq.2 (h.trans Prepartition.iUnion_top) end IntegrationParams diff --git a/Mathlib/Analysis/BoxIntegral/Partition/Split.lean b/Mathlib/Analysis/BoxIntegral/Partition/Split.lean index 50bc2ecd32943..06363982a7538 100644 --- a/Mathlib/Analysis/BoxIntegral/Partition/Split.lean +++ b/Mathlib/Analysis/BoxIntegral/Partition/Split.lean @@ -35,12 +35,9 @@ is available as `BoxIntegral.Prepartition.compl`. rectangular box, partition, hyperplane -/ - noncomputable section open scoped Classical -open Filter - open Function Set Filter namespace BoxIntegral @@ -152,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) @@ -247,7 +244,7 @@ theorem inf_splitMany {I : Box ι} (π : Prepartition I) (s : Finset (ι × ℝ) /-- Let `s : Finset (ι × ℝ)` be a set of hyperplanes `{x : ι → ℝ | x i = r}` in `ι → ℝ` encoded as pairs `(i, r)`. Suppose that this set contains all faces of a box `J`. The hyperplanes of `s` split a box `I` into subboxes. Let `Js` be one of them. If `J` and `Js` have nonempty intersection, then -`Js` is a subbox of `J`. -/ +`Js` is a subbox of `J`. -/ theorem not_disjoint_imp_le_of_subset_of_mem_splitMany {I J Js : Box ι} {s : Finset (ι × ℝ)} (H : ∀ i, {(i, J.lower i), (i, J.upper i)} ⊆ s) (HJs : Js ∈ splitMany I s) (Hn : ¬Disjoint (J : WithBot (Box ι)) Js) : Js ≤ J := by diff --git a/Mathlib/Analysis/BoxIntegral/Partition/Tagged.lean b/Mathlib/Analysis/BoxIntegral/Partition/Tagged.lean index 71fea77c5b71a..967500dc84169 100644 --- a/Mathlib/Analysis/BoxIntegral/Partition/Tagged.lean +++ b/Mathlib/Analysis/BoxIntegral/Partition/Tagged.lean @@ -49,7 +49,7 @@ namespace TaggedPrepartition variable {I J J₁ J₂ : Box ι} (π : TaggedPrepartition I) {x : ι → ℝ} instance : Membership (Box ι) (TaggedPrepartition I) := - ⟨fun J π => J ∈ π.boxes⟩ + ⟨fun π J => J ∈ π.boxes⟩ @[simp] theorem mem_toPrepartition {π : TaggedPrepartition I} : J ∈ π.toPrepartition ↔ J ∈ π := Iff.rfl diff --git a/Mathlib/Analysis/CStarAlgebra/Basic.lean b/Mathlib/Analysis/CStarAlgebra/Basic.lean index f0cb7d301a058..34c2684caead7 100644 --- a/Mathlib/Analysis/CStarAlgebra/Basic.lean +++ b/Mathlib/Analysis/CStarAlgebra/Basic.lean @@ -233,7 +233,7 @@ end CStarRing theorem IsSelfAdjoint.nnnorm_pow_two_pow [NormedRing E] [StarRing E] [CStarRing E] {x : E} (hx : IsSelfAdjoint x) (n : ℕ) : ‖x ^ 2 ^ n‖₊ = ‖x‖₊ ^ 2 ^ n := by induction' n with k hk - · simp only [pow_zero, pow_one, Nat.zero_eq] + · simp only [pow_zero, pow_one] · rw [pow_succ', pow_mul', sq] nth_rw 1 [← selfAdjoint.mem_iff.mp hx] rw [← star_pow, CStarRing.nnnorm_star_mul_self, ← sq, hk, pow_mul'] diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Basic.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Basic.lean index 2dc9d1ad67c79..073d532f7a479 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Basic.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Basic.lean @@ -25,8 +25,10 @@ description is perfectly accurate in finite dimension, but only heuristic in inf there might be no genuine eigenvector. In particular, when `f` is a polynomial `∑ cᵢ Xⁱ`, then `f a` is `∑ cᵢ aⁱ`. Also, `id a = a`. -This file also includes a proof of the **spectral permanence** theorem for (unital) C⋆-algebras -(see `StarSubalgebra.spectrum_eq`) +The result we have established here is the strongest possible, but it is not the version which is +most useful in practice. The generic API for the continuous functional calculus can be found in +`Analysis.CStarAlgebra.ContinuousFunctionalCalculus` in the `Unital` and `NonUnital` files. The +relevant instances on C⋆-algebra can be found in the `Instances` file. ## Main definitions @@ -39,19 +41,7 @@ This file also includes a proof of the **spectral permanence** theorem for (unit algebra homomorphism. Moreover, this map is continuous and bijective and since the spaces involved are compact Hausdorff, it is a homeomorphism. -## Main statements - -* `StarSubalgebra.coe_isUnit`: for `x : S` in a C⋆-Subalgebra `S` of `A`, then `↑x : A` is a Unit - if and only if `x` is a unit. -* `StarSubalgebra.spectrum_eq`: **spectral_permanence** for `x : S`, where `S` is a C⋆-Subalgebra - of `A`, `spectrum ℂ x = spectrum ℂ (x : A)`. - -## Notes - -The result we have established here is the strongest possible, but it is likely not the version -which will be most useful in practice. Future work will include developing an appropriate API for -the continuous functional calculus (including one for real-valued functions with real argument that -applies to self-adjoint elements of the algebra). -/ + -/ open scoped Pointwise ENNReal NNReal ComplexOrder @@ -67,142 +57,8 @@ instance {R A : Type*} [CommRing R] [StarRing R] [NormedRing A] [Algebra R A] [S { SubringClass.toNormedRing (elementalStarAlgebra R a) with mul_comm := mul_comm } --- Porting note: these hack instances no longer seem to be necessary - variable [CompleteSpace A] (a : A) [IsStarNormal a] (S : StarSubalgebra ℂ A) -/-- This lemma is used in the proof of `elementalStarAlgebra.isUnit_of_isUnit_of_isStarNormal`, -which in turn is the key to spectral permanence `StarSubalgebra.spectrum_eq`, which is itself -necessary for the continuous functional calculus. Using the continuous functional calculus, this -lemma can be superseded by one that omits the `IsStarNormal` hypothesis. -/ -theorem spectrum_star_mul_self_of_isStarNormal : - spectrum ℂ (star a * a) ⊆ Set.Icc (0 : ℂ) ‖star a * a‖ := by - -- this instance should be found automatically, but without providing it Lean goes on a wild - -- goose chase when trying to apply `spectrum.gelfandTransform_eq`. - --letI := elementalStarAlgebra.Complex.normedAlgebra a - rcases subsingleton_or_nontrivial A with ⟨⟩ - · simp only [spectrum.of_subsingleton, Set.empty_subset] - · set a' : elementalStarAlgebra ℂ a := ⟨a, self_mem ℂ a⟩ - refine (spectrum.subset_subalgebra (star a' * a')).trans ?_ - rw [← spectrum.gelfandTransform_eq (star a' * a'), ContinuousMap.spectrum_eq_range] - rintro - ⟨φ, rfl⟩ - rw [gelfandTransform_apply_apply ℂ _ (star a' * a') φ, map_mul φ, map_star φ] - rw [Complex.eq_coe_norm_of_nonneg (star_mul_self_nonneg _), ← map_star, ← map_mul] - exact ⟨by positivity, Complex.real_le_real.2 (AlgHom.norm_apply_le_self φ (star a' * a'))⟩ - -variable {a} - -/-- This is the key lemma on the way to establishing spectral permanence for C⋆-algebras, which is -established in `StarSubalgebra.spectrum_eq`. This lemma is superseded by -`StarSubalgebra.coe_isUnit`, which does not require an `IsStarNormal` hypothesis and holds for -any closed star subalgebra. -/ -theorem elementalStarAlgebra.isUnit_of_isUnit_of_isStarNormal (h : IsUnit a) : - IsUnit (⟨a, self_mem ℂ a⟩ : elementalStarAlgebra ℂ a) := by - /- Sketch of proof: Because `a` is normal, it suffices to prove that `star a * a` is invertible - in `elementalStarAlgebra ℂ a`. For this it suffices to prove that it is sufficiently close to a - unit, namely `algebraMap ℂ _ ‖star a * a‖`, and in this case the required distance is - `‖star a * a‖`. So one must show `‖star a * a - algebraMap ℂ _ ‖star a * a‖‖ < ‖star a * a‖`. - Since `star a * a - algebraMap ℂ _ ‖star a * a‖` is selfadjoint, by a corollary of Gelfand's - formula for the spectral radius (`IsSelfAdjoint.spectralRadius_eq_nnnorm`) its norm is the - supremum of the norms of elements in its spectrum (we may use the spectrum in `A` here because - the norm in `A` and the norm in the subalgebra coincide). - - By `spectrum_star_mul_self_of_isStarNormal`, the spectrum (in the algebra `A`) of `star a * a` - is contained in the interval `[0, ‖star a * a‖]`, and since `a` (and hence `star a * a`) is - invertible in `A`, we may omit `0` from this interval. Therefore, by basic spectral mapping - properties, the spectrum (in the algebra `A`) of `star a * a - algebraMap ℂ _ ‖star a * a‖` is - contained in `[0, ‖star a * a‖)`. The supremum of the (norms of) elements of the spectrum must - be *strictly* less that `‖star a * a‖` because the spectrum is compact, which completes the - proof. -/ - /- We may assume `A` is nontrivial. It suffices to show that `star a * a` is invertible in the - commutative (because `a` is normal) ring `elementalStarAlgebra ℂ a`. Indeed, by commutativity, - if `star a * a` is invertible, then so is `a`. -/ - nontriviality A - set a' : elementalStarAlgebra ℂ a := ⟨a, self_mem ℂ a⟩ - suffices IsUnit (star a' * a') from (IsUnit.mul_iff.1 this).2 - replace h := (show Commute (star a) a from star_comm_self' a).isUnit_mul_iff.2 ⟨h.star, h⟩ - /- Since `a` is invertible, `‖star a * a‖ ≠ 0`, so `‖star a * a‖ • 1` is invertible in - `elementalStarAlgebra ℂ a`, and so it suffices to show that the distance between this unit and - `star a * a` is less than `‖star a * a‖`. -/ - have h₁ : (‖star a * a‖ : ℂ) ≠ 0 := Complex.ofReal_ne_zero.mpr (norm_ne_zero_iff.mpr h.ne_zero) - set u : Units (elementalStarAlgebra ℂ a) := - Units.map (algebraMap ℂ (elementalStarAlgebra ℂ a)).toMonoidHom (Units.mk0 _ h₁) - refine ⟨u.ofNearby _ ?_, rfl⟩ - simp only [u, Units.coe_map, Units.val_inv_eq_inv_val, RingHom.toMonoidHom_eq_coe, Units.val_mk0, - Units.coe_map_inv, MonoidHom.coe_coe, norm_algebraMap', norm_inv, Complex.norm_eq_abs, - Complex.abs_ofReal, abs_norm, inv_inv] - /- Since `a` is invertible, by `spectrum_star_mul_self_of_isStarNormal`, the spectrum (in `A`) - of `star a * a` is contained in the half-open interval `(0, ‖star a * a‖]`. Therefore, by basic - spectral mapping properties, the spectrum of `‖star a * a‖ • 1 - star a * a` is contained in - `[0, ‖star a * a‖)`. -/ - have h₂ : ∀ z ∈ spectrum ℂ (algebraMap ℂ A ‖star a * a‖ - star a * a), ‖z‖₊ < ‖star a * a‖₊ := by - intro z hz - rw [← spectrum.singleton_sub_eq, Set.singleton_sub] at hz - have h₃ : z ∈ Set.Icc (0 : ℂ) ‖star a * a‖ := by - replace hz := Set.image_subset _ (spectrum_star_mul_self_of_isStarNormal a) hz - rwa [Set.image_const_sub_Icc, sub_self, sub_zero] at hz - refine lt_of_le_of_ne (Complex.real_le_real.1 <| Complex.eq_coe_norm_of_nonneg h₃.1 ▸ h₃.2) ?_ - · intro hz' - replace hz' := congr_arg (fun x : ℝ≥0 => ((x : ℝ) : ℂ)) hz' - simp only [coe_nnnorm] at hz' - rw [← Complex.eq_coe_norm_of_nonneg h₃.1] at hz' - obtain ⟨w, hw₁, hw₂⟩ := hz - refine (spectrum.zero_not_mem_iff ℂ).mpr h ?_ - rw [hz', sub_eq_self] at hw₂ - rwa [hw₂] at hw₁ - /- The norm of `‖star a * a‖ • 1 - star a * a` in the subalgebra and in `A` coincide. In `A`, - because this element is selfadjoint, by `IsSelfAdjoint.spectralRadius_eq_nnnorm`, its norm is - the supremum of the norms of the elements of the spectrum, which is strictly less than - `‖star a * a‖` by `h₂` and because the spectrum is compact. -/ - exact ENNReal.coe_lt_coe.1 - (calc - (‖star a' * a' - algebraMap ℂ _ ‖star a * a‖‖₊ : ℝ≥0∞) = - ‖algebraMap ℂ A ‖star a * a‖ - star a * a‖₊ := by - rw [← nnnorm_neg, neg_sub]; rfl - _ = spectralRadius ℂ (algebraMap ℂ A ‖star a * a‖ - star a * a) := by - refine (IsSelfAdjoint.spectralRadius_eq_nnnorm ?_).symm - rw [IsSelfAdjoint, star_sub, star_mul, star_star, ← algebraMap_star_comm] - congr! - exact RCLike.conj_ofReal _ - _ < ‖star a * a‖₊ := spectrum.spectralRadius_lt_of_forall_lt _ h₂) - -/-- For `x : A` which is invertible in `A`, the inverse lies in any unital C⋆-subalgebra `S` -containing `x`. -/ -theorem StarSubalgebra.isUnit_coe_inv_mem {S : StarSubalgebra ℂ A} (hS : IsClosed (S : Set A)) - {x : A} (h : IsUnit x) (hxS : x ∈ S) : ↑h.unit⁻¹ ∈ S := by - have hx := h.star.mul h - suffices this : (↑hx.unit⁻¹ : A) ∈ S by - rw [← one_mul (↑h.unit⁻¹ : A), ← hx.unit.inv_mul, mul_assoc, IsUnit.unit_spec, mul_assoc, - h.mul_val_inv, mul_one] - exact mul_mem this (star_mem hxS) - refine le_of_isClosed_of_mem ℂ hS (mul_mem (star_mem hxS) hxS) ?_ - haveI := (IsSelfAdjoint.star_mul_self x).isStarNormal - have hx' := elementalStarAlgebra.isUnit_of_isUnit_of_isStarNormal hx - convert (↑hx'.unit⁻¹ : elementalStarAlgebra ℂ (star x * x)).prop using 1 - refine left_inv_eq_right_inv hx.unit.inv_mul ?_ - exact (congr_arg ((↑) : _ → A) hx'.unit.mul_inv) - -/-- For a unital C⋆-subalgebra `S` of `A` and `x : S`, if `↑x : A` is invertible in `A`, then -`x` is invertible in `S`. -/ -theorem StarSubalgebra.coe_isUnit {S : StarSubalgebra ℂ A} (hS : IsClosed (S : Set A)) {x : S} : - IsUnit (x : A) ↔ IsUnit x := by - refine ⟨fun hx => - ⟨⟨x, ⟨(↑hx.unit⁻¹ : A), StarSubalgebra.isUnit_coe_inv_mem hS hx x.prop⟩, ?_, ?_⟩, rfl⟩, - fun hx => hx.map S.subtype⟩ - exacts [Subtype.coe_injective hx.mul_val_inv, Subtype.coe_injective hx.val_inv_mul] - -theorem StarSubalgebra.mem_spectrum_iff {S : StarSubalgebra ℂ A} (hS : IsClosed (S : Set A)) {x : S} - {z : ℂ} : z ∈ spectrum ℂ x ↔ z ∈ spectrum ℂ (x : A) := - not_iff_not.2 (StarSubalgebra.coe_isUnit hS).symm - -/-- **Spectral permanence.** The spectrum of an element is invariant of the (closed) -`StarSubalgebra` in which it is contained. -/ -theorem StarSubalgebra.spectrum_eq {S : StarSubalgebra ℂ A} (hS : IsClosed (S : Set A)) (x : S) : - spectrum ℂ x = spectrum ℂ (x : A) := - Set.ext fun _z => StarSubalgebra.mem_spectrum_iff hS - -variable (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`, but because we want something in `spectrum ℂ x`, as opposed to @@ -212,9 +68,8 @@ noncomputable def elementalStarAlgebra.characterSpaceToSpectrum (x : A) (φ : characterSpace ℂ (elementalStarAlgebra ℂ x)) : spectrum ℂ x where val := φ ⟨x, self_mem ℂ x⟩ property := by - simpa only [StarSubalgebra.spectrum_eq (elementalStarAlgebra.isClosed ℂ x) - ⟨x, self_mem ℂ x⟩] using - AlgHom.apply_mem_spectrum φ ⟨x, self_mem ℂ x⟩ + simpa only [StarSubalgebra.spectrum_eq (hS := elementalStarAlgebra.isClosed ℂ x) + (a := ⟨x, self_mem ℂ x⟩)] using AlgHom.apply_mem_spectrum φ ⟨x, self_mem ℂ x⟩ #adaptation_note /-- nightly-2024-04-01 The simpNF linter now times out on this lemma. @@ -234,8 +89,8 @@ theorem elementalStarAlgebra.bijective_characterSpaceToSpectrum : · simpa only [elementalStarAlgebra.characterSpaceToSpectrum, Subtype.mk_eq_mk, ContinuousMap.coe_mk] using h · rintro ⟨z, hz⟩ - have hz' := (StarSubalgebra.spectrum_eq (elementalStarAlgebra.isClosed ℂ a) - ⟨a, self_mem ℂ a⟩).symm.subst hz + have hz' := (StarSubalgebra.spectrum_eq (hS := elementalStarAlgebra.isClosed ℂ a) + (a := ⟨a, self_mem ℂ a⟩) ▸ hz) rw [CharacterSpace.mem_spectrum_iff_exists] at hz' obtain ⟨φ, rfl⟩ := hz' exact ⟨φ, rfl⟩ diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Instances.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Instances.lean index cc87a12072105..180ca90ca5288 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 @@ -169,7 +169,7 @@ instance IsStarNormal.instContinuousFunctionalCalculus {A : Type*} [NormedRing A case hom_map_spectrum => intro f simp only [StarAlgHom.comp_apply, StarAlgHom.coe_coe, StarSubalgebra.coe_subtype] - rw [← StarSubalgebra.spectrum_eq (elementalStarAlgebra.isClosed ℂ a), + rw [← StarSubalgebra.spectrum_eq (hS := elementalStarAlgebra.isClosed ℂ 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 _⟩ @@ -215,13 +215,11 @@ lemma QuasispectrumRestricts.isSelfAdjoint (a : A) (ha : QuasispectrumRestricts [IsStarNormal a] : IsSelfAdjoint a := isSelfAdjoint_iff_isStarNormal_and_quasispectrumRestricts.mpr ⟨‹_›, ha⟩ -instance IsSelfAdjoint.instNonUnitalContinuousFunctionalCalculus - [∀ x : A, CompactSpace (σₙ ℂ x)] : +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) - (fun _ _ ↦ inferInstance) end SelfAdjointNonUnital @@ -263,12 +261,16 @@ lemma SpectrumRestricts.isSelfAdjoint (a : A) (ha : SpectrumRestricts a Complex. [IsStarNormal a] : IsSelfAdjoint a := isSelfAdjoint_iff_isStarNormal_and_spectrumRestricts.mpr ⟨‹_›, ha⟩ -instance IsSelfAdjoint.instContinuousFunctionalCalculus [∀ x : A, CompactSpace (spectrum ℂ x)] : +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) - (fun _ _ ↦ inferInstance) + +lemma IsSelfAdjoint.spectrum_nonempty {A : Type*} [Ring A] [StarRing A] + [TopologicalSpace A] [Algebra ℝ A] [ContinuousFunctionalCalculus ℝ (IsSelfAdjoint : A → Prop)] + [Nontrivial A] {a : A} (ha : IsSelfAdjoint a) : (σ ℝ a).Nonempty := + CFC.spectrum_nonempty ℝ a ha end SelfAdjointUnital @@ -308,12 +310,17 @@ lemma nonneg_iff_isSelfAdjoint_and_quasispectrumRestricts {a : A} : simpa [sq, hx.star_eq] using star_mul_self_nonneg x open NNReal in -instance Nonneg.instNonUnitalContinuousFunctionalCalculus [∀ a : A, CompactSpace (σₙ ℝ a)] : +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) - (fun _ _ ↦ inferInstance) + +open NNReal in +lemma NNReal.spectrum_nonempty {A : Type*} [Ring A] [StarRing A] [PartialOrder A] + [TopologicalSpace A] [Algebra ℝ≥0 A] [ContinuousFunctionalCalculus ℝ≥0 (fun x : A ↦ 0 ≤ x)] + [Nontrivial A] {a : A} (ha : 0 ≤ a) : (spectrum ℝ≥0 a).Nonempty := + CFC.spectrum_nonempty ℝ≥0 a ha end Nonneg @@ -349,11 +356,10 @@ lemma nonneg_iff_isSelfAdjoint_and_spectrumRestricts {a : A} : simpa [sq, hx.star_eq] using star_mul_self_nonneg x open NNReal in -instance Nonneg.instContinuousFunctionalCalculus [∀ a : A, CompactSpace (spectrum ℝ a)] : +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) - (fun _ _ ↦ inferInstance) + isUniformEmbedding_subtype_val le_rfl (fun _ ↦ nonneg_iff_isSelfAdjoint_and_spectrumRestricts) end Nonneg @@ -489,7 +495,7 @@ variable {A : Type*} [NormedRing A] [CompleteSpace A] variable [PartialOrder A] [StarRing A] [StarOrderedRing A] [CStarRing A] variable [NormedAlgebra ℂ A] [StarModule ℂ 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 @@ -505,7 +511,7 @@ instance CStarRing.instNonnegSpectrumClass : NonnegSpectrumClass ℝ A := 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 ↦ ?_) @@ -525,7 +531,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] @@ -538,9 +544,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 @@ -572,12 +578,12 @@ 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] -instance CStarRing.instNonnegSpectrumClass' : NonnegSpectrumClass ℝ A where +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 (Unitization ℂ A) + have := CStarAlgebra.spectralOrderedRing (Unitization ℂ A) apply spectrum_nonneg_of_nonneg rw [StarOrderedRing.nonneg_iff] at ha ⊢ have := AddSubmonoid.mem_map_of_mem (Unitization.inrNonUnitalStarAlgHom ℂ A) ha @@ -595,25 +601,42 @@ section RealEqComplex variable {A : Type*} [TopologicalSpace A] [Ring A] [StarRing A] [Algebra ℂ A] [ContinuousFunctionalCalculus ℂ (IsStarNormal : A → Prop)] - [ContinuousFunctionalCalculus ℝ (IsSelfAdjoint : A → Prop)] [UniqueContinuousFunctionalCalculus ℝ A] - [UniqueContinuousFunctionalCalculus ℂ A] lemma cfcHom_real_eq_restrict {a : A} (ha : IsSelfAdjoint a) : cfcHom ha = ha.spectrumRestricts.starAlgHom (cfcHom ha.isStarNormal) (f := Complex.reCLM) := - have := UniqueContinuousFunctionalCalculus.compactSpace_spectrum a (R := ℂ) - 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 - have := UniqueContinuousFunctionalCalculus.compactSpace_spectrum a (R := ℂ) 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 +section RealEqComplexNonUnital + +variable {A : Type*} [TopologicalSpace A] [NonUnitalRing A] [StarRing A] [Module ℂ A] + [IsScalarTower ℂ A A] [SMulCommClass ℂ A A] + [NonUnitalContinuousFunctionalCalculus ℂ (IsStarNormal : A → Prop)] + [UniqueNonUnitalContinuousFunctionalCalculus ℝ A] + +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.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.isUniformEmbedding ha ha.isStarNormal f + +end RealEqComplexNonUnital + section NNRealEqReal open NNReal @@ -627,16 +650,39 @@ 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 - have := UniqueContinuousFunctionalCalculus.compactSpace_spectrum a (R := ℝ) - 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 - have := UniqueContinuousFunctionalCalculus.compactSpace_spectrum a (R := ℝ) 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 +section NNRealEqRealNonUnital + +open NNReal + +variable {A : Type*} [TopologicalSpace A] [NonUnitalRing A] [PartialOrder A] [StarRing A] + [StarOrderedRing A] [Module ℝ A] [TopologicalRing A] [IsScalarTower ℝ A A] [SMulCommClass ℝ A A] + [NonUnitalContinuousFunctionalCalculus ℝ (IsSelfAdjoint : A → Prop)] + [NonUnitalContinuousFunctionalCalculus ℝ≥0 ((0 : A) ≤ ·)] + [UniqueNonUnitalContinuousFunctionalCalculus ℝ A] + [NonnegSpectrumClass ℝ A] + +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 _ + 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 _ + isUniformEmbedding_subtype_val ha (.of_nonneg ha) + +end NNRealEqRealNonUnital + end diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Integral.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Integral.lean new file mode 100644 index 0000000000000..f56a3cf3d1927 --- /dev/null +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Integral.lean @@ -0,0 +1,147 @@ +/- +Copyright (c) 2024 Frédéric Dupuis. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Dupuis +-/ + +import Mathlib.Analysis.Normed.Algebra.Spectrum +import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Unital +import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.NonUnital +import Mathlib.MeasureTheory.Integral.SetIntegral + +/-! +# Integrals and the continuous functional calculus + +This file gives results about integrals of the form `∫ x, cfc (f x) a`. Most notably, we show +that the integral commutes with the continuous functional calculus under appropriate conditions. + +## Main declarations + ++ `cfc_integral`: given a function `f : X → 𝕜 → 𝕜`, we have that + `cfc (fun r => ∫ x, f x r ∂μ) a = ∫ x, cfc (f x) a ∂μ` + under appropriate conditions ++ `cfcₙ_integral`: given a function `f : X → 𝕜 → 𝕜`, we have that + `cfcₙ (fun r => ∫ x, f x r ∂μ) a = ∫ x, cfcₙ (f x) a ∂μ` + under appropriate conditions + +## TODO + ++ Lift this to the case where the CFC is over `ℝ≥0` ++ Use this to prove operator monotonicity and concavity/convexity of `rpow` and `log` +-/ + +open MeasureTheory +open scoped ContinuousMapZero + +section unital + +variable {X : Type*} {𝕜 : Type*} {A : Type*} {p : A → Prop} [RCLike 𝕜] + [MeasurableSpace X] {μ : Measure X} + [NormedRing A] [StarRing A] [NormedAlgebra 𝕜 A] [NormedAlgebra ℝ A] [CompleteSpace A] + [ContinuousFunctionalCalculus 𝕜 p] + +lemma cfcL_integral (a : A) (f : X → C(spectrum 𝕜 a, 𝕜)) (hf₁ : Integrable f μ) + (ha : p a := by cfc_tac) : + ∫ x, cfcL (a := a) ha (f x) ∂μ = cfcL (a := a) ha (∫ x, f x ∂μ) := by + rw [ContinuousLinearMap.integral_comp_comm _ hf₁] + +lemma cfcHom_integral (a : A) (f : X → C(spectrum 𝕜 a, 𝕜)) (hf₁ : Integrable f μ) + (ha : p a := by cfc_tac) : + ∫ x, cfcHom (a := a) ha (f x) ∂μ = cfcHom (a := a) ha (∫ x, f x ∂μ) := + cfcL_integral a f hf₁ ha + +open ContinuousMap in +/-- The continuous functional calculus commutes with integration. -/ +lemma cfc_integral [TopologicalSpace X] [OpensMeasurableSpace X] (f : X → 𝕜 → 𝕜) + (bound : X → ℝ) (a : A) [SecondCountableTopologyEither X C(spectrum 𝕜 a, 𝕜)] + (hf₁ : ∀ x, ContinuousOn (f x) (spectrum 𝕜 a)) + (hf₂ : Continuous (fun x ↦ (⟨_, hf₁ x |>.restrict⟩ : C(spectrum 𝕜 a, 𝕜)))) + (hbound : ∀ x, ∀ z ∈ spectrum 𝕜 a, ‖f x z‖ ≤ ‖bound x‖) + (hbound_finite_integral : HasFiniteIntegral bound μ) (ha : p a := by cfc_tac) : + cfc (fun r => ∫ x, f x r ∂μ) a = ∫ x, cfc (f x) a ∂μ := by + let fc : X → C(spectrum 𝕜 a, 𝕜) := fun x => ⟨_, (hf₁ x).restrict⟩ + have fc_integrable : Integrable fc μ := by + refine ⟨hf₂.aestronglyMeasurable, ?_⟩ + refine hbound_finite_integral.mono <| .of_forall fun x ↦ ?_ + rw [norm_le _ (norm_nonneg (bound x))] + exact fun z ↦ hbound x z.1 z.2 + have h_int_fc : (spectrum 𝕜 a).restrict (∫ x, f x · ∂μ) = ∫ x, fc x ∂μ := by + ext; simp [integral_apply fc_integrable, fc] + have hcont₂ : ContinuousOn (fun r => ∫ x, f x r ∂μ) (spectrum 𝕜 a) := by + rw [continuousOn_iff_continuous_restrict] + convert map_continuous (∫ x, fc x ∂μ) + rw [integral_congr_ae (.of_forall fun _ ↦ cfc_apply ..), cfc_apply .., + cfcHom_integral _ _ fc_integrable] + congr + +/-- The continuous functional calculus commutes with integration. -/ +lemma cfc_integral' [TopologicalSpace X] [OpensMeasurableSpace X] (f : X → 𝕜 → 𝕜) + (bound : X → ℝ) (a : A) [SecondCountableTopologyEither X C(spectrum 𝕜 a, 𝕜)] + (hf : Continuous (fun x => (spectrum 𝕜 a).restrict (f x)).uncurry) + (hbound : ∀ x, ∀ z ∈ spectrum 𝕜 a, ‖f x z‖ ≤ ‖bound x‖) + (hbound_finite_integral : HasFiniteIntegral bound μ) (ha : p a := by cfc_tac) : + cfc (fun r => ∫ x, f x r ∂μ) a = ∫ x, cfc (f x) a ∂μ := by + refine cfc_integral f bound a ?_ ?_ hbound hbound_finite_integral + · exact (continuousOn_iff_continuous_restrict.mpr <| hf.uncurry_left ·) + · exact ContinuousMap.curry ⟨_, hf⟩ |>.continuous + +end unital + +section nonunital + +variable {X : Type*} {𝕜 : Type*} {A : Type*} {p : A → Prop} [RCLike 𝕜] + [MeasurableSpace X] {μ : Measure X} [NonUnitalNormedRing A] [StarRing A] [CompleteSpace A] + [NormedSpace 𝕜 A] [NormedSpace ℝ A] [IsScalarTower 𝕜 A A] [SMulCommClass 𝕜 A A] + [NonUnitalContinuousFunctionalCalculus 𝕜 p] + +lemma cfcₙL_integral (a : A) (f : X → C(quasispectrum 𝕜 a, 𝕜)₀) (hf₁ : Integrable f μ) + (ha : p a := by cfc_tac) : + ∫ x, cfcₙL (a := a) ha (f x) ∂μ = cfcₙL (a := a) ha (∫ x, f x ∂μ) := by + rw [ContinuousLinearMap.integral_comp_comm _ hf₁] + +lemma cfcₙHom_integral (a : A) (f : X → C(quasispectrum 𝕜 a, 𝕜)₀) (hf₁ : Integrable f μ) + (ha : p a := by cfc_tac) : + ∫ x, cfcₙHom (a := a) ha (f x) ∂μ = cfcₙHom (a := a) ha (∫ x, f x ∂μ) := + cfcₙL_integral a f hf₁ ha + +open ContinuousMapZero in +/-- The non-unital continuous functional calculus commutes with integration. -/ +lemma cfcₙ_integral [TopologicalSpace X] [OpensMeasurableSpace X] (f : X → 𝕜 → 𝕜) + (bound : X → ℝ) (a : A) [SecondCountableTopologyEither X C(quasispectrum 𝕜 a, 𝕜)₀] + (hf₁ : ∀ x, ContinuousOn (f x) (quasispectrum 𝕜 a)) + (hf₂ : ∀ x, f x 0 = 0) + (hf₃ : Continuous (fun x ↦ (⟨⟨_, hf₁ x |>.restrict⟩, hf₂ x⟩ : C(quasispectrum 𝕜 a, 𝕜)₀))) + (hbound : ∀ x, ∀ z ∈ quasispectrum 𝕜 a, ‖f x z‖ ≤ ‖bound x‖) + (hbound_finite_integral : HasFiniteIntegral bound μ) (ha : p a := by cfc_tac) : + cfcₙ (fun r => ∫ x, f x r ∂μ) a = ∫ x, cfcₙ (f x) a ∂μ := by + let fc : X → C(quasispectrum 𝕜 a, 𝕜)₀ := fun x => ⟨⟨_, (hf₁ x).restrict⟩, hf₂ x⟩ + have fc_integrable : Integrable fc μ := by + refine ⟨hf₃.aestronglyMeasurable, ?_⟩ + refine hbound_finite_integral.mono <| .of_forall fun x ↦ ?_ + change ‖(fc x : C(quasispectrum 𝕜 a, 𝕜))‖ ≤ ‖bound x‖ + rw [ContinuousMap.norm_le _ (norm_nonneg (bound x))] + exact fun z ↦ hbound x z.1 z.2 + have h_int_fc : (quasispectrum 𝕜 a).restrict (∫ x, f x · ∂μ) = ∫ x, fc x ∂μ := by + ext; simp [integral_apply fc_integrable, fc] + have hcont₂ : ContinuousOn (fun r => ∫ x, f x r ∂μ) (quasispectrum 𝕜 a) := by + rw [continuousOn_iff_continuous_restrict] + convert map_continuous (∫ x, fc x ∂μ) + rw [integral_congr_ae (.of_forall fun _ ↦ cfcₙ_apply ..), cfcₙ_apply .., + cfcₙHom_integral _ _ fc_integrable] + congr + +/-- The non-unital continuous functional calculus commutes with integration. -/ +lemma cfcₙ_integral' [TopologicalSpace X] [OpensMeasurableSpace X] (f : X → 𝕜 → 𝕜) + (bound : X → ℝ) (a : A) [SecondCountableTopologyEither X C(quasispectrum 𝕜 a, 𝕜)₀] + (hf : Continuous (fun x => (quasispectrum 𝕜 a).restrict (f x)).uncurry) + (hf₂ : ∀ x, f x 0 = 0) + (hbound : ∀ x, ∀ z ∈ quasispectrum 𝕜 a, ‖f x z‖ ≤ ‖bound x‖) + (hbound_finite_integral : HasFiniteIntegral bound μ) (ha : p a := by cfc_tac) : + cfcₙ (fun r => ∫ x, f x r ∂μ) a = ∫ x, cfcₙ (f x) a ∂μ := by + 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 ?_ + exact ContinuousMap.curry ⟨_, hf⟩ |>.continuous + +end nonunital diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/NonUnital.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/NonUnital.lean index dfb187b624e62..361cdc8aefebc 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 @@ -127,6 +127,10 @@ lemma cfcₙHom_closedEmbedding : ClosedEmbedding <| (cfcₙHom ha : C(σₙ R a, R)₀ →⋆ₙₐ[R] A) := (NonUnitalContinuousFunctionalCalculus.exists_cfc_of_predicate a ha).choose_spec.1 +@[fun_prop] +lemma cfcₙHom_continuous : Continuous (cfcₙHom ha : C(σₙ R a, R)₀ →⋆ₙₐ[R] A) := + cfcₙHom_closedEmbedding ha |>.continuous + lemma cfcₙHom_id : cfcₙHom ha ⟨(ContinuousMap.id R).restrict <| σₙ R a, rfl⟩ = a := (NonUnitalContinuousFunctionalCalculus.exists_cfc_of_predicate a ha).choose_spec.2.1 @@ -170,6 +174,17 @@ theorem cfcₙHom_comp [UniqueNonUnitalContinuousFunctionalCalculus R A] (f : C( end cfcₙHom +section cfcₙL + +/-- `cfcₙHom` bundled as a continuous linear map. -/ +@[simps apply] +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 } + +end cfcₙL section CFCn @@ -406,7 +421,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⟩ @@ -458,6 +473,7 @@ lemma CFC.quasispectrum_zero_eq : σₙ R (0 : A) = {0} := by simpa [CFC.quasispectrum_zero_eq] · exact cfcₙ_apply_of_not_map_zero _ hf0 +@[simp] instance IsStarNormal.cfcₙ_map (f : R → R) (a : A) : IsStarNormal (cfcₙ f a) where star_comm_self := by refine cfcₙ_cases (fun x ↦ Commute (star x) x) _ _ (Commute.zero_right _) fun _ _ _ ↦ ?_ @@ -466,6 +482,19 @@ instance IsStarNormal.cfcₙ_map (f : R → R) (a : A) : IsStarNormal (cfcₙ f congr! 2 exact mul_comm _ _ +-- The following two lemmas are just `cfcₙ_predicate`, but specific enough for the `@[simp]` tag. +@[simp] +protected lemma IsSelfAdjoint.cfcₙ + [NonUnitalContinuousFunctionalCalculus R (IsSelfAdjoint : A → Prop)] {f : R → R} {a : A} : + IsSelfAdjoint (cfcₙ f a) := + cfcₙ_predicate _ _ + +@[simp] +lemma cfcₙ_nonneg_of_predicate [PartialOrder A] + [NonUnitalContinuousFunctionalCalculus R (fun (a : A) => 0 ≤ a)] {f : R → R} {a : A} : + 0 ≤ cfcₙ f a := + cfcₙ_predicate _ _ + end CFCn end Main @@ -662,12 +691,8 @@ lemma closedEmbedding_cfcₙHom_of_cfcHom {a : A} (ha : p a) : ClosedEmbedding (cfcₙHom_of_cfcHom R ha) := by let f : C(spectrum R a, σₙ R a) := ⟨_, continuous_inclusion <| spectrum_subset_quasispectrum R a⟩ - 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 (cfcHom_closedEmbedding ha).comp <| - (UniformInducing.uniformEmbedding ⟨?_⟩).toClosedEmbedding + (IsUniformInducing.isUniformEmbedding ⟨?_⟩).toClosedEmbedding 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, diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean index 2bebd79a58986..8536353d9475b 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean @@ -5,8 +5,9 @@ Authors: Frédéric Dupuis -/ import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Instances -import Mathlib.Topology.ContinuousFunction.StarOrdered import Mathlib.Analysis.CStarAlgebra.Unitization +import Mathlib.Analysis.SpecialFunctions.ContinuousFunctionalCalculus.Rpow +import Mathlib.Topology.ContinuousMap.StarOrdered /-! # Facts about star-ordered rings that depend on the continuous functional calculus @@ -23,10 +24,11 @@ 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). +* `CStarAlgebra.inv_le_inv_iff`: in a unital C⋆-algebra, `b⁻¹ ≤ a⁻¹` iff `a ≤ b`. ## Tags @@ -41,9 +43,11 @@ 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] -instance instPartialOrder : PartialOrder (Unitization ℂ A) := CStarRing.spectralOrder _ +instance instPartialOrder : PartialOrder (Unitization ℂ A) := + CStarAlgebra.spectralOrder _ -instance instStarOrderedRing : StarOrderedRing (Unitization ℂ A) := CStarRing.spectralOrderedRing _ +instance instStarOrderedRing : StarOrderedRing (Unitization ℂ A) := + CStarAlgebra.spectralOrderedRing _ lemma inr_le_iff (a b : A) (ha : IsSelfAdjoint a := by cfc_tac) (hb : IsSelfAdjoint b := by cfc_tac) : @@ -64,6 +68,39 @@ lemma inr_nonneg_iff {a : A} : 0 ≤ (a : Unitization ℂ A) ↔ 0 ≤ a := by end Unitization +/-- `cfc_le_iff` only applies to a scalar ring where `R` is an actual `Ring`, and not a `Semiring`. +However, this theorem still holds for `ℝ≥0` as long as the algebra `A` itself is an `ℝ`-algebra. -/ +lemma cfc_nnreal_le_iff {A : Type*} [TopologicalSpace A] [Ring A] [StarRing A] [PartialOrder A] + [StarOrderedRing A] [Algebra ℝ A] [TopologicalRing A] [NonnegSpectrumClass ℝ A] + [ContinuousFunctionalCalculus ℝ (IsSelfAdjoint : A → Prop)] + [UniqueContinuousFunctionalCalculus ℝ A] + (f : ℝ≥0 → ℝ≥0) (g : ℝ≥0 → ℝ≥0) (a : A) + (ha_spec : SpectrumRestricts a ContinuousMap.realToNNReal) + (hf : ContinuousOn f (spectrum ℝ≥0 a) := by cfc_cont_tac) + (hg : ContinuousOn g (spectrum ℝ≥0 a) := by cfc_cont_tac) + (ha : 0 ≤ a := by cfc_tac) : + cfc f a ≤ cfc g a ↔ ∀ x ∈ spectrum ℝ≥0 a, f x ≤ g x := by + have hf' := hf.ofReal_map_toNNReal <| ha_spec.image ▸ Set.mapsTo_image .. + have hg' := hg.ofReal_map_toNNReal <| ha_spec.image ▸ Set.mapsTo_image .. + rw [cfc_nnreal_eq_real, cfc_nnreal_eq_real, cfc_le_iff ..] + simp [NNReal.coe_le_coe, ← ha_spec.image] + +/-- 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] + [ContinuousFunctionalCalculus ℝ (IsSelfAdjoint : A → Prop)] + {a : A} [CompactSpace (spectrum ℝ a)] + (h_non : (spectrum ℝ a).Nonempty) (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 + exact ⟨r, h _ hr, hr_min⟩ + section CStar_unital variable {A : Type*} [NormedRing A] [StarRing A] [CStarRing A] [CompleteSpace A] @@ -89,11 +126,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 @@ -103,7 +142,9 @@ 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] -lemma CStarRing.norm_or_neg_norm_mem_spectrum [Nontrivial A] {a : A} +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 have ha' : SpectrumRestricts a Complex.reCLM := ha.spectrumRestricts rw [← ha.toReal_spectralRadius_eq_norm] @@ -111,16 +152,168 @@ lemma CStarRing.norm_or_neg_norm_mem_spectrum [Nontrivial A] {a : A} variable [PartialOrder A] [StarOrderedRing A] -lemma CStarRing.nnnorm_mem_spectrum_of_nonneg [Nontrivial A] {a : A} (ha : 0 ≤ a := by cfc_tac) : +lemma nnnorm_mem_spectrum_of_nonneg [Nontrivial A] {a : A} (ha : 0 ≤ a := by cfc_tac) : ‖a‖₊ ∈ spectrum ℝ≥0 a := by have : IsSelfAdjoint a := .of_nonneg ha convert NNReal.spectralRadius_mem_spectrum (a := a) ?_ (.nnreal_of_nonneg ha) · simp [this.spectrumRestricts.spectralRadius_eq, this.spectralRadius_eq_nnnorm] · exact this.spectrumRestricts.image ▸ (spectrum.nonempty a).image _ -lemma CStarRing.norm_mem_spectrum_of_nonneg [Nontrivial A] {a : A} (ha : 0 ≤ a := by cfc_tac) : +lemma norm_mem_spectrum_of_nonneg [Nontrivial A] {a : A} (ha : 0 ≤ a := by cfc_tac) : ‖a‖ ∈ spectrum ℝ a := by - simpa using spectrum.algebraMap_mem ℝ <| CStarRing.nnnorm_mem_spectrum_of_nonneg ha + simpa using spectrum.algebraMap_mem ℝ <| nnnorm_mem_spectrum_of_nonneg ha + +lemma norm_le_iff_le_algebraMap (a : A) {r : ℝ} (hr : 0 ≤ r) (ha : 0 ≤ a := by cfc_tac) : + ‖a‖ ≤ r ↔ a ≤ algebraMap ℝ A r := by + rw [le_algebraMap_iff_spectrum_le] + obtain (h | _) := subsingleton_or_nontrivial A + · simp [Subsingleton.elim a 0, hr] + · exact ⟨fun h x hx ↦ Real.le_norm_self x |>.trans (spectrum.norm_le_norm_of_mem hx) |>.trans h, + fun h ↦ h ‖a‖ <| norm_mem_spectrum_of_nonneg⟩ + +lemma nnnorm_le_iff_of_nonneg (a : A) (r : ℝ≥0) (ha : 0 ≤ a := by cfc_tac) : + ‖a‖₊ ≤ r ↔ a ≤ algebraMap ℝ≥0 A r := by + rw [← NNReal.coe_le_coe] + exact norm_le_iff_le_algebraMap a r.2 + +lemma norm_le_one_iff_of_nonneg (a : A) (ha : 0 ≤ a := by cfc_tac) : + ‖a‖ ≤ 1 ↔ a ≤ 1 := by + simpa using norm_le_iff_le_algebraMap a zero_le_one + +lemma nnnorm_le_one_iff_of_nonneg (a : A) (ha : 0 ≤ a := by cfc_tac) : + ‖a‖₊ ≤ 1 ↔ a ≤ 1 := by + rw [← NNReal.coe_le_coe] + exact norm_le_one_iff_of_nonneg a + +lemma norm_le_natCast_iff_of_nonneg (a : A) (n : ℕ) (ha : 0 ≤ a := by cfc_tac) : + ‖a‖ ≤ n ↔ a ≤ n := by + simpa using norm_le_iff_le_algebraMap a n.cast_nonneg + +lemma nnnorm_le_natCast_iff_of_nonneg (a : A) (n : ℕ) (ha : 0 ≤ a := by cfc_tac) : + ‖a‖₊ ≤ n ↔ a ≤ n := by + simpa using nnnorm_le_iff_of_nonneg a n + +end CStarAlgebra + +section Inv + +open CFC + +variable [PartialOrder A] [StarOrderedRing A] + +-- TODO : relate everything in this section to strict positivity + +lemma CFC.conjugate_rpow_neg_one_half {a : A} (h₀ : IsUnit a) (ha : 0 ≤ a := by cfc_tac) : + a ^ (-(1 / 2) : ℝ) * a * a ^ (-(1 / 2) : ℝ) = 1 := by + lift a to Aˣ using h₀ + nth_rw 2 [← rpow_one (a : A)] + simp only [← rpow_add (a.zero_not_mem_spectrum ℝ≥0)] + norm_num + exact rpow_zero _ + +/-- In a unital C⋆-algebra, if `a` is nonnegative and invertible, and `a ≤ b`, then `b` is +invertible. -/ +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₀ ⊢ + peel h₀ with r hr _ + exact this.trans hab + +lemma le_iff_norm_sqrt_mul_rpow {a b : A} (hbu : IsUnit b) (ha : 0 ≤ a) (hb : 0 ≤ (b : A)) : + a ≤ b ↔ ‖sqrt a * (b : A) ^ (-(1 / 2) : ℝ)‖ ≤ 1 := by + lift b to Aˣ using hbu + have hbab : 0 ≤ (b : A) ^ (-(1 / 2) : ℝ) * a * (b : A) ^ (-(1 / 2) : ℝ) := + conjugate_nonneg_of_nonneg ha rpow_nonneg + conv_rhs => + rw [← sq_le_one_iff (norm_nonneg _), sq, ← CStarRing.norm_star_mul_self, star_mul, + IsSelfAdjoint.of_nonneg sqrt_nonneg, IsSelfAdjoint.of_nonneg rpow_nonneg, + ← mul_assoc, mul_assoc _ _ (sqrt a), sqrt_mul_sqrt_self a, + CStarAlgebra.norm_le_one_iff_of_nonneg _ hbab] + refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ + · calc + _ ≤ ↑b ^ (-(1 / 2) : ℝ) * (b : A) * ↑b ^ (-(1 / 2) : ℝ) := + IsSelfAdjoint.of_nonneg rpow_nonneg |>.conjugate_le_conjugate h + _ = 1 := conjugate_rpow_neg_one_half b.isUnit + · calc + a = (sqrt ↑b * ↑b ^ (-(1 / 2) : ℝ)) * a * (↑b ^ (-(1 / 2) : ℝ) * sqrt ↑b) := by + simp only [CFC.sqrt_eq_rpow .., ← CFC.rpow_add (b.zero_not_mem_spectrum ℝ≥0)] + norm_num + simp [CFC.rpow_zero (b : A)] + _ = sqrt ↑b * (↑b ^ (-(1 / 2) : ℝ) * a * ↑b ^ (-(1 / 2) : ℝ)) * sqrt ↑b := by + simp only [mul_assoc] + _ ≤ b := conjugate_le_conjugate_of_nonneg h sqrt_nonneg |>.trans <| by + simp [CFC.sqrt_mul_sqrt_self (b : A)] + +lemma le_iff_norm_sqrt_mul_sqrt_inv {a : A} {b : Aˣ} (ha : 0 ≤ a) (hb : 0 ≤ (b : A)) : + a ≤ b ↔ ‖sqrt a * sqrt (↑b⁻¹ : A)‖ ≤ 1 := by + rw [CFC.sqrt_eq_rpow (a := (↑b⁻¹ : A)), ← CFC.rpow_neg_one_eq_inv b, + 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 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 + have ha_inv : (0 : A) ≤ a⁻¹ := inv_nonneg_of_nonneg a ha + rw [le_iff_norm_sqrt_mul_sqrt_inv ha hb, ← sq_le_one_iff (norm_nonneg _), sq, + ← CStarRing.norm_star_mul_self] at hab + rw [le_iff_norm_sqrt_mul_sqrt_inv hb_inv ha_inv, inv_inv, ← sq_le_one_iff (norm_nonneg _), sq, + ← CStarRing.norm_self_mul_star] + rwa [star_mul, IsSelfAdjoint.of_nonneg sqrt_nonneg, + IsSelfAdjoint.of_nonneg sqrt_nonneg] at hab ⊢ + +/-- 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 inv_le_inv_iff {a b : Aˣ} (ha : 0 ≤ (a : A)) (hb : 0 ≤ (b : A)) : + (↑a⁻¹ : A) ≤ b⁻¹ ↔ (b : A) ≤ a := + ⟨CStarAlgebra.inv_le_inv (inv_nonneg_of_nonneg a ha), CStarAlgebra.inv_le_inv hb⟩ + +lemma inv_le_iff {a b : Aˣ} (ha : 0 ≤ (a : A)) (hb : 0 ≤ (↑b : A)) : + (↑a⁻¹ : A) ≤ b ↔ (↑b⁻¹ : A) ≤ a := by + simpa using CStarAlgebra.inv_le_inv_iff ha (inv_nonneg_of_nonneg b hb) + +lemma le_inv_iff {a b : Aˣ} (ha : 0 ≤ (a : A)) (hb : 0 ≤ (↑b : A)) : + a ≤ (↑b⁻¹ : A) ↔ b ≤ (↑a⁻¹ : A) := by + simpa using CStarAlgebra.inv_le_inv_iff (inv_nonneg_of_nonneg a ha) hb + +lemma one_le_inv_iff_le_one {a : Aˣ} (ha : 0 ≤ (a : A)) : + 1 ≤ (↑a⁻¹ : A) ↔ a ≤ 1 := by + simpa using CStarAlgebra.le_inv_iff (a := 1) (by simp) ha + +lemma inv_le_one_iff_one_le {a : Aˣ} (ha : 0 ≤ (a : A)) : + (↑a⁻¹ : A) ≤ 1 ↔ 1 ≤ a := by + simpa using CStarAlgebra.inv_le_iff ha (b := 1) (by simp) + +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 le_one_of_one_le_inv {a : Aˣ} (ha : 1 ≤ (↑a⁻¹ : A)) : (a : A) ≤ 1 := by + simpa using CStarAlgebra.inv_le_one ha + +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 CStarAlgebra.inv_le_inv ha hab + +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 @@ -130,13 +323,15 @@ variable {A : Type*} [NonUnitalNormedRing A] [CompleteSpace A] [PartialOrder A] [StarOrderedRing A] [CStarRing A] [NormedSpace ℂ A] [StarModule ℂ A] [SMulCommClass ℂ A A] [IsScalarTower ℂ A A] +namespace CStarAlgebra + open ComplexOrder in -instance CStarRing.instNonnegSpectrumClassComplexNonUnital : NonnegSpectrumClass ℂ A where +instance instNonnegSpectrumClassComplexNonUnital : NonnegSpectrumClass ℂ A where quasispectrum_nonneg_of_nonneg a ha x hx := by rw [Unitization.quasispectrum_eq_spectrum_inr' ℂ ℂ a] at hx exact spectrum_nonneg_of_nonneg (Unitization.inr_nonneg_iff.mpr ha) hx -lemma CStarRing.norm_le_norm_of_nonneg_of_le {a b : A} (ha : 0 ≤ a := by cfc_tac) (hab : a ≤ b) : +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 have hb := ha.trans hab @@ -156,7 +351,7 @@ lemma CStarRing.norm_le_norm_of_nonneg_of_le {a b : A} (ha : 0 ≤ a := by cfc_t rw [cfc_le_iff id (fun _ => ‖b‖) a] at h₂ exact h₂ ‖a‖ <| norm_mem_spectrum_of_nonneg ha -lemma CStarRing.conjugate_le_norm_smul {a b : A} (hb : IsSelfAdjoint b := by cfc_tac) : +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 rw [← Unitization.inr_le_iff _ _ (by aesop) ((IsSelfAdjoint.all _).smul (.star_mul_self a))] @@ -167,11 +362,27 @@ lemma CStarRing.conjugate_le_norm_smul {a b : A} (hb : IsSelfAdjoint b := by cfc conjugate_le_conjugate hb.le_algebraMap_norm_self _ _ = ‖b‖ • (star a * a) := by simp [Algebra.algebraMap_eq_smul_one] -lemma CStarRing.conjugate_le_norm_smul' {a b : A} (hb : IsSelfAdjoint b := by cfc_tac) : +lemma conjugate_le_norm_smul' {a b : A} (hb : IsSelfAdjoint b := by cfc_tac) : a * b * star a ≤ ‖b‖ • (a * star a) := by have h₁ : a * b * star a = star (star a) * b * star a := by simp have h₂ : a * star a = star (star a) * star a := by simp simp only [h₁, h₂] exact conjugate_le_norm_smul +/-- 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 + 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 + exact and_congr_left fun h ↦ by simp [← h] + simp only [nonneg_iff_isSelfAdjoint_and_spectrumRestricts, + and_congr_right (SpectrumRestricts.nnreal_iff_nnnorm · le_rfl), Set.setOf_and] + refine isClosed_eq ?_ ?_ |>.inter <| isClosed_le ?_ ?_ + all_goals fun_prop + +end CStarAlgebra + end CStar_nonunital diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Restrict.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Restrict.lean index b3720734734ab..cf36028a7922e 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Restrict.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Restrict.lean @@ -3,7 +3,7 @@ Copyright (c) 2024 Jireh Loreaux. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jireh Loreaux -/ -import Mathlib.Analysis.Normed.Algebra.Spectrum +import Mathlib.Topology.Algebra.Algebra import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.NonUnital /-! # Restriction of the continuous functional calculus to a scalar subring @@ -84,26 +84,24 @@ 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)) [CompactSpace (spectrum S a)] : + (halg : IsUniformEmbedding (algebraMap R S)) : ClosedEmbedding (h.starAlgHom φ) := - have := h.compactSpace - hφ.comp <| UniformEmbedding.toClosedEmbedding <| .comp - (ContinuousMap.uniformEmbedding_comp _ halg) - (UniformEquiv.arrowCongr h.homeomorph.symm (.refl _) |>.uniformEmbedding) + hφ.comp <| IsUniformEmbedding.toClosedEmbedding <| .comp + (ContinuousMap.isUniformEmbedding_comp _ halg) + (UniformEquiv.arrowCongr h.homeomorph.symm (.refl _) |>.isUniformEmbedding) /-- 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) - (h : ∀ a, p a ↔ q a ∧ SpectrumRestricts a f) (h_cpct : ∀ a, q a → CompactSpace (spectrum S a)) : +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 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 => - have := h_cpct a ((h a).mp ha).1 exact ((h a).mp ha).2.closedEmbedding_starAlgHom (cfcHom_closedEmbedding ((h a).mp ha).1) halg case hom_id => exact ((h a).mp ha).2.starAlgHom_id <| cfcHom_id ((h a).mp ha).1 @@ -135,15 +133,15 @@ 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)) - {a : A} (hpa : p a) (hqa : q a) (h : SpectrumRestricts a f) [CompactSpace (spectrum S a)] : +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.starAlgHom_id (cfcHom_id hqa) -lemma cfc_eq_restrict (f : C(S, R)) (halg : UniformEmbedding (algebraMap R S)) {a : A} (hpa : p a) - (hqa : q a) (h : SpectrumRestricts a f) [CompactSpace (spectrum S a)] (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 : 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) · rw [cfc_apply g a, cfcHom_eq_restrict f halg hpa hqa h, SpectrumRestricts.starAlgHom_apply, @@ -154,7 +152,7 @@ lemma cfc_eq_restrict (f : C(S, R)) (halg : UniformEmbedding (algebraMap R S)) { · 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, h.left_inv _] using + 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 [cfc_apply_of_not_continuousOn a hg, cfc_apply_of_not_continuousOn a this] @@ -220,13 +218,12 @@ 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)) [h_cpct : CompactSpace (σₙ S a)] : + (halg : IsUniformEmbedding (algebraMap R S)) : ClosedEmbedding (h.nonUnitalStarAlgHom φ) := by - have := h.compactSpace 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.toClosedEmbedding <| .comp + (ContinuousMapZero.isUniformEmbedding_comp _ halg) + (UniformEquiv.arrowCongrLeft₀ h.homeomorph.symm this |>.isUniformEmbedding) variable [IsScalarTower R A A] [SMulCommClass R A A] @@ -234,8 +231,8 @@ 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) - (h : ∀ a, p a ↔ q a ∧ QuasispectrumRestricts a f) (h_cpct : ∀ a, q a → CompactSpace (σₙ S a)) : +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 exists_cfc_of_predicate a ha := by @@ -243,7 +240,7 @@ protected theorem cfc (f : C(S, R)) (halg : UniformEmbedding (algebraMap 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 (h_cpct := h_cpct a ((h a).mp ha).1) + (cfcₙHom_closedEmbedding ((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 @@ -278,15 +275,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} - (hpa : p a) (hqa : q a) (h : QuasispectrumRestricts a f) [CompactSpace (σₙ S 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.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) [CompactSpace (σₙ S a)] (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 @@ -300,7 +297,7 @@ lemma cfcₙ_eq_restrict (f : C(S, R)) (halg : UniformEmbedding (algebraMap R S) · 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, h.left_inv _] using + simpa [halg.embedding.continuousOn_iff, Function.comp_def, h.left_inv _] using hg'.comp halg.embedding.continuous.continuousOn (fun _ : R ↦ quasispectrum.algebraMap_mem S) rw [cfcₙ_apply_of_not_continuousOn a hg, cfcₙ_apply_of_not_continuousOn a this] diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unique.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unique.lean index 830edf4006647..155a1b6dd519c 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 @@ -420,3 +420,103 @@ instance NNReal.instUniqueNonUnitalContinuousFunctionalCalculus end NNReal end UniqueNonUnital + +section NonUnitalStarAlgHom + +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] + [NonUnitalRing A] [StarRing A] [TopologicalSpace A] [Module R A] + [IsScalarTower R A A] [SMulCommClass R A A] + [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] + [StarHomClass F A B] + +include S in +/-- Non-unital star algebra homomorphisms commute with the non-unital continuous functional +calculus. -/ +lemma NonUnitalStarAlgHomClass.map_cfcₙ (φ : F) (f : R → R) (a : A) + [CompactSpace (quasispectrum R a)] (hf : ContinuousOn f (quasispectrum R a) := by cfc_cont_tac) + (hf₀ : f 0 = 0 := by cfc_zero_tac) (hφ : Continuous φ := by fun_prop) (ha : p a := by cfc_tac) + (hφa : q (φ a) := by cfc_tac) : φ (cfcₙ f a) = cfcₙ f (φ a) := by + let ψ : A →⋆ₙₐ[R] B := (φ : A →⋆ₙₐ[S] B).restrictScalars R + have : Continuous ψ := hφ + have h_spec := NonUnitalAlgHom.quasispectrum_apply_subset' (R := R) S φ a + have hψa : q (ψ a) := hφa + let ι : C(quasispectrum R (ψ a), quasispectrum R a)₀ := + ⟨⟨Set.inclusion h_spec, continuous_id.subtype_map h_spec⟩, rfl⟩ + suffices ψ.comp (cfcₙHom ha) = + (cfcₙHom hψa).comp (ContinuousMapZero.nonUnitalStarAlgHom_precomp R ι) by + have hf' : ContinuousOn f (quasispectrum R (ψ a)) := hf.mono h_spec + rw [cfcₙ_apply .., cfcₙ_apply ..] + exact DFunLike.congr_fun this _ + refine UniqueNonUnitalContinuousFunctionalCalculus.eq_of_continuous_of_map_id _ rfl _ _ + ?_ ?_ ?apply_id + case apply_id => + trans cfcₙHom hψa ⟨.restrict (quasispectrum R (ψ a)) (.id R), rfl⟩ + · simp [cfcₙHom_id] + · congr + all_goals + simp [ContinuousMapZero.nonUnitalStarAlgHom_precomp] + fun_prop + +/-- Non-unital star algebra homomorphisms commute with the non-unital continuous functional +calculus. This version is specialized to `A →⋆ₙₐ[S] B` to allow for dot notation. -/ +lemma NonUnitalStarAlgHom.map_cfcₙ (φ : A →⋆ₙₐ[S] B) (f : R → R) (a : A) + [CompactSpace (quasispectrum R a)] (hf : ContinuousOn f (quasispectrum R a) := by cfc_cont_tac) + (hf₀ : f 0 = 0 := by cfc_zero_tac) (hφ : Continuous φ := by fun_prop) (ha : p a := by cfc_tac) + (hφa : q (φ a) := by cfc_tac) : φ (cfcₙ f a) = cfcₙ f (φ a) := + NonUnitalStarAlgHomClass.map_cfcₙ φ f a + +end NonUnitalStarAlgHom + +section StarAlgHom + +variable {F R S A B : Type*} {p : A → Prop} {q : B → Prop} + [CommSemiring R] [StarRing R] [MetricSpace R] [TopologicalSemiring R] [ContinuousStar R] + [Ring A] [StarRing A] [TopologicalSpace A] [Algebra R A] + [Ring B] [StarRing B] [TopologicalSpace B] [Algebra R B] + [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] + [StarHomClass F A B] + +include S in +/-- Star algebra homomorphisms commute with the continuous functional calculus. -/ +lemma StarAlgHomClass.map_cfc (φ : F) (f : R → R) (a : A) + [CompactSpace (spectrum R a)] (hf : ContinuousOn f (spectrum R a) := by cfc_cont_tac) + (hφ : Continuous φ := by fun_prop) (ha : p a := by cfc_tac) (hφa : q (φ a) := by cfc_tac) : + φ (cfc f a) = cfc f (φ a) := by + let ψ : A →⋆ₐ[R] B := (φ : A →⋆ₐ[S] B).restrictScalars R + have : Continuous ψ := hφ + have h_spec := AlgHom.spectrum_apply_subset ψ a + have hψa : q (ψ a) := hφa + let ι : C(spectrum R (ψ a), spectrum R a) := + ⟨Set.inclusion h_spec, continuous_id.subtype_map h_spec⟩ + suffices ψ.comp (cfcHom ha) = (cfcHom hψa).comp (ContinuousMap.compStarAlgHom' R R ι) by + have hf' : ContinuousOn f (spectrum R (ψ a)) := hf.mono h_spec + rw [cfc_apply .., cfc_apply ..] + congrm($(this) ⟨_, hf.restrict⟩) + refine UniqueContinuousFunctionalCalculus.eq_of_continuous_of_map_id _ _ _ ?_ ?_ ?apply_id + case apply_id => + trans cfcHom hψa (.restrict (spectrum R (ψ a)) (.id R)) + · simp [cfcHom_id] + · congr + all_goals + simp [ContinuousMap.compStarAlgHom'] + fun_prop + +/-- Star algebra homomorphisms commute with the continuous functional calculus. +This version is specialized to `A →⋆ₐ[S] B` to allow for dot notation. -/ +lemma StarAlgHom.map_cfc (φ : A →⋆ₐ[S] B) (f : R → R) (a : A) [CompactSpace (spectrum R a)] + (hf : ContinuousOn f (spectrum R a) := by cfc_cont_tac) (hφ : Continuous φ := by fun_prop) + (ha : p a := by cfc_tac) (hφa : q (φ a) := by cfc_tac) : + φ (cfc f a) = cfc f (φ a) := + StarAlgHomClass.map_cfc φ f a + +end StarAlgHom diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unital.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unital.lean index bb752066f3920..8b6473cba0de3 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unital.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unital.lean @@ -5,9 +5,9 @@ Authors: Jireh Loreaux -/ import Mathlib.Algebra.Algebra.Quasispectrum import Mathlib.Algebra.Algebra.Spectrum -import Mathlib.Algebra.Star.Order +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 /-! @@ -107,7 +107,7 @@ b = cfc id b = cfc (NNReal.sqrt ∘ (· ^ 2)) b = + `cfc : (R → R) → A → A`: an unbundled version of `cfcHom` which takes the junk value `0` when `cfcHom` is not defined. + `cfcUnits`: builds a unit from `cfc f a` when `f` is nonzero and continuous on the - specturm of `a`. + spectrum of `a`. ## Main theorems @@ -225,6 +225,10 @@ lemma cfcHom_closedEmbedding : ClosedEmbedding <| (cfcHom ha : C(spectrum R a, R) →⋆ₐ[R] A) := (ContinuousFunctionalCalculus.exists_cfc_of_predicate a ha).choose_spec.1 +@[fun_prop] +lemma cfcHom_continuous : Continuous (cfcHom ha : C(spectrum R a, R) →⋆ₐ[R] A) := + cfcHom_closedEmbedding ha |>.continuous + lemma cfcHom_id : cfcHom ha ((ContinuousMap.id R).restrict <| spectrum R a) = a := (ContinuousFunctionalCalculus.exists_cfc_of_predicate a ha).choose_spec.2.1 @@ -260,6 +264,18 @@ theorem cfcHom_comp [UniqueContinuousFunctionalCalculus R A] (f : C(spectrum R a end cfcHom +section cfcL + +/-- `cfcHom` bundled as a continuous linear map. -/ +@[simps apply] +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 } + +end cfcL + section CFC open scoped Classical in @@ -310,6 +326,10 @@ lemma cfcHom_eq_cfc_extend {a : A} (g : R → R) (ha : p a) (f : C(spectrum R a, rw [cfc_apply ..] congr! +lemma cfc_eq_cfcL {a : A} {f : R → R} (ha : p a) (hf : ContinuousOn f (spectrum R a)) : + cfc f a = cfcL ha ⟨_, hf.restrict⟩ := by + rw [cfc_def, dif_pos ⟨ha, hf⟩, cfcL_apply] + lemma cfc_cases (P : A → Prop) (a : A) (f : R → R) (h₀ : P 0) (haf : (hf : ContinuousOn f (spectrum R a)) → (ha : p a) → P (cfcHom ha ⟨_, hf.restrict⟩)) : P (cfc f a) := by @@ -564,7 +584,7 @@ lemma cfc_comp_smul {S : Type*} [SMul S R] [ContinuousConstSMul S R] [SMulZeroCl rw [cfc_comp' .., cfc_smul_id ..] lemma cfc_comp_const_mul (r : R) (f : R → R) (a : A) - (hf : ContinuousOn f ((r * ·) '' (spectrum R a)) := by cfc_cont_tac) (ha : p a := by cfc_tac) : + (hf : ContinuousOn f ((r * ·) '' (spectrum R a)) := by cfc_cont_tac) (ha : p a := by cfc_tac) : cfc (f <| r * ·) a = cfc f (r • a) := by rw [cfc_comp' .., cfc_const_mul_id ..] @@ -637,6 +657,7 @@ lemma cfc_algebraMap (r : R) (f : R → R) : cfc f (algebraMap R A r) = algebraM @[simp] lemma cfc_apply_one {f : R → R} : cfc f (1 : A) = algebraMap R A (f 1) := by simpa using cfc_algebraMap (A := A) 1 f +@[simp] instance IsStarNormal.cfc_map (f : R → R) (a : A) : IsStarNormal (cfc f a) where star_comm_self := by rw [Commute, SemiconjBy] @@ -646,6 +667,27 @@ instance IsStarNormal.cfc_map (f : R → R) (a : A) : IsStarNormal (cfc f a) whe exact mul_comm _ _ · simp [cfc_apply_of_not_continuousOn a h] +-- The following two lemmas are just `cfc_predicate`, but specific enough for the `@[simp]` tag. +@[simp] +protected lemma IsSelfAdjoint.cfc [ContinuousFunctionalCalculus R (IsSelfAdjoint : A → Prop)] + {f : R → R} {a : A} : IsSelfAdjoint (cfc f a) := + cfc_predicate _ _ + +@[simp] +lemma cfc_nonneg_of_predicate [PartialOrder A] + [ContinuousFunctionalCalculus R (fun (a : A) => 0 ≤ a)] {f : R → R} {a : A} : 0 ≤ cfc f a := + cfc_predicate _ _ + +variable (R) in +/-- In an `R`-algebra with a continuous functional calculus, every element satisfying the predicate +has nonempty `R`-spectrum. -/ +lemma CFC.spectrum_nonempty [Nontrivial A] (a : A) (ha : p a := by cfc_tac) : + (spectrum R a).Nonempty := by + by_contra! h + apply one_ne_zero (α := A) + rw [← cfc_one R a, ← cfc_zero R a] + exact cfc_congr fun x hx ↦ by simp_all + end CFC end Basic @@ -681,7 +723,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] @@ -736,7 +778,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 @@ -807,7 +849,7 @@ variable {R A : Type*} {p : A → Prop} [OrderedCommSemiring R] [StarRing R] variable [MetricSpace R] [TopologicalSemiring R] [ContinuousStar R] variable [∀ (α) [TopologicalSpace α], StarOrderedRing C(α, R)] variable [TopologicalSpace A] [Ring A] [StarRing A] [PartialOrder A] [StarOrderedRing A] -variable [Algebra R A] [ContinuousFunctionalCalculus R p] +variable [Algebra R A] [instCFC : ContinuousFunctionalCalculus R p] lemma cfcHom_mono {a : A} (ha : p a) {f g : C(spectrum R a, R)} (hfg : f ≤ g) : cfcHom ha f ≤ cfcHom ha g := @@ -882,15 +924,38 @@ lemma one_le_cfc (f : R → R) (a : A) (h : ∀ x ∈ spectrum R a, 1 ≤ f x) 1 ≤ cfc f a := by simpa using algebraMap_le_cfc f 1 a h +lemma CFC.le_one {a : A} (h : ∀ x ∈ spectrum R a, x ≤ 1) (ha : p a := by cfc_tac) : + a ≤ 1 := by + simpa using le_algebraMap_of_spectrum_le h + +lemma CFC.one_le {a : A} (h : ∀ x ∈ spectrum R a, 1 ≤ x) (ha : p a := by cfc_tac) : + 1 ≤ a := by + simpa using algebraMap_le_of_le_spectrum h + end Semiring +section NNReal + +open scoped NNReal + +variable {A : Type*} [TopologicalSpace A] [Ring A] [StarRing A] [PartialOrder A] + [Algebra ℝ≥0 A] [ContinuousFunctionalCalculus ℝ≥0 (fun (a : A) => 0 ≤ a)] + +lemma CFC.inv_nonneg_of_nonneg (a : Aˣ) (ha : (0 : A) ≤ a := by cfc_tac) : (0 : A) ≤ a⁻¹ := + cfc_inv_id (R := ℝ≥0) a ▸ cfc_predicate _ (a : A) + +lemma CFC.inv_nonneg (a : Aˣ) : (0 : A) ≤ a⁻¹ ↔ (0 : A) ≤ a := + ⟨fun _ ↦ inv_inv a ▸ inv_nonneg_of_nonneg a⁻¹, fun _ ↦ inv_nonneg_of_nonneg a⟩ + +end NNReal + section Ring variable {R A : Type*} {p : A → Prop} [OrderedCommRing R] [StarRing R] variable [MetricSpace R] [TopologicalRing R] [ContinuousStar R] variable [∀ (α) [TopologicalSpace α], StarOrderedRing C(α, R)] variable [TopologicalSpace A] [Ring A] [StarRing A] [PartialOrder A] [StarOrderedRing A] -variable [Algebra R A] [ContinuousFunctionalCalculus R p] +variable [Algebra R A] [instCFC : ContinuousFunctionalCalculus R p] variable [NonnegSpectrumClass R A] lemma cfcHom_le_iff {a : A} (ha : p a) {f g : C(spectrum R a, R)} : @@ -908,6 +973,44 @@ lemma cfc_nonpos_iff (f : R → R) (a : A) (hf : ContinuousOn f (spectrum R a) : simp_rw [← neg_nonneg, ← cfc_neg] exact cfc_nonneg_iff (fun x ↦ -f x) a +lemma cfc_le_algebraMap_iff (f : R → R) (r : R) (a : A) + (hf : ContinuousOn f (spectrum R a) := by cfc_cont_tac) (ha : p a := by cfc_tac) : + cfc f a ≤ algebraMap R A r ↔ ∀ x ∈ spectrum R a, f x ≤ r := by + rw [← cfc_const r a, cfc_le_iff ..] + +lemma algebraMap_le_cfc_iff (f : R → R) (r : R) (a : A) + (hf : ContinuousOn f (spectrum R a) := by cfc_cont_tac) (ha : p a := by cfc_tac) : + algebraMap R A r ≤ cfc f a ↔ ∀ x ∈ spectrum R a, r ≤ f x := by + rw [← cfc_const r a, cfc_le_iff ..] + +lemma le_algebraMap_iff_spectrum_le {r : R} {a : A} (ha : p a := by cfc_tac) : + a ≤ algebraMap R A r ↔ ∀ x ∈ spectrum R a, x ≤ r := by + nth_rw 1 [← cfc_id R a] + exact cfc_le_algebraMap_iff id r a + +lemma algebraMap_le_iff_le_spectrum {r : R} {a : A} (ha : p a := by cfc_tac) : + algebraMap R A r ≤ a ↔ ∀ x ∈ spectrum R a, r ≤ x:= by + nth_rw 1 [← cfc_id R a] + exact algebraMap_le_cfc_iff id r a + +lemma cfc_le_one_iff (f : R → R) (a : A) + (hf : ContinuousOn f (spectrum R a) := by cfc_cont_tac) (ha : p a := by cfc_tac) : + cfc f a ≤ 1 ↔ ∀ x ∈ spectrum R a, f x ≤ 1 := by + simpa using cfc_le_algebraMap_iff f 1 a + +lemma one_le_cfc_iff (f : R → R) (a : A) + (hf : ContinuousOn f (spectrum R a) := by cfc_cont_tac) (ha : p a := by cfc_tac) : + 1 ≤ cfc f a ↔ ∀ x ∈ spectrum R a, 1 ≤ f x := by + simpa using algebraMap_le_cfc_iff f 1 a + +lemma CFC.le_one_iff (a : A) (ha : p a := by cfc_tac) : + a ≤ 1 ↔ ∀ x ∈ spectrum R a, x ≤ 1 := by + simpa using le_algebraMap_iff_spectrum_le (r := (1 : R)) (a := a) + +lemma CFC.one_le_iff (a : A) (ha : p a := by cfc_tac) : + 1 ≤ a ↔ ∀ x ∈ spectrum R a, 1 ≤ x := by + simpa using algebraMap_le_iff_le_spectrum (r := (1 : R)) (a := a) + end Ring end Order diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unitary.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unitary.lean index d39bee3d59145..3ff6426b45606 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unitary.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Unitary.lean @@ -43,8 +43,7 @@ lemma unitary_iff_isStarNormal_and_spectrum_subset_unitary {u : A} : refine and_congr_right fun hu ↦ ?_ nth_rw 1 [← cfc_id ℂ u] rw [cfc_unitary_iff id u, Set.subset_def] - congr! with x - - simp [unitary.mem_iff_star_mul_self] + simp only [id_eq, RCLike.star_def, SetLike.mem_coe, unitary.mem_iff_star_mul_self] lemma mem_unitary_of_spectrum_subset_unitary {u : A} [IsStarNormal u] (hu : spectrum ℂ u ⊆ unitary ℂ) : u ∈ unitary A := diff --git a/Mathlib/Analysis/CStarAlgebra/GelfandDuality.lean b/Mathlib/Analysis/CStarAlgebra/GelfandDuality.lean index c3e2791a52a09..af17ea013e3fc 100644 --- a/Mathlib/Analysis/CStarAlgebra/GelfandDuality.lean +++ b/Mathlib/Analysis/CStarAlgebra/GelfandDuality.lean @@ -6,11 +6,11 @@ Authors: Jireh Loreaux import Mathlib.Analysis.CStarAlgebra.Spectrum 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 diff --git a/Mathlib/Analysis/CStarAlgebra/Hom.lean b/Mathlib/Analysis/CStarAlgebra/Hom.lean new file mode 100644 index 0000000000000..1f062615cf409 --- /dev/null +++ b/Mathlib/Analysis/CStarAlgebra/Hom.lean @@ -0,0 +1,86 @@ +/- +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*} + [NormedRing A] [CompleteSpace A] [StarRing A] [CStarRing A] + [NormedAlgebra ℂ A] [StarModule ℂ A] + [NormedRing B] [CompleteSpace B] [StarRing B] [CStarRing B] + [NormedAlgebra ℂ B] [StarModule ℂ 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*} +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] [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 2a7915775d319..49e853c8a1438 100644 --- a/Mathlib/Analysis/CStarAlgebra/Matrix.lean +++ b/Mathlib/Analysis/CStarAlgebra/Matrix.lean @@ -125,14 +125,14 @@ lemma piLp_equiv_toEuclideanCLM (A : Matrix n n 𝕜) (x : EuclideanSpace 𝕜 n rfl /-- An auxiliary definition used only to construct the true `NormedAddCommGroup` (and `Metric`) -structure provided by `Matrix.instMetricSpaceL2Op` and `Matrix.instNormedAddCommGroupL2Op`. -/ +structure provided by `Matrix.instMetricSpaceL2Op` and `Matrix.instNormedAddCommGroupL2Op`. -/ def l2OpNormedAddCommGroupAux : NormedAddCommGroup (Matrix m n 𝕜) := @NormedAddCommGroup.induced ((Matrix m n 𝕜) ≃ₗ[𝕜] (EuclideanSpace 𝕜 n →L[𝕜] EuclideanSpace 𝕜 m)) _ _ _ _ ContinuousLinearMap.toNormedAddCommGroup.toNormedAddGroup _ _ <| (toEuclideanLin.trans toContinuousLinearMap).injective /-- An auxiliary definition used only to construct the true `NormedRing` (and `Metric`) structure -provided by `Matrix.instMetricSpaceL2Op` and `Matrix.instNormedRingL2Op`. -/ +provided by `Matrix.instMetricSpaceL2Op` and `Matrix.instNormedRingL2Op`. -/ def l2OpNormedRingAux : NormedRing (Matrix n n 𝕜) := @NormedRing.induced ((Matrix n n 𝕜) ≃⋆ₐ[𝕜] (EuclideanSpace 𝕜 n →L[𝕜] EuclideanSpace 𝕜 n)) _ _ _ _ ContinuousLinearMap.toNormedRing _ _ toEuclideanCLM.injective diff --git a/Mathlib/Analysis/CStarAlgebra/Module/Constructions.lean b/Mathlib/Analysis/CStarAlgebra/Module/Constructions.lean new file mode 100644 index 0000000000000..a2bc174a1c07d --- /dev/null +++ b/Mathlib/Analysis/CStarAlgebra/Module/Constructions.lean @@ -0,0 +1,351 @@ +/- +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.Module.Defs +import Mathlib.Analysis.CStarAlgebra.Module.Synonym +import Mathlib.Topology.MetricSpace.Bilipschitz + +/-! # Constructions of Hilbert C⋆-modules + +In this file we define the following constructions of `CStarModule`s where `A` denotes a C⋆-algebra. +For some of the types listed below, the instance is declared on the type synonym `WithCStarModule E` +(with the notation `C⋆ᵐᵒᵈ E`), instead of on `E` itself; we explain the reasoning behind each +decision below. + +1. `A` as a `CStarModule` over itself. +2. `C⋆ᵐᵒᵈ (E × F)` as a `CStarModule` over `A`, when `E` and `F` are themselves `CStarModule`s over + `A`. +3. `C⋆ᵐᵒᵈ (Π i : ι, E i)` as a `CStarModule` over `A`, when each `E i` is a `CStarModule` over `A` + and `ι` is a `Fintype`. +4. `E` as a `CStarModule` over `ℂ`, when `E` is an `InnerProductSpace` over `ℂ`. + +For `E × F` and `Π i : ι, E i`, we are required to declare the instance on a type synonym rather +than on the product or pi-type itself because the existing norm on these types does not agree with +the one induced by the C⋆-module structure. Moreover, the norm induced by the C⋆-module structure +doesn't agree with any other natural norm on these types (e.g., `WithLp 2 (E × F)` unless `A := ℂ`), +so we need a new synonym. + +On `A` (a C⋆-algebra) and `E` (an inner product space), we declare the instances on the types +themselves to ease the use of the C⋆-module structure. This does have the potential to cause +inconvenience (as sometimes Lean will see terms of type `A` and apply lemmas pertaining to +C⋆-modules to those terms, when the lemmas were actually intended for terms of some other +C⋆-module in context, say `F`, in which case the arguments must be provided explicitly; see for +instance the application of `CStarModule.norm_eq_sqrt_norm_inner_self` in the proof of +`WithCStarModule.max_le_prod_norm` below). However, we believe that this, hopefully rare, +inconvenience is outweighed by avoiding translating between type synonyms where possible. + +For more details on the importance of the `WithCStarModule` type synonym, see the module +documentation for `Analysis.CStarAlgebra.Module.Synonym`. + +## Implementation notes + +When `A := ℂ` and `E := ℂ`, then `ℂ` is both a C⋆-algebra (so it inherits a `CStarModule` instance +via (1) above) and an inner product space (so it inherits a `CStarModule` instance via (4) above). +We provide a sanity check ensuring that these two instances are definitionally equal. We also ensure +that the `Inner ℂ ℂ` instance from `InnerProductSpace` is definitionally equal to the one inherited +from the `CStarModule` instances. + +Note that `C⋆ᵐᵒᵈ E` is *already* equipped with a bornology and uniformity whenever `E` is (namely, +the pullback of the respective structures through `WithCStarModule.equiv`), so in each of the above +cases, it is necessary to temporarily instantiate `C⋆ᵐᵒᵈ E` with `CStarModule.normedAddCommGroup`, +show the resulting type is bilipschitz equivalent to `E` via `WithCStarModule.equiv` (in the first +and last case, this map is actually trivially an isometry), and then replace the uniformity and +bornology with the correct ones. + +-/ + +open CStarModule CStarRing + +namespace WithCStarModule + +variable {A : Type*} [NonUnitalNormedRing A] [StarRing A] [NormedSpace ℂ A] [PartialOrder A] + +/-! ## A C⋆-algebra as a C⋆-module over itself -/ + +section Self + +variable [CStarRing A] [StarOrderedRing A] [SMulCommClass ℂ A A] + +/-- Reinterpret a C⋆-algebra `A` as a `CStarModule` over itself. -/ +instance : CStarModule A A where + inner x y := star x * y + inner_add_right := mul_add .. + inner_self_nonneg := star_mul_self_nonneg _ + inner_self := CStarRing.star_mul_self_eq_zero_iff _ + inner_op_smul_right := mul_assoc .. |>.symm + inner_smul_right_complex := mul_smul_comm .. + star_inner x y := by simp + norm_eq_sqrt_norm_inner_self {x} := by + 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 + +/-! ## Products of C⋆-modules -/ + +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] +variable [CStarModule A E] [CStarModule A F] + +noncomputable instance : Norm (C⋆ᵐᵒᵈ (E × F)) where + norm x := √‖⟪x.1, x.1⟫_A + ⟪x.2, x.2⟫_A‖ + +lemma prod_norm (x : C⋆ᵐᵒᵈ (E × F)) : ‖x‖ = √‖⟪x.1, x.1⟫_A + ⟪x.2, x.2⟫_A‖ := rfl + +lemma prod_norm_sq (x : C⋆ᵐᵒᵈ (E × F)) : ‖x‖ ^ 2 = ‖⟪x.1, x.1⟫_A + ⟪x.2, x.2⟫_A‖ := by + simp [prod_norm] + +lemma prod_norm_le_norm_add (x : C⋆ᵐᵒᵈ (E × F)) : ‖x‖ ≤ ‖x.1‖ + ‖x.2‖ := by + refine abs_le_of_sq_le_sq' ?_ (by positivity) |>.2 + calc ‖x‖ ^ 2 ≤ ‖⟪x.1, x.1⟫_A‖ + ‖⟪x.2, x.2⟫_A‖ := prod_norm_sq x ▸ norm_add_le _ _ + _ = ‖x.1‖ ^ 2 + 0 + ‖x.2‖ ^ 2 := by simp [norm_sq_eq] + _ ≤ ‖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] + +noncomputable instance : CStarModule A (C⋆ᵐᵒᵈ (E × F)) where + inner x y := inner x.1 y.1 + inner x.2 y.2 + inner_add_right {x y z} := by simpa using add_add_add_comm .. + inner_self_nonneg := add_nonneg CStarModule.inner_self_nonneg CStarModule.inner_self_nonneg + inner_self {x} := by + refine ⟨fun h ↦ ?_, fun h ↦ by simp [h, CStarModule.inner_zero_left]⟩ + apply equiv (E × F) |>.injective + ext + · refine inner_self.mp <| le_antisymm ?_ inner_self_nonneg + exact le_add_of_nonneg_right CStarModule.inner_self_nonneg |>.trans_eq h + · refine inner_self.mp <| le_antisymm ?_ inner_self_nonneg + exact le_add_of_nonneg_left CStarModule.inner_self_nonneg |>.trans_eq h + inner_op_smul_right := by simp [add_mul] + inner_smul_right_complex := by simp [smul_add] + star_inner x y := by simp + norm_eq_sqrt_norm_inner_self {x} := by with_reducible_and_instances rfl + +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), + norm_eq_sqrt_norm_inner_self (E := F), equiv_snd, max_le_iff, norm_nonneg, + Real.sqrt_le_sqrt_iff] + constructor + all_goals + apply CStarAlgebra.norm_le_norm_of_nonneg_of_le + all_goals + aesop (add safe apply CStarModule.inner_self_nonneg) + +lemma norm_equiv_le_norm_prod (x : C⋆ᵐᵒᵈ (E × F)) : ‖equiv (E × F) x‖ ≤ ‖x‖ := + max_le_prod_norm x + +section Aux + +-- We temporarily disable the uniform space and bornology on `C⋆ᵐᵒᵈ A` while proving +-- that those induced by the new norm are equal to the old ones. +attribute [-instance] WithCStarModule.instUniformSpace WithCStarModule.instBornology +attribute [local instance] CStarModule.normedAddCommGroup + +open Filter Uniformity Bornology + +private lemma antilipschitzWith_two_equiv_prod_aux : AntilipschitzWith 2 (equiv (E × F)) := + AddMonoidHomClass.antilipschitz_of_bound (linearEquiv ℂ (E × F)) fun x ↦ by + apply prod_norm_le_norm_add x |>.trans + simp only [NNReal.coe_ofNat, linearEquiv_apply, two_mul] + gcongr + · exact norm_fst_le x + · exact norm_snd_le x + +private lemma lipschitzWith_one_equiv_prod_aux : LipschitzWith 1 (equiv (E × F)) := + AddMonoidHomClass.lipschitz_of_bound_nnnorm (linearEquiv ℂ (E × F)) 1 <| by + simpa using norm_equiv_le_norm_prod + +private lemma uniformity_prod_eq_aux : + 𝓤[(inferInstance : UniformSpace (E × F)).comap <| equiv _] = 𝓤 (C⋆ᵐᵒᵈ (E × F)) := + uniformity_eq_of_bilipschitz antilipschitzWith_two_equiv_prod_aux lipschitzWith_one_equiv_prod_aux + +private lemma isBounded_prod_iff_aux (s : Set (C⋆ᵐᵒᵈ (E × F))) : + @IsBounded _ (induced <| equiv (E × F)) s ↔ IsBounded s := + isBounded_iff_of_bilipschitz antilipschitzWith_two_equiv_prod_aux + lipschitzWith_one_equiv_prod_aux s + +end Aux + +noncomputable instance : NormedAddCommGroup (C⋆ᵐᵒᵈ (E × F)) := + .ofCoreReplaceAll normedSpaceCore uniformity_prod_eq_aux isBounded_prod_iff_aux + +instance : NormedSpace ℂ (C⋆ᵐᵒᵈ (E × F)) := .ofCore normedSpaceCore + +end Prod + +/-! ## Pi-types of C⋆-modules -/ + +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)] + +noncomputable instance : Norm (C⋆ᵐᵒᵈ (Π i, E i)) where + norm x := √‖∑ i, ⟪x i, x i⟫_A‖ + +lemma pi_norm (x : C⋆ᵐᵒᵈ (Π i, E i)) : ‖x‖ = √‖∑ i, ⟪x i, x i⟫_A‖ := by + with_reducible_and_instances rfl + +lemma pi_norm_sq (x : C⋆ᵐᵒᵈ (Π i, E i)) : ‖x‖ ^ 2 = ‖∑ i, ⟪x i, x i⟫_A‖ := by + simp [pi_norm] + +open Finset in +lemma pi_norm_le_sum_norm (x : C⋆ᵐᵒᵈ (Π i, E i)) : ‖x‖ ≤ ∑ i, ‖x i‖ := by + refine abs_le_of_sq_le_sq' ?_ (by positivity) |>.2 + calc ‖x‖ ^ 2 ≤ ∑ i, ‖⟪x i, x i⟫_A‖ := pi_norm_sq x ▸ norm_sum_le _ _ + _ = ∑ 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] + +open Finset in +noncomputable instance : CStarModule A (C⋆ᵐᵒᵈ (Π i, E i)) where + inner x y := ∑ i, inner (x i) (y i) + inner_add_right {x y z} := by simp [inner_sum_right, sum_add_distrib] + inner_self_nonneg := sum_nonneg <| fun _ _ ↦ CStarModule.inner_self_nonneg + inner_self {x} := by + refine ⟨fun h ↦ ?_, fun h ↦ by simp [h, CStarModule.inner_zero_left]⟩ + ext i + refine inner_self.mp <| le_antisymm (le_of_le_of_eq ?_ h) inner_self_nonneg + exact single_le_sum (fun i _ ↦ CStarModule.inner_self_nonneg (x := x i)) (mem_univ _) + inner_op_smul_right := by simp [sum_mul] + inner_smul_right_complex := by simp [smul_sum] + star_inner x y := by simp + norm_eq_sqrt_norm_inner_self {x} := by with_reducible_and_instances rfl + +lemma pi_inner (x y : C⋆ᵐᵒᵈ (Π i, E i)) : ⟪x, y⟫_A = ∑ i, ⟪x i, y i⟫_A := rfl + +@[simp] +lemma inner_single_left [DecidableEq ι] (x : C⋆ᵐᵒᵈ (Π i, E i)) {i : ι} (y : E i) : + ⟪equiv _ |>.symm <| Pi.single i y, x⟫_A = ⟪y, x i⟫_A := by + simp only [pi_inner, equiv_symm_pi_apply] + rw [Finset.sum_eq_single i] + all_goals simp_all + +@[simp] +lemma inner_single_right [DecidableEq ι] (x : C⋆ᵐᵒᵈ (Π i, E i)) {i : ι} (y : E i) : + ⟪x, equiv _ |>.symm <| Pi.single i y⟫_A = ⟪x i, y⟫_A := by + simp only [pi_inner, equiv_symm_pi_apply] + 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 + let _ : NormedAddCommGroup (C⋆ᵐᵒᵈ (Π i, E i)) := normedAddCommGroup + rw [← sq_eq_sq (by positivity) (by positivity)] + simp [norm_sq_eq] + +lemma norm_apply_le_norm (x : C⋆ᵐᵒᵈ (Π i, E i)) (i : ι) : ‖x i‖ ≤ ‖x‖ := by + 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 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 +lemma norm_equiv_le_norm_pi (x : C⋆ᵐᵒᵈ (Π i, E i)) : ‖equiv _ x‖ ≤ ‖x‖ := by + let _ : NormedAddCommGroup (C⋆ᵐᵒᵈ (Π i, E i)) := normedAddCommGroup + rw [pi_norm_le_iff_of_nonneg (by positivity)] + simpa using norm_apply_le_norm x + +section Aux + +-- We temporarily disable the uniform space and bornology on `C⋆ᵐᵒᵈ A` while proving +-- that those induced by the new norm are equal to the old ones. +attribute [-instance] WithCStarModule.instUniformSpace WithCStarModule.instBornology +attribute [local instance] CStarModule.normedAddCommGroup + +open Uniformity Bornology + +private lemma antilipschitzWith_card_equiv_pi_aux : + AntilipschitzWith (Fintype.card ι) (equiv (Π i, E i)) := + AddMonoidHomClass.antilipschitz_of_bound (linearEquiv ℂ (Π i, E i)) fun x ↦ by + simp only [NNReal.coe_natCast, linearEquiv_apply] + calc ‖x‖ ≤ ∑ i, ‖x i‖ := pi_norm_le_sum_norm x + _ ≤ ∑ _, ‖⇑x‖ := Finset.sum_le_sum fun _ _ ↦ norm_le_pi_norm .. + _ ≤ Fintype.card ι * ‖⇑x‖ := by simp + +private lemma lipschitzWith_one_equiv_pi_aux : LipschitzWith 1 (equiv (Π i, E i)) := + AddMonoidHomClass.lipschitz_of_bound_nnnorm (linearEquiv ℂ (Π i, E i)) 1 <| by + simpa using norm_equiv_le_norm_pi + +private lemma uniformity_pi_eq_aux : + 𝓤[(inferInstance : UniformSpace (Π i, E i)).comap <| equiv _] = 𝓤 (C⋆ᵐᵒᵈ (Π i, E i)) := + uniformity_eq_of_bilipschitz antilipschitzWith_card_equiv_pi_aux lipschitzWith_one_equiv_pi_aux + +private lemma isBounded_pi_iff_aux (s : Set (C⋆ᵐᵒᵈ (Π i, E i))) : + @IsBounded _ (induced <| equiv (Π i, E i)) s ↔ IsBounded s := + isBounded_iff_of_bilipschitz antilipschitzWith_card_equiv_pi_aux lipschitzWith_one_equiv_pi_aux s + +end Aux + +noncomputable instance : NormedAddCommGroup (C⋆ᵐᵒᵈ (Π i, E i)) := + .ofCoreReplaceAll normedSpaceCore uniformity_pi_eq_aux isBounded_pi_iff_aux + +instance : NormedSpace ℂ (C⋆ᵐᵒᵈ (Π i, E i)) := .ofCore normedSpaceCore + +end Pi + +/-! ## Inner product spaces as C⋆-modules -/ + +section InnerProductSpace + +open ComplexOrder + +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`, +which is unlikely to occur in practice. However, in practice one could either add those instances +to the type `E` in question, or else supply them to this instance manually, which is reason behind +the naming of these two instance arguments. -/ +instance instCStarModuleComplex : CStarModule ℂ E where + inner x y := ⟪x, y⟫_ℂ + inner_add_right := _root_.inner_add_right .. + inner_self_nonneg {x} := by + simp only + rw [← inner_self_ofReal_re, RCLike.ofReal_nonneg] + exact inner_self_nonneg + inner_self := inner_self_eq_zero + inner_op_smul_right := by simp [inner_smul_right, mul_comm] + inner_smul_right_complex := inner_smul_right .. + star_inner _ _ := inner_conj_symm .. + norm_eq_sqrt_norm_inner_self {x} := by + simpa only [← inner_self_re_eq_norm] using norm_eq_sqrt_inner x + +-- Ensures that the two ways to obtain `CStarModule ℂ ℂ` are definitionally equal. +example : instCStarModule (A := ℂ) = instCStarModuleComplex := by with_reducible_and_instances rfl + +/- Ensures that the two `Inner ℂ ℂ` instances are definitionally equal. Note that this cannot be at +reducible and instances transparency because the one from `InnerProductSpace` uses `StarRingEnd` +whereas `WithCStarModule.instCStarModule.toInner` uses `star` since `A` may not be commutative. -/ +example : (toInner : Inner ℂ ℂ) = WithCStarModule.instCStarModule.toInner := rfl + +end InnerProductSpace + +end WithCStarModule diff --git a/Mathlib/Analysis/CStarAlgebra/Module/Defs.lean b/Mathlib/Analysis/CStarAlgebra/Module/Defs.lean index 80dc5201159e3..a94e81711816a 100644 --- a/Mathlib/Analysis/CStarAlgebra/Module/Defs.lean +++ b/Mathlib/Analysis/CStarAlgebra/Module/Defs.lean @@ -10,9 +10,8 @@ import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Order # Hilbert C⋆-modules A Hilbert C⋆-module is a complex module `E` together with a right `A`-module structure, where `A` -is a C⋆-algebra, and with an "inner product" that takes values in `A`. This inner -product satisfies the Cauchy-Schwarz inequality, and induces a norm that makes `E` a normed -vector space. +is a C⋆-algebra, and with an `A`-valued inner product. This inner product satisfies the +Cauchy-Schwarz inequality, and induces a norm that makes `E` a normed vector space over `ℂ`. ## Main declarations @@ -36,6 +35,20 @@ and which would send the type class search algorithm on a chase for `A`), we pro `NormedSpace.Core` structure which enables downstream users of the class to easily register these instances themselves on a particular type. +Although the `Norm` is passed as a parameter, it almost never coincides with the norm on the +underlying type, unless that it is a purpose built type, as with the *standard Hilbert C⋆-module*. +However, with generic types already equipped with a norm, the norm as a Hilbert C⋆-module almost +never coincides with the norm on the underlying type. The two notable exceptions to this are when +we view `A` as a C⋆-module over itself, or when `A := ℂ`. For this reason we will later use the +type synonym `WithCStarModule`. + +As an example of just how different the norm can be, consider `CStarModule`s `E` and `F` over `A`. +One would like to put a `CStarModule` structure on (a type synonym of) `E × F`, where the `A`-valued +inner product is given, for `x y : E × F`, `⟪x, y⟫_A := ⟪x.1, y.1⟫_A + ⟪x.2, y.2⟫_A`. The norm this +induces satisfies `‖x‖ ^ 2 = ‖⟪x.1, y.1⟫ + ⟪x.2, y.2⟫‖`, but this doesn't coincide with *any* +natural norm on `E × F` unless `A := ℂ`, in which case it is `WithLp 2 (E × F)` because `E × F` is +then an `InnerProductSpace` over `ℂ`. + ## References + Erin Wittlich. *Formalizing Hilbert Modules in C⋆-algebras with the Lean Proof Assistant*, @@ -145,18 +158,18 @@ variable {A E : Type*} [NonUnitalNormedRing A] [StarRing A] [PartialOrder A] local notation "⟪" x ", " y "⟫" => inner (𝕜 := A) x y -variable (A) in +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 : Norm E where - norm x := Real.sqrt ‖⟪x, x⟫‖ +noncomputable def norm (A : Type*) {E : Type*} [Norm A] [Inner A E] : Norm E where + norm x := Real.sqrt ‖⟪x, x⟫_A‖ -lemma inner_self_eq_norm_sq {x : E} : ‖⟪x, x⟫‖ = ‖x‖ ^ 2 := by simp [norm_eq_sqrt_norm_inner_self] +lemma norm_sq_eq {x : E} : ‖x‖ ^ 2 = ‖⟪x, x⟫‖ := by simp [norm_eq_sqrt_norm_inner_self] section include A -protected lemma norm_nonneg {x : E} : 0 ≤ ‖x‖ := by simp [norm_eq_sqrt_norm_inner_self]; positivity +protected lemma norm_nonneg {x : E} : 0 ≤ ‖x‖ := by simp [norm_eq_sqrt_norm_inner_self] protected lemma norm_pos {x : E} (hx : x ≠ 0) : 0 < ‖x‖ := by simp only [norm_eq_sqrt_norm_inner_self, Real.sqrt_pos, norm_pos_iff] @@ -170,15 +183,14 @@ protected lemma norm_zero : ‖(0 : E)‖ = 0 := by simp [norm_eq_sqrt_norm_inne lemma norm_zero_iff (x : E) : ‖x‖ = 0 ↔ x = 0 := ⟨fun h => by simpa [norm_eq_sqrt_norm_inner_self, inner_self] using h, - fun h => by simp [norm, h]; rw [CStarModule.norm_zero] ⟩ + fun h => by simp [norm, h, norm_eq_sqrt_norm_inner_self]⟩ end -lemma norm_sq_eq {x : E} : ‖x‖ ^ 2 = ‖⟪x, x⟫‖ := by simp [norm_eq_sqrt_norm_inner_self] - variable [CStarRing A] [StarOrderedRing A] [StarModule ℂ A] [IsScalarTower ℂ A A] [SMulCommClass ℂ A 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 rcases eq_or_ne x 0 with h|h @@ -197,7 +209,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 @@ -207,13 +219,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 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] @@ -245,13 +258,19 @@ lemma normedSpaceCore [CompleteSpace A] : NormedSpace.Core ℂ E where 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 := + NormedAddCommGroup.ofCore CStarModule.normedSpaceCore + +open scoped InnerProductSpace in lemma norm_eq_csSup [CompleteSpace A] (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) - · simp [norm_smul, CStarModule.inner_self_eq_norm_sq, pow_two, ← mul_assoc] + · 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 _ ≤ 1 * ‖v‖ := by gcongr @@ -261,6 +280,12 @@ 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] diff --git a/Mathlib/Analysis/CStarAlgebra/Module/Synonym.lean b/Mathlib/Analysis/CStarAlgebra/Module/Synonym.lean new file mode 100644 index 0000000000000..82554bb415dee --- /dev/null +++ b/Mathlib/Analysis/CStarAlgebra/Module/Synonym.lean @@ -0,0 +1,319 @@ +/- +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.RingTheory.Finiteness +import Mathlib.Topology.Bornology.Constructions +import Mathlib.Topology.UniformSpace.Equiv + +/-! # Type synonym for types with a `CStarModule` structure + +It is often the case that we want to construct a `CStarModule` instance on a type that is already +endowed with a norm, but this norm is not the one associated to its `CStarModule` structure. For +this reason, we create a type synonym `WithCStarModule` which is endowed with the requisite +`CStarModule` instance. We also introduce the scoped notation `C⋆ᵐᵒᵈ` for this type synonym. + +The common use cases are, when `A` is a C⋆-algebra: + ++ `E × F` where `E` and `F` are `CStarModule`s over `A` ++ `Π i, E i` where `E i` is a `CStarModule` over `A` and `i : ι` with `ι` a `Fintype` + +In this way, the set up is very similar to the `WithLp` type synonym, although there is no way to +reuse `WithLp` because the norms *do not* coincide in general. + +The `WithCStarModule` synonym is of vital importance, especially because the `CStarModule` class +marks `A` as an `outParam`. Indeed, we want to infer `A` from the type of `E`, but, as with modules, +a type `E` can be a `CStarModule` over different C⋆-algebras. For example, note that if `A` is a +C⋆-algebra, then so is `A × A`, and therefore we may consider both `A` and `A × A` as `CStarModule`s +over themselves, respectively. However, we may *also* consider `A × A` as a `CStarModule` over `A`. +However, by utilizing the type synonym, these actually correspond to *different types*, namely: + ++ `A` as a `CStarModule` over `A` corresponds to `A` ++ `A × A` as a `CStarModule` over `A × A` corresponds to `A × A` ++ `A × A` as a `CStarModule` over `A` corresponds to `C⋆ᵐᵒᵈ (A × A)` + +## Main definitions + +* `WithCStarModule E`: a copy of `E` to be equipped with a `CStarModule A` structure. Note that + `A` is an `outParam` in the class `CStarModule`, so it can be inferred from the type of `E`. +* `WithCStarModule.equiv E`: the canonical equivalence between `WithCStarModule E` and `E`. +* `WithCStarModule.linearEquiv ℂ A E`: the canonical `ℂ`-module isomorphism between + `WithCStarModule E` and `E`. + +## Implementation notes + +The pattern here is the same one as is used by `Lex` for order structures; it avoids having a +separate synonym for each type, and allows all the structure-copying code to be shared. +-/ + +/-- A type synonym for endowing a given type with a `CStarModule` structure. This has the scoped +notation `C⋆ᵐᵒᵈ`. + +Note: because the C⋆-algebra `A` over which `E` is a `CStarModule` is listed as an `outParam` in +that class, we don't pass it as an unused argument to `WithCStarModule`, unlike the `p` parameter +in `WithLp`, which can vary. -/ +def WithCStarModule (E : Type*) := E + +namespace WithCStarModule + +@[inherit_doc] +scoped notation "C⋆ᵐᵒᵈ" => WithCStarModule + +section Basic + +variable (R R' E : Type*) + +/-- The canonical equivalence between `WithCStarModule E` and `E`. This should always be used to +convert back and forth between the representations. -/ +def equiv : WithCStarModule E ≃ E := Equiv.refl _ + +instance instNontrivial [Nontrivial E] : Nontrivial (WithCStarModule E) := ‹Nontrivial E› +instance instInhabited [Inhabited E] : Inhabited (WithCStarModule E) := ‹Inhabited E› +instance instNonempty [Nonempty E] : Nonempty (WithCStarModule E) := ‹Nonempty E› +instance instUnique [Unique E] : Unique (WithCStarModule E) := ‹Unique E› + +/-! ## `WithCStarModule E` inherits various module-adjacent structures from `E`. -/ + +instance instAddCommGroup [AddCommGroup E] : AddCommGroup (WithCStarModule E) := ‹AddCommGroup E› +instance instSMul {R : Type*} [SMul R E] : SMul R (WithCStarModule E) := ‹SMul R E› +instance instModule {R : Type*} [Semiring R] [AddCommGroup E] [Module R E] : + Module R (WithCStarModule E) := + ‹Module R E› + +instance instIsScalarTower [SMul R R'] [SMul R E] [SMul R' E] + [IsScalarTower R R' E] : IsScalarTower R R' (WithCStarModule E) := + ‹IsScalarTower R R' E› + +instance instSMulCommClass [SMul R E] [SMul R' E] [SMulCommClass R R' E] : + SMulCommClass R R' (WithCStarModule E) := + ‹SMulCommClass R R' E› + +instance instModuleFinite [Semiring R] [AddCommGroup E] [Module R E] [Module.Finite R E] : + Module.Finite R (WithCStarModule E) := + ‹Module.Finite R E› + + +section Equiv + +variable {R E} +variable [SMul R E] (c : R) (x y : WithCStarModule E) (x' y' : E) + +/-! `WithCStarModule.equiv` preserves the module structure. -/ + +section AddCommGroup + +variable [AddCommGroup E] + +@[simp] +theorem equiv_zero : equiv E 0 = 0 := + rfl + +@[simp] +theorem equiv_symm_zero : (equiv E).symm 0 = 0 := + rfl + +@[simp] +theorem equiv_add : equiv E (x + y) = equiv E x + equiv E y := + rfl + +@[simp] +theorem equiv_symm_add : + (equiv E).symm (x' + y') = (equiv E).symm x' + (equiv E).symm y' := + rfl + +@[simp] +theorem equiv_sub : equiv E (x - y) = equiv E x - equiv E y := + rfl + +@[simp] +theorem equiv_symm_sub : + (equiv E).symm (x' - y') = (equiv E).symm x' - (equiv E).symm y' := + rfl + +@[simp] +theorem equiv_neg : equiv E (-x) = -equiv E x := + rfl + +@[simp] +theorem equiv_symm_neg : (equiv E).symm (-x') = -(equiv E).symm x' := + rfl + +end AddCommGroup + +@[simp] +theorem equiv_smul : equiv E (c • x) = c • equiv E x := + rfl + +@[simp] +theorem equiv_symm_smul : (equiv E).symm (c • x') = c • (equiv E).symm x' := + rfl + +end Equiv + +/-- `WithCStarModule.equiv` as a linear equivalence. -/ +@[simps (config := .asFn)] +def linearEquiv [Semiring R] [AddCommGroup E] [Module R E] : C⋆ᵐᵒᵈ E ≃ₗ[R] E := + { LinearEquiv.refl _ _ with + toFun := equiv _ + invFun := (equiv _).symm } + +/-! ## `WithCStarModule E` inherits the uniformity and bornology from `E`. -/ + +variable {E} + +instance [u : UniformSpace E] : UniformSpace (C⋆ᵐᵒᵈ E) := u.comap <| equiv E + +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 |>.toUniformEquivOfIsUniformInducing ⟨rfl⟩ + +instance [UniformSpace E] [CompleteSpace E] : CompleteSpace (C⋆ᵐᵒᵈ E) := + uniformEquiv.completeSpace_iff.mpr inferInstance + +end Basic + +/-! ## Prod + +Register simplification lemmas for the applications of `WithCStarModule (E × F)` elements, as +the usual lemmas for `Prod` will not trigger. -/ + +section Prod + +variable {R E F : Type*} +variable [SMul R E] [SMul R F] +variable (x y : C⋆ᵐᵒᵈ (E × F)) (c : R) + +section AddCommGroup + +variable [AddCommGroup E] [AddCommGroup F] + +@[simp] +theorem zero_fst : (0 : C⋆ᵐᵒᵈ (E × F)).fst = 0 := + rfl + +@[simp] +theorem zero_snd : (0 : C⋆ᵐᵒᵈ (E × F)).snd = 0 := + rfl + +@[simp] +theorem add_fst : (x + y).fst = x.fst + y.fst := + rfl + +@[simp] +theorem add_snd : (x + y).snd = x.snd + y.snd := + rfl + +@[simp] +theorem sub_fst : (x - y).fst = x.fst - y.fst := + rfl + +@[simp] +theorem sub_snd : (x - y).snd = x.snd - y.snd := + rfl + +@[simp] +theorem neg_fst : (-x).fst = -x.fst := + rfl + +@[simp] +theorem neg_snd : (-x).snd = -x.snd := + rfl + +end AddCommGroup + +@[simp] +theorem smul_fst : (c • x).fst = c • x.fst := + rfl + +@[simp] +theorem smul_snd : (c • x).snd = c • x.snd := + rfl + +/-! Note that the unapplied versions of these lemmas are deliberately omitted, as they break +the use of the type synonym. -/ + +@[simp] +theorem equiv_fst (x : C⋆ᵐᵒᵈ (E × F)) : (equiv (E × F) x).fst = x.fst := + rfl + +@[simp] +theorem equiv_snd (x : C⋆ᵐᵒᵈ (E × F)) : (equiv (E × F) x).snd = x.snd := + rfl + +@[simp] +theorem equiv_symm_fst (x : E × F) : ((equiv (E × F)).symm x).fst = x.fst := + rfl + +@[simp] +theorem equiv_symm_snd (x : E × F) : ((equiv (E × F)).symm x).snd = x.snd := + rfl + +end Prod + +/-! ## Pi + +Register simplification lemmas for the applications of `WithCStarModule (Π i, E i)` elements, as +the usual lemmas for `Pi` will not trigger. + +We also provide a `CoeFun` instance for `WithCStarModule (Π i, E i)`. -/ + +section Pi + +/- The following should not be a `FunLike` instance because then the coercion `⇑` would get +unfolded to `FunLike.coe` instead of `WithCStarModule.equiv`. -/ +instance {ι : Type*} (E : ι → Type*) : CoeFun (C⋆ᵐᵒᵈ (Π i, E i)) (fun _ ↦ Π i, E i) where + coe := WithCStarModule.equiv _ + +@[ext] +protected theorem ext {ι : Type*} {E : ι → Type*} {x y : C⋆ᵐᵒᵈ (Π i, E i)} + (h : ∀ i, x i = y i) : x = y := + funext h + +variable {R ι : Type*} {E : ι → Type*} +variable [∀ i, SMul R (E i)] +variable (c : R) (x y : C⋆ᵐᵒᵈ (Π i, E i)) (i : ι) + +section AddCommGroup + +variable [∀ i, AddCommGroup (E i)] + +@[simp] +theorem zero_apply : (0 : C⋆ᵐᵒᵈ (Π i, E i)) i = 0 := + rfl + +@[simp] +theorem add_apply : (x + y) i = x i + y i := + rfl + +@[simp] +theorem sub_apply : (x - y) i = x i - y i := + rfl + +@[simp] +theorem neg_apply : (-x) i = -x i := + rfl + +end AddCommGroup + +@[simp] +theorem smul_apply : (c • x) i = c • x i := + rfl + +/-! Note that the unapplied versions of these lemmas are deliberately omitted, as they break +the use of the type synonym. -/ + +@[simp] +theorem equiv_pi_apply (i : ι) : equiv _ x i = x i := + rfl + +@[simp] +theorem equiv_symm_pi_apply (x : ∀ i, E i) (i : ι) : + (WithCStarModule.equiv _).symm x i = x i := + rfl + +end Pi + +end WithCStarModule diff --git a/Mathlib/Analysis/CStarAlgebra/Multiplier.lean b/Mathlib/Analysis/CStarAlgebra/Multiplier.lean index 06bd224d0b51a..3c84852d4f405 100644 --- a/Mathlib/Analysis/CStarAlgebra/Multiplier.lean +++ b/Mathlib/Analysis/CStarAlgebra/Multiplier.lean @@ -534,11 +534,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 ?_ ?_ @@ -559,8 +563,8 @@ theorem norm_fst_eq_snd (a : 𝓜(𝕜, A)) : ‖a.fst‖ = ‖a.snd‖ := by intro b convert mul_le_mul_right' (mul_le_mul_left' (f.le_opNNNorm b) C) ‖b‖₊ using 1 ring - have := NNReal.div_le_of_le_mul $ f.opNNNorm_le_bound _ $ by - simpa only [sqrt_sq, sqrt_mul] using fun b ↦ sqrt_le_sqrt.2 $ (h b).trans (h1 b) + have := NNReal.div_le_of_le_mul <| f.opNNNorm_le_bound _ <| by + simpa only [sqrt_sq, sqrt_mul] using fun b ↦ sqrt_le_sqrt.2 <| (h b).trans (h1 b) convert NNReal.rpow_le_rpow this two_pos.le · simp only [NNReal.rpow_two, div_pow, sq_sqrt] simp only [sq, mul_self_div_self] diff --git a/Mathlib/Analysis/CStarAlgebra/Spectrum.lean b/Mathlib/Analysis/CStarAlgebra/Spectrum.lean index ceac7a25b3c1e..6d91e465acfeb 100644 --- a/Mathlib/Analysis/CStarAlgebra/Spectrum.lean +++ b/Mathlib/Analysis/CStarAlgebra/Spectrum.lean @@ -3,16 +3,58 @@ 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.Normed.Algebra.Spectrum +import Mathlib.Analysis.Complex.UpperHalfPlane.Topology import Mathlib.Analysis.CStarAlgebra.Unitization +import Mathlib.Analysis.Normed.Algebra.Spectrum import Mathlib.Analysis.SpecialFunctions.Exponential import Mathlib.Algebra.Star.StarAlgHom /-! # Spectral properties in C⋆-algebras + In this file, we establish various properties related to the spectrum of elements in C⋆-algebras. +In particular, we show that the spectrum of a unitary element is contained in the unit circle in +`ℂ`, the spectrum of a selfadjoint element is real, the spectral radius of a selfadjoint element +or normal element is its norm, among others. + +An essential feature of C⋆-algebras is **spectral permanence**. This is the property that the +spectrum of an element in a closed subalgebra is the same as the spectrum of the element in the +whole algebra. For Banach algebras more generally, and even for Banach ⋆-algebras, this fails. + +A consequence of spectral permanence is that one may always enlarge the C⋆-algebra (via a unital +embedding) while preserving the spectrum of any element. In addition, it allows us to make sense of +the spectrum of elements in non-unital C⋆-algebras by considering them as elements in the +`Unitization` of the C⋆-algebra, or indeed *any* unital C⋆-algebra. Of course, one may do this +(that is, consider the spectrum of an element in a non-unital by embedding it in a unital algebra) +for any Banach algebra, but the downside in that setting is that embedding in different unital +algebras results in varying spectra. + +In Mathlib, we don't *define* the spectrum of an element in a non-unital C⋆-algebra, and instead +simply consider the `quasispectrum` so as to avoid depending on a choice of unital algebra. However, +we can still establish a form of spectral permanence. + +## Main statements + ++ `unitary.spectrum_subset_circle`: The spectrum of a unitary element is contained in the unit + sphere in `ℂ`. ++ `IsSelfAdjoint.spectralRadius_eq_nnnorm`: The spectral radius of a selfadjoint element is equal + to its norm. ++ `IsStarNormal.spectralRadius_eq_nnnorm`: The spectral radius of a normal element is equal to + its norm. ++ `IsSelfAdjoint.mem_spectrum_eq_re`: Any element of the spectrum of a selfadjoint element is real. +* `StarSubalgebra.coe_isUnit`: for `x : S` in a C⋆-Subalgebra `S` of `A`, then `↑x : A` is a Unit + if and only if `x` is a unit. +* `StarSubalgebra.spectrum_eq`: **spectral_permanence** for `x : S`, where `S` is a C⋆-Subalgebra + of `A`, `spectrum ℂ x = spectrum ℂ (x : A)`. + +## TODO + ++ prove a variation of spectral permanence using `StarAlgHom` instead of `StarSubalgebra`. ++ prove a variation of spectral permanence for `quasispectrum`. + -/ +local notation "σ" => spectrum local postfix:max "⋆" => star section @@ -36,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 := @@ -87,8 +129,10 @@ theorem IsStarNormal.spectralRadius_eq_nnnorm (a : A) [IsStarNormal a] : convert tendsto_nhds_unique h₂ (pow_nnnorm_pow_one_div_tendsto_nhds_spectralRadius (a⋆ * a)) rw [(IsSelfAdjoint.star_mul_self a).spectralRadius_eq_nnnorm, sq, nnnorm_star_mul_self, coe_mul] +variable [StarModule ℂ A] + /-- Any element of the spectrum of a selfadjoint is real. -/ -theorem IsSelfAdjoint.mem_spectrum_eq_re [StarModule ℂ A] {a : A} (ha : IsSelfAdjoint a) {z : ℂ} +theorem IsSelfAdjoint.mem_spectrum_eq_re {a : A} (ha : IsSelfAdjoint a) {z : ℂ} (hz : z ∈ spectrum ℂ a) : z = z.re := by have hu := exp_mem_unitary_of_mem_skewAdjoint ℂ (ha.smul_mem_skewAdjoint conj_I) let Iu := Units.mk0 I I_ne_zero @@ -101,22 +145,78 @@ theorem IsSelfAdjoint.mem_spectrum_eq_re [StarModule ℂ A] {a : A} (ha : IsSelf spectrum.subset_circle_of_unitary hu this /-- Any element of the spectrum of a selfadjoint is real. -/ -theorem selfAdjoint.mem_spectrum_eq_re [StarModule ℂ A] (a : selfAdjoint A) {z : ℂ} +theorem selfAdjoint.mem_spectrum_eq_re (a : selfAdjoint A) {z : ℂ} (hz : z ∈ spectrum ℂ (a : A)) : z = z.re := a.prop.mem_spectrum_eq_re hz +/-- Any element of the spectrum of a selfadjoint is real. -/ +theorem IsSelfAdjoint.im_eq_zero_of_mem_spectrum {a : A} (ha : IsSelfAdjoint a) + {z : ℂ} (hz : z ∈ spectrum ℂ a) : z.im = 0 := by + rw [ha.mem_spectrum_eq_re hz, ofReal_im] + /-- The spectrum of a selfadjoint is real -/ -theorem IsSelfAdjoint.val_re_map_spectrum [StarModule ℂ A] {a : A} (ha : IsSelfAdjoint a) : +theorem IsSelfAdjoint.val_re_map_spectrum {a : A} (ha : IsSelfAdjoint a) : spectrum ℂ a = ((↑) ∘ re '' spectrum ℂ a : Set ℂ) := le_antisymm (fun z hz => ⟨z, hz, (ha.mem_spectrum_eq_re hz).symm⟩) fun z => by rintro ⟨z, hz, rfl⟩ simpa only [(ha.mem_spectrum_eq_re hz).symm, Function.comp_apply] using hz /-- The spectrum of a selfadjoint is real -/ -theorem selfAdjoint.val_re_map_spectrum [StarModule ℂ A] (a : selfAdjoint A) : +theorem selfAdjoint.val_re_map_spectrum (a : selfAdjoint A) : spectrum ℂ (a : A) = ((↑) ∘ re '' spectrum ℂ (a : A) : Set ℂ) := a.property.val_re_map_spectrum +/-- The complement of the spectrum of a selfadjoint element in a C⋆-algebra is connected. -/ +lemma IsSelfAdjoint.isConnected_spectrum_compl {a : A} (ha : IsSelfAdjoint a) : + IsConnected (σ ℂ a)ᶜ := by + suffices IsConnected (((σ ℂ a)ᶜ ∩ {z | 0 ≤ z.im}) ∪ (σ ℂ a)ᶜ ∩ {z | z.im ≤ 0}) by + rw [← Set.inter_union_distrib_left, ← Set.setOf_or] at this + rw [← Set.inter_univ (σ ℂ a)ᶜ] + convert this using 2 + exact Eq.symm <| Set.eq_univ_of_forall (fun z ↦ le_total 0 z.im) + refine IsConnected.union ?nonempty ?upper ?lower + 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 + case' upper => apply Complex.isConnected_of_upperHalfPlane ?_ <| Set.inter_subset_right + case' lower => apply Complex.isConnected_of_lowerHalfPlane ?_ <| Set.inter_subset_right + all_goals + refine Set.subset_inter (fun z hz hz' ↦ ?_) (fun _ ↦ by simpa using le_of_lt) + rw [Set.mem_setOf_eq, ha.im_eq_zero_of_mem_spectrum hz'] at hz + simp_all + +namespace StarSubalgebra + +variable (S : StarSubalgebra ℂ A) [hS : IsClosed (S : Set A)] + +/-- For a unital C⋆-subalgebra `S` of `A` and `x : S`, if `↑x : A` is invertible in `A`, then +`x` is invertible in `S`. -/ +lemma coe_isUnit {a : S} : IsUnit (a : A) ↔ IsUnit a := by + refine ⟨fun ha ↦ ?_, IsUnit.map S.subtype⟩ + have ha₁ := ha.star.mul ha + have ha₂ := ha.mul ha.star + have spec_eq {x : S} (hx : IsSelfAdjoint x) : spectrum ℂ x = spectrum ℂ (x : A) := + Subalgebra.spectrum_eq_of_isPreconnected_compl S _ <| + (hx.map S.subtype).isConnected_spectrum_compl.isPreconnected + rw [← StarMemClass.coe_star, ← MulMemClass.coe_mul, ← spectrum.zero_not_mem_iff ℂ, ← spec_eq, + spectrum.zero_not_mem_iff] at ha₁ ha₂ + · have h₁ : ha₁.unit⁻¹ * star a * a = 1 := mul_assoc _ _ a ▸ ha₁.val_inv_mul + have h₂ : a * (star a * ha₂.unit⁻¹) = 1 := (mul_assoc a _ _).symm ▸ ha₂.mul_val_inv + exact ⟨⟨a, ha₁.unit⁻¹ * star a, left_inv_eq_right_inv h₁ h₂ ▸ h₂, h₁⟩, rfl⟩ + · exact IsSelfAdjoint.mul_star_self a + · exact IsSelfAdjoint.star_mul_self a + +lemma mem_spectrum_iff {a : S} {z : ℂ} : z ∈ spectrum ℂ a ↔ z ∈ spectrum ℂ (a : A) := + not_iff_not.mpr S.coe_isUnit.symm + +/-- **Spectral permanence.** The spectrum of an element is invariant of the (closed) +`StarSubalgebra` in which it is contained. -/ +lemma spectrum_eq {a : S} : spectrum ℂ a = spectrum ℂ (a : A) := + Set.ext fun _ ↦ S.mem_spectrum_iff + +end StarSubalgebra + end ComplexScalars namespace NonUnitalStarAlgHom @@ -126,7 +226,7 @@ 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 [FunLike F A B] [NonUnitalAlgHomClass F ℂ A B] [StarHomClass F A B] open Unitization @@ -141,7 +241,7 @@ lemma nnnorm_apply_le (φ : F) (a : A) : ‖φ a‖₊ ≤ ‖a‖₊ := by 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.starHom_apply ψ).spectralRadius_eq_nnnorm, hs.spectralRadius_eq_nnnorm, coe_le_coe] + 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) simpa [nnnorm_inr] using h (starLift (inrNonUnitalStarAlgHom ℂ B |>.comp (φ : A →⋆ₙₐ[ℂ] B))) a @@ -163,11 +263,11 @@ end NonUnitalStarAlgHom namespace StarAlgEquiv -variable {F A B : Type*} [NormedRing A] [NormedSpace ℂ A] [SMulCommClass ℂ A A] +variable {F A B : Type*} [NonUnitalNormedRing A] [NormedSpace ℂ A] [SMulCommClass ℂ A A] variable [IsScalarTower ℂ A A] [CompleteSpace A] [StarRing A] [CStarRing A] [StarModule ℂ A] -variable [NormedRing B] [NormedSpace ℂ B] [SMulCommClass ℂ B B] [IsScalarTower ℂ B B] +variable [NonUnitalNormedRing B] [NormedSpace ℂ B] [SMulCommClass ℂ B B] [IsScalarTower ℂ B B] variable [CompleteSpace B] [StarRing B] [CStarRing B] [StarModule ℂ B] [EquivLike F A B] -variable [NonUnitalAlgEquivClass F ℂ A B] [StarAlgEquivClass 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 @@ -192,7 +292,7 @@ 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 ℂ] -/-- 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 @@ -209,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 0ccc38b7262f0..7a5bdee2eef6e 100644 --- a/Mathlib/Analysis/CStarAlgebra/Unitization.lean +++ b/Mathlib/Analysis/CStarAlgebra/Unitization.lean @@ -72,7 +72,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 @@ -129,7 +129,7 @@ instance Unitization.instCStarRing : CStarRing (Unitization 𝕜 E) where norm_mul_self_le x := by -- rewrite both sides as a `⊔` simp only [Unitization.norm_def, Prod.norm_def, ← sup_eq_max] - -- Show that `(Unitization.splitMul 𝕜 E x).snd` satisifes the C⋆-property, in two stages: + -- Show that `(Unitization.splitMul 𝕜 E x).snd` satisfies the C⋆-property, in two stages: have h₁ : ∀ x : Unitization 𝕜 E, ‖(Unitization.splitMul 𝕜 E x).snd‖ ≤ ‖(Unitization.splitMul 𝕜 E (star x)).snd‖ := by simp only [add_zero, Unitization.splitMul_apply, Unitization.snd_star, Unitization.fst_star] diff --git a/Mathlib/Analysis/Calculus/BumpFunction/Convolution.lean b/Mathlib/Analysis/Calculus/BumpFunction/Convolution.lean index bc3b1582c4f18..4b70bd94ec863 100644 --- a/Mathlib/Analysis/Calculus/BumpFunction/Convolution.lean +++ b/Mathlib/Analysis/Calculus/BumpFunction/Convolution.lean @@ -85,8 +85,8 @@ nonrec theorem convolution_tendsto_right {ι} {φ : ι → ContDiffBump (0 : G)} (hig : ∀ᶠ i in l, AEStronglyMeasurable (g i) μ) (hcg : Tendsto (uncurry g) (l ×ˢ 𝓝 x₀) (𝓝 z₀)) (hk : Tendsto k l (𝓝 x₀)) : Tendsto (fun i => ((φ i).normed μ ⋆[lsmul ℝ ℝ, μ] g i) (k i)) l (𝓝 z₀) := - convolution_tendsto_right (eventually_of_forall fun i => (φ i).nonneg_normed) - (eventually_of_forall fun i => (φ i).integral_normed) (tendsto_support_normed_smallSets hφ) hig + convolution_tendsto_right (Eventually.of_forall fun i => (φ i).nonneg_normed) + (Eventually.of_forall fun i => (φ i).integral_normed) (tendsto_support_normed_smallSets hφ) hig hcg hk /-- Special case of `ContDiffBump.convolution_tendsto_right` where `g` is continuous, @@ -94,7 +94,7 @@ nonrec theorem convolution_tendsto_right {ι} {φ : ι → ContDiffBump (0 : G)} theorem convolution_tendsto_right_of_continuous {ι} {φ : ι → ContDiffBump (0 : G)} {l : Filter ι} (hφ : Tendsto (fun i => (φ i).rOut) l (𝓝 0)) (hg : Continuous g) (x₀ : G) : Tendsto (fun i => ((φ i).normed μ ⋆[lsmul ℝ ℝ, μ] g) x₀) l (𝓝 (g x₀)) := - convolution_tendsto_right hφ (eventually_of_forall fun _ => hg.aestronglyMeasurable) + convolution_tendsto_right hφ (Eventually.of_forall fun _ => hg.aestronglyMeasurable) ((hg.tendsto x₀).comp tendsto_snd) tendsto_const_nhds /-- If a function `g` is locally integrable, then the convolution `φ i * g` converges almost @@ -112,10 +112,10 @@ theorem ae_convolution_tendsto_right_of_locallyIntegrable filter_upwards [(Besicovitch.vitaliFamily μ).ae_tendsto_average_norm_sub hg] with x₀ h₀ simp only [convolution_eq_swap, lsmul_apply] have hφ' : Tendsto (fun i ↦ (φ i).rOut) l (𝓝[>] 0) := - tendsto_nhdsWithin_iff.2 ⟨hφ, eventually_of_forall (fun i ↦ (φ i).rOut_pos)⟩ + 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 d2928d8ac311c..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,12 +407,12 @@ 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, Real.norm_eq_abs, abs_div] - simp only [div_le_iff B, field_simps] + simp only [div_le_iff₀ B, field_simps] ring_nf rfl · have ID : ‖D / (1 + D) - 1‖ = 1 / (1 + D) := by @@ -425,7 +425,7 @@ theorem y_pos_of_mem_ball {D : ℝ} {x : E} (Dpos : 0 < D) (D_lt_one : D < 1) rw [← mem_closedBall_iff_norm'] apply closedBall_subset_closedBall' _ (ball_subset_closedBall hy) rw [← one_smul ℝ x, dist_eq_norm, hz, ← sub_smul, one_smul, norm_smul, ID] - simp only [B.ne', div_le_iff B, field_simps] + simp only [B.ne', div_le_iff₀ B, field_simps] nlinarith only [hx, D_lt_one] apply lt_of_lt_of_le _ (measure_mono C) apply measure_ball_pos @@ -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/Normed.lean b/Mathlib/Analysis/Calculus/BumpFunction/Normed.lean index 81bf4037d473e..a61f635da6766 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 @@ -99,7 +99,7 @@ theorem measure_closedBall_le_integral : (μ (closedBall c f.rIn)).toReal ≤ (μ (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 (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)) + _ ≤ ∫ x, f x ∂μ := setIntegral_le_integral f.integrable (Eventually.of_forall (fun x ↦ f.nonneg)) theorem normed_le_div_measure_closedBall_rIn [μ.IsOpenPosMeasure] (x : E) : f.normed μ x ≤ 1 / (μ (closedBall c f.rIn)).toReal := by @@ -124,7 +124,7 @@ theorem measure_closedBall_div_le_integral [IsAddHaarMeasure μ] (K : ℝ) (h : have K_pos : 0 < K := by simpa [f.rIn_pos, not_lt.2 f.rIn_pos.le] using mul_pos_iff.1 (f.rOut_pos.trans_le h) apply le_trans _ (f.measure_closedBall_le_integral μ) - rw [div_le_iff (pow_pos K_pos _), addHaar_closedBall' _ _ f.rIn_pos.le, + rw [div_le_iff₀ (pow_pos K_pos _), addHaar_closedBall' _ _ f.rIn_pos.le, addHaar_closedBall' _ _ f.rOut_pos.le, ENNReal.toReal_mul, ENNReal.toReal_mul, ENNReal.toReal_ofReal (pow_nonneg f.rOut_pos.le _), ENNReal.toReal_ofReal (pow_nonneg f.rIn_pos.le _), mul_assoc, mul_comm _ (K ^ _), ← mul_assoc, @@ -142,7 +142,7 @@ theorem normed_le_div_measure_closedBall_rOut [IsAddHaarMeasure μ] (K : ℝ) (h · exact f.integral_pos.le · exact f.le_one apply this.trans - rw [div_le_div_iff f.integral_pos, one_mul, ← div_le_iff' (pow_pos K_pos _)] + rw [div_le_div_iff f.integral_pos, one_mul, ← div_le_iff₀' (pow_pos K_pos _)] · exact f.measure_closedBall_div_le_integral μ K h · exact ENNReal.toReal_pos (measure_closedBall_pos _ _ f.rOut_pos).ne' measure_closedBall_lt_top.ne diff --git a/Mathlib/Analysis/Calculus/Conformal/NormedSpace.lean b/Mathlib/Analysis/Calculus/Conformal/NormedSpace.lean index b64a5bf2e5cc8..5e7a4a62baea7 100644 --- a/Mathlib/Analysis/Calculus/Conformal/NormedSpace.lean +++ b/Mathlib/Analysis/Calculus/Conformal/NormedSpace.lean @@ -63,7 +63,7 @@ theorem conformalAt_const_smul {c : ℝ} (h : c ≠ 0) (x : X) : ConformalAt (fu theorem Subsingleton.conformalAt [Subsingleton X] (f : X → Y) (x : X) : ConformalAt f x := ⟨0, hasFDerivAt_of_subsingleton _ _, isConformalMap_of_subsingleton _⟩ -/-- A function is a conformal map if and only if its differential is a conformal linear map-/ +/-- A function is a conformal map if and only if its differential is a conformal linear map -/ theorem conformalAt_iff_isConformalMap_fderiv {f : X → Y} {x : X} : ConformalAt f x ↔ IsConformalMap (fderiv ℝ f x) := by constructor diff --git a/Mathlib/Analysis/Calculus/ContDiff/Basic.lean b/Mathlib/Analysis/Calculus/ContDiff/Basic.lean index d45ba684d6e3d..56efdab13165b 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Basic.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Basic.lean @@ -240,7 +240,7 @@ theorem ContinuousLinearEquiv.iteratedFDerivWithin_comp_left (g : F ≃L[𝕜] G (g : F →L[𝕜] G).compContinuousMultilinearMap (iteratedFDerivWithin 𝕜 i f s x) := by induction' i with i IH generalizing x · ext1 m - simp only [Nat.zero_eq, iteratedFDerivWithin_zero_apply, comp_apply, + simp only [iteratedFDerivWithin_zero_apply, comp_apply, ContinuousLinearMap.compContinuousMultilinearMap_coe, coe_coe] · ext1 m rw [iteratedFDerivWithin_succ_apply_left] @@ -299,7 +299,7 @@ point in a domain. -/ theorem ContinuousLinearEquiv.comp_contDiffWithinAt_iff (e : F ≃L[𝕜] G) : ContDiffWithinAt 𝕜 n (e ∘ f) s x ↔ ContDiffWithinAt 𝕜 n f s x := ⟨fun H => by - simpa only [(· ∘ ·), e.symm.coe_coe, e.symm_apply_apply] using + simpa only [Function.comp_def, e.symm.coe_coe, e.symm_apply_apply] using H.continuousLinearMap_comp (e.symm : G →L[𝕜] F), fun H => H.continuousLinearMap_comp (e : F →L[𝕜] G)⟩ @@ -382,7 +382,7 @@ theorem ContinuousLinearEquiv.iteratedFDerivWithin_comp_right (g : G ≃L[𝕜] (iteratedFDerivWithin 𝕜 i f s (g x)).compContinuousLinearMap fun _ => g := by induction' i with i IH generalizing x · ext1 - simp only [Nat.zero_eq, iteratedFDerivWithin_zero_apply, comp_apply, + simp only [iteratedFDerivWithin_zero_apply, comp_apply, ContinuousMultilinearMap.compContinuousLinearMap_apply] · ext1 m simp only [ContinuousMultilinearMap.compContinuousLinearMap_apply, @@ -432,7 +432,7 @@ theorem ContinuousLinearEquiv.contDiffWithinAt_comp_iff (e : G ≃L[𝕜] E) : ContDiffWithinAt 𝕜 n (f ∘ e) (e ⁻¹' s) (e.symm x) ↔ ContDiffWithinAt 𝕜 n f s x := by constructor · intro H - simpa [← preimage_comp, (· ∘ ·)] using H.comp_continuousLinearMap (e.symm : E →L[𝕜] G) + simpa [← preimage_comp, Function.comp_def] using H.comp_continuousLinearMap (e.symm : E →L[𝕜] G) · intro H rw [← e.apply_symm_apply x, ← e.coe_coe] at H exact H.comp_continuousLinearMap _ @@ -448,8 +448,8 @@ theorem ContinuousLinearEquiv.contDiffAt_comp_iff (e : G ≃L[𝕜] E) : domains. -/ theorem ContinuousLinearEquiv.contDiffOn_comp_iff (e : G ≃L[𝕜] E) : ContDiffOn 𝕜 n (f ∘ e) (e ⁻¹' s) ↔ ContDiffOn 𝕜 n f s := - ⟨fun H => by simpa [(· ∘ ·)] using H.comp_continuousLinearMap (e.symm : E →L[𝕜] G), fun H => - H.comp_continuousLinearMap (e : G →L[𝕜] E)⟩ + ⟨fun H => by simpa [Function.comp_def] using H.comp_continuousLinearMap (e.symm : E →L[𝕜] G), + fun H => H.comp_continuousLinearMap (e : G →L[𝕜] E)⟩ /-- Composition by continuous linear equivs on the right respects higher differentiability. -/ theorem ContinuousLinearEquiv.contDiff_comp_iff (e : G ≃L[𝕜] E) : @@ -781,15 +781,20 @@ theorem ContDiff.comp₃ {g : E₁ × E₂ × E₃ → G} {f₁ : F → E₁} {f ContDiff 𝕜 n fun x => g (f₁ x, f₂ x, f₃ x) := hg.comp₂ hf₁ <| hf₂.prod hf₃ -theorem ContDiff.comp_contDiff_on₂ {g : E₁ × E₂ → G} {f₁ : F → E₁} {f₂ : F → E₂} {s : Set F} +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₂ + +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₃ + end NAry @@ -802,7 +807,7 @@ 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 ContDiff.clm_apply {f : E → F →L[𝕜] G} {g : E → F} {n : ℕ∞} (hf : ContDiff 𝕜 n f) (hg : ContDiff 𝕜 n g) : ContDiff 𝕜 n fun x => (f x) (g x) := @@ -810,7 +815,7 @@ theorem ContDiff.clm_apply {f : E → F →L[𝕜] G} {g : E → F} {n : ℕ∞} theorem ContDiffOn.clm_apply {f : E → F →L[𝕜] G} {g : E → F} {n : ℕ∞} (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 -- 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. @@ -882,7 +887,7 @@ then there is a function `f' : E → F →L[𝕜] G` that is `C^n` at `x₀` wit sufficiently close to `x₀` within `s ∪ {x₀}` the function `y ↦ f x y` has derivative `f' x` at `g x` within `t ⊆ F`. For convenience, we return an explicit set of `x`'s where this holds that is a subset of `s ∪ {x₀}`. We need one additional condition, namely that `t` is a neighborhood of -`g(x₀)` within `g '' s`. -/ +`g(x₀)` within `g '' s`. -/ theorem ContDiffWithinAt.hasFDerivWithinAt_nhds {f : E → F → G} {g : E → F} {t : Set F} {n : ℕ} {x₀ : E} (hf : ContDiffWithinAt 𝕜 (n + 1) (uncurry f) (insert x₀ s ×ˢ t) (x₀, g x₀)) (hg : ContDiffWithinAt 𝕜 n g s x₀) (hgt : t ∈ 𝓝[g '' s] g x₀) : @@ -892,7 +897,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 => @@ -982,7 +987,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 : ℕ∞} @@ -1042,7 +1048,7 @@ continuous. -/ theorem ContDiffOn.continuousOn_fderivWithin_apply (hf : ContDiffOn 𝕜 n f s) (hs : UniqueDiffOn 𝕜 s) (hn : 1 ≤ n) : ContinuousOn (fun p : E × E => (fderivWithin 𝕜 f s p.1 : E → F) p.2) (s ×ˢ univ) := - (contDiffOn_fderivWithin_apply hf hs <| by rwa [zero_add]).continuousOn + (contDiffOn_fderivWithin_apply (m := 0) hf hs hn).continuousOn /-- The bundled derivative of a `C^{n+1}` function is `C^n`. -/ theorem ContDiff.contDiff_fderiv_apply {f : E → F} (hf : ContDiff 𝕜 n f) (hmn : m + 1 ≤ n) : @@ -1070,15 +1076,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' : @@ -1948,3 +1953,5 @@ theorem ContDiff.restrict_scalars (h : ContDiff 𝕜' n f) : ContDiff 𝕜 n f : contDiff_iff_contDiffAt.2 fun _ => h.contDiffAt.restrict_scalars _ end RestrictScalars + +set_option linter.style.longFile 2100 diff --git a/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean b/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean index 9d0be42f520d6..08ff13d596c47 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean @@ -50,7 +50,7 @@ theorem ContinuousLinearMap.norm_iteratedFDerivWithin_le_of_bilinear_aux {Du Eu original spaces, which explains why we assume in the lemma that all spaces live in the same universe. -/ induction' n with n IH generalizing Eu Fu Gu - · simp only [Nat.zero_eq, norm_iteratedFDerivWithin_zero, zero_add, Finset.range_one, + · simp only [norm_iteratedFDerivWithin_zero, zero_add, Finset.range_one, Finset.sum_singleton, Nat.choose_self, Nat.cast_one, one_mul, Nat.sub_zero, ← mul_assoc] apply B.le_opNorm₂ · have In : (n : ℕ∞) + 1 ≤ n.succ := by simp only [Nat.cast_succ, le_refl] @@ -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 c18cbf87b9e2d..8ab71d0fee09d 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 (𝕜) @@ -501,17 +222,20 @@ protected theorem ContDiffWithinAt.insert (h : ContDiffWithinAt 𝕜 n f s x) : /-- 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 : ℕ} : @@ -602,7 +326,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) : @@ -626,7 +350,7 @@ protected theorem ContDiffWithinAt.eventually {n : ℕ} (h : ContDiffWithinAt ∀ᶠ 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 + (eventually_eventually_nhdsWithin.2 hu).and hu refine this.mono fun y hy => (hd y hy.2).mono_of_mem ?_ exact nhdsWithin_mono y (subset_insert _ _) hy.1 @@ -701,214 +425,9 @@ 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 n ihn - · exact h.mono fun y hy => DFunLike.ext _ _ fun _ => hy - · have : fderivWithin 𝕜 _ t =ᶠ[𝓝[s] x] fderivWithin 𝕜 _ t := ihn.fderivWithin' ht - apply this.mono - intro 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 with n ihn generalizing x - · rfl - · 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 => ?_⟩ - intro x hx m hm + refine ⟨fun H => H.continuousOn, fun H => fun x hx m hm ↦ ?_⟩ have : (m : ℕ∞) = 0 := le_antisymm hm bot_le rw [this] refine ⟨insert x s, self_mem_nhdsWithin, ftaylorSeriesWithin 𝕜 f s, ?_⟩ @@ -929,36 +448,16 @@ 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 (ENat.add_one_le_of_lt hm) with ⟨u, hu, p, Hp⟩ + rcases (h x hx) m.succ (Order.add_one_le_of_lt hm) with ⟨u, hu, p, Hp⟩ rw [insert_eq_of_mem hx] at hu rcases mem_nhdsWithin.1 hu with ⟨o, o_open, xo, ho⟩ rw [inter_comm] at ho @@ -1002,7 +501,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 @@ -1027,7 +526,7 @@ theorem ContDiffOn.differentiableOn_iteratedFDerivWithin {m : ℕ} (h : ContDiff theorem ContDiffWithinAt.differentiableWithinAt_iteratedFDerivWithin {m : ℕ} (h : ContDiffWithinAt 𝕜 n f s x) (hmn : (m : ℕ∞) < n) (hs : UniqueDiffOn 𝕜 (insert x s)) : DifferentiableWithinAt 𝕜 (iteratedFDerivWithin 𝕜 m f s) s x := by - rcases h.contDiffOn' (ENat.add_one_le_of_lt hmn) with ⟨u, uo, xu, hu⟩ + rcases h.contDiffOn' (Order.add_one_le_of_lt hmn) with ⟨u, uo, xu, hu⟩ set t := insert x s ∩ u have A : t =ᶠ[𝓝[≠] x] s := by simp only [set_eventuallyEq_iff_inf_principal, ← nhdsWithin_inter'] @@ -1139,99 +638,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 (𝕜) @@ -1392,147 +798,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 n IH - · rw [iteratedFDeriv_zero_eq_comp] - exact closure_minimal ((support_comp_subset (LinearIsometryEquiv.map_zero _) _).trans - subset_closure) isClosed_closure - · 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 n IH - · ext x; simp - · 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 n IH - · intro x _ - ext1 - simp only [Nat.zero_eq, iteratedFDerivWithin_zero_apply, iteratedFDeriv_zero_apply] - · 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 : 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..5b3ed3d9a9e4f 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean @@ -24,7 +24,7 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {D : Type uD} [NormedAddC section FiniteDimensional -open Function FiniteDimensional +open Function Module variable [CompleteSpace 𝕜] diff --git a/Mathlib/Analysis/Calculus/ContDiff/RCLike.lean b/Mathlib/Analysis/Calculus/ContDiff/RCLike.lean index 134a423eaeca7..d9f341edf671a 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/RCLike.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/RCLike.lean @@ -89,7 +89,7 @@ theorem HasFTaylorSeriesUpToOn.exists_lipschitzOnWith_of_nnnorm_lt {E F : Type*} replace hK : ‖f' x‖₊ < K := by simpa only [f', LinearIsometryEquiv.nnnorm_map] exact hs.exists_nhdsWithin_lipschitzOnWith_of_hasFDerivWithinAt_of_nnnorm_lt - (eventually_nhdsWithin_iff.2 <| eventually_of_forall hder) hcont K hK + (eventually_nhdsWithin_iff.2 <| Eventually.of_forall hder) hcont K hK /-- If `f` has a formal Taylor series `p` up to order `1` on `{x} ∪ s`, where `s` is a convex set, then `f` is Lipschitz in a neighborhood of `x` within `s`. -/ 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 bc4c7216fb90a..169722bc11409 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Add.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Add.lean @@ -23,9 +23,9 @@ derivative universe u v w open scoped Classical -open Topology Filter ENNReal +open scoped Topology Filter ENNReal -open Filter Asymptotics Set +open Asymptotics Set variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] variable {F : Type v} [NormedAddCommGroup F] [NormedSpace 𝕜 F] @@ -120,6 +120,26 @@ theorem deriv_const_add (c : F) : deriv (fun y => c + f y) x = deriv f x := by theorem deriv_const_add' (c : F) : (deriv fun y => c + f y) = deriv f := funext fun _ => deriv_const_add c +lemma differentiableAt_comp_const_add {a b : 𝕜} : + DifferentiableAt 𝕜 (fun x ↦ f (b + x)) a ↔ DifferentiableAt 𝕜 f (b + a) := by + refine ⟨fun H ↦ ?_, fun H ↦ H.comp _ (differentiable_id.const_add _).differentiableAt⟩ + convert DifferentiableAt.comp (b + a) (by simpa) + (differentiable_id.const_add (-b)).differentiableAt + ext + simp + +lemma differentiableAt_comp_add_const {a b : 𝕜} : + DifferentiableAt 𝕜 (fun x ↦ f (x + b)) a ↔ DifferentiableAt 𝕜 f (a + b) := by + simpa [add_comm b] using differentiableAt_comp_const_add (f := f) (b := b) + +lemma differentiableAt_iff_comp_const_add {a b : 𝕜} : + DifferentiableAt 𝕜 f a ↔ DifferentiableAt 𝕜 (fun x ↦ f (b + x)) (-b + a) := by + simp [differentiableAt_comp_const_add] + +lemma differentiableAt_iff_comp_add_const {a b : 𝕜} : + DifferentiableAt 𝕜 f a ↔ DifferentiableAt 𝕜 (fun x ↦ f (x + b)) (a - b) := by + simp [differentiableAt_comp_add_const] + end Add section Sum @@ -227,23 +247,17 @@ 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_iff {a : 𝕜} : - DifferentiableAt 𝕜 f (-a) ↔ DifferentiableAt 𝕜 (fun x ↦ f (-x)) a := by - refine ⟨fun H ↦ H.comp a differentiable_neg.differentiableAt, fun H ↦ ?_⟩ +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⟩ convert ((neg_neg a).symm ▸ H).comp (-a) differentiable_neg.differentiableAt ext simp only [Function.comp_apply, neg_neg] +lemma differentiableAt_iff_comp_neg {a : 𝕜} : + DifferentiableAt 𝕜 f a ↔ DifferentiableAt 𝕜 (fun x ↦ f (-x)) (-a) := by + simp_rw [← differentiableAt_comp_neg, neg_neg] + end Neg2 section Sub @@ -319,4 +333,24 @@ theorem deriv_const_sub (c : F) : deriv (fun y => c - f y) x = -deriv f x := by simp only [← derivWithin_univ, derivWithin_const_sub (uniqueDiffWithinAt_univ : UniqueDiffWithinAt 𝕜 _ _)] +lemma differentiableAt_comp_sub_const {a b : 𝕜} : + DifferentiableAt 𝕜 (fun x ↦ f (x - b)) a ↔ DifferentiableAt 𝕜 f (a - b) := by + simp [sub_eq_add_neg, differentiableAt_comp_add_const] + +lemma differentiableAt_comp_const_sub {a b : 𝕜} : + DifferentiableAt 𝕜 (fun x ↦ f (b - x)) a ↔ DifferentiableAt 𝕜 f (b - a) := by + refine ⟨fun H ↦ ?_, fun H ↦ H.comp a (differentiable_id.const_sub _).differentiableAt⟩ + convert ((sub_sub_cancel _ a).symm ▸ H).comp (b - a) + (differentiable_id.const_sub _).differentiableAt + ext + simp + +lemma differentiableAt_iff_comp_sub_const {a b : 𝕜} : + DifferentiableAt 𝕜 f a ↔ DifferentiableAt 𝕜 (fun x ↦ f (x - b)) (a + b) := by + simp [sub_eq_add_neg, differentiableAt_comp_add_const] + +lemma differentiableAt_iff_comp_const_sub {a b : 𝕜} : + DifferentiableAt 𝕜 f a ↔ DifferentiableAt 𝕜 (fun x ↦ f (b - x)) (b - a) := by + simp [differentiableAt_comp_const_sub] + end Sub diff --git a/Mathlib/Analysis/Calculus/Deriv/Basic.lean b/Mathlib/Analysis/Calculus/Deriv/Basic.lean index edda887e12373..5ed888191d0e0 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Basic.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Basic.lean @@ -416,7 +416,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 1dca57b89bb78..bb0e4bdc37b52 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Comp.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Comp.lean @@ -34,8 +34,7 @@ derivative, chain rule universe u v w -open scoped Classical -open Topology Filter ENNReal +open scoped Classical Topology Filter ENNReal open Filter Asymptotics Set @@ -81,7 +80,7 @@ theorem HasDerivAtFilter.scomp_of_eq (hg : HasDerivAtFilter g₁ g₁' y L') theorem HasDerivWithinAt.scomp_hasDerivAt (hg : HasDerivWithinAt g₁ g₁' s' (h x)) (hh : HasDerivAt h h' x) (hs : ∀ x, h x ∈ s') : HasDerivAt (g₁ ∘ h) (h' • g₁') x := - hg.scomp x hh <| tendsto_inf.2 ⟨hh.continuousAt, tendsto_principal.2 <| eventually_of_forall hs⟩ + hg.scomp x hh <| tendsto_inf.2 ⟨hh.continuousAt, tendsto_principal.2 <| Eventually.of_forall hs⟩ theorem HasDerivWithinAt.scomp_hasDerivAt_of_eq (hg : HasDerivWithinAt g₁ g₁' s' y) (hh : HasDerivAt h h' x) (hs : ∀ x, h x ∈ s') (hy : y = h x) : diff --git a/Mathlib/Analysis/Calculus/Deriv/Inv.lean b/Mathlib/Analysis/Calculus/Deriv/Inv.lean index 0fda49102f336..8687b3af9373d 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Inv.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Inv.lean @@ -23,9 +23,7 @@ derivative universe u v w -open scoped Classical -open Topology Filter ENNReal - +open scoped Classical Topology ENNReal open Filter Asymptotics Set open ContinuousLinearMap (smulRight smulRight_one_eq_iff) @@ -47,7 +45,7 @@ theorem hasStrictDerivAt_inv (hx : x ≠ 0) : HasStrictDerivAt Inv.inv (-(x ^ 2) suffices (fun p : 𝕜 × 𝕜 => (p.1 - p.2) * ((x * x)⁻¹ - (p.1 * p.2)⁻¹)) =o[𝓝 (x, x)] fun p => (p.1 - p.2) * 1 by - refine this.congr' ?_ (eventually_of_forall fun _ => mul_one _) + refine this.congr' ?_ (Eventually.of_forall fun _ => mul_one _) refine Eventually.mono ((isOpen_ne.prod isOpen_ne).mem_nhds ⟨hx, hx⟩) ?_ rintro ⟨y, z⟩ ⟨hy, hz⟩ simp only [mem_setOf_eq] at hy hz @@ -65,20 +63,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] @@ -87,13 +78,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 @@ -103,7 +98,7 @@ 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} @@ -118,22 +113,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 d2524c850858d..424877d8f983b 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Inverse.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Inverse.lean @@ -24,9 +24,7 @@ derivative, inverse function universe u v w -open scoped Classical -open Topology Filter ENNReal - +open scoped Classical Topology ENNReal open Filter Asymptotics Set variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] diff --git a/Mathlib/Analysis/Calculus/Deriv/Mul.lean b/Mathlib/Analysis/Calculus/Deriv/Mul.lean index 64628ceb448d0..8577c4b84784c 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Mul.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Mul.lean @@ -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] @@ -324,22 +323,26 @@ end HasDeriv variable {ι : Type*} {𝔸' : Type*} [NormedCommRing 𝔸'] [NormedAlgebra 𝕜 𝔸'] {u : Finset ι} {f : ι → 𝕜 → 𝔸'} {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) @@ -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/Shift.lean b/Mathlib/Analysis/Calculus/Deriv/Shift.lean index 777f322714c8b..45f45b6335f23 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Shift.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Shift.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2023 Michael Stoll. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Michael Stoll +Authors: Michael Stoll, Yaël Dillies -/ import Mathlib.Analysis.Calculus.Deriv.Add import Mathlib.Analysis.Calculus.Deriv.Comp @@ -9,40 +9,55 @@ import Mathlib.Analysis.Calculus.Deriv.Comp /-! ### Invariance of the derivative under translation -We show that if a function `h` has derivative `h'` at a point `a + x`, then `h (a + ·)` -has derivative `h'` at `x`. Similarly for `x + a`. +We show that if a function `f` has derivative `f'` at a point `a + x`, then `f (a + ·)` +has derivative `f'` at `x`. Similarly for `x + a`. -/ +variable {𝕜 F : Type*} [NontriviallyNormedField 𝕜] [NormedAddCommGroup F] [NormedSpace 𝕜 F] + {f : 𝕜 → F} {f' : F} + +/-- Translation in the domain does not change the derivative. -/ +lemma HasDerivAt.comp_const_add (a x : 𝕜) (hf : HasDerivAt f f' (a + x)) : + HasDerivAt (fun x ↦ f (a + x)) f' x := by + simpa [Function.comp_def] using HasDerivAt.scomp (𝕜 := 𝕜) x hf <| hasDerivAt_id' x |>.const_add a + +/-- Translation in the domain does not change the derivative. -/ +lemma HasDerivAt.comp_add_const (x a : 𝕜) (hf : HasDerivAt f f' (x + a)) : + HasDerivAt (fun x ↦ f (x + a)) f' x := by + simpa [Function.comp_def] using HasDerivAt.scomp (𝕜 := 𝕜) x hf <| hasDerivAt_id' x |>.add_const a + /-- Translation in the domain does not change the derivative. -/ -lemma HasDerivAt.comp_const_add {𝕜 : Type*} [NontriviallyNormedField 𝕜] (a x : 𝕜) {𝕜' : Type*} - [NormedAddCommGroup 𝕜'] [NormedSpace 𝕜 𝕜'] {h : 𝕜 → 𝕜'} {h' : 𝕜'} - (hh : HasDerivAt h h' (a + x)) : - HasDerivAt (fun x ↦ h (a + x)) h' x := by - simpa [Function.comp_def] using HasDerivAt.scomp (𝕜 := 𝕜) x hh <| hasDerivAt_id' x |>.const_add a +lemma HasDerivAt.comp_const_sub (a x : 𝕜) (hf : HasDerivAt f f' (a - x)) : + HasDerivAt (fun x ↦ f (a - x)) (-f') x := by + simpa [Function.comp_def] using HasDerivAt.scomp (𝕜 := 𝕜) x hf <| hasDerivAt_id' x |>.const_sub a /-- Translation in the domain does not change the derivative. -/ -lemma HasDerivAt.comp_add_const {𝕜 : Type*} [NontriviallyNormedField 𝕜] (x a : 𝕜) {𝕜' : Type*} - [NormedAddCommGroup 𝕜'] [NormedSpace 𝕜 𝕜'] {h : 𝕜 → 𝕜'} {h' : 𝕜'} - (hh : HasDerivAt h h' (x + a)) : - HasDerivAt (fun x ↦ h (x + a)) h' x := by - simpa [Function.comp_def] using HasDerivAt.scomp (𝕜 := 𝕜) x hh <| hasDerivAt_id' x |>.add_const a +lemma HasDerivAt.comp_sub_const (x a : 𝕜) (hf : HasDerivAt f f' (x - a)) : + HasDerivAt (fun x ↦ f (x - a)) f' x := by + simpa [Function.comp_def] using HasDerivAt.scomp (𝕜 := 𝕜) x hf <| hasDerivAt_id' x |>.sub_const a + +variable (f) (a x : 𝕜) /-- The derivative of `x ↦ f (-x)` at `a` is the negative of the derivative of `f` at `-a`. -/ -lemma deriv_comp_neg {𝕜 : Type*} [NontriviallyNormedField 𝕜] {F : Type*} [NormedAddCommGroup F] - [NormedSpace 𝕜 F] (f : 𝕜 → F) (a : 𝕜) : deriv (fun x ↦ f (-x)) a = -deriv f (-a) := by - by_cases h : DifferentiableAt 𝕜 f (-a) - · simpa only [deriv_neg, neg_one_smul] using deriv.scomp a h (differentiable_neg _) - · rw [deriv_zero_of_not_differentiableAt (mt differentiableAt_comp_neg_iff.mpr h), - deriv_zero_of_not_differentiableAt h, neg_zero] +lemma deriv_comp_neg : deriv (fun x ↦ f (-x)) x = -deriv f (-x) := by + by_cases f : DifferentiableAt 𝕜 f (-x) + · simpa only [deriv_neg, neg_one_smul] using deriv.scomp _ f (differentiable_neg _) + · rw [deriv_zero_of_not_differentiableAt (differentiableAt_comp_neg.not.2 f), + deriv_zero_of_not_differentiableAt f, neg_zero] /-- Translation in the domain does not change the derivative. -/ -lemma deriv_comp_const_add {𝕜 : Type*} [NontriviallyNormedField 𝕜] (a x : 𝕜) {𝕜' : Type*} - [NormedAddCommGroup 𝕜'] [NormedSpace 𝕜 𝕜'] {h : 𝕜 → 𝕜'} - (hh : DifferentiableAt 𝕜 h (a + x)) : - deriv (fun x ↦ h (a + x)) x = deriv h (a + x) := HasDerivAt.deriv hh.hasDerivAt.comp_const_add +lemma deriv_comp_const_add : deriv (fun x ↦ f (a + x)) x = deriv f (a + x) := by + by_cases hf : DifferentiableAt 𝕜 f (a + x) + · exact HasDerivAt.deriv hf.hasDerivAt.comp_const_add + · rw [deriv_zero_of_not_differentiableAt (differentiableAt_comp_const_add.not.2 hf), + deriv_zero_of_not_differentiableAt hf] /-- Translation in the domain does not change the derivative. -/ -lemma deriv_comp_add_const {𝕜 : Type*} [NontriviallyNormedField 𝕜] (a x : 𝕜) {𝕜' : Type*} - [NormedAddCommGroup 𝕜'] [NormedSpace 𝕜 𝕜'] {h : 𝕜 → 𝕜'} - (hh : DifferentiableAt 𝕜 h (x + a)) : - deriv (fun x ↦ h (x + a)) x = deriv h (x + a) := HasDerivAt.deriv hh.hasDerivAt.comp_add_const +lemma deriv_comp_add_const : deriv (fun x ↦ f (x + a)) x = deriv f (x + a) := by + simpa [add_comm] using deriv_comp_const_add f a x + +lemma deriv_comp_const_sub : deriv (fun x ↦ f (a - x)) x = -deriv f (a - x) := by + simp_rw [sub_eq_add_neg, deriv_comp_neg (f <| a + ·), deriv_comp_const_add] + +lemma deriv_comp_sub_const : deriv (fun x ↦ f (x - a)) x = deriv f (x - a) := by + simp_rw [sub_eq_add_neg, deriv_comp_add_const] diff --git a/Mathlib/Analysis/Calculus/Deriv/Slope.lean b/Mathlib/Analysis/Calculus/Deriv/Slope.lean index 3b9f51dde30cf..6ffd40c200519 100644 --- a/Mathlib/Analysis/Calculus/Deriv/Slope.lean +++ b/Mathlib/Analysis/Calculus/Deriv/Slope.lean @@ -76,7 +76,7 @@ theorem hasDerivAt_iff_tendsto_slope_zero : HasDerivAt f f' x ↔ Tendsto (fun t ↦ t⁻¹ • (f (x + t) - f x)) (𝓝[≠] 0) (𝓝 f') := by have : 𝓝[≠] x = Filter.map (fun t ↦ x + t) (𝓝[≠] 0) := by simp [nhdsWithin, map_add_left_nhds_zero x, Filter.map_inf, add_right_injective x] - simp [hasDerivAt_iff_tendsto_slope, this, slope, Function.comp] + simp [hasDerivAt_iff_tendsto_slope, this, slope, Function.comp_def] alias ⟨HasDerivAt.tendsto_slope_zero, _⟩ := hasDerivAt_iff_tendsto_slope_zero diff --git a/Mathlib/Analysis/Calculus/Deriv/ZPow.lean b/Mathlib/Analysis/Calculus/Deriv/ZPow.lean index 29c9091921c56..73cd119155a71 100644 --- a/Mathlib/Analysis/Calculus/Deriv/ZPow.lean +++ b/Mathlib/Analysis/Calculus/Deriv/ZPow.lean @@ -46,7 +46,7 @@ theorem hasStrictDerivAt_zpow (m : ℤ) (x : 𝕜) (h : x ≠ 0 ∨ 0 ≤ m) : · have hx : x ≠ 0 := h.resolve_right hm.not_le have := (hasStrictDerivAt_inv ?_).scomp _ (this (-m) (neg_pos.2 hm)) <;> [skip; exact zpow_ne_zero _ hx] - simp only [(· ∘ ·), zpow_neg, one_div, inv_inv, smul_eq_mul] at this + simp only [Function.comp_def, zpow_neg, one_div, inv_inv, smul_eq_mul] at this convert this using 1 rw [sq, mul_inv, inv_inv, Int.cast_neg, neg_mul, neg_mul_neg, ← zpow_add₀ hx, mul_assoc, ← zpow_add₀ hx] @@ -96,7 +96,7 @@ theorem iter_deriv_zpow' (m : ℤ) (k : ℕ) : (deriv^[k] fun x : 𝕜 => x ^ m) = fun x => (∏ i ∈ Finset.range k, ((m : 𝕜) - i)) * x ^ (m - k) := by induction' k with k ihk - · simp only [Nat.zero_eq, one_mul, Int.ofNat_zero, id, sub_zero, Finset.prod_range_zero, + · simp only [one_mul, Int.ofNat_zero, id, sub_zero, Finset.prod_range_zero, Function.iterate_zero] · simp only [Function.iterate_succ_apply', ihk, deriv_const_mul_field', deriv_zpow', Finset.prod_range_succ, Int.ofNat_succ, ← sub_sub, Int.cast_sub, Int.cast_natCast, mul_assoc] 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/Analytic.lean b/Mathlib/Analysis/Calculus/FDeriv/Analytic.lean index 8b829d21486fe..80735fc0538cf 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,31 +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 - induction' n with n IH - · rw [iteratedFDeriv_zero_eq_comp] - exact ((continuousMultilinearCurryFin0 𝕜 E F).symm : F →L[𝕜] E[×0]→L[𝕜] F).comp_analyticOn h - · rw [iteratedFDeriv_succ_eq_comp_left] +/-- 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_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 @@ -120,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.embedding.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 @@ -144,16 +444,28 @@ 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 - induction' n with n IH - · exact h - · simpa only [Function.iterate_succ', Function.comp_apply] using IH.deriv +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 @@ -221,12 +533,14 @@ theorem CPolynomialOn.fderiv (h : CPolynomialOn 𝕜 f s) : /-- If a function is polynomial on a set `s`, so are its successive Fréchet derivative. -/ theorem CPolynomialOn.iteratedFDeriv (h : CPolynomialOn 𝕜 f s) (n : ℕ) : CPolynomialOn 𝕜 (iteratedFDeriv 𝕜 n f) s := by - induction' n with n IH - · rw [iteratedFDeriv_zero_eq_comp] + induction n with + | zero => + rw [iteratedFDeriv_zero_eq_comp] exact ((continuousMultilinearCurryFin0 𝕜 E F).symm : F →L[𝕜] E[×0]→L[𝕜] F).comp_cPolynomialOn h - · rw [iteratedFDeriv_succ_eq_comp_left] + | 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. -/ @@ -239,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 : ℕ∞} : @@ -261,9 +575,9 @@ protected theorem CPolynomialOn.deriv (h : CPolynomialOn 𝕜 f s) : CPolynomial /-- If a function is polynomial on a set `s`, so are its successive derivatives. -/ theorem CPolynomialOn.iterated_deriv (h : CPolynomialOn 𝕜 f s) (n : ℕ) : CPolynomialOn 𝕜 (deriv^[n] f) s := by - induction' n with n IH - · exact h - · simpa only [Function.iterate_succ', Function.comp_apply] using IH.deriv + induction n with + | zero => exact h + | succ n IH => simpa only [Function.iterate_succ', Function.comp_apply] using IH.deriv end deriv @@ -274,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 @@ -309,7 +616,7 @@ 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] @@ -329,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 ι] @@ -459,7 +790,7 @@ private theorem factorial_smul' {n : ℕ} : ∀ {F : Type max u v} [NormedAddCom [NormedSpace 𝕜 F] [CompleteSpace F] {p : FormalMultilinearSeries 𝕜 E F} {f : E → F}, HasFPowerSeriesOnBall f p x r → n ! • p n (fun _ ↦ y) = iteratedFDeriv 𝕜 n f x (fun _ ↦ y) := by - induction' n with n ih <;> intro F _ _ _ p f h + induction n with | zero => _ | succ n ih => _ <;> intro F _ _ _ p f h · rw [factorial_zero, one_smul, h.iteratedFDeriv_zero_apply_diag] · rw [factorial_succ, mul_comm, mul_smul, ← derivSeries_apply_diag, ← smul_apply, ih h.fderiv, iteratedFDeriv_succ_apply_right] @@ -483,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 031c14bda50c7..88e55627bf87e 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Basic.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Basic.lean @@ -306,7 +306,7 @@ theorem hasFDerivAt_iff_tendsto : theorem hasFDerivAt_iff_isLittleO_nhds_zero : HasFDerivAt f f' x ↔ (fun h : E => f (x + h) - f x - f' h) =o[𝓝 0] fun h => h := by rw [HasFDerivAt, hasFDerivAtFilter_iff_isLittleO, ← map_add_left_nhds_zero x, isLittleO_map] - simp [(· ∘ ·)] + simp [Function.comp_def] /-- Converse to the mean value inequality: if `f` is differentiable at `x₀` and `C`-lipschitz on a neighborhood of `x₀` then its derivative at `x₀` has norm bounded by `C`. This version @@ -732,7 +732,7 @@ theorem HasStrictFDerivAt.isBigO_sub_rev {f' : E ≃L[𝕜] F} theorem HasFDerivAtFilter.isBigO_sub_rev (hf : HasFDerivAtFilter f f' x L) {C} (hf' : AntilipschitzWith C f') : (fun x' => x' - x) =O[L] fun x' => f x' - f x := have : (fun x' => x' - x) =O[L] fun x' => f' (x' - x) := - isBigO_iff.2 ⟨C, eventually_of_forall fun _ => ZeroHomClass.bound_of_antilipschitz f' hf' _⟩ + isBigO_iff.2 ⟨C, Eventually.of_forall fun _ => ZeroHomClass.bound_of_antilipschitz f' hf' _⟩ (this.trans (hf.isLittleO.trans_isBigO this).right_isBigO_add).congr (fun _ => rfl) fun _ => sub_add_cancel _ _ @@ -895,7 +895,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 9505419593904..b5afecc0aa536 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Bilinear.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Bilinear.lean @@ -69,7 +69,7 @@ theorem IsBoundedBilinearMap.hasStrictFDerivAt (h : IsBoundedBilinearMap 𝕜 b) refine (isBigO_refl _ _).mul_isLittleO ((isLittleO_one_iff _).2 ?_) -- TODO: `continuity` fails exact (continuous_snd.fst.prod_mk continuous_fst.snd).norm.tendsto' _ _ (by simp) - _ = _ := by simp [(· ∘ ·)] + _ = _ := by simp [Function.comp_def] @[fun_prop] theorem IsBoundedBilinearMap.hasFDerivAt (h : IsBoundedBilinearMap 𝕜 b) (p : E × F) : diff --git a/Mathlib/Analysis/Calculus/FDeriv/Comp.lean b/Mathlib/Analysis/Calculus/FDeriv/Comp.lean index 3a29e467e58b6..410d6d1cf3e69 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Comp.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Comp.lean @@ -67,7 +67,7 @@ example {g : F → G} {g' : F →L[𝕜] G} (hg : HasFDerivAtFilter g g' (f x) ( refine .of_isLittleO <| this.triangle ?_ calc (fun x' : E => g' (f x' - f x) - g'.comp f' (x' - x)) - _ =ᶠ[L] fun x' => g' (f x' - f x - f' (x' - x)) := eventually_of_forall fun x' => by simp + _ =ᶠ[L] fun x' => g' (f x' - f x - f' (x' - x)) := Eventually.of_forall fun x' => by simp _ =O[L] fun x' => f x' - f x - f' (x' - x) := g'.isBigO_comp _ _ _ =o[L] fun x' => x' - x := hf.isLittleO @@ -172,7 +172,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 @@ -191,9 +191,10 @@ variable {x} protected theorem HasFDerivAtFilter.iterate {f : E → E} {f' : E →L[𝕜] E} (hf : HasFDerivAtFilter f f' x L) (hL : Tendsto f L L) (hx : f x = x) (n : ℕ) : HasFDerivAtFilter f^[n] (f' ^ n) x L := by - induction' n with n ihn - · exact hasFDerivAtFilter_id x L - · rw [Function.iterate_succ, pow_succ] + induction n with + | zero => exact hasFDerivAtFilter_id x L + | succ n ihn => + rw [Function.iterate_succ, pow_succ] rw [← hx] at ihn exact ihn.comp x hf hL @@ -218,9 +219,10 @@ protected theorem HasFDerivWithinAt.iterate {f : E → E} {f' : E →L[𝕜] E} protected theorem HasStrictFDerivAt.iterate {f : E → E} {f' : E →L[𝕜] E} (hf : HasStrictFDerivAt f f' x) (hx : f x = x) (n : ℕ) : HasStrictFDerivAt f^[n] (f' ^ n) x := by - induction' n with n ihn - · exact hasStrictFDerivAt_id x - · rw [Function.iterate_succ, pow_succ] + induction n with + | zero => exact hasStrictFDerivAt_id x + | succ n ihn => + rw [Function.iterate_succ, pow_succ] rw [← hx] at ihn exact ihn.comp x hf diff --git a/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean b/Mathlib/Analysis/Calculus/FDeriv/Equiv.lean index d05eb97118ca7..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 => @@ -349,13 +349,13 @@ theorem HasStrictFDerivAt.of_local_left_inverse {f : E → F} {f' : E ≃L[𝕜] refine this.trans_isLittleO ?_ clear this refine ((hf.comp_tendsto hg).symm.congr' - (hfg.mono ?_) (eventually_of_forall fun _ => rfl)).trans_isBigO ?_ + (hfg.mono ?_) (Eventually.of_forall fun _ => rfl)).trans_isBigO ?_ · rintro p ⟨hp1, hp2⟩ simp [hp1, hp2] - · refine (hf.isBigO_sub_rev.comp_tendsto hg).congr' (eventually_of_forall fun _ => rfl) + · 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`. @@ -375,7 +375,7 @@ theorem HasFDerivAt.of_local_left_inverse {f : E → F} {f' : E ≃L[𝕜] F} {g · intro p hp simp [hp, hfg.self_of_nhds] · refine ((hf.isBigO_sub_rev f'.antilipschitz).comp_tendsto hg).congr' - (eventually_of_forall fun _ => rfl) (hfg.mono ?_) + (Eventually.of_forall fun _ => rfl) (hfg.mono ?_) rintro p hp simp only [(· ∘ ·), hp, hfg.self_of_nhds] @@ -404,7 +404,7 @@ theorem HasFDerivWithinAt.eventually_ne (h : HasFDerivWithinAt f f' s x) (hf' : ∃ C, ∀ z, ‖z‖ ≤ C * ‖f' z‖) : ∀ᶠ z in 𝓝[s \ {x}] x, f z ≠ f x := by rw [nhdsWithin, diff_eq, ← inf_principal, ← inf_assoc, eventually_inf_principal] have A : (fun z => z - x) =O[𝓝[s] x] fun z => f' (z - x) := - isBigO_iff.2 <| hf'.imp fun C hC => eventually_of_forall fun z => hC _ + isBigO_iff.2 <| hf'.imp fun C hC => Eventually.of_forall fun z => hC _ have : (fun z => f z - f x) ~[𝓝[s] x] fun z => f' (z - x) := h.isLittleO.trans_isBigO A simpa [not_imp_not, sub_eq_zero] using (A.trans this.isBigO_symm).eq_zero_imp diff --git a/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean b/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean index d201d59948dd7..28e1539f0e516 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Measurable.lean @@ -174,7 +174,7 @@ theorem norm_sub_le_of_mem_A {c : 𝕜} (hc : 1 < ‖c‖) {r ε : ℝ} (hε : 0 {L₁ L₂ : E →L[𝕜] F} (h₁ : x ∈ A f L₁ r ε) (h₂ : x ∈ A f L₂ r ε) : ‖L₁ - L₂‖ ≤ 4 * ‖c‖ * ε := by refine opNorm_le_of_shell (half_pos hr) (by positivity) hc ?_ intro y ley ylt - rw [div_div, div_le_iff' (mul_pos (by norm_num : (0 : ℝ) < 2) (zero_lt_one.trans hc))] at ley + rw [div_div, div_le_iff₀' (mul_pos (by norm_num : (0 : ℝ) < 2) (zero_lt_one.trans hc))] at ley calc ‖(L₁ - L₂) y‖ = ‖f (x + y) - f x - L₂ (x + y - x) - (f (x + y) - f x - L₁ (x + y - x))‖ := by simp @@ -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) @@ -638,7 +638,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 +661,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] diff --git a/Mathlib/Analysis/Calculus/FDeriv/Mul.lean b/Mathlib/Analysis/Calculus/FDeriv/Mul.lean index 9c79b4bf2279c..990bb02bd9599 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 /-! @@ -50,20 +52,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 +109,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 +241,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 +573,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 +596,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 +648,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 +663,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 +777,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 +810,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 +839,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 +892,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/Symmetric.lean b/Mathlib/Analysis/Calculus/FDeriv/Symmetric.lean index fa52f1fbe6370..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 @@ -167,10 +167,10 @@ theorem Convex.taylor_approx_two_segment {v w : E} (hv : x + v ∈ interior s) convert I using 1 · congr 1 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] + 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'] @@ -319,4 +304,4 @@ theorem second_derivative_symmetric_of_eventually {f : E → F} {f' : E → E derivative is symmetric. -/ theorem second_derivative_symmetric {f : E → F} {f' : E → E →L[ℝ] F} {f'' : E →L[ℝ] E →L[ℝ] F} (hf : ∀ y, HasFDerivAt f (f' y) y) (hx : HasFDerivAt f' f'' x) (v w : E) : f'' v w = f'' w v := - second_derivative_symmetric_of_eventually (Filter.eventually_of_forall hf) hx v w + second_derivative_symmetric_of_eventually (Filter.Eventually.of_forall hf) hx v w diff --git a/Mathlib/Analysis/Calculus/FormalMultilinearSeries.lean b/Mathlib/Analysis/Calculus/FormalMultilinearSeries.lean index a4e5c528314f8..06d42a093e031 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 [Nat.zero_eq, ContinuousMultilinearMap.curry0_apply] + · simp only [ContinuousMultilinearMap.uncurry0_apply] · simp only [constFormalMultilinearSeries.match_1.eq_2, ContinuousMultilinearMap.zero_apply] end Const @@ -349,12 +356,12 @@ 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 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 theorem fpowerSeries_apply_one (f : E →L[𝕜] F) (x : E) : diff --git a/Mathlib/Analysis/Calculus/Implicit.lean b/Mathlib/Analysis/Calculus/Implicit.lean index 72620c2d28d46..2e323d8872a82 100644 --- a/Mathlib/Analysis/Calculus/Implicit.lean +++ b/Mathlib/Analysis/Calculus/Implicit.lean @@ -326,12 +326,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 7994a8712c5d2..67b3db1e4cd80 100644 --- a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean +++ b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/ApproximatesLinearOn.lean @@ -144,7 +144,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 ε`. @@ -193,7 +193,7 @@ theorem surjOn_closedBall_of_nonlinearRightInverse have C : ∀ (n : ℕ) (w : E), dist w b ≤ f'symm.nnnorm * (1 - ((c : ℝ) * f'symm.nnnorm) ^ n) / (1 - c * f'symm.nnnorm) * dist (f b) y → w ∈ closedBall b ε := fun n w hw ↦ by apply hw.trans - rw [div_mul_eq_mul_div, div_le_iff]; swap; · linarith + rw [div_mul_eq_mul_div, div_le_iff₀]; swap; · linarith calc (f'symm.nnnorm : ℝ) * (1 - ((c : ℝ) * f'symm.nnnorm) ^ n) * dist (f b) y = f'symm.nnnorm * dist (f b) y * (1 - ((c : ℝ) * f'symm.nnnorm) ^ n) := by @@ -252,13 +252,13 @@ theorem surjOn_closedBall_of_nonlinearRightInverse obtain ⟨x, hx⟩ : ∃ x, Tendsto u atTop (𝓝 x) := cauchySeq_tendsto_of_complete this -- As all the `uₙ` belong to the ball `closedBall b ε`, so does their limit `x`. have xmem : x ∈ closedBall b ε := - isClosed_ball.mem_of_tendsto hx (eventually_of_forall fun n => C n _ (D n).2) + isClosed_ball.mem_of_tendsto hx (Eventually.of_forall fun n => C n _ (D n).2) refine ⟨x, xmem, ?_⟩ -- 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] - exact eventually_of_forall fun n => C n _ (D n).2 + 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' have T2 : Tendsto (f ∘ u) atTop (𝓝 y) := by diff --git a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/FDeriv.lean b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/FDeriv.lean index 82d6364c31eb6..43a83ae9b58a1 100644 --- a/Mathlib/Analysis/Calculus/InverseFunctionTheorem/FDeriv.lean +++ b/Mathlib/Analysis/Calculus/InverseFunctionTheorem/FDeriv.lean @@ -186,7 +186,7 @@ theorem to_localInverse (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) : and `g (f x) = x` in a neighborhood of `a`, then `g` has derivative `f'.symm` at `f a`. For a version assuming `f (g y) = y` and continuity of `g` at `f a` but not `[CompleteSpace E]` -see `of_local_left_inverse`. -/ +see `of_local_left_inverse`. -/ theorem to_local_left_inverse (hf : HasStrictFDerivAt f (f' : E →L[𝕜] F) a) {g : F → E} (hg : ∀ᶠ x in 𝓝 a, g (f x) = x) : HasStrictFDerivAt g (f'.symm : F →L[𝕜] E) (f a) := hf.to_localInverse.congr_of_eventuallyEq <| (hf.localInverse_unique hg).mono fun _ => Eq.symm diff --git a/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean b/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean index 32cf207826227..f5790c73a631f 100644 --- a/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean +++ b/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean @@ -82,7 +82,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 @@ -174,9 +174,10 @@ theorem iteratedDerivWithin_succ {x : 𝕜} (hxs : UniqueDiffWithinAt 𝕜 s x) iterating `n` times the differentiation operation. -/ theorem iteratedDerivWithin_eq_iterate {x : 𝕜} (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) : iteratedDerivWithin n f s x = (fun g : 𝕜 → F => derivWithin g s)^[n] f x := by - induction' n with n IH generalizing x - · simp - · rw [iteratedDerivWithin_succ (hs x hx), Function.iterate_succ'] + induction n generalizing x with + | zero => simp + | succ n IH => + rw [iteratedDerivWithin_succ (hs x hx), Function.iterate_succ'] exact derivWithin_congr (fun y hy => IH hy) (IH hx) /-- The `n+1`-th iterated derivative within a set with unique derivatives can be obtained by @@ -202,7 +203,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 f81f092709a46..9b8588e207bce 100644 --- a/Mathlib/Analysis/Calculus/IteratedDeriv/Lemmas.lean +++ b/Mathlib/Analysis/Calculus/IteratedDeriv/Lemmas.lean @@ -117,7 +117,7 @@ lemma iteratedDeriv_neg (n : ℕ) (f : 𝕜 → F) (a : 𝕜) : lemma iteratedDeriv_comp_neg (n : ℕ) (f : 𝕜 → F) (a : 𝕜) : iteratedDeriv n (fun x ↦ f (-x)) a = (-1 : 𝕜) ^ n • iteratedDeriv n f (-a) := by induction' n with n ih generalizing a - · simp only [Nat.zero_eq, iteratedDeriv_zero, pow_zero, one_smul] + · simp only [iteratedDeriv_zero, pow_zero, one_smul] · have ih' : iteratedDeriv n (fun x ↦ f (-x)) = fun x ↦ (-1 : 𝕜) ^ n • iteratedDeriv n f (-x) := funext ih rw [iteratedDeriv_succ, iteratedDeriv_succ, ih', pow_succ', neg_mul, one_mul, diff --git a/Mathlib/Analysis/Calculus/LHopital.lean b/Mathlib/Analysis/Calculus/LHopital.lean index 0e18fd06df1c3..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 @@ -364,12 +364,12 @@ theorem lhopital_zero_nhds_right (hdf : ∀ᶠ x in 𝓝[>] a, DifferentiableAt (hdiv : Tendsto (fun x => (deriv f) x / (deriv g) x) (𝓝[>] a) l) : Tendsto (fun x => f x / g x) (𝓝[>] a) l := by have hdg : ∀ᶠ x in 𝓝[>] a, DifferentiableAt ℝ g x := - hg'.mp (eventually_of_forall fun _ hg' => + hg'.mp (Eventually.of_forall fun _ hg' => by_contradiction fun h => hg' (deriv_zero_of_not_differentiableAt h)) have hdf' : ∀ᶠ x in 𝓝[>] a, HasDerivAt f (deriv f x) x := - hdf.mp (eventually_of_forall fun _ => DifferentiableAt.hasDerivAt) + hdf.mp (Eventually.of_forall fun _ => DifferentiableAt.hasDerivAt) have hdg' : ∀ᶠ x in 𝓝[>] a, HasDerivAt g (deriv g x) x := - hdg.mp (eventually_of_forall fun _ => DifferentiableAt.hasDerivAt) + hdg.mp (Eventually.of_forall fun _ => DifferentiableAt.hasDerivAt) exact HasDerivAt.lhopital_zero_nhds_right hdf' hdg' hg' hfa hga hdiv /-- **L'Hôpital's rule** for approaching a real from the left, `deriv` version -/ @@ -379,12 +379,12 @@ theorem lhopital_zero_nhds_left (hdf : ∀ᶠ x in 𝓝[<] a, DifferentiableAt (hdiv : Tendsto (fun x => (deriv f) x / (deriv g) x) (𝓝[<] a) l) : Tendsto (fun x => f x / g x) (𝓝[<] a) l := by have hdg : ∀ᶠ x in 𝓝[<] a, DifferentiableAt ℝ g x := - hg'.mp (eventually_of_forall fun _ hg' => + hg'.mp (Eventually.of_forall fun _ hg' => by_contradiction fun h => hg' (deriv_zero_of_not_differentiableAt h)) have hdf' : ∀ᶠ x in 𝓝[<] a, HasDerivAt f (deriv f x) x := - hdf.mp (eventually_of_forall fun _ => DifferentiableAt.hasDerivAt) + hdf.mp (Eventually.of_forall fun _ => DifferentiableAt.hasDerivAt) have hdg' : ∀ᶠ x in 𝓝[<] a, HasDerivAt g (deriv g x) x := - hdg.mp (eventually_of_forall fun _ => DifferentiableAt.hasDerivAt) + hdg.mp (Eventually.of_forall fun _ => DifferentiableAt.hasDerivAt) exact HasDerivAt.lhopital_zero_nhds_left hdf' hdg' hg' hfa hga hdiv /-- **L'Hôpital's rule** for approaching a real, `deriv` version. This @@ -413,12 +413,12 @@ theorem lhopital_zero_atTop (hdf : ∀ᶠ x : ℝ in atTop, DifferentiableAt ℝ (hgtop : Tendsto g atTop (𝓝 0)) (hdiv : Tendsto (fun x => (deriv f) x / (deriv g) x) atTop l) : Tendsto (fun x => f x / g x) atTop l := by have hdg : ∀ᶠ x in atTop, DifferentiableAt ℝ g x := hg'.mp - (eventually_of_forall fun _ hg' => + (Eventually.of_forall fun _ hg' => by_contradiction fun h => hg' (deriv_zero_of_not_differentiableAt h)) have hdf' : ∀ᶠ x in atTop, HasDerivAt f (deriv f x) x := - hdf.mp (eventually_of_forall fun _ => DifferentiableAt.hasDerivAt) + hdf.mp (Eventually.of_forall fun _ => DifferentiableAt.hasDerivAt) have hdg' : ∀ᶠ x in atTop, HasDerivAt g (deriv g x) x := - hdg.mp (eventually_of_forall fun _ => DifferentiableAt.hasDerivAt) + hdg.mp (Eventually.of_forall fun _ => DifferentiableAt.hasDerivAt) exact HasDerivAt.lhopital_zero_atTop hdf' hdg' hg' hftop hgtop hdiv /-- **L'Hôpital's rule** for approaching -∞, `deriv` version -/ @@ -427,12 +427,12 @@ theorem lhopital_zero_atBot (hdf : ∀ᶠ x : ℝ in atBot, DifferentiableAt ℝ (hgbot : Tendsto g atBot (𝓝 0)) (hdiv : Tendsto (fun x => (deriv f) x / (deriv g) x) atBot l) : Tendsto (fun x => f x / g x) atBot l := by have hdg : ∀ᶠ x in atBot, DifferentiableAt ℝ g x := - hg'.mp (eventually_of_forall fun _ hg' => + hg'.mp (Eventually.of_forall fun _ hg' => by_contradiction fun h => hg' (deriv_zero_of_not_differentiableAt h)) have hdf' : ∀ᶠ x in atBot, HasDerivAt f (deriv f x) x := - hdf.mp (eventually_of_forall fun _ => DifferentiableAt.hasDerivAt) + hdf.mp (Eventually.of_forall fun _ => DifferentiableAt.hasDerivAt) have hdg' : ∀ᶠ x in atBot, HasDerivAt g (deriv g x) x := - hdg.mp (eventually_of_forall fun _ => DifferentiableAt.hasDerivAt) + hdg.mp (Eventually.of_forall fun _ => DifferentiableAt.hasDerivAt) exact HasDerivAt.lhopital_zero_atBot hdf' hdg' hg' hfbot hgbot hdiv end deriv diff --git a/Mathlib/Analysis/Calculus/LineDeriv/Basic.lean b/Mathlib/Analysis/Calculus/LineDeriv/Basic.lean index eb08a5c169706..c3b79965c35ff 100644 --- a/Mathlib/Analysis/Calculus/LineDeriv/Basic.lean +++ b/Mathlib/Analysis/Calculus/LineDeriv/Basic.lean @@ -499,7 +499,7 @@ theorem HasLineDerivWithinAt.smul (h : HasLineDerivWithinAt 𝕜 f f' s x v) (c have A : HasDerivAt g c 0 := by simpa using (hasDerivAt_id (0 : 𝕜)).const_smul c have B : HasDerivWithinAt (fun t ↦ f (x + t • v)) f' s' (g 0) := by simpa [g] using h have Z := B.scomp (0 : 𝕜) A.hasDerivWithinAt (mapsTo_preimage g s') - simp only [g, s', Function.comp, smul_eq_mul, mul_comm c, ← smul_smul] at Z + simp only [g, s', Function.comp_def, smul_eq_mul, mul_comm c, ← smul_smul] at Z convert Z ext t simp [← smul_smul] diff --git a/Mathlib/Analysis/Calculus/LineDeriv/IntegrationByParts.lean b/Mathlib/Analysis/Calculus/LineDeriv/IntegrationByParts.lean index e46ccfaeb5601..81863eb235bbc 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] @@ -134,9 +134,9 @@ theorem integral_bilinear_hasLineDerivAt_right_eq_neg_left_of_integrable simpa [this, hL.integral_map] using H have L_emb : MeasurableEmbedding L := L.toHomeomorph.measurableEmbedding apply integral_bilinear_hasLineDerivAt_right_eq_neg_left_of_integrable_aux2 - · simpa [L_emb.integrable_map_iff, Function.comp] using hf'g - · simpa [L_emb.integrable_map_iff, Function.comp] using hfg' - · simpa [L_emb.integrable_map_iff, Function.comp] using hfg + · simpa [L_emb.integrable_map_iff, Function.comp_def] using hf'g + · simpa [L_emb.integrable_map_iff, Function.comp_def] using hfg' + · simpa [L_emb.integrable_map_iff, Function.comp_def] using hfg · intro x have : f = (f ∘ L.symm) ∘ (L : E →ₗ[ℝ] (E' × ℝ)) := by ext y; simp specialize hf (L.symm x) diff --git a/Mathlib/Analysis/Calculus/LocalExtr/Basic.lean b/Mathlib/Analysis/Calculus/LocalExtr/Basic.lean index bfa8f865b600c..946cbc383845a 100644 --- a/Mathlib/Analysis/Calculus/LocalExtr/Basic.lean +++ b/Mathlib/Analysis/Calculus/LocalExtr/Basic.lean @@ -83,7 +83,7 @@ theorem posTangentConeAt_mono : Monotone fun s => posTangentConeAt s a := by theorem mem_posTangentConeAt_of_frequently_mem (h : ∃ᶠ t : ℝ in 𝓝[>] 0, x + t • y ∈ s) : y ∈ posTangentConeAt s x := by obtain ⟨a, ha, has⟩ := Filter.exists_seq_forall_of_frequently h - refine ⟨a⁻¹, (a · • y), eventually_of_forall has, tendsto_inv_zero_atTop.comp ha, ?_⟩ + refine ⟨a⁻¹, (a · • y), Eventually.of_forall has, tendsto_inv_zero_atTop.comp ha, ?_⟩ refine tendsto_const_nhds.congr' ?_ filter_upwards [(tendsto_nhdsWithin_iff.1 ha).2] with n (hn : 0 < a n) simp [ne_of_gt hn] diff --git a/Mathlib/Analysis/Calculus/LocalExtr/Polynomial.lean b/Mathlib/Analysis/Calculus/LocalExtr/Polynomial.lean index 1aa1c46474630..062cf3b3b7880 100644 --- a/Mathlib/Analysis/Calculus/LocalExtr/Polynomial.lean +++ b/Mathlib/Analysis/Calculus/LocalExtr/Polynomial.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Benjamin Davidson. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Benjamin Davidson, Yury Kudryashov -/ -import Mathlib.Algebra.Star.Order +import Mathlib.Algebra.Order.Star.Basic import Mathlib.Analysis.Calculus.LocalExtr.Rolle import Mathlib.Analysis.Calculus.Deriv.Polynomial import Mathlib.Topology.Algebra.Polynomial diff --git a/Mathlib/Analysis/Calculus/LocalExtr/Rolle.lean b/Mathlib/Analysis/Calculus/LocalExtr/Rolle.lean index dbaffb564b895..bd4dace2f8094 100644 --- a/Mathlib/Analysis/Calculus/LocalExtr/Rolle.lean +++ b/Mathlib/Analysis/Calculus/LocalExtr/Rolle.lean @@ -58,7 +58,7 @@ theorem exists_deriv_eq_zero (hab : a < b) (hfc : ContinuousOn f (Icc a b)) (hfI /-- **Rolle's Theorem**, a version for a function on an open interval: if `f` has derivative `f'` on `(a, b)` and has the same limit `l` at `𝓝[>] a` and `𝓝[<] b`, then `f' c = 0` -for some `c ∈ (a, b)`. -/ +for some `c ∈ (a, b)`. -/ theorem exists_hasDerivAt_eq_zero' (hab : a < b) (hfa : Tendsto f (𝓝[>] a) (𝓝 l)) (hfb : Tendsto f (𝓝[<] b) (𝓝 l)) (hff' : ∀ x ∈ Ioo a b, HasDerivAt f (f' x) x) : ∃ c ∈ Ioo a b, f' c = 0 := diff --git a/Mathlib/Analysis/Calculus/MeanValue.lean b/Mathlib/Analysis/Calculus/MeanValue.lean index d28d3e874e5b0..703da3c9d5c78 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`. -/ @@ -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`. -/ @@ -917,7 +927,7 @@ theorem Convex.mul_sub_le_image_sub_of_le_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'_ge _ (hxyD' a_mem) - exact (le_div_iff (sub_pos.2 hxy')).1 this + exact (le_div_iff₀ (sub_pos.2 hxy')).1 this /-- Let `f : ℝ → ℝ` be a differentiable function. If `C ≤ f'`, then `f` grows at least as fast as `C * x`, i.e., `C * (y - x) ≤ f y - f x` whenever `x ≤ y`. -/ 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/ParametricIntervalIntegral.lean b/Mathlib/Analysis/Calculus/ParametricIntervalIntegral.lean index a6d43de3221c4..fa25dfa3f5ee9 100644 --- a/Mathlib/Analysis/Calculus/ParametricIntervalIntegral.lean +++ b/Mathlib/Analysis/Calculus/ParametricIntervalIntegral.lean @@ -10,7 +10,7 @@ import Mathlib.MeasureTheory.Integral.IntervalIntegral # Derivatives of interval integrals depending on parameters In this file we restate theorems about derivatives of integrals depending on parameters for interval -integrals. -/ +integrals. -/ open TopologicalSpace MeasureTheory Filter Metric diff --git a/Mathlib/Analysis/Calculus/Rademacher.lean b/Mathlib/Analysis/Calculus/Rademacher.lean index cbca99bb29e9a..67771abec0dce 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 @@ -64,7 +64,7 @@ variation, and is therefore ae differentiable, together with a Fubini argument. theorem memℒp_lineDeriv (hf : LipschitzWith C f) (v : E) : Memℒp (fun x ↦ lineDeriv ℝ f x v) ∞ μ := memℒp_top_of_bound (aestronglyMeasurable_lineDeriv hf.continuous μ) - (C * ‖v‖) (eventually_of_forall (fun _x ↦ norm_lineDeriv_le_of_lipschitz ℝ hf)) + (C * ‖v‖) (.of_forall fun _x ↦ norm_lineDeriv_le_of_lipschitz ℝ hf) variable [FiniteDimensional ℝ E] [IsAddHaarMeasure μ] @@ -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 803f02e84a103..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 @@ -230,7 +232,7 @@ theorem contDiff_tsum (hf : ∀ i, ContDiff 𝕜 N (f i)) (hv : ∀ k : ℕ, (k exact h'f _ _ _ hm · intro m hm have h'm : ((m + 1 : ℕ) : ℕ∞) ≤ N := by - simpa only [ENat.coe_add, ENat.coe_one] using ENat.add_one_le_of_lt hm + simpa only [ENat.coe_add, ENat.coe_one] using Order.add_one_le_of_lt hm rw [iteratedFDeriv_tsum hf hv h'f hm.le] have A : ∀ n x, HasFDerivAt (iteratedFDeriv 𝕜 m (f n)) (fderiv 𝕜 (iteratedFDeriv 𝕜 m (f n)) x) x := diff --git a/Mathlib/Analysis/Calculus/TangentCone.lean b/Mathlib/Analysis/Calculus/TangentCone.lean index e4c5b68d694c1..f3ac765b70a30 100644 --- a/Mathlib/Analysis/Calculus/TangentCone.lean +++ b/Mathlib/Analysis/Calculus/TangentCone.lean @@ -81,13 +81,13 @@ 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 := let ⟨_r, hr₀, hr⟩ := exists_norm_lt_one 𝕜 eq_univ_of_forall fun _ ↦ mem_tangentConeAt_of_pow_smul (norm_pos_iff.1 hr₀) hr <| - eventually_of_forall fun _ ↦ mem_univ _ + Eventually.of_forall fun _ ↦ mem_univ _ theorem tangentCone_mono (h : s ⊆ t) : tangentConeAt 𝕜 s x ⊆ tangentConeAt 𝕜 t x := by rintro y ⟨c, d, ds, ctop, clim⟩ @@ -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/Taylor.lean b/Mathlib/Analysis/Calculus/Taylor.lean index d48e71fcee876..9f73b88cf066d 100644 --- a/Mathlib/Analysis/Calculus/Taylor.lean +++ b/Mathlib/Analysis/Calculus/Taylor.lean @@ -98,17 +98,18 @@ theorem taylor_within_zero_eval (f : ℝ → E) (s : Set ℝ) (x₀ x : ℝ) : @[simp] theorem taylorWithinEval_self (f : ℝ → E) (n : ℕ) (s : Set ℝ) (x₀ : ℝ) : taylorWithinEval f n s x₀ x₀ = f x₀ := by - induction' n with k hk - · exact taylor_within_zero_eval _ _ _ _ - simp [hk] + induction n with + | zero => exact taylor_within_zero_eval _ _ _ _ + | succ k hk => simp [hk] theorem taylor_within_apply (f : ℝ → E) (n : ℕ) (s : Set ℝ) (x₀ x : ℝ) : taylorWithinEval f n s x₀ x = ∑ k ∈ Finset.range (n + 1), ((k ! : ℝ)⁻¹ * (x - x₀) ^ k) • iteratedDerivWithin k f s x₀ := by - induction' n with k hk - · simp - rw [taylorWithinEval_succ, Finset.sum_range_succ, hk] - simp [Nat.factorial] + induction n with + | zero => simp + | succ k hk => + rw [taylorWithinEval_succ, Finset.sum_range_succ, hk] + simp [Nat.factorial] /-- If `f` is `n` times continuous differentiable on a set `s`, then the Taylor polynomial `taylorWithinEval f n s x₀ x` is continuous in `x₀`. -/ @@ -166,21 +167,23 @@ theorem hasDerivWithinAt_taylorWithinEval {f : ℝ → E} {x y : ℝ} {n : ℕ} (hf' : DifferentiableWithinAt ℝ (iteratedDerivWithin n f s) s y) : HasDerivWithinAt (fun t => taylorWithinEval f n s t x) (((n ! : ℝ)⁻¹ * (x - y) ^ n) • iteratedDerivWithin (n + 1) f s y) s' y := by - induction' n with k hk - · simp only [taylor_within_zero_eval, Nat.factorial_zero, Nat.cast_one, inv_one, pow_zero, + induction n with + | zero => + simp only [taylor_within_zero_eval, Nat.factorial_zero, Nat.cast_one, inv_one, pow_zero, mul_one, zero_add, one_smul] simp only [iteratedDerivWithin_zero] at hf' rw [iteratedDerivWithin_one (hs_unique _ (h hy))] exact hf'.hasDerivWithinAt.mono h - simp_rw [Nat.add_succ, taylorWithinEval_succ] - simp only [add_zero, Nat.factorial_succ, Nat.cast_mul, Nat.cast_add, Nat.cast_one] - have coe_lt_succ : (k : WithTop ℕ) < k.succ := Nat.cast_lt.2 k.lt_succ_self - have hdiff : DifferentiableOn ℝ (iteratedDerivWithin k f s) s' := - (hf.differentiableOn_iteratedDerivWithin coe_lt_succ hs_unique).mono h - specialize hk hf.of_succ ((hdiff y hy).mono_of_mem hs') - convert hk.add (hasDerivWithinAt_taylor_coeff_within hs'_unique - (nhdsWithin_mono _ h self_mem_nhdsWithin) hf') using 1 - exact (add_sub_cancel _ _).symm + | succ k hk => + simp_rw [Nat.add_succ, taylorWithinEval_succ] + simp only [add_zero, Nat.factorial_succ, Nat.cast_mul, Nat.cast_add, Nat.cast_one] + have coe_lt_succ : (k : WithTop ℕ) < k.succ := Nat.cast_lt.2 k.lt_succ_self + have hdiff : DifferentiableOn ℝ (iteratedDerivWithin k f s) s' := + (hf.differentiableOn_iteratedDerivWithin coe_lt_succ hs_unique).mono h + specialize hk hf.of_succ ((hdiff y hy).mono_of_mem hs') + convert hk.add (hasDerivWithinAt_taylor_coeff_within hs'_unique + (nhdsWithin_mono _ h self_mem_nhdsWithin) hf') using 1 + exact (add_sub_cancel _ _).symm /-- Calculate the derivative of the Taylor polynomial with respect to `x₀`. 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 0e14c1272df17..167aa0434d806 100644 --- a/Mathlib/Analysis/Complex/AbelLimit.lean +++ b/Mathlib/Analysis/Complex/AbelLimit.lean @@ -206,9 +206,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 @@ -268,6 +268,5 @@ theorem tendsto_tsum_powerSeries_nhdsWithin_lt convert h simp_rw [Function.comp_apply, dist_eq_norm] norm_cast - rw [norm_real] end Real diff --git a/Mathlib/Analysis/Complex/AbsMax.lean b/Mathlib/Analysis/Complex/AbsMax.lean index 9bb3354667e7c..0d367d1d608d3 100644 --- a/Mathlib/Analysis/Complex/AbsMax.lean +++ b/Mathlib/Analysis/Complex/AbsMax.lean @@ -128,7 +128,7 @@ theorem norm_max_aux₁ [CompleteSpace F] {f : ℂ → F} {z w : ℂ} exact fun ζ hζ => sub_ne_zero.2 (ne_of_mem_sphere hζ hr.ne') · show ∀ ζ ∈ sphere z r, ‖(ζ - z)⁻¹ • f ζ‖ ≤ ‖f z‖ / r rintro ζ (hζ : abs (ζ - z) = r) - rw [le_div_iff hr, norm_smul, norm_inv, norm_eq_abs, hζ, mul_comm, mul_inv_cancel_left₀ hr.ne'] + rw [le_div_iff₀ hr, norm_smul, norm_inv, norm_eq_abs, hζ, mul_comm, mul_inv_cancel_left₀ hr.ne'] exact hz (hsub hζ) show ‖(w - z)⁻¹ • f w‖ < ‖f z‖ / r rw [norm_smul, norm_inv, norm_eq_abs, ← div_eq_inv_mul] @@ -143,8 +143,8 @@ theorem norm_max_aux₂ {f : ℂ → F} {z w : ℂ} (hd : DiffContOnCl ℂ f (ba set e : F →L[ℂ] F̂ := UniformSpace.Completion.toComplL have he : ∀ x, ‖e x‖ = ‖x‖ := UniformSpace.Completion.norm_coe replace hz : IsMaxOn (norm ∘ e ∘ f) (closedBall z (dist w z)) z := by - simpa only [IsMaxOn, (· ∘ ·), he] using hz - simpa only [he, (· ∘ ·)] + simpa only [IsMaxOn, Function.comp_def, he] using hz + simpa only [he, Function.comp_def] using norm_max_aux₁ (e.differentiable.comp_diffContOnCl hd) hz /-! @@ -172,7 +172,7 @@ Finally, we generalize the theorem from a disk in `ℂ` to a closed ball in any /-- **Maximum modulus principle** on a closed ball: if `f : E → F` is continuous on a closed ball, is complex differentiable on the corresponding open ball, and the norm `‖f w‖` takes its maximum -value on the open ball at its center, then the norm `‖f w‖` is constant on the closed ball. -/ +value on the open ball at its center, then the norm `‖f w‖` is constant on the closed ball. -/ theorem norm_eqOn_closedBall_of_isMaxOn {f : E → F} {z : E} {r : ℝ} (hd : DiffContOnCl ℂ f (ball z r)) (hz : IsMaxOn (norm ∘ f) (ball z r) z) : EqOn (norm ∘ f) (const E ‖f z‖) (closedBall z r) := by @@ -306,7 +306,7 @@ normed complex space to a strictly convex normed complex space has the following - it is complex differentiable on the corresponding open ball; - the norm `‖f w‖` takes its maximum value on the open ball at its center. -Then `f` is a constant on the closed ball. -/ +Then `f` is a constant on the closed ball. -/ theorem eqOn_closedBall_of_isMaxOn_norm {f : E → F} {z : E} {r : ℝ} (hd : DiffContOnCl ℂ f (ball z r)) (hz : IsMaxOn (norm ∘ f) (ball z r) z) : EqOn f (const E (f z)) (closedBall z r) := fun _x hx => @@ -330,7 +330,7 @@ theorem eventually_eq_or_eq_zero_of_isLocalMin_norm {f : E → ℂ} {c : E} refine or_iff_not_imp_right.mpr fun h => ?_ have h1 : ∀ᶠ z in 𝓝 c, f z ≠ 0 := hf.self_of_nhds.continuousAt.eventually_ne h have h2 : IsLocalMax (norm ∘ f)⁻¹ c := hc.inv (h1.mono fun z => norm_pos_iff.mpr) - have h3 : IsLocalMax (norm ∘ f⁻¹) c := by refine h2.congr (eventually_of_forall ?_); simp + have h3 : IsLocalMax (norm ∘ f⁻¹) c := by refine h2.congr (Eventually.of_forall ?_); simp have h4 : ∀ᶠ z in 𝓝 c, DifferentiableAt ℂ f⁻¹ z := by filter_upwards [hf, h1] with z h using h.inv filter_upwards [eventually_eq_of_isLocalMax_norm h4 h3] with z using inv_inj.mp diff --git a/Mathlib/Analysis/Complex/Angle.lean b/Mathlib/Analysis/Complex/Angle.lean index 95b1c80bb289e..e7031e3748729 100644 --- a/Mathlib/Analysis/Complex/Angle.lean +++ b/Mathlib/Analysis/Complex/Angle.lean @@ -96,7 +96,7 @@ lemma norm_sub_mem_Icc_angle (hx : ‖x‖ = 1) (hy : ‖y‖ = 1) : calc _ = 2 * (1 - (1 - 2 / π ^ 2 * θ ^ 2)) := by ring _ ≤ 2 * (1 - θ.cos) := by - gcongr; exact Real.cos_quadratic_upper_bound <| abs_le.2 <| Ioc_subset_Icc_self hθ + gcongr; exact Real.cos_le_one_sub_mul_cos_sq <| abs_le.2 <| Ioc_subset_Icc_self hθ _ = _ := by linear_combination -θ.cos_sq_add_sin_sq · rw [Real.sqrt_le_left (by positivity), ← _root_.abs_pow, abs_sq] calc @@ -116,6 +116,6 @@ lemma mul_angle_le_norm_sub (hx : ‖x‖ = 1) (hy : ‖y‖ = 1) : 2 / π * ang /-- Arc-length is always less than a multiple of chord-length. -/ lemma angle_le_mul_norm_sub (hx : ‖x‖ = 1) (hy : ‖y‖ = 1) : angle x y ≤ π / 2 * ‖x - y‖ := by - rw [← div_le_iff' <| by positivity, div_eq_inv_mul, inv_div]; exact mul_angle_le_norm_sub hx hy + rw [← div_le_iff₀' <| by positivity, div_eq_inv_mul, inv_div]; exact mul_angle_le_norm_sub hx hy end Complex 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 5cce5c3e7eeb1..b2b77580329f5 100644 --- a/Mathlib/Analysis/Complex/Basic.lean +++ b/Mathlib/Analysis/Complex/Basic.lean @@ -92,6 +92,8 @@ instance (priority := 900) _root_.NormedAlgebra.complexToReal {A : Type*} [Semin [NormedAlgebra ℂ A] : NormedAlgebra ℝ A := NormedAlgebra.restrictScalars ℝ ℂ A +@[simp] lemma nnnorm_I : ‖I‖₊ = 1 := by simp [nnnorm] + theorem dist_eq (z w : ℂ) : dist z w = abs (z - w) := rfl @@ -138,23 +140,38 @@ theorem nndist_self_conj (z : ℂ) : nndist z (conj z) = 2 * Real.nnabs z.im := theorem comap_abs_nhds_zero : comap abs (𝓝 0) = 𝓝 0 := comap_norm_nhds_zero -theorem norm_real (r : ℝ) : ‖(r : ℂ)‖ = ‖r‖ := - abs_ofReal _ +@[simp 1100, norm_cast] lemma norm_real (r : ℝ) : ‖(r : ℂ)‖ = ‖r‖ := abs_ofReal _ +@[simp, norm_cast] lemma nnnorm_real (r : ℝ) : ‖(r : ℂ)‖₊ = ‖r‖₊ := by ext; exact norm_real _ -@[simp 1100] -theorem norm_rat (r : ℚ) : ‖(r : ℂ)‖ = |(r : ℝ)| := by - rw [← ofReal_ratCast] - exact norm_real _ +@[simp 1100, norm_cast] lemma norm_natCast (n : ℕ) : ‖(n : ℂ)‖ = n := abs_natCast _ +@[simp 1100, norm_cast] lemma norm_intCast (n : ℤ) : ‖(n : ℂ)‖ = |(n : ℝ)| := abs_intCast n +@[simp 1100, norm_cast] lemma norm_ratCast (q : ℚ) : ‖(q : ℂ)‖ = |(q : ℝ)| := norm_real _ -@[simp 1100] -theorem norm_nat (n : ℕ) : ‖(n : ℂ)‖ = n := - abs_natCast _ +@[simp 1100, norm_cast] lemma nnnorm_natCast (n : ℕ) : ‖(n : ℂ)‖₊ = n := Subtype.ext <| by simp +@[simp 1100, norm_cast] lemma nnnorm_intCast (n : ℤ) : ‖(n : ℂ)‖₊ = ‖n‖₊ := by + ext; exact norm_intCast n +@[simp 1100, norm_cast] lemma nnnorm_ratCast (q : ℚ) : ‖(q : ℂ)‖₊ = ‖(q : ℝ)‖₊ := nnnorm_real q -@[simp 1100] -lemma norm_int {n : ℤ} : ‖(n : ℂ)‖ = |(n : ℝ)| := abs_intCast n +@[simp 1100] lemma norm_ofNat (n : ℕ) [n.AtLeastTwo] : + ‖(no_index (OfNat.ofNat n) : ℂ)‖ = OfNat.ofNat n := norm_natCast n + +@[simp 1100] lemma nnnorm_ofNat (n : ℕ) [n.AtLeastTwo] : + ‖(no_index (OfNat.ofNat n) : ℂ)‖₊ = OfNat.ofNat n := nnnorm_natCast n + +@[deprecated (since := "2024-08-25")] alias norm_nat := norm_natCast +@[deprecated (since := "2024-08-25")] alias norm_int := norm_intCast +@[deprecated (since := "2024-08-25")] alias norm_rat := norm_ratCast +@[deprecated (since := "2024-08-25")] alias nnnorm_nat := nnnorm_natCast +@[deprecated (since := "2024-08-25")] alias nnnorm_int := nnnorm_intCast + +@[simp 1100, norm_cast] +lemma norm_nnratCast (q : ℚ≥0) : ‖(q : ℂ)‖ = q := abs_of_nonneg q.cast_nonneg + +@[simp 1100, norm_cast] +lemma nnnorm_nnratCast (q : ℚ≥0) : ‖(q : ℂ)‖₊ = q := by simp [nnnorm, -norm_eq_abs] theorem norm_int_of_nonneg {n : ℤ} (hn : 0 ≤ n) : ‖(n : ℂ)‖ = n := by - rw [norm_int, ← Int.cast_abs, _root_.abs_of_nonneg hn] + rw [norm_intCast, ← Int.cast_abs, _root_.abs_of_nonneg hn] lemma normSq_eq_norm_sq (z : ℂ) : normSq z = ‖z‖ ^ 2 := by rw [normSq_eq_abs, norm_eq_abs] @@ -167,17 +184,6 @@ theorem continuous_abs : Continuous abs := theorem continuous_normSq : Continuous normSq := by simpa [← normSq_eq_abs] using continuous_abs.pow 2 -@[simp, norm_cast] -theorem nnnorm_real (r : ℝ) : ‖(r : ℂ)‖₊ = ‖r‖₊ := - Subtype.ext <| norm_real r - -@[simp, norm_cast] -theorem nnnorm_nat (n : ℕ) : ‖(n : ℂ)‖₊ = n := - Subtype.ext <| by simp - -@[simp, norm_cast] -theorem nnnorm_int (n : ℤ) : ‖(n : ℂ)‖₊ = ‖n‖₊ := - Subtype.ext norm_int theorem nnnorm_eq_one_of_pow_eq_one {ζ : ℂ} {n : ℕ} (h : ζ ^ n = 1) (hn : n ≠ 0) : ‖ζ‖₊ = 1 := (pow_left_inj zero_le' zero_le' hn).1 <| by rw [← nnnorm_pow, h, nnnorm_one, one_pow] @@ -202,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 @@ -275,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[ℂ] ℂ) = diff --git a/Mathlib/Analysis/Complex/CauchyIntegral.lean b/Mathlib/Analysis/Complex/CauchyIntegral.lean index 23f031e5b652c..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 @@ -466,7 +465,7 @@ theorem two_pi_I_inv_smul_circleIntegral_sub_inv_smul_of_differentiable_on_off_c rcases mem_nhds_iff_exists_Ioo_subset.1 (this <| inter_mem ht <| isOpen_ball.mem_nhds hw) with ⟨l, u, hlu₀, hlu_sub⟩ obtain ⟨x, hx⟩ : (Ioo l u \ g ⁻¹' s).Nonempty := by - refine nonempty_diff.2 fun hsub => ?_ + refine diff_nonempty.2 fun hsub => ?_ have : (Ioo l u).Countable := (hs.preimage ((add_right_injective w).comp ofReal_injective)).mono hsub rw [← Cardinal.le_aleph0_iff_set_countable, Cardinal.mk_Ioo_real (hlu₀.1.trans hlu₀.2)] at this @@ -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 aab56f8eec106..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 /-! @@ -34,7 +34,7 @@ is the kernel of the homomorphism `Complex.normSq` from `ℂ` to `ℝ`. noncomputable section -open Complex Metric +open Complex Function Metric open ComplexConjugate @@ -60,16 +60,26 @@ def Circle : Type := Submonoid.unitSphere ℂ deriving TopologicalSpace namespace Circle +variable {x y : Circle} instance instCoeOut : CoeOut Circle ℂ := subtypeCoe instance instCommGroup : CommGroup Circle := Metric.sphere.commGroup instance instMetricSpace : MetricSpace Circle := Subtype.metricSpace +@[ext] lemma ext : (x : ℂ) = y → x = y := Subtype.ext + +lemma coe_injective : Injective ((↑) : Circle → ℂ) := fun _ _ ↦ ext + +-- Not simp because `SetLike.coe_eq_coe` already proves it +lemma coe_inj : (x : ℂ) = y ↔ x = y := coe_injective.eq_iff + @[simp] lemma abs_coe (z : Circle) : abs z = 1 := mem_sphere_zero_iff_norm.1 z.2 @[simp] lemma normSq_coe (z : Circle) : normSq z = 1 := by simp [normSq_eq_abs] @[simp] lemma coe_ne_zero (z : Circle) : (z : ℂ) ≠ 0 := ne_zero_of_mem_unit_sphere z @[simp, norm_cast] lemma coe_one : ↑(1 : Circle) = (1 : ℂ) := rfl +-- Not simp because `OneMemClass.coe_eq_one` already proves it +@[norm_cast] lemma coe_eq_one : (x : ℂ) = 1 ↔ x = 1 := by rw [← coe_inj, coe_one] @[simp, norm_cast] lemma coe_mul (z w : Circle) : ↑(z * w) = (z : ℂ) * w := rfl @[simp, norm_cast] lemma coe_inv (z : Circle) : ↑z⁻¹ = (z : ℂ)⁻¹ := rfl lemma coe_inv_eq_conj (z : Circle) : ↑z⁻¹ = conj (z : ℂ) := by @@ -117,17 +127,17 @@ def exp : C(ℝ, Circle) where continuous_toFun := Continuous.subtype_mk (by fun_prop) (by simp [Submonoid.unitSphere, exp_mul_I, abs_cos_add_sin_mul_I]) -@[simp] -theorem exp_apply (t : ℝ) : ↑(exp t) = Complex.exp (t * Complex.I) := rfl +@[simp, norm_cast] +theorem coe_exp (t : ℝ) : exp t = Complex.exp (t * Complex.I) := rfl @[simp] theorem exp_zero : exp 0 = 1 := - Subtype.ext <| by rw [exp_apply, ofReal_zero, zero_mul, Complex.exp_zero, coe_one] + Subtype.ext <| by rw [coe_exp, ofReal_zero, zero_mul, Complex.exp_zero, coe_one] @[simp] theorem exp_add (x y : ℝ) : exp (x + y) = exp x * exp y := Subtype.ext <| by - simp only [exp_apply, Submonoid.coe_mul, ofReal_add, add_mul, Complex.exp_add, coe_mul] + simp only [coe_exp, Submonoid.coe_mul, ofReal_add, add_mul, Complex.exp_add, coe_mul] /-- The map `fun t => exp (t * I)` from `ℝ` to the unit circle in `ℂ`, considered as a homomorphism of groups. -/ @@ -170,7 +180,7 @@ protected lemma norm_smul {E : Type*} [SeminormedAddCommGroup E] [NormedSpace rw [Submonoid.smul_def, norm_smul, norm_eq_of_mem_sphere, one_mul] @[deprecated (since := "2024-07-24")] noncomputable alias _root_.expMapCircle := exp -@[deprecated (since := "2024-07-24")] noncomputable alias _root_.expMapCircle_apply := exp_apply +@[deprecated (since := "2024-07-24")] noncomputable alias _root_.expMapCircle_apply := coe_exp @[deprecated (since := "2024-07-24")] noncomputable alias _root_.expMapCircle_zero := exp_zero @[deprecated (since := "2024-07-24")] noncomputable alias _root_.expMapCircle_sub := exp_sub @[deprecated (since := "2024-07-24")] noncomputable alias _root_.norm_circle_smul := diff --git a/Mathlib/Analysis/Complex/Hadamard.lean b/Mathlib/Analysis/Complex/Hadamard.lean index 663f0d998f29a..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] @@ -219,7 +219,7 @@ theorem norm_mul_invInterpStrip_le_one_of_mem_verticalClosedStrip (f : ℂ → E rw [Asymptotics.isBigO_iff] use 1 rw [eventually_inf_principal] - apply eventually_of_forall + apply Eventually.of_forall intro x hx norm_num exact (hBF x ((preimage_mono Ioo_subset_Icc_self) hx)).trans @@ -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/IsIntegral.lean b/Mathlib/Analysis/Complex/IsIntegral.lean new file mode 100644 index 0000000000000..939434a7a666d --- /dev/null +++ b/Mathlib/Analysis/Complex/IsIntegral.lean @@ -0,0 +1,27 @@ +/- +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.Analysis.Complex.Basic +import Mathlib.RingTheory.IntegralClosure.IsIntegral.Basic + +/-! +# Integral elements of ℂ + +This file proves that `Complex.I` is integral over ℤ and ℚ. +-/ + +open Polynomial + +namespace Complex + +theorem isIntegral_int_I : IsIntegral ℤ I := by + refine ⟨X ^ 2 + C 1, monic_X_pow_add_C _ two_ne_zero, ?_⟩ + rw [eval₂_add, eval₂_X_pow, eval₂_C, I_sq, eq_intCast, Int.cast_one, neg_add_cancel] + +theorem isIntegral_rat_I : IsIntegral ℚ I := + isIntegral_int_I.tower_top + +end Complex diff --git a/Mathlib/Analysis/Complex/LocallyUniformLimit.lean b/Mathlib/Analysis/Complex/LocallyUniformLimit.lean index 09792d0f7a4bd..14b603b86f48e 100644 --- a/Mathlib/Analysis/Complex/LocallyUniformLimit.lean +++ b/Mathlib/Analysis/Complex/LocallyUniformLimit.lean @@ -170,7 +170,7 @@ theorem differentiableOn_tsum_of_summable_norm {u : ι → ℝ} (hu : Summable u DifferentiableOn ℂ (fun w : ℂ => ∑' i : ι, F i w) U := by classical have hc := (tendstoUniformlyOn_tsum hu hF_le).tendstoLocallyUniformlyOn - refine hc.differentiableOn (eventually_of_forall fun s => ?_) hU + refine hc.differentiableOn (Eventually.of_forall fun s => ?_) hU exact DifferentiableOn.sum fun i _ => hf i /-- If the terms in the sum `∑' (i : ι), F i` are uniformly bounded on `U` by a @@ -182,7 +182,7 @@ theorem hasSum_deriv_of_summable_norm {u : ι → ℝ} (hu : Summable u) HasSum (fun i : ι => deriv (F i) z) (deriv (fun w : ℂ => ∑' i : ι, F i w) z) := by rw [HasSum] have hc := (tendstoUniformlyOn_tsum hu hF_le).tendstoLocallyUniformlyOn - convert (hc.deriv (eventually_of_forall fun s => + convert (hc.deriv (Eventually.of_forall fun s => DifferentiableOn.sum fun i _ => hf i) hU).tendsto_at hz using 1 ext1 s exact (deriv_sum fun i _ => (hf i).differentiableAt (hU.mem_nhds hz)).symm diff --git a/Mathlib/Analysis/Complex/OpenMapping.lean b/Mathlib/Analysis/Complex/OpenMapping.lean index 9ce4d01945319..c37d82d1058c9 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. -/ @@ -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 a4a9e03590e0f..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` @@ -282,8 +282,8 @@ theorem vertical_strip (hfd : DiffContOnCl ℂ f (re ⁻¹' Ioo a b)) have : Tendsto (· * -I) (comap (|re ·|) atTop ⊓ 𝓟 (im ⁻¹' Ioo a b)) (comap (|im ·|) atTop ⊓ 𝓟 (re ⁻¹' Ioo a b)) := by refine (tendsto_comap_iff.2 ?_).inf H.tendsto - simpa [(· ∘ ·)] using tendsto_comap - simpa [(· ∘ ·)] using hO.comp_tendsto this + simpa [Function.comp_def] using tendsto_comap + simpa [Function.comp_def] using hO.comp_tendsto this all_goals simpa /-- **Phragmen-Lindelöf principle** in a strip `U = {z : ℂ | a < re z < b}`. @@ -453,7 +453,7 @@ theorem quadrant_II (hd : DiffContOnCl ℂ f (Iio 0 ×ℂ Ioi 0)) rcases hB with ⟨c, hc, B, hO⟩ refine quadrant_I (hd.comp (differentiable_id.mul_const _).diffContOnCl H) ⟨c, hc, B, ?_⟩ him (fun x hx => ?_) hz_im hz_re - · simpa only [(· ∘ ·), map_mul, abs_I, mul_one] + · simpa only [Function.comp_def, map_mul, abs_I, mul_one] using hO.comp_tendsto ((tendsto_mul_right_cobounded I_ne_zero).inf H.tendsto) · rw [comp_apply, mul_assoc, I_mul_I, mul_neg_one, ← ofReal_neg] exact hre _ (neg_nonpos.2 hx) @@ -518,7 +518,7 @@ theorem quadrant_III (hd : DiffContOnCl ℂ f (Iio 0 ×ℂ Iio 0)) hz_re hz_im · rcases hB with ⟨c, hc, B, hO⟩ refine ⟨c, hc, B, ?_⟩ - simpa only [(· ∘ ·), Complex.abs.map_neg] + simpa only [Function.comp_def, Complex.abs.map_neg] using hO.comp_tendsto (tendsto_neg_cobounded.inf H.tendsto) · rw [comp_apply, ← ofReal_neg] exact hre (-x) (neg_nonpos.2 hx) @@ -582,7 +582,7 @@ theorem quadrant_IV (hd : DiffContOnCl ℂ f (Ioi 0 ×ℂ Iio 0)) (hd.comp differentiable_neg.diffContOnCl H) ?_ (fun x hx => ?_) (fun x hx => ?_) hz_re hz_im · rcases hB with ⟨c, hc, B, hO⟩ refine ⟨c, hc, B, ?_⟩ - simpa only [(· ∘ ·), Complex.abs.map_neg] + simpa only [Function.comp_def, Complex.abs.map_neg] using hO.comp_tendsto (tendsto_neg_cobounded.inf H.tendsto) · rw [comp_apply, ← ofReal_neg] exact hre (-x) (neg_nonneg.2 hx) @@ -733,7 +733,7 @@ theorem right_half_plane_of_bounded_on_real (hd : DiffContOnCl ℂ f {z | 0 < z. refine right_half_plane_of_tendsto_zero_on_real hd ?_ ?_ (fun y => ?_) hz · rcases hexp with ⟨c, hc, B, hO⟩ refine ⟨c, hc, B, (IsBigO.of_bound 1 ?_).trans hO⟩ - refine eventually_inf_principal.2 <| eventually_of_forall fun z hz => ?_ + refine eventually_inf_principal.2 <| Eventually.of_forall fun z hz => ?_ rw [hgn, one_mul] refine mul_le_of_le_one_left (norm_nonneg _) (Real.exp_le_one_iff.2 ?_) exact mul_nonpos_of_nonpos_of_nonneg ε₀.le (le_of_lt hz) diff --git a/Mathlib/Analysis/Complex/Polynomial/Basic.lean b/Mathlib/Analysis/Complex/Polynomial/Basic.lean index 145fa099c8971..82e38a8adc578 100644 --- a/Mathlib/Analysis/Complex/Polynomial/Basic.lean +++ b/Mathlib/Analysis/Complex/Polynomial/Basic.lean @@ -128,7 +128,7 @@ theorem galActionHom_bijective_of_prime_degree {p : ℚ[X]} (p_irr : Irreducible let conj' := restrict p ℂ (Complex.conjAe.restrictScalars ℚ) refine ⟨galActionHom_injective p ℂ, fun x => - (congr_arg (Membership.mem x) (show (galActionHom p ℂ).range = ⊤ from ?_)).mpr + (congr_arg (x ∈ ·) (show (galActionHom p ℂ).range = ⊤ from ?_)).mpr (Subgroup.mem_top x)⟩ apply Equiv.Perm.subgroup_eq_top_of_swap_mem · rwa [h1] 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 cf851529fbf6f..4c91fb9c0f890 100644 --- a/Mathlib/Analysis/Complex/Schwarz.lean +++ b/Mathlib/Analysis/Complex/Schwarz.lean @@ -149,7 +149,7 @@ theorem dist_le_div_mul_dist_of_mapsTo_ball (hd : DifferentiableOn ℂ f (ball c rcases eq_or_ne z c with (rfl | hne) · simp only [dist_self, mul_zero, le_rfl] simpa only [dslope_of_ne _ hne, slope_def_module, norm_smul, norm_inv, ← div_eq_inv_mul, ← - dist_eq_norm, div_le_iff (dist_pos.2 hne)] using norm_dslope_le_div_of_mapsTo_ball hd h_maps hz + dist_eq_norm, div_le_iff₀ (dist_pos.2 hne)] using norm_dslope_le_div_of_mapsTo_ball hd h_maps hz end Space diff --git a/Mathlib/Analysis/Complex/TaylorSeries.lean b/Mathlib/Analysis/Complex/TaylorSeries.lean index 90a8b74ad8c80..dbd3037467b3a 100644 --- a/Mathlib/Analysis/Complex/TaylorSeries.lean +++ b/Mathlib/Analysis/Complex/TaylorSeries.lean @@ -11,7 +11,7 @@ import Mathlib.Analysis.Complex.CauchyIntegral We show that the Taylor series around some point `c : ℂ` of a function `f` that is complex differentiable on the open ball of radius `r` around `c` converges to `f` on that open ball; see `Complex.hasSum_taylorSeries_on_ball` and `Complex.taylorSeries_eq_on_ball` for versions -(in terms of `HasSum` and `tsum`, repsectively) for functions to a complete normed +(in terms of `HasSum` and `tsum`, respectively) for functions to a complete normed space over `ℂ`, and `Complex.taylorSeries_eq_on_ball'` for a variant when `f : ℂ → ℂ`. There are corresponding statements for `EMEtric.ball`s; see @@ -24,16 +24,24 @@ see `Complex.hasSum_taylorSeries_of_entire`, `Complex.taylorSeries_eq_of_entire` `Complex.taylorSeries_eq_of_entire'`. -/ +#adaptation_note +/-- +Due to https://github.com/leanprover/lean4/issues/5126, we've had to change all +the `⦃⦄` stricit implicit variable statements in this file to normal `{}` implicit variables. + +Once this issue is fixed, we should change them back. For now it doesn't break anything downstream. +-/ + namespace Complex open Nat -variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [CompleteSpace E] ⦃f : ℂ → E⦄ +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [CompleteSpace E] {f : ℂ → E} section ball -variable ⦃c : ℂ⦄ ⦃r : ℝ⦄ (hf : DifferentiableOn ℂ f (Metric.ball c r)) -variable ⦃z : ℂ⦄ (hz : z ∈ Metric.ball c r) +variable {c : ℂ} {r : ℝ} (hf : DifferentiableOn ℂ f (Metric.ball c r)) +variable {z : ℂ} (hz : z ∈ Metric.ball c r) include hf hz in /-- A function that is complex differentiable on the open ball of radius `r` around `c` @@ -74,8 +82,8 @@ end ball section emetric -variable ⦃c : ℂ⦄ ⦃r : ENNReal⦄ (hf : DifferentiableOn ℂ f (EMetric.ball c r)) -variable ⦃z : ℂ⦄ (hz : z ∈ EMetric.ball c r) +variable {c : ℂ} {r : ENNReal} (hf : DifferentiableOn ℂ f (EMetric.ball c r)) +variable {z : ℂ} (hz : z ∈ EMetric.ball c r) include hf hz in /-- A function that is complex differentiable on the open ball of radius `r ≤ ∞` around `c` @@ -108,7 +116,7 @@ end emetric section entire -variable ⦃f : ℂ → E⦄ (hf : Differentiable ℂ f) (c z : ℂ) +variable {f : ℂ → E} (hf : Differentiable ℂ f) (c z : ℂ) include hf in /-- A function that is complex differentiable on the complex plane is given by evaluating diff --git a/Mathlib/Analysis/Complex/UpperHalfPlane/Basic.lean b/Mathlib/Analysis/Complex/UpperHalfPlane/Basic.lean index 6afa53eec6ef1..f9c084804d861 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 diff --git a/Mathlib/Analysis/Complex/UpperHalfPlane/Manifold.lean b/Mathlib/Analysis/Complex/UpperHalfPlane/Manifold.lean index f3d8eacb2243d..2bc3767cffe15 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 /-! diff --git a/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean b/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean index 1ec268788ba90..256120e306349 100644 --- a/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean +++ b/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean @@ -93,7 +93,7 @@ theorem dist_eq_iff_eq_sq_sinh (hr : 0 ≤ r) : all_goals positivity protected theorem dist_triangle (a b c : ℍ) : dist a c ≤ dist a b + dist b c := by - rw [dist_le_iff_le_sinh, sinh_half_dist_add_dist, div_mul_eq_div_div _ _ (dist _ _), le_div_iff, + rw [dist_le_iff_le_sinh, sinh_half_dist_add_dist, div_mul_eq_div_div _ _ (dist _ _), le_div_iff₀, div_mul_eq_mul_div] · gcongr exact EuclideanGeometry.mul_dist_le_mul_dist_add_mul_dist (a : ℂ) b c (conj (b : ℂ)) @@ -218,11 +218,11 @@ theorem dist_log_im_le (z w : ℍ) : dist (log z.im) (log w.im) ≤ dist z w := simpa [sqrt_sq_eq_abs] using Complex.abs_im_le_abs (z - w) theorem im_le_im_mul_exp_dist (z w : ℍ) : z.im ≤ w.im * Real.exp (dist z w) := by - rw [← div_le_iff' w.im_pos, ← exp_log z.im_pos, ← exp_log w.im_pos, ← Real.exp_sub, exp_le_exp] + rw [← div_le_iff₀' w.im_pos, ← exp_log z.im_pos, ← exp_log w.im_pos, ← Real.exp_sub, exp_le_exp] exact (le_abs_self _).trans (dist_log_im_le z w) theorem im_div_exp_dist_le (z w : ℍ) : z.im / Real.exp (dist z w) ≤ w.im := - (div_le_iff (exp_pos _)).2 (im_le_im_mul_exp_dist z w) + (div_le_iff₀ (exp_pos _)).2 (im_le_im_mul_exp_dist z w) /-- An upper estimate on the complex distance between two points in terms of the hyperbolic distance and the imaginary part of one of the points. -/ @@ -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 := @@ -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 28f5dd099e13f..3c32e2e099f23 100644 --- a/Mathlib/Analysis/Complex/UpperHalfPlane/Topology.lean +++ b/Mathlib/Analysis/Complex/UpperHalfPlane/Topology.lean @@ -127,7 +127,45 @@ scoped notation "↑ₕ" f => f ∘ ofComplex lemma ofComplex_apply (z : ℍ) : ofComplex (z : ℂ) = z := OpenEmbedding.toPartialHomeomorph_left_inv .. -lemma comp_ofComplex (f : ℍ → ℂ) (z : ℍ) : (↑ₕ f) z = f z := by - rw [Function.comp_apply, ofComplex_apply] +lemma ofComplex_apply_eq_ite (w : ℂ) : + ofComplex w = if hw : 0 < w.im then ⟨w, hw⟩ else Classical.choice inferInstance := by + split_ifs with hw + · exact ofComplex_apply ⟨w, hw⟩ + · change (Function.invFunOn UpperHalfPlane.coe Set.univ w) = _ + simp only [invFunOn, dite_eq_right_iff, mem_univ, true_and] + rintro ⟨a, rfl⟩ + exact (a.prop.not_le (by simpa using hw)).elim + +lemma ofComplex_apply_of_im_nonpos {w : ℂ} (hw : w.im ≤ 0) : + ofComplex w = Classical.choice inferInstance := by + simp [ofComplex_apply_eq_ite w, hw] + +lemma ofComplex_apply_eq_of_im_nonpos {w w' : ℂ} (hw : w.im ≤ 0) (hw' : w'.im ≤ 0) : + ofComplex w = ofComplex w' := by + simp [ofComplex_apply_of_im_nonpos, hw, hw'] + +lemma comp_ofComplex (f : ℍ → ℂ) (z : ℍ) : (↑ₕ f) z = f z := + congrArg _ <| ofComplex_apply z + +lemma comp_ofComplex_of_im_pos (f : ℍ → ℂ) (z : ℂ) (hz : 0 < z.im) : (↑ₕ f) z = f ⟨z, hz⟩ := + congrArg _ <| ofComplex_apply ⟨z, hz⟩ + +lemma comp_ofComplex_of_im_le_zero (f : ℍ → ℂ) (z z' : ℂ) (hz : z.im ≤ 0) (hz' : z'.im ≤ 0) : + (↑ₕ f) z = (↑ₕ f) z' := by + simp [ofComplex_apply_of_im_nonpos, hz, hz'] end UpperHalfPlane + +lemma Complex.isConnected_of_upperHalfPlane {s : Set ℂ} (hs₁ : {z | 0 < z.im} ⊆ s) + (hs₂ : s ⊆ {z | 0 ≤ z.im}) : IsConnected s := by + refine IsConnected.subset_closure ?_ hs₁ (by simpa using hs₂) + rw [isConnected_iff_connectedSpace] + exact inferInstanceAs (ConnectedSpace UpperHalfPlane) + +lemma Complex.isConnected_of_lowerHalfPlane {s : Set ℂ} (hs₁ : {z | z.im < 0} ⊆ s) + (hs₂ : s ⊆ {z | z.im ≤ 0}) : IsConnected s := by + rw [← Equiv.star.surjective.image_preimage s] + refine IsConnected.image (f := Equiv.star) ?_ continuous_star.continuousOn + apply Complex.isConnected_of_upperHalfPlane + · exact fun z hz ↦ hs₁ <| show star z ∈ _ by simpa + · exact fun z hz ↦ by simpa using show (star z).im ≤ 0 from hs₂ hz diff --git a/Mathlib/Analysis/ConstantSpeed.lean b/Mathlib/Analysis/ConstantSpeed.lean index 48b06bbe4565c..268a8fb396472 100644 --- a/Mathlib/Analysis/ConstantSpeed.lean +++ b/Mathlib/Analysis/ConstantSpeed.lean @@ -232,9 +232,7 @@ theorem edist_naturalParameterization_eq_zero {f : α → E} {s : Set α} edist (naturalParameterization f s a (variationOnFromTo f s a b)) (f b) = 0 := by dsimp only [naturalParameterization] haveI : Nonempty α := ⟨a⟩ - obtain ⟨cs, hc⟩ := - @Function.invFunOn_pos _ _ _ s (variationOnFromTo f s a) (variationOnFromTo f s a b) - ⟨b, bs, rfl⟩ + obtain ⟨cs, hc⟩ := Function.invFunOn_pos (b := variationOnFromTo f s a b) ⟨b, bs, rfl⟩ rw [variationOnFromTo.eq_left_iff hf as cs bs] at hc apply variationOnFromTo.edist_zero_of_eq_zero hf cs bs hc diff --git a/Mathlib/Analysis/Convex/Basic.lean b/Mathlib/Analysis/Convex/Basic.lean index 24f8e44ef54c4..a06894150ee98 100644 --- a/Mathlib/Analysis/Convex/Basic.lean +++ b/Mathlib/Analysis/Convex/Basic.lean @@ -5,8 +5,11 @@ Authors: Alexander Bentkamp, Yury Kudryashov, Yaël Dillies -/ import Mathlib.Algebra.Order.BigOperators.Ring.Finset 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 @@ -157,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 @@ -405,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 @@ -424,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 _ _) @@ -504,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 @@ -514,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 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..a754f5db135c9 --- /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 := univ.filter (M i · ≠ 0) + have hf (A : Finset n) : A.card ≤ (A.biUnion f).card := 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.card * s := by simp [this] + have h₂ : ∑ i, ∑ j ∈ A.biUnion f, M i j = (A.biUnion f).card * s := by + simp [sum_comm (t := A.biUnion f), hM.2.2, mul_comm s] + suffices A.card * s ≤ (A.biUnion f).card * 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 : ℕ := (Finset.univ.filter fun i : n × n => M i.1 i.2 ≠ 0).card 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' : (univ.filter fun i : n × n => N i.1 i.2 ≠ 0).card < 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 334349d6395d4..219c7807cb05d 100644 --- a/Mathlib/Analysis/Convex/Body.lean +++ b/Mathlib/Analysis/Convex/Body.lean @@ -153,14 +153,14 @@ instance : Module ℝ≥0 (ConvexBody V) where theorem smul_le_of_le (K : ConvexBody V) (h_zero : 0 ∈ K) {a b : ℝ≥0} (h : a ≤ b) : a • K ≤ b • K := by rw [← SetLike.coe_subset_coe, coe_smul', coe_smul'] - by_cases ha : a = 0 - · rw [ha, Set.zero_smul_set K.nonempty, Set.zero_subset] + obtain rfl | ha := eq_zero_or_pos a + · rw [Set.zero_smul_set K.nonempty, Set.zero_subset] exact Set.mem_smul_set.mpr ⟨0, h_zero, smul_zero _⟩ · intro x hx obtain ⟨y, hy, rfl⟩ := Set.mem_smul_set.mp hx - rw [← Set.mem_inv_smul_set_iff₀ ha, smul_smul] - exact Convex.mem_smul_of_zero_mem K.convex h_zero hy - (by rwa [← NNReal.mul_le_iff_le_inv ha, mul_one] : 1 ≤ a⁻¹ * b) + rw [← Set.mem_inv_smul_set_iff₀ ha.ne', smul_smul] + refine Convex.mem_smul_of_zero_mem K.convex h_zero hy (?_ : 1 ≤ a⁻¹ * b) + rwa [le_inv_mul_iff₀ ha, mul_one] end TVS @@ -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 350831d128c98..6bae295f47f1a 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 @@ -79,13 +79,13 @@ theorem mem_convexHull_erase [DecidableEq E] {t : Finset E} (h : ¬AffineIndepen · have hge : 0 < g e := by rw [mem_filter] at hes exact hes.2 - rw [← le_div_iff hge] + rw [← le_div_iff₀ hge] exact w _ hes · calc _ ≤ 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 @@ -95,14 +95,16 @@ theorem mem_convexHull_erase [DecidableEq E] {t : Finset E} (h : ¬AffineIndepen simp only [sub_smul, mul_smul, sum_sub_distrib, ← smul_sum, gcombo, smul_zero, sub_zero, centerMass, fsum, inv_one, one_smul, id] -variable {s : Set E} {x : E} (hx : x ∈ convexHull 𝕜 s) +variable {s : Set E} {x : E} /-- Given a point `x` in the convex hull of a set `s`, this is a finite subset of `s` of minimum cardinality, whose convex hull contains `x`. -/ -noncomputable def minCardFinsetOfMemConvexHull : Finset E := +noncomputable def minCardFinsetOfMemConvexHull (hx : x ∈ convexHull 𝕜 s) : Finset E := Function.argminOn Finset.card Nat.lt_wfRel.2 { t | ↑t ⊆ s ∧ x ∈ convexHull 𝕜 (t : Set E) } <| by simpa only [convexHull_eq_union_convexHull_finite_subsets s, exists_prop, mem_iUnion] using hx +variable (hx : x ∈ convexHull 𝕜 s) + theorem minCardFinsetOfMemConvexHull_subseteq : ↑(minCardFinsetOfMemConvexHull hx) ⊆ s := (Function.argminOn_mem _ _ { t : Finset E | ↑t ⊆ s ∧ x ∈ convexHull 𝕜 (t : Set E) } _).1 @@ -131,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 @@ -170,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 a1b480de2d161..399464ada7406 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] @@ -124,7 +127,7 @@ theorem Finset.centerMass_subset {t' : Finset ι} (ht : t ⊆ t') (h : ∀ i ∈ theorem Finset.centerMass_filter_ne_zero : (t.filter fun i => 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 @@ -376,7 +379,7 @@ lemma Finset.mem_convexHull' {s : Finset E} {x : E} : x ∈ convexHull R (s : Set E) ↔ ∃ w : E → R, (∀ y ∈ s, 0 ≤ w y) ∧ ∑ y ∈ s, w y = 1 ∧ ∑ y ∈ s, w y • y = x := by rw [mem_convexHull] - refine exists_congr fun w ↦ and_congr_right' $ and_congr_right fun hw ↦ ?_ + refine exists_congr fun w ↦ and_congr_right' <| and_congr_right fun hw ↦ ?_ simp_rw [centerMass_eq_of_sum_1 _ _ hw, id_eq] theorem Set.Finite.convexHull_eq {s : Set E} (hs : s.Finite) : convexHull R s = @@ -481,7 +484,7 @@ theorem Set.Finite.convexHull_eq_image {s : Set E} (hs : s.Finite) : convexHull letI := hs.fintype rw [← convexHull_basis_eq_stdSimplex, LinearMap.image_convexHull, ← Set.range_comp] apply congr_arg - simp_rw [Function.comp] + simp_rw [Function.comp_def] convert Subtype.range_coe.symm simp [LinearMap.sum_apply, ite_smul, Finset.filter_eq, Finset.mem_univ] @@ -517,13 +520,13 @@ variable {s t t₁ t₂ : Finset E} lemma AffineIndependent.convexHull_inter (hs : AffineIndependent R ((↑) : s → E)) (ht₁ : t₁ ⊆ s) (ht₂ : t₂ ⊆ s) : convexHull R (t₁ ∩ t₂ : Set E) = convexHull R t₁ ∩ convexHull R t₂ := by - refine (Set.subset_inter (convexHull_mono inf_le_left) $ + refine (Set.subset_inter (convexHull_mono inf_le_left) <| convexHull_mono inf_le_right).antisymm ?_ simp_rw [Set.subset_def, mem_inter_iff, Set.inf_eq_inter, ← coe_inter, mem_convexHull'] rintro x ⟨⟨w₁, h₁w₁, h₂w₁, h₃w₁⟩, w₂, -, h₂w₂, h₃w₂⟩ let w (x : E) : R := (if x ∈ t₁ then w₁ x else 0) - if x ∈ t₂ then w₂ x else 0 have h₁w : ∑ i ∈ s, w i = 0 := by simp [w, Finset.inter_eq_right.2, *] - replace hs := hs.eq_zero_of_sum_eq_zero_subtype h₁w $ by + replace hs := hs.eq_zero_of_sum_eq_zero_subtype h₁w <| by simp only [w, sub_smul, zero_smul, ite_smul, Finset.sum_sub_distrib, ← Finset.sum_filter, h₃w₁, Finset.filter_mem_eq_inter, Finset.inter_eq_right.2 ht₁, Finset.inter_eq_right.2 ht₂, h₃w₂, sub_self] @@ -593,7 +596,7 @@ lemma mem_convexHull_pi (h : ∀ i ∈ s, x i ∈ convexHull 𝕜 (t i)) : x ∈ @[simp] lemma convexHull_pi (s : Set ι) (t : Π i, Set (E i)) : convexHull 𝕜 (s.pi t) = s.pi (fun i ↦ convexHull 𝕜 (t i)) := - Set.Subset.antisymm (convexHull_min (Set.pi_mono fun _ _ ↦ subset_convexHull _ _) $ convex_pi $ + Set.Subset.antisymm (convexHull_min (Set.pi_mono fun _ _ ↦ subset_convexHull _ _) <| convex_pi <| fun _ _ ↦ convex_convexHull _ _) fun _ ↦ mem_convexHull_pi end pi diff --git a/Mathlib/Analysis/Convex/Cone/Closure.lean b/Mathlib/Analysis/Convex/Cone/Closure.lean index a467f4ce5c3a5..2e5daf051b7a5 100644 --- a/Mathlib/Analysis/Convex/Cone/Closure.lean +++ b/Mathlib/Analysis/Convex/Cone/Closure.lean @@ -51,7 +51,7 @@ variable {E : Type*} [AddCommMonoid E] [TopologicalSpace E] [ContinuousAdd E] [M [ContinuousConstSMul 𝕜 E] lemma toConvexCone_closure_pointed (K : PointedCone 𝕜 E) : (K : ConvexCone 𝕜 E).closure.Pointed := - subset_closure $ PointedCone.toConvexCone_pointed _ + subset_closure <| PointedCone.toConvexCone_pointed _ /-- The closure of a pointed cone inside a topological space as a pointed cone. This construction is mainly used for defining maps between proper cones. -/ 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 555882971d866..8bf4feeae7d46 100644 --- a/Mathlib/Analysis/Convex/Cone/InnerDual.lean +++ b/Mathlib/Analysis/Convex/Cone/InnerDual.lean @@ -147,6 +147,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) @@ -181,7 +182,7 @@ theorem ConvexCone.hyperplane_separation_of_nonempty_of_isClosed_of_nmem (K : Co _ = ⟪b - z, b - z + z⟫_ℝ := (inner_add_right _ _ _).symm _ = ⟪b - z, b⟫_ℝ := by rw [sub_add_cancel] -/-- The inner dual of inner dual of a non-empty, closed convex cone is itself. -/ +/-- The inner dual of inner dual of a non-empty, closed convex cone is itself. -/ theorem ConvexCone.innerDualCone_of_innerDualCone_eq_self (K : ConvexCone ℝ H) (ne : (K : Set H).Nonempty) (hc : IsClosed (K : Set H)) : ((K : Set H).innerDualCone : Set H).innerDualCone = K := by 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 20066fe9abaa8..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) @@ -239,7 +239,7 @@ lemma convexOn_of_hasDerivWithinAt2_nonneg {D : Set ℝ} (hD : Convex ℝ D) {f convert hf''₀ _ hx using 1 dsimp rw [deriv_eqOn isOpen_interior (fun y hy ↦ ?_) hx] - exact (hf'' _ hy).congr this $ by rw [this hy] + exact (hf'' _ hy).congr this <| by rw [this hy] /-- If a function `f` is continuous on a convex set `D ⊆ ℝ`, is twice differentiable on its interior, and `f''` is nonpositive on the interior, then `f` is concave on `D`. -/ @@ -255,7 +255,7 @@ lemma concaveOn_of_hasDerivWithinAt2_nonpos {D : Set ℝ} (hD : Convex ℝ D) {f convert hf''₀ _ hx using 1 dsimp rw [deriv_eqOn isOpen_interior (fun y hy ↦ ?_) hx] - exact (hf'' _ hy).congr this $ by rw [this hy] + exact (hf'' _ hy).congr this <| by rw [this hy] /-- If a function `f` is continuous on a convex set `D ⊆ ℝ` and `f''` is strictly positive on the interior, then `f` is strictly convex on `D`. diff --git a/Mathlib/Analysis/Convex/Extrema.lean b/Mathlib/Analysis/Convex/Extrema.lean index 336609efc130a..53797cd0f3710 100644 --- a/Mathlib/Analysis/Convex/Extrema.lean +++ b/Mathlib/Analysis/Convex/Extrema.lean @@ -5,8 +5,8 @@ Authors: Frédéric Dupuis -/ import Mathlib.Analysis.Convex.Function import Mathlib.Topology.Algebra.Affine -import Mathlib.Topology.MetricSpace.Pseudo.Lemmas import Mathlib.Topology.Order.LocalExtr +import Mathlib.Topology.MetricSpace.Pseudo.Lemmas /-! # Minima and maxima of convex functions diff --git a/Mathlib/Analysis/Convex/Gauge.lean b/Mathlib/Analysis/Convex/Gauge.lean index 84b136c6fc755..df43239a123de 100644 --- a/Mathlib/Analysis/Convex/Gauge.lean +++ b/Mathlib/Analysis/Convex/Gauge.lean @@ -67,7 +67,7 @@ private theorem gauge_set_bddBelow : BddBelow { r : ℝ | 0 < r ∧ x ∈ r • ⟨0, fun _ hr => hr.1.le⟩ /-- If the given subset is `Absorbent` then the set we take an infimum over in `gauge` is nonempty, -which is useful for proving many properties about the gauge. -/ +which is useful for proving many properties about the gauge. -/ theorem Absorbent.gauge_set_nonempty (absorbs : Absorbent ℝ s) : { r : ℝ | 0 < r ∧ x ∈ r • s }.Nonempty := let ⟨r, hr₁, hr₂⟩ := (absorbs x).exists_pos @@ -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 @@ -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'] @@ -359,17 +359,17 @@ theorem gauge_lt_one_eq_self_of_isOpen (hs₁ : Convex ℝ s) (hs₀ : (0 : E) convert interior_subset_gauge_lt_one s exact hs₂.interior_eq.symm --- Porting note: droped unneeded assumptions +-- Porting note: dropped unneeded assumptions theorem gauge_lt_one_of_mem_of_isOpen (hs₂ : IsOpen s) {x : E} (hx : x ∈ s) : gauge s x < 1 := interior_subset_gauge_lt_one s <| by rwa [hs₂.interior_eq] --- Porting note: droped unneeded assumptions +-- Porting note: dropped unneeded assumptions theorem gauge_lt_of_mem_smul (x : E) (ε : ℝ) (hε : 0 < ε) (hs₂ : IsOpen s) (hx : x ∈ ε • 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) : @@ -538,10 +538,6 @@ theorem gauge_ball (hr : 0 ≤ r) (x : E) : gauge (ball (0 : E) r) x = ‖x‖ / simp_rw [mem_ball_zero_iff, norm_neg] exact fun _ => id -@[deprecated gauge_ball (since := "2023-07-24")] -theorem gauge_ball' (hr : 0 < r) (x : E) : gauge (ball (0 : E) r) x = ‖x‖ / r := - gauge_ball hr.le x - @[simp] theorem gauge_closure_zero : gauge (closure (0 : Set E)) = 0 := funext fun x ↦ by simp only [← singleton_zero, gauge_def', mem_closure_zero_iff_norm, norm_smul, mul_eq_zero, @@ -570,7 +566,7 @@ theorem gauge_closedBall (hr : 0 ≤ r) (x : E) : gauge (closedBall (0 : E) r) x theorem mul_gauge_le_norm (hs : Metric.ball (0 : E) r ⊆ s) : r * gauge s x ≤ ‖x‖ := by obtain hr | hr := le_or_lt r 0 · exact (mul_nonpos_of_nonpos_of_nonneg hr <| gauge_nonneg _).trans (norm_nonneg _) - rw [mul_comm, ← le_div_iff hr, ← gauge_ball hr.le] + rw [mul_comm, ← le_div_iff₀ hr, ← gauge_ball hr.le] exact gauge_mono (absorbent_ball_zero hr) hs x theorem Convex.lipschitzWith_gauge {r : ℝ≥0} (hc : Convex ℝ s) (hr : 0 < r) diff --git a/Mathlib/Analysis/Convex/GaugeRescale.lean b/Mathlib/Analysis/Convex/GaugeRescale.lean index 76930a882f4c9..5355e87f1273a 100644 --- a/Mathlib/Analysis/Convex/GaugeRescale.lean +++ b/Mathlib/Analysis/Convex/GaugeRescale.lean @@ -79,7 +79,7 @@ theorem gaugeRescale_gaugeRescale {s t u : Set E} (hta : Absorbent ℝ t) (htb : (x : E) : gaugeRescale t u (gaugeRescale s t x) = gaugeRescale s u x := by rcases eq_or_ne x 0 with rfl | hx; · simp rw [gaugeRescale_def s t x, gaugeRescale_smul, gaugeRescale, gaugeRescale, smul_smul, - div_mul_div_cancel] + div_mul_div_cancel₀] exacts [((gauge_pos hta htb).2 hx).ne', div_nonneg (gauge_nonneg _) (gauge_nonneg _)] /-- `gaugeRescale` bundled as an `Equiv`. -/ @@ -115,7 +115,7 @@ theorem continuous_gaugeRescale {s t : Set E} (hs : Convex ℝ s) (hs₀ : s ∈ rcases eq_or_ne x 0 with rfl | hx · rw [ContinuousAt, gaugeRescale_zero] nth_rewrite 2 [← comap_gauge_nhds_zero htb ht₀] - simp only [tendsto_comap_iff, (· ∘ ·), gauge_gaugeRescale _ hta htb] + simp only [tendsto_comap_iff, Function.comp_def, gauge_gaugeRescale _ hta htb] exact tendsto_gauge_nhds_zero hs₀ · exact ((continuousAt_gauge hs hs₀).div (continuousAt_gauge ht ht₀) ((gauge_pos hta htb).2 hx).ne').smul continuousAt_id diff --git a/Mathlib/Analysis/Convex/Integral.lean b/Mathlib/Analysis/Convex/Integral.lean index 435c9f7ec4a19..dd75c412a4ffc 100644 --- a/Mathlib/Analysis/Convex/Integral.lean +++ b/Mathlib/Analysis/Convex/Integral.lean @@ -68,7 +68,7 @@ theorem Convex.integral_mem [IsProbabilityMeasure μ] (hs : Convex ℝ s) (hsc : set G : ℕ → SimpleFunc α E := SimpleFunc.approxOn _ hgm.measurable (range g ∩ s) y₀ h₀ have : Tendsto (fun n => (G n).integral μ) atTop (𝓝 <| ∫ x, g x ∂μ) := tendsto_integral_approxOn_of_measurable hfi _ hg _ (integrable_const _) - refine hsc.mem_of_tendsto this (eventually_of_forall fun n => hs.sum_mem ?_ ?_ ?_) + refine hsc.mem_of_tendsto this (Eventually.of_forall fun n => hs.sum_mem ?_ ?_ ?_) · exact fun _ _ => ENNReal.toReal_nonneg · rw [← ENNReal.toReal_sum, (G n).sum_range_measure_preimage_singleton, measure_univ, ENNReal.one_toReal] @@ -328,7 +328,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 7e5b5e4ee2e13..82cc1b1b0da2d 100644 --- a/Mathlib/Analysis/Convex/Intrinsic.lean +++ b/Mathlib/Analysis/Convex/Intrinsic.lean @@ -116,8 +116,8 @@ alias ⟨Set.Nonempty.ofIntrinsicClosure, Set.Nonempty.intrinsicClosure⟩ := in @[simp] theorem intrinsicInterior_singleton (x : P) : intrinsicInterior 𝕜 ({x} : Set P) = {x} := by - simpa only [intrinsicInterior, preimage_coe_affineSpan_singleton, interior_univ, image_univ, - Subtype.range_coe] using coe_affineSpan_singleton _ _ _ + simp only [intrinsicInterior, preimage_coe_affineSpan_singleton, interior_univ, image_univ, + Subtype.range_coe_subtype, mem_affineSpan_singleton, setOf_eq_eq_singleton] @[simp] theorem intrinsicFrontier_singleton (x : P) : intrinsicFrontier 𝕜 ({x} : Set P) = ∅ := by @@ -125,8 +125,8 @@ theorem intrinsicFrontier_singleton (x : P) : intrinsicFrontier 𝕜 ({x} : Set @[simp] theorem intrinsicClosure_singleton (x : P) : intrinsicClosure 𝕜 ({x} : Set P) = {x} := by - simpa only [intrinsicClosure, preimage_coe_affineSpan_singleton, closure_univ, image_univ, - Subtype.range_coe] using coe_affineSpan_singleton _ _ _ + simp only [intrinsicClosure, preimage_coe_affineSpan_singleton, closure_univ, image_univ, + Subtype.range_coe_subtype, mem_affineSpan_singleton, setOf_eq_eq_singleton] /-! Note that neither `intrinsicInterior` nor `intrinsicFrontier` is monotone. @@ -223,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] @@ -236,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] @@ -249,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 cbfbf7d8bf46b..93f195e014393 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**. @@ -244,25 +243,31 @@ end Jensen section MaximumPrinciple variable [LinearOrderedField 𝕜] [AddCommGroup E] [LinearOrderedAddCommGroup β] [Module 𝕜 E] - [Module 𝕜 β] [OrderedSMul 𝕜 β] {s : Set E} {f : E → β} {t : Finset ι} {w : ι → 𝕜} {p : ι → E} + [Module 𝕜 β] [OrderedSMul 𝕜 β] {s : Set E} {f : E → β} {w : ι → 𝕜} {p : ι → E} {x y z : E} -theorem le_sup_of_mem_convexHull {s : Finset E} (hf : ConvexOn 𝕜 (convexHull 𝕜 (s : Set E)) f) - (hx : x ∈ convexHull 𝕜 (s : Set E)) : - f x ≤ s.sup' (coe_nonempty.1 <| convexHull_nonempty_iff.1 ⟨x, hx⟩) f := by +theorem ConvexOn.le_sup_of_mem_convexHull {t : Finset E} (hf : ConvexOn 𝕜 s f) (hts : ↑t ⊆ s) + (hx : x ∈ convexHull 𝕜 (t : Set E)) : + f x ≤ t.sup' (coe_nonempty.1 <| convexHull_nonempty_iff.1 ⟨x, hx⟩) f := by obtain ⟨w, hw₀, hw₁, rfl⟩ := mem_convexHull.1 hx - exact (hf.map_centerMass_le hw₀ (by positivity) <| subset_convexHull _ _).trans + exact (hf.map_centerMass_le hw₀ (by positivity) hts).trans (centerMass_le_sup hw₀ <| by positivity) -theorem inf_le_of_mem_convexHull {s : Finset E} (hf : ConcaveOn 𝕜 (convexHull 𝕜 (s : Set E)) f) - (hx : x ∈ convexHull 𝕜 (s : Set E)) : - s.inf' (coe_nonempty.1 <| convexHull_nonempty_iff.1 ⟨x, hx⟩) f ≤ f x := - le_sup_of_mem_convexHull hf.dual hx +theorem ConvexOn.inf_le_of_mem_convexHull {t : Finset E} (hf : ConcaveOn 𝕜 s f) (hts : ↑t ⊆ s) + (hx : x ∈ convexHull 𝕜 (t : Set E)) : + t.inf' (coe_nonempty.1 <| convexHull_nonempty_iff.1 ⟨x, hx⟩) f ≤ f x := + hf.dual.le_sup_of_mem_convexHull hts hx + +@[deprecated (since := "2024-08-25")] +alias le_sup_of_mem_convexHull := ConvexOn.le_sup_of_mem_convexHull + +@[deprecated (since := "2024-08-25")] +alias inf_le_of_mem_convexHull := ConvexOn.inf_le_of_mem_convexHull /-- If a function `f` is convex on `s`, then the value it takes at some center of mass of points of `s` is less than the value it takes on one of those points. -/ -theorem ConvexOn.exists_ge_of_centerMass (h : ConvexOn 𝕜 s f) (hw₀ : ∀ i ∈ t, 0 ≤ w i) - (hw₁ : 0 < ∑ i ∈ t, w i) (hp : ∀ i ∈ t, p i ∈ s) : +lemma ConvexOn.exists_ge_of_centerMass {t : Finset ι} (h : ConvexOn 𝕜 s f) + (hw₀ : ∀ i ∈ t, 0 ≤ w i) (hw₁ : 0 < ∑ i ∈ t, w i) (hp : ∀ i ∈ t, p i ∈ s) : ∃ 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? @@ -277,49 +282,57 @@ theorem ConvexOn.exists_ge_of_centerMass (h : ConvexOn 𝕜 s f) (hw₀ : ∀ i /-- If a function `f` is concave on `s`, then the value it takes at some center of mass of points of `s` is greater than the value it takes on one of those points. -/ -theorem ConcaveOn.exists_le_of_centerMass (h : ConcaveOn 𝕜 s f) (hw₀ : ∀ i ∈ t, 0 ≤ w i) - (hw₁ : 0 < ∑ i ∈ t, w i) (hp : ∀ i ∈ t, p i ∈ s) : ∃ i ∈ t, f (p i) ≤ f (t.centerMass w p) := - ConvexOn.exists_ge_of_centerMass (β := βᵒᵈ) h hw₀ hw₁ hp +lemma ConcaveOn.exists_le_of_centerMass {t : Finset ι} (h : ConcaveOn 𝕜 s f) + (hw₀ : ∀ i ∈ t, 0 ≤ w i) (hw₁ : 0 < ∑ i ∈ t, w i) (hp : ∀ i ∈ t, p i ∈ s) : + ∃ i ∈ t, f (p i) ≤ f (t.centerMass w p) := h.dual.exists_ge_of_centerMass hw₀ hw₁ hp /-- **Maximum principle** for convex functions. If a function `f` is convex on the convex hull of `s`, then the eventual maximum of `f` on `convexHull 𝕜 s` lies in `s`. -/ -theorem ConvexOn.exists_ge_of_mem_convexHull (hf : ConvexOn 𝕜 (convexHull 𝕜 s) f) {x} - (hx : x ∈ convexHull 𝕜 s) : ∃ y ∈ s, f x ≤ f y := by +lemma ConvexOn.exists_ge_of_mem_convexHull {t : Set E} (hf : ConvexOn 𝕜 s f) (hts : t ⊆ s) + (hx : x ∈ convexHull 𝕜 t) : ∃ y ∈ t, f x ≤ f y := by rw [_root_.convexHull_eq] at hx obtain ⟨α, t, w, p, hw₀, hw₁, hp, rfl⟩ := hx - rcases hf.exists_ge_of_centerMass hw₀ (hw₁.symm ▸ zero_lt_one) fun i hi => - subset_convexHull 𝕜 s (hp i hi) with - ⟨i, hit, Hi⟩ + obtain ⟨i, hit, Hi⟩ := hf.exists_ge_of_centerMass hw₀ (hw₁.symm ▸ zero_lt_one) + fun i hi ↦ hts (hp i hi) exact ⟨p i, hp i hit, Hi⟩ /-- **Minimum principle** for concave functions. If a function `f` is concave on the convex hull of `s`, then the eventual minimum of `f` on `convexHull 𝕜 s` lies in `s`. -/ -theorem ConcaveOn.exists_le_of_mem_convexHull (hf : ConcaveOn 𝕜 (convexHull 𝕜 s) f) {x} - (hx : x ∈ convexHull 𝕜 s) : ∃ y ∈ s, f y ≤ f x := - ConvexOn.exists_ge_of_mem_convexHull (β := βᵒᵈ) hf hx +lemma ConcaveOn.exists_le_of_mem_convexHull {t : Set E} (hf : ConcaveOn 𝕜 s f) (hts : t ⊆ s) + (hx : x ∈ convexHull 𝕜 t) : ∃ y ∈ t, f y ≤ f x := hf.dual.exists_ge_of_mem_convexHull hts hx /-- **Maximum principle** for convex functions on a segment. If a function `f` is convex on the segment `[x, y]`, then the eventual maximum of `f` on `[x, y]` is at `x` or `y`. -/ -lemma ConvexOn.le_max_of_mem_segment (hf : ConvexOn 𝕜 [x -[𝕜] y] f) (hz : z ∈ [x -[𝕜] y]) : - f z ≤ max (f x) (f y) := by - rw [← convexHull_pair] at hf hz; simpa using hf.exists_ge_of_mem_convexHull hz +lemma ConvexOn.le_max_of_mem_segment (hf : ConvexOn 𝕜 s f) (hx : x ∈ s) (hy : y ∈ s) + (hz : z ∈ [x -[𝕜] y]) : f z ≤ max (f x) (f y) := by + rw [← convexHull_pair] at hz; simpa using hf.exists_ge_of_mem_convexHull (pair_subset hx hy) hz /-- **Minimum principle** for concave functions on a segment. If a function `f` is concave on the segment `[x, y]`, then the eventual minimum of `f` on `[x, y]` is at `x` or `y`. -/ -lemma ConcaveOn.min_le_of_mem_segment (hf : ConcaveOn 𝕜 [x -[𝕜] y] f) (hz : z ∈ [x -[𝕜] y]) : - min (f x) (f y) ≤ f z := by - rw [← convexHull_pair] at hf hz; simpa using hf.exists_le_of_mem_convexHull hz +lemma ConcaveOn.min_le_of_mem_segment (hf : ConcaveOn 𝕜 s f) (hx : x ∈ s) (hy : y ∈ s) + (hz : z ∈ [x -[𝕜] y]) : min (f x) (f y) ≤ f z := hf.dual.le_max_of_mem_segment hx hy hz /-- **Maximum principle** for convex functions on an interval. If a function `f` is convex on the interval `[x, y]`, then the eventual maximum of `f` on `[x, y]` is at `x` or `y`. -/ -lemma ConvexOn.le_max_of_mem_Icc {f : 𝕜 → β} {x y z : 𝕜} (hf : ConvexOn 𝕜 (Icc x y) f) - (hz : z ∈ Icc x y) : f z ≤ max (f x) (f y) := by - rw [← segment_eq_Icc (hz.1.trans hz.2)] at hf hz; exact hf.le_max_of_mem_segment hz +lemma ConvexOn.le_max_of_mem_Icc {s : Set 𝕜} {f : 𝕜 → β} {x y z : 𝕜} (hf : ConvexOn 𝕜 s f) + (hx : x ∈ s) (hy : y ∈ s) (hz : z ∈ Icc x y) : f z ≤ max (f x) (f y) := by + rw [← segment_eq_Icc (hz.1.trans hz.2)] at hz; exact hf.le_max_of_mem_segment hx hy hz /-- **Minimum principle** for concave functions on an interval. If a function `f` is concave on the interval `[x, y]`, then the eventual minimum of `f` on `[x, y]` is at `x` or `y`. -/ -lemma ConcaveOn.min_le_of_mem_Icc {f : 𝕜 → β} {x y z : 𝕜} (hf : ConcaveOn 𝕜 (Icc x y) f) - (hz : z ∈ Icc x y) : min (f x) (f y) ≤ f z := by - rw [← segment_eq_Icc (hz.1.trans hz.2)] at hf hz; exact hf.min_le_of_mem_segment hz +lemma ConcaveOn.min_le_of_mem_Icc {s : Set 𝕜} {f : 𝕜 → β} {x y z : 𝕜} (hf : ConcaveOn 𝕜 s f) + (hx : x ∈ s) (hy : y ∈ s) (hz : z ∈ Icc x y) : min (f x) (f y) ≤ f z := + hf.dual.le_max_of_mem_Icc hx hy hz + +lemma ConvexOn.bddAbove_convexHull {s t : Set E} (hst : s ⊆ t) (hf : ConvexOn 𝕜 t f) : + BddAbove (f '' s) → BddAbove (f '' convexHull 𝕜 s) := by + rintro ⟨b, hb⟩ + refine ⟨b, ?_⟩ + rintro _ ⟨x, hx, rfl⟩ + obtain ⟨y, hy, hxy⟩ := hf.exists_ge_of_mem_convexHull hst hx + exact hxy.trans <| hb <| mem_image_of_mem _ hy + +lemma ConcaveOn.bddBelow_convexHull {s t : Set E} (hst : s ⊆ t) (hf : ConcaveOn 𝕜 t f) : + BddBelow (f '' s) → BddBelow (f '' convexHull 𝕜 s) := hf.dual.bddAbove_convexHull hst end MaximumPrinciple diff --git a/Mathlib/Analysis/Convex/Join.lean b/Mathlib/Analysis/Convex/Join.lean index a8641487cfccd..590ebaa4aa614 100644 --- a/Mathlib/Analysis/Convex/Join.lean +++ b/Mathlib/Analysis/Convex/Join.lean @@ -113,19 +113,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 +149,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 6dec1b9d305d3..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 @@ -59,12 +59,12 @@ theorem addHaar_frontier (hs : Convex ℝ s) : μ (frontier s) = 0 := by `μ (closure s) ≤ μ (interior s)`. -/ replace hb : μ (interior s) ≠ ∞ := (hb.subset interior_subset).measure_lt_top.ne suffices μ (closure s) ≤ μ (interior s) by - rwa [frontier, measure_diff interior_subset_closure isOpen_interior.measurableSet hb, + rwa [frontier, measure_diff interior_subset_closure isOpen_interior.nullMeasurableSet hb, tsub_eq_zero_iff_le] /- Due to `Convex.closure_subset_image_homothety_interior_of_one_lt`, for any `r > 1` we have `closure s ⊆ homothety x r '' interior s`, hence `μ (closure s) ≤ r ^ d * μ (interior s)`, where `d = finrank ℝ E`. -/ - set d : ℕ := 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 2359391cb0ece..bfb9ac2e29cd3 100644 --- a/Mathlib/Analysis/Convex/Normed.lean +++ b/Mathlib/Analysis/Convex/Normed.lean @@ -8,6 +8,7 @@ import Mathlib.Analysis.Convex.Jensen import Mathlib.Analysis.Convex.Topology import Mathlib.Analysis.Normed.Group.Pointwise import Mathlib.Analysis.Normed.Affine.AddTorsor +import Mathlib.Analysis.Normed.Affine.AddTorsorBases /-! # Topological and metric properties of convex sets in normed spaces @@ -26,9 +27,10 @@ We prove the following facts: variable {ι : Type*} {E P : Type*} -open Metric Set -open scoped Convex +open AffineBasis Module Metric Set +open scoped Convex Pointwise Topology +section SeminormedAddCommGroup variable [SeminormedAddCommGroup E] [NormedSpace ℝ E] [PseudoMetricSpace P] [NormedAddTorsor E P] variable {s t : Set E} @@ -74,7 +76,7 @@ theorem Convex.cthickening (hs : Convex ℝ s) (δ : ℝ) : Convex ℝ (cthicken of `s` at distance at least `dist x y` from `y`. -/ theorem convexHull_exists_dist_ge {s : Set E} {x : E} (hx : x ∈ convexHull ℝ s) (y : E) : ∃ x' ∈ s, dist x y ≤ dist x' y := - (convexOn_dist y (convex_convexHull ℝ _)).exists_ge_of_mem_convexHull hx + (convexOn_dist y (convex_convexHull ℝ _)).exists_ge_of_mem_convexHull (subset_convexHull ..) hx /-- Given a point `x` in the convex hull of `s` and a point `y` in the convex hull of `t`, there exist points `x' ∈ s` and `y' ∈ t` at distance at least `dist x y`. -/ @@ -133,3 +135,56 @@ theorem isConnected_setOf_sameRay_and_ne_zero {x : E} (hx : x ≠ 0) : IsConnected { y | SameRay ℝ x y ∧ y ≠ 0 } := by simp_rw [← exists_pos_left_iff_sameRay_and_ne_zero hx] exact isConnected_Ioi.image _ (continuous_id.smul continuous_const).continuousOn + +end SeminormedAddCommGroup + +section NormedAddCommGroup +variable [NormedAddCommGroup E] [NormedSpace ℝ E] [FiniteDimensional ℝ E] {s : Set E} {x : E} + +/-- We can intercalate a simplex between a point and one of its neighborhoods. -/ +lemma exists_mem_interior_convexHull_affineBasis (hs : s ∈ 𝓝 x) : + ∃ b : AffineBasis (Fin (finrank ℝ E + 1)) ℝ E, + x ∈ interior (convexHull ℝ (range b)) ∧ convexHull ℝ (range b) ⊆ s := by + classical + -- By translating, WLOG `x` is the origin. + wlog hx : x = 0 + · obtain ⟨b, hb⟩ := this (s := -x +ᵥ s) (by simpa using vadd_mem_nhds_vadd (-x) hs) rfl + use x +ᵥ b + simpa [subset_set_vadd_iff, mem_vadd_set_iff_neg_vadd_mem, convexHull_vadd, interior_vadd, + Pi.vadd_def, -vadd_eq_add, vadd_eq_add (a := -x), ← Set.vadd_set_range] using hb + subst hx + -- The strategy is now to find an arbitrary maximal spanning simplex (aka an affine basis)... + obtain ⟨b⟩ := exists_affineBasis_of_finiteDimensional + (ι := Fin (finrank ℝ E + 1)) (k := ℝ) (P := E) (by simp) + -- ... translate it to contain the origin... + set c : AffineBasis (Fin (finrank ℝ E + 1)) ℝ E := -Finset.univ.centroid ℝ b +ᵥ b + have hc₀ : 0 ∈ interior (convexHull ℝ (range c) : Set E) := by + simpa [c, convexHull_vadd, interior_vadd, range_add, Pi.vadd_def, mem_vadd_set_iff_neg_vadd_mem] + using b.centroid_mem_interior_convexHull + set cnorm := Finset.univ.sup' Finset.univ_nonempty (fun i ↦ ‖c i‖) + have hcnorm : range c ⊆ closedBall 0 (cnorm + 1) := by + simpa only [cnorm, subset_def, Finset.mem_coe, mem_closedBall, dist_zero_right, + ← sub_le_iff_le_add, Finset.le_sup'_iff, forall_mem_range] using fun i ↦ ⟨i, by simp⟩ + -- ... and finally scale it to fit inside the neighborhood `s`. + obtain ⟨ε, hε, hεs⟩ := Metric.mem_nhds_iff.1 hs + set ε' : ℝ := ε / 2 / (cnorm + 1) + have hc' : 0 < cnorm + 1 := by + have : 0 ≤ cnorm := Finset.le_sup'_of_le _ (Finset.mem_univ 0) (norm_nonneg _) + positivity + have hε' : 0 < ε' := by positivity + set d : AffineBasis (Fin (finrank ℝ E + 1)) ℝ E := Units.mk0 ε' hε'.ne' • c + have hε₀ : 0 < ε / 2 := by positivity + have hdnorm : (range d : Set E) ⊆ closedBall 0 (ε / 2) := by + simp [d, Set.set_smul_subset_iff₀ hε'.ne', hε₀.le, _root_.smul_closedBall, abs_of_nonneg hε'.le, + range_subset_iff, norm_smul] + simpa [ε', hε₀.ne', range_subset_iff, ← mul_div_right_comm (ε / 2), div_le_iff₀ hc', + mul_le_mul_left hε₀] using hcnorm + refine ⟨d, ?_, ?_⟩ + · simpa [d, Pi.smul_def, range_smul, interior_smul₀, convexHull_smul, zero_mem_smul_set_iff, + hε'.ne'] + · calc + convexHull ℝ (range d) ⊆ closedBall 0 (ε / 2) := convexHull_min hdnorm (convex_closedBall ..) + _ ⊆ ball 0 ε := closedBall_subset_ball (by linarith) + _ ⊆ s := hεs + +end NormedAddCommGroup diff --git a/Mathlib/Analysis/Convex/Radon.lean b/Mathlib/Analysis/Convex/Radon.lean index ee505ba41b251..f297649b6f470 100644 --- a/Mathlib/Analysis/Convex/Radon.lean +++ b/Mathlib/Analysis/Convex/Radon.lean @@ -62,7 +62,7 @@ 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 ι} diff --git a/Mathlib/Analysis/Convex/Segment.lean b/Mathlib/Analysis/Convex/Segment.lean index 87adc0a70ac2e..9f5026dbeb8cc 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 diff --git a/Mathlib/Analysis/Convex/Side.lean b/Mathlib/Analysis/Convex/Side.lean index 13933585a56e0..45bc7d0036eb8 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 := @@ -411,9 +407,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 +580,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 +771,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 +812,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/SimplicialComplex/Basic.lean b/Mathlib/Analysis/Convex/SimplicialComplex/Basic.lean index b1f12fdb8b073..41111c8c7ea85 100644 --- a/Mathlib/Analysis/Convex/SimplicialComplex/Basic.lean +++ b/Mathlib/Analysis/Convex/SimplicialComplex/Basic.lean @@ -72,7 +72,7 @@ variable {K : SimplicialComplex 𝕜 E} {s t : Finset E} {x : E} /-- A `Finset` belongs to a `SimplicialComplex` if it's a face of it. -/ instance : Membership (Finset E) (SimplicialComplex 𝕜 E) := - ⟨fun s K => s ∈ K.faces⟩ + ⟨fun K s => s ∈ K.faces⟩ /-- The underlying space of a simplicial complex is the union of its faces. -/ def space (K : SimplicialComplex 𝕜 E) : Set E := @@ -166,7 +166,7 @@ theorem face_subset_face_iff (hs : s ∈ K.faces) (ht : t ∈ K.faces) : ⟨fun h _ hxs => (vertex_mem_convexHull_iff (K.down_closed hs (Finset.singleton_subset_iff.2 hxs) <| singleton_ne_empty _) ht).1 - (h (subset_convexHull 𝕜 (↑s) hxs)), + (h (subset_convexHull 𝕜 (E := E) s hxs)), convexHull_mono⟩ /-! ### Facets -/ diff --git a/Mathlib/Analysis/Convex/Slope.lean b/Mathlib/Analysis/Convex/Slope.lean index 4bfa3fe7e4643..38072902d3e91 100644 --- a/Mathlib/Analysis/Convex/Slope.lean +++ b/Mathlib/Analysis/Convex/Slope.lean @@ -113,7 +113,7 @@ theorem convexOn_of_slope_mono_adjacent (hs : Convex 𝕜 s) simp_rw [div_eq_iff hxz.ne', ← hab] ring rwa [sub_mul, sub_mul, sub_le_iff_le_add', ← add_sub_assoc, le_sub_iff_add_le, ← mul_add, - sub_add_sub_cancel, ← le_div_iff hxz, add_div, mul_div_assoc, mul_div_assoc, mul_comm (f x), + sub_add_sub_cancel, ← le_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 @@ -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 @@ -221,7 +221,7 @@ theorem ConvexOn.secant_mono_aux1 (hf : ConvexOn 𝕜 s f) {x y z : 𝕜} (hx : have hxy' : 0 < y - x := by linarith have hyz' : 0 < z - y := by linarith have hxz' : 0 < z - x := by linarith - rw [← le_div_iff' hxz'] + rw [← le_div_iff₀' hxz'] have ha : 0 ≤ (z - y) / (z - x) := by positivity have hb : 0 ≤ (y - x) / (z - x) := by positivity calc @@ -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 0d78d9d0e1048..981b12a32e26c 100644 --- a/Mathlib/Analysis/Convex/SpecificFunctions/Deriv.lean +++ b/Mathlib/Analysis/Convex/SpecificFunctions/Deriv.lean @@ -67,17 +67,18 @@ theorem Finset.prod_nonneg_of_card_nonpos_even {α β : Type*} [LinearOrderedCom theorem int_prod_range_nonneg (m : ℤ) (n : ℕ) (hn : Even n) : 0 ≤ ∏ k ∈ Finset.range n, (m - k) := by rcases hn with ⟨n, rfl⟩ - induction' n with n ihn - · simp - rw [← two_mul] at ihn - rw [← two_mul, mul_add, mul_one, ← one_add_one_eq_two, ← add_assoc, - Finset.prod_range_succ, Finset.prod_range_succ, mul_assoc] - refine mul_nonneg ihn ?_; generalize (1 + 1) * n = k - rcases le_or_lt m k with hmk | hmk - · have : m ≤ k + 1 := hmk.trans (lt_add_one (k : ℤ)).le - convert mul_nonneg_of_nonpos_of_nonpos (sub_nonpos_of_le hmk) _ - convert sub_nonpos_of_le this - · exact mul_nonneg (sub_nonneg_of_le hmk.le) (sub_nonneg_of_le hmk) + induction n with + | zero => simp + | succ n ihn => + rw [← two_mul] at ihn + rw [← two_mul, mul_add, mul_one, ← one_add_one_eq_two, ← add_assoc, + Finset.prod_range_succ, Finset.prod_range_succ, mul_assoc] + refine mul_nonneg ihn ?_; generalize (1 + 1) * n = k + rcases le_or_lt m k with hmk | hmk + · have : m ≤ k + 1 := hmk.trans (lt_add_one (k : ℤ)).le + convert mul_nonneg_of_nonpos_of_nonpos (sub_nonpos_of_le hmk) _ + convert sub_nonpos_of_le this + · exact mul_nonneg (sub_nonneg_of_le hmk.le) (sub_nonneg_of_le hmk) theorem int_prod_range_pos {m : ℤ} {n : ℕ} (hn : Even n) (hm : m ∉ Ico (0 : ℤ) n) : 0 < ∏ k ∈ Finset.range n, (m - k) := by @@ -95,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 f85ffeac0a9fe..ad0ee8acf1ca5 100644 --- a/Mathlib/Analysis/Convex/Star.lean +++ b/Mathlib/Analysis/Convex/Star.lean @@ -4,9 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ import Mathlib.Algebra.Module.LinearMap.Prod +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 @@ -209,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) : @@ -384,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 3a0fdf9701a5f..1027690d2b881 100644 --- a/Mathlib/Analysis/Convex/StoneSeparation.lean +++ b/Mathlib/Analysis/Convex/StoneSeparation.lean @@ -46,7 +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, add_comm, ← 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] @@ -59,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 - rw [Finset.centerMass] - simp_rw [div_eq_inv_mul, hw, mul_assoc, mul_smul (az * av + bz * au)⁻¹, ← smul_add, add_assoc, ← - mul_assoc] + 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, 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/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/Uniform.lean b/Mathlib/Analysis/Convex/Uniform.lean index a5ad07edba1ae..9e22c41ca4d16 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 @@ -117,7 +118,7 @@ theorem exists_forall_closed_ball_dist_add_le_two_mul_sub (hε : 0 < ε) (r : rw [← div_le_one hr, div_eq_inv_mul, ← norm_smul_of_nonneg (inv_nonneg.2 hr.le)] at hx hy have := h hx hy simp_rw [← smul_add, ← smul_sub, norm_smul_of_nonneg (inv_nonneg.2 hr.le), ← div_eq_inv_mul, - div_le_div_right hr, div_le_iff hr, sub_mul] at this + div_le_div_right hr, div_le_iff₀ hr, sub_mul] at this exact this hxy end SeminormedAddCommGroup diff --git a/Mathlib/Analysis/Convolution.lean b/Mathlib/Analysis/Convolution.lean index a1f0062306e40..55806cb2f24fa 100644 --- a/Mathlib/Analysis/Convolution.lean +++ b/Mathlib/Analysis/Convolution.lean @@ -227,7 +227,7 @@ theorem ConvolutionExistsAt.ofNorm' {x₀ : G} (hmf : AEStronglyMeasurable f μ) (hmg : AEStronglyMeasurable g <| map (fun t => x₀ - t) μ) : ConvolutionExistsAt f g x₀ L μ := by refine (h.const_mul ‖L‖).mono' - (hmf.convolution_integrand_snd' L hmg) (eventually_of_forall fun x => ?_) + (hmf.convolution_integrand_snd' L hmg) (Eventually.of_forall fun x => ?_) rw [mul_apply', ← mul_assoc] apply L.le_opNorm₂ @@ -278,15 +278,15 @@ theorem Integrable.convolution_integrand (hf : Integrable f ν) (hg : Integrable have h2_meas : AEStronglyMeasurable (fun y : G => ∫ x : G, ‖L (f y) (g (x - y))‖ ∂μ) ν := h_meas.prod_swap.norm.integral_prod_right' simp_rw [integrable_prod_iff' h_meas] - refine ⟨eventually_of_forall fun t => (L (f t)).integrable_comp (hg.comp_sub_right t), ?_⟩ + refine ⟨Eventually.of_forall fun t => (L (f t)).integrable_comp (hg.comp_sub_right t), ?_⟩ refine Integrable.mono' ?_ h2_meas - (eventually_of_forall fun t => (?_ : _ ≤ ‖L‖ * ‖f t‖ * ∫ x, ‖g (x - t)‖ ∂μ)) + (Eventually.of_forall fun t => (?_ : _ ≤ ‖L‖ * ‖f t‖ * ∫ x, ‖g (x - t)‖ ∂μ)) · simp only [integral_sub_right_eq_self (‖g ·‖)] exact (hf.norm.const_mul _).mul_const _ · simp_rw [← integral_mul_left] rw [Real.norm_of_nonneg (by positivity)] - exact integral_mono_of_nonneg (eventually_of_forall fun t => norm_nonneg _) - ((hg.comp_sub_right t).norm.const_mul _) (eventually_of_forall fun t => L.le_opNorm₂ _ _) + exact integral_mono_of_nonneg (Eventually.of_forall fun t => norm_nonneg _) + ((hg.comp_sub_right t).norm.const_mul _) (Eventually.of_forall fun t => L.le_opNorm₂ _ _) theorem Integrable.ae_convolution_exists (hf : Integrable f ν) (hg : Integrable g μ) : ∀ᵐ x ∂μ, ConvolutionExistsAt f g x L ν := @@ -545,7 +545,7 @@ theorem continuousOn_convolution_right_with_param {g : P → G → E'} {s : Set by_cases H : ∀ p ∈ s, ∀ x, g p x = 0 · apply (continuousOn_const (c := 0)).congr rintro ⟨p, x⟩ ⟨hp, -⟩ - apply integral_eq_zero_of_ae (eventually_of_forall (fun y ↦ ?_)) + apply integral_eq_zero_of_ae (Eventually.of_forall (fun y ↦ ?_)) simp [H p hp _] have : LocallyCompactSpace G := by push_neg at H @@ -618,10 +618,10 @@ theorem _root_.BddAbove.continuous_convolution_right_of_integrable filter_upwards with x; filter_upwards with t apply_rules [L.le_of_opNorm₂_le_of_le, le_rfl, le_ciSup hbg (x - t)] refine continuousAt_of_dominated ?_ this ?_ ?_ - · exact eventually_of_forall fun x => + · exact Eventually.of_forall fun x => hf.aestronglyMeasurable.convolution_integrand_snd' L hg.aestronglyMeasurable · exact (hf.norm.const_mul _).mul_const _ - · exact eventually_of_forall fun t => (L.continuous₂.comp₂ continuous_const <| + · exact Eventually.of_forall fun t => (L.continuous₂.comp₂ continuous_const <| hg.comp <| continuous_id.sub continuous_const).continuousAt end Group @@ -752,7 +752,7 @@ theorem dist_convolution_le' {x₀ : G} {R ε : ℝ} {z₀ : E'} (hε : 0 ≤ ε simp_rw [dist_eq_norm] at h2 ⊢ rw [← integral_sub hfg.integrable]; swap; · exact (L.flip z₀).integrable_comp hif refine (norm_integral_le_of_norm_le ((L.integrable_comp hif).norm.mul_const ε) - (eventually_of_forall h2)).trans ?_ + (Eventually.of_forall h2)).trans ?_ rw [integral_mul_right] refine mul_le_mul_of_nonneg_right ?_ hε have h3 : ∀ t, ‖L (f t)‖ ≤ ‖L‖ * ‖f t‖ := by @@ -899,7 +899,7 @@ theorem convolution_assoc (hL : ∀ (x : E) (y : E') (z : E''), L₂ (L x y) z = ((measurable_const.sub measurable_snd).sub measurable_fst) refine QuasiMeasurePreserving.absolutelyContinuous ?_ refine QuasiMeasurePreserving.prod_of_left - ((measurable_const.sub measurable_snd).sub measurable_fst) (eventually_of_forall fun y => ?_) + ((measurable_const.sub measurable_snd).sub measurable_fst) (Eventually.of_forall fun y => ?_) dsimp only exact quasiMeasurePreserving_sub_left_of_right_invariant μ _ have h2_meas : @@ -920,8 +920,8 @@ theorem convolution_assoc (hL : ∀ (x : E) (y : E') (z : E''), L₂ (L x y) z = (((quasiMeasurePreserving_sub_left_of_right_invariant ν x₀).ae hgk).mono fun t ht => ?_) simp_rw [convolution_def, mul_apply', mul_mul_mul_comm ‖L₃‖ ‖L₄‖, ← integral_mul_left] rw [Real.norm_of_nonneg (by positivity)] - refine integral_mono_of_nonneg (eventually_of_forall fun t => norm_nonneg _) - ((ht.const_mul _).const_mul _) (eventually_of_forall fun s => ?_) + refine integral_mono_of_nonneg (Eventually.of_forall fun t => norm_nonneg _) + ((ht.const_mul _).const_mul _) (Eventually.of_forall fun s => ?_) simp only [← mul_assoc ‖L₄‖] apply_rules [ContinuousLinearMap.le_of_opNorm₂_le_of_le, le_rfl] @@ -951,7 +951,7 @@ theorem _root_.HasCompactSupport.hasFDerivAt_convolution_right (hcg : HasCompact have : ProperSpace G := FiniteDimensional.proper_rclike 𝕜 G set L' := L.precompR G have h1 : ∀ᶠ x in 𝓝 x₀, AEStronglyMeasurable (fun t => L (f t) (g (x - t))) μ := - eventually_of_forall + Eventually.of_forall (hf.aestronglyMeasurable.convolution_integrand_snd L hg.continuous.aestronglyMeasurable) have h2 : ∀ x, AEStronglyMeasurable (fun t => L' (f t) (fderiv 𝕜 g (x - t))) μ := hf.aestronglyMeasurable.convolution_integrand_snd L' @@ -971,7 +971,7 @@ theorem _root_.HasCompactSupport.hasFDerivAt_convolution_right (hcg : HasCompact (ball_subset_closedBall hx) · rw [integrable_indicator_iff hK'.measurableSet] exact ((hf.integrableOn_isCompact hK').norm.const_mul _).mul_const _ - · exact eventually_of_forall fun t x _ => (L _).hasFDerivAt.comp x (h3 x t) + · exact Eventually.of_forall fun t x _ => (L _).hasFDerivAt.comp x (h3 x t) · exact hcg.convolutionExists_right L hf hg.continuous x₀ theorem _root_.HasCompactSupport.hasFDerivAt_convolution_left [IsNegInvariant μ] @@ -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 μ := @@ -1178,10 +1178,12 @@ theorem contDiffOn_convolution_right_with_param_aux {G : Type uP} {E' : Type uP} `n` (but for this we need the spaces at the different steps of the induction to live in the same universe, which is why we make the assumption in the lemma that all the relevant spaces come from the same universe). -/ - induction' n using ENat.nat_induction with n ih ih generalizing g E' F - · rw [contDiffOn_zero] at hg ⊢ + induction n using ENat.nat_induction generalizing g E' F with + | h0 => + rw [contDiffOn_zero] at hg ⊢ exact continuousOn_convolution_right_with_param L hk hgs hf hg - · let f' : P → G → P × G →L[𝕜] F := fun p a => + | hsuc n ih => + let f' : P → G → P × G →L[𝕜] F := fun p a => (f ⋆[L.precompR (P × G), μ] fun x : G => fderiv 𝕜 (uncurry g) (p, x)) a have A : ∀ q₀ : P × G, q₀.1 ∈ s → HasFDerivAt (fun q : P × G => (f ⋆[L, μ] g q.1) q.2) (f' q₀.1 q₀.2) q₀ := @@ -1205,9 +1207,9 @@ theorem contDiffOn_convolution_right_with_param_aux {G : Type uP} {E' : Type uP} exact hgs p y hp hy apply ih (L.precompR (P × G) : _) B convert hg.2 - · rw [contDiffOn_top] at hg ⊢ - intro n - exact ih n L hgs (hg n) + | htop ih => + rw [contDiffOn_top] at hg ⊢ + exact fun n ↦ ih n L hgs (hg n) /-- The convolution `f * g` is `C^n` when `f` is locally integrable and `g` is `C^n` and compactly supported. Version where `g` depends on an additional parameter in an open subset `s` of a @@ -1249,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 diff --git a/Mathlib/Analysis/Distribution/AEEqOfIntegralContDiff.lean b/Mathlib/Analysis/Distribution/AEEqOfIntegralContDiff.lean index 8919c573b7372..530b964dfa9a1 100644 --- a/Mathlib/Analysis/Distribution/AEEqOfIntegralContDiff.lean +++ b/Mathlib/Analysis/Distribution/AEEqOfIntegralContDiff.lean @@ -112,6 +112,8 @@ theorem ae_eq_zero_of_integral_smooth_smul_eq_zero [SigmaCompactSpace M] simpa [g_supp] using vK n simpa [this] using L +-- An instance with keys containing `Opens` +instance (U : Opens M) : BorelSpace U := inferInstanceAs (BorelSpace (U : Set M)) /-- If a function `f` locally integrable on an open subset `U` of a finite-dimensional real manifold has zero integral when multiplied by any smooth function compactly supported diff --git a/Mathlib/Analysis/Distribution/SchwartzSpace.lean b/Mathlib/Analysis/Distribution/SchwartzSpace.lean index 2d2ee1ed85185..ba8aae073aff9 100644 --- a/Mathlib/Analysis/Distribution/SchwartzSpace.lean +++ b/Mathlib/Analysis/Distribution/SchwartzSpace.lean @@ -138,8 +138,8 @@ theorem isBigO_cocompact_zpow_neg_nat (k : ℕ) : simp_rw [Asymptotics.IsBigO, Asymptotics.IsBigOWith] 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) _] + rw [Real.norm_of_nonneg (zpow_nonneg (norm_nonneg _) _), zpow_neg, ← div_eq_mul_inv, le_div_iff₀'] + 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 @@ -380,7 +380,7 @@ end Module section Seminorms -/-! ### Seminorms on Schwartz space-/ +/-! ### Seminorms on Schwartz space -/ variable [NormedField 𝕜] [NormedSpace 𝕜 F] [SMulCommClass ℝ 𝕜 F] @@ -480,7 +480,7 @@ end Seminorms section Topology -/-! ### The topology on the Schwartz space-/ +/-! ### The topology on the Schwartz space -/ variable [NormedField 𝕜] [NormedSpace 𝕜 F] [SMulCommClass ℝ 𝕜 F] @@ -533,7 +533,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 +575,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 +616,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 @@ -854,13 +854,13 @@ 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 intro i hi have hpos : 0 < (1 + ‖g x‖) ^ k' := by positivity - rw [le_div_iff' hpos] + rw [le_div_iff₀' hpos] change i ≤ (k', n).snd at hi exact one_add_le_sup_seminorm_apply le_rfl hi _ _ have hgrowth' : ∀ N : ℕ, 1 ≤ N → N ≤ n → @@ -870,8 +870,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 := @@ -886,7 +886,7 @@ def compCLM {g : D → E} (hg : g.HasTemperateGrowth) ring rw [rearrange] have hgxk' : 0 < (1 + ‖g x‖) ^ k' := by positivity - rw [← div_le_iff hgxk'] at hg_upper'' + rw [← div_le_iff₀ hgxk'] at hg_upper'' have hpos : (0 : ℝ) ≤ (C + 1) ^ n * n ! * 2 ^ k' * seminorm_f := by have : 0 ≤ seminorm_f := apply_nonneg _ _ positivity @@ -956,7 +956,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 @@ -1002,20 +1002,22 @@ theorem iteratedPDeriv_succ_left {n : ℕ} (m : Fin (n + 1) → E) (f : 𝓢(E, theorem iteratedPDeriv_succ_right {n : ℕ} (m : Fin (n + 1) → E) (f : 𝓢(E, F)) : iteratedPDeriv 𝕜 m f = iteratedPDeriv 𝕜 (Fin.init m) (pderivCLM 𝕜 (m (Fin.last n)) f) := by - induction' n with n IH - · rw [iteratedPDeriv_zero, iteratedPDeriv_one] + induction n with + | zero => + rw [iteratedPDeriv_zero, iteratedPDeriv_one] rfl -- The proof is `∂^{n + 2} = ∂ ∂^{n + 1} = ∂ ∂^n ∂ = ∂^{n+1} ∂` - have hmzero : Fin.init m 0 = m 0 := by simp only [Fin.init_def, Fin.castSucc_zero] - have hmtail : Fin.tail m (Fin.last n) = m (Fin.last n.succ) := by - simp only [Fin.tail_def, Fin.succ_last] - calc - _ = pderivCLM 𝕜 (m 0) (iteratedPDeriv 𝕜 _ f) := iteratedPDeriv_succ_left _ _ _ - _ = pderivCLM 𝕜 (m 0) ((iteratedPDeriv 𝕜 _) ((pderivCLM 𝕜 _) f)) := by - congr 1 - exact IH _ - _ = _ := by - simp only [hmtail, iteratedPDeriv_succ_left, hmzero, Fin.tail_init_eq_init_tail] + | succ n IH => + have hmzero : Fin.init m 0 = m 0 := by simp only [Fin.init_def, Fin.castSucc_zero] + have hmtail : Fin.tail m (Fin.last n) = m (Fin.last n.succ) := by + simp only [Fin.tail_def, Fin.succ_last] + calc + _ = pderivCLM 𝕜 (m 0) (iteratedPDeriv 𝕜 _ f) := iteratedPDeriv_succ_left _ _ _ + _ = pderivCLM 𝕜 (m 0) ((iteratedPDeriv 𝕜 _) ((pderivCLM 𝕜 _) f)) := by + congr 1 + exact IH _ + _ = _ := by + simp only [hmtail, iteratedPDeriv_succ_left, hmzero, Fin.tail_init_eq_init_tail] theorem iteratedPDeriv_eq_iteratedFDeriv {n : ℕ} {m : Fin n → E} {f : 𝓢(E, F)} {x : E} : iteratedPDeriv 𝕜 m f x = iteratedFDeriv ℝ n f x m := by @@ -1034,7 +1036,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] @@ -1070,7 +1072,7 @@ lemma integrable_pow_mul (f : 𝓢(D, V)) lemma integrable (f : 𝓢(D, V)) : Integrable f μ := (f.integrable_pow_mul μ 0).mono f.continuous.aestronglyMeasurable - (eventually_of_forall (fun _ ↦ by simp)) + (Eventually.of_forall (fun _ ↦ by simp)) variable (𝕜 μ) in /-- The integral as a continuous linear map from Schwartz space to the codomain. -/ @@ -1087,7 +1089,7 @@ def integralCLM : 𝓢(D, V) →L[𝕜] V := have h' : ∀ x, ‖f x‖ ≤ (1 + ‖x‖) ^ (-(n : ℝ)) * (2 ^ n * ((Finset.Iic m).sup (fun m' => SchwartzMap.seminorm 𝕜 m'.1 m'.2) f)) := by intro x - rw [rpow_neg (by positivity), ← div_eq_inv_mul, le_div_iff' (by positivity), rpow_natCast] + rw [rpow_neg (by positivity), ← div_eq_inv_mul, le_div_iff₀' (by positivity), rpow_natCast] simpa using one_add_le_sup_seminorm_apply (m := m) (k := n) (n := 0) le_rfl le_rfl f x apply (integral_mono (by simpa using f.integrable_pow_mul μ 0) _ h').trans · rw [integral_mul_right, ← mul_assoc, mul_comm (2 ^ n)] @@ -1180,16 +1182,16 @@ 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 simp only [hxzero, norm_zero, zero_mul, ← not_le] at hx exact hx (apply_nonneg (SchwartzMap.seminorm ℝ 1 0) f) have := norm_pow_mul_le_seminorm ℝ f 1 x - rw [pow_one, ← le_div_iff' hxpos] at this + 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 fe1f6f77fa8b1..7ca64c6a78543 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 /-! @@ -111,7 +111,7 @@ theorem fourier_apply {n : ℤ} {x : AddCircle T} : fourier n x = toCircle (n 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, - Circle.exp_apply, Complex.ofReal_mul, Complex.ofReal_div, Complex.ofReal_mul, zsmul_eq_mul, + Circle.coe_exp, Complex.ofReal_mul, Complex.ofReal_div, Complex.ofReal_mul, zsmul_eq_mul, Complex.ofReal_mul, Complex.ofReal_intCast] norm_num congr 1; ring @@ -173,7 +173,7 @@ theorem fourier_add_half_inv_index {n : ℤ} (hn : n ≠ 0) (hT : 0 < T) (x : Ad rw [fourier_apply, zsmul_add, ← QuotientAddGroup.mk_zsmul, toCircle_add, coe_mul_unitSphere] have : (n : ℂ) ≠ 0 := by simpa using hn have : (@toCircle T (n • (T / 2 / n) : ℝ) : ℂ) = -1 := by - rw [zsmul_eq_mul, toCircle, Function.Periodic.lift_coe, Circle.exp_apply] + rw [zsmul_eq_mul, toCircle, Function.Periodic.lift_coe, Circle.coe_exp] replace hT := Complex.ofReal_ne_zero.mpr hT.ne' convert Complex.exp_pi_mul_I using 3 field_simp; ring @@ -403,7 +403,7 @@ variable (f : C(AddCircle T, ℂ)) theorem fourierCoeff_toLp (n : ℤ) : fourierCoeff (toLp (E := ℂ) 2 haarAddCircle ℂ f) n = fourierCoeff f n := - integral_congr_ae (Filter.EventuallyEq.mul (Filter.eventually_of_forall (by tauto)) + integral_congr_ae (Filter.EventuallyEq.mul (Filter.Eventually.of_forall (by tauto)) (ContinuousMap.coeFn_toAEEqFun haarAddCircle f)) variable {f} diff --git a/Mathlib/Analysis/Fourier/FourierTransform.lean b/Mathlib/Analysis/Fourier/FourierTransform.lean index 562e533a3b0f4..8a1b83c8d5e3e 100644 --- a/Mathlib/Analysis/Fourier/FourierTransform.lean +++ b/Mathlib/Analysis/Fourier/FourierTransform.lean @@ -78,15 +78,11 @@ def fourierIntegral (e : AddChar 𝕜 𝕊) (μ : Measure V) (L : V →ₗ[𝕜] (w : W) : E := ∫ v, e (-L v w) • f v ∂μ -theorem fourierIntegral_smul_const (e : AddChar 𝕜 𝕊) (μ : Measure V) +theorem fourierIntegral_const_smul (e : AddChar 𝕜 𝕊) (μ : Measure V) (L : V →ₗ[𝕜] W →ₗ[𝕜] 𝕜) (f : V → E) (r : ℂ) : fourierIntegral e μ L (r • f) = r • fourierIntegral e μ L f := by ext1 w - -- Porting note: was - -- simp only [Pi.smul_apply, fourierIntegral, smul_comm _ r, integral_smul] - simp only [Pi.smul_apply, fourierIntegral, ← integral_smul] - congr 1 with v - rw [smul_comm] + simp only [Pi.smul_apply, fourierIntegral, smul_comm _ r, integral_smul] /-- The uniform norm of the Fourier integral of `f` is bounded by the `L¹` norm of `f`. -/ theorem norm_fourierIntegral_le_integral_norm (e : AddChar 𝕜 𝕊) (μ : Measure V) @@ -145,7 +141,7 @@ alias fourier_integral_convergent_iff := VectorFourier.fourierIntegral_convergen theorem fourierIntegral_add (he : Continuous e) (hL : Continuous fun p : V × W ↦ L p.1 p.2) {f g : V → E} (hf : Integrable f μ) (hg : Integrable g μ) : - fourierIntegral e μ L f + fourierIntegral e μ L g = fourierIntegral e μ L (f + g) := by + fourierIntegral e μ L (f + g) = fourierIntegral e μ L f + fourierIntegral e μ L g := by ext1 w dsimp only [Pi.add_apply, fourierIntegral] simp_rw [smul_add] @@ -281,9 +277,9 @@ theorem fourierIntegral_def (e : AddChar 𝕜 𝕊) (μ : Measure 𝕜) (f : fourierIntegral e μ f w = ∫ v : 𝕜, e (-(v * w)) • f v ∂μ := rfl -theorem fourierIntegral_smul_const (e : AddChar 𝕜 𝕊) (μ : Measure 𝕜) (f : 𝕜 → E) (r : ℂ) : +theorem fourierIntegral_const_smul (e : AddChar 𝕜 𝕊) (μ : Measure 𝕜) (f : 𝕜 → E) (r : ℂ) : fourierIntegral e μ (r • f) = r • fourierIntegral e μ f := - VectorFourier.fourierIntegral_smul_const _ _ _ _ _ + VectorFourier.fourierIntegral_const_smul _ _ _ _ _ /-- The uniform norm of the Fourier transform of `f` is bounded by the `L¹` norm of `f`. -/ theorem norm_fourierIntegral_le_integral_norm (e : AddChar 𝕜 𝕊) (μ : Measure 𝕜) diff --git a/Mathlib/Analysis/Fourier/FourierTransformDeriv.lean b/Mathlib/Analysis/Fourier/FourierTransformDeriv.lean index a4616a71f06cb..0fbe303edbe46 100644 --- a/Mathlib/Analysis/Fourier/FourierTransformDeriv.lean +++ b/Mathlib/Analysis/Fourier/FourierTransformDeriv.lean @@ -218,7 +218,7 @@ theorem hasFDerivAt_fourierIntegral (fourierIntegral_convergent_iff continuous_fourierChar (by apply L.continuous₂ : Continuous (fun p : V × W ↦ L.toLinearMap₂ p.1 p.2)) w').2 hf have h1 : ∀ᶠ w' in 𝓝 w, AEStronglyMeasurable (F w') μ := - eventually_of_forall (fun w' ↦ (h0 w').aestronglyMeasurable) + Eventually.of_forall (fun w' ↦ (h0 w').aestronglyMeasurable) have h3 : AEStronglyMeasurable (F' w) μ := by refine .smul ?_ hf.1.fourierSMulRight refine (continuous_fourierChar.comp ?_).aestronglyMeasurable @@ -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] @@ -456,7 +455,7 @@ lemma hasFTaylorSeriesUpTo_fourierIntegral {N : ℕ∞} have I₁ : Integrable (fun v ↦ fourierPowSMulRight L f v n) μ := integrable_fourierPowSMulRight L (hf n hn.le) h'f have I₂ : Integrable (fun v ↦ ‖v‖ * ‖fourierPowSMulRight L f v n‖) μ := by - apply ((hf (n+1) (ENat.add_one_le_of_lt hn)).const_mul ((2 * π * ‖L‖) ^ n)).mono' + apply ((hf (n+1) (Order.add_one_le_of_lt hn)).const_mul ((2 * π * ‖L‖) ^ n)).mono' (continuous_norm.aestronglyMeasurable.mul (h'f.fourierPowSMulRight L n).norm) filter_upwards with v simp only [Pi.mul_apply, norm_mul, norm_norm] @@ -466,7 +465,7 @@ lemma hasFTaylorSeriesUpTo_fourierIntegral {N : ℕ∞} gcongr; apply norm_fourierPowSMulRight_le _ = (2 * π * ‖L‖) ^ n * (‖v‖ ^ (n + 1) * ‖f v‖) := by rw [pow_succ]; ring have I₃ : Integrable (fun v ↦ fourierPowSMulRight L f v (n + 1)) μ := - integrable_fourierPowSMulRight L (hf (n + 1) (ENat.add_one_le_of_lt hn)) h'f + integrable_fourierPowSMulRight L (hf (n + 1) (Order.add_one_le_of_lt hn)) h'f have I₄ : Integrable (fun v ↦ fourierSMulRight L (fun v ↦ fourierPowSMulRight L f v n) v) μ := by apply (I₂.const_mul ((2 * π * ‖L‖))).mono' (h'f.fourierPowSMulRight L n).fourierSMulRight @@ -522,7 +521,7 @@ theorem fourierIntegral_iteratedFDeriv [FiniteDimensional ℝ V] induction n with | zero => ext w m - simp only [iteratedFDeriv_zero_apply, Nat.zero_eq, fourierPowSMulRight_apply, pow_zero, + simp only [iteratedFDeriv_zero_apply, fourierPowSMulRight_apply, pow_zero, Finset.univ_eq_empty, ContinuousLinearMap.neg_apply, ContinuousLinearMap.flip_apply, Finset.prod_empty, one_smul, fourierIntegral_continuousMultilinearMap_apply' ((h'f 0 bot_le))] | succ n ih => @@ -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 59c58e215be50..1531edb4f4be0 100644 --- a/Mathlib/Analysis/Fourier/RiemannLebesgueLemma.lean +++ b/Mathlib/Analysis/Fourier/RiemannLebesgueLemma.lean @@ -9,9 +9,9 @@ import Mathlib.Analysis.InnerProductSpace.EuclideanDist import Mathlib.MeasureTheory.Function.ContinuousMapDense import Mathlib.MeasureTheory.Group.Integral import Mathlib.MeasureTheory.Integral.SetIntegral -import Mathlib.MeasureTheory.Measure.Haar.NormedSpace import Mathlib.Topology.EMetricSpace.Paracompact import Mathlib.MeasureTheory.Measure.Haar.Unique +import Mathlib.Topology.Algebra.Module.WeakDual /-! # The Riemann-Lebesgue Lemma @@ -45,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 @@ -140,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. @@ -164,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 @@ -177,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 ?_ @@ -203,7 +203,7 @@ theorem tendsto_integral_exp_inner_smul_cocompact : (tendsto_integral_exp_inner_smul_cocompact_of_continuous_compact_support hg_cont hg_supp)) _ (div_pos hε two_pos)).mp - (eventually_of_forall fun w hI => ?_) + (Eventually.of_forall fun w hI => ?_) rw [dist_eq_norm] at hI ⊢ have : ‖(∫ v, 𝐞 (-⟪v, w⟫) • f v) - ∫ v, 𝐞 (-⟪v, w⟫) • g v‖ ≤ ε / 2 := by refine le_trans ?_ hfg @@ -262,41 +262,11 @@ theorem tendsto_integral_exp_smul_cocompact (μ : Measure V) [μ.IsAddHaarMeasur borelize V' -- various equivs derived from A let Aₘ : MeasurableEquiv V V' := A.toHomeomorph.toMeasurableEquiv - -- isomorphism between duals derived from A -- need to do continuity as a separate step in order - -- to apply `LinearMap.continuous_of_finiteDimensional`. - let Adualₗ : (V →L[ℝ] ℝ) ≃ₗ[ℝ] V' →L[ℝ] ℝ := - { toFun := fun t => t.comp A.symm.toContinuousLinearMap - invFun := fun t => t.comp A.toContinuousLinearMap - map_add' := by - intro t s - ext1 v - simp only [ContinuousLinearMap.coe_comp', Function.comp_apply, - ContinuousLinearMap.add_apply] - map_smul' := by - intro x f - ext1 v - simp only [RingHom.id_apply, ContinuousLinearMap.coe_comp', Function.comp_apply, - ContinuousLinearMap.smul_apply] - left_inv := by - intro w - ext1 v - simp only [ContinuousLinearMap.coe_comp', - ContinuousLinearEquiv.coe_coe, Function.comp_apply, - ContinuousLinearEquiv.symm_apply_apply] - right_inv := by - intro w - ext1 v - simp only [ContinuousLinearMap.coe_comp', - ContinuousLinearEquiv.coe_coe, Function.comp_apply, - ContinuousLinearEquiv.apply_symm_apply] } - let Adual : (V →L[ℝ] ℝ) ≃L[ℝ] V' →L[ℝ] ℝ := - { Adualₗ with - continuous_toFun := Adualₗ.toLinearMap.continuous_of_finiteDimensional - continuous_invFun := Adualₗ.symm.toLinearMap.continuous_of_finiteDimensional } - have : (μ.map Aₘ).IsAddHaarMeasure := Measure.MapContinuousLinearEquiv.isAddHaarMeasure _ A - convert - (tendsto_integral_exp_smul_cocompact_of_inner_product (f ∘ A.symm) (μ.map Aₘ)).comp - Adual.toHomeomorph.toCocompactMap.cocompact_tendsto' with w + -- isomorphism between duals derived from A + let Adual : (V →L[ℝ] ℝ) ≃L[ℝ] V' →L[ℝ] ℝ := A.arrowCongrSL (.refl _ _) + have : (μ.map Aₘ).IsAddHaarMeasure := A.isAddHaarMeasure_map _ + convert (tendsto_integral_exp_smul_cocompact_of_inner_product (f ∘ A.symm) (μ.map Aₘ)).comp + Adual.toHomeomorph.toCocompactMap.cocompact_tendsto' with w rw [Function.comp_apply, integral_map_equiv] congr 1 with v : 1 congr diff --git a/Mathlib/Analysis/Fourier/ZMod.lean b/Mathlib/Analysis/Fourier/ZMod.lean index f93cc4bef7da1..4fad478f0bc2c 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 @@ -10,42 +11,193 @@ import Mathlib.NumberTheory.DirichletCharacter.GaussSum /-! # Fourier theory on `ZMod N` -Basic definitions and properties of the discrete Fourier transform for functions on `ZMod N`. +Basic definitions and properties of the discrete Fourier transform for functions on `ZMod N` +(taking values in an arbitrary `ℂ`-vector space). ### Main definitions and results -* `ZMod.dft`: the Fourier transform with respect to the standard additive character +* `ZMod.dft`: the Fourier transform, with respect to the standard additive character `ZMod.stdAddChar` (mapping `j mod N` to `exp (2 * π * I * j / N)`). The notation `𝓕`, scoped in namespace `ZMod`, is available for this. +* `ZMod.dft_dft`: the Fourier inversion formula. * `DirichletCharacter.fourierTransform_eq_inv_mul_gaussSum`: the discrete Fourier transform of a primitive Dirichlet character `χ` is a Gauss sum times `χ⁻¹`. -/ -open scoped Real - -open MeasureTheory +open MeasureTheory Finset AddChar ZMod namespace ZMod -variable {N : ℕ} [NeZero N] +variable {N : ℕ} [NeZero N] {E : Type*} [AddCommGroup E] [Module ℂ E] -/-- The discrete Fourier transform on `ℤ / N ℤ` (with the counting measure) -/ -noncomputable def dft (Φ : ZMod N → ℂ) (k : ZMod N) : ℂ := - Fourier.fourierIntegral toCircle Measure.count Φ k +section private_defs +/- +It doesn't _quite_ work to define the Fourier transform as a `LinearEquiv` in one go, because that +leads to annoying repetition between the proof fields. So we set up a private definition first, +prove a minimal set of lemmas about it, and then define the `LinearEquiv` using that. + +**Do not add more lemmas about `auxDFT`**: it should be invisible to end-users. +-/ + +/-- +The discrete Fourier transform on `ℤ / N ℤ` (with the counting measure). This definition is +private because it is superseded by the bundled `LinearEquiv` version. +-/ +private noncomputable def auxDFT (Φ : ZMod N → E) (k : ZMod N) : E := + ∑ j : ZMod N, stdAddChar (-(j * k)) • Φ j + +private lemma auxDFT_neg (Φ : ZMod N → E) : auxDFT (fun j ↦ Φ (-j)) = fun k ↦ auxDFT Φ (-k) := by + ext1 k; simpa only [auxDFT] using + Fintype.sum_equiv (Equiv.neg _) _ _ (fun j ↦ by rw [Equiv.neg_apply, neg_mul_neg]) + +/-- Fourier inversion formula, discrete case. -/ +private lemma auxDFT_auxDFT (Φ : ZMod N → E) : auxDFT (auxDFT Φ) = fun j ↦ (N : ℂ) • Φ (-j) := by + ext1 j + simp only [auxDFT, mul_comm _ j, smul_sum, ← smul_assoc, smul_eq_mul, ← map_add_eq_mul, ← + neg_add, ← add_mul] + rw [sum_comm] + simp only [← sum_smul, ← neg_mul] + have h1 (t : ZMod N) : ∑ i, stdAddChar (t * i) = if t = 0 then ↑N else 0 := by + split_ifs with h + · simp only [h, zero_mul, map_zero_eq_one, sum_const, card_univ, card, + nsmul_eq_mul, mul_one] + · exact sum_eq_zero_of_ne_one (isPrimitive_stdAddChar N h) + have h2 (x j : ZMod N) : -(j + x) = 0 ↔ x = -j := by + rw [neg_add, add_comm, add_eq_zero_iff_neg_eq, neg_neg] + simp only [h1, h2, ite_smul, zero_smul, sum_ite_eq', mem_univ, ite_true] + +private lemma auxDFT_smul (c : ℂ) (Φ : ZMod N → E) : + auxDFT (c • Φ) = c • auxDFT Φ := by + ext; simp only [Pi.smul_def, auxDFT, smul_sum, smul_comm c] + +end private_defs + +section defs + +/-- +The discrete Fourier transform on `ℤ / N ℤ` (with the counting measure), bundled as a linear +equivalence. +-/ +noncomputable def dft : (ZMod N → E) ≃ₗ[ℂ] (ZMod N → E) where + toFun := auxDFT + map_add' Φ₁ Φ₂ := by + ext; simp only [auxDFT, Pi.add_def, smul_add, sum_add_distrib] + map_smul' c Φ := by + ext; simp only [auxDFT, Pi.smul_apply, RingHom.id_apply, smul_sum, smul_comm c] + invFun Φ k := (N : ℂ)⁻¹ • auxDFT Φ (-k) + left_inv Φ := by + simp only [auxDFT_auxDFT, neg_neg, ← mul_smul, inv_mul_cancel₀ (NeZero.ne _), one_smul] + right_inv Φ := by + ext1 j + simp only [← Pi.smul_def, auxDFT_smul, auxDFT_neg, auxDFT_auxDFT, neg_neg, ← mul_smul, + inv_mul_cancel₀ (NeZero.ne _), one_smul] @[inherit_doc] scoped notation "𝓕" => dft -lemma dft_apply (Φ : ZMod N → ℂ) (k : ZMod N) : - 𝓕 Φ k = ∑ j : ZMod N, toCircle (-(j * k)) • Φ j := by - simp only [dft, Fourier.fourierIntegral_def, integral_countable' <| .of_finite .., - Measure.count_singleton, ENNReal.one_toReal, one_smul, tsum_fintype] +/-- The inverse Fourier transform on `ZMod N`. -/ +scoped notation "𝓕⁻" => LinearEquiv.symm dft -lemma dft_def (Φ : ZMod N → ℂ) : 𝓕 Φ = fun k ↦ ∑ j : ZMod N, toCircle (-(j * k)) • Φ j := - funext (dft_apply Φ) +lemma dft_apply (Φ : ZMod N → E) (k : ZMod N) : + 𝓕 Φ k = ∑ j : ZMod N, stdAddChar (-(j * k)) • Φ j := + rfl -end ZMod +lemma dft_def (Φ : ZMod N → E) : + 𝓕 Φ = fun k ↦ ∑ j : ZMod N, stdAddChar (-(j * k)) • Φ j := + rfl + +lemma invDFT_apply (Ψ : ZMod N → E) (k : ZMod N) : + 𝓕⁻ Ψ k = (N : ℂ)⁻¹ • ∑ j : ZMod N, stdAddChar (j * k) • Ψ j := by + simp only [dft, LinearEquiv.coe_symm_mk, auxDFT, mul_neg, neg_neg] + +lemma invDFT_def (Ψ : ZMod N → E) : + 𝓕⁻ Ψ = fun k ↦ (N : ℂ)⁻¹ • ∑ j : ZMod N, stdAddChar (j * k) • Ψ j := + funext <| invDFT_apply Ψ + +lemma invDFT_apply' (Ψ : ZMod N → E) (k : ZMod N) : 𝓕⁻ Ψ k = (N : ℂ)⁻¹ • 𝓕 Ψ (-k) := + rfl + +lemma invDFT_def' (Ψ : ZMod N → E) : 𝓕⁻ Ψ = fun k ↦ (N : ℂ)⁻¹ • 𝓕 Ψ (-k) := + rfl + +lemma dft_apply_zero (Φ : ZMod N → E) : 𝓕 Φ 0 = ∑ j, Φ j := by + simp only [dft_apply, mul_zero, neg_zero, map_zero_eq_one, one_smul] + +/-- +The discrete Fourier transform agrees with the general one (assuming the target space is a complete +normed space). +-/ +lemma dft_eq_fourier {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] [CompleteSpace E] + (Φ : ZMod N → E) (k : ZMod N) : + 𝓕 Φ k = Fourier.fourierIntegral toCircle Measure.count Φ k := by + simp only [dft_apply, stdAddChar_apply, Fourier.fourierIntegral_def, Circle.smul_def, + integral_countable' <| .of_finite .., Measure.count_singleton, ENNReal.one_toReal, one_smul, + tsum_fintype] + +end defs + +section arith +/-! +## Compatibility with scalar multiplication -open ZMod +These lemmas are more general than `LinearEquiv.map_mul` etc, since they allow any scalars that +commute with the `ℂ`-action, rather than just `ℂ` itself. +-/ + +lemma dft_const_smul {R : Type*} [DistribSMul R E] [SMulCommClass R ℂ E] (r : R) (Φ : ZMod N → E) : + 𝓕 (r • Φ) = r • 𝓕 Φ := by + simp only [Pi.smul_def, dft_def, smul_sum, smul_comm] + +lemma dft_smul_const {R : Type*} [Ring R] [Module ℂ R] [Module R E] [IsScalarTower ℂ R E] + (Φ : ZMod N → R) (e : E) : + 𝓕 (fun j ↦ Φ j • e) = fun k ↦ 𝓕 Φ k • e := by + simp only [dft_def, sum_smul, smul_assoc] + +lemma dft_const_mul {R : Type*} [Ring R] [Algebra ℂ R] (r : R) (Φ : ZMod N → R) : + 𝓕 (fun j ↦ r * Φ j) = fun k ↦ r * 𝓕 Φ k := + dft_const_smul r Φ + +lemma dft_mul_const {R : Type*} [Ring R] [Algebra ℂ R] (Φ : ZMod N → R) (r : R) : + 𝓕 (fun j ↦ Φ j * r) = fun k ↦ 𝓕 Φ k * r := + dft_smul_const Φ r + +end arith + +section inversion + +lemma dft_comp_neg (Φ : ZMod N → E) : 𝓕 (fun j ↦ Φ (-j)) = fun k ↦ 𝓕 Φ (-k) := + auxDFT_neg .. + +/-- Fourier inversion formula, discrete case. -/ +lemma dft_dft (Φ : ZMod N → E) : 𝓕 (𝓕 Φ) = fun j ↦ (N : ℂ) • Φ (-j) := + auxDFT_auxDFT .. + +end inversion + +lemma dft_comp_unitMul (Φ : ZMod N → E) (u : (ZMod N)ˣ) (k : ZMod N) : + 𝓕 (fun j ↦ Φ (u.val * j)) k = 𝓕 Φ (u⁻¹.val * k) := by + 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 @@ -53,10 +205,9 @@ variable {N : ℕ} [NeZero N] (χ : DirichletCharacter ℂ N) lemma fourierTransform_eq_gaussSum_mulShift (k : ZMod N) : 𝓕 χ k = gaussSum χ (stdAddChar.mulShift (-k)) := by - simp only [dft_def] + simp only [dft_apply, smul_eq_mul] congr 1 with j - rw [AddChar.mulShift_apply, mul_comm j, Submonoid.smul_def, smul_eq_mul, neg_mul, - stdAddChar_apply, mul_comm (χ _)] + rw [mulShift_apply, mul_comm j, neg_mul, stdAddChar_apply, mul_comm (χ _)] /-- For a primitive Dirichlet character `χ`, the Fourier transform of `χ` is a constant multiple of `χ⁻¹` (and the constant is essentially the Gauss sum). -/ diff --git a/Mathlib/Analysis/FunctionalSpaces/SobolevInequality.lean b/Mathlib/Analysis/FunctionalSpaces/SobolevInequality.lean index 82122b6dce018..8164bbd406fee 100644 --- a/Mathlib/Analysis/FunctionalSpaces/SobolevInequality.lean +++ b/Mathlib/Analysis/FunctionalSpaces/SobolevInequality.lean @@ -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`. @@ -421,7 +421,7 @@ theorem lintegral_pow_le_pow_lintegral_fderiv {u : E → F} refine (Continuous.nnnorm ?_).measurable.coe_nnreal_ennreal exact (hu.continuous_fderiv le_rfl).comp e.symm.continuous _ = (‖(e.symm : (ι → ℝ) →L[ℝ] E)‖₊ ^ p : ℝ≥0) * (∫⁻ y, ‖fderiv ℝ u (e.symm y)‖₊) ^ p := by - rw [ENNReal.mul_rpow_of_nonneg _ _ h0p, ENNReal.coe_rpow_of_nonneg _ h0p] + rw [ENNReal.mul_rpow_of_nonneg _ _ h0p, ← ENNReal.coe_rpow_of_nonneg _ h0p] _ = (‖(e.symm : (ι → ℝ) →L[ℝ] E)‖₊ ^ p : ℝ≥0) * (∫⁻ x, ‖fderiv ℝ u x‖₊ ∂(volume : Measure (ι → ℝ)).map e.symm) ^ p := by congr @@ -430,7 +430,7 @@ theorem lintegral_pow_le_pow_lintegral_fderiv {u : E → F} fun_prop rw [← ENNReal.mul_le_mul_left h3c ENNReal.coe_ne_top, ← mul_assoc, ← ENNReal.coe_mul, ← hC, ENNReal.coe_mul] at this - rw [ENNReal.mul_rpow_of_nonneg _ _ h0p, ← mul_assoc, ENNReal.coe_rpow_of_ne_zero hc.ne'] + rw [ENNReal.mul_rpow_of_nonneg _ _ h0p, ← mul_assoc, ← ENNReal.coe_rpow_of_ne_zero hc.ne'] exact this /-- The constant factor occurring in the conclusion of `eLpNorm_le_eLpNorm_fderiv_one`. @@ -448,7 +448,7 @@ theorem eLpNorm_le_eLpNorm_fderiv_one {u : E → F} (hu : ContDiff ℝ 1 u) (h2 have h0p : 0 < (p : ℝ) := hp.coe.symm.pos rw [eLpNorm_one_eq_lintegral_nnnorm, ← ENNReal.rpow_le_rpow_iff h0p, ENNReal.mul_rpow_of_nonneg _ _ h0p.le, - ENNReal.coe_rpow_of_nonneg _ h0p.le, eLpNormLESNormFDerivOneConst, ← NNReal.rpow_mul, + ← ENNReal.coe_rpow_of_nonneg _ h0p.le, eLpNormLESNormFDerivOneConst, ← NNReal.rpow_mul, eLpNorm_nnreal_pow_eq_lintegral hp.symm.pos.ne', inv_mul_cancel₀ h0p.ne', NNReal.rpow_one] exact lintegral_pow_le_pow_lintegral_fderiv μ hu h2u hp.coe @@ -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] @@ -553,13 +553,13 @@ theorem eLpNorm_le_eLpNorm_fderiv_of_eq_inner {u : E → F'} calc (∫⁻ x, ‖u x‖₊ ^ (p' : ℝ) ∂μ) ^ (1 / (n' : ℝ)) = eLpNorm v n' μ := by rw [← h2γ, eLpNorm_nnreal_eq_lintegral hn.symm.pos.ne'] simp (discharger := positivity) [v, Real.nnnorm_rpow_of_nonneg, ENNReal.rpow_mul, - ENNReal.coe_rpow_of_nonneg] + ← ENNReal.coe_rpow_of_nonneg] _ ≤ C * eLpNorm (fderiv ℝ v) 1 μ := eLpNorm_le_eLpNorm_fderiv_one μ hv h2v hn _ = C * ∫⁻ x, ‖fderiv ℝ v x‖₊ ∂μ := by rw [eLpNorm_one_eq_lintegral_nnnorm] _ ≤ C * γ * ∫⁻ x, ‖u x‖₊ ^ ((γ : ℝ) - 1) * ‖fderiv ℝ u x‖₊ ∂μ := by rw [mul_assoc, ← lintegral_const_mul γ] gcongr - simp_rw [← mul_assoc, ENNReal.coe_rpow_of_nonneg _ (sub_nonneg.mpr h1γ.le)] + simp_rw [← mul_assoc, ← ENNReal.coe_rpow_of_nonneg _ (sub_nonneg.mpr h1γ.le)] exact ENNReal.coe_le_coe.mpr <| nnnorm_fderiv_norm_rpow_le (hu.differentiable le_rfl) h1γ fun_prop _ ≤ C * γ * ((∫⁻ x, ‖u x‖₊ ^ (p' : ℝ) ∂μ) ^ (1 / q) * @@ -634,14 +634,14 @@ theorem eLpNorm_le_eLpNorm_fderiv_of_eq [FiniteDimensional ℝ F] (fderiv ℝ e (u x)).opNorm_comp_le (fderiv ℝ u x) _ = C₂ * ‖fderiv ℝ u x‖ := by simp_rw [e.fderiv, C₂, coe_nnnorm] calc eLpNorm u p' μ - = eLpNorm (e.symm ∘ v) p' μ := by simp_rw [v, Function.comp, e.symm_apply_apply] + = eLpNorm (e.symm ∘ v) p' μ := by simp_rw [v, Function.comp_def, e.symm_apply_apply] _ ≤ C₁ • eLpNorm v p' μ := by apply eLpNorm_le_nnreal_smul_eLpNorm_of_ae_le_mul - exact eventually_of_forall (fun x ↦ (e.symm : F' →L[ℝ] F).le_opNNNorm _) + exact Eventually.of_forall (fun x ↦ (e.symm : F' →L[ℝ] F).le_opNNNorm _) _ = C₁ * eLpNorm v p' μ := rfl _ ≤ C₁ * C * eLpNorm (fderiv ℝ v) p μ := by rw [mul_assoc]; gcongr _ ≤ C₁ * C * (C₂ * eLpNorm (fderiv ℝ u) p μ) := by - gcongr; exact eLpNorm_le_nnreal_smul_eLpNorm_of_ae_le_mul (eventually_of_forall h4v) p + gcongr; exact eLpNorm_le_nnreal_smul_eLpNorm_of_ae_le_mul (Eventually.of_forall h4v) p _ = SNormLESNormFDerivOfEqConst F μ p * eLpNorm (fderiv ℝ u) p μ := by simp_rw [SNormLESNormFDerivOfEqConst] push_cast @@ -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] @@ -697,7 +697,7 @@ theorem eLpNorm_le_eLpNorm_fderiv_of_le [FiniteDimensional ℝ F] = eLpNorm u q (μ.restrict s) := by rw [eLpNorm_restrict_eq_of_support_subset h2u] _ ≤ eLpNorm u p' (μ.restrict s) * t := by convert eLpNorm_le_eLpNorm_mul_rpow_measure_univ this hu.continuous.aestronglyMeasurable - rw [← ENNReal.coe_rpow_of_nonneg] + rw [ENNReal.coe_rpow_of_nonneg] · simp [ENNReal.coe_toNNReal hs.measure_lt_top.ne] · rw [one_div, one_div] norm_cast diff --git a/Mathlib/Analysis/Hofer.lean b/Mathlib/Analysis/Hofer.lean index 6ed5d0e71bb32..8d5fda97eb89e 100644 --- a/Mathlib/Analysis/Hofer.lean +++ b/Mathlib/Analysis/Hofer.lean @@ -28,16 +28,15 @@ theorem hofer {X : Type*} [MetricSpace X] [CompleteSpace X] (x : X) (ε : ℝ) ( by_contra H have reformulation : ∀ (x') (k : ℕ), ε * ϕ x ≤ ε / 2 ^ k * ϕ x' ↔ 2 ^ k * ϕ x ≤ ϕ x' := by intro x' k - rw [div_mul_eq_mul_div, le_div_iff, mul_assoc, mul_le_mul_left ε_pos, mul_comm] + rw [div_mul_eq_mul_div, le_div_iff₀, mul_assoc, mul_le_mul_left ε_pos, mul_comm] positivity -- Now let's specialize to `ε/2^k` replace H : ∀ k : ℕ, ∀ x', d x' x ≤ 2 * ε ∧ 2 ^ k * ϕ 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 - clear reformulation haveI : Nonempty X := ⟨x⟩ choose! F hF using H -- Use the axiom of choice @@ -48,32 +47,29 @@ theorem hofer {X : Type*} [MetricSpace X] [CompleteSpace X] (x : X) (ε : ℝ) ( ∀ n, d (u n) x ≤ 2 * ε ∧ 2 ^ n * ϕ x ≤ ϕ (u n) → d (u n) (u <| n + 1) ≤ ε / 2 ^ n ∧ 2 * ϕ (u n) < ϕ (u <| n + 1) := by - intro n - exact hF n (u n) - clear hF + exact fun n ↦ hF n (u n) -- Key properties of u, to be proven by induction have key : ∀ n, d (u n) (u (n + 1)) ≤ ε / 2 ^ n ∧ 2 * ϕ (u n) < ϕ (u (n + 1)) := by intro n - induction' n using Nat.case_strong_induction_on with n IH - · simpa [u, ε_pos.le] using hu 0 - have A : d (u (n + 1)) x ≤ 2 * ε := by - rw [dist_comm] - let r := range (n + 1) -- range (n+1) = {0, ..., n} - calc - d (u 0) (u (n + 1)) ≤ ∑ i ∈ r, d (u i) (u <| i + 1) := dist_le_range_sum_dist u (n + 1) - _ ≤ ∑ i ∈ r, ε / 2 ^ i := - (sum_le_sum fun i i_in => (IH i <| Nat.lt_succ_iff.mp <| Finset.mem_range.mp i_in).1) - _ = (∑ i ∈ r, (1 / 2 : ℝ) ^ i) * ε := by - rw [Finset.sum_mul] - congr with i - field_simp - _ ≤ 2 * ε := by gcongr; apply sum_geometric_two_le - have B : 2 ^ (n + 1) * ϕ x ≤ ϕ (u (n + 1)) := by - refine @geom_le (ϕ ∘ u) _ zero_le_two (n + 1) fun m hm => ?_ - exact (IH _ <| Nat.lt_add_one_iff.1 hm).2.le - exact hu (n + 1) ⟨A, B⟩ + induction n using Nat.case_strong_induction_on with + | hz => simpa [u, ε_pos.le] using hu 0 + | hi n IH => + have A : d (u (n + 1)) x ≤ 2 * ε := by + rw [dist_comm] + let r := range (n + 1) -- range (n+1) = {0, ..., n} + calc + d (u 0) (u (n + 1)) ≤ ∑ i ∈ r, d (u i) (u <| i + 1) := dist_le_range_sum_dist u (n + 1) + _ ≤ ∑ i ∈ r, ε / 2 ^ i := + (sum_le_sum fun i i_in => (IH i <| Nat.lt_succ_iff.mp <| Finset.mem_range.mp i_in).1) + _ = (∑ i ∈ r, (1 / 2 : ℝ) ^ i) * ε := by + rw [Finset.sum_mul] + field_simp + _ ≤ 2 * ε := by gcongr; apply sum_geometric_two_le + have B : 2 ^ (n + 1) * ϕ x ≤ ϕ (u (n + 1)) := by + refine @geom_le (ϕ ∘ u) _ zero_le_two (n + 1) fun m hm => ?_ + exact (IH _ <| Nat.lt_add_one_iff.1 hm).2.le + exact hu (n + 1) ⟨A, B⟩ cases' forall_and.mp key with key₁ key₂ - clear hu key -- Hence u is Cauchy have cauchy_u : CauchySeq u := by refine cauchySeq_of_le_geometric _ ε one_half_lt_one fun n => ?_ diff --git a/Mathlib/Analysis/InnerProductSpace/Adjoint.lean b/Mathlib/Analysis/InnerProductSpace/Adjoint.lean index c4a1bcd72f1b5..d70316a5027b3 100644 --- a/Mathlib/Analysis/InnerProductSpace/Adjoint.lean +++ b/Mathlib/Analysis/InnerProductSpace/Adjoint.lean @@ -564,7 +564,7 @@ lemma Matrix.toLin_conjTranspose (A : Matrix m n 𝕜) : orthonormal_iff_ite.mp v₁.orthonormal, orthonormal_iff_ite.mp v₂.orthonormal] /-- The matrix associated to the adjoint of a linear map corresponding to two orthonormal bases -is the conjugate tranpose of the matrix associated to the linear map. -/ +is the conjugate transpose of the matrix associated to the linear map. -/ lemma LinearMap.toMatrix_adjoint (f : E →ₗ[𝕜] F) : toMatrix v₂.toBasis v₁.toBasis (adjoint f) = (toMatrix v₁.toBasis v₂.toBasis f)ᴴ := toLin v₂.toBasis v₁.toBasis |>.injective <| by simp [toLin_conjTranspose] diff --git a/Mathlib/Analysis/InnerProductSpace/Basic.lean b/Mathlib/Analysis/InnerProductSpace/Basic.lean index f5aa42ed27d81..1e37689bab1f9 100644 --- a/Mathlib/Analysis/InnerProductSpace/Basic.lean +++ b/Mathlib/Analysis/InnerProductSpace/Basic.lean @@ -68,7 +68,7 @@ noncomputable section open RCLike Real Filter -open Topology ComplexConjugate +open Topology ComplexConjugate Finsupp open LinearMap (BilinForm) @@ -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 @@ -299,10 +299,10 @@ theorem inner_add_add_self (x y : F) : ⟪x + y, x + y⟫ = ⟪x, x⟫ + ⟪x, y theorem inner_sub_sub_self (x y : F) : ⟪x - y, x - y⟫ = ⟪x, x⟫ - ⟪x, y⟫ - ⟪y, x⟫ + ⟪y, y⟫ := by simp only [inner_sub_left, inner_sub_right]; ring -theorem inner_smul_ofReal_left (x y : F) {t : ℝ} : ⟪(t : 𝕜) • x, y⟫ = ⟪x, y⟫ * t := by +theorem inner_smul_ofReal_left (x y : F) {t : ℝ} : ⟪(t : 𝕜) • x, y⟫ = ⟪x, y⟫ * t := by rw [inner_smul_left, conj_ofReal, mul_comm] -theorem inner_smul_ofReal_right (x y : F) {t : ℝ} : ⟪x, (t : 𝕜) • y⟫ = ⟪x, y⟫ * t := by +theorem inner_smul_ofReal_right (x y : F) {t : ℝ} : ⟪x, (t : 𝕜) • y⟫ = ⟪x, y⟫ * t := by rw [inner_smul_right, mul_comm] theorem re_inner_smul_ofReal_smul_self (x : F) {t : ℝ} : @@ -324,7 +324,7 @@ lemma cauchy_schwarz_aux' (x y : F) (t : ℝ) : 0 ≤ normSqF x * t * t + 2 * re [re_inner_smul_ofReal_smul_self, inner_smul_ofReal_left, inner_smul_ofReal_right] _ = normSq x * t * t + re ⟪x, y⟫ * t + re ⟪y, x⟫ * t + re ⟪y, y⟫ := by rw [mul_comm ⟪x,y⟫ _, RCLike.re_ofReal_mul, mul_comm t _, mul_comm ⟪y,x⟫ _, RCLike.re_ofReal_mul, mul_comm t _] - _ = normSq x * t * t + re ⟪x, y⟫ * t + re ⟪y, x⟫ * t + normSq y := by exact rfl + _ = normSq x * t * t + re ⟪x, y⟫ * t + re ⟪y, x⟫ * t + normSq y := by rw [← normSq] _ = normSq x * t * t + re ⟪x, y⟫ * t + re ⟪x, y⟫ * t + normSq y := by rw [inner_re_symm] _ = normSq x * t * t + 2 * re ⟪x, y⟫ * t + normSq y := by ring @@ -359,7 +359,7 @@ theorem inner_mul_inner_self_le (x y : F) : ‖⟪x, y⟫‖ * ‖⟪y, x⟫‖ convert cauchy_schwarz_aux' (𝕜 := 𝕜) (⟪x, y⟫ • x) y (t / ‖⟪x, y⟫‖) using 3 · field_simp rw [← sq, normSq, normSq, inner_smul_right, inner_smul_left, ← mul_assoc _ _ ⟪x, x⟫, - mul_conj] + mul_conj] nth_rw 2 [sq] rw [← ofReal_mul, re_ofReal_mul] ring @@ -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 := @@ -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 _ _ _ @@ -591,26 +615,26 @@ theorem inner_sum {ι : Type*} (s : Finset ι) (f : ι → E) (x : E) : map_sum (LinearMap.flip sesqFormOfInner x) _ _ /-- An inner product with a sum on the left, `Finsupp` version. -/ -theorem Finsupp.sum_inner {ι : Type*} (l : ι →₀ 𝕜) (v : ι → E) (x : E) : +protected theorem Finsupp.sum_inner {ι : Type*} (l : ι →₀ 𝕜) (v : ι → E) (x : E) : ⟪l.sum fun (i : ι) (a : 𝕜) => a • v i, x⟫ = l.sum fun (i : ι) (a : 𝕜) => conj a • ⟪v i, x⟫ := by - convert _root_.sum_inner (𝕜 := 𝕜) l.support (fun a => l a • v a) x + convert sum_inner (𝕜 := 𝕜) l.support (fun a => l a • v a) x simp only [inner_smul_left, Finsupp.sum, smul_eq_mul] /-- An inner product with a sum on the right, `Finsupp` version. -/ -theorem Finsupp.inner_sum {ι : Type*} (l : ι →₀ 𝕜) (v : ι → E) (x : E) : +protected theorem Finsupp.inner_sum {ι : Type*} (l : ι →₀ 𝕜) (v : ι → E) (x : E) : ⟪x, l.sum fun (i : ι) (a : 𝕜) => a • v i⟫ = l.sum fun (i : ι) (a : 𝕜) => a • ⟪x, v i⟫ := by - convert _root_.inner_sum (𝕜 := 𝕜) l.support (fun a => l a • v a) x + convert inner_sum (𝕜 := 𝕜) l.support (fun a => l a • v a) x simp only [inner_smul_right, Finsupp.sum, smul_eq_mul] -theorem DFinsupp.sum_inner {ι : Type*} [DecidableEq ι] {α : ι → Type*} +protected theorem DFinsupp.sum_inner {ι : Type*} [DecidableEq ι] {α : ι → Type*} [∀ i, AddZeroClass (α i)] [∀ (i) (x : α i), Decidable (x ≠ 0)] (f : ∀ i, α i → E) (l : Π₀ i, α i) (x : E) : ⟪l.sum f, x⟫ = l.sum fun i a => ⟪f i a, x⟫ := by - simp (config := { contextual := true }) only [DFinsupp.sum, _root_.sum_inner, smul_eq_mul] + simp (config := { contextual := true }) only [DFinsupp.sum, sum_inner, smul_eq_mul] -theorem DFinsupp.inner_sum {ι : Type*} [DecidableEq ι] {α : ι → Type*} +protected theorem DFinsupp.inner_sum {ι : Type*} [DecidableEq ι] {α : ι → Type*} [∀ i, AddZeroClass (α i)] [∀ (i) (x : α i), Decidable (x ≠ 0)] (f : ∀ i, α i → E) (l : Π₀ i, α i) (x : E) : ⟪x, l.sum f⟫ = l.sum fun i a => ⟪x, f i a⟫ := by - simp (config := { contextual := true }) only [DFinsupp.sum, _root_.inner_sum, smul_eq_mul] + simp (config := { contextual := true }) only [DFinsupp.sum, inner_sum, smul_eq_mul] @[simp] theorem inner_zero_left (x : E) : ⟪0, x⟫ = 0 := by @@ -634,7 +658,7 @@ theorem real_inner_self_nonneg {x : F} : 0 ≤ ⟪x, x⟫_ℝ := @[simp] theorem inner_self_ofReal_re (x : E) : (re ⟪x, x⟫ : 𝕜) = ⟪x, x⟫ := - ((RCLike.is_real_TFAE (⟪x, x⟫ : 𝕜)).out 2 3).2 (inner_self_im _) + ((RCLike.is_real_TFAE (⟪x, x⟫ : 𝕜)).out 2 3).2 (inner_self_im (𝕜 := 𝕜) x) theorem inner_self_eq_norm_sq_to_K (x : E) : ⟪x, x⟫ = (‖x‖ : 𝕜) ^ 2 := by rw [← inner_self_ofReal_re, ← norm_sq_eq_inner, ofReal_pow] @@ -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 @@ -829,9 +854,9 @@ theorem orthonormal_subtype_iff_ite [DecidableEq E] {s : Set E} : /-- The inner product of a linear combination of a set of orthonormal vectors with one of those vectors picks out the coefficient of that vector. -/ theorem Orthonormal.inner_right_finsupp {v : ι → E} (hv : Orthonormal 𝕜 v) (l : ι →₀ 𝕜) (i : ι) : - ⟪v i, Finsupp.total ι E 𝕜 v l⟫ = l i := by + ⟪v i, linearCombination 𝕜 v l⟫ = l i := by classical - simpa [Finsupp.total_apply, Finsupp.inner_sum, orthonormal_iff_ite.mp hv] using Eq.symm + simpa [linearCombination_apply, Finsupp.inner_sum, orthonormal_iff_ite.mp hv] using Eq.symm /-- The inner product of a linear combination of a set of orthonormal vectors with one of those vectors picks out the coefficient of that vector. -/ @@ -849,7 +874,7 @@ theorem Orthonormal.inner_right_fintype [Fintype ι] {v : ι → E} (hv : Orthon /-- The inner product of a linear combination of a set of orthonormal vectors with one of those vectors picks out the coefficient of that vector. -/ theorem Orthonormal.inner_left_finsupp {v : ι → E} (hv : Orthonormal 𝕜 v) (l : ι →₀ 𝕜) (i : ι) : - ⟪Finsupp.total ι E 𝕜 v l, v i⟫ = conj (l i) := by rw [← inner_conj_symm, hv.inner_right_finsupp] + ⟪linearCombination 𝕜 v l, v i⟫ = conj (l i) := by rw [← inner_conj_symm, hv.inner_right_finsupp] /-- The inner product of a linear combination of a set of orthonormal vectors with one of those vectors picks out the coefficient of that vector. -/ @@ -868,19 +893,20 @@ theorem Orthonormal.inner_left_fintype [Fintype ι] {v : ι → E} (hv : Orthono /-- The inner product of two linear combinations of a set of orthonormal vectors, expressed as a sum over the first `Finsupp`. -/ theorem Orthonormal.inner_finsupp_eq_sum_left {v : ι → E} (hv : Orthonormal 𝕜 v) (l₁ l₂ : ι →₀ 𝕜) : - ⟪Finsupp.total ι E 𝕜 v l₁, Finsupp.total ι E 𝕜 v l₂⟫ = l₁.sum fun i y => conj y * l₂ i := by - simp only [l₁.total_apply _, Finsupp.sum_inner, hv.inner_right_finsupp, smul_eq_mul] + ⟪linearCombination 𝕜 v l₁, linearCombination 𝕜 v l₂⟫ = l₁.sum fun i y => conj y * l₂ i := by + simp only [l₁.linearCombination_apply _, Finsupp.sum_inner, hv.inner_right_finsupp, smul_eq_mul] /-- The inner product of two linear combinations of a set of orthonormal vectors, expressed as a sum over the second `Finsupp`. -/ theorem Orthonormal.inner_finsupp_eq_sum_right {v : ι → E} (hv : Orthonormal 𝕜 v) (l₁ l₂ : ι →₀ 𝕜) : - ⟪Finsupp.total ι E 𝕜 v l₁, Finsupp.total ι E 𝕜 v l₂⟫ = l₂.sum fun i y => conj (l₁ i) * y := by - simp only [l₂.total_apply _, Finsupp.inner_sum, hv.inner_left_finsupp, mul_comm, smul_eq_mul] + ⟪linearCombination 𝕜 v l₁, linearCombination 𝕜 v l₂⟫ = l₂.sum fun i y => conj (l₁ i) * y := by + simp only [l₂.linearCombination_apply _, Finsupp.inner_sum, hv.inner_left_finsupp, mul_comm, + smul_eq_mul] /-- The inner product of two linear combinations of a set of orthonormal vectors, expressed as a sum. -/ -theorem Orthonormal.inner_sum {v : ι → E} (hv : Orthonormal 𝕜 v) (l₁ l₂ : ι → 𝕜) (s : Finset ι) : - ⟪∑ i ∈ s, l₁ i • v i, ∑ i ∈ s, l₂ i • v i⟫ = ∑ i ∈ s, conj (l₁ i) * l₂ i := by +protected theorem Orthonormal.inner_sum {v : ι → E} (hv : Orthonormal 𝕜 v) (l₁ l₂ : ι → 𝕜) + (s : Finset ι) : ⟪∑ i ∈ s, l₁ i • v i, ∑ i ∈ s, l₂ i • v i⟫ = ∑ i ∈ s, conj (l₁ i) * l₂ i := by simp_rw [sum_inner, inner_smul_left] refine Finset.sum_congr rfl fun i hi => ?_ rw [hv.inner_right_sum l₂ hi] @@ -900,7 +926,7 @@ theorem Orthonormal.linearIndependent {v : ι → E} (hv : Orthonormal 𝕜 v) : rw [linearIndependent_iff] intro l hl ext i - have key : ⟪v i, Finsupp.total ι E 𝕜 v l⟫ = ⟪v i, 0⟫ := by rw [hl] + have key : ⟪v i, Finsupp.linearCombination 𝕜 v l⟫ = ⟪v i, 0⟫ := by rw [hl] simpa only [hv.inner_right_finsupp, inner_zero_right] using key /-- A subfamily of an orthonormal family (i.e., a composition with an injective map) is an @@ -932,7 +958,7 @@ theorem Orthonormal.toSubtypeRange {v : ι → E} (hv : Orthonormal 𝕜 v) : set. -/ theorem Orthonormal.inner_finsupp_eq_zero {v : ι → E} (hv : Orthonormal 𝕜 v) {s : Set ι} {i : ι} (hi : i ∉ s) {l : ι →₀ 𝕜} (hl : l ∈ Finsupp.supported 𝕜 𝕜 s) : - ⟪Finsupp.total ι E 𝕜 v l, v i⟫ = 0 := by + ⟪Finsupp.linearCombination 𝕜 v l, v i⟫ = 0 := by rw [Finsupp.mem_supported'] at hl simp only [hv.inner_left_finsupp, hl i hi, map_zero] @@ -987,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) @@ -1000,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] @@ -1193,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 -/ @@ -1221,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 @@ -1321,7 +1340,8 @@ theorem Orthonormal.mapLinearIsometryEquiv {v : Basis ι 𝕜 E} (hv : Orthonorm def LinearMap.isometryOfOrthonormal (f : E →ₗ[𝕜] E') {v : Basis ι 𝕜 E} (hv : Orthonormal 𝕜 v) (hf : Orthonormal 𝕜 (f ∘ v)) : E →ₗᵢ[𝕜] E' := f.isometryOfInner fun x y => by - classical rw [← v.total_repr x, ← v.total_repr y, Finsupp.apply_total, Finsupp.apply_total, + classical rw [← v.linearCombination_repr x, ← v.linearCombination_repr y, + Finsupp.apply_linearCombination, Finsupp.apply_linearCombination, hv.inner_finsupp_eq_sum_left, hf.inner_finsupp_eq_sum_left] @[simp] @@ -1341,8 +1361,9 @@ def LinearEquiv.isometryOfOrthonormal (f : E ≃ₗ[𝕜] E') {v : Basis ι 𝕜 (hf : Orthonormal 𝕜 (f ∘ v)) : E ≃ₗᵢ[𝕜] E' := f.isometryOfInner fun x y => by rw [← LinearEquiv.coe_coe] at hf - classical rw [← v.total_repr x, ← v.total_repr y, ← LinearEquiv.coe_coe f, Finsupp.apply_total, - Finsupp.apply_total, hv.inner_finsupp_eq_sum_left, hf.inner_finsupp_eq_sum_left] + classical rw [← v.linearCombination_repr x, ← v.linearCombination_repr y, + ← LinearEquiv.coe_coe f, Finsupp.apply_linearCombination, + Finsupp.apply_linearCombination, hv.inner_finsupp_eq_sum_left, hf.inner_finsupp_eq_sum_left] @[simp] theorem LinearEquiv.coe_isometryOfOrthonormal (f : E ≃ₗ[𝕜] E') {v : Basis ι 𝕜 E} @@ -1414,8 +1435,8 @@ theorem norm_add_sq_eq_norm_sq_add_norm_sq_iff_real_inner_eq_zero (x y : F) : /-- Pythagorean theorem, if-and-if vector inner product form using square roots. -/ theorem norm_add_eq_sqrt_iff_real_inner_eq_zero {x y : F} : ‖x + y‖ = √(‖x‖ * ‖x‖ + ‖y‖ * ‖y‖) ↔ ⟪x, y⟫_ℝ = 0 := by - rw [← norm_add_sq_eq_norm_sq_add_norm_sq_iff_real_inner_eq_zero, eq_comm, - sqrt_eq_iff_mul_self_eq (add_nonneg (mul_self_nonneg _) (mul_self_nonneg _)) (norm_nonneg _)] + rw [← norm_add_sq_eq_norm_sq_add_norm_sq_iff_real_inner_eq_zero, eq_comm, sqrt_eq_iff_mul_self_eq, + eq_comm] <;> positivity /-- Pythagorean theorem, vector inner product form. -/ theorem norm_add_sq_eq_norm_sq_add_norm_sq_of_inner_eq_zero (x y : E) (h : ⟪x, y⟫ = 0) : @@ -1441,8 +1462,8 @@ theorem norm_sub_sq_eq_norm_sq_add_norm_sq_iff_real_inner_eq_zero (x y : F) : roots. -/ theorem norm_sub_eq_sqrt_iff_real_inner_eq_zero {x y : F} : ‖x - y‖ = √(‖x‖ * ‖x‖ + ‖y‖ * ‖y‖) ↔ ⟪x, y⟫_ℝ = 0 := by - rw [← norm_sub_sq_eq_norm_sq_add_norm_sq_iff_real_inner_eq_zero, eq_comm, - sqrt_eq_iff_mul_self_eq (add_nonneg (mul_self_nonneg _) (mul_self_nonneg _)) (norm_nonneg _)] + rw [← norm_sub_sq_eq_norm_sq_add_norm_sq_iff_real_inner_eq_zero, eq_comm, sqrt_eq_iff_mul_self_eq, + eq_comm] <;> positivity /-- Pythagorean theorem, subtracting vectors, vector inner product form. -/ @@ -1474,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 @@ -1544,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 @@ -1569,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*} @@ -1602,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. -/ @@ -1662,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 @@ -1673,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 @@ -1796,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 @@ -1880,7 +1902,7 @@ theorem Orthonormal.sum_inner_products_le {s : Finset ι} (hv : Orthonormal 𝕜 rw [← sub_nonneg, ← hbf] simp only [norm_nonneg, pow_nonneg] rw [@norm_sub_sq 𝕜, sub_add] - simp only [@InnerProductSpace.norm_sq_eq_inner 𝕜, _root_.inner_sum, _root_.sum_inner] + simp only [@InnerProductSpace.norm_sq_eq_inner 𝕜, inner_sum, sum_inner] simp only [inner_smul_right, two_mul, inner_smul_left, inner_conj_symm, ← mul_assoc, h₂, add_sub_cancel_right, sub_right_inj] simp only [map_sum, ← inner_conj_symm x, ← h₃] @@ -2036,12 +2058,12 @@ theorem OrthogonalFamily.inner_right_fintype [Fintype ι] (l : ∀ i, G i) (i : _ = ⟪v, l i⟫ := by simp only [Finset.sum_ite_eq, Finset.mem_univ, (V i).inner_map_map, if_true] -theorem OrthogonalFamily.inner_sum (l₁ l₂ : ∀ i, G i) (s : Finset ι) : +nonrec theorem OrthogonalFamily.inner_sum (l₁ l₂ : ∀ i, G i) (s : Finset ι) : ⟪∑ i ∈ s, V i (l₁ i), ∑ j ∈ s, V j (l₂ j)⟫ = ∑ i ∈ s, ⟪l₁ i, l₂ i⟫ := by classical calc ⟪∑ i ∈ s, V i (l₁ i), ∑ j ∈ s, V j (l₂ j)⟫ = ∑ j ∈ s, ∑ i ∈ s, ⟪V i (l₁ i), V j (l₂ j)⟫ := by - simp only [_root_.sum_inner, _root_.inner_sum] + simp only [sum_inner, inner_sum] _ = ∑ j ∈ s, ∑ i ∈ s, ite (i = j) ⟪V i (l₁ i), V j (l₂ j)⟫ 0 := by congr with i congr with j @@ -2193,6 +2215,8 @@ end OrthogonalFamily section RCLikeToReal +open scoped InnerProductSpace + variable {G : Type*} variable (𝕜 E) variable [SeminormedAddCommGroup E] [InnerProductSpace 𝕜 E] @@ -2258,7 +2282,7 @@ end RCLikeToReal section Continuous -variable [NormedAddCommGroup E] [InnerProductSpace 𝕜 E] +variable [SeminormedAddCommGroup E] [InnerProductSpace 𝕜 E] local notation "⟪" x ", " y "⟫" => @inner 𝕜 _ _ x y @@ -2273,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*} @@ -2323,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 @@ -2343,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 @@ -2359,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 : @@ -2376,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) : α → 𝕜) := @@ -2413,3 +2465,5 @@ instance innerProductSpace : InnerProductSpace 𝕜 (Completion E) where end UniformSpace.Completion end UniformSpace.Completion + +set_option linter.style.longFile 2500 diff --git a/Mathlib/Analysis/InnerProductSpace/Calculus.lean b/Mathlib/Analysis/InnerProductSpace/Calculus.lean index 031592910f445..44808e4d72423 100644 --- a/Mathlib/Analysis/InnerProductSpace/Calculus.lean +++ b/Mathlib/Analysis/InnerProductSpace/Calculus.lean @@ -80,15 +80,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) : 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 dc8c71696a394..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 ι (· < ·)] @@ -137,7 +137,7 @@ theorem gramSchmidt_mem_span (f : ι → E) : (Submodule.sum_mem _ fun k hk => ?_) let hkj : k < j := (Finset.mem_Iio.1 hk).trans_le hij exact smul_mem _ _ - (span_mono (image_subset f <| Iic_subset_Iic.2 hkj.le) <| gramSchmidt_mem_span _ le_rfl) + (span_mono (image_subset f <| Set.Iic_subset_Iic.2 hkj.le) <| gramSchmidt_mem_span _ le_rfl) termination_by j => j theorem span_gramSchmidt_Iic (f : ι → E) (c : ι) : diff --git a/Mathlib/Analysis/InnerProductSpace/JointEigenspace.lean b/Mathlib/Analysis/InnerProductSpace/JointEigenspace.lean new file mode 100644 index 0000000000000..049ba1532a238 --- /dev/null +++ b/Mathlib/Analysis/InnerProductSpace/JointEigenspace.lean @@ -0,0 +1,113 @@ +/- +Copyright (c) 2024 Jon Bannon. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jon Bannon, Jack Cheverton, Samyak Dhar Tuladhar +-/ + +import Mathlib.Analysis.InnerProductSpace.Spectrum +import Mathlib.Analysis.InnerProductSpace.Projection +import Mathlib.Order.CompleteLattice +import Mathlib.LinearAlgebra.Eigenspace.Basic + +/-! # Joint eigenspaces of a commuting pair of symmetric operators + +This file collects various decomposition results for joint eigenspaces of a commuting pair +of symmetric operators on a finite-dimensional inner product space. + +# Main Result + +* `LinearMap.IsSymmetric.directSum_isInternal_of_commute` establishes that + if `{A B : E →ₗ[𝕜] E}`, then `IsSymmetric A`, `IsSymmetric B` and `A ∘ₗ B = B ∘ₗ A` imply that + `E` decomposes as an internal direct sum of the pairwise orthogonal spaces + `eigenspace B μ ⊓ eigenspace A ν` + +## TODO + +Develop a `Diagonalization` structure for linear maps and / or matrices which consists of a basis, +and a proof obligation that the basis vectors are eigenvectors. + +## Tags + +self-adjoint operator, simultaneous eigenspaces, joint eigenspaces + +-/ + +variable {𝕜 E : Type*} [RCLike 𝕜] +variable [NormedAddCommGroup E] [InnerProductSpace 𝕜 E] + +open Module.End + +namespace LinearMap + +namespace IsSymmetric + +section Pair + +variable {α : 𝕜} {A B : E →ₗ[𝕜] E} + +/--If a pair of operators commute, then the eigenspaces of one are invariant under the other.-/ +theorem eigenspace_invariant_of_commute + (hAB : A ∘ₗ B = B ∘ₗ A) (α : 𝕜) : ∀ v ∈ (eigenspace A α), (B v ∈ eigenspace A α) := by + intro v hv + 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 +`OrthogonalFamily`.-/ +theorem orthogonalFamily_eigenspace_inf_eigenspace (hA : A.IsSymmetric) (hB : B.IsSymmetric) : + OrthogonalFamily 𝕜 (fun (i : 𝕜 × 𝕜) => (eigenspace A i.2 ⊓ eigenspace B i.1 : Submodule 𝕜 E)) + (fun i => (eigenspace A i.2 ⊓ eigenspace B i.1).subtypeₗᵢ) := + OrthogonalFamily.of_pairwise fun i j hij v ⟨hv1 , hv2⟩ ↦ by + obtain (h₁ | h₂) : i.1 ≠ j.1 ∨ i.2 ≠ j.2 := by rwa [Ne.eq_def, Prod.ext_iff, not_and_or] at hij + all_goals intro w ⟨hw1, hw2⟩ + · exact hB.orthogonalFamily_eigenspaces.pairwise h₁ hv2 w hw2 + · exact hA.orthogonalFamily_eigenspaces.pairwise h₂ hv1 w hw1 + +open Submodule in + +/-- The intersection of eigenspaces of commuting selfadjoint operators is equal to the eigenspace of +one operator restricted to the eigenspace of the other, which is an invariant subspace because the +operators commute. -/ +theorem eigenspace_inf_eigenspace + (hAB : A ∘ₗ B = B ∘ₗ A) (γ : 𝕜) : + eigenspace A α ⊓ eigenspace B γ = map (Submodule.subtype (eigenspace A α)) + (eigenspace (B.restrict (eigenspace_invariant_of_commute hAB α)) γ) := + (eigenspace A α).inf_genEigenspace _ _ (k := 1) + +variable [FiniteDimensional 𝕜 E] + +/-- If A and B are commuting symmetric operators on a finite dimensional inner product space +then the eigenspaces of the restriction of B to any eigenspace of A exhaust that eigenspace.-/ +theorem iSup_eigenspace_inf_eigenspace (hB : B.IsSymmetric) + (hAB : A ∘ₗ B = B ∘ₗ A): + (⨆ γ, eigenspace A α ⊓ eigenspace B γ) = eigenspace A α := by + conv_rhs => rw [← (eigenspace A α).map_subtype_top] + simp only [eigenspace_inf_eigenspace hAB, ← Submodule.map_iSup] + congr 1 + rw [← Submodule.orthogonal_eq_bot_iff] + exact orthogonalComplement_iSup_eigenspaces_eq_bot <| + hB.restrict_invariant <| eigenspace_invariant_of_commute hAB α + +/-- If A and B are commuting symmetric operators acting on a finite dimensional inner product space, +then the simultaneous eigenspaces of A and B exhaust the space. -/ +theorem iSup_iSup_eigenspace_inf_eigenspace_eq_top (hA : A.IsSymmetric) (hB : B.IsSymmetric) + (hAB : A ∘ₗ B = B ∘ₗ A) : + (⨆ α, ⨆ γ, eigenspace A α ⊓ eigenspace B γ) = ⊤ := by + simpa [iSup_eigenspace_inf_eigenspace hB hAB] using + Submodule.orthogonal_eq_bot_iff.mp <| hA.orthogonalComplement_iSup_eigenspaces_eq_bot + +/-- Given a commuting pair of symmetric linear operators on a finite dimensional inner product +space, the space decomposes as an internal direct sum of simultaneous eigenspaces of these +operators. -/ +theorem directSum_isInteral_of_commute (hA : A.IsSymmetric) (hB : B.IsSymmetric) + (hAB : A ∘ₗ B = B ∘ₗ A) : + DirectSum.IsInternal (fun (i : 𝕜 × 𝕜) ↦ (eigenspace A i.2 ⊓ eigenspace B i.1)):= by + apply (orthogonalFamily_eigenspace_inf_eigenspace hA hB).isInternal_iff.mpr + rw [Submodule.orthogonal_eq_bot_iff, iSup_prod, iSup_comm] + exact iSup_iSup_eigenspace_inf_eigenspace_eq_top hA hB hAB + +end Pair + +end IsSymmetric + +end LinearMap diff --git a/Mathlib/Analysis/InnerProductSpace/LaxMilgram.lean b/Mathlib/Analysis/InnerProductSpace/LaxMilgram.lean index 4cc1814eab7a9..9aa623e738fae 100644 --- a/Mathlib/Analysis/InnerProductSpace/LaxMilgram.lean +++ b/Mathlib/Analysis/InnerProductSpace/LaxMilgram.lean @@ -44,7 +44,7 @@ namespace IsCoercive variable {V : Type u} [NormedAddCommGroup V] [InnerProductSpace ℝ V] [CompleteSpace V] variable {B : V →L[ℝ] V →L[ℝ] ℝ} -local postfix:1024 "♯" => @continuousLinearMapOfBilin ℝ V _ _ _ _ +local postfix:1024 "♯" => continuousLinearMapOfBilin (𝕜 := ℝ) theorem bounded_below (coercive : IsCoercive B) : ∃ C, 0 < C ∧ ∀ v, C * ‖v‖ ≤ ‖B♯ v‖ := by rcases coercive with ⟨C, C_ge_0, coercivity⟩ @@ -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..13396afdb97d0 100644 --- a/Mathlib/Analysis/InnerProductSpace/LinearPMap.lean +++ b/Mathlib/Analysis/InnerProductSpace/LinearPMap.lean @@ -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 cc637d03ff57a..e2e23c0b46a9d 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_, Nat.zero_eq, 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 => ?_) + 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 4629fbeeaa6c4..5fb4aa1c20293 100644 --- a/Mathlib/Analysis/InnerProductSpace/PiL2.lean +++ b/Mathlib/Analysis/InnerProductSpace/PiL2.lean @@ -136,7 +136,7 @@ theorem EuclideanSpace.sphere_zero_eq {n : Type*} [Fintype n] (r : ℝ) (hr : 0 ext x have : (0 : ℝ) ≤ ∑ i, x i ^ 2 := Finset.sum_nonneg fun _ _ => sq_nonneg _ simp_rw [mem_setOf, mem_sphere_zero_iff_norm, norm_eq, norm_eq_abs, sq_abs, - Real.sqrt_eq_iff_sq_eq this hr, eq_comm] + Real.sqrt_eq_iff_eq_sq this hr] section @@ -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) := @@ -386,6 +386,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 +669,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 +679,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 +708,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 +792,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 +840,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 +885,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 +935,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 +947,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/Positive.lean b/Mathlib/Analysis/InnerProductSpace/Positive.lean index c874c7b049ac5..d3c5fef5c6c27 100644 --- a/Mathlib/Analysis/InnerProductSpace/Positive.lean +++ b/Mathlib/Analysis/InnerProductSpace/Positive.lean @@ -99,6 +99,31 @@ theorem IsPositive.orthogonalProjection_comp {T : E →L[𝕜] E} (hT : T.IsPosi have := hT.conj_adjoint (orthogonalProjection U : E →L[𝕜] U) rwa [U.adjoint_orthogonalProjection] at this +open scoped NNReal + +lemma antilipschitz_of_forall_le_inner_map {H : Type*} [NormedAddCommGroup H] + [InnerProductSpace 𝕜 H] (f : H →L[𝕜] H) {c : ℝ≥0} (hc : 0 < c) + (h : ∀ x, ‖x‖ ^ 2 * c ≤ ‖⟪f x, x⟫_𝕜‖) : AntilipschitzWith c⁻¹ f := by + refine f.antilipschitz_of_bound (K := c⁻¹) fun x ↦ ?_ + rw [NNReal.coe_inv, inv_mul_eq_div, le_div_iff₀ (by exact_mod_cast hc)] + simp_rw [sq, mul_assoc] at h + by_cases hx0 : x = 0 + · simp [hx0] + · apply (map_le_map_iff <| OrderIso.mulLeft₀ ‖x‖ (norm_pos_iff'.mpr hx0)).mp + exact (h x).trans <| (norm_inner_le_norm _ _).trans <| (mul_comm _ _).le + +lemma isUnit_of_forall_le_norm_inner_map (f : E →L[𝕜] E) {c : ℝ≥0} (hc : 0 < c) + (h : ∀ x, ‖x‖ ^ 2 * c ≤ ‖⟪f x, x⟫_𝕜‖) : IsUnit f := by + rw [isUnit_iff_bijective, bijective_iff_dense_range_and_antilipschitz] + have h_anti : AntilipschitzWith c⁻¹ f := antilipschitz_of_forall_le_inner_map f hc h + refine ⟨?_, ⟨_, h_anti⟩⟩ + have _inst := h_anti.completeSpace_range_clm + rw [Submodule.topologicalClosure_eq_top_iff, Submodule.eq_bot_iff] + intro x hx + have : ‖x‖ ^ 2 * c = 0 := le_antisymm (by simpa only [hx (f x) ⟨x, rfl⟩, norm_zero] using h x) + (by positivity) + aesop + section Complex variable {E' : Type*} [NormedAddCommGroup E'] [InnerProductSpace ℂ E'] [CompleteSpace E'] diff --git a/Mathlib/Analysis/InnerProductSpace/Projection.lean b/Mathlib/Analysis/InnerProductSpace/Projection.lean index 16736b2f40a3e..28ef290eefc60 100644 --- a/Mathlib/Analysis/InnerProductSpace/Projection.lean +++ b/Mathlib/Analysis/InnerProductSpace/Projection.lean @@ -42,11 +42,13 @@ 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 +891,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 +1031,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 +1040,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 +1190,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 +1272,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. -/ @@ -1329,8 +1332,8 @@ theorem maximal_orthonormal_iff_orthogonalComplement_eq_bot (hv : Orthonormal intro hxv y hy have hxv' : (⟨x, hxu⟩ : u) ∉ ((↑) ⁻¹' v : Set u) := by simp [huv, hxv] obtain ⟨l, hl, rfl⟩ : - ∃ l ∈ Finsupp.supported 𝕜 𝕜 ((↑) ⁻¹' v : Set u), (Finsupp.total (↥u) E 𝕜 (↑)) l = y := by - rw [← Finsupp.mem_span_image_iff_total] + ∃ l ∈ supported 𝕜 𝕜 ((↑) ⁻¹' v : Set u), (linearCombination 𝕜 ((↑) : u → E)) l = y := by + rw [← Finsupp.mem_span_image_iff_linearCombination] simp [huv, inter_eq_self_of_subset_right, hy] exact hu.inner_finsupp_eq_zero hxv' hl @@ -1340,7 +1343,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 new file mode 100644 index 0000000000000..7ed9ab6de0e4b --- /dev/null +++ b/Mathlib/Analysis/InnerProductSpace/StarOrder.lean @@ -0,0 +1,77 @@ +/- +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.InnerProductSpace.Positive +import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.Instances + +/-! +# Continuous linear maps on a Hilbert space are a `StarOrderedRing` + +In this file we show that the continuous linear maps on a complex Hilbert space form a +`StarOrderedRing`. Note that they are already equipped with the Loewner partial order. We also +prove that, with respect to this partial order, a map is positive if every element of the +real spectrum is nonnegative. Consequently, when `H` is a Hilbert space, then `H →L[ℂ] H` is +equipped with all the usual instances of the continuous functional calculus. + + -/ + +namespace ContinuousLinearMap + +open RCLike +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] + intro c hc + contrapose! hc + rw [spectrum.not_mem_iff, IsUnit.sub_iff, sub_eq_add_neg, ← map_neg] + rw [← neg_pos] at hc + set c := -c + exact isUnit_of_forall_le_norm_inner_map _ (c := ⟨c, hc.le⟩) hc fun x ↦ calc + ‖x‖ ^ 2 * c = re ⟪algebraMap ℝ (H →L[𝕜] H) c x, x⟫_𝕜 := by + rw [Algebra.algebraMap_eq_smul_one, ← algebraMap_smul 𝕜 c (1 : (H →L[𝕜] H)), coe_smul', + Pi.smul_apply, one_apply, inner_smul_left, RCLike.algebraMap_eq_ofReal, conj_ofReal, + re_ofReal_mul, inner_self_eq_norm_sq, mul_comm] + _ ≤ re ⟪(f + (algebraMap ℝ (H →L[𝕜] H)) c) x, x⟫_𝕜 := by + simpa only [add_apply, inner_add_left, map_add, le_add_iff_nonneg_left] + using hf.inner_nonneg_left x + _ ≤ ‖⟪(f + (algebraMap ℝ (H →L[𝕜] H)) c) x, x⟫_𝕜‖ := RCLike.re_le_norm _ + +instance : NonnegSpectrumClass ℝ (H →L[𝕜] H) where + quasispectrum_nonneg_of_nonneg f hf := + QuasispectrumRestricts.nnreal_iff.mp <| sub_zero f ▸ hf.spectrumRestricts + +/-- Because this takes `ContinuousFunctionalCalculus ℝ IsSelfAdjoint` as an argument, and for +the moment we only have this for `𝕜 := ℂ`, this is not registered as an instance. -/ +lemma instStarOrderedRingRCLike + [ContinuousFunctionalCalculus ℝ (IsSelfAdjoint : (H →L[𝕜] H) → Prop)] : + StarOrderedRing (H →L[𝕜] H) where + le_iff f g := by + constructor + · intro h + rw [le_def] at h + obtain ⟨p, hp₁, -, hp₃⟩ := + CFC.exists_sqrt_of_isSelfAdjoint_of_spectrumRestricts h.1 h.spectrumRestricts + refine ⟨p ^ 2, ?_, by symm; rwa [add_comm, ← eq_sub_iff_add_eq]⟩ + 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 + | 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 + +instance instStarOrderedRing {H : Type*} [NormedAddCommGroup H] + [InnerProductSpace ℂ H] [CompleteSpace H] : StarOrderedRing (H →L[ℂ] H) := + instStarOrderedRingRCLike + +end ContinuousLinearMap diff --git a/Mathlib/Analysis/InnerProductSpace/Symmetric.lean b/Mathlib/Analysis/InnerProductSpace/Symmetric.lean index cc99f2f374367..9acf7b33a0635 100644 --- a/Mathlib/Analysis/InnerProductSpace/Symmetric.lean +++ b/Mathlib/Analysis/InnerProductSpace/Symmetric.lean @@ -36,11 +36,13 @@ open RCLike open ComplexConjugate +section Seminormed + 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'] +variable [SeminormedAddCommGroup E] [InnerProductSpace 𝕜 E] +variable [SeminormedAddCommGroup F] [InnerProductSpace 𝕜 F] +variable [SeminormedAddCommGroup G] [InnerProductSpace 𝕜 G] +variable [SeminormedAddCommGroup E'] [InnerProductSpace ℝ E'] local notation "⟪" x ", " y "⟫" => @inner 𝕜 _ _ x y @@ -72,33 +74,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 +131,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 +183,39 @@ 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 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'] + +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 +227,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 8792d83e9e577..329dd441e2adc 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) @@ -418,12 +418,11 @@ theorem nonneg_inner_and_areaForm_eq_zero_iff_sameRay (x y : E) : have hx' : 0 < ‖x‖ := by simpa using hx have ha' : 0 ≤ a := nonneg_of_mul_nonneg_left ha (by positivity) have hb' : b = 0 := eq_zero_of_ne_zero_of_mul_right_eq_zero (pow_ne_zero 2 hx'.ne') hb - exact (SameRay.sameRay_nonneg_smul_right x ha').add_right $ by simp [hb'] + exact (SameRay.sameRay_nonneg_smul_right x ha').add_right <| by simp [hb'] · 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 4552de407ddb4..54a08fc3d190b 100644 --- a/Mathlib/Analysis/InnerProductSpace/l2Space.lean +++ b/Mathlib/Analysis/InnerProductSpace/l2Space.lean @@ -187,7 +187,7 @@ protected theorem summable_of_lp (f : lp G 2) : /-- A mutually orthogonal family of subspaces of `E` induce a linear isometry from `lp 2` of the subspaces into `E`. -/ -protected def linearIsometry : lp G 2 →ₗᵢ[𝕜] E where +protected def linearIsometry (hV : OrthogonalFamily 𝕜 G V) : lp G 2 →ₗᵢ[𝕜] E where toFun f := ∑' i, V i (f i) map_add' f g := by simp only [tsum_add (hV.summable_of_lp f) (hV.summable_of_lp g), lp.coeFn_add, Pi.add_apply, @@ -237,7 +237,7 @@ protected theorem range_linearIsometry [∀ i, CompleteSpace (G i)] : classical refine le_antisymm ?_ ?_ · rintro x ⟨f, rfl⟩ - refine mem_closure_of_tendsto (hV.hasSum_linearIsometry f) (eventually_of_forall ?_) + refine mem_closure_of_tendsto (hV.hasSum_linearIsometry f) (Eventually.of_forall ?_) intro s rw [SetLike.mem_coe] refine sum_mem ?_ @@ -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 @@ -441,7 +441,7 @@ protected theorem dense_span (b : HilbertBasis ι 𝕜 E) : classical rw [eq_top_iff] rintro x - - refine mem_closure_of_tendsto (b.hasSum_repr x) (eventually_of_forall ?_) + refine mem_closure_of_tendsto (b.hasSum_repr x) (Eventually.of_forall ?_) intro s simp only [SetLike.mem_coe] refine sum_mem ?_ diff --git a/Mathlib/Analysis/LocallyConvex/BalancedCoreHull.lean b/Mathlib/Analysis/LocallyConvex/BalancedCoreHull.lean index c5cb5452393dd..08b82218840f4 100644 --- a/Mathlib/Analysis/LocallyConvex/BalancedCoreHull.lean +++ b/Mathlib/Analysis/LocallyConvex/BalancedCoreHull.lean @@ -131,7 +131,7 @@ 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⟩ end Module @@ -139,7 +139,7 @@ end SeminormedRing section NormedField -variable [NormedField 𝕜] [AddCommGroup E] [Module 𝕜 E] {s t : Set E} +variable [NormedDivisionRing 𝕜] [AddCommGroup E] [Module 𝕜 E] {s t : Set E} @[simp] theorem balancedCoreAux_empty : balancedCoreAux 𝕜 (∅ : Set E) = ∅ := by @@ -158,7 +158,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 +167,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) @@ -181,11 +181,11 @@ theorem balancedCore_eq_iInter (hs : (0 : E) ∈ s) : theorem subset_balancedCore (ht : (0 : E) ∈ t) (hst : ∀ a : 𝕜, ‖a‖ ≤ 1 → a • s ⊆ t) : s ⊆ balancedCore 𝕜 t := by rw [balancedCore_eq_iInter ht] - refine subset_iInter₂ fun a ha => ?_ - rw [← smul_inv_smul₀ (norm_pos_iff.mp <| zero_lt_one.trans_le ha) s] - refine smul_set_mono (hst _ ?_) + refine subset_iInter₂ fun a ha ↦ ?_ + 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 @@ -196,7 +196,7 @@ end balancedHull section Topology -variable [NontriviallyNormedField 𝕜] [AddCommGroup E] [Module 𝕜 E] [TopologicalSpace E] +variable [NormedDivisionRing 𝕜] [AddCommGroup E] [Module 𝕜 E] [TopologicalSpace E] [ContinuousSMul 𝕜 E] {U : Set E} protected theorem IsClosed.balancedCore (hU : IsClosed U) : IsClosed (balancedCore 𝕜 U) := by @@ -213,6 +213,9 @@ protected theorem IsClosed.balancedCore (hU : IsClosed U) : IsClosed (balancedCo rw [this] exact isClosed_empty +-- We don't have a `NontriviallyNormedDivisionRing`, so we use a `NeBot` assumption instead +variable [NeBot (𝓝[≠] (0 : 𝕜))] + theorem balancedCore_mem_nhds_zero (hU : U ∈ 𝓝 (0 : E)) : balancedCore 𝕜 U ∈ 𝓝 (0 : E) := by -- Getting neighborhoods of the origin for `0 : 𝕜` and `0 : E` obtain ⟨r, V, hr, hV, hrVU⟩ : ∃ (r : ℝ) (V : Set E), @@ -221,8 +224,9 @@ theorem balancedCore_mem_nhds_zero (hU : U ∈ 𝓝 (0 : E)) : balancedCore 𝕜 continuous_smul.tendsto' (0, 0) _ (smul_zero _) simpa only [← Prod.exists', ← Prod.forall', ← and_imp, ← and_assoc, exists_prop] using h.basis_left (NormedAddCommGroup.nhds_zero_basis_norm_lt.prod_nhds (𝓝 _).basis_sets) U hU - rcases NormedField.exists_norm_lt 𝕜 hr with ⟨y, hy₀, hyr⟩ - rw [norm_pos_iff] at hy₀ + obtain ⟨y, hyr, hy₀⟩ : ∃ y : 𝕜, ‖y‖ < r ∧ y ≠ 0 := + Filter.nonempty_of_mem <| + (nhdsWithin_hasBasis NormedAddCommGroup.nhds_zero_basis_norm_lt {0}ᶜ).mem_of_mem hr have : y • V ∈ 𝓝 (0 : E) := (set_smul_mem_nhds_zero_iff hy₀).mpr hV -- It remains to show that `y • V ⊆ balancedCore 𝕜 U` refine Filter.mem_of_superset this (subset_balancedCore (mem_of_mem_nhds hU) fun a ha => ?_) diff --git a/Mathlib/Analysis/LocallyConvex/Barrelled.lean b/Mathlib/Analysis/LocallyConvex/Barrelled.lean index 18409cff2a2f8..f01f4a9bb0e81 100644 --- a/Mathlib/Analysis/LocallyConvex/Barrelled.lean +++ b/Mathlib/Analysis/LocallyConvex/Barrelled.lean @@ -179,7 +179,8 @@ is a *continuous* linear map as well. This actually works for any *countably generated* filter instead of `atTop : Filter ℕ`, but the proof ultimately goes back to sequences. -/ -protected def continuousLinearMapOfTendsto [T2Space F] {l : Filter α} [l.IsCountablyGenerated] +protected def continuousLinearMapOfTendsto (hq : WithSeminorms q) + [T2Space F] {l : Filter α} [l.IsCountablyGenerated] [l.NeBot] (g : α → E →SL[σ₁₂] F) {f : E → F} (h : Tendsto (fun n x ↦ g n x) l (𝓝 f)) : E →SL[σ₁₂] F where toLinearMap := linearMapOfTendsto _ _ h diff --git a/Mathlib/Analysis/LocallyConvex/Basic.lean b/Mathlib/Analysis/LocallyConvex/Basic.lean index c5bf0dfa6a4e3..4b242d6809928 100644 --- a/Mathlib/Analysis/LocallyConvex/Basic.lean +++ b/Mathlib/Analysis/LocallyConvex/Basic.lean @@ -183,18 +183,18 @@ 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 rcases eq_or_ne a 0 with rfl | ha₀ · simp_all · calc - b • x = (a⁻¹ • b) • a • x := by rw [smul_comm, smul_assoc, smul_inv_smul₀ ha₀] - _ ∈ s := by + (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 rw [← @norm_one 𝕜] at ha; simpa using hA.smul_mono ha diff --git a/Mathlib/Analysis/LocallyConvex/Bounded.lean b/Mathlib/Analysis/LocallyConvex/Bounded.lean index 680f38ea9ba4f..9463b8d6760d7 100644 --- a/Mathlib/Analysis/LocallyConvex/Bounded.lean +++ b/Mathlib/Analysis/LocallyConvex/Bounded.lean @@ -99,7 +99,7 @@ theorem IsVonNBounded.of_boundedSpace [BoundedSpace 𝕜] {s : Set E} : IsVonNBo @[nontriviality] theorem IsVonNBounded.of_subsingleton [Subsingleton E] {s : Set E} : IsVonNBounded 𝕜 s := - fun U hU ↦ eventually_of_forall fun c ↦ calc + fun U hU ↦ .of_forall fun c ↦ calc s ⊆ univ := subset_univ s _ = c • U := .symm <| Subsingleton.eq_univ_of_nonempty <| (Filter.nonempty_of_mem hU).image _ @@ -176,11 +176,16 @@ 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 simp_rw [isVonNBounded_iff_tendsto_smallSets_nhds, nhds_pi, Filter.pi, smallSets_iInf, - smallSets_comap_eq_comap_image, tendsto_iInf, tendsto_comap_iff, Function.comp, + smallSets_comap_eq_comap_image, tendsto_iInf, tendsto_comap_iff, Function.comp_def, ← image_smul, image_image, eval, Pi.smul_apply, Pi.zero_apply] section Image @@ -239,7 +244,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 x 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 @@ -255,7 +260,7 @@ theorem IsVonNBounded.extend_scalars [NontriviallyNormedField 𝕜] obtain ⟨ε, hε, hε₀⟩ : ∃ ε : ℕ → 𝕜, Tendsto ε atTop (𝓝 0) ∧ ∀ᶠ n in atTop, ε n ≠ 0 := by simpa only [tendsto_nhdsWithin_iff] using exists_seq_tendsto (𝓝[≠] (0 : 𝕜)) refine isVonNBounded_of_smul_tendsto_zero (ε := (ε · • 1)) (by simpa) fun x hx ↦ ?_ - have := h.smul_tendsto_zero (eventually_of_forall hx) hε + have := h.smul_tendsto_zero (.of_forall hx) hε simpa only [Pi.smul_def', smul_one_smul] section NormedField 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 3dda893c0ca9e..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] @@ -91,10 +95,15 @@ theorem polar_empty : B.polar ∅ = Set.univ := B.polar_gc.l_bot @[simp] +theorem polar_singleton {a : E} : B.polar {a} = { y | ‖B a y‖ ≤ 1 } := le_antisymm + (fun _ hy => hy _ rfl) + (fun y hy => (polar_mem_iff _ _ _).mp (fun _ hb => by rw [Set.mem_singleton_iff.mp hb]; exact hy)) + +theorem mem_polar_singleton {x : E} (y : F) : y ∈ B.polar {x} ↔ ‖B x y‖ ≤ 1 := by + simp only [polar_singleton, Set.mem_setOf_eq] + theorem polar_zero : B.polar ({0} : Set E) = Set.univ := by - refine Set.eq_univ_iff_forall.mpr fun y x hx => ?_ - rw [Set.mem_singleton_iff.mp hx, map_zero, LinearMap.zero_apply, norm_zero] - exact zero_le_one + simp only [polar_singleton, map_zero, zero_apply, norm_zero, zero_le_one, Set.setOf_true] theorem subset_bipolar (s : Set E) : s ⊆ B.flip.polar (B.polar s) := fun x hx y hy => by rw [B.flip_apply] @@ -111,6 +120,13 @@ theorem polar_weak_closed (s : Set E) : IsClosed[WeakBilin.instTopologicalSpace refine isClosed_iInter fun x => isClosed_iInter fun _ => ?_ exact isClosed_le (WeakBilin.eval_continuous B.flip x).norm continuous_const +theorem sInter_polar_finite_subset_eq_polar (s : Set E) : + ⋂₀ (B.polar '' { F | F.Finite ∧ F ⊆ s }) = B.polar s := by + ext x + simp only [Set.sInter_image, Set.mem_setOf_eq, Set.mem_iInter, and_imp] + refine ⟨fun hx a ha ↦ ?_, fun hx F _ hF₂ => polar_antitone _ hF₂ hx⟩ + simpa [mem_polar_singleton] using hx _ (Set.finite_singleton a) (Set.singleton_subset_iff.mpr ha) + end NormedRing section NontriviallyNormedField @@ -140,8 +156,8 @@ theorem polar_subMulAction {S : Type*} [SetLike S E] [SMulMemClass S 𝕜 E] (m · intro hy x hx obtain ⟨r, hr⟩ := NormedField.exists_lt_norm 𝕜 ‖B x y‖⁻¹ contrapose! hr - rw [← one_div, le_div_iff (norm_pos_iff.2 hr)] - simpa using hy _ (SMulMemClass.smul_mem r hx) + rw [← one_div, le_div_iff₀ (norm_pos_iff.2 hr)] + simpa using hy _ (SMulMemClass.smul_mem r hx) · intro h x hx simp [h x hx] diff --git a/Mathlib/Analysis/LocallyConvex/WeakDual.lean b/Mathlib/Analysis/LocallyConvex/WeakDual.lean index ff5b801a83d03..13d4746c6c707 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.Basic +import Mathlib.Analysis.Normed.Field.Lemmas import Mathlib.Analysis.LocallyConvex.WithSeminorms +import Mathlib.Topology.Algebra.Module.WeakBilin /-! # Weak Dual in Topological Vector Spaces @@ -112,7 +112,7 @@ theorem LinearMap.hasBasis_weakBilin (B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜) : 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] + simp only [Set.empty_pi, Set.preimage_univ, Set.subset_univ, and_true] exact Exists.intro ((p 0).ball 0 1) (p.basisSets_singleton_mem 0 one_pos) rintro U (hU : U ∈ p.basisSets) rw [SeminormFamily.basisSets_iff] at hU 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 2ca1c42f8b1e6..b4165a1a77053 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,12 +639,11 @@ 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) _ <| - eventually_of_forall fun x k ↦ by simpa using hfp k x + | ⟨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*} @@ -766,7 +762,7 @@ lemma bound_of_continuous_normedSpace (q : Seminorm 𝕜 F) exact le_of_eq (map_eq_zero_of_norm_zero q hq hx) · refine (normSeminorm 𝕜 F).bound_of_shell q ε_pos hc (fun x hle hlt ↦ ?_) hx refine (le_of_lt <| show q x < _ from hε hlt).trans ?_ - rwa [← div_le_iff' this, one_div_div] + rwa [← div_le_iff₀' this, one_div_div] /-- Let `E` be a topological vector space (over a `NontriviallyNormedField`) whose topology is generated by some family of seminorms `p`, and let `q` be a seminorm on `E`. If `q` is continuous, diff --git a/Mathlib/Analysis/MeanInequalities.lean b/Mathlib/Analysis/MeanInequalities.lean index 7dc403aec3cca..ebc7bb9056c0f 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 @@ -268,13 +270,13 @@ theorem harm_mean_le_geom_mean_weighted (w z : ι → ℝ) (hs : s.Nonempty) (hw have p_pos : 0 < ∏ i in s, (z i)⁻¹ ^ w i := prod_pos fun i hi => rpow_pos_of_pos (inv_pos.2 (hz i hi)) _ have s_pos : 0 < ∑ i in s, w i * (z i)⁻¹ := - sum_pos (fun i hi => Real.mul_pos (hw i hi) (inv_pos.2 (hz i hi))) hs + 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 @@ -330,7 +332,7 @@ end Real namespace NNReal /-- **Young's inequality**, `ℝ≥0` version. We use `{p q : ℝ≥0}` in order to avoid constructing -witnesses of `0 ≤ p` and `0 ≤ q` for the denominators. -/ +witnesses of `0 ≤ p` and `0 ≤ q` for the denominators. -/ theorem young_inequality (a b : ℝ≥0) {p q : ℝ≥0} (hpq : p.IsConjExponent q) : a * b ≤ a ^ (p : ℝ) / p + b ^ (q : ℝ) / q := Real.young_inequality_of_nonneg a.coe_nonneg b.coe_nonneg hpq.coe @@ -353,8 +355,8 @@ theorem young_inequality (a b : ℝ≥0∞) {p q : ℝ} (hpq : p.IsConjExponent cases' h with h h <;> rw [h] <;> simp [h, hpq.pos, hpq.symm.pos] push_neg at h -- if a ≠ ⊤ and b ≠ ⊤, use the nnreal version: nnreal.young_inequality_real - rw [← coe_toNNReal h.left, ← coe_toNNReal h.right, ← coe_mul, coe_rpow_of_nonneg _ hpq.nonneg, - coe_rpow_of_nonneg _ hpq.symm.nonneg, ENNReal.ofReal, ENNReal.ofReal, ← + rw [← coe_toNNReal h.left, ← coe_toNNReal h.right, ← coe_mul, ← coe_rpow_of_nonneg _ hpq.nonneg, + ← coe_rpow_of_nonneg _ hpq.symm.nonneg, ENNReal.ofReal, ENNReal.ofReal, ← @coe_div (Real.toNNReal p) _ (by simp [hpq.pos]), ← @coe_div (Real.toNNReal q) _ (by simp [hpq.symm.pos]), ← coe_add, coe_le_coe] exact NNReal.young_inequality_real a.toNNReal b.toNNReal hpq @@ -373,17 +375,15 @@ namespace NNReal private theorem inner_le_Lp_mul_Lp_of_norm_le_one (f g : ι → ℝ≥0) {p q : ℝ} (hpq : p.IsConjExponent q) (hf : ∑ i ∈ s, f i ^ p ≤ 1) (hg : ∑ i ∈ s, g i ^ q ≤ 1) : ∑ i ∈ s, f i * g i ≤ 1 := by - have hp_ne_zero : Real.toNNReal p ≠ 0 := (zero_lt_one.trans hpq.toNNReal.one_lt).ne.symm - have hq_ne_zero : Real.toNNReal q ≠ 0 := (zero_lt_one.trans hpq.toNNReal.symm.one_lt).ne.symm + have hp : 0 < p.toNNReal := zero_lt_one.trans hpq.toNNReal.one_lt + have hq : 0 < q.toNNReal := zero_lt_one.trans hpq.toNNReal.symm.one_lt calc ∑ i ∈ s, f i * g i ≤ ∑ i ∈ s, (f i ^ p / Real.toNNReal p + g i ^ q / Real.toNNReal q) := Finset.sum_le_sum fun i _ => young_inequality_real (f i) (g i) hpq _ = (∑ i ∈ s, f i ^ p) / Real.toNNReal p + (∑ i ∈ s, g i ^ q) / Real.toNNReal q := by rw [sum_add_distrib, sum_div, sum_div] _ ≤ 1 / Real.toNNReal p + 1 / Real.toNNReal q := by - refine add_le_add ?_ ?_ - · rwa [div_le_iff hp_ne_zero, div_mul_cancel₀ _ hp_ne_zero] - · rwa [div_le_iff hq_ne_zero, div_mul_cancel₀ _ hq_ne_zero] + refine add_le_add ?_ ?_ <;> rwa [div_le_iff₀, div_mul_cancel₀] <;> positivity _ = 1 := by simp_rw [one_div, hpq.toNNReal.inv_add_inv_conj] private theorem inner_le_Lp_mul_Lp_of_norm_eq_zero (f g : ι → ℝ≥0) {p q : ℝ} @@ -401,31 +401,28 @@ private theorem inner_le_Lp_mul_Lp_of_norm_eq_zero (f g : ι → ℝ≥0) {p q : with `ℝ≥0`-valued functions. -/ theorem inner_le_Lp_mul_Lq (f g : ι → ℝ≥0) {p q : ℝ} (hpq : p.IsConjExponent q) : ∑ i ∈ s, f i * g i ≤ (∑ i ∈ s, f i ^ p) ^ (1 / p) * (∑ i ∈ s, g i ^ q) ^ (1 / q) := by - by_cases hF_zero : ∑ i ∈ s, f i ^ p = 0 - · exact inner_le_Lp_mul_Lp_of_norm_eq_zero s f g hpq hF_zero - by_cases hG_zero : ∑ i ∈ s, g i ^ q = 0 + obtain hf | hf := eq_zero_or_pos (∑ i ∈ s, f i ^ p) + · exact inner_le_Lp_mul_Lp_of_norm_eq_zero s f g hpq hf + obtain hg | hg := eq_zero_or_pos (∑ i ∈ s, g i ^ q) · calc ∑ i ∈ s, f i * g i = ∑ i ∈ s, g i * f i := by congr with i rw [mul_comm] _ ≤ (∑ i ∈ s, g i ^ q) ^ (1 / q) * (∑ i ∈ s, f i ^ p) ^ (1 / p) := - (inner_le_Lp_mul_Lp_of_norm_eq_zero s g f hpq.symm hG_zero) + (inner_le_Lp_mul_Lp_of_norm_eq_zero s g f hpq.symm hg) _ = (∑ i ∈ s, f i ^ p) ^ (1 / p) * (∑ i ∈ s, g i ^ q) ^ (1 / q) := mul_comm _ _ let f' i := f i / (∑ i ∈ s, f i ^ p) ^ (1 / p) let g' i := g i / (∑ i ∈ s, g i ^ q) ^ (1 / q) suffices (∑ i ∈ s, f' i * g' i) ≤ 1 by simp_rw [f', g', div_mul_div_comm, ← sum_div] at this - rwa [div_le_iff, one_mul] at this - refine mul_ne_zero ?_ ?_ - · rw [Ne, rpow_eq_zero_iff, not_and_or] - exact Or.inl hF_zero - · rw [Ne, rpow_eq_zero_iff, not_and_or] - exact Or.inl hG_zero + rwa [div_le_iff₀, one_mul] at this + -- TODO: We are missing a positivity extension here + exact mul_pos (rpow_pos hf) (rpow_pos hg) refine inner_le_Lp_mul_Lp_of_norm_le_one s f' g' hpq (le_of_eq ?_) (le_of_eq ?_) · simp_rw [f', div_rpow, ← sum_div, ← rpow_mul, one_div, inv_mul_cancel₀ hpq.ne_zero, rpow_one, - div_self hF_zero] + div_self hf.ne'] · simp_rw [g', div_rpow, ← sum_div, ← rpow_mul, one_div, inv_mul_cancel₀ hpq.symm.ne_zero, - rpow_one, div_self hG_zero] + rpow_one, div_self hg.ne'] /-- **Weighted Hölder inequality**. -/ lemma inner_le_weight_mul_Lp (s : Finset ι) {p : ℝ} (hp : 1 ≤ p) (w f : ι → ℝ≥0) : @@ -481,7 +478,7 @@ theorem inner_le_Lp_mul_Lq_tsum' {f g : ι → ℝ≥0} {p q : ℝ} (hpq : p.IsC /-- **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 `NNReal`-valued functions. For an alternative version, convenient if the infinite sums are not already expressed as -`p`-th powers, see `inner_le_Lp_mul_Lq_tsum`. -/ +`p`-th powers, see `inner_le_Lp_mul_Lq_tsum`. -/ theorem inner_le_Lp_mul_Lq_hasSum {f g : ι → ℝ≥0} {A B : ℝ≥0} {p q : ℝ} (hpq : p.IsConjExponent q) (hf : HasSum (fun i => f i ^ p) (A ^ p)) (hg : HasSum (fun i => g i ^ q) (B ^ q)) : ∃ C, C ≤ A * B ∧ HasSum (fun i => f i * g i) C := by @@ -517,17 +514,17 @@ theorem isGreatest_Lp (f : ι → ℝ≥0) {p q : ℝ} (hpq : p.IsConjExponent q ((∑ i ∈ s, f i ^ p) ^ (1 / p)) := by constructor · use fun i => f i ^ p / f i / (∑ i ∈ s, f i ^ p) ^ (1 / q) - by_cases hf : ∑ i ∈ s, f i ^ p = 0 + obtain hf | hf := eq_zero_or_pos (∑ i ∈ s, f i ^ p) · simp [hf, hpq.ne_zero, hpq.symm.ne_zero] · have A : p + q - q ≠ 0 := by simp [hpq.ne_zero] have B : ∀ y : ℝ≥0, y * y ^ p / y = y ^ p := by refine fun y => mul_div_cancel_left_of_imp fun h => ?_ 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] - rw [div_eq_iff, ← rpow_add hf, one_div, one_div, hpq.inv_add_inv_conj, rpow_one] - simpa [hpq.symm.ne_zero] using hf + 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, ← 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⟩ apply le_trans (inner_le_Lp_mul_Lq s f g hpq) simpa only [mul_one] using @@ -589,7 +586,7 @@ theorem Lp_add_le_tsum' {f g : ι → ℝ≥0} {p : ℝ} (hp : 1 ≤ p) (hf : Su /-- **Minkowski inequality**: the `L_p` seminorm of the infinite sum of two vectors is less than or equal to the infinite sum of the `L_p`-seminorms of the summands, if these infinite sums both exist. A version for `NNReal`-valued functions. For an alternative version, convenient if the -infinite sums are not already expressed as `p`-th powers, see `Lp_add_le_tsum_of_nonneg`. -/ +infinite sums are not already expressed as `p`-th powers, see `Lp_add_le_tsum_of_nonneg`. -/ theorem Lp_add_le_hasSum {f g : ι → ℝ≥0} {A B : ℝ≥0} {p : ℝ} (hp : 1 ≤ p) (hf : HasSum (fun i => f i ^ p) (A ^ p)) (hg : HasSum (fun i => g i ^ p) (B ^ p)) : ∃ C, C ≤ A + B ∧ HasSum (fun i => (f i + g i) ^ p) (C ^ p) := by @@ -665,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, @@ -693,7 +702,7 @@ theorem inner_le_Lp_mul_Lq_tsum_of_nonneg' (hpq : p.IsConjExponent q) (hf : ∀ /-- **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 `NNReal`-valued functions. For an alternative version, convenient if the infinite sums are not already expressed as -`p`-th powers, see `inner_le_Lp_mul_Lq_tsum_of_nonneg`. -/ +`p`-th powers, see `inner_le_Lp_mul_Lq_tsum_of_nonneg`. -/ theorem inner_le_Lp_mul_Lq_hasSum_of_nonneg (hpq : p.IsConjExponent q) {A B : ℝ} (hA : 0 ≤ A) (hB : 0 ≤ B) (hf : ∀ i, 0 ≤ f i) (hg : ∀ i, 0 ≤ g i) (hf_sum : HasSum (fun i => f i ^ p) (A ^ p)) (hg_sum : HasSum (fun i => g i ^ q) (B ^ q)) : @@ -797,11 +806,11 @@ theorem inner_le_Lp_mul_Lq (hpq : p.IsConjExponent q) : · cases' H' with H' H' <;> simp [H', -one_div, -sum_eq_zero_iff, -rpow_eq_zero_iff, H] replace H' : (∀ i ∈ s, f i ≠ ⊤) ∧ ∀ i ∈ s, g i ≠ ⊤ := by simpa [ENNReal.rpow_eq_top_iff, asymm hpq.pos, asymm hpq.symm.pos, hpq.pos, hpq.symm.pos, - ENNReal.sum_eq_top_iff, not_or] using H' + ENNReal.sum_eq_top, not_or] using H' have := ENNReal.coe_le_coe.2 (@NNReal.inner_le_Lp_mul_Lq _ s (fun i => ENNReal.toNNReal (f i)) (fun i => ENNReal.toNNReal (g i)) _ _ hpq) - simp [← ENNReal.coe_rpow_of_nonneg, le_of_lt hpq.pos, le_of_lt hpq.one_div_pos, - le_of_lt hpq.symm.pos, le_of_lt hpq.symm.one_div_pos] at this + simp [ENNReal.coe_rpow_of_nonneg, hpq.pos.le, hpq.one_div_pos.le, hpq.symm.pos.le, + hpq.symm.one_div_pos.le] at this convert this using 1 <;> [skip; congr 2] <;> [skip; skip; simp; skip; simp] <;> · refine Finset.sum_congr rfl fun i hi => ?_ simp [H'.1 i hi, H'.2 i hi, -WithZero.coe_mul] @@ -812,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 @@ -822,13 +831,13 @@ lemma inner_le_weight_mul_Lp_of_nonneg (s : Finset ι) {p : ℝ} (hp : 1 ≤ p) by_cases H' : (∑ i ∈ s, w i) ^ (1 - p⁻¹) = ⊤ ∨ (∑ i ∈ s, w i * f i ^ p) ^ p⁻¹ = ⊤ · cases' H' with H' H' <;> simp [H', -one_div, -sum_eq_zero_iff, -rpow_eq_zero_iff, H] replace H' : (∀ i ∈ s, w i ≠ ⊤) ∧ ∀ i ∈ s, w i * f i ^ p ≠ ⊤ := by - simpa [rpow_eq_top_iff,hp₀, hp₁, hp₀.not_lt, hp₁.not_lt, sum_eq_top_iff, not_or] using H' - have := coe_le_coe.2 $ NNReal.inner_le_weight_mul_Lp s hp.le (fun i ↦ ENNReal.toNNReal (w i)) + simpa [rpow_eq_top_iff,hp₀, hp₁, hp₀.not_lt, hp₁.not_lt, sum_eq_top, not_or] using H' + have := coe_le_coe.2 <| NNReal.inner_le_weight_mul_Lp s hp.le (fun i ↦ ENNReal.toNNReal (w i)) fun i ↦ ENNReal.toNNReal (f i) rw [coe_mul] at this - simp_rw [← coe_rpow_of_nonneg _ $ inv_nonneg.2 hp₀.le, coe_finset_sum, ENNReal.toNNReal_rpow, + simp_rw [coe_rpow_of_nonneg _ <| inv_nonneg.2 hp₀.le, coe_finset_sum, ← ENNReal.toNNReal_rpow, ← ENNReal.toNNReal_mul, sum_congr rfl fun i hi ↦ coe_toNNReal (H'.2 i hi)] at this - simp [← ENNReal.coe_rpow_of_nonneg, hp₀.le, hp₁.le] at this + simp [ENNReal.coe_rpow_of_nonneg, hp₀.le, hp₁.le] at this convert this using 2 with i hi · obtain hw | hw := eq_or_ne (w i) 0 · simp [hw] @@ -864,12 +873,12 @@ theorem Lp_add_le (hp : 1 ≤ p) : · cases' H' with H' H' <;> simp [H', -one_div] have pos : 0 < p := lt_of_lt_of_le zero_lt_one hp replace H' : (∀ i ∈ s, f i ≠ ⊤) ∧ ∀ i ∈ s, g i ≠ ⊤ := by - simpa [ENNReal.rpow_eq_top_iff, asymm pos, pos, ENNReal.sum_eq_top_iff, not_or] using H' + simpa [ENNReal.rpow_eq_top_iff, asymm pos, pos, ENNReal.sum_eq_top, not_or] using H' have := ENNReal.coe_le_coe.2 (@NNReal.Lp_add_le _ s (fun i => ENNReal.toNNReal (f i)) (fun i => ENNReal.toNNReal (g i)) _ hp) - push_cast [← ENNReal.coe_rpow_of_nonneg, le_of_lt pos, le_of_lt (one_div_pos.2 pos)] at this + push_cast [ENNReal.coe_rpow_of_nonneg, le_of_lt pos, le_of_lt (one_div_pos.2 pos)] at this convert this using 2 <;> [skip; congr 1; congr 1] <;> · refine Finset.sum_congr rfl fun i hi => ?_ simp [H'.1 i hi, H'.2 i hi] diff --git a/Mathlib/Analysis/MeanInequalitiesPow.lean b/Mathlib/Analysis/MeanInequalitiesPow.lean index bd0833e79f889..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 : ℝ} @@ -141,7 +119,7 @@ theorem rpow_add_le_mul_rpow_add_rpow (z₁ z₂ : ℝ≥0) {p : ℝ} (hp : 1 · simp only [one_div, inv_mul_cancel_left₀, Ne, mul_eq_zero, two_ne_zero, one_ne_zero, not_false_iff] · have A : p - 1 ≠ 0 := ne_of_gt (sub_pos.2 h'p) - simp only [mul_rpow, rpow_sub' _ A, div_eq_inv_mul, rpow_one, mul_one] + simp only [mul_rpow, rpow_sub' A, div_eq_inv_mul, rpow_one, mul_one] ring /-- Weighted generalized mean inequality, version for sums over finite sets, with `ℝ≥0`-valued @@ -219,9 +197,9 @@ theorem rpow_arith_mean_le_arith_mean_rpow (w z : ι → ℝ≥0∞) (hw' : ∑ simp [ENNReal.mul_eq_top, hp_pos, hp_nonneg, hp_not_neg] refine le_of_top_imp_top_of_toNNReal_le ?_ ?_ · -- first, prove `(∑ i ∈ s, w i * z i) ^ p = ⊤ → ∑ i ∈ s, (w i * z i ^ p) = ⊤` - rw [rpow_eq_top_iff, sum_eq_top_iff, sum_eq_top_iff] + 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] @@ -241,7 +219,7 @@ theorem rpow_arith_mean_le_arith_mean_rpow (w z : ι → ℝ≥0∞) (hw' : ∑ specialize h_top i hi rwa [Ne, ← h_top_iff_rpow_top i hi] -- put the `.toNNReal` inside the sums. - simp_rw [toNNReal_sum h_top_rpow, ← toNNReal_rpow, toNNReal_sum h_top, toNNReal_mul, ← + simp_rw [toNNReal_sum h_top_rpow, toNNReal_rpow, toNNReal_sum h_top, toNNReal_mul, toNNReal_rpow] -- use corresponding nnreal result refine @@ -282,7 +260,7 @@ theorem add_rpow_le_rpow_add {p : ℝ} (a b : ℝ≥0∞) (hp1 : 1 ≤ p) : a ^ obtain ⟨ha_top, hb_top⟩ := add_ne_top.mp h_top lift a to ℝ≥0 using ha_top lift b to ℝ≥0 using hb_top - simpa [← ENNReal.coe_rpow_of_nonneg _ hp_pos.le] using + simpa [ENNReal.coe_rpow_of_nonneg _ hp_pos.le] using ENNReal.coe_le_coe.2 (NNReal.add_rpow_le_rpow_add a b hp1) theorem rpow_add_rpow_le_add {p : ℝ} (a b : ℝ≥0∞) (hp1 : 1 ≤ p) : diff --git a/Mathlib/Analysis/MellinTransform.lean b/Mathlib/Analysis/MellinTransform.lean index 81136cb0e8e3c..6712829f036dc 100644 --- a/Mathlib/Analysis/MellinTransform.lean +++ b/Mathlib/Analysis/MellinTransform.lean @@ -229,7 +229,7 @@ theorem mellin_convergent_zero_of_isBigO {b : ℝ} {f : ℝ → ℝ} rw [← IntegrableOn, ← integrableOn_Ioc_iff_integrableOn_Ioo, ← intervalIntegrable_iff_integrableOn_Ioc_of_le hε.le] exact intervalIntegral.intervalIntegrable_rpow' (by linarith) - · refine (ae_restrict_iff' measurableSet_Ioo).mpr (eventually_of_forall fun t ht => ?_) + · refine (ae_restrict_iff' measurableSet_Ioo).mpr (Eventually.of_forall fun t ht => ?_) rw [mul_comm, norm_mul] specialize hε' _ ht.1 · rw [dist_eq_norm, sub_zero, norm_of_nonneg (le_of_lt ht.1)] @@ -256,7 +256,7 @@ theorem mellin_convergent_of_isBigO_scalar {a b : ℝ} {f : ℝ → ℝ} {s : rw [this, integrableOn_union, integrableOn_union] refine ⟨⟨hc2', integrableOn_Icc_iff_integrableOn_Ioc.mp ?_⟩, hc1'⟩ refine - (hfc.continuousOn_mul ?_ isOpen_Ioi).integrableOn_compact_subset + (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 @@ -278,8 +278,8 @@ theorem isBigO_rpow_top_log_smul [NormedSpace ℝ E] {a b : ℝ} {f : ℝ → E} (fun t : ℝ => log t • f t) =O[atTop] (· ^ (-b)) := by refine ((isLittleO_log_rpow_atTop (sub_pos.mpr hab)).isBigO.smul hf).congr' - (eventually_of_forall fun t => by rfl) - ((eventually_gt_atTop 0).mp (eventually_of_forall fun t ht => ?_)) + (Eventually.of_forall fun t => by rfl) + ((eventually_gt_atTop 0).mp (Eventually.of_forall fun t ht => ?_)) simp only rw [smul_eq_mul, ← rpow_add ht, ← sub_eq_add_neg, sub_eq_add_neg a, add_sub_cancel_left] @@ -290,13 +290,13 @@ theorem isBigO_rpow_zero_log_smul [NormedSpace ℝ E] {a b : ℝ} {f : ℝ → E have : log =o[𝓝[>] 0] fun t : ℝ => t ^ (a - b) := by refine ((isLittleO_log_rpow_atTop (sub_pos.mpr hab)).neg_left.comp_tendsto tendsto_inv_zero_atTop).congr' - (eventually_nhdsWithin_iff.mpr <| eventually_of_forall fun t ht => ?_) - (eventually_nhdsWithin_iff.mpr <| eventually_of_forall fun t ht => ?_) + (eventually_nhdsWithin_iff.mpr <| Eventually.of_forall fun t ht => ?_) + (eventually_nhdsWithin_iff.mpr <| Eventually.of_forall fun t ht => ?_) · simp_rw [Function.comp_apply, ← one_div, log_div one_ne_zero (ne_of_gt ht), Real.log_one, zero_sub, neg_neg] · simp_rw [Function.comp_apply, inv_rpow (le_of_lt ht), ← rpow_neg (le_of_lt ht), neg_sub] - refine (this.isBigO.smul hf).congr' (eventually_of_forall fun t => by rfl) - (eventually_nhdsWithin_iff.mpr (eventually_of_forall fun t ht => ?_)) + refine (this.isBigO.smul hf).congr' (Eventually.of_forall fun t => by rfl) + (eventually_nhdsWithin_iff.mpr (Eventually.of_forall fun t ht => ?_)) simp_rw [smul_eq_mul, ← rpow_add ht] congr 1 abel @@ -319,7 +319,7 @@ theorem mellin_hasDerivAt_of_isBigO_rpow [NormedSpace ℂ E] {a b : ℝ} ⟨min w w', lt_min hw1 hw1', (min_le_right _ _).trans_lt hw2', (min_le_left _ _).trans_lt hw2⟩ let bound : ℝ → ℝ := fun t : ℝ => (t ^ (s.re + v - 1) + t ^ (s.re - v - 1)) * |log t| * ‖f t‖ have h1 : ∀ᶠ z : ℂ in 𝓝 s, AEStronglyMeasurable (F z) (volume.restrict <| Ioi 0) := by - refine eventually_of_forall fun z => AEStronglyMeasurable.smul ?_ hfc.aestronglyMeasurable + refine Eventually.of_forall fun z => AEStronglyMeasurable.smul ?_ hfc.aestronglyMeasurable refine ContinuousOn.aestronglyMeasurable ?_ measurableSet_Ioi refine ContinuousAt.continuousOn fun t ht => ?_ exact continuousAt_ofReal_cpow_const _ _ (Or.inr <| ne_of_gt ht) @@ -327,7 +327,8 @@ theorem mellin_hasDerivAt_of_isBigO_rpow [NormedSpace ℂ E] {a b : ℝ} 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 ((ContinuousAt.continuousOn fun t ht => ?_).mul ?_) + refine hfc.continuousOn_smul isOpen_Ioi.isLocallyClosed + ((ContinuousAt.continuousOn 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) @@ -362,7 +363,7 @@ theorem mellin_hasDerivAt_of_isBigO_rpow [NormedSpace ℂ E] {a b : ℝ} obtain ⟨w', hw1', hw2'⟩ := exists_between hj' refine mellin_convergent_of_isBigO_scalar ?_ ?_ hw1' ?_ hw2 · simp_rw [mul_comm] - refine hfc.norm.mul_continuousOn ?_ isOpen_Ioi + refine hfc.norm.mul_continuousOn ?_ isOpen_Ioi.isLocallyClosed refine Continuous.comp_continuousOn _root_.continuous_abs (continuousOn_log.mono ?_) exact subset_compl_singleton_iff.mpr not_mem_Ioi_self · refine (isBigO_rpow_top_log_smul hw2' hf_top).norm_left.congr_left fun t ↦ ?_ diff --git a/Mathlib/Analysis/Normed/Affine/AddTorsor.lean b/Mathlib/Analysis/Normed/Affine/AddTorsor.lean index caa4e080fffdf..2e2257c96f378 100644 --- a/Mathlib/Analysis/Normed/Affine/AddTorsor.lean +++ b/Mathlib/Analysis/Normed/Affine/AddTorsor.lean @@ -220,7 +220,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/Isometry.lean b/Mathlib/Analysis/Normed/Affine/Isometry.lean index 737521f2a9dec..67f6a72b44673 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 := @@ -447,8 +447,7 @@ theorem symm_apply_apply (x : P) : e.symm (e x) = x := e.toAffineEquiv.symm_apply_apply x @[simp] -theorem symm_symm : e.symm.symm = e := - ext fun _ => rfl +theorem symm_symm : e.symm.symm = e := rfl @[simp] theorem toAffineEquiv_symm : e.toAffineEquiv.symm = e.symm.toAffineEquiv := @@ -675,15 +674,13 @@ theorem pointReflection_symm (x : P) : (pointReflection 𝕜 x).symm = pointRefl theorem dist_pointReflection_fixed (x y : P) : dist (pointReflection 𝕜 x y) x = dist y x := by rw [← (pointReflection 𝕜 x).dist_map y x, pointReflection_self] -set_option linter.deprecated false in theorem dist_pointReflection_self' (x y : P) : dist (pointReflection 𝕜 x y) y = ‖2 • (x -ᵥ y)‖ := by rw [pointReflection_apply, dist_eq_norm_vsub V, vadd_vsub_assoc, two_nsmul] -set_option linter.deprecated false in theorem dist_pointReflection_self (x y : P) : dist (pointReflection 𝕜 x y) y = ‖(2 : 𝕜)‖ * dist x y := by - rw [dist_pointReflection_self', ← two_smul' 𝕜 (x -ᵥ y), norm_smul, ← dist_eq_norm_vsub V] + rw [dist_pointReflection_self', two_nsmul, ← two_smul 𝕜, norm_smul, ← dist_eq_norm_vsub V] theorem pointReflection_fixed_iff [Invertible (2 : 𝕜)] {x y : P} : pointReflection 𝕜 x y = y ↔ y = x := diff --git a/Mathlib/Analysis/Normed/Affine/MazurUlam.lean b/Mathlib/Analysis/Normed/Affine/MazurUlam.lean index 0ccabea54df9c..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]`. @@ -74,7 +74,7 @@ theorem midpoint_fixed {x y : PE} : have : c ≤ c / 2 := by apply ciSup_le rintro ⟨e, he⟩ - simp only [Subtype.coe_mk, le_div_iff' (zero_lt_two' ℝ), ← hf_dist] + simp only [Subtype.coe_mk, le_div_iff₀' (zero_lt_two' ℝ), ← hf_dist] exact le_ciSup h_bdd ⟨f e, hf_maps_to he⟩ replace : c ≤ 0 := by linarith refine fun e hx hy => dist_le_zero.1 (le_trans ?_ this) diff --git a/Mathlib/Analysis/Normed/Algebra/Exponential.lean b/Mathlib/Analysis/Normed/Algebra/Exponential.lean index f9679a22cb191..e211c1cfd4a8d 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 @@ -154,6 +151,7 @@ theorem star_exp [T2Space 𝔸] [StarRing 𝔸] [ContinuousStar 𝔸] (x : 𝔸) variable (𝕂) +@[aesop safe apply] theorem _root_.IsSelfAdjoint.exp [T2Space 𝔸] [StarRing 𝔸] [ContinuousStar 𝔸] {x : 𝔸} (h : IsSelfAdjoint x) : IsSelfAdjoint (exp 𝕂 x) := (star_exp x).trans <| h.symm ▸ rfl @@ -269,7 +267,7 @@ theorem exp_add_of_commute_of_mem_ball [CharZero 𝕂] {x y : 𝔸} (hxy : Commu ext rw [hxy.add_pow' _, Finset.smul_sum] refine tsum_congr fun n => Finset.sum_congr rfl fun kl hkl => ?_ - rw [← Nat.cast_smul_eq_nsmul 𝕂, smul_smul, smul_mul_smul, ← Finset.mem_antidiagonal.mp hkl, + rw [← Nat.cast_smul_eq_nsmul 𝕂, smul_smul, smul_mul_smul_comm, ← Finset.mem_antidiagonal.mp hkl, Nat.cast_add_choose, Finset.mem_antidiagonal.mp hkl] congr 1 have : (n ! : 𝕂) ≠ 0 := Nat.cast_ne_zero.mpr n.factorial_ne_zero @@ -482,9 +480,9 @@ theorem exp_sum_of_commute {ι} (s : Finset ι) (f : ι → 𝔸) exact h.of_refl (Finset.mem_insert_self _ _) (Finset.mem_insert_of_mem hi) theorem exp_nsmul (n : ℕ) (x : 𝔸) : exp 𝕂 (n • x) = exp 𝕂 x ^ n := by - induction' n with n ih - · rw [zero_smul, pow_zero, exp_zero] - · rw [succ_nsmul, pow_succ, exp_add_of_commute ((Commute.refl x).smul_left n), ih] + induction n with + | zero => rw [zero_smul, pow_zero, exp_zero] + | succ n ih => rw [succ_nsmul, pow_succ, exp_add_of_commute ((Commute.refl x).smul_left n), ih] variable (𝕂) @@ -512,7 +510,7 @@ theorem _root_.Prod.snd_exp [CompleteSpace 𝔹] (x : 𝔸 × 𝔹) : (exp 𝕂 map_exp _ (RingHom.snd 𝔸 𝔹) continuous_snd x @[simp] -theorem _root_.Pi.exp_apply {ι : Type*} {𝔸 : ι → Type*} [Finite ι] [∀ i, NormedRing (𝔸 i)] +theorem _root_.Pi.coe_exp {ι : Type*} {𝔸 : ι → Type*} [Finite ι] [∀ i, NormedRing (𝔸 i)] [∀ i, NormedAlgebra 𝕂 (𝔸 i)] [∀ i, CompleteSpace (𝔸 i)] (x : ∀ i, 𝔸 i) (i : ι) : exp 𝕂 x i = exp 𝕂 (x i) := let ⟨_⟩ := nonempty_fintype ι @@ -521,7 +519,7 @@ theorem _root_.Pi.exp_apply {ι : Type*} {𝔸 : ι → Type*} [Finite ι] [∀ theorem _root_.Pi.exp_def {ι : Type*} {𝔸 : ι → Type*} [Finite ι] [∀ i, NormedRing (𝔸 i)] [∀ i, NormedAlgebra 𝕂 (𝔸 i)] [∀ i, CompleteSpace (𝔸 i)] (x : ∀ i, 𝔸 i) : exp 𝕂 x = fun i => exp 𝕂 (x i) := - funext <| Pi.exp_apply 𝕂 x + funext <| Pi.coe_exp 𝕂 x theorem _root_.Function.update_exp {ι : Type*} {𝔸 : ι → Type*} [Finite ι] [DecidableEq ι] [∀ i, NormedRing (𝔸 i)] [∀ i, NormedAlgebra 𝕂 (𝔸 i)] [∀ i, CompleteSpace (𝔸 i)] (x : ∀ i, 𝔸 i) diff --git a/Mathlib/Analysis/Normed/Algebra/MatrixExponential.lean b/Mathlib/Analysis/Normed/Algebra/MatrixExponential.lean index 2f0463ab0aa36..a481e6f7c4823 100644 --- a/Mathlib/Analysis/Normed/Algebra/MatrixExponential.lean +++ b/Mathlib/Analysis/Normed/Algebra/MatrixExponential.lean @@ -145,17 +145,15 @@ 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 diff --git a/Mathlib/Analysis/Normed/Algebra/Norm.lean b/Mathlib/Analysis/Normed/Algebra/Norm.lean new file mode 100644 index 0000000000000..eb815ac91298e --- /dev/null +++ b/Mathlib/Analysis/Normed/Algebra/Norm.lean @@ -0,0 +1,202 @@ +/- +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' + +/-- Helper instance for when there's too many metavariables to apply `fun_like.has_coe_to_fun`. -/ +instance : CoeFun (AlgebraNorm R S) fun _ => S → ℝ := + DFunLike.hasCoeToFun + +theorem toFun_eq_coe (p : AlgebraNorm R S) : p.toFun = p := rfl + +@[ext] +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' + +/-- Helper instance for when there's too many metavariables to apply `fun_like.has_coe_to_fun`. -/ +instance : CoeFun (MulAlgebraNorm R S) fun _ => S → ℝ := + DFunLike.hasCoeToFun + +theorem toFun_eq_coe (p : MulAlgebraNorm R S) : p.toFun = p := rfl + +@[ext] +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 560f636a6afa2..fa49b3701161c 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 @@ -203,11 +203,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 +270,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 +278,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 [Nat.zero_eq, 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 +295,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 {𝕜} @@ -573,11 +571,14 @@ section BoundarySpectrum local notation "σ" => spectrum -variable {𝕜 A SA : Type*} [NormedField 𝕜] [NormedRing A] [NormedAlgebra 𝕜 A] [CompleteSpace A] -variable [SetLike SA A] [SubringClass SA A] [instSMulMem : SMulMemClass SA 𝕜 A] -variable (S : SA) [hS : IsClosed (S : Set A)] (x : S) +variable {𝕜 A SA : Type*} [NormedRing A] [CompleteSpace A] [SetLike SA A] [SubringClass SA A] + +open Topology Filter Set -open Topology Filter +section NormedField + +variable [NormedField 𝕜] [NormedAlgebra 𝕜 A] [instSMulMem : SMulMemClass SA 𝕜 A] +variable (S : SA) [hS : IsClosed (S : Set A)] (x : S) open SubalgebraClass in include instSMulMem in @@ -596,15 +597,13 @@ lemma _root_.Subalgebra.isUnit_of_isUnit_val_of_eventually {l : Filter S} {a : S all_goals ext; simp apply hS.mem_of_tendsto hla₂ rw [Filter.eventually_map] - apply hl.mp <| eventually_of_forall fun x hx ↦ ?_ + apply hl.mono fun x hx ↦ ?_ suffices Ring.inverse (val S x) = (val S ↑hx.unit⁻¹) from this ▸ Subtype.property _ rw [← (hx.map (val S)).unit_spec, Ring.inverse_unit (hx.map (val S)).unit, val] apply Units.mul_eq_one_iff_inv_eq.mp simpa [-IsUnit.mul_val_inv] using congr(($hx.mul_val_inv : A)) -open Set - -/-- If `S` is a closed subalgebra of a Banach algebra `A`, then for any +/-- If `S : Subalgebra 𝕜 A` is a closed subalgebra of a Banach algebra `A`, then for any `x : S`, the boundary of the spectrum of `x` relative to `S` is a subset of the spectrum of `↑x : A` relative to `A`. -/ lemma _root_.Subalgebra.frontier_spectrum : frontier (σ 𝕜 x) ⊆ σ 𝕜 (x : A) := by @@ -676,6 +675,25 @@ lemma Subalgebra.spectrum_isBounded_connectedComponentIn {z : 𝕜} (hz : z ∈ rw [spectrum_sUnion_connectedComponentIn S] exact subset_biUnion_of_mem (mem_diff_of_mem hz hz') |>.trans subset_union_right +end NormedField + +variable [NontriviallyNormedField 𝕜] [NormedAlgebra 𝕜 A] [SMulMemClass SA 𝕜 A] +variable (S : SA) [hS : IsClosed (S : Set A)] (x : S) + +/-- Let `S` be a closed subalgebra of a Banach algebra `A`. If for `x : S` the complement of the +spectrum of `↑x : A` is connected, then `spectrum 𝕜 x = spectrum 𝕜 (x : A)`. -/ +lemma Subalgebra.spectrum_eq_of_isPreconnected_compl (h : IsPreconnected (σ 𝕜 (x : A))ᶜ) : + σ 𝕜 x = σ 𝕜 (x : A) := by + nontriviality A + suffices σ 𝕜 x \ σ 𝕜 (x : A) = ∅ by + rw [spectrum_sUnion_connectedComponentIn, this] + simp + refine eq_empty_of_forall_not_mem fun z hz ↦ NormedSpace.unbounded_univ 𝕜 𝕜 ?_ + obtain ⟨hz, hz'⟩ := mem_diff _ |>.mp hz + have := (spectrum.isBounded (x : A)).union <| + h.connectedComponentIn hz' ▸ spectrum_isBounded_connectedComponentIn S x hz + simpa + end BoundarySpectrum namespace SpectrumRestricts @@ -720,6 +738,26 @@ lemma real_iff [Algebra ℂ A] {a : A} : simp · exact .of_subset_range_algebraMap Complex.ofReal_re fun x hx ↦ ⟨x.re, (h x hx).symm⟩ +lemma nnreal_le_iff [Algebra ℝ A] {a : A} + (ha : SpectrumRestricts a ContinuousMap.realToNNReal) {r : ℝ≥0} : + (∀ x ∈ spectrum ℝ≥0 a, r ≤ x) ↔ ∀ x ∈ spectrum ℝ a, r ≤ x := by + simp [← ha.algebraMap_image] + +lemma nnreal_lt_iff [Algebra ℝ A] {a : A} + (ha : SpectrumRestricts a ContinuousMap.realToNNReal) {r : ℝ≥0} : + (∀ x ∈ spectrum ℝ≥0 a, r < x) ↔ ∀ x ∈ spectrum ℝ a, r < x := by + simp [← ha.algebraMap_image] + +lemma le_nnreal_iff [Algebra ℝ A] {a : A} + (ha : SpectrumRestricts a ContinuousMap.realToNNReal) {r : ℝ≥0} : + (∀ x ∈ spectrum ℝ≥0 a, x ≤ r) ↔ ∀ x ∈ spectrum ℝ a, x ≤ r := by + simp [← ha.algebraMap_image] + +lemma lt_nnreal_iff [Algebra ℝ A] {a : A} + (ha : SpectrumRestricts a ContinuousMap.realToNNReal) {r : ℝ≥0} : + (∀ x ∈ spectrum ℝ≥0 a, x < r) ↔ ∀ x ∈ spectrum ℝ a, x < r := by + simp [← ha.algebraMap_image] + lemma nnreal_iff_spectralRadius_le [Algebra ℝ A] {a : A} {t : ℝ≥0} (ht : spectralRadius ℝ a ≤ t) : SpectrumRestricts a ContinuousMap.realToNNReal ↔ spectralRadius ℝ (algebraMap ℝ A t - a) ≤ t := by @@ -797,6 +835,16 @@ lemma real_iff [Module ℂ A] [IsScalarTower ℂ A A] [SMulCommClass ℂ A A] {a rw [quasispectrumRestricts_iff_spectrumRestricts_inr, Unitization.quasispectrum_eq_spectrum_inr' _ ℂ, SpectrumRestricts.real_iff] +lemma le_nnreal_iff [Module ℝ A] [IsScalarTower ℝ A A] [SMulCommClass ℝ A A] {a : A} + (ha : QuasispectrumRestricts a ContinuousMap.realToNNReal) {r : ℝ≥0} : + (∀ x ∈ quasispectrum ℝ≥0 a, x ≤ r) ↔ ∀ x ∈ quasispectrum ℝ a, x ≤ r := by + simp [← ha.algebraMap_image] + +lemma lt_nnreal_iff [Module ℝ A] [IsScalarTower ℝ A A] [SMulCommClass ℝ A A] {a : A} + (ha : QuasispectrumRestricts a ContinuousMap.realToNNReal) {r : ℝ≥0} : + (∀ x ∈ quasispectrum ℝ≥0 a, x < r) ↔ ∀ x ∈ quasispectrum ℝ a, x < r := by + simp [← ha.algebraMap_image] + end QuasispectrumRestricts variable {A : Type*} [Ring A] [PartialOrder A] diff --git a/Mathlib/Analysis/Normed/Algebra/Unitization.lean b/Mathlib/Analysis/Normed/Algebra/Unitization.lean index 789e764e8c4e0..de8b39cdbddce 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 -/-- `Unitization 𝕜 A` is complete whenever `𝕜` and `A` are also. -/ +@[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 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 fbcfe54ff4ad9..405b9ae12e4fa 100644 --- a/Mathlib/Analysis/Normed/Field/Basic.lean +++ b/Mathlib/Analysis/Normed/Field/Basic.lean @@ -5,30 +5,35 @@ Authors: Patrick Massot, Johannes Hölzl -/ import Mathlib.Algebra.Algebra.NonUnitalSubalgebra import Mathlib.Algebra.Algebra.Subalgebra.Basic -import Mathlib.Algebra.Order.Ring.Finset -import Mathlib.Analysis.Normed.Group.Bounded import Mathlib.Analysis.Normed.Group.Constructions -import Mathlib.Analysis.Normed.Group.Rat import Mathlib.Analysis.Normed.Group.Submodule -import Mathlib.Analysis.Normed.Group.Uniform -import Mathlib.GroupTheory.OrderOfElement -import Mathlib.Topology.Instances.NNReal -import Mathlib.Topology.MetricSpace.DilationEquiv +import Mathlib.Data.Set.Pointwise.Interval /-! # Normed fields 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` -/ -- Guard against import creep. +assert_not_exists AddChar +assert_not_exists comap_norm_atTop +assert_not_exists DilationEquiv +assert_not_exists Finset.sup_mul_le_mul_sup_of_nonneg +assert_not_exists IsOfFinOrder +assert_not_exists Isometry.norm_map_of_map_one +assert_not_exists NNReal.isOpen_Ico_zero +assert_not_exists Rat.norm_cast_real assert_not_exists RestrictScalars -variable {α : Type*} {β : Type*} {γ : Type*} {ι : Type*} +variable {α : Type*} {β : Type*} {ι : Type*} -open Filter Metric Bornology -open scoped Topology NNReal ENNReal uniformity Pointwise +open Filter +open scoped Topology NNReal /-- A non-unital seminormed ring is a not-necessarily-unital ring endowed with a seminorm which satisfies the inequality `‖x y‖ ≤ ‖x‖ ‖y‖`. -/ @@ -223,17 +228,6 @@ theorem one_le_norm_one (β) [NormedRing β] [Nontrivial β] : 1 ≤ ‖(1 : β) theorem one_le_nnnorm_one (β) [NormedRing β] [Nontrivial β] : 1 ≤ ‖(1 : β)‖₊ := one_le_norm_one β -theorem Filter.Tendsto.zero_mul_isBoundedUnder_le {f g : ι → α} {l : Filter ι} - (hf : Tendsto f l (𝓝 0)) (hg : IsBoundedUnder (· ≤ ·) l ((‖·‖) ∘ g)) : - Tendsto (fun x => f x * g x) l (𝓝 0) := - hf.op_zero_isBoundedUnder_le hg (· * ·) norm_mul_le - -theorem Filter.isBoundedUnder_le_mul_tendsto_zero {f g : ι → α} {l : Filter ι} - (hf : IsBoundedUnder (· ≤ ·) l (norm ∘ f)) (hg : Tendsto g l (𝓝 0)) : - Tendsto (fun x => f x * g x) l (𝓝 0) := - hg.op_zero_isBoundedUnder_le hf (flip (· * ·)) fun x y => - (norm_mul_le y x).trans_eq (mul_comm _ _) - /-- In a seminormed ring, the left-multiplication `AddMonoidHom` is bounded. -/ theorem mulLeft_bound (x : α) : ∀ y : α, ‖AddMonoidHom.mulLeft x y‖ ≤ ‖x‖ * ‖y‖ := norm_mul_le x @@ -244,7 +238,7 @@ theorem mulRight_bound (x : α) : ∀ y : α, ‖AddMonoidHom.mulRight x y‖ exact norm_mul_le y x /-- A non-unital subalgebra of a non-unital seminormed ring is also a non-unital seminormed ring, -with the restriction of the norm. -/ +with the restriction of the norm. -/ instance NonUnitalSubalgebra.nonUnitalSeminormedRing {𝕜 : Type*} [CommRing 𝕜] {E : Type*} [NonUnitalSeminormedRing E] [Module 𝕜 E] (s : NonUnitalSubalgebra 𝕜 E) : NonUnitalSeminormedRing s := @@ -252,7 +246,7 @@ instance NonUnitalSubalgebra.nonUnitalSeminormedRing {𝕜 : Type*} [CommRing norm_mul := fun a b => norm_mul_le a.1 b.1 } /-- A non-unital subalgebra of a non-unital seminormed ring is also a non-unital seminormed ring, -with the restriction of the norm. -/ +with the restriction of the norm. -/ -- necessary to require `SMulMemClass S 𝕜 E` so that `𝕜` can be determined as an `outParam` @[nolint unusedArguments] instance (priority := 75) NonUnitalSubalgebraClass.nonUnitalSeminormedRing {S 𝕜 E : Type*} @@ -263,14 +257,14 @@ instance (priority := 75) NonUnitalSubalgebraClass.nonUnitalSeminormedRing {S norm_mul := fun a b => norm_mul_le a.1 b.1 } /-- A non-unital subalgebra of a non-unital normed ring is also a non-unital normed ring, with the -restriction of the norm. -/ +restriction of the norm. -/ instance NonUnitalSubalgebra.nonUnitalNormedRing {𝕜 : Type*} [CommRing 𝕜] {E : Type*} [NonUnitalNormedRing E] [Module 𝕜 E] (s : NonUnitalSubalgebra 𝕜 E) : NonUnitalNormedRing s := { s.nonUnitalSeminormedRing with eq_of_dist_eq_zero := eq_of_dist_eq_zero } /-- A non-unital subalgebra of a non-unital normed ring is also a non-unital normed ring, -with the restriction of the norm. -/ +with the restriction of the norm. -/ instance (priority := 75) NonUnitalSubalgebraClass.nonUnitalNormedRing {S 𝕜 E : Type*} [CommRing 𝕜] [NonUnitalNormedRing E] [Module 𝕜 E] [SetLike S E] [NonUnitalSubringClass S E] [SMulMemClass S 𝕜 E] (s : S) : @@ -300,21 +294,6 @@ instance Prod.nonUnitalSeminormedRing [NonUnitalSeminormedRing β] : _ = ‖x‖ * ‖y‖ := rfl } -/-- Non-unital seminormed ring structure on the product of finitely many non-unital seminormed -rings, using the sup norm. -/ -instance Pi.nonUnitalSeminormedRing {π : ι → Type*} [Fintype ι] - [∀ i, NonUnitalSeminormedRing (π i)] : NonUnitalSeminormedRing (∀ i, π i) := - { Pi.seminormedAddCommGroup, Pi.nonUnitalRing with - norm_mul := fun x y => - NNReal.coe_mono <| - calc - (Finset.univ.sup fun i => ‖x i * y i‖₊) ≤ - Finset.univ.sup ((fun i => ‖x i‖₊) * fun i => ‖y i‖₊) := - Finset.sup_mono_fun fun _ _ => norm_mul_le _ _ - _ ≤ (Finset.univ.sup fun i => ‖x i‖₊) * Finset.univ.sup fun i => ‖y i‖₊ := - Finset.sup_mul_le_mul_sup_of_nonneg _ (fun _ _ => zero_le _) fun _ _ => zero_le _ - } - instance MulOpposite.instNonUnitalSeminormedRing : NonUnitalSeminormedRing αᵐᵒᵖ where __ := instNonUnitalRing __ := instSeminormedAddCommGroup @@ -325,7 +304,7 @@ end NonUnitalSeminormedRing section SeminormedRing -variable [SeminormedRing α] +variable [SeminormedRing α] {a b c : α} /-- A subalgebra of a seminormed ring is also a seminormed ring, with the restriction of the norm. -/ @@ -358,6 +337,7 @@ instance (priority := 75) SubalgebraClass.normedRing {S 𝕜 E : Type*} [CommRin { seminormedRing s with eq_of_dist_eq_zero := eq_of_dist_eq_zero } + theorem Nat.norm_cast_le : ∀ n : ℕ, ‖(n : α)‖ ≤ n * ‖(1 : α)‖ | 0 => by simp | n + 1 => by @@ -368,7 +348,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) @@ -412,7 +392,7 @@ theorem nnnorm_pow_le' (a : α) : ∀ {n : ℕ}, 0 < n → ‖a ^ n‖₊ ≤ /-- If `α` is a seminormed ring with `‖1‖₊ = 1`, then `‖a ^ n‖₊ ≤ ‖a‖₊ ^ n`. See also `nnnorm_pow_le'`. -/ theorem nnnorm_pow_le [NormOneClass α] (a : α) (n : ℕ) : ‖a ^ n‖₊ ≤ ‖a‖₊ ^ n := - Nat.recOn n (by simp only [Nat.zero_eq, pow_zero, nnnorm_one, le_rfl]) + Nat.recOn n (by simp only [pow_zero, nnnorm_one, le_rfl]) fun k _hk => nnnorm_pow_le' a k.succ_pos /-- If `α` is a seminormed ring, then `‖a ^ n‖ ≤ ‖a‖ ^ n` for `n > 0`. See also `norm_pow_le`. -/ @@ -422,7 +402,7 @@ theorem norm_pow_le' (a : α) {n : ℕ} (h : 0 < n) : ‖a ^ n‖ ≤ ‖a‖ ^ /-- If `α` is a seminormed ring with `‖1‖ = 1`, then `‖a ^ n‖ ≤ ‖a‖ ^ n`. See also `norm_pow_le'`. -/ theorem norm_pow_le [NormOneClass α] (a : α) (n : ℕ) : ‖a ^ n‖ ≤ ‖a‖ ^ n := - Nat.recOn n (by simp only [Nat.zero_eq, pow_zero, norm_one, le_rfl]) + Nat.recOn n (by simp only [pow_zero, norm_one, le_rfl]) fun n _hn => norm_pow_le' a n.succ_pos theorem eventually_norm_pow_le (a : α) : ∀ᶠ n : ℕ in atTop, ‖a ^ n‖ ≤ ‖a‖ ^ n := @@ -436,16 +416,39 @@ instance ULift.seminormedRing : SeminormedRing (ULift α) := instance Prod.seminormedRing [SeminormedRing β] : SeminormedRing (α × β) := { nonUnitalSeminormedRing, instRing with } -/-- Seminormed ring structure on the product of finitely many seminormed rings, - using the sup norm. -/ -instance Pi.seminormedRing {π : ι → Type*} [Fintype ι] [∀ i, SeminormedRing (π i)] : - SeminormedRing (∀ i, π i) := - { Pi.nonUnitalSeminormedRing, Pi.ring with } - instance MulOpposite.instSeminormedRing : SeminormedRing αᵐᵒᵖ where __ := instRing __ := instNonUnitalSeminormedRing +/-- This inequality is particularly useful when `c = 1` and `‖a‖ = ‖b‖ = 1` as it then shows that +chord length is a metric on the unit complex numbers. -/ +lemma norm_sub_mul_le (ha : ‖a‖ ≤ 1) : ‖c - a * b‖ ≤ ‖c - a‖ + ‖1 - b‖ := + calc + _ ≤ ‖c - a‖ + ‖a * (1 - b)‖ := by + simpa [mul_one_sub] using norm_sub_le_norm_sub_add_norm_sub c a (a * b) + _ ≤ ‖c - a‖ + ‖a‖ * ‖1 - b‖ := by gcongr; exact norm_mul_le .. + _ ≤ ‖c - a‖ + 1 * ‖1 - b‖ := by gcongr + _ = ‖c - a‖ + ‖1 - b‖ := by simp + +/-- This inequality is particularly useful when `c = 1` and `‖a‖ = ‖b‖ = 1` as it then shows that +chord length is a metric on the unit complex numbers. -/ +lemma norm_sub_mul_le' (hb : ‖b‖ ≤ 1) : ‖c - a * b‖ ≤ ‖1 - a‖ + ‖c - b‖ := by + rw [add_comm]; exact norm_sub_mul_le (α := αᵐᵒᵖ) hb + +/-- This inequality is particularly useful when `c = 1` and `‖a‖ = ‖b‖ = 1` as it then shows that +chord length is a metric on the unit complex numbers. -/ +lemma nnnorm_sub_mul_le (ha : ‖a‖₊ ≤ 1) : ‖c - a * b‖₊ ≤ ‖c - a‖₊ + ‖1 - b‖₊ := norm_sub_mul_le ha + +/-- This inequality is particularly useful when `c = 1` and `‖a‖ = ‖b‖ = 1` as it then shows that +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 + +/-- 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 @@ -460,12 +463,6 @@ using the sup norm. -/ instance Prod.nonUnitalNormedRing [NonUnitalNormedRing β] : NonUnitalNormedRing (α × β) := { Prod.nonUnitalSeminormedRing, Prod.normedAddCommGroup with } -/-- Normed ring structure on the product of finitely many non-unital normed rings, using the sup -norm. -/ -instance Pi.nonUnitalNormedRing {π : ι → Type*} [Fintype ι] [∀ i, NonUnitalNormedRing (π i)] : - NonUnitalNormedRing (∀ i, π i) := - { Pi.nonUnitalSeminormedRing, Pi.normedAddCommGroup with } - instance MulOpposite.instNonUnitalNormedRing : NonUnitalNormedRing αᵐᵒᵖ where __ := instNonUnitalRing __ := instNonUnitalSeminormedRing @@ -490,11 +487,6 @@ instance ULift.normedRing : NormedRing (ULift α) := instance Prod.normedRing [NormedRing β] : NormedRing (α × β) := { nonUnitalNormedRing, instRing with } -/-- Normed ring structure on the product of finitely many normed rings, using the sup norm. -/ -instance Pi.normedRing {π : ι → Type*} [Fintype ι] [∀ i, NormedRing (π i)] : - NormedRing (∀ i, π i) := - { Pi.seminormedRing, Pi.normedAddCommGroup with } - instance MulOpposite.instNormedRing : NormedRing αᵐᵒᵖ where __ := instRing __ := instSeminormedRing @@ -515,12 +507,6 @@ instance Prod.nonUnitalSeminormedCommRing [NonUnitalSeminormedCommRing β] : NonUnitalSeminormedCommRing (α × β) := { nonUnitalSeminormedRing, instNonUnitalCommRing with } -/-- Non-unital seminormed commutative ring structure on the product of finitely many non-unital -seminormed commutative rings, using the sup norm. -/ -instance Pi.nonUnitalSeminormedCommRing {π : ι → Type*} [Fintype ι] - [∀ i, NonUnitalSeminormedCommRing (π i)] : NonUnitalSeminormedCommRing (∀ i, π i) := - { Pi.nonUnitalSeminormedRing, Pi.nonUnitalCommRing with } - instance MulOpposite.instNonUnitalSeminormedCommRing : NonUnitalSeminormedCommRing αᵐᵒᵖ where __ := instNonUnitalSeminormedRing __ := instNonUnitalCommRing @@ -532,14 +518,14 @@ section NonUnitalNormedCommRing variable [NonUnitalNormedCommRing α] /-- A non-unital subalgebra of a non-unital seminormed commutative ring is also a non-unital -seminormed commutative ring, with the restriction of the norm. -/ +seminormed commutative ring, with the restriction of the norm. -/ instance NonUnitalSubalgebra.nonUnitalSeminormedCommRing {𝕜 : Type*} [CommRing 𝕜] {E : Type*} [NonUnitalSeminormedCommRing E] [Module 𝕜 E] (s : NonUnitalSubalgebra 𝕜 E) : NonUnitalSeminormedCommRing s := { s.nonUnitalSeminormedRing, s.toNonUnitalCommRing with } /-- A non-unital subalgebra of a non-unital normed commutative ring is also a non-unital normed -commutative ring, with the restriction of the norm. -/ +commutative ring, with the restriction of the norm. -/ instance NonUnitalSubalgebra.nonUnitalNormedCommRing {𝕜 : Type*} [CommRing 𝕜] {E : Type*} [NonUnitalNormedCommRing E] [Module 𝕜 E] (s : NonUnitalSubalgebra 𝕜 E) : NonUnitalNormedCommRing s := @@ -554,12 +540,6 @@ instance Prod.nonUnitalNormedCommRing [NonUnitalNormedCommRing β] : NonUnitalNormedCommRing (α × β) := { Prod.nonUnitalSeminormedCommRing, Prod.normedAddCommGroup with } -/-- Normed commutative ring structure on the product of finitely many non-unital normed -commutative rings, using the sup norm. -/ -instance Pi.nonUnitalNormedCommRing {π : ι → Type*} [Fintype ι] - [∀ i, NonUnitalNormedCommRing (π i)] : NonUnitalNormedCommRing (∀ i, π i) := - { Pi.nonUnitalSeminormedCommRing, Pi.normedAddCommGroup with } - instance MulOpposite.instNonUnitalNormedCommRing : NonUnitalNormedCommRing αᵐᵒᵖ where __ := instNonUnitalNormedRing __ := instNonUnitalSeminormedCommRing @@ -578,12 +558,6 @@ instance ULift.seminormedCommRing : SeminormedCommRing (ULift α) := instance Prod.seminormedCommRing [SeminormedCommRing β] : SeminormedCommRing (α × β) := { Prod.nonUnitalSeminormedCommRing, instCommRing with } -/-- Seminormed commutative ring structure on the product of finitely many seminormed commutative -rings, using the sup norm. -/ -instance Pi.seminormedCommRing {π : ι → Type*} [Fintype ι] [∀ i, SeminormedCommRing (π i)] : - SeminormedCommRing (∀ i, π i) := - { Pi.nonUnitalSeminormedCommRing, Pi.ring with } - instance MulOpposite.instSeminormedCommRing : SeminormedCommRing αᵐᵒᵖ where __ := instSeminormedRing __ := instNonUnitalSeminormedCommRing @@ -593,13 +567,13 @@ end SeminormedCommRing section NormedCommRing /-- A subalgebra of a seminormed commutative ring is also a seminormed commutative ring, with the -restriction of the norm. -/ +restriction of the norm. -/ instance Subalgebra.seminormedCommRing {𝕜 : Type*} [CommRing 𝕜] {E : Type*} [SeminormedCommRing E] [Algebra 𝕜 E] (s : Subalgebra 𝕜 E) : SeminormedCommRing s := { s.seminormedRing, s.toCommRing with } /-- A subalgebra of a normed commutative ring is also a normed commutative ring, with the -restriction of the norm. -/ +restriction of the norm. -/ instance Subalgebra.normedCommRing {𝕜 : Type*} [CommRing 𝕜] {E : Type*} [NormedCommRing E] [Algebra 𝕜 E] (s : Subalgebra 𝕜 E) : NormedCommRing s := { s.seminormedCommRing, s.normedRing with } @@ -614,47 +588,17 @@ norm. -/ instance Prod.normedCommRing [NormedCommRing β] : NormedCommRing (α × β) := { nonUnitalNormedRing, instCommRing with } -/-- Normed commutative ring structure on the product of finitely many normed commutative rings, -using the sup norm. -/ -instance Pi.normedCommutativeRing {π : ι → Type*} [Fintype ι] [∀ i, NormedCommRing (π i)] : - NormedCommRing (∀ i, π i) := - { Pi.seminormedCommRing, Pi.normedAddCommGroup with } - instance MulOpposite.instNormedCommRing : NormedCommRing αᵐᵒᵖ where __ := instNormedRing __ := instSeminormedCommRing -end NormedCommRing - --- see Note [lower instance priority] -instance (priority := 100) semi_normed_ring_top_monoid [NonUnitalSeminormedRing α] : - ContinuousMul α := - ⟨continuous_iff_continuousAt.2 fun x => - tendsto_iff_norm_sub_tendsto_zero.2 <| by - have : ∀ e : α × α, - ‖e.1 * e.2 - x.1 * x.2‖ ≤ ‖e.1‖ * ‖e.2 - x.2‖ + ‖e.1 - x.1‖ * ‖x.2‖ := by - 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 - _ ≤ ‖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 ?_ - convert - ((continuous_fst.tendsto x).norm.mul - ((continuous_snd.tendsto x).sub tendsto_const_nhds).norm).add - (((continuous_fst.tendsto x).sub tendsto_const_nhds).norm.mul _) - -- Porting note: `show` used to select a goal to work on - rotate_right - · show Tendsto _ _ _ - exact tendsto_const_nhds - · simp⟩ +/-- 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 --- see Note [lower instance priority] -/-- A seminormed ring is a topological ring. -/ -instance (priority := 100) semi_normed_top_ring [NonUnitalSeminormedRing α] : - TopologicalRing α where +end NormedCommRing section NormedDivisionRing @@ -740,113 +684,45 @@ 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 antilipschitzWith_mul_left {a : α} (ha : a ≠ 0) : AntilipschitzWith (‖a‖₊⁻¹) (a * ·) := - AntilipschitzWith.of_le_mul_dist fun _ _ ↦ by simp [dist_eq_norm, ← _root_.mul_sub, ha] - -lemma antilipschitzWith_mul_right {a : α} (ha : a ≠ 0) : AntilipschitzWith (‖a‖₊⁻¹) (· * a) := - AntilipschitzWith.of_le_mul_dist fun _ _ ↦ by - simp [dist_eq_norm, ← _root_.sub_mul, ← mul_comm (‖a‖), ha] - -/-- Multiplication by a nonzero element `a` on the left -as a `DilationEquiv` of a normed division ring. -/ -@[simps!] -def DilationEquiv.mulLeft (a : α) (ha : a ≠ 0) : α ≃ᵈ α where - toEquiv := Equiv.mulLeft₀ a ha - edist_eq' := ⟨‖a‖₊, nnnorm_ne_zero_iff.2 ha, fun x y ↦ by - simp [edist_nndist, nndist_eq_nnnorm, ← mul_sub]⟩ - -/-- Multiplication by a nonzero element `a` on the right -as a `DilationEquiv` of a normed division ring. -/ -@[simps!] -def DilationEquiv.mulRight (a : α) (ha : a ≠ 0) : α ≃ᵈ α where - toEquiv := Equiv.mulRight₀ a ha - edist_eq' := ⟨‖a‖₊, nnnorm_ne_zero_iff.2 ha, fun x y ↦ by - simp [edist_nndist, nndist_eq_nnnorm, ← sub_mul, ← mul_comm (‖a‖₊)]⟩ - -namespace Filter +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 comap_mul_left_cobounded {a : α} (ha : a ≠ 0) : - comap (a * ·) (cobounded α) = cobounded α := - Dilation.comap_cobounded (DilationEquiv.mulLeft a ha) +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] -@[simp] -lemma map_mul_left_cobounded {a : α} (ha : a ≠ 0) : - map (a * ·) (cobounded α) = cobounded α := - DilationEquiv.map_cobounded (DilationEquiv.mulLeft a ha) - -@[simp] -lemma comap_mul_right_cobounded {a : α} (ha : a ≠ 0) : - comap (· * a) (cobounded α) = cobounded α := - Dilation.comap_cobounded (DilationEquiv.mulRight a ha) - -@[simp] -lemma map_mul_right_cobounded {a : α} (ha : a ≠ 0) : - map (· * a) (cobounded α) = cobounded α := - DilationEquiv.map_cobounded (DilationEquiv.mulRight a ha) - -/-- Multiplication on the left by a nonzero element of a normed division ring tends to infinity at -infinity. -/ -theorem tendsto_mul_left_cobounded {a : α} (ha : a ≠ 0) : - Tendsto (a * ·) (cobounded α) (cobounded α) := - (map_mul_left_cobounded ha).le - -/-- Multiplication on the right by a nonzero element of a normed division ring tends to infinity at -infinity. -/ -theorem tendsto_mul_right_cobounded {a : α} (ha : a ≠ 0) : - Tendsto (· * a) (cobounded α) (cobounded α) := - (map_mul_right_cobounded ha).le - -@[simp] -lemma inv_cobounded₀ : (cobounded α)⁻¹ = 𝓝[≠] 0 := by - rw [← comap_norm_atTop, ← Filter.comap_inv, ← comap_norm_nhdsWithin_Ioi_zero, - ← inv_atTop₀, ← Filter.comap_inv] - simp only [comap_comap, (· ∘ ·), norm_inv] - -@[simp] -lemma inv_nhdsWithin_ne_zero : (𝓝[≠] (0 : α))⁻¹ = cobounded α := by - rw [← inv_cobounded₀, inv_inv] - -lemma tendsto_inv₀_cobounded' : Tendsto Inv.inv (cobounded α) (𝓝[≠] 0) := - inv_cobounded₀.le - -theorem tendsto_inv₀_cobounded : Tendsto Inv.inv (cobounded α) (𝓝 0) := - tendsto_inv₀_cobounded'.mono_right inf_le_left - -lemma tendsto_inv₀_nhdsWithin_ne_zero : Tendsto Inv.inv (𝓝[≠] 0) (cobounded α) := - inv_nhdsWithin_ne_zero.le - -end Filter - --- see Note [lower instance priority] -instance (priority := 100) NormedDivisionRing.to_hasContinuousInv₀ : HasContinuousInv₀ α := by - refine ⟨fun r r0 => tendsto_iff_norm_sub_tendsto_zero.2 ?_⟩ - have r0' : 0 < ‖r‖ := norm_pos_iff.2 r0 - rcases exists_between r0' with ⟨ε, ε0, εr⟩ - have : ∀ᶠ e in 𝓝 r, ‖e⁻¹ - r⁻¹‖ ≤ ‖r - e‖ / ‖r‖ / ε := by - filter_upwards [(isOpen_lt continuous_const continuous_norm).eventually_mem εr] with e he - 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, - 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 ?_ - refine (((continuous_const.sub continuous_id).norm.div_const _).div_const _).tendsto' _ _ ?_ +lemma discreteTopology_unit_closedBall_eq_univ : (Metric.closedBall 0 1 : Set 𝕜) = Set.univ := by + ext simp --- see Note [lower instance priority] -/-- A normed division ring is a topological division ring. -/ -instance (priority := 100) NormedDivisionRing.to_topologicalDivisionRing : - TopologicalDivisionRing α where - -protected lemma IsOfFinOrder.norm_eq_one (ha : IsOfFinOrder a) : ‖a‖ = 1 := - ((normHom : α →*₀ ℝ).toMonoidHom.isOfFinOrder ha).eq_one $ norm_nonneg _ +end Discrete -example [Monoid β] (φ : β →* α) {x : β} {k : ℕ+} (h : x ^ (k : ℕ) = 1) : - ‖φ x‖ = 1 := (φ.isOfFinOrder <| isOfFinOrder_iff_pow_eq_one.2 ⟨_, k.2, h⟩).norm_eq_one +end NormedDivisionRing end NormedDivisionRing @@ -960,11 +836,6 @@ instance denselyOrdered_range_nnnorm : DenselyOrdered (Set.range (nnnorm : α let ⟨z, h⟩ := exists_lt_nnnorm_lt α hxy exact ⟨⟨‖z‖₊, z, rfl⟩, h⟩ -theorem denseRange_nnnorm : DenseRange (nnnorm : α → ℝ≥0) := - dense_of_exists_between fun _ _ hr => - let ⟨x, h⟩ := exists_lt_nnnorm_lt α hr - ⟨‖x‖₊, ⟨x, rfl⟩, h⟩ - end Densely end NormedField @@ -979,7 +850,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 ℝ := @@ -1017,14 +888,6 @@ theorem norm_eq (x : ℝ≥0) : ‖(x : ℝ)‖ = x := by rw [Real.norm_eq_abs, theorem nnnorm_eq (x : ℝ≥0) : ‖(x : ℝ)‖₊ = x := NNReal.eq <| Real.norm_of_nonneg x.2 -lemma lipschitzWith_sub : LipschitzWith 2 (fun (p : ℝ≥0 × ℝ≥0) ↦ p.1 - p.2) := by - rw [← isometry_subtype_coe.lipschitzWith_iff] - have : Isometry (Prod.map ((↑) : ℝ≥0 → ℝ) ((↑) : ℝ≥0 → ℝ)) := - isometry_subtype_coe.prod_map isometry_subtype_coe - convert (((LipschitzWith.prod_fst.comp this.lipschitz).sub - (LipschitzWith.prod_snd.comp this.lipschitz)).max_const 0) - norm_num - end NNReal @[simp 1001] -- Porting note: increase priority so that the LHS doesn't simplify @@ -1036,37 +899,19 @@ 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]) -instance Int.instNormedCommRing : NormedCommRing ℤ where - __ := instCommRing - __ := instNormedAddCommGroup - norm_mul m n := by simp only [norm, Int.cast_mul, abs_mul, le_rfl] - -instance Int.instNormOneClass : NormOneClass ℤ := - ⟨by simp [← Int.norm_cast_real]⟩ - -instance Rat.instNormedField : NormedField ℚ where - __ := instField - __ := instNormedAddCommGroup - norm_mul' a b := by simp only [norm, Rat.cast_mul, abs_mul] - -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 RingHomIsometric variable {R₁ : Type*} {R₂ : Type*} {R₃ : Type*} diff --git a/Mathlib/Analysis/Normed/Field/InfiniteSum.lean b/Mathlib/Analysis/Normed/Field/InfiniteSum.lean index 4defadc79c84a..720c5451551ec 100644 --- a/Mathlib/Analysis/Normed/Field/InfiniteSum.lean +++ b/Mathlib/Analysis/Normed/Field/InfiniteSum.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Anatole Dedecker. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Anatole Dedecker -/ -import Mathlib.Analysis.Normed.Field.Basic +import Mathlib.Analysis.Normed.Field.Lemmas import Mathlib.Analysis.Normed.Group.InfiniteSum import Mathlib.Topology.Algebra.InfiniteSum.Real @@ -21,9 +21,9 @@ We first establish results about arbitrary index types, `ι` and `ι'`, and then variable {R : Type*} {ι : Type*} {ι' : Type*} [NormedRing R] -open scoped Classical +open scoped Topology -open Finset +open Finset Filter /-! ### Arbitrary index types -/ @@ -43,13 +43,35 @@ theorem summable_mul_of_summable_norm [CompleteSpace R] {f : ι → R} {g : ι' Summable fun x : ι × ι' => f x.1 * g x.2 := (hf.mul_norm hg).of_norm -/-- Product of two infinites sums indexed by arbitrary types. - See also `tsum_mul_tsum` if `f` and `g` are *not* absolutely summable. -/ +theorem summable_mul_of_summable_norm' {f : ι → R} {g : ι' → R} + (hf : Summable fun x => ‖f x‖) (h'f : Summable f) + (hg : Summable fun x => ‖g x‖) (h'g : Summable g) : + Summable fun x : ι × ι' => f x.1 * g x.2 := by + classical + suffices HasSum (fun x : ι × ι' => f x.1 * g x.2) ((∑' i, f i) * (∑' j, g j)) from this.summable + let s : Finset ι × Finset ι' → Finset (ι × ι') := fun p ↦ p.1 ×ˢ p.2 + apply hasSum_of_subseq_of_summable (hf.mul_norm hg) tendsto_finset_prod_atTop + rw [← prod_atTop_atTop_eq] + have := Tendsto.prod_map h'f.hasSum h'g.hasSum + rw [← nhds_prod_eq] at this + convert ((continuous_mul (M := R)).continuousAt + (x := (∑' (i : ι), f i, ∑' (j : ι'), g j))).tendsto.comp this with p + simp [s, sum_product, ← mul_sum, ← sum_mul] + +/-- Product of two infinite sums indexed by arbitrary types. + See also `tsum_mul_tsum` if `f` and `g` are *not* absolutely summable, and + `tsum_mul_tsum_of_summable_norm'` when the space is not complete. -/ theorem tsum_mul_tsum_of_summable_norm [CompleteSpace R] {f : ι → R} {g : ι' → R} (hf : Summable fun x => ‖f x‖) (hg : Summable fun x => ‖g x‖) : ((∑' x, f x) * ∑' y, g y) = ∑' z : ι × ι', f z.1 * g z.2 := tsum_mul_tsum hf.of_norm hg.of_norm (summable_mul_of_summable_norm hf hg) +theorem tsum_mul_tsum_of_summable_norm' {f : ι → R} {g : ι' → R} + (hf : Summable fun x => ‖f x‖) (h'f : Summable f) + (hg : Summable fun x => ‖g x‖) (h'g : Summable g) : + ((∑' x, f x) * ∑' y, g y) = ∑' z : ι × ι', f z.1 * g z.2 := + tsum_mul_tsum h'f h'g (summable_mul_of_summable_norm' hf h'f hg h'g) + /-! ### `ℕ`-indexed families (Cauchy product) We prove two versions of the Cauchy product formula. The first one is @@ -76,28 +98,69 @@ theorem summable_norm_sum_mul_antidiagonal_of_summable_norm {f g : ℕ → R} norm_sum_le _ _ _ ≤ ∑ kl ∈ antidiagonal n, ‖f kl.1‖ * ‖g kl.2‖ := by gcongr; apply norm_mul_le +theorem summable_sum_mul_antidiagonal_of_summable_norm' {f g : ℕ → R} + (hf : Summable fun x => ‖f x‖) (h'f : Summable f) + (hg : Summable fun x => ‖g x‖) (h'g : Summable g) : + Summable fun n => ∑ kl ∈ antidiagonal n, f kl.1 * g kl.2 := + summable_sum_mul_antidiagonal_of_summable_mul (summable_mul_of_summable_norm' hf h'f hg h'g) + /-- The Cauchy product formula for the product of two infinite sums indexed by `ℕ`, expressed by summing on `Finset.antidiagonal`. See also `tsum_mul_tsum_eq_tsum_sum_antidiagonal` if `f` and `g` are - *not* absolutely summable. -/ + *not* absolutely summable, and `tsum_mul_tsum_eq_tsum_sum_antidiagonal_of_summable_norm'` + when the space is not complete. -/ theorem tsum_mul_tsum_eq_tsum_sum_antidiagonal_of_summable_norm [CompleteSpace R] {f g : ℕ → R} (hf : Summable fun x => ‖f x‖) (hg : Summable fun x => ‖g x‖) : ((∑' n, f n) * ∑' n, g n) = ∑' n, ∑ kl ∈ antidiagonal n, f kl.1 * g kl.2 := tsum_mul_tsum_eq_tsum_sum_antidiagonal hf.of_norm hg.of_norm (summable_mul_of_summable_norm hf hg) +theorem tsum_mul_tsum_eq_tsum_sum_antidiagonal_of_summable_norm' {f g : ℕ → R} + (hf : Summable fun x => ‖f x‖) (h'f : Summable f) + (hg : Summable fun x => ‖g x‖) (h'g : Summable g) : + ((∑' n, f n) * ∑' n, g n) = ∑' n, ∑ kl ∈ antidiagonal n, f kl.1 * g kl.2 := + tsum_mul_tsum_eq_tsum_sum_antidiagonal h'f h'g (summable_mul_of_summable_norm' hf h'f hg h'g) + theorem summable_norm_sum_mul_range_of_summable_norm {f g : ℕ → R} (hf : Summable fun x => ‖f x‖) (hg : Summable fun x => ‖g x‖) : Summable fun n => ‖∑ k ∈ range (n + 1), f k * g (n - k)‖ := by simp_rw [← sum_antidiagonal_eq_sum_range_succ fun k l => f k * g l] exact summable_norm_sum_mul_antidiagonal_of_summable_norm hf hg +theorem summable_sum_mul_range_of_summable_norm' {f g : ℕ → R} + (hf : Summable fun x => ‖f x‖) (h'f : Summable f) + (hg : Summable fun x => ‖g x‖) (h'g : Summable g) : + Summable fun n => ∑ k ∈ range (n + 1), f k * g (n - k) := by + simp_rw [← sum_antidiagonal_eq_sum_range_succ fun k l => f k * g l] + exact summable_sum_mul_antidiagonal_of_summable_norm' hf h'f hg h'g + /-- The Cauchy product formula for the product of two infinite sums indexed by `ℕ`, expressed by summing on `Finset.range`. See also `tsum_mul_tsum_eq_tsum_sum_range` if `f` and `g` are - *not* absolutely summable. -/ + *not* absolutely summable, and `tsum_mul_tsum_eq_tsum_sum_range_of_summable_norm'` when the + space is not complete. -/ theorem tsum_mul_tsum_eq_tsum_sum_range_of_summable_norm [CompleteSpace R] {f g : ℕ → R} (hf : Summable fun x => ‖f x‖) (hg : Summable fun x => ‖g x‖) : ((∑' n, f n) * ∑' n, g n) = ∑' n, ∑ k ∈ range (n + 1), f k * g (n - k) := by simp_rw [← sum_antidiagonal_eq_sum_range_succ fun k l => f k * g l] exact tsum_mul_tsum_eq_tsum_sum_antidiagonal_of_summable_norm hf hg +theorem hasSum_sum_range_mul_of_summable_norm [CompleteSpace R] {f g : ℕ → R} + (hf : Summable fun x => ‖f x‖) (hg : Summable fun x => ‖g x‖) : + HasSum (fun n ↦ ∑ k ∈ range (n + 1), f k * g (n - k)) ((∑' n, f n) * ∑' n, g n) := by + convert (summable_norm_sum_mul_range_of_summable_norm hf hg).of_norm.hasSum + exact tsum_mul_tsum_eq_tsum_sum_range_of_summable_norm hf hg + +theorem tsum_mul_tsum_eq_tsum_sum_range_of_summable_norm' {f g : ℕ → R} + (hf : Summable fun x => ‖f x‖) (h'f : Summable f) + (hg : Summable fun x => ‖g x‖) (h'g : Summable g) : + ((∑' n, f n) * ∑' n, g n) = ∑' n, ∑ k ∈ range (n + 1), f k * g (n - k) := by + simp_rw [← sum_antidiagonal_eq_sum_range_succ fun k l => f k * g l] + exact tsum_mul_tsum_eq_tsum_sum_antidiagonal_of_summable_norm' hf h'f hg h'g + +theorem hasSum_sum_range_mul_of_summable_norm' {f g : ℕ → R} + (hf : Summable fun x => ‖f x‖) (h'f : Summable f) + (hg : Summable fun x => ‖g x‖) (h'g : Summable g) : + HasSum (fun n ↦ ∑ k ∈ range (n + 1), f k * g (n - k)) ((∑' n, f n) * ∑' n, g n) := by + convert (summable_sum_mul_range_of_summable_norm' hf h'f hg h'g).hasSum + exact tsum_mul_tsum_eq_tsum_sum_range_of_summable_norm' hf h'f hg h'g + end Nat diff --git a/Mathlib/Analysis/Normed/Field/Lemmas.lean b/Mathlib/Analysis/Normed/Field/Lemmas.lean new file mode 100644 index 0000000000000..a2236fabdefec --- /dev/null +++ b/Mathlib/Analysis/Normed/Field/Lemmas.lean @@ -0,0 +1,422 @@ +/- +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.Algebra.Group.AddChar +import Mathlib.Algebra.Order.Ring.Finset +import Mathlib.Analysis.Normed.Field.Basic +import Mathlib.Analysis.Normed.Group.Bounded +import Mathlib.Analysis.Normed.Group.Rat +import Mathlib.Analysis.Normed.Group.Uniform +import Mathlib.Topology.Instances.NNReal +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. +assert_not_exists RestrictScalars + +variable {α : Type*} {β : Type*} {ι : Type*} + +open Filter Bornology +open scoped Topology NNReal Pointwise + +section NonUnitalSeminormedRing + +variable [NonUnitalSeminormedRing α] + +theorem Filter.Tendsto.zero_mul_isBoundedUnder_le {f g : ι → α} {l : Filter ι} + (hf : Tendsto f l (𝓝 0)) (hg : IsBoundedUnder (· ≤ ·) l ((‖·‖) ∘ g)) : + Tendsto (fun x => f x * g x) l (𝓝 0) := + hf.op_zero_isBoundedUnder_le hg (· * ·) norm_mul_le + +theorem Filter.isBoundedUnder_le_mul_tendsto_zero {f g : ι → α} {l : Filter ι} + (hf : IsBoundedUnder (· ≤ ·) l (norm ∘ f)) (hg : Tendsto g l (𝓝 0)) : + Tendsto (fun x => f x * g x) l (𝓝 0) := + hg.op_zero_isBoundedUnder_le hf (flip (· * ·)) fun x y => + (norm_mul_le y x).trans_eq (mul_comm _ _) + +/-- Non-unital seminormed ring structure on the product of finitely many non-unital seminormed +rings, using the sup norm. -/ +instance Pi.nonUnitalSeminormedRing {π : ι → Type*} [Fintype ι] + [∀ i, NonUnitalSeminormedRing (π i)] : NonUnitalSeminormedRing (∀ i, π i) := + { Pi.seminormedAddCommGroup, Pi.nonUnitalRing with + norm_mul := fun x y => + NNReal.coe_mono <| + calc + (Finset.univ.sup fun i => ‖x i * y i‖₊) ≤ + Finset.univ.sup ((fun i => ‖x i‖₊) * fun i => ‖y i‖₊) := + Finset.sup_mono_fun fun _ _ => norm_mul_le _ _ + _ ≤ (Finset.univ.sup fun i => ‖x i‖₊) * Finset.univ.sup fun i => ‖y i‖₊ := + Finset.sup_mul_le_mul_sup_of_nonneg _ (fun _ _ => zero_le _) fun _ _ => zero_le _ + } + +end NonUnitalSeminormedRing + +section SeminormedRing + +variable [SeminormedRing α] + +/-- Seminormed ring structure on the product of finitely many seminormed rings, + using the sup norm. -/ +instance Pi.seminormedRing {π : ι → Type*} [Fintype ι] [∀ i, SeminormedRing (π i)] : + SeminormedRing (∀ i, π i) := + { Pi.nonUnitalSeminormedRing, Pi.ring with } + +end SeminormedRing + +section NonUnitalNormedRing + +variable [NonUnitalNormedRing α] + +/-- Normed ring structure on the product of finitely many non-unital normed rings, using the sup +norm. -/ +instance Pi.nonUnitalNormedRing {π : ι → Type*} [Fintype ι] [∀ i, NonUnitalNormedRing (π i)] : + NonUnitalNormedRing (∀ i, π i) := + { Pi.nonUnitalSeminormedRing, Pi.normedAddCommGroup with } + +end NonUnitalNormedRing + +section NormedRing + +variable [NormedRing α] + +/-- Normed ring structure on the product of finitely many normed rings, using the sup norm. -/ +instance Pi.normedRing {π : ι → Type*} [Fintype ι] [∀ i, NormedRing (π i)] : + NormedRing (∀ i, π i) := + { Pi.seminormedRing, Pi.normedAddCommGroup with } + +end NormedRing + +section NonUnitalSeminormedCommRing + +variable [NonUnitalSeminormedCommRing α] + +/-- Non-unital seminormed commutative ring structure on the product of finitely many non-unital +seminormed commutative rings, using the sup norm. -/ +instance Pi.nonUnitalSeminormedCommRing {π : ι → Type*} [Fintype ι] + [∀ i, NonUnitalSeminormedCommRing (π i)] : NonUnitalSeminormedCommRing (∀ i, π i) := + { Pi.nonUnitalSeminormedRing, Pi.nonUnitalCommRing with } + +end NonUnitalSeminormedCommRing + +section NonUnitalNormedCommRing + +variable [NonUnitalNormedCommRing α] + +/-- Normed commutative ring structure on the product of finitely many non-unital normed +commutative rings, using the sup norm. -/ +instance Pi.nonUnitalNormedCommRing {π : ι → Type*} [Fintype ι] + [∀ i, NonUnitalNormedCommRing (π i)] : NonUnitalNormedCommRing (∀ i, π i) := + { Pi.nonUnitalSeminormedCommRing, Pi.normedAddCommGroup with } + +end NonUnitalNormedCommRing + +section SeminormedCommRing + +variable [SeminormedCommRing α] + +/-- Seminormed commutative ring structure on the product of finitely many seminormed commutative +rings, using the sup norm. -/ +instance Pi.seminormedCommRing {π : ι → Type*} [Fintype ι] [∀ i, SeminormedCommRing (π i)] : + SeminormedCommRing (∀ i, π i) := + { Pi.nonUnitalSeminormedCommRing, Pi.ring with } + +end SeminormedCommRing + +section NormedCommRing + +variable [NormedCommRing α] + +/-- Normed commutative ring structure on the product of finitely many normed commutative rings, +using the sup norm. -/ +instance Pi.normedCommutativeRing {π : ι → Type*} [Fintype ι] [∀ i, NormedCommRing (π i)] : + NormedCommRing (∀ i, π i) := + { Pi.seminormedCommRing, Pi.normedAddCommGroup with } + +end NormedCommRing + +-- see Note [lower instance priority] +instance (priority := 100) NonUnitalSeminormedRing.toContinuousMul [NonUnitalSeminormedRing α] : + ContinuousMul α := + ⟨continuous_iff_continuousAt.2 fun x => + tendsto_iff_norm_sub_tendsto_zero.2 <| by + have : ∀ e : α × α, + ‖e.1 * e.2 - x.1 * x.2‖ ≤ ‖e.1‖ * ‖e.2 - x.2‖ + ‖e.1 - x.1‖ * ‖x.2‖ := by + 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 + _ ≤ ‖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 ?_ + convert + ((continuous_fst.tendsto x).norm.mul + ((continuous_snd.tendsto x).sub tendsto_const_nhds).norm).add + (((continuous_fst.tendsto x).sub tendsto_const_nhds).norm.mul _) + -- Porting note: `show` used to select a goal to work on + rotate_right + · show Tendsto _ _ _ + exact tendsto_const_nhds + · simp⟩ + +-- see Note [lower instance priority] +/-- A seminormed ring is a topological ring. -/ +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 : α} + +lemma antilipschitzWith_mul_left {a : α} (ha : a ≠ 0) : AntilipschitzWith (‖a‖₊⁻¹) (a * ·) := + AntilipschitzWith.of_le_mul_dist fun _ _ ↦ by simp [dist_eq_norm, ← _root_.mul_sub, ha] + +lemma antilipschitzWith_mul_right {a : α} (ha : a ≠ 0) : AntilipschitzWith (‖a‖₊⁻¹) (· * a) := + AntilipschitzWith.of_le_mul_dist fun _ _ ↦ by + simp [dist_eq_norm, ← _root_.sub_mul, ← mul_comm (‖a‖), ha] + +/-- Multiplication by a nonzero element `a` on the left +as a `DilationEquiv` of a normed division ring. -/ +@[simps!] +def DilationEquiv.mulLeft (a : α) (ha : a ≠ 0) : α ≃ᵈ α where + toEquiv := Equiv.mulLeft₀ a ha + edist_eq' := ⟨‖a‖₊, nnnorm_ne_zero_iff.2 ha, fun x y ↦ by + simp [edist_nndist, nndist_eq_nnnorm, ← mul_sub]⟩ + +/-- Multiplication by a nonzero element `a` on the right +as a `DilationEquiv` of a normed division ring. -/ +@[simps!] +def DilationEquiv.mulRight (a : α) (ha : a ≠ 0) : α ≃ᵈ α where + toEquiv := Equiv.mulRight₀ a ha + edist_eq' := ⟨‖a‖₊, nnnorm_ne_zero_iff.2 ha, fun x y ↦ by + simp [edist_nndist, nndist_eq_nnnorm, ← sub_mul, ← mul_comm (‖a‖₊)]⟩ + +namespace Filter + +@[simp] +lemma comap_mul_left_cobounded {a : α} (ha : a ≠ 0) : + comap (a * ·) (cobounded α) = cobounded α := + Dilation.comap_cobounded (DilationEquiv.mulLeft a ha) + +@[simp] +lemma map_mul_left_cobounded {a : α} (ha : a ≠ 0) : + map (a * ·) (cobounded α) = cobounded α := + DilationEquiv.map_cobounded (DilationEquiv.mulLeft a ha) + +@[simp] +lemma comap_mul_right_cobounded {a : α} (ha : a ≠ 0) : + comap (· * a) (cobounded α) = cobounded α := + Dilation.comap_cobounded (DilationEquiv.mulRight a ha) + +@[simp] +lemma map_mul_right_cobounded {a : α} (ha : a ≠ 0) : + map (· * a) (cobounded α) = cobounded α := + DilationEquiv.map_cobounded (DilationEquiv.mulRight a ha) + +/-- Multiplication on the left by a nonzero element of a normed division ring tends to infinity at +infinity. -/ +theorem tendsto_mul_left_cobounded {a : α} (ha : a ≠ 0) : + Tendsto (a * ·) (cobounded α) (cobounded α) := + (map_mul_left_cobounded ha).le + +/-- Multiplication on the right by a nonzero element of a normed division ring tends to infinity at +infinity. -/ +theorem tendsto_mul_right_cobounded {a : α} (ha : a ≠ 0) : + Tendsto (· * a) (cobounded α) (cobounded α) := + (map_mul_right_cobounded ha).le + +@[simp] +lemma inv_cobounded₀ : (cobounded α)⁻¹ = 𝓝[≠] 0 := by + rw [← comap_norm_atTop, ← Filter.comap_inv, ← comap_norm_nhdsWithin_Ioi_zero, + ← inv_atTop₀, ← Filter.comap_inv] + simp only [comap_comap, Function.comp_def, norm_inv] + +@[simp] +lemma inv_nhdsWithin_ne_zero : (𝓝[≠] (0 : α))⁻¹ = cobounded α := by + rw [← inv_cobounded₀, inv_inv] + +lemma tendsto_inv₀_cobounded' : Tendsto Inv.inv (cobounded α) (𝓝[≠] 0) := + inv_cobounded₀.le + +theorem tendsto_inv₀_cobounded : Tendsto Inv.inv (cobounded α) (𝓝 0) := + tendsto_inv₀_cobounded'.mono_right inf_le_left + +lemma tendsto_inv₀_nhdsWithin_ne_zero : Tendsto Inv.inv (𝓝[≠] 0) (cobounded α) := + inv_nhdsWithin_ne_zero.le + +end Filter + +-- see Note [lower instance priority] +instance (priority := 100) NormedDivisionRing.to_hasContinuousInv₀ : HasContinuousInv₀ α := by + refine ⟨fun r r0 => tendsto_iff_norm_sub_tendsto_zero.2 ?_⟩ + have r0' : 0 < ‖r‖ := norm_pos_iff.2 r0 + rcases exists_between r0' with ⟨ε, ε0, εr⟩ + have : ∀ᶠ e in 𝓝 r, ‖e⁻¹ - r⁻¹‖ ≤ ‖r - e‖ / ‖r‖ / ε := by + filter_upwards [(isOpen_lt continuous_const continuous_norm).eventually_mem εr] with e he + 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, + 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 ?_ + refine (((continuous_const.sub continuous_id).norm.div_const _).div_const _).tendsto' _ _ ?_ + simp + +-- see Note [lower instance priority] +/-- A normed division ring is a topological division ring. -/ +instance (priority := 100) NormedDivisionRing.to_topologicalDivisionRing : + TopologicalDivisionRing α where + +protected lemma IsOfFinOrder.norm_eq_one (ha : IsOfFinOrder a) : ‖a‖ = 1 := + ((normHom : α →*₀ ℝ).toMonoidHom.isOfFinOrder ha).eq_one <| norm_nonneg _ + +example [Monoid β] (φ : β →* α) {x : β} {k : ℕ+} (h : x ^ (k : ℕ) = 1) : + ‖φ x‖ = 1 := (φ.isOfFinOrder <| isOfFinOrder_iff_pow_eq_one.2 ⟨_, k.2, h⟩).norm_eq_one + +@[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 + +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 α] + +theorem denseRange_nnnorm : DenseRange (nnnorm : α → ℝ≥0) := + dense_of_exists_between fun _ _ hr => + let ⟨x, h⟩ := exists_lt_nnnorm_lt α hr + ⟨‖x‖₊, ⟨x, rfl⟩, h⟩ + +end Densely + +end NormedField + +namespace NNReal + +lemma lipschitzWith_sub : LipschitzWith 2 (fun (p : ℝ≥0 × ℝ≥0) ↦ p.1 - p.2) := by + rw [← isometry_subtype_coe.lipschitzWith_iff] + have : Isometry (Prod.map ((↑) : ℝ≥0 → ℝ) ((↑) : ℝ≥0 → ℝ)) := + isometry_subtype_coe.prod_map isometry_subtype_coe + convert (((LipschitzWith.prod_fst.comp this.lipschitz).sub + (LipschitzWith.prod_snd.comp this.lipschitz)).max_const 0) + norm_num + +end NNReal + +instance Int.instNormedCommRing : NormedCommRing ℤ where + __ := instCommRing + __ := instNormedAddCommGroup + norm_mul m n := by simp only [norm, Int.cast_mul, abs_mul, le_rfl] + +instance Int.instNormOneClass : NormOneClass ℤ := + ⟨by simp [← Int.norm_cast_real]⟩ + +instance Rat.instNormedField : NormedField ℚ where + __ := instField + __ := instNormedAddCommGroup + norm_mul' a b := by simp only [norm, Rat.cast_mul, abs_mul] + +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/UnitBall.lean b/Mathlib/Analysis/Normed/Field/UnitBall.lean index 8652d79164427..146e37b0e5af2 100644 --- a/Mathlib/Analysis/Normed/Field/UnitBall.lean +++ b/Mathlib/Analysis/Normed/Field/UnitBall.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Yury Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov, Heather Macbeth -/ -import Mathlib.Analysis.Normed.Field.Basic +import Mathlib.Analysis.Normed.Field.Lemmas import Mathlib.Analysis.Normed.Group.BallSphere /-! @@ -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 8a26d2971bb7e..c4b97754790bb 100644 --- a/Mathlib/Analysis/Normed/Group/AddTorsor.lean +++ b/Mathlib/Analysis/Normed/Group/AddTorsor.lean @@ -283,7 +283,7 @@ theorem IsClosed.vadd_right_of_isCompact {s : Set V} {t : Set P} (hs : IsClosed choose! a ha v hv hav using husv rcases ht.isSeqCompact hv with ⟨q, hqt, φ, φ_mono, hφq⟩ refine ⟨p -ᵥ q, hs.mem_of_tendsto ((hup.comp φ_mono.tendsto_atTop).vsub hφq) - (eventually_of_forall fun n ↦ ?_), q, hqt, vsub_vadd _ _⟩ + (Eventually.of_forall fun n ↦ ?_), q, hqt, vsub_vadd _ _⟩ convert ha (φ n) using 1 exact (eq_vadd_iff_vsub_eq _ _ _).mp (hav (φ n)).symm diff --git a/Mathlib/Analysis/Normed/Group/Basic.lean b/Mathlib/Analysis/Normed/Group/Basic.lean index 8c619280197ef..04e1413e4bea8 100644 --- a/Mathlib/Analysis/Normed/Group/Basic.lean +++ b/Mathlib/Analysis/Normed/Group/Basic.lean @@ -544,7 +544,7 @@ theorem norm_lt_of_mem_ball' (h : b ∈ ball a r) : ‖b‖ < ‖a‖ + r := @[to_additive] theorem norm_div_sub_norm_div_le_norm_div (u v w : E) : ‖u / w‖ - ‖v / w‖ ≤ ‖u / v‖ := by - simpa only [div_div_div_cancel_right'] using norm_sub_norm_le' (u / w) (v / w) + simpa only [div_div_div_cancel_right] using norm_sub_norm_le' (u / w) (v / w) @[to_additive (attr := simp 1001) mem_sphere_iff_norm] -- Porting note: increase priority so the left-hand side doesn't reduce @@ -739,7 +739,7 @@ real function `a` which tends to `0`, then `f` tends to `0`. In this pair of lem theorem squeeze_one_norm' {f : α → E} {a : α → ℝ} {t₀ : Filter α} (h : ∀ᶠ n in t₀, ‖f n‖ ≤ a n) (h' : Tendsto a t₀ (𝓝 0)) : Tendsto f t₀ (𝓝 1) := tendsto_one_iff_norm_tendsto_zero.2 <| - squeeze_zero' (eventually_of_forall fun _n => norm_nonneg' _) h h' + squeeze_zero' (Eventually.of_forall fun _n => norm_nonneg' _) h h' /-- Special case of the sandwich theorem: if the norm of `f` is bounded by a real function `a` which tends to `0`, then `f` tends to `1`. -/ @@ -747,7 +747,7 @@ tends to `0`, then `f` tends to `1`. -/ function `a` which tends to `0`, then `f` tends to `0`."] theorem squeeze_one_norm {f : α → E} {a : α → ℝ} {t₀ : Filter α} (h : ∀ n, ‖f n‖ ≤ a n) : Tendsto a t₀ (𝓝 0) → Tendsto f t₀ (𝓝 1) := - squeeze_one_norm' <| eventually_of_forall h + squeeze_one_norm' <| Eventually.of_forall h @[to_additive] theorem tendsto_norm_div_self (x : E) : Tendsto (fun a => ‖a / x‖) (𝓝 x) (𝓝 0) := by @@ -770,6 +770,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] @@ -1022,8 +1032,10 @@ theorem preimage_mul_sphere (a b : E) (r : ℝ) : (b * ·) ⁻¹' sphere a r = s @[to_additive norm_nsmul_le] theorem norm_pow_le_mul_norm (n : ℕ) (a : E) : ‖a ^ n‖ ≤ n * ‖a‖ := by - induction' n with n ih; · simp - simpa only [pow_succ, Nat.cast_succ, add_mul, one_mul] using norm_mul_le_of_le ih le_rfl + 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 @[to_additive nnnorm_nsmul_le] theorem nnnorm_pow_le_mul_norm (n : ℕ) (a : E) : ‖a ^ n‖₊ ≤ n * ‖a‖₊ := by @@ -1127,7 +1139,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 @@ -1150,24 +1162,26 @@ theorem norm_of_nonpos (hr : r ≤ 0) : ‖r‖ = -r := theorem le_norm_self (r : ℝ) : r ≤ ‖r‖ := le_abs_self r --- Porting note (#10618): `simp` can prove this -theorem norm_natCast (n : ℕ) : ‖(n : ℝ)‖ = n := - abs_of_nonneg n.cast_nonneg - -@[simp] -theorem nnnorm_natCast (n : ℕ) : ‖(n : ℝ)‖₊ = n := - NNReal.eq <| norm_natCast _ +@[simp 1100] lemma norm_natCast (n : ℕ) : ‖(n : ℝ)‖ = n := abs_of_nonneg n.cast_nonneg +@[simp 1100] lemma nnnorm_natCast (n : ℕ) : ‖(n : ℝ)‖₊ = n := NNReal.eq <| norm_natCast _ @[deprecated (since := "2024-04-05")] alias norm_coe_nat := norm_natCast @[deprecated (since := "2024-04-05")] alias nnnorm_coe_nat := nnnorm_natCast --- Porting note (#10618): `simp` can prove this -theorem norm_two : ‖(2 : ℝ)‖ = 2 := - abs_of_pos zero_lt_two +@[simp 1100] lemma norm_ofNat (n : ℕ) [n.AtLeastTwo] : + ‖(no_index (OfNat.ofNat n) : ℝ)‖ = OfNat.ofNat n := norm_natCast n -@[simp] -theorem nnnorm_two : ‖(2 : ℝ)‖₊ = 2 := - NNReal.eq <| by simp +@[simp 1100] lemma nnnorm_ofNat (n : ℕ) [n.AtLeastTwo] : + ‖(no_index (OfNat.ofNat n) : ℝ)‖₊ = OfNat.ofNat n := nnnorm_natCast n + +lemma norm_two : ‖(2 : ℝ)‖ = 2 := abs_of_pos zero_lt_two +lemma nnnorm_two : ‖(2 : ℝ)‖₊ = 2 := NNReal.eq <| by simp + +@[simp 1100, norm_cast] +lemma norm_nnratCast (q : ℚ≥0) : ‖(q : ℝ)‖ = q := norm_of_nonneg q.cast_nonneg + +@[simp 1100, norm_cast] +lemma nnnorm_nnratCast (q : ℚ≥0) : ‖(q : ℝ)‖₊ = q := by simp [nnnorm, -norm_eq_abs] theorem nnnorm_of_nonneg (hr : 0 ≤ r) : ‖r‖₊ = ⟨r, hr⟩ := NNReal.eq <| norm_of_nonneg hr diff --git a/Mathlib/Analysis/Normed/Group/Bounded.lean b/Mathlib/Analysis/Normed/Group/Bounded.lean index 9a4c7dac9e078..329d2bfa734ce 100644 --- a/Mathlib/Analysis/Normed/Group/Bounded.lean +++ b/Mathlib/Analysis/Normed/Group/Bounded.lean @@ -59,7 +59,7 @@ lemma tendsto_norm_cocompact_atTop' [ProperSpace E] : Tendsto norm (cocompact E) @[to_additive (attr := simp)] lemma Filter.inv_cobounded : (cobounded E)⁻¹ = cobounded E := by - simp only [← comap_norm_atTop', ← Filter.comap_inv, comap_comap, (· ∘ ·), norm_inv'] + simp only [← comap_norm_atTop', ← Filter.comap_inv, comap_comap, Function.comp_def, norm_inv'] /-- In a (semi)normed group, inversion `x ↦ x⁻¹` tends to infinity at infinity. -/ @[to_additive "In a (semi)normed group, negation `x ↦ -x` tends to infinity at infinity."] 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/Completeness.lean b/Mathlib/Analysis/Normed/Group/Completeness.lean index 6390ce5cd3cc9..8fee862ad3d6d 100644 --- a/Mathlib/Analysis/Normed/Group/Completeness.lean +++ b/Mathlib/Analysis/Normed/Group/Completeness.lean @@ -51,7 +51,7 @@ section Normed variable {E : Type*} [NormedAddCommGroup E] /-- A normed additive group is complete if any absolutely convergent series converges in the -space. -/ +space. -/ lemma NormedAddCommGroup.completeSpace_of_summable_imp_tendsto (h : ∀ u : ℕ → E, Summable (‖u ·‖) → ∃ a, Tendsto (fun n => ∑ i ∈ range n, u i) atTop (𝓝 a)) : @@ -73,14 +73,14 @@ lemma NormedAddCommGroup.completeSpace_of_summable_imp_tendsto simpa only [sub_add_cancel] using h₁ /-- In a complete normed additive group, every absolutely convergent series converges in the -space. -/ +space. -/ lemma NormedAddCommGroup.summable_imp_tendsto_of_complete [CompleteSpace E] (u : ℕ → E) (hu : Summable (‖u ·‖)) : ∃ a, Tendsto (fun n => ∑ i ∈ range n, u i) atTop (𝓝 a) := by refine cauchySeq_tendsto_of_complete <| cauchySeq_of_summable_dist ?_ simp [dist_eq_norm, sum_range_succ, hu] /-- In a normed additive group, every absolutely convergent series converges in the -space iff the space is complete. -/ +space iff the space is complete. -/ lemma NormedAddCommGroup.summable_imp_tendsto_iff_completeSpace : (∀ u : ℕ → E, Summable (‖u ·‖) → ∃ a, Tendsto (fun n => ∑ i ∈ range n, u i) atTop (𝓝 a)) ↔ CompleteSpace E := 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 50127f79f7499..36439765ebe21 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 @@ -208,8 +208,8 @@ theorem le_opNorm (x : V₁) : ‖f x‖ ≤ ‖f‖ * ‖x‖ := by · rwa [h, mul_zero] at hC ⊢ have hlt : 0 < ‖x‖ := lt_of_le_of_ne (norm_nonneg x) (Ne.symm h) exact - (div_le_iff hlt).mp - (le_csInf bounds_nonempty fun c ⟨_, hc⟩ => (div_le_iff hlt).mpr <| by apply hc) + (div_le_iff₀ hlt).mp + (le_csInf bounds_nonempty fun c ⟨_, hc⟩ => (div_le_iff₀ hlt).mpr <| by apply hc) theorem le_opNorm_of_le {c : ℝ} {x} (h : ‖x‖ ≤ c) : ‖f x‖ ≤ ‖f‖ * c := le_trans (f.le_opNorm x) (by gcongr; exact f.opNorm_nonneg) @@ -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 := @@ -532,7 +532,7 @@ instance toNormedAddCommGroup {V₁ V₂ : Type*} [NormedAddCommGroup V₁] [Nor add_le' := opNorm_add_le eq_zero_of_map_eq_zero' := fun _f => opNorm_zero_iff.1 } -/-- Coercion of a `NormedAddGroupHom` is an `AddMonoidHom`. Similar to `AddMonoidHom.coeFn`. -/ +/-- Coercion of a `NormedAddGroupHom` is an `AddMonoidHom`. Similar to `AddMonoidHom.coeFn`. -/ @[simps] def coeAddHom : NormedAddGroupHom V₁ V₂ →+ V₁ → V₂ where toFun := DFunLike.coe @@ -656,7 +656,7 @@ theorem mem_ker (v : V₁) : v ∈ f.ker ↔ f v = 0 := by @[simps] def ker.lift (h : g.comp f = 0) : NormedAddGroupHom V₁ g.ker where toFun v := ⟨f v, by rw [g.mem_ker, ← comp_apply g f, h, zero_apply]⟩ - map_add' v w := by simp only [map_add, AddSubmonoid.mk_add_mk] + map_add' v w := by simp only [map_add, AddMemClass.mk_add_mk] bound' := f.bound' @[simp] 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/InfiniteSum.lean b/Mathlib/Analysis/Normed/Group/InfiniteSum.lean index fb02a2775c4d7..2eb196f059adf 100644 --- a/Mathlib/Analysis/Normed/Group/InfiniteSum.lean +++ b/Mathlib/Analysis/Normed/Group/InfiniteSum.lean @@ -65,7 +65,7 @@ theorem cauchySeq_finset_of_norm_bounded_eventually {f : ι → E} {g : ι → theorem cauchySeq_finset_of_norm_bounded {f : ι → E} (g : ι → ℝ) (hg : Summable g) (h : ∀ i, ‖f i‖ ≤ g i) : CauchySeq fun s : Finset ι => ∑ i ∈ s, f i := - cauchySeq_finset_of_norm_bounded_eventually hg <| eventually_of_forall h + cauchySeq_finset_of_norm_bounded_eventually hg <| Eventually.of_forall h /-- A version of the **direct comparison test** for conditionally convergent series. See `cauchySeq_finset_of_norm_bounded` for the same statement about absolutely convergent ones. -/ diff --git a/Mathlib/Analysis/Normed/Group/Pointwise.lean b/Mathlib/Analysis/Normed/Group/Pointwise.lean index dc38a34ea6770..ae8862a8aa948 100644 --- a/Mathlib/Analysis/Normed/Group/Pointwise.lean +++ b/Mathlib/Analysis/Normed/Group/Pointwise.lean @@ -67,8 +67,8 @@ theorem infEdist_inv (x : E) (s : Set E) : infEdist x⁻¹ s = infEdist x s⁻¹ @[to_additive] theorem ediam_mul_le (x y : Set E) : EMetric.diam (x * y) ≤ EMetric.diam x + EMetric.diam y := (LipschitzOnWith.ediam_image2_le (· * ·) _ _ - (fun _ _ => (isometry_mul_right _).lipschitz.lipschitzOnWith _) fun _ _ => - (isometry_mul_left _).lipschitz.lipschitzOnWith _).trans_eq <| + (fun _ _ => (isometry_mul_right _).lipschitz.lipschitzOnWith) fun _ _ => + (isometry_mul_left _).lipschitz.lipschitzOnWith).trans_eq <| by simp only [ENNReal.coe_one, one_mul] end EMetric diff --git a/Mathlib/Analysis/Normed/Group/Quotient.lean b/Mathlib/Analysis/Normed/Group/Quotient.lean index 7406b8e2cf248..9acc022a5fcfb 100644 --- a/Mathlib/Analysis/Normed/Group/Quotient.lean +++ b/Mathlib/Analysis/Normed/Group/Quotient.lean @@ -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‖ := @@ -213,7 +213,7 @@ theorem quotient_nhd_basis (S : AddSubgroup M) : refine fun ε ↦ Set.ext <| forall_mk.2 fun x ↦ ?_ rw [ball_zero_eq, mem_setOf_eq, norm_lt_iff, mem_image] exact exists_congr fun _ ↦ and_comm - rw [← mk_zero, nhds_eq, ← funext this] + rw [← QuotientAddGroup.mk_zero, nhds_eq, ← funext this] exact .map _ Metric.nhds_basis_ball /-- The seminormed group structure on the quotient by an additive subgroup. -/ @@ -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..f63a09356056d 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' diff --git a/Mathlib/Analysis/Normed/Group/SemiNormedGrp/Completion.lean b/Mathlib/Analysis/Normed/Group/SemiNormedGrp/Completion.lean index ffdb4b1697738..ca858da92cd33 100644 --- a/Mathlib/Analysis/Normed/Group/SemiNormedGrp/Completion.lean +++ b/Mathlib/Analysis/Normed/Group/SemiNormedGrp/Completion.lean @@ -102,12 +102,8 @@ instance : Preadditive SemiNormedGrp.{u} where 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 13db71e0908f2..e5aff9ade9489 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 @@ -124,7 +124,7 @@ instance hasLimit_parallelPair {V W : SemiNormedGrp.{u}} (f g : V ⟶ W) : 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 - -- Porting note: the `simp_rw` was was `rw [← h]` but motive is not type correct in mathlib4 + -- Porting note: the `simp_rw` was `rw [← h]` but motive is not type correct in mathlib4 ext x; dsimp; simp_rw [← h]; rfl} instance : Limits.HasEqualizers.{u, u + 1} SemiNormedGrp := diff --git a/Mathlib/Analysis/Normed/Group/Seminorm.lean b/Mathlib/Analysis/Normed/Group/Seminorm.lean index 39f1d2b490a43..06d80361d16b3 100644 --- a/Mathlib/Analysis/Normed/Group/Seminorm.lean +++ b/Mathlib/Analysis/Normed/Group/Seminorm.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, Yaël Dillies -/ import Mathlib.Data.NNReal.Basic -import Mathlib.Tactic.GCongr.Core +import Mathlib.Tactic.GCongr.CoreAttrs /-! # Group seminorms @@ -48,7 +48,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`. -/ @@ -325,7 +325,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 _ => @@ -381,7 +381,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 @@ -435,7 +435,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 @@ -477,7 +477,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 : Zero (NonarchAddGroupSeminorm E) := ⟨{ toFun := 0 @@ -522,7 +522,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)) := @@ -653,7 +653,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 @@ -703,7 +703,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 +787,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 @@ -829,7 +829,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..8e83b3535e430 --- /dev/null +++ b/Mathlib/Analysis/Normed/Group/Ultra.lean @@ -0,0 +1,240 @@ +/- +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 + +/-! +# 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 + +end CommGroup + +end IsUltrametricDist diff --git a/Mathlib/Analysis/Normed/Group/Uniform.lean b/Mathlib/Analysis/Normed/Group/Uniform.lean index 5a5962ff3c7b7..f8e72a4535b45 100644 --- a/Mathlib/Analysis/Normed/Group/Uniform.lean +++ b/Mathlib/Analysis/Normed/Group/Uniform.lean @@ -258,28 +258,65 @@ lemma lipschitzOnWith_inv_iff : LipschitzOnWith K f⁻¹ s ↔ LipschitzOnWith K lemma locallyLipschitz_inv_iff : LocallyLipschitz f⁻¹ ↔ LocallyLipschitz f := by simp [LocallyLipschitz] +@[to_additive (attr := simp)] +lemma locallyLipschitzOn_inv_iff : LocallyLipschitzOn s f⁻¹ ↔ LocallyLipschitzOn s f := by + simp [LocallyLipschitzOn] + @[to_additive] alias ⟨LipschitzWith.of_inv, LipschitzWith.inv⟩ := lipschitzWith_inv_iff @[to_additive] alias ⟨AntilipschitzWith.of_inv, AntilipschitzWith.inv⟩ := antilipschitzWith_inv_iff @[to_additive] alias ⟨LipschitzOnWith.of_inv, LipschitzOnWith.inv⟩ := lipschitzOnWith_inv_iff @[to_additive] alias ⟨LocallyLipschitz.of_inv, LocallyLipschitz.inv⟩ := locallyLipschitz_inv_iff +@[to_additive] +alias ⟨LocallyLipschitzOn.of_inv, LocallyLipschitzOn.inv⟩ := locallyLipschitzOn_inv_iff -namespace LipschitzWith - -@[to_additive add] -theorem mul' (hf : LipschitzWith Kf f) (hg : LipschitzWith Kg g) : - LipschitzWith (Kf + Kg) fun x => f x * g x := fun x y => +@[to_additive] +lemma LipschitzOnWith.mul (hf : LipschitzOnWith Kf f s) (hg : LipschitzOnWith Kg g s) : + LipschitzOnWith (Kf + Kg) (fun x ↦ f x * g x) s := fun x hx y hy ↦ calc edist (f x * g x) (f y * g y) ≤ edist (f x) (f y) + edist (g x) (g y) := edist_mul_mul_le _ _ _ _ - _ ≤ Kf * edist x y + Kg * edist x y := add_le_add (hf x y) (hg x y) + _ ≤ Kf * edist x y + Kg * edist x y := add_le_add (hf hx hy) (hg hx hy) _ = (Kf + Kg) * edist x y := (add_mul _ _ _).symm @[to_additive] -theorem div (hf : LipschitzWith Kf f) (hg : LipschitzWith Kg g) : +lemma LipschitzWith.mul (hf : LipschitzWith Kf f) (hg : LipschitzWith Kg g) : + LipschitzWith (Kf + Kg) fun x ↦ f x * g x := by + simpa [← lipschitzOnWith_univ] using hf.lipschitzOnWith.mul hg.lipschitzOnWith + +@[deprecated (since := "2024-08-25")] alias LipschitzWith.mul' := LipschitzWith.mul + +@[to_additive] +lemma LocallyLipschitzOn.mul (hf : LocallyLipschitzOn s f) (hg : LocallyLipschitzOn s g) : + LocallyLipschitzOn s fun x ↦ f x * g x := fun x hx ↦ by + obtain ⟨Kf, t, ht, hKf⟩ := hf hx + obtain ⟨Kg, u, hu, hKg⟩ := hg hx + exact ⟨Kf + Kg, t ∩ u, inter_mem ht hu, + (hKf.mono Set.inter_subset_left).mul (hKg.mono Set.inter_subset_right)⟩ + +@[to_additive] +lemma LocallyLipschitz.mul (hf : LocallyLipschitz f) (hg : LocallyLipschitz g) : + LocallyLipschitz fun x ↦ f x * g x := by + simpa [← locallyLipschitzOn_univ] using hf.locallyLipschitzOn.mul hg.locallyLipschitzOn + +@[to_additive] +lemma LipschitzOnWith.div (hf : LipschitzOnWith Kf f s) (hg : LipschitzOnWith Kg g s) : + LipschitzOnWith (Kf + Kg) (fun x ↦ f x / g x) s := by + simpa only [div_eq_mul_inv] using hf.mul hg.inv + +@[to_additive] +theorem LipschitzWith.div (hf : LipschitzWith Kf f) (hg : LipschitzWith Kg g) : LipschitzWith (Kf + Kg) fun x => f x / g x := by - simpa only [div_eq_mul_inv] using hf.mul' hg.inv + simpa only [div_eq_mul_inv] using hf.mul hg.inv + +@[to_additive] +lemma LocallyLipschitzOn.div (hf : LocallyLipschitzOn s f) (hg : LocallyLipschitzOn s g) : + LocallyLipschitzOn s fun x ↦ f x / g x := by + simpa only [div_eq_mul_inv] using hf.mul hg.inv -end LipschitzWith +@[to_additive] +lemma LocallyLipschitz.div (hf : LocallyLipschitz f) (hg : LocallyLipschitz g) : + LocallyLipschitz fun x ↦ f x / g x := by + simpa only [div_eq_mul_inv] using hf.mul hg.inv namespace AntilipschitzWith @@ -289,7 +326,7 @@ theorem mul_lipschitzWith (hf : AntilipschitzWith Kf f) (hg : LipschitzWith Kg g letI : PseudoMetricSpace α := PseudoEMetricSpace.toPseudoMetricSpace hf.edist_ne_top 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 [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`? calc @@ -312,7 +349,7 @@ end PseudoEMetricSpace -- See note [lower instance priority] @[to_additive] instance (priority := 100) SeminormedCommGroup.to_lipschitzMul : LipschitzMul E := - ⟨⟨1 + 1, LipschitzWith.prod_fst.mul' LipschitzWith.prod_snd⟩⟩ + ⟨⟨1 + 1, LipschitzWith.prod_fst.mul LipschitzWith.prod_snd⟩⟩ -- See note [lower instance priority] /-- A seminormed group is a uniform group, i.e., multiplication and division are uniformly @@ -328,6 +365,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) : @@ -342,4 +402,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 d43a285b86665..144ad83e536db 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 @@ -72,7 +72,7 @@ theorem coe_equiv_lpPiLp_symm (f : PiLp p E) : (Equiv.lpPiLp.symm f : ∀ i, E i def AddEquiv.lpPiLp : lp E p ≃+ PiLp p E := { Equiv.lpPiLp with map_add' := fun _f _g ↦ rfl } -theorem coe_addEquiv_lpPiLp (f : lp E p) : AddEquiv.lpPiLp f = ⇑f := +theorem coe_addEquiv_lpPiLp (f : lp E p) : AddEquiv.lpPiLp f = ⇑f := rfl theorem coe_addEquiv_lpPiLp_symm (f : PiLp p E) : diff --git a/Mathlib/Analysis/Normed/Lp/PiLp.lean b/Mathlib/Analysis/Normed/Lp/PiLp.lean index a1f0fe08603c7..decc915289980 100644 --- a/Mathlib/Analysis/Normed/Lp/PiLp.lean +++ b/Mathlib/Analysis/Normed/Lp/PiLp.lean @@ -342,11 +342,8 @@ abbrev pseudoMetricAux : PseudoMetricSpace (PiLp p α) := rcases p.dichotomy with (rfl | h) · exact iSup_edist_ne_top_aux f g · rw [edist_eq_sum (zero_lt_one.trans_le h)] - exact - ENNReal.rpow_ne_top_of_nonneg (one_div_nonneg.2 (zero_le_one.trans h)) - (ne_of_lt <| - ENNReal.sum_lt_top fun i hi => - ENNReal.rpow_ne_top_of_nonneg (zero_le_one.trans h) (edist_ne_top _ _))) + exact ENNReal.rpow_ne_top_of_nonneg (by positivity) <| ENNReal.sum_ne_top.2 fun _ _ ↦ + ENNReal.rpow_ne_top_of_nonneg (by positivity) (edist_ne_top _ _)) fun f g => by rcases p.dichotomy with (rfl | h) · rw [edist_eq_iSup, dist_eq_iSup] @@ -357,7 +354,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 _ _ ≤ _ @@ -416,8 +413,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 @@ -643,7 +640,7 @@ variable (p 𝕜) variable (E : Type*) [SeminormedAddCommGroup E] [Module 𝕜 E] /-- An equivalence of finite domains induces a linearly isometric equivalence of finitely supported -functions-/ +functions -/ def _root_.LinearIsometryEquiv.piLpCongrLeft (e : ι ≃ ι') : (PiLp p fun _ : ι => E) ≃ₗᵢ[𝕜] PiLp p fun _ : ι' => E where toLinearEquiv := LinearEquiv.piCongrLeft' 𝕜 (fun _ : ι => E) e @@ -666,13 +663,8 @@ theorem _root_.LinearIsometryEquiv.piLpCongrLeft_apply (e : ι ≃ ι') (v : PiL theorem _root_.LinearIsometryEquiv.piLpCongrLeft_symm (e : ι ≃ ι') : (LinearIsometryEquiv.piLpCongrLeft p 𝕜 E e).symm = LinearIsometryEquiv.piLpCongrLeft p 𝕜 E e.symm := - LinearIsometryEquiv.ext fun z => by -- Porting note: was `rfl` - simp only [LinearIsometryEquiv.piLpCongrLeft, LinearIsometryEquiv.symm, - LinearIsometryEquiv.coe_mk] - unfold PiLp WithLp - ext - simp only [LinearEquiv.piCongrLeft'_symm_apply, eq_rec_constant, - LinearEquiv.piCongrLeft'_apply, Equiv.symm_symm_apply] + LinearIsometryEquiv.ext fun z ↦ -- Porting note: was `rfl` + congr_arg (Equiv.toFun · z) (Equiv.piCongrLeft'_symm _ _) @[simp high] theorem _root_.LinearIsometryEquiv.piLpCongrLeft_single [DecidableEq ι] [DecidableEq ι'] @@ -944,7 +936,7 @@ nonrec theorem basis_toMatrix_basisFun_mul [Fintype ι] Matrix.of fun i j => b.repr ((WithLp.equiv _ _).symm (Aᵀ j)) i := by have := basis_toMatrix_basisFun_mul (b.map (WithLp.linearEquiv _ 𝕜 _)) A simp_rw [← PiLp.basisFun_map p, Basis.map_repr, LinearEquiv.trans_apply, - WithLp.linearEquiv_symm_apply, Basis.toMatrix_map, Function.comp, Basis.map_apply, + WithLp.linearEquiv_symm_apply, Basis.toMatrix_map, Function.comp_def, Basis.map_apply, LinearEquiv.symm_apply_apply] at this exact this diff --git a/Mathlib/Analysis/Normed/Lp/ProdLp.lean b/Mathlib/Analysis/Normed/Lp/ProdLp.lean index 6d23a952e2391..23d86ced09013 100644 --- a/Mathlib/Analysis/Normed/Lp/ProdLp.lean +++ b/Mathlib/Analysis/Normed/Lp/ProdLp.lean @@ -325,7 +325,7 @@ def prodPseudoEMetricAux [PseudoEMetricSpace α] [PseudoEMetricSpace β] : (if · = 0 then edist f.fst g.fst else edist f.snd g.snd) (if · = 0 then edist g.fst h.fst else edist g.snd h.snd) hp simp only [Finset.mem_singleton, not_false_eq_true, Finset.sum_insert, - Finset.sum_singleton] at this + Finset.sum_singleton, reduceCtorEq] at this exact this attribute [local instance] WithLp.prodPseudoEMetricAux @@ -420,12 +420,12 @@ theorem prod_antilipschitzWith_equiv_aux [PseudoEMetricSpace α] [PseudoEMetricS gcongr <;> simp [edist] _ = (2 ^ (1 / p.toReal) : ℝ≥0) * edist (WithLp.equiv p _ x) (WithLp.equiv p _ y) := by simp only [← two_mul, ENNReal.mul_rpow_of_nonneg _ _ nonneg, ← ENNReal.rpow_mul, cancel, - ENNReal.rpow_one, ← ENNReal.coe_rpow_of_nonneg _ nonneg, coe_ofNat] + ENNReal.rpow_one, ENNReal.coe_rpow_of_nonneg _ nonneg, coe_ofNat] 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/WithLp.lean b/Mathlib/Analysis/Normed/Lp/WithLp.lean index b636322d0d7e8..d921359dcb5a5 100644 --- a/Mathlib/Analysis/Normed/Lp/WithLp.lean +++ b/Mathlib/Analysis/Normed/Lp/WithLp.lean @@ -46,7 +46,7 @@ instance, on `Prod` and finite `Pi` types). -/ @[nolint unusedArguments] def WithLp (_p : ℝ≥0∞) (V : Type uV) : Type uV := V -variable (p : ℝ≥0∞) (K : Type uK) (K' : Type uK') (V : Type uV) +variable (p : ℝ≥0∞) (K : Type uK) (K' : Type uK') (V : Type uV) namespace WithLp diff --git a/Mathlib/Analysis/Normed/Lp/lpSpace.lean b/Mathlib/Analysis/Normed/Lp/lpSpace.lean index 23bb44f6901d5..dfe8bef80fdec 100644 --- a/Mathlib/Analysis/Normed/Lp/lpSpace.lean +++ b/Mathlib/Analysis/Normed/Lp/lpSpace.lean @@ -595,7 +595,7 @@ theorem norm_const_smul_le (hp : p ≠ 0) (c : 𝕜) (f : lp E p) : ‖c • f · simp [lp.eq_zero' f] have hcf := lp.isLUB_norm (c • f) have hfc := (lp.isLUB_norm f).mul_left (norm_nonneg c) - simp_rw [← Set.range_comp, Function.comp] at hfc + simp_rw [← Set.range_comp, Function.comp_def] at hfc -- TODO: some `IsLUB` API should make it a one-liner from here. refine hcf.right ?_ have := hfc.left @@ -1066,9 +1066,9 @@ theorem memℓp_of_tendsto {F : ι → lp E p} (hF : Bornology.IsBounded (Set.ra · apply memℓp_infty use C rintro _ ⟨a, rfl⟩ - exact norm_apply_le_of_tendsto (eventually_of_forall hCF) hf a + exact norm_apply_le_of_tendsto (Eventually.of_forall hCF) hf a · apply memℓp_gen' - exact sum_rpow_le_of_tendsto hp.ne (eventually_of_forall hCF) hf + exact sum_rpow_le_of_tendsto hp.ne (Eventually.of_forall hCF) hf /-- If a sequence is Cauchy in the `lp E p` topology and pointwise convergent to an element `f` of `lp E p`, then it converges to `f` in the `lp E p` topology. -/ diff --git a/Mathlib/Analysis/Normed/Module/Basic.lean b/Mathlib/Analysis/Normed/Module/Basic.lean index 4541f328011b9..d1bb26f18316d 100644 --- a/Mathlib/Analysis/Normed/Module/Basic.lean +++ b/Mathlib/Analysis/Normed/Module/Basic.lean @@ -8,7 +8,7 @@ import Mathlib.Algebra.Algebra.Prod import Mathlib.Algebra.Algebra.Rat import Mathlib.Algebra.Algebra.RestrictScalars import Mathlib.Algebra.Module.Rat -import Mathlib.Analysis.Normed.Field.Basic +import Mathlib.Analysis.Normed.Field.Lemmas import Mathlib.Analysis.Normed.MulAction /-! @@ -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 => @@ -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 @@ -455,8 +462,10 @@ Please consider using `IsScalarTower` and/or `RestrictScalars 𝕜 𝕜' E` inst This definition allows the `RestrictScalars.normedSpace` instance to be put directly on `E` rather on `RestrictScalars 𝕜 𝕜' E`. This would be a very bad instance; both because `𝕜'` cannot be inferred, and because it is likely to create instance diamonds. + +See Note [reducible non-instances]. -/ -def NormedSpace.restrictScalars : NormedSpace 𝕜 E := +abbrev NormedSpace.restrictScalars : NormedSpace 𝕜 E := RestrictScalars.normedSpace _ 𝕜' E end NormedSpace @@ -488,8 +497,10 @@ Please consider using `IsScalarTower` and/or `RestrictScalars 𝕜 𝕜' E` inst This definition allows the `RestrictScalars.normedAlgebra` instance to be put directly on `E` rather on `RestrictScalars 𝕜 𝕜' E`. This would be a very bad instance; both because `𝕜'` cannot be inferred, and because it is likely to create instance diamonds. + +See Note [reducible non-instances]. -/ -def NormedAlgebra.restrictScalars : NormedAlgebra 𝕜 E := +abbrev NormedAlgebra.restrictScalars : NormedAlgebra 𝕜 E := RestrictScalars.normedAlgebra _ 𝕜' _ end NormedAlgebra diff --git a/Mathlib/Analysis/Normed/Module/Completion.lean b/Mathlib/Analysis/Normed/Module/Completion.lean index 4e50f3b1130b0..f0a8fdeed667d 100644 --- a/Mathlib/Analysis/Normed/Module/Completion.lean +++ b/Mathlib/Analysis/Normed/Module/Completion.lean @@ -6,6 +6,7 @@ Authors: Yury Kudryashov import Mathlib.Analysis.Normed.Group.Completion import Mathlib.Analysis.NormedSpace.OperatorNorm.NormedSpace import Mathlib.Topology.Algebra.UniformRing +import Mathlib.Topology.Algebra.UniformField /-! # Normed space structure on the completion of a normed space @@ -26,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 := @@ -65,40 +62,36 @@ 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 + __ : 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 de23a0957c44e..f8115711046c5 100644 --- a/Mathlib/Analysis/Normed/Module/Dual.lean +++ b/Mathlib/Analysis/Normed/Module/Dual.lean @@ -6,6 +6,7 @@ Authors: Heather Macbeth import Mathlib.Analysis.NormedSpace.HahnBanach.Extension import Mathlib.Analysis.NormedSpace.RCLike import Mathlib.Analysis.LocallyConvex.Polar +import Mathlib.Data.Set.Finite /-! # The topological dual of a normed space @@ -28,9 +29,13 @@ theory for `SeminormedAddCommGroup` and we specialize to `NormedAddCommGroup` wh * `polar 𝕜 s` is the subset of `Dual 𝕜 E` consisting of those functionals `x'` for which `‖x' z‖ ≤ 1` for every `z ∈ s`. +## References + +* [Conway, John B., A course in functional analysis][conway1990] + ## Tags -dual +dual, polar -/ @@ -154,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 @@ -200,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 (𝕜) @@ -224,6 +236,23 @@ theorem polar_closedBall {𝕜 E : Type*} [RCLike 𝕜] [NormedAddCommGroup E] [ refine ContinuousLinearMap.opNorm_le_of_ball hr (inv_nonneg.mpr hr.le) fun z _ => ?_ simpa only [one_div] using LinearMap.bound_of_ball_bound' hr 1 x'.toLinearMap h z +theorem polar_ball {𝕜 E : Type*} [RCLike 𝕜] [NormedAddCommGroup E] [NormedSpace 𝕜 E] {r : ℝ} + (hr : 0 < r) : polar 𝕜 (ball (0 : E) r) = closedBall (0 : Dual 𝕜 E) r⁻¹ := by + apply le_antisymm + · intro x hx + rw [mem_closedBall_zero_iff] + apply le_of_forall_le_of_dense + 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_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_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 + /-- Given a neighborhood `s` of the origin in a normed space `E`, the dual norms of all elements of the polar `polar 𝕜 s` are bounded by a constant. -/ theorem isBounded_polar_of_mem_nhds_zero {s : Set E} (s_nhd : s ∈ 𝓝 (0 : E)) : @@ -234,6 +263,27 @@ 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] + +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 + conv_rhs => rw [← inv_inv r] + rw [← polar_closedBall (inv_pos_of_pos hr), polar, + (dualPairing 𝕜 E).flip.sInter_polar_finite_subset_eq_polar (closedBall (0 : E) r⁻¹)] + end PolarSets end NormedSpace diff --git a/Mathlib/Analysis/Normed/Module/FiniteDimension.lean b/Mathlib/Analysis/Normed/Module/FiniteDimension.lean index 6fbb936e9f60b..4735888f210dd 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⟩ := @@ -508,7 +508,7 @@ lemma ProperSpace.of_locallyCompactSpace (𝕜 : Type*) [NontriviallyNormedField simpa [_root_.smul_closedBall' this] using hr.smul (c ^ n) 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) + exact .of_seq_closedBall hTop (Eventually.of_forall hC) @[deprecated (since := "2024-01-31")] alias properSpace_of_locallyCompactSpace := ProperSpace.of_locallyCompactSpace @@ -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/WeakDual.lean b/Mathlib/Analysis/Normed/Module/WeakDual.lean index 71dc2da624481..9eceea12586f7 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 diff --git a/Mathlib/Analysis/Normed/MulAction.lean b/Mathlib/Analysis/Normed/MulAction.lean index 618fab80dff3f..2c9c706fdb6c1 100644 --- a/Mathlib/Analysis/Normed/MulAction.lean +++ b/Mathlib/Analysis/Normed/MulAction.lean @@ -3,8 +3,9 @@ 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.Topology.MetricSpace.Algebra 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 26a210ee9dcea..8561d451ba771 100644 --- a/Mathlib/Analysis/Normed/Operator/Banach.lean +++ b/Mathlib/Analysis/Normed/Operator/Banach.lean @@ -177,9 +177,10 @@ theorem exists_preimage_norm_le (surj : Surjective f) : refine ⟨2 * C + 1, by linarith, fun y => ?_⟩ have hnle : ∀ n : ℕ, ‖h^[n] y‖ ≤ (1 / 2) ^ n * ‖y‖ := by intro n - induction' n with n IH - · simp only [one_div, Nat.zero_eq, one_mul, iterate_zero_apply, pow_zero, le_rfl] - · rw [iterate_succ'] + induction n with + | zero => simp only [one_div, one_mul, iterate_zero_apply, pow_zero, le_rfl] + | succ n IH => + rw [iterate_succ'] apply le_trans (hle _) _ rw [pow_succ', mul_assoc] gcongr @@ -205,9 +206,9 @@ theorem exists_preimage_norm_le (surj : Surjective f) : _ = (2 * C + 1) * ‖y‖ := by ring have fsumeq : ∀ n : ℕ, f (∑ i ∈ Finset.range n, u i) = y - h^[n] y := by intro n - induction' n with n IH - · simp [f.map_zero] - · rw [sum_range_succ, f.map_add, IH, iterate_succ_apply', sub_add] + induction n with + | zero => simp [f.map_zero] + | succ n IH => rw [sum_range_succ, f.map_add, IH, iterate_succ_apply', sub_add] have : Tendsto (fun n => ∑ i ∈ Finset.range n, u i) atTop (𝓝 x) := su.hasSum.tendsto_sum_nat have L₁ : Tendsto (fun n => f (∑ i ∈ Finset.range n, u i)) atTop (𝓝 (f x)) := (f.continuous.tendsto _).comp this @@ -530,7 +531,7 @@ section BijectivityCriteria namespace ContinuousLinearMap -variable {σ : 𝕜 →+* 𝕜'} {σ' : 𝕜' →+* 𝕜} [RingHomInvPair σ σ'] {f : E →SL[σ] F} +variable {σ : 𝕜 →+* 𝕜'} {σ' : 𝕜' →+* 𝕜} [RingHomInvPair σ σ'] {f : E →SL[σ] F} 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 b43fd4cefc393..4d0fea4e147c4 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‖ @@ -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 @@ -315,9 +315,9 @@ def IsBoundedBilinearMap.toContinuousLinearMap (hf : IsBoundedBilinearMap 𝕜 f protected theorem IsBoundedBilinearMap.isBigO (h : IsBoundedBilinearMap 𝕜 f) : f =O[⊤] fun p : E × F => ‖p.1‖ * ‖p.2‖ := - let ⟨C, Cpos, hC⟩ := h.bound - Asymptotics.IsBigO.of_bound _ <| - Filter.eventually_of_forall fun ⟨x, y⟩ => by simpa [mul_assoc] using hC x y + let ⟨C, _, hC⟩ := h.bound + Asymptotics.IsBigO.of_bound C <| + Filter.Eventually.of_forall fun ⟨x, y⟩ => by simpa [mul_assoc] using hC x y theorem IsBoundedBilinearMap.isBigO_comp {α : Type*} (H : IsBoundedBilinearMap 𝕜 f) {g : α → E} {h : α → F} {l : Filter α} : (fun x => f (g x, h x)) =O[l] fun x => ‖g x‖ * ‖h x‖ := @@ -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/ContinuousLinearMap.lean b/Mathlib/Analysis/Normed/Operator/ContinuousLinearMap.lean index da7b7a93c50c0..64c5ba0eb60b5 100644 --- a/Mathlib/Analysis/Normed/Operator/ContinuousLinearMap.lean +++ b/Mathlib/Analysis/Normed/Operator/ContinuousLinearMap.lean @@ -3,8 +3,9 @@ Copyright (c) 2019 Jan-David Salchow. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jan-David Salchow, Sébastien Gouëzel, Jean Lo -/ -import Mathlib.Topology.Algebra.Module.Basic +import Mathlib.Analysis.Normed.Group.Uniform import Mathlib.Analysis.Normed.MulAction +import Mathlib.Topology.Algebra.Module.Basic /-! # Constructions of continuous linear maps between (semi-)normed spaces @@ -152,9 +153,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 dcba3cf3c238e..92b76035981f0 100644 --- a/Mathlib/Analysis/Normed/Operator/LinearIsometry.lean +++ b/Mathlib/Analysis/Normed/Operator/LinearIsometry.lean @@ -205,10 +205,12 @@ theorem nnnorm_map (x : E) : ‖f x‖₊ = ‖x‖₊ := protected theorem isometry : Isometry f := AddMonoidHomClass.isometry_of_norm f.toLinearMap (norm_map _) +protected lemma embedding (f : F →ₛₗᵢ[σ₁₂] E₂) : Embedding f := f.isometry.embedding + -- 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} : @@ -640,8 +642,7 @@ theorem map_eq_zero_iff {x : E} : e x = 0 ↔ x = 0 := e.toLinearEquiv.map_eq_zero_iff @[simp] -theorem symm_symm : e.symm.symm = e := - ext fun _ => rfl +theorem symm_symm : e.symm.symm = e := rfl @[simp] theorem toLinearEquiv_symm : e.toLinearEquiv.symm = e.symm.toLinearEquiv := diff --git a/Mathlib/Analysis/Normed/Operator/WeakOperatorTopology.lean b/Mathlib/Analysis/Normed/Operator/WeakOperatorTopology.lean index b7a5ea7136815..45dfa1892cbcc 100644 --- a/Mathlib/Analysis/Normed/Operator/WeakOperatorTopology.lean +++ b/Mathlib/Analysis/Normed/Operator/WeakOperatorTopology.lean @@ -85,7 +85,7 @@ variable (𝕜) (E) (F) unseal ContinuousLinearMapWOT in /-- The linear equivalence that sends a continuous linear map to the type copy endowed with the -weak operator topology. -/ +weak operator topology. -/ def _root_.ContinuousLinearMap.toWOT : (E →L[𝕜] F) ≃ₗ[𝕜] (E →WOT[𝕜] F) := LinearEquiv.refl 𝕜 _ variable {𝕜} {E} {F} @@ -211,7 +211,7 @@ end Topology section Seminorms /-- The family of seminorms that induce the weak operator topology, namely `‖y (A x)‖` for -all `x` and `y`. -/ +all `x` and `y`. -/ def seminorm (x : E) (y : F⋆) : Seminorm 𝕜 (E →WOT[𝕜] F) where toFun A := ‖y (A x)‖ map_zero' := by simp @@ -221,7 +221,7 @@ def seminorm (x : E) (y : F⋆) : Seminorm 𝕜 (E →WOT[𝕜] F) where variable (𝕜) (E) (F) in /-- The family of seminorms that induce the weak operator topology, namely `‖y (A x)‖` for -all `x` and `y`. -/ +all `x` and `y`. -/ def seminormFamily : SeminormFamily 𝕜 (E →WOT[𝕜] F) (E × F⋆) := fun ⟨x, y⟩ => seminorm x y diff --git a/Mathlib/Analysis/Normed/Order/Basic.lean b/Mathlib/Analysis/Normed/Order/Basic.lean index d78be19a7ae1f..e3f1e8a5b1e77 100644 --- a/Mathlib/Analysis/Normed/Order/Basic.lean +++ b/Mathlib/Analysis/Normed/Order/Basic.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Anatole Dedecker, Yaël Dillies -/ import Mathlib.Algebra.Order.Group.TypeTags -import Mathlib.Analysis.Normed.Field.Basic +import Mathlib.Analysis.Normed.Field.Lemmas /-! # Ordered normed spaces diff --git a/Mathlib/Analysis/Normed/Order/UpperLower.lean b/Mathlib/Analysis/Normed/Order/UpperLower.lean index 824536ea40231..b30f015561105 100644 --- a/Mathlib/Analysis/Normed/Order/UpperLower.lean +++ b/Mathlib/Analysis/Normed/Order/UpperLower.lean @@ -142,8 +142,8 @@ lemma dist_anti_right_pi : AntitoneOn (dist x) (Iic x) := by lemma dist_le_dist_of_le_pi (ha : a₂ ≤ a₁) (h₁ : a₁ ≤ b₁) (hb : b₁ ≤ b₂) : dist a₁ b₁ ≤ dist a₂ b₂ := - (dist_mono_right_pi h₁ (h₁.trans hb) hb).trans $ - dist_anti_left_pi (ha.trans $ h₁.trans hb) (h₁.trans hb) ha + (dist_mono_right_pi h₁ (h₁.trans hb) hb).trans <| + dist_anti_left_pi (ha.trans <| h₁.trans hb) (h₁.trans hb) ha theorem IsUpperSet.exists_subset_ball (hs : IsUpperSet s) (hx : x ∈ closure s) (hδ : 0 < δ) : ∃ y, closedBall y (δ / 4) ⊆ closedBall x δ ∧ closedBall y (δ / 4) ⊆ interior s := by @@ -213,7 +213,7 @@ protected lemma IsClosed.lowerClosure_pi (hs : IsClosed s) (hs' : BddAbove s) : haveI : BoundedGENhdsClass ℝ := by infer_instance obtain ⟨a, ha⟩ := hx.bddBelow_range obtain ⟨b, hb, φ, hφ, hbf⟩ := tendsto_subseq_of_bounded (hs'.isBounded_inter bddBelow_Ici) fun n ↦ - ⟨hg n, (ha $ mem_range_self _).trans $ hfg _⟩ + ⟨hg n, (ha <| mem_range_self _).trans <| hfg _⟩ exact ⟨b, closure_minimal inter_subset_left hs hb, le_of_tendsto_of_tendsto' (hx.comp hφ.tendsto_atTop) hbf fun _ ↦ hfg _⟩ @@ -225,14 +225,14 @@ protected lemma IsClopen.lowerClosure_pi (hs : IsClopen s) (hs' : BddAbove s) : lemma closure_upperClosure_comm_pi (hs : BddBelow s) : closure (upperClosure s : Set (ι → ℝ)) = upperClosure (closure s) := - (closure_minimal (upperClosure_anti subset_closure) $ - isClosed_closure.upperClosure_pi hs.closure).antisymm $ + (closure_minimal (upperClosure_anti subset_closure) <| + isClosed_closure.upperClosure_pi hs.closure).antisymm <| upperClosure_min (closure_mono subset_upperClosure) (upperClosure s).upper.closure lemma closure_lowerClosure_comm_pi (hs : BddAbove s) : closure (lowerClosure s : Set (ι → ℝ)) = lowerClosure (closure s) := - (closure_minimal (lowerClosure_mono subset_closure) $ - isClosed_closure.lowerClosure_pi hs.closure).antisymm $ + (closure_minimal (lowerClosure_mono subset_closure) <| + isClosed_closure.lowerClosure_pi hs.closure).antisymm <| lowerClosure_min (closure_mono subset_lowerClosure) (lowerClosure s).lower.closure end Finite 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 9d88d4bb64e68..650ace74daac1 100644 --- a/Mathlib/Analysis/Normed/Ring/Seminorm.lean +++ b/Mathlib/Analysis/Normed/Ring/Seminorm.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 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, Yaël Dillies -/ -import Mathlib.Analysis.Normed.Field.Basic +import Mathlib.Analysis.Normed.Field.Lemmas import Mathlib.Analysis.SpecialFunctions.Pow.Real /-! @@ -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 @@ -298,7 +318,7 @@ instance : Inhabited (MulRingNorm R) := variable {R : Type*} [Ring R] /-- Two multiplicative ring norms `f, g` on `R` are equivalent if there exists a positive constant - `c` such that for all `x ∈ R`, `(f x)^c = g x`. -/ + `c` such that for all `x ∈ R`, `(f x)^c = g x`. -/ def equiv (f : MulRingNorm R) (g : MulRingNorm R) := ∃ c : ℝ, 0 < c ∧ (fun x => (f x) ^ c) = g @@ -368,3 +388,36 @@ 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 diff --git a/Mathlib/Analysis/Normed/Ring/SeminormFromBounded.lean b/Mathlib/Analysis/Normed/Ring/SeminormFromBounded.lean index 2797ff18c5b52..a98f45db8cc03 100644 --- a/Mathlib/Analysis/Normed/Ring/SeminormFromBounded.lean +++ b/Mathlib/Analysis/Normed/Ring/SeminormFromBounded.lean @@ -97,7 +97,7 @@ theorem seminormFromBounded_aux (f_nonneg : 0 ≤ f) replace f_nonneg : 0 ≤ f 1 := f_nonneg 1 rcases f_nonneg.eq_or_gt with h1 | h1 · linarith [show (1 : ℝ) ≤ 0 by simpa [h1] using f_mul] - · rw [← div_le_iff h1] at f_mul + · rw [← div_le_iff₀ h1] at f_mul linarith [one_div_pos.mpr h1] positivity @@ -110,7 +110,7 @@ theorem seminormFromBounded_bddAbove_range (f_nonneg : 0 ≤ f) rintro r ⟨y, rfl⟩ rcases (f_nonneg y).eq_or_gt with hy0 | hy0 · simpa [hy0] using seminormFromBounded_aux f_nonneg f_mul x - · simpa [div_le_iff hy0] using f_mul x y + · simpa [div_le_iff₀ hy0] using f_mul x y /-- If `f : R → ℝ` is a nonnegative, multiplicatively bounded function, then for every `x : R`, `seminormFromBounded' f x` is bounded above by some multiple of `f x`. -/ @@ -120,7 +120,7 @@ theorem seminormFromBounded_le (f_nonneg : 0 ≤ f) refine ciSup_le (fun y ↦ ?_) rcases (f_nonneg y).eq_or_gt with hy | hy · simpa [hy] using seminormFromBounded_aux f_nonneg f_mul x - · rw [div_le_iff hy] + · rw [div_le_iff₀ hy] apply f_mul /-- If `f : R → ℝ` is a nonnegative, multiplicatively bounded function, then for every `x : R`, @@ -133,7 +133,7 @@ theorem seminormFromBounded_ge (f_nonneg : 0 ≤ f) rw [mul_one, h1, mul_zero] at f_mul have hx0 : f x = 0 := f_mul.antisymm (f_nonneg _) rw [hx0, h1, zero_mul] - · rw [mul_comm, ← div_le_iff (lt_of_le_of_ne' (f_nonneg _) h1)] + · rw [mul_comm, ← div_le_iff₀ (lt_of_le_of_ne' (f_nonneg _) h1)] conv_lhs => rw [← mul_one x] exact le_ciSup (seminormFromBounded_bddAbove_range f_nonneg f_mul x) (1 : R) @@ -153,11 +153,11 @@ theorem seminormFromBounded_eq_zero_iff (f_nonneg : 0 ≤ f) refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ · have hf := seminormFromBounded_ge f_nonneg f_mul x rw [h, mul_zero] at hf - exact hf.antisymm (f_nonneg _) + exact hf.antisymm (f_nonneg _) · have hf : seminormFromBounded' f x ≤ c * f x := seminormFromBounded_le f_nonneg f_mul x rw [h, mul_zero] at hf - exact hf.antisymm (seminormFromBounded_nonneg f_nonneg f_mul x) + exact hf.antisymm (seminormFromBounded_nonneg f_nonneg f_mul x) /-- If `f` is invariant under negation of `x`, then so is `seminormFromBounded'`.-/ theorem seminormFromBounded_neg (f_neg : ∀ x : R, f (-x) = f x) (x : R) : @@ -180,9 +180,9 @@ theorem seminormFromBounded_mul (f_nonneg : 0 ≤ f) exact mul_nonneg (seminormFromBounded_nonneg f_nonneg f_mul x) (seminormFromBounded_nonneg f_nonneg f_mul y) · intro z - rw [← div_le_iff (lt_of_le_of_ne' (seminormFromBounded_nonneg f_nonneg f_mul _) hy)] + rw [← div_le_iff₀ (lt_of_le_of_ne' (seminormFromBounded_nonneg f_nonneg f_mul _) hy)] apply le_ciSup_of_le (seminormFromBounded_bddAbove_range f_nonneg f_mul x) z - rw [div_le_iff (lt_of_le_of_ne' (seminormFromBounded_nonneg f_nonneg f_mul _) hy), + rw [div_le_iff₀ (lt_of_le_of_ne' (seminormFromBounded_nonneg f_nonneg f_mul _) hy), div_mul_eq_mul_div] by_cases hz : f z = 0 · have hxyz : f (z * (x * y)) = 0 := map_mul_zero_of_map_zero f_nonneg f_mul hz _ @@ -193,7 +193,7 @@ theorem seminormFromBounded_mul (f_nonneg : 0 ≤ f) by_cases hxz : f (x * z) = 0 · rw [mul_comm x y, mul_assoc, mul_comm y, map_mul_zero_of_map_zero f_nonneg f_mul hxz y] exact mul_nonneg (seminormFromBounded_nonneg f_nonneg f_mul y) (f_nonneg _) - · rw [← div_le_iff (lt_of_le_of_ne' (f_nonneg _) hxz)] + · rw [← div_le_iff₀ (lt_of_le_of_ne' (f_nonneg _) hxz)] apply le_ciSup_of_le (seminormFromBounded_bddAbove_range f_nonneg f_mul y) (x * z) rw [div_le_div_right (lt_of_le_of_ne' (f_nonneg _) hxz), mul_comm x y, mul_assoc] @@ -305,7 +305,7 @@ theorem seminormFromBounded_of_mul_le (f_nonneg : 0 ≤ f) {x : R} · refine ciSup_le (fun y ↦ ?_) by_cases hy : f y = 0 · rw [hy, div_zero]; exact f_nonneg _ - · rw [div_le_iff (lt_of_le_of_ne' (f_nonneg _) hy)]; exact hx _ + · rw [div_le_iff₀ (lt_of_le_of_ne' (f_nonneg _) hy)]; exact hx _ · have h_bdd : BddAbove (Set.range fun y ↦ f (x * y) / f y) := by use f x rintro r ⟨y, rfl⟩ @@ -313,7 +313,7 @@ theorem seminormFromBounded_of_mul_le (f_nonneg : 0 ≤ f) {x : R} · simp only [hy0, div_zero] exact f_nonneg _ · rw [← mul_one (f x), ← div_self hy0, ← mul_div_assoc, - div_le_iff (lt_of_le_of_ne' (f_nonneg _) hy0), mul_div_assoc, div_self hy0, mul_one] + div_le_iff₀ (lt_of_le_of_ne' (f_nonneg _) hy0), mul_div_assoc, div_self hy0, mul_one] exact hx y convert le_ciSup h_bdd (1 : R) by_cases h0 : f x = 0 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 c46b35e61a4d4..86883d4c5d017 100644 --- a/Mathlib/Analysis/Normed/Ring/Units.lean +++ b/Mathlib/Analysis/Normed/Ring/Units.lean @@ -14,12 +14,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 +31,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 +51,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 +74,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 +107,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 +142,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 @@ -197,7 +190,7 @@ theorem inverse_continuousAt (x : Rˣ) : ContinuousAt inverse (x : R) := by refine tendsto_zero_iff_norm_tendsto_zero.mpr ?_ exact tendsto_iff_norm_sub_tendsto_zero.mp tendsto_id rw [ContinuousAt, tendsto_iff_norm_sub_tendsto_zero, inverse_unit] - simpa [(· ∘ ·)] using h_is_o.norm_left.tendsto_div_nhds_zero.comp h_lim + simpa [Function.comp_def] using h_is_o.norm_left.tendsto_div_nhds_zero.comp h_lim end NormedRing @@ -205,15 +198,15 @@ 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. -/ +/-- In a normed ring with summable geometric series, the coercion from `Rˣ` (equipped with the +induced topology from the embedding in `R × R`) to `R` is an open embedding. -/ theorem openEmbedding_val : OpenEmbedding (val : Rˣ → R) where toEmbedding := embedding_val_mk' (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. -/ +/-- 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 @@ -227,16 +220,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/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 fbbb8c726b3ad..48c17b7994ce9 100644 --- a/Mathlib/Analysis/NormedSpace/ENorm.lean +++ b/Mathlib/Analysis/NormedSpace/ENorm.lean @@ -182,7 +182,7 @@ def finiteSubspace : Subspace 𝕜 V where smul_mem' c x (hx : _ < _) := calc e (c • x) = ‖c‖₊ * e x := e.map_smul c x - _ < ⊤ := ENNReal.mul_lt_top ENNReal.coe_ne_top hx.ne + _ < ⊤ := ENNReal.mul_lt_top ENNReal.coe_lt_top hx /-- Metric space structure on `e.finiteSubspace`. We use `EMetricSpace.toMetricSpace` to ensure that this definition agrees with `e.emetricSpace`. -/ diff --git a/Mathlib/Analysis/NormedSpace/FunctionSeries.lean b/Mathlib/Analysis/NormedSpace/FunctionSeries.lean index b101059caa463..d4783a6874149 100644 --- a/Mathlib/Analysis/NormedSpace/FunctionSeries.lean +++ b/Mathlib/Analysis/NormedSpace/FunctionSeries.lean @@ -65,7 +65,7 @@ theorem continuousOn_tsum [TopologicalSpace β] {f : α → β → F} {s : Set (hf : ∀ i, ContinuousOn (f i) s) (hu : Summable u) (hfu : ∀ n x, x ∈ s → ‖f n x‖ ≤ u n) : ContinuousOn (fun x => ∑' n, f n x) s := by classical - refine (tendstoUniformlyOn_tsum hu hfu).continuousOn (eventually_of_forall ?_) + refine (tendstoUniformlyOn_tsum hu hfu).continuousOn (Eventually.of_forall ?_) intro t exact continuousOn_finset_sum _ fun i _ => hf i 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/Int.lean b/Mathlib/Analysis/NormedSpace/Int.lean index fe43e855c5bea..b08f55039887a 100644 --- a/Mathlib/Analysis/NormedSpace/Int.lean +++ b/Mathlib/Analysis/NormedSpace/Int.lean @@ -3,7 +3,7 @@ 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.Analysis.Normed.Field.Basic +import Mathlib.Analysis.Normed.Field.Lemmas /-! # The integers as normed ring diff --git a/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean b/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean index c3efa1e0e4436..4b87da345fe31 100644 --- a/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean +++ b/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean @@ -74,19 +74,48 @@ 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] : + [TopologicalSpace F] [AddCommGroup F] [TopologicalAddGroup F] [Module 𝕜 F] + +/-- Applying a multilinear map to a vector is continuous in both coordinates. -/ +theorem ContinuousMultilinearMap.continuous_eval : Continuous fun p : ContinuousMultilinearMap 𝕜 E F × ∀ i, E i => p.1 p.2 := by cases nonempty_fintype ι let _ := TopologicalAddGroup.toUniformSpace F have := comm_topologicalAddGroup_is_uniform (G := F) refine (UniformOnFun.continuousOn_eval₂ fun m ↦ ?_).comp_continuous - (embedding_toUniformOnFun.continuous.prod_map continuous_id) fun (f, x) ↦ f.cont.continuousAt + (embedding_toUniformOnFun.continuous.prodMap continuous_id) fun (f, x) ↦ f.cont.continuousAt exact ⟨ball m 1, NormedSpace.isVonNBounded_of_isBounded _ isBounded_ball, ball_mem_nhds _ one_pos⟩ +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) := + ContinuousMultilinearMap.continuous_eval.comp <| .prodMap (map_continuous f) continuous_id + +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 variable {𝕜 : Type u} {ι : Type v} {ι' : Type v'} {E : ι → Type wE} {E₁ : ι → Type wE₁} @@ -160,7 +189,7 @@ theorem exists_bound_of_continuous (hf : Continuous f) : refine ⟨_, this, ?_⟩ refine f.bound_of_shell_of_continuous hf (fun _ => ε0) (fun _ => hc) fun m hcm hm => ?_ refine (hε m ((pi_norm_lt_iff ε0).2 hm)).le.trans ?_ - rw [← div_le_iff' this, one_div, ← inv_pow, inv_div, Fintype.card, ← prod_const] + rw [← div_le_iff₀' this, one_div, ← inv_pow, inv_div, Fintype.card, ← prod_const] exact prod_le_prod (fun _ _ => div_nonneg ε0.le (norm_nonneg _)) fun i _ => hcm i /-- If `f` satisfies a boundedness property around `0`, one can deduce a bound on `f m₁ - f m₂` @@ -189,7 +218,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 @@ -340,7 +368,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 +419,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 @@ -657,17 +685,6 @@ def restrictScalarsₗᵢ : ContinuousMultilinearMap 𝕜 E G →ₗᵢ[𝕜'] C map_smul' _ _ := rfl norm_map' _ := rfl -/-- `ContinuousMultilinearMap.restrictScalars` as a `ContinuousLinearMap`. -/ -def restrictScalarsLinear : ContinuousMultilinearMap 𝕜 E G →L[𝕜'] ContinuousMultilinearMap 𝕜' E G := - (restrictScalarsₗᵢ 𝕜').toContinuousLinearMap - -variable {𝕜'} - -theorem continuous_restrictScalars : - Continuous - (restrictScalars 𝕜' : ContinuousMultilinearMap 𝕜 E G → ContinuousMultilinearMap 𝕜' E G) := - (restrictScalarsLinear 𝕜').continuous - end RestrictScalars /-- The difference `f m₁ - f m₂` is controlled in terms of `‖f‖` and `‖m₁ - m₂‖`, precise version. @@ -759,7 +776,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] @@ -775,6 +792,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 @@ -796,11 +819,11 @@ theorem nnnorm_smulRight (f : ContinuousMultilinearMap 𝕜 E 𝕜) (z : G) : rw [mul_right_comm] gcongr exact le_opNNNorm _ _ - · obtain hz | hz := eq_or_ne ‖z‖₊ 0 + · obtain hz | hz := eq_zero_or_pos ‖z‖₊ · simp [hz] - rw [← NNReal.le_div_iff hz, opNNNorm_le_iff] + rw [← le_div_iff₀ hz, opNNNorm_le_iff] intro m - rw [div_mul_eq_mul_div, NNReal.le_div_iff hz] + rw [div_mul_eq_mul_div, le_div_iff₀ hz] refine le_trans ?_ ((f.smulRight z).le_opNNNorm m) rw [smulRight_apply, nnnorm_smul] @@ -1252,7 +1275,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..433b3db5d9d54 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 f₁ f₂ => rfl + map_smul' := fun c f => 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 f₁ f₂ => rfl + map_smul' := fun c f => 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'} @@ -614,3 +603,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 cb8d792f631d6..5d787cb4490a6 100644 --- a/Mathlib/Analysis/NormedSpace/OperatorNorm/Basic.lean +++ b/Mathlib/Analysis/NormedSpace/OperatorNorm/Basic.lean @@ -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] @@ -277,7 +277,7 @@ theorem opNorm_le_of_unit_norm [NormedSpace ℝ E] [NormedSpace ℝ F] {f : E refine opNorm_le_bound' f hC fun x hx => ?_ have H₁ : ‖‖x‖⁻¹ • x‖ = 1 := by rw [norm_smul, norm_inv, norm_norm, inv_mul_cancel₀ hx] have H₂ := hf _ H₁ - rwa [map_smul, norm_smul, norm_inv, norm_norm, ← div_eq_inv_mul, _root_.div_le_iff] at H₂ + rwa [map_smul, norm_smul, norm_inv, norm_norm, ← div_eq_inv_mul, div_le_iff₀] at H₂ exact (norm_nonneg x).lt_of_ne' hx @[deprecated (since := "2024-02-02")] alias op_norm_le_of_unit_norm := opNorm_le_of_unit_norm @@ -325,7 +325,7 @@ private lemma uniformity_eq_seminorm : simpa [NormedSpace.isVonNBounded_closedBall, closedBall_mem_nhds, subset_def] using this intro f hf refine opNorm_le_of_shell (f := f) one_pos (norm_nonneg c) hc fun x hcx hx ↦ ?_ - exact (hf x hx.le).trans ((div_le_iff' <| one_pos.trans hc).1 hcx) + exact (hf x hx.le).trans ((div_le_iff₀' <| one_pos.trans hc).1 hcx) · rcases (NormedSpace.isVonNBounded_iff' _).1 hs with ⟨ε, hε⟩ rcases exists_pos_mul_lt hr ε with ⟨δ, hδ₀, hδ⟩ refine ⟨δ, hδ₀, fun f hf x hx ↦ ?_⟩ diff --git a/Mathlib/Analysis/NormedSpace/OperatorNorm/Bilinear.lean b/Mathlib/Analysis/NormedSpace/OperatorNorm/Bilinear.lean index 07c05d0a62e73..61f5199b50531 100644 --- a/Mathlib/Analysis/NormedSpace/OperatorNorm/Bilinear.lean +++ b/Mathlib/Analysis/NormedSpace/OperatorNorm/Bilinear.lean @@ -382,7 +382,7 @@ variable {𝕜₁' : Type*} {𝕜₂' : Type*} [NontriviallyNormedField 𝕜₁' [RingHomIsometric σ₂₃] [RingHomIsometric σ₁₃'] [RingHomIsometric σ₂₃'] /-- Compose a bilinear map `E →SL[σ₁₃] F →SL[σ₂₃] G` with two linear maps -`E' →SL[σ₁'] E` and `F' →SL[σ₂'] F`. -/ +`E' →SL[σ₁'] E` and `F' →SL[σ₂'] F`. -/ def bilinearComp (f : E →SL[σ₁₃] F →SL[σ₂₃] G) (gE : E' →SL[σ₁'] E) (gF : F' →SL[σ₂'] F) : E' →SL[σ₁₃'] F' →SL[σ₂₃'] G := ((f.comp gE).flip.comp gF).flip @@ -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 62d8d4d30f47c..783b55750d8fb 100644 --- a/Mathlib/Analysis/NormedSpace/OperatorNorm/Completeness.lean +++ b/Mathlib/Analysis/NormedSpace/OperatorNorm/Completeness.lean @@ -60,7 +60,7 @@ def ofTendstoOfBoundedRange {α : Type*} {l : Filter α} [l.NeBot] (f : E' → F (g : α → E' →SL[σ₁₂] F) (hf : Tendsto (fun a x => g a x) l (𝓝 f)) (hg : IsBounded (Set.range g)) : E' →SL[σ₁₂] F := ofMemClosureImageCoeBounded f hg <| mem_closure_of_tendsto hf <| - eventually_of_forall fun _ => mem_image_of_mem _ <| Set.mem_range_self _ + Eventually.of_forall fun _ => mem_image_of_mem _ <| Set.mem_range_self _ /-- If a Cauchy sequence of continuous linear map converges to a continuous linear map pointwise, then it converges to the same map in norm. This lemma is used to prove that the space of continuous @@ -181,16 +181,16 @@ 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ₗ`. -/ +complete normed space, along a uniform and dense embedding `e : E →L[𝕜] Fₗ`. -/ def extend : Fₗ →SL[σ₁₂] F := -- extension of `f` is continuous 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 +208,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 +230,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..a42244f918fa7 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 𝕜 𝕜') 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 c57a94705a314..253805834044d 100644 --- a/Mathlib/Analysis/NormedSpace/OperatorNorm/NormedSpace.lean +++ b/Mathlib/Analysis/NormedSpace/OperatorNorm/NormedSpace.lean @@ -59,7 +59,7 @@ theorem bound_of_ball_bound {r : ℝ} (r_pos : 0 < r) (c : ℝ) (f : E →ₗ[ _ ≤ c * (‖x‖ * ‖k‖ / r) := le_mul_of_one_le_right ?_ ?_ _ = _ := by ring · exact le_trans (norm_nonneg _) (h 0 (by simp [r_pos])) - · rw [div_le_iff (zero_lt_one.trans hk)] at hko + · rw [div_le_iff₀ (zero_lt_one.trans hk)] at hko exact (one_le_div r_pos).mpr hko theorem antilipschitz_of_comap_nhds_le [h : RingHomIsometric σ₁₂] (f : E →ₛₗ[σ₁₂] F) @@ -165,6 +165,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 @@ -200,58 +209,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 @@ -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 a31afd3501b4f..299585582989c 100644 --- a/Mathlib/Analysis/NormedSpace/PiTensorProduct/InjectiveSeminorm.lean +++ b/Mathlib/Analysis/NormedSpace/PiTensorProduct/InjectiveSeminorm.lean @@ -179,12 +179,13 @@ theorem norm_eval_le_injectiveSeminorm (f : ContinuousMultilinearMap 𝕜 E F) ( set f' := MultilinearMap.mkContinuous f'₀ ‖f‖ hf'₀ have hnorm : ‖f'‖ ≤ ‖f‖ := (f'.opNorm_le_iff (norm_nonneg f)).mpr hf'₀ have heq : e (lift f'.toMultilinearMap x) = lift f.toMultilinearMap x := by - induction' x using PiTensorProduct.induction_on with a m _ _ hx hy - · simp only [lift_symm, map_smul, lift.tprod, ContinuousMultilinearMap.coe_coe, + induction x using PiTensorProduct.induction_on with + | smul_tprod => + simp only [lift_symm, map_smul, lift.tprod, ContinuousMultilinearMap.coe_coe, MultilinearMap.coe_mkContinuous, LinearMap.compMultilinearMap_apply, LinearMap.coe_comp, LinearEquiv.coe_coe, Function.comp_apply, LinearEquiv.apply_symm_apply, SetLike.val_smul, LinearMap.codRestrict_apply, f', f'₀] - · simp only [map_add, AddSubmonoid.coe_add, Submodule.coe_toAddSubmonoid, hx, hy] + | add _ _ hx hy => simp only [map_add, Submodule.coe_add, hx, hy] suffices h : ‖lift f'.toMultilinearMap x‖ ≤ ‖f'‖ * injectiveSeminorm x by change ‖(e (lift f'.toMultilinearMap x)).1‖ ≤ _ at h rw [heq] at h @@ -210,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 @@ -343,11 +343,12 @@ theorem mapL_coe : (mapL f).toLinearMap = map (fun i ↦ (f i).toLinearMap) := b @[simp] theorem mapL_apply (x : ⨂[𝕜] i, E i) : mapL f x = map (fun i ↦ (f i).toLinearMap) x := by - induction' x using PiTensorProduct.induction_on with _ _ _ _ hx hy - · simp only [mapL, map_smul, liftIsometry_apply_apply, lift.tprod, + induction x using PiTensorProduct.induction_on with + | smul_tprod => + simp only [mapL, map_smul, liftIsometry_apply_apply, lift.tprod, ContinuousMultilinearMap.coe_coe, ContinuousMultilinearMap.compContinuousLinearMap_apply, tprodL_toFun, map_tprod, ContinuousLinearMap.coe_coe] - · simp only [map_add, hx, hy] + | add _ _ hx hy => simp only [map_add, hx, hy] /-- Given submodules `pᵢ ⊆ Eᵢ`, this is the natural map: `⨂[𝕜] i, pᵢ → ⨂[𝕜] i, Eᵢ`. This is the continuous version of `PiTensorProduct.mapIncl`. 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/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/ODE/Gronwall.lean b/Mathlib/Analysis/ODE/Gronwall.lean index 243e6fdc3e392..f45756db1a781 100644 --- a/Mathlib/Analysis/ODE/Gronwall.lean +++ b/Mathlib/Analysis/ODE/Gronwall.lean @@ -175,7 +175,7 @@ theorem dist_le_of_approx_trajectories_ODE (ha : dist (f a) (g a) ≤ δ) : ∀ t ∈ Icc a b, dist (f t) (g t) ≤ gronwallBound δ K (εf + εg) (t - a) := have hfs : ∀ t ∈ Ico a b, f t ∈ @univ E := fun _ _ => trivial - dist_le_of_approx_trajectories_ODE_of_mem (fun t => (hv t).lipschitzOnWith _) hf hf' + dist_le_of_approx_trajectories_ODE_of_mem (fun t => (hv t).lipschitzOnWith) hf hf' f_bound hfs hg hg' g_bound (fun _ _ => trivial) ha include hv in @@ -213,7 +213,7 @@ theorem dist_le_of_trajectories_ODE (ha : dist (f a) (g a) ≤ δ) : ∀ t ∈ Icc a b, dist (f t) (g t) ≤ δ * exp (K * (t - a)) := have hfs : ∀ t ∈ Ico a b, f t ∈ @univ E := fun _ _ => trivial - dist_le_of_trajectories_ODE_of_mem (fun t => (hv t).lipschitzOnWith _) hf hf' hfs hg + dist_le_of_trajectories_ODE_of_mem (fun t => (hv t).lipschitzOnWith) hf hf' hfs hg hg' (fun _ _ => trivial) ha include hv in @@ -354,5 +354,5 @@ theorem ODE_solution_unique (ha : f a = g a) : EqOn f g (Icc a b) := have hfs : ∀ t ∈ Ico a b, f t ∈ @univ E := fun _ _ => trivial - ODE_solution_unique_of_mem_Icc_right (fun t => (hv t).lipschitzOnWith _) hf hf' hfs hg hg' + ODE_solution_unique_of_mem_Icc_right (fun t => (hv t).lipschitzOnWith) hf hf' hfs hg hg' (fun _ _ => trivial) ha diff --git a/Mathlib/Analysis/ODE/PicardLindelof.lean b/Mathlib/Analysis/ODE/PicardLindelof.lean index ed06739eb6415..9c46abf777613 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,7 +81,7 @@ 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 t _ => (LipschitzWith.const 0).lipschitzOnWith cont := fun _ _ => by simpa only [Pi.zero_apply] using continuousOn_const norm_le := fun t _ x _ => norm_zero.le C_mul_le_R := (zero_mul _).le }⟩⟩ @@ -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,7 +220,7 @@ 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 ?_ @@ -265,10 +269,12 @@ theorem dist_next_apply_le_of_le {f₁ f₂ : FunSpace v} {n : ℕ} {d : ℝ} theorem dist_iterate_next_apply_le (f₁ f₂ : FunSpace v) (n : ℕ) (t : Icc v.tMin v.tMax) : dist (next^[n] f₁ t) (next^[n] f₂ t) ≤ (v.L * |t.1 - v.t₀|) ^ n / n ! * dist f₁ f₂ := by - induction' n with n ihn generalizing t - · rw [pow_zero, Nat.factorial_zero, Nat.cast_one, div_one, one_mul] + induction n generalizing t with + | zero => + rw [pow_zero, Nat.factorial_zero, Nat.cast_one, div_one, one_mul] exact dist_apply_le_dist f₁ f₂ t - · rw [iterate_succ_apply', iterate_succ_apply'] + | succ n ihn => + rw [iterate_succ_apply', iterate_succ_apply'] exact dist_next_apply_le_of_le ihn _ theorem dist_iterate_next_le (f₁ f₂ : FunSpace v) (n : ℕ) : @@ -282,7 +288,7 @@ variable [CompleteSpace E] theorem hasDerivWithinAt_next (t : Icc v.tMin v.tMax) : HasDerivWithinAt (f.next ∘ v.proj) (v t (f t)) (Icc v.tMin v.tMax) t := by haveI : Fact ((t : ℝ) ∈ Icc v.tMin v.tMax) := ⟨t.2⟩ - simp only [(· ∘ ·), next_apply] + simp only [Function.comp_def, next_apply] refine HasDerivWithinAt.const_add _ ?_ have : HasDerivWithinAt (∫ τ in v.t₀..·, f.vComp τ) (f.vComp t) (Icc v.tMin v.tMax) t := integral_hasDerivWithinAt_right (f.intervalIntegrable_vComp _ _) @@ -299,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 48e3533c9ef10..c6327e3b9a059 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.Basic +import Mathlib.Data.ENNReal.Real import Mathlib.Order.WellFoundedSet +import Mathlib.Topology.EMetricSpace.Diam /-! # Oscillation diff --git a/Mathlib/Analysis/PSeries.lean b/Mathlib/Analysis/PSeries.lean index 8a19619191174..a0365a83cfc7b 100644 --- a/Mathlib/Analysis/PSeries.lean +++ b/Mathlib/Analysis/PSeries.lean @@ -48,21 +48,22 @@ variable {M : Type*} [OrderedAddCommMonoid M] {f : ℕ → M} {u : ℕ → ℕ} theorem le_sum_schlomilch' (hf : ∀ ⦃m n⦄, 0 < m → m ≤ n → f n ≤ f m) (h_pos : ∀ n, 0 < u n) (hu : Monotone u) (n : ℕ) : (∑ k ∈ Ico (u 0) (u n), f k) ≤ ∑ k ∈ range n, (u (k + 1) - u k) • f (u k) := by - induction' n with n ihn - · simp - suffices (∑ k ∈ Ico (u n) (u (n + 1)), f k) ≤ (u (n + 1) - u n) • f (u n) by - rw [sum_range_succ, ← sum_Ico_consecutive] - · exact add_le_add ihn this - exacts [hu n.zero_le, hu n.le_succ] - have : ∀ k ∈ Ico (u n) (u (n + 1)), f k ≤ f (u n) := fun k hk => - hf (Nat.succ_le_of_lt (h_pos n)) (mem_Ico.mp hk).1 - convert sum_le_sum this - simp [pow_succ, mul_two] + induction n with + | zero => simp + | succ n ihn => + suffices (∑ k ∈ Ico (u n) (u (n + 1)), f k) ≤ (u (n + 1) - u n) • f (u n) by + rw [sum_range_succ, ← sum_Ico_consecutive] + · exact add_le_add ihn this + exacts [hu n.zero_le, hu n.le_succ] + have : ∀ k ∈ Ico (u n) (u (n + 1)), f k ≤ f (u n) := fun k hk => + hf (Nat.succ_le_of_lt (h_pos n)) (mem_Ico.mp hk).1 + convert sum_le_sum this + simp [pow_succ, mul_two] 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) @@ -80,23 +81,24 @@ theorem le_sum_condensed (hf : ∀ ⦃m n⦄, 0 < m → m ≤ n → f n ≤ f m) theorem sum_schlomilch_le' (hf : ∀ ⦃m n⦄, 1 < m → m ≤ n → f n ≤ f m) (h_pos : ∀ n, 0 < u n) (hu : Monotone u) (n : ℕ) : (∑ k ∈ range n, (u (k + 1) - u k) • f (u (k + 1))) ≤ ∑ k ∈ Ico (u 0 + 1) (u n + 1), f k := by - induction' n with n ihn - · simp - suffices (u (n + 1) - u n) • f (u (n + 1)) ≤ ∑ k ∈ Ico (u n + 1) (u (n + 1) + 1), f k by - rw [sum_range_succ, ← sum_Ico_consecutive] - exacts [add_le_add ihn this, - (add_le_add_right (hu n.zero_le) _ : u 0 + 1 ≤ u n + 1), - add_le_add_right (hu n.le_succ) _] - have : ∀ k ∈ Ico (u n + 1) (u (n + 1) + 1), f (u (n + 1)) ≤ f k := fun k hk => - hf (Nat.lt_of_le_of_lt (Nat.succ_le_of_lt (h_pos n)) <| (Nat.lt_succ_of_le le_rfl).trans_le - (mem_Ico.mp hk).1) (Nat.le_of_lt_succ <| (mem_Ico.mp hk).2) - convert sum_le_sum this - simp [pow_succ, mul_two] + induction n with + | zero => simp + | succ n ihn => + suffices (u (n + 1) - u n) • f (u (n + 1)) ≤ ∑ k ∈ Ico (u n + 1) (u (n + 1) + 1), f k by + rw [sum_range_succ, ← sum_Ico_consecutive] + exacts [add_le_add ihn this, + (add_le_add_right (hu n.zero_le) _ : u 0 + 1 ≤ u n + 1), + add_le_add_right (hu n.le_succ) _] + have : ∀ k ∈ Ico (u n + 1) (u (n + 1) + 1), f (u (n + 1)) ≤ f k := fun k hk => + hf (Nat.lt_of_le_of_lt (Nat.succ_le_of_lt (h_pos n)) <| (Nat.lt_succ_of_le le_rfl).trans_le + (mem_Ico.mp hk).1) (Nat.le_of_lt_succ <| (mem_Ico.mp hk).2) + convert sum_le_sum this + simp [pow_succ, mul_two] 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) @@ -160,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 @@ -196,7 +198,7 @@ theorem summable_schlomilch_iff {C : ℕ} {u : ℕ → ℕ} {f : ℕ → ℝ≥0 simpa [add_eq_top, mul_ne_top, mul_eq_top, hC_nonzero] using eq_top_mono hC h · replace hf : ∀ m n, 0 < m → m ≤ n → (f n : ℝ≥0∞) ≤ f m := fun m n hm hmn => ENNReal.coe_le_coe.2 (hf hm hmn) - have : ∑ k ∈ range (u 0), (f k : ℝ≥0∞) ≠ ∞ := (sum_lt_top fun a _ => coe_ne_top).ne + have : ∑ k ∈ range (u 0), (f k : ℝ≥0∞) ≠ ∞ := sum_ne_top.2 fun a _ => coe_ne_top simpa [h, add_eq_top, this] using le_tsum_schlomilch hf h_pos hu_strict open ENNReal in @@ -281,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] @@ -399,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 @@ -414,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..3466df2251849 100644 --- a/Mathlib/Analysis/Quaternion.lean +++ b/Mathlib/Analysis/Quaternion.lean @@ -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 5fc1882b59565..69097ee6513a0 100644 --- a/Mathlib/Analysis/RCLike/Basic.lean +++ b/Mathlib/Analysis/RCLike/Basic.lean @@ -3,12 +3,13 @@ Copyright (c) 2020 Frédéric Dupuis. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Frédéric Dupuis -/ -import Mathlib.Algebra.Star.Order +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.Analysis.Normed.Module.Basic import Mathlib.Data.Real.Sqrt -import Mathlib.Algebra.Algebra.Field /-! # `RCLike`: a typeclass for ℝ or ℂ @@ -40,12 +41,13 @@ their counterparts in `Mathlib/Analysis/Complex/Basic.lean` (which causes linter A few lemmas requiring heavier imports are in `Mathlib/Data/RCLike/Lemmas.lean`. -/ +open Fintype +open scoped BigOperators ComplexConjugate + section local notation "𝓚" => algebraMap ℝ _ -open ComplexConjugate - /-- This typeclass captures properties shared by ℝ and ℂ, with an API that closely matches that of ℂ. -/ @@ -82,8 +84,6 @@ variable {K E : Type*} [RCLike K] namespace RCLike -open ComplexConjugate - /-- Coercion from `ℝ` to an `RCLike` field. -/ @[coe] abbrev ofReal : ℝ → K := Algebra.cast @@ -233,10 +233,21 @@ theorem norm_ofReal (r : ℝ) : ‖(r : K)‖ = |r| := /-! ### Characteristic zero -/ -- see Note [lower instance priority] -/-- ℝ and ℂ are both of characteristic zero. -/ +/-- ℝ and ℂ are both of characteristic zero. -/ 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. -/ @@ -320,20 +331,20 @@ 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) := - ((is_real_TFAE z).out 0 1).trans <| by simp only [eq_comm] + calc + _ ↔ ∃ r : ℝ, (r : K) = z := (is_real_TFAE z).out 0 1 + _ ↔ _ := by simp only [eq_comm] theorem conj_eq_iff_re {z : K} : conj z = z ↔ (re z : K) = z := (is_real_TFAE z).out 0 2 @@ -418,7 +429,7 @@ theorem mul_conj (z : K) : z * conj z = ‖z‖ ^ 2 := by theorem conj_mul (z : K) : conj z * z = ‖z‖ ^ 2 := by rw [mul_comm, mul_conj] lemma inv_eq_conj (hz : ‖z‖ = 1) : z⁻¹ = conj z := - inv_eq_of_mul_eq_one_left $ by simp_rw [conj_mul, hz, algebraMap.coe_one, one_pow] + inv_eq_of_mul_eq_one_left <| by simp_rw [conj_mul, hz, algebraMap.coe_one, one_pow] theorem normSq_sub (z w : K) : normSq (z - w) = normSq z + normSq w - 2 * re (z * conj w) := by simp only [normSq_add, sub_eq_add_neg, map_neg, mul_neg, normSq_neg, map_neg] @@ -503,11 +514,13 @@ theorem normSq_inv (z : K) : normSq z⁻¹ = (normSq z)⁻¹ := theorem normSq_div (z w : K) : normSq (z / w) = normSq z / normSq w := map_div₀ normSq z w -@[rclike_simps] -- porting note (#10618): was `simp` -theorem norm_conj {z : K} : ‖conj z‖ = ‖z‖ := by simp only [← sqrt_normSq_eq_norm, normSq_conj] +@[simp 1100, rclike_simps] +theorem norm_conj (z : K) : ‖conj z‖ = ‖z‖ := by simp only [← sqrt_normSq_eq_norm, normSq_conj] + +@[simp, rclike_simps] lemma nnnorm_conj (z : K) : ‖conj z‖₊ = ‖z‖₊ := by simp [nnnorm] instance (priority := 100) : CStarRing K where - norm_mul_self_le x := le_of_eq <| ((norm_mul _ _).trans <| congr_arg (· * ‖x‖) norm_conj).symm + norm_mul_self_le x := le_of_eq <| ((norm_mul _ _).trans <| congr_arg (· * ‖x‖) (norm_conj _)).symm /-! ### Cast lemmas -/ @@ -515,6 +528,9 @@ instance (priority := 100) : CStarRing K where theorem ofReal_natCast (n : ℕ) : ((n : ℝ) : K) = n := map_natCast (algebraMap ℝ K) n +@[rclike_simps, norm_cast] +lemma ofReal_nnratCast (q : ℚ≥0) : ((q : ℝ) : K) = q := map_nnratCast (algebraMap ℝ K) _ + @[simp, rclike_simps] -- Porting note: removed `norm_cast` theorem natCast_re (n : ℕ) : re (n : K) = n := by rw [← ofReal_natCast, ofReal_re] @@ -575,21 +591,56 @@ theorem norm_natCast (n : ℕ) : ‖(n : K)‖ = n := by rw [← ofReal_natCast] exact norm_of_nonneg (Nat.cast_nonneg n) +@[simp, rclike_simps, norm_cast] lemma nnnorm_natCast (n : ℕ) : ‖(n : K)‖₊ = n := by simp [nnnorm] + @[simp, rclike_simps] theorem norm_ofNat (n : ℕ) [n.AtLeastTwo] : ‖(no_index (OfNat.ofNat n) : K)‖ = OfNat.ofNat n := norm_natCast n +@[simp, rclike_simps] +lemma nnnorm_ofNat (n : ℕ) [n.AtLeastTwo] : ‖(no_index (OfNat.ofNat n) : K)‖₊ = OfNat.ofNat n := + nnnorm_natCast n + +lemma norm_two : ‖(2 : K)‖ = 2 := norm_ofNat 2 +lemma nnnorm_two : ‖(2 : K)‖₊ = 2 := nnnorm_ofNat 2 + +@[simp, rclike_simps, norm_cast] +lemma norm_nnratCast (q : ℚ≥0) : ‖(q : K)‖ = q := by + rw [← ofReal_nnratCast]; exact norm_of_nonneg q.cast_nonneg + +@[simp, rclike_simps, norm_cast] +lemma nnnorm_nnratCast (q : ℚ≥0) : ‖(q : K)‖₊ = q := by simp [nnnorm] + variable (K) in lemma norm_nsmul [NormedAddCommGroup E] [NormedSpace K E] (n : ℕ) (x : E) : ‖n • x‖ = n • ‖x‖ := by - rw [← Nat.cast_smul_eq_nsmul K, norm_smul, RCLike.norm_natCast, nsmul_eq_mul] + simpa [Nat.cast_smul_eq_nsmul] using norm_smul (n : K) x + +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 (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 (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] attribute [rclike_simps] norm_zero norm_one norm_eq_zero abs_norm norm_inv norm_div --- Porting note: removed @[simp, rclike_simps], b/c generalized to `norm_ofNat` -theorem norm_two : ‖(2 : K)‖ = 2 := norm_ofNat 2 - theorem abs_re_le_norm (z : K) : |re z| ≤ ‖z‖ := by rw [mul_self_le_mul_self_iff (abs_nonneg _) (norm_nonneg _), abs_mul_abs_self, mul_self_norm] apply re_sq_le_normSq @@ -621,11 +672,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, @@ -666,7 +717,7 @@ end RCLike section Instances -noncomputable instance Real.RCLike : RCLike ℝ where +noncomputable instance Real.instRCLike : RCLike ℝ where re := AddMonoidHom.id ℝ im := 0 I := 0 @@ -803,7 +854,7 @@ theorem toOrderedSMul : OrderedSMul ℝ K := scoped[ComplexOrder] attribute [instance] RCLike.toOrderedSMul -/-- A star algebra over `K` has a scalar multiplication that respects the order. -/ +/-- A star algebra over `K` has a scalar multiplication that respects the order. -/ 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 @@ -822,8 +873,6 @@ scoped[ComplexOrder] attribute [instance] StarModule.instOrderedSMul end Order -open ComplexConjugate - section CleanupLemmas local notation "reR" => @RCLike.re ℝ _ @@ -924,7 +973,7 @@ theorem conjAe_coe : (conjAe : K → K) = conj := /-- Conjugate as a linear isometry -/ noncomputable def conjLIE : K ≃ₗᵢ[ℝ] K := - ⟨conjAe.toLinearEquiv, fun _ => norm_conj⟩ + ⟨conjAe.toLinearEquiv, norm_conj⟩ @[simp, rclike_simps] theorem conjLIE_apply : (conjLIE : K → K) = conj := @@ -1020,3 +1069,75 @@ noncomputable def realLinearIsometryEquiv (h : I = (0 : K)) : K ≃ₗᵢ[ℝ] end CaseSpecific end RCLike + +namespace AddChar +variable {G : Type*} [Finite G] + +lemma inv_apply_eq_conj [AddLeftCancelMonoid G] (ψ : AddChar G K) (x : G) : (ψ x)⁻¹ = conj (ψ x) := + RCLike.inv_eq_conj <| norm_apply _ _ + +lemma map_neg_eq_conj [AddCommGroup G] (ψ : AddChar G K) (x : G) : ψ (-x) = conj (ψ x) := by + 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/Seminorm.lean b/Mathlib/Analysis/Seminorm.lean index 99aa49d8ceb0b..a448a13eadcc8 100644 --- a/Mathlib/Analysis/Seminorm.lean +++ b/Mathlib/Analysis/Seminorm.lean @@ -495,7 +495,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 @@ -658,13 +658,13 @@ 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 ext rw [mem_closedBall, mem_closedBall, smul_apply, NNReal.smul_def, smul_eq_mul, mul_comm, - le_div_iff (NNReal.coe_pos.mpr hc)] + le_div_iff₀ (NNReal.coe_pos.mpr hc)] theorem ball_sup (p : Seminorm 𝕜 E) (q : Seminorm 𝕜 E) (e : E) (r : ℝ) : ball (p ⊔ q) e r = ball p e r ∩ ball q e r := by @@ -815,14 +815,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₂ : ℝ) : @@ -899,7 +899,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 +952,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 +1047,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,14 +1184,14 @@ 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), + 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] - exact (le_div_iff εpos).1 hn.1 + 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 rw [zpow_neg, norm_inv, inv_inv, norm_zpow, zpow_add₀ (ne_of_gt cpos), zpow_one, this, @@ -1255,7 +1255,7 @@ lemma bddAbove_of_absorbent {ι : Sort*} {p : ι → Seminorm 𝕜 E} {s : Set E obtain ⟨c, hc₀, hc⟩ : ∃ c ≠ 0, (c : 𝕜) • x ∈ s := (eventually_mem_nhdsWithin.and (hs.eventually_nhdsWithin_zero x)).exists rcases h _ hc with ⟨M, hM⟩ - refine ⟨M / ‖c‖, forall_mem_range.mpr fun i ↦ (le_div_iff' (norm_pos_iff.2 hc₀)).2 ?_⟩ + refine ⟨M / ‖c‖, forall_mem_range.mpr fun i ↦ (le_div_iff₀' (norm_pos_iff.2 hc₀)).2 ?_⟩ exact hM ⟨i, map_smul_eq_mul ..⟩ end NontriviallyNormedField diff --git a/Mathlib/Analysis/SpecialFunctions/Bernstein.lean b/Mathlib/Analysis/SpecialFunctions/Bernstein.lean index 5cfa043e78334..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 @@ -92,7 +93,7 @@ def z {n : ℕ} (k : Fin (n + 1)) : I := · norm_num · have h₁ : 0 < (n.succ : ℝ) := mod_cast Nat.succ_pos _ have h₂ : ↑k ≤ n.succ := mod_cast Fin.le_last k - rw [Set.mem_Icc, le_div_iff h₁, div_le_iff h₁] + rw [Set.mem_Icc, le_div_iff₀ h₁, div_le_iff₀ h₁] norm_cast simp [h₂]⟩ @@ -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 new file mode 100644 index 0000000000000..c74cbff25c9e5 --- /dev/null +++ b/Mathlib/Analysis/SpecialFunctions/BinaryEntropy.lean @@ -0,0 +1,449 @@ +/- +Copyright (c) 2023 Adomas Baliuka. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Adomas Baliuka +-/ +import Mathlib.Analysis.SpecialFunctions.Log.NegMulLog +import Mathlib.Analysis.Convex.SpecificFunctions.Basic + +/-! +# Properties of Shannon q-ary entropy and binary entropy functions + +The [binary entropy function](https://en.wikipedia.org/wiki/Binary_entropy_function) +`binEntropy p := - p * log p - (1 - p) * log (1 - p)` +is the Shannon entropy of a Bernoulli random variable with success probability `p`. + +More generally, the q-ary entropy function is the Shannon entropy of the random variable +with possible outcomes `{1, ..., q}`, where outcome `1` has probability `1 - p` +and all other outcomes are equally likely. + +`qaryEntropy (q : ℕ) (p : ℝ) := p * log (q - 1) - p * log p - (1 - p) * log (1 - p)` + +This file assumes that entropy is measured in Nats, hence the use of natural logarithms. +Most lemmas are also valid using a logarithm in a different base. + +## Main declarations + +* `Real.binEntropy`: the binary entropy function +* `Real.qaryEntropy`: the `q`-ary entropy function + +## Main results + +The functions are also defined outside the interval `Icc 0 1` due to `log x = log |x|`. + +* They are continuous everywhere (`binEntropy_continuous` and `qaryEntropy_continuous`). +* They are differentiable everywhere except at points `0` or `1` + (`hasDerivAt_binEntropy` and `hasDerivAt_qaryEntropy`). + In addition, due to junk values, `deriv binEntropy p = log (1 - p) - log p` + holds everywhere (`deriv_binEntropy`). +* they are strictly increasing on `Icc 0 (1 - 1/q))` + (`qaryEntropy_strictMonoOn`, `binEntropy_strictMonoOn`) + and strictly decreasing on `Icc (1 - 1/q) 1` + (`binEntropy_strictAntiOn` and `qaryEntropy_strictAntiOn`). +* they are strictly concave on `Icc 0 1` + (`strictConcaveOn_qaryEntropy` and `strictConcave_binEntropy`). + +## Tags + +entropy, Shannon, binary, nit, nepit +-/ + +namespace Real +variable {q : ℕ} {p : ℝ} + +/-! ### Binary entropy -/ + +/-- The [binary entropy function](https://en.wikipedia.org/wiki/Binary_entropy_function) +`binEntropy p := - p * log p - (1-p) * log (1 - p)` +is the Shannon entropy of a Bernoulli random variable with success probability `p`. -/ +@[pp_nodot] noncomputable def binEntropy (p : ℝ) : ℝ := p * log p⁻¹ + (1 - p) * log (1 - p)⁻¹ + +@[simp] lemma binEntropy_zero : binEntropy 0 = 0 := by simp [binEntropy] +@[simp] lemma binEntropy_one : binEntropy 1 = 0 := by simp [binEntropy] +@[simp] lemma binEntropy_two_inv : binEntropy 2⁻¹ = log 2 := by norm_num [binEntropy]; simp; ring + +lemma binEntropy_eq_negMulLog_add_negMulLog_one_sub (p : ℝ) : + binEntropy p = negMulLog p + negMulLog (1 - p) := by simp [binEntropy, negMulLog, ← neg_mul] + +lemma binEntropy_eq_negMulLog_add_negMulLog_one_sub' : + binEntropy = fun p ↦ negMulLog p + negMulLog (1 - p) := + funext binEntropy_eq_negMulLog_add_negMulLog_one_sub + +/-- `binEntropy` is symmetric about 1/2. -/ +@[simp] lemma binEntropy_one_sub (p : ℝ) : binEntropy (1 - p) = binEntropy p := by + simp [binEntropy, add_comm] + +/-- `binEntropy` is symmetric about 1/2. -/ +lemma binEntropy_two_inv_add (p : ℝ) : binEntropy (2⁻¹ + p) = binEntropy (2⁻¹ - p) := by + rw [← binEntropy_one_sub]; ring_nf + +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₀).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 + obtain rfl | hp₀ := hp₀.eq_or_lt + · simp + obtain rfl | hp₁ := hp₁.eq_or_lt + · simp + exact (binEntropy_pos hp₀ hp₁).le + +/-- Outside the usual range of `binEntropy`, it is negative. This is due to `log p = log |p|`. -/ +lemma binEntropy_neg_of_neg (hp : p < 0) : binEntropy p < 0 := by + rw [binEntropy, log_inv, log_inv] + suffices -p * log p < (1 - p) * log (1 - p) by linarith + by_cases hp' : p < -1 + · have : log p < log (1 - p) := by + rw [← log_neg_eq_log] + exact log_lt_log (Left.neg_pos_iff.mpr hp) (by linarith) + nlinarith [log_pos_of_lt_neg_one hp'] + · have : -p * log p ≤ 0 := by + wlog h : -1 < p + · simp only [show p = -1 by linarith, log_neg_eq_log, log_one, le_refl, mul_zero] + · nlinarith [log_neg_of_lt_zero hp h] + nlinarith [(log_pos (by linarith) : 0 < log (1 - p))] + +/-- Outside the usual range of `binEntropy`, it is negative. This is due to `log p = log |p|`. -/ +lemma binEntropy_nonpos_of_nonpos (hp : p ≤ 0) : binEntropy p ≤ 0 := by + obtain rfl | hp := hp.eq_or_lt + · simp + · exact (binEntropy_neg_of_neg hp).le + +/-- Outside the usual range of `binEntropy`, it is negative. This is due to `log p = log |p|` -/ +lemma binEntropy_neg_of_one_lt (hp : 1 < p) : binEntropy p < 0 := by + rw [← binEntropy_one_sub]; exact binEntropy_neg_of_neg (sub_neg.2 hp) + +/-- Outside the usual range of `binEntropy`, it is negative. This is due to `log p = log |p|` -/ +lemma binEntropy_nonpos_of_one_le (hp : 1 ≤ p) : binEntropy p ≤ 0 := by + rw [← binEntropy_one_sub]; exact binEntropy_nonpos_of_nonpos (sub_nonpos.2 hp) + +lemma binEntropy_eq_zero : binEntropy p = 0 ↔ p = 0 ∨ p = 1 := by + refine ⟨fun h ↦ ?_, by rintro (rfl | rfl) <;> simp⟩ + contrapose! h + obtain hp₀ | hp₀ := h.1.lt_or_lt + · exact (binEntropy_neg_of_neg hp₀).ne + obtain hp₁ | hp₁ := h.2.lt_or_lt.symm + · exact (binEntropy_neg_of_one_lt hp₁).ne + · exact (binEntropy_pos hp₀ hp₁).ne' + +/-- For probability `p ≠ 0.5`, `binEntropy p < log 2`. -/ +lemma binEntropy_lt_log_two : binEntropy p < log 2 ↔ p ≠ 2⁻¹ := by + refine ⟨?_, fun h ↦ ?_⟩ + · rintro h rfl + simp at h + wlog hp : p < 2⁻¹ + · have hp : 1 - p < 2⁻¹ := by + rw [sub_lt_comm]; norm_num at *; linarith (config := { splitNe := true }) + rw [← binEntropy_one_sub] + exact this hp.ne hp + obtain hp₀ | hp₀ := le_or_lt p 0 + · exact (binEntropy_nonpos_of_nonpos hp₀).trans_lt <| log_pos <| by norm_num + have hp₁ : 0 < 1 - p := sub_pos.2 <| hp.trans <| by norm_num + calc + _ < log (p * p⁻¹ + (1 - p) * (1 - p)⁻¹) := + strictConcaveOn_log_Ioi.2 (inv_pos.2 hp₀) (inv_pos.2 hp₁) + (by simpa [eq_sub_iff_add_eq, ← two_mul, mul_comm, mul_eq_one_iff_eq_inv₀]) hp₀ hp₁ (by simp) + _ = log 2 := by rw [mul_inv_cancel₀, mul_inv_cancel₀, one_add_one_eq_two] <;> positivity + +lemma binEntropy_le_log_two : binEntropy p ≤ log 2 := by + obtain rfl | hp := eq_or_ne p 2⁻¹ + · simp + · exact (binEntropy_lt_log_two.2 hp).le + +lemma binEntropy_eq_log_two : binEntropy p = log 2 ↔ p = 2⁻¹ := by + rw [binEntropy_le_log_two.eq_iff_not_lt, binEntropy_lt_log_two, not_ne_iff] + +/-- Binary entropy is continuous everywhere. +This is due to definition of `Real.log` for negative numbers. -/ +@[fun_prop] lemma binEntropy_continuous : Continuous binEntropy := by + rw [binEntropy_eq_negMulLog_add_negMulLog_one_sub']; fun_prop + +@[fun_prop] lemma differentiableAt_binEntropy (hp₀ : p ≠ 0) (hp₁ : p ≠ 1) : + DifferentiableAt ℝ binEntropy p := by + rw [ne_comm, ← sub_ne_zero] at hp₁ + unfold binEntropy + simp only [log_inv, mul_neg] + fun_prop (disch := assumption) + +set_option push_neg.use_distrib true in +lemma differentiableAt_binEntropy_iff_ne_zero_one : + DifferentiableAt ℝ binEntropy p ↔ p ≠ 0 ∧ p ≠ 1 := by + refine ⟨fun h ↦ ⟨?_, ?_⟩, fun h ↦ differentiableAt_binEntropy h.1 h.2⟩ + <;> rintro rfl <;> unfold binEntropy at h + · rw [DifferentiableAt.add_iff_left] at h + · simp [log_inv, mul_neg, ← neg_mul, ← negMulLog_def, differentiableAt_negMulLog_iff] at h + · fun_prop (disch := simp) + · rw [DifferentiableAt.add_iff_right, differentiableAt_iff_comp_const_sub (b := 1)] at h + · simp [log_inv, mul_neg, ← neg_mul, ← negMulLog_def, differentiableAt_negMulLog_iff] at h + · fun_prop (disch := simp) + +set_option push_neg.use_distrib true in +/-- Binary entropy has derivative `log (1 - p) - log p`. +It's not differentiable at `0` or `1` but the junk values of `deriv` and `log` coincide there. -/ +lemma deriv_binEntropy (p : ℝ) : deriv binEntropy p = log (1 - p) - log p := by + by_cases hp : p ≠ 0 ∧ p ≠ 1 + · obtain ⟨hp₀, hp₁⟩ := hp + rw [ne_comm, ← sub_ne_zero] at hp₁ + rw [binEntropy_eq_negMulLog_add_negMulLog_one_sub', deriv_add, deriv_comp_const_sub, + deriv_negMulLog hp₀, deriv_negMulLog hp₁] + · ring + all_goals fun_prop (disch := assumption) + -- pathological case where `deriv = 0` since `binEntropy` is not differentiable there + · rw [deriv_zero_of_not_differentiableAt (differentiableAt_binEntropy_iff_ne_zero_one.not.2 hp)] + push_neg at hp + obtain rfl | rfl := hp <;> simp + +/-! ### `q`-ary entropy -/ + +/-- Shannon q-ary Entropy function (measured in Nats, i.e., using natural logs). + +It's the Shannon entropy of a random variable with possible outcomes {1, ..., q} +where outcome `1` has probability `1 - p` and all other outcomes are equally likely. + +The usual domain of definition is p ∈ [0,1], i.e., input is a probability. + +This is a generalization of the binary entropy function `binEntropy`. -/ +@[pp_nodot] noncomputable def qaryEntropy (q : ℕ) (p : ℝ) : ℝ := p * log (q - 1 : ℤ) + binEntropy p + +@[simp] lemma qaryEntropy_zero (q : ℕ) : qaryEntropy q 0 = 0 := by simp [qaryEntropy] +@[simp] lemma qaryEntropy_one (q : ℕ) : qaryEntropy q 1 = log (q - 1 : ℤ) := by simp [qaryEntropy] +@[simp] lemma qaryEntropy_two : qaryEntropy 2 = binEntropy := by ext; simp [qaryEntropy] + +lemma qaryEntropy_pos (hp₀ : 0 < p) (hp₁ : p < 1) : 0 < qaryEntropy q p := by + unfold qaryEntropy + have := binEntropy_pos hp₀ hp₁ + positivity + +lemma qaryEntropy_nonneg (hp₀ : 0 ≤ p) (hp₁ : p ≤ 1) : 0 ≤ qaryEntropy q p := by + obtain rfl | hp₀ := hp₀.eq_or_lt + · simp + obtain rfl | hp₁ := hp₁.eq_or_lt + · simpa [qaryEntropy, -Int.cast_sub] using log_intCast_nonneg _ + exact (qaryEntropy_pos hp₀ hp₁).le + +/-- Outside the usual range of `qaryEntropy`, it is negative. This is due to `log p = log |p|`. -/ +lemma qaryEntropy_neg_of_neg (hp : p < 0) : qaryEntropy q p < 0 := + add_neg_of_nonpos_of_neg (mul_nonpos_of_nonpos_of_nonneg hp.le (log_intCast_nonneg _)) + (binEntropy_neg_of_neg hp) + +/-- Outside the usual range of `qaryEntropy`, it is negative. This is due to `log p = log |p|`. -/ +lemma qaryEntropy_nonpos_of_nonpos (hp : p ≤ 0) : qaryEntropy q p ≤ 0 := + add_nonpos (mul_nonpos_of_nonpos_of_nonneg hp (log_intCast_nonneg _)) + (binEntropy_nonpos_of_nonpos hp) + +/-- The q-ary entropy function is continuous everywhere. +This is due to definition of `Real.log` for negative numbers. -/ +@[fun_prop] lemma qaryEntropy_continuous : Continuous (qaryEntropy q) := by + unfold qaryEntropy; fun_prop + +@[fun_prop] lemma differentiableAt_qaryEntropy (hp₀ : p ≠ 0) (hp₁ : p ≠ 1) : + DifferentiableAt ℝ (qaryEntropy q) p := by unfold qaryEntropy; fun_prop (disch := assumption) + +lemma deriv_qaryEntropy (hp₀ : p ≠ 0) (hp₁ : p ≠ 1) : + deriv (qaryEntropy q) p = log (q - 1) + log (1 - p) - log p := by + unfold qaryEntropy + rw [deriv_add] + · simp only [Int.cast_sub, Int.cast_natCast, Int.cast_one, differentiableAt_id', deriv_mul_const, + deriv_id'', one_mul, deriv_binEntropy, add_sub_assoc] + all_goals fun_prop (disch := assumption) + +/-- Binary entropy has derivative `log (1 - p) - log p`. -/ +lemma hasDerivAt_binEntropy (hp₀ : p ≠ 0) (hp₁ : p ≠ 1) : + HasDerivAt binEntropy (log (1 - p) - log p) p := + deriv_binEntropy _ ▸ (differentiableAt_binEntropy hp₀ hp₁).hasDerivAt + +lemma hasDerivAt_qaryEntropy (hp₀ : p ≠ 0) (hp₁ : p ≠ 1) : + HasDerivAt (qaryEntropy q) (log (q - 1) + log (1 - p) - log p) p := + deriv_qaryEntropy hp₀ hp₁ ▸ (differentiableAt_qaryEntropy hp₀ hp₁).hasDerivAt + +open Filter Topology Set + +private lemma tendsto_log_one_sub_sub_log_nhdsWithin_atAtop : + Tendsto (fun p ↦ log (1 - p) - log p) (𝓝[>] 0) atTop := by + apply Filter.tendsto_atTop_add_left_of_le' (𝓝[>] 0) (log (1/2) : ℝ) + · have h₁ : (0 : ℝ) < 1 / 2 := by norm_num + filter_upwards [Ioc_mem_nhdsWithin_Ioi' h₁] with p hx + gcongr + linarith [hx.2] + · apply tendsto_neg_atTop_iff.mpr tendsto_log_nhdsWithin_zero_right + +private lemma tendsto_log_one_sub_sub_log_nhdsWithin_one_atBot : + Tendsto (fun p ↦ log (1 - p) - log p) (𝓝[<] 1) atBot := by + apply Filter.tendsto_atBot_add_right_of_ge' (𝓝[<] 1) (-log (1 - 2⁻¹)) + · have : Tendsto log (𝓝[>] 0) atBot := Real.tendsto_log_nhdsWithin_zero_right + apply Tendsto.comp (f := (1 - ·)) (g := log) this + have contF : Continuous ((1 : ℝ) - ·) := continuous_sub_left 1 + have : MapsTo ((1 : ℝ) - ·) (Iio 1) (Ioi 0) := by + intro p hx + simp_all only [mem_Iio, mem_Ioi, sub_pos] + convert ContinuousWithinAt.tendsto_nhdsWithin (x :=(1 : ℝ)) contF.continuousWithinAt this + exact Eq.symm (sub_eq_zero_of_eq rfl) + · have h₁ : (1 : ℝ) - (2 : ℝ)⁻¹ < 1 := by norm_num + filter_upwards [Ico_mem_nhdsWithin_Iio' h₁] with p hx + gcongr + exact hx.1 + +lemma not_continuousAt_deriv_qaryEntropy_one : + ¬ContinuousAt (deriv (qaryEntropy q)) 1 := by + have tendstoBot : Tendsto (fun p ↦ log (q - 1) + log (1 - p) - log p) (𝓝[<] 1) atBot := by + have : (fun p ↦ log (q - 1) + log (1 - p) - log p) + = (fun p ↦ log (q - 1) + (log (1 - p) - log p)) := by + ext + ring + rw [this] + apply tendsto_atBot_add_const_left + exact tendsto_log_one_sub_sub_log_nhdsWithin_one_atBot + apply not_continuousAt_of_tendsto (Filter.Tendsto.congr' _ tendstoBot) nhdsWithin_le_nhds + · simp only [disjoint_nhds_atBot_iff, not_isBot, not_false_eq_true] + filter_upwards [Ioo_mem_nhdsWithin_Iio' (show 1 - 2⁻¹ < (1 : ℝ) by norm_num)] + intros + apply (deriv_qaryEntropy _ _).symm + · simp_all only [mem_Ioo, ne_eq] + linarith [show (1 : ℝ) = 2⁻¹ + 2⁻¹ by norm_num] + · simp_all only [mem_Ioo, ne_eq] + linarith [two_inv_lt_one (α := ℝ)] + +lemma not_continuousAt_deriv_qaryEntropy_zero : + ¬ContinuousAt (deriv (qaryEntropy q)) 0 := by + have tendstoTop : Tendsto (fun p ↦ log (q - 1) + log (1 - p) - log p) (𝓝[>] 0) atTop := by + have : (fun p ↦ log (q - 1) + log (1 - p) - log p) + = (fun p ↦ log (q - 1) + (log (1 - p) - log p)) := by ext; ring + rw [this] + exact tendsto_atTop_add_const_left _ _ tendsto_log_one_sub_sub_log_nhdsWithin_atAtop + apply not_continuousAt_of_tendsto (Filter.Tendsto.congr' _ tendstoTop) nhdsWithin_le_nhds + · simp only [disjoint_nhds_atTop_iff, not_isTop, not_false_eq_true] + filter_upwards [Ioo_mem_nhdsWithin_Ioi' (show (0 : ℝ) < 2⁻¹ by norm_num)] + intros + apply (deriv_qaryEntropy _ _).symm + · simp_all only [zero_add, mem_Ioo, ne_eq] + linarith + · simp_all only [zero_add, mem_Ioo, ne_eq] + linarith [two_inv_lt_one (α := ℝ)] + +/-- Second derivative of q-ary entropy. -/ +lemma deriv2_qaryEntropy : + deriv^[2] (qaryEntropy q) p = -1 / (p * (1 - p)) := by + simp only [Function.iterate_succ, Function.iterate_zero, Function.id_comp, Function.comp_apply] + by_cases is_x_where_nondiff : p ≠ 0 ∧ p ≠ 1 -- normal case + · obtain ⟨xne0, xne1⟩ := is_x_where_nondiff + suffices ∀ᶠ y in (𝓝 p), + deriv (fun p ↦ (qaryEntropy q) p) y = log (q - 1) + log (1 - y) - log y by + refine (Filter.EventuallyEq.deriv_eq this).trans ?_ + rw [deriv_sub ?_ (differentiableAt_log xne0)] + · rw [deriv.log differentiableAt_id' xne0] + simp only [deriv_id'', one_div] + · have {q : ℝ} (p : ℝ) : DifferentiableAt ℝ (fun p => q - p) p := by fun_prop + have d_oneminus (p : ℝ) : deriv (fun (y : ℝ) ↦ 1 - y) p = -1 := by + rw [deriv_const_sub 1, deriv_id''] + field_simp [sub_ne_zero_of_ne xne1.symm, this, d_oneminus] + ring + · apply DifferentiableAt.add + simp only [ne_eq, differentiableAt_const] + exact DifferentiableAt.log (by fun_prop) (sub_ne_zero.mpr xne1.symm) + filter_upwards [eventually_ne_nhds xne0, eventually_ne_nhds xne1] + with y xne0 h2 using deriv_qaryEntropy xne0 h2 + -- Pathological case where we use junk value (because function not differentiable) + · have : p = 0 ∨ p = 1 := Decidable.or_iff_not_and_not.mpr is_x_where_nondiff + rw [deriv_zero_of_not_differentiableAt] + · simp_all only [ne_eq, not_and, Decidable.not_not] + cases this <;> simp_all only [ + mul_zero, one_ne_zero, zero_ne_one, sub_zero, mul_one, div_zero, sub_self] + · intro h + have contAt := h.continuousAt + cases this <;> simp_all [ + not_continuousAt_deriv_qaryEntropy_zero, not_continuousAt_deriv_qaryEntropy_one, contAt] + +lemma deriv2_binEntropy : deriv^[2] binEntropy p = -1 / (p * (1 - p)) := + qaryEntropy_two ▸ deriv2_qaryEntropy + +/-! ### Strict monotonicity of entropy -/ + +/-- Qary entropy is strictly increasing in the interval [0, 1 - q⁻¹]. -/ +lemma qaryEntropy_strictMonoOn (qLe2 : 2 ≤ q) : + StrictMonoOn (qaryEntropy q) (Icc 0 (1 - 1/q)) := by + intro p1 hp1 p2 hp2 p1le2 + apply strictMonoOn_of_deriv_pos (convex_Icc 0 (1 - 1/(q : ℝ))) _ _ hp1 hp2 p1le2 + · exact qaryEntropy_continuous.continuousOn + · intro p hp + have : 2 ≤ (q : ℝ) := Nat.ofNat_le_cast.mpr qLe2 + have zero_le_qinv : 0 < (q : ℝ)⁻¹ := by positivity + have : 0 < 1 - p := by + simp only [sub_pos, hp.2] + have p_lt_1_minus_qinv : p < 1 - (q : ℝ)⁻¹ := by + simp_all only [inv_pos, interior_Icc, mem_Ioo, one_div] + linarith + simp only [one_div, interior_Icc, mem_Ioo] at hp + rw [deriv_qaryEntropy (by linarith)] + · field_simp + rw [← log_mul (by linarith) (by linarith)] + apply Real.strictMonoOn_log (mem_Ioi.mpr hp.1) + · simp_all only [mem_Ioi, mul_pos_iff_of_pos_left, show 0 < (q : ℝ) - 1 by linarith] + · have qpos : 0 < (q : ℝ) := by positivity + have : q * p < q - 1 := by + convert (mul_lt_mul_left qpos).2 hp.2 using 1 + simp only [mul_sub, mul_one, isUnit_iff_ne_zero, ne_eq, ne_of_gt qpos, not_false_eq_true, + IsUnit.mul_inv_cancel] + linarith + exact (ne_of_gt (lt_add_neg_iff_lt.mp this : p < 1)).symm + +/-- Qary entropy is strictly decreasing in the interval [1 - q⁻¹, 1]. -/ +lemma qaryEntropy_strictAntiOn (qLe2 : 2 ≤ q) : + StrictAntiOn (qaryEntropy q) (Icc (1 - 1/q) 1) := by + intro p1 hp1 p2 hp2 p1le2 + apply strictAntiOn_of_deriv_neg (convex_Icc (1 - 1/(q : ℝ)) 1) _ _ hp1 hp2 p1le2 + · 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_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)] + · field_simp + rw [← log_mul (by linarith) (by linarith)] + apply Real.strictMonoOn_log (mem_Ioi.mpr (show 0 < (↑q - 1) * (1 - p) by nlinarith)) + · simp_all only [mem_Ioi, mul_pos_iff_of_pos_left] + linarith + · have qpos : 0 < (q : ℝ) := by positivity + ring_nf + simp only [add_lt_iff_neg_right, neg_add_lt_iff_lt_add, add_zero, gt_iff_lt] + have : (q : ℝ) - 1 < p * q := by + have tmp := mul_lt_mul_of_pos_right hp.1 qpos + simp at tmp + have : (q : ℝ) ≠ 0 := (ne_of_lt qpos).symm + have asdfasfd : (1 - (q : ℝ)⁻¹) * ↑q = q - 1 := by calc (1 - (q : ℝ)⁻¹) * ↑q + _ = q - (q : ℝ)⁻¹ * (q : ℝ) := by ring + _ = q - 1 := by simp_all only [ne_eq, isUnit_iff_ne_zero, Rat.cast_eq_zero, + not_false_eq_true, IsUnit.inv_mul_cancel] + rwa [asdfasfd] at tmp + nlinarith + exact (ne_of_gt (lt_add_neg_iff_lt.mp zero_lt_1_sub_p : p < 1)).symm + +/-- Binary entropy is strictly increasing in interval [0, 1/2]. -/ +lemma binEntropy_strictMonoOn : StrictMonoOn binEntropy (Icc 0 2⁻¹) := by + rw [show Icc (0 : ℝ) 2⁻¹ = Icc 0 (1 - 1/2) by norm_num, ← qaryEntropy_two] + exact qaryEntropy_strictMonoOn (by rfl) + +/-- Binary entropy is strictly decreasing in interval [1/2, 1]. -/ +lemma binEntropy_strictAntiOn : StrictAntiOn binEntropy (Icc 2⁻¹ 1) := by + rw [show (Icc (2⁻¹ : ℝ) 1) = Icc (1/2) 1 by norm_num, ← qaryEntropy_two] + convert qaryEntropy_strictAntiOn (by rfl) using 1 + norm_num + +/-! ### Strict concavity of entropy -/ + +lemma strictConcaveOn_qaryEntropy : StrictConcaveOn ℝ (Icc 0 1) (qaryEntropy q) := by + apply strictConcaveOn_of_deriv2_neg (convex_Icc 0 1) qaryEntropy_continuous.continuousOn + intro p hp + rw [deriv2_qaryEntropy] + · simp_all only [interior_Icc, mem_Ioo] + apply div_neg_of_neg_of_pos + · norm_num [show 0 < log 2 by positivity] + · simp_all only [gt_iff_lt, mul_pos_iff_of_pos_left, sub_pos, hp] + +lemma strictConcave_binEntropy : StrictConcaveOn ℝ (Icc 0 1) binEntropy := + qaryEntropy_two ▸ strictConcaveOn_qaryEntropy + +end Real 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 352fd5d5ee08d..d5bc0c1f1b5ba 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/Arctan.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/Arctan.lean @@ -73,8 +73,8 @@ 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 [← le_div_iff' two_pos] + · rwa [← div_lt_iff₀' two_pos, neg_div] + · rwa [← le_div_iff₀' two_pos] @[simp, norm_cast] theorem ofReal_arctan (x : ℝ) : (Real.arctan x : ℂ) = arctan x := by diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean b/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean index 567ae939e14d0..b7b5fa601494d 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/Arg.lean @@ -107,7 +107,7 @@ theorem arg_cos_add_sin_mul_I {θ : ℝ} (hθ : θ ∈ Set.Ioc (-π) π) : arg ( lemma arg_exp_mul_I (θ : ℝ) : arg (exp (θ * I)) = toIocMod (mul_pos two_pos Real.pi_pos) (-π) θ := by convert arg_cos_add_sin_mul_I (θ := toIocMod (mul_pos two_pos Real.pi_pos) (-π) θ) _ using 2 - · rw [← exp_mul_I, eq_sub_of_add_eq $ toIocMod_add_toIocDiv_zsmul _ _ θ, ofReal_sub, + · rw [← exp_mul_I, eq_sub_of_add_eq <| toIocMod_add_toIocDiv_zsmul _ _ θ, ofReal_sub, ofReal_zsmul, ofReal_mul, ofReal_ofNat, exp_mul_I_periodic.sub_zsmul_eq] · convert toIocMod_mem_Ioc _ _ _ ring @@ -154,7 +154,7 @@ theorem arg_nonneg_iff {z : ℂ} : 0 ≤ arg z ↔ 0 ≤ z.im := by contrapose! intro h exact Real.sin_neg_of_neg_of_neg_pi_lt h (neg_pi_lt_arg _)⟩ - _ ↔ _ := by rw [sin_arg, le_div_iff (abs.pos h₀), zero_mul] + _ ↔ _ := by rw [sin_arg, le_div_iff₀ (abs.pos h₀), zero_mul] @[simp] theorem arg_neg_iff {z : ℂ} : arg z < 0 ↔ z.im < 0 := @@ -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) @@ -192,7 +192,7 @@ theorem arg_neg_I : arg (-I) = -(π / 2) := by simp [arg, le_refl] theorem tan_arg (x : ℂ) : Real.tan (arg x) = x.im / x.re := by by_cases h : x = 0 · simp only [h, zero_div, Complex.zero_im, Complex.arg_zero, Real.tan_zero, Complex.zero_re] - rw [Real.tan_eq_sin_div_cos, sin_arg, cos_arg h, div_div_div_cancel_right _ (abs.ne_zero h)] + rw [Real.tan_eq_sin_div_cos, sin_arg, cos_arg h, div_div_div_cancel_right₀ (abs.ne_zero h)] theorem arg_ofReal_of_nonneg {x : ℝ} (hx : 0 ≤ x) : arg x = 0 := by simp [arg, hx] @@ -312,7 +312,7 @@ lemma abs_eq_one_iff' : abs x = 1 ↔ ∃ θ ∈ Set.Ioc (-π) π, exp (θ * I) refine ⟨toIocMod (mul_pos two_pos Real.pi_pos) (-π) θ, ?_, ?_⟩ · convert toIocMod_mem_Ioc _ _ _ ring - · rw [eq_sub_of_add_eq $ toIocMod_add_toIocDiv_zsmul _ _ θ, ofReal_sub, + · rw [eq_sub_of_add_eq <| toIocMod_add_toIocDiv_zsmul _ _ θ, ofReal_sub, ofReal_zsmul, ofReal_mul, ofReal_ofNat, exp_mul_I_periodic.sub_zsmul_eq] · rintro ⟨θ, _, rfl⟩ exact ⟨θ, rfl⟩ @@ -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 @@ -598,7 +598,7 @@ theorem continuousAt_arg_coe_angle (h : x ≠ 0) : ContinuousAt ((↑) ∘ arg : · 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] + 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/Circle.lean b/Mathlib/Analysis/SpecialFunctions/Complex/Circle.lean index 0b7ee63908505..6ff1439a9f28c 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/Circle.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/Circle.lean @@ -29,7 +29,7 @@ theorem arg_eq_arg {z w : Circle} : arg z = arg w ↔ z = w := injective_arg.eq_iff theorem arg_exp {x : ℝ} (h₁ : -π < x) (h₂ : x ≤ π) : arg (exp x) = x := by - rw [exp_apply, exp_mul_I, arg_cos_add_sin_mul_I ⟨h₁, h₂⟩] + rw [coe_exp, exp_mul_I, arg_cos_add_sin_mul_I ⟨h₁, h₂⟩] @[simp] theorem exp_arg (z : Circle) : exp (arg z) = z := @@ -64,7 +64,7 @@ lemma invOn_arg_exp : InvOn (arg ∘ (↑)) exp (Ioc (-π) π) univ := argPartia lemma surjOn_exp_neg_pi_pi : SurjOn exp (Ioc (-π) π) univ := argPartialEquiv.symm.surjOn lemma exp_eq_exp {x y : ℝ} : exp x = exp y ↔ ∃ m : ℤ, x = y + m * (2 * π) := by - rw [Subtype.ext_iff, exp_apply, exp_apply, exp_eq_exp_iff_exists_int] + rw [Subtype.ext_iff, coe_exp, coe_exp, exp_eq_exp_iff_exists_int] refine exists_congr fun n => ?_ rw [← mul_assoc, ← add_mul, mul_left_inj' I_ne_zero] norm_cast @@ -73,6 +73,16 @@ lemma periodic_exp : Periodic exp (2 * π) := fun z ↦ exp_eq_exp.2 ⟨1, by rw @[simp] lemma exp_two_pi : exp (2 * π) = 1 := periodic_exp.eq.trans exp_zero +lemma exp_int_mul_two_pi (n : ℤ) : exp (n * (2 * π)) = 1 := + ext <| by simpa [mul_assoc] using Complex.exp_int_mul_two_pi_mul_I n + +lemma exp_two_pi_mul_int (n : ℤ) : exp (2 * π * n) = 1 := by + simpa only [mul_comm] using exp_int_mul_two_pi n + +lemma exp_eq_one {r : ℝ} : exp r = 1 ↔ ∃ n : ℤ, r = n * (2 * π) := by + simp [Circle.ext_iff, Complex.exp_eq_one_iff, ← mul_assoc, Complex.I_ne_zero, + ← Complex.ofReal_inj] + lemma exp_sub_two_pi (x : ℝ) : exp (x - 2 * π) = exp x := periodic_exp.sub_eq x lemma exp_add_two_pi (x : ℝ) : exp (x + 2 * π) = exp x := periodic_exp x @@ -115,7 +125,7 @@ lemma coe_toCircle (θ : Angle) : (θ.toCircle : ℂ) = θ.cos + θ.sin * I := b @[simp] lemma arg_toCircle (θ : Real.Angle) : (arg θ.toCircle : Angle) = θ := by induction θ using Real.Angle.induction_on - rw [toCircle_coe, Circle.exp_apply, exp_mul_I, ← ofReal_cos, ← ofReal_sin, ← + rw [toCircle_coe, Circle.coe_exp, exp_mul_I, ← ofReal_cos, ← ofReal_sin, ← Real.Angle.cos_coe, ← Real.Angle.sin_coe, arg_cos_add_sin_mul_I_coe_angle] @[deprecated (since := "2024-07-25")] alias expMapCircle := toCircle diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/CircleAddChar.lean b/Mathlib/Analysis/SpecialFunctions/Complex/CircleAddChar.lean index 02804c44f2602..b00a93b87b285 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/CircleAddChar.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/CircleAddChar.lean @@ -47,7 +47,7 @@ noncomputable def toCircle : AddChar (ZMod N) Circle := lemma toCircle_intCast (j : ℤ) : toCircle (j : ZMod N) = exp (2 * π * I * j / N) := by rw [toCircle, AddChar.compAddMonoidHom_apply, toCircle_addChar, AddChar.coe_mk, - AddCircle.toCircle, toAddCircle_intCast, Function.Periodic.lift_coe, Circle.exp_apply] + AddCircle.toCircle, toAddCircle_intCast, Function.Periodic.lift_coe, Circle.coe_exp] push_cast ring_nf diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/Log.lean b/Mathlib/Analysis/SpecialFunctions/Complex/Log.lean index 97e787098b93d..ad7f981e284ec 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/Log.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/Log.lean @@ -243,3 +243,69 @@ theorem _root_.Continuous.clog {f : α → ℂ} (h₁ : Continuous f) continuous_iff_continuousAt.2 fun x => h₁.continuousAt.clog (h₂ x) end LogDeriv + +section tsum_tprod + +variable {α ι: Type*} + +open Real + +lemma Real.HasSum_rexp_HasProd (f : ι → α → ℝ) (hfn : ∀ x n, 0 < f n x) + (hf : ∀ x : α, HasSum (fun n => log (f n x)) (∑' i, log (f i x))) (a : α) : + HasProd (fun b ↦ f b a) (∏' n : ι, (f n a)) := by + have : HasProd (fun b ↦ f b a) ((rexp ∘ fun a ↦ ∑' (n : ι), log (f n a)) a) := by + apply ((hf a).rexp).congr + intro _ + congr + exact funext fun x ↦ exp_log (hfn a x) + rwa [HasProd.tprod_eq this] + + +/--The exponential of a infinite sum of real logs (which converges absolutely) is an infinite +product.-/ +lemma Real.rexp_tsum_eq_tprod (f : ι → α → ℝ) (hfn : ∀ x n, 0 < f n x) + (hf : ∀ x : α, Summable fun n => log ((f n x))) : + (rexp ∘ (fun a : α => (∑' n : ι, log (f n a)))) = (fun a : α => ∏' n : ι, (f n a)) := by + ext a + apply (HasProd.tprod_eq ?_).symm + apply ((hf a).hasSum.rexp).congr + intro _ + congr + exact funext fun x ↦ exp_log (hfn a x) + +lemma Real.summable_cexp_multipliable (f : ι → α → ℝ) (hfn : ∀ x n, 0 < f n x) + (hf : ∀ x : α, Summable fun n => log (f n x)) (a : α): Multipliable fun b ↦ f b a := by + have := (Real.HasSum_rexp_HasProd f hfn fun a => (hf a).hasSum) a + use (∏' n : ι, (f n a)) + +open Complex + +lemma Complex.HasSum_cexp_HasProd (f : ι → α → ℂ) (hfn : ∀ x n, f n x ≠ 0) + (hf : ∀ x : α, HasSum (fun n => log (f n x)) (∑' i, log (f i x))) (a : α) : + HasProd (fun b ↦ f b a) (∏' n : ι, (f n a)) := by + have : HasProd (fun b ↦ f b a) ((cexp ∘ fun a ↦ ∑' (n : ι), log (f n a)) a) := by + apply ((hf a).cexp).congr + intro _ + congr + exact funext fun x ↦ exp_log (hfn a x) + rwa [HasProd.tprod_eq this] + +lemma Complex.summable_cexp_multipliable (f : ι → α → ℂ) (hfn : ∀ x n, f n x ≠ 0) + (hf : ∀ x : α, Summable fun n => log (f n x)) (a : α): + Multipliable fun b ↦ f b a := by + have := (Complex.HasSum_cexp_HasProd f hfn fun a => (hf a).hasSum) a + use (∏' n : ι, (f n a)) + +/--The exponential of a infinite sum of comples logs (which converges absolutely) is an infinite +product.-/ +lemma Complex.cexp_tsum_eq_tprod (f : ι → α → ℂ) (hfn : ∀ x n, f n x ≠ 0) + (hf : ∀ x : α, Summable fun n => log (f n x)) : + (cexp ∘ (fun a : α => (∑' n : ι, log (f n a)))) = (fun a : α => ∏' n : ι, ((f n a))) := by + ext a + apply (HasProd.tprod_eq ?_).symm + apply ((hf a).hasSum.cexp).congr + intro _ + congr + exact funext fun x ↦ exp_log (hfn a x) + +end tsum_tprod diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/LogBounds.lean b/Mathlib/Analysis/SpecialFunctions/Complex/LogBounds.lean index 695b5f7943f0f..f5e05a1e202df 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/LogBounds.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/LogBounds.lean @@ -60,7 +60,7 @@ def logTaylor (n : ℕ) : ℂ → ℂ := fun z ↦ ∑ j ∈ Finset.range n, (-1 lemma logTaylor_zero : logTaylor 0 = fun _ ↦ 0 := by funext - simp only [logTaylor, Finset.range_zero, Nat.odd_iff_not_even, Int.cast_pow, Int.cast_neg, + simp only [logTaylor, Finset.range_zero, ← Nat.not_even_iff_odd, Int.cast_pow, Int.cast_neg, Int.cast_one, Finset.sum_empty] lemma logTaylor_succ (n : ℕ) : @@ -79,10 +79,10 @@ lemma hasDerivAt_logTaylor (n : ℕ) (z : ℂ) : | zero => simp [logTaylor_succ, logTaylor_zero, Pi.add_def, hasDerivAt_const] | succ n ih => rw [logTaylor_succ] - simp only [cpow_natCast, Nat.cast_add, Nat.cast_one, Nat.odd_iff_not_even, + simp only [cpow_natCast, Nat.cast_add, Nat.cast_one, ← Nat.not_even_iff_odd, Finset.sum_range_succ, (show (-1) ^ (n + 1 + 1) = (-1) ^ n by ring)] refine HasDerivAt.add ih ?_ - simp only [Nat.odd_iff_not_even, Int.cast_pow, Int.cast_neg, Int.cast_one, mul_div_assoc] + simp only [← Nat.not_even_iff_odd, Int.cast_pow, Int.cast_neg, Int.cast_one, mul_div_assoc] have : HasDerivAt (fun x : ℂ ↦ (x ^ (n + 1) / (n + 1))) (z ^ n) z := by simp_rw [div_eq_mul_inv] convert HasDerivAt.mul_const (hasDerivAt_pow (n + 1) z) (((n : ℂ) + 1)⁻¹) using 1 @@ -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] @@ -188,7 +188,7 @@ lemma norm_log_one_add_le {z : ℂ} (hz : ‖z‖ < 1) : lemma norm_log_one_add_half_le_self {z : ℂ} (hz : ‖z‖ ≤ 1/2) : ‖(log (1 + z))‖ ≤ (3/2) * ‖z‖ := by apply le_trans (norm_log_one_add_le (lt_of_le_of_lt hz one_half_lt_one)) have hz3 : (1 - ‖z‖)⁻¹ ≤ 2 := by - rw [inv_eq_one_div, div_le_iff] + rw [inv_eq_one_div, div_le_iff₀] · linarith · linarith have hz4 : ‖z‖^2 * (1 - ‖z‖)⁻¹ / 2 ≤ ‖z‖/2 * 2 / 2 := by @@ -227,7 +227,7 @@ lemma hasSum_taylorSeries_log {z : ℂ} (hz : ‖z‖ < 1) : refine (hasSum_iff_tendsto_nat_of_summable_norm ?_).mpr ?_ · refine (summable_geometric_of_norm_lt_one hz).norm.of_nonneg_of_le (fun _ ↦ norm_nonneg _) ?_ intro n - simp only [norm_div, norm_mul, norm_pow, norm_neg, norm_one, one_pow, one_mul, norm_nat] + simp only [norm_div, norm_mul, norm_pow, norm_neg, norm_one, one_pow, one_mul, norm_natCast] rcases n.eq_zero_or_pos with rfl | hn · simp conv => enter [2]; rw [← div_one (‖z‖ ^ n)] diff --git a/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/ExpLog.lean b/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/ExpLog.lean index 4879f5d427b76..8c7bd3f605070 100644 --- a/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/ExpLog.lean +++ b/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/ExpLog.lean @@ -7,6 +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.ContinuousMap.StarOrdered /-! # The exponential and logarithm based on the continuous functional calculus @@ -74,14 +75,21 @@ end RCLikeNormed section RealNormed -variable {A : Type*} {p : A → Prop} [NormedRing A] [StarRing A] +variable {A : Type*} [NormedRing A] [StarRing A] [TopologicalRing A] [NormedAlgebra ℝ A] [CompleteSpace A] - [ContinuousFunctionalCalculus ℝ p] + [ContinuousFunctionalCalculus ℝ (IsSelfAdjoint : A → Prop)] -lemma real_exp_eq_normedSpace_exp {a : A} (ha : p a := by cfc_tac) : +lemma real_exp_eq_normedSpace_exp {a : A} (ha : IsSelfAdjoint a := by cfc_tac) : cfc Real.exp a = exp ℝ a := Real.exp_eq_exp_ℝ ▸ exp_eq_normedSpace_exp ha +@[aesop safe apply (rule_sets := [CStarAlgebra])] +lemma _root_.IsSelfAdjoint.exp_nonneg {𝕜 : Type*} [Field 𝕜] [Algebra 𝕜 A] + [PartialOrder A] [StarOrderedRing A] {a : A} (ha : IsSelfAdjoint a) : + 0 ≤ exp 𝕜 a := by + rw [exp_eq_exp 𝕜 ℝ, ← real_exp_eq_normedSpace_exp] + exact cfc_nonneg fun x _ => Real.exp_nonneg x + end RealNormed section ComplexNormed diff --git a/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Rpow.lean b/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Rpow.lean new file mode 100644 index 0000000000000..9fcf8e77c60a6 --- /dev/null +++ b/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Rpow.lean @@ -0,0 +1,377 @@ +/- +Copyright (c) 2024 Frédéric Dupuis. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Frédéric Dupuis +-/ + +import Mathlib.Analysis.SpecialFunctions.Pow.Real +import Mathlib.Analysis.Normed.Algebra.Spectrum +import Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.NonUnital + +/-! +# Real powers defined via the continuous functional calculus + +This file defines real powers via the continuous functional calculus (CFC) and builds its API. +This allows one to take real powers of matrices, operators, elements of a C⋆-algebra, etc. The +square root is also defined via the non-unital CFC. + +## Main declarations + ++ `CFC.nnrpow`: the `ℝ≥0` power function based on the non-unital CFC, i.e. `cfcₙ NNReal.rpow` + composed with `(↑) : ℝ≥0 → ℝ`. ++ `CFC.sqrt`: the square root function based on the non-unital CFC, i.e. `cfcₙ NNReal.sqrt` ++ `CFC.rpow`: the real power function based on the unital CFC, i.e. `cfc NNReal.rpow` + +## Implementation notes + +We define two separate versions `CFC.nnrpow` and `CFC.rpow` due to what happens at 0. Since +`NNReal.rpow 0 0 = 1`, this means that this function does not map zero to zero when the exponent +is zero, and hence `CFC.nnrpow a 0 = 0` whereas `CFC.rpow a 0 = 1`. Note that the non-unital version +only makes sense for nonnegative exponents, and hence we define it such that the exponent is in +`ℝ≥0`. + +## Notation + ++ We define a `Pow A ℝ` instance for `CFC.rpow`, i.e `a ^ y` with `A` an operator and `y : ℝ` works + as expected. Likewise, we define a `Pow A ℝ≥0` instance for `CFC.nnrpow`. Note that these are + low-priority instances, in order to avoid overriding instances such as `Pow ℝ ℝ`. + +## TODO + ++ Relate these to the log and exp functions ++ Lemmas about how these functions interact with commuting `a` and `b`. ++ Prove the order properties (operator monotonicity and concavity/convexity) +-/ + +open scoped NNReal + +namespace NNReal + +/-- Taking a nonnegative power of a nonnegative number. This is defined as a standalone definition +in order to speed up automation such as `cfc_cont_tac`. -/ +noncomputable abbrev nnrpow (a : ℝ≥0) (b : ℝ≥0) : ℝ≥0 := a ^ (b : ℝ) + +@[simp] lemma nnrpow_def (a b : ℝ≥0) : nnrpow a b = a ^ (b : ℝ) := rfl + +@[fun_prop] +lemma continuous_nnrpow_const (y : ℝ≥0) : Continuous (nnrpow · y) := + continuous_rpow_const zero_le_coe + +/- This is a "redeclaration" of the attribute to speed up the proofs in this file. -/ +attribute [fun_prop] continuousOn_rpow_const + +end NNReal + +namespace CFC + +section NonUnital + +variable {A : Type*} [PartialOrder A] [NonUnitalNormedRing A] [StarRing A] + [Module ℝ≥0 A] [SMulCommClass ℝ≥0 A A] [IsScalarTower ℝ≥0 A A] + [NonUnitalContinuousFunctionalCalculus ℝ≥0 (fun (a : A) => 0 ≤ a)] + +/- ## `nnrpow` -/ + +/-- Real powers of operators, based on the non-unital continuous functional calculus. -/ +noncomputable def nnrpow (a : A) (y : ℝ≥0) : A := cfcₙ (NNReal.nnrpow · y) a + +/-- Enable `a ^ y` notation for `CFC.nnrpow`. This is a low-priority instance to make sure it does +not take priority over other instances when they are available. -/ +noncomputable instance (priority := 100) : Pow A ℝ≥0 where + pow a y := nnrpow a y + +@[simp] +lemma nnrpow_eq_pow {a : A} {y : ℝ≥0} : nnrpow a y = a ^ y := rfl + +@[simp] +lemma nnrpow_nonneg {a : A} {x : ℝ≥0} : 0 ≤ a ^ x := cfcₙ_predicate _ a + +lemma nnrpow_def {a : A} {y : ℝ≥0} : a ^ y = cfcₙ (NNReal.nnrpow · y) a := rfl + +lemma nnrpow_add {a : A} {x y : ℝ≥0} (hx : 0 < x) (hy : 0 < y) : + a ^ (x + y) = a ^ x * a ^ y := by + simp only [nnrpow_def] + rw [← cfcₙ_mul _ _ a] + congr! 2 with z + exact mod_cast z.rpow_add' <| ne_of_gt (add_pos hx hy) + +@[simp] +lemma nnrpow_zero {a : A} : a ^ (0 : ℝ≥0) = 0 := by + simp [nnrpow_def, cfcₙ_apply_of_not_map_zero] + +lemma nnrpow_one (a : A) (ha : 0 ≤ a := by cfc_tac) : a ^ (1 : ℝ≥0) = a := by + simp only [nnrpow_def, NNReal.nnrpow_def, NNReal.coe_one, NNReal.rpow_one] + change cfcₙ (id : ℝ≥0 → ℝ≥0) a = a + rw [cfcₙ_id ℝ≥0 a] + +lemma nnrpow_two (a : A) (ha : 0 ≤ a := by cfc_tac) : a ^ (2 : ℝ≥0) = a * a := by + simp only [nnrpow_def, NNReal.nnrpow_def, NNReal.coe_ofNat, NNReal.rpow_ofNat, pow_two] + change cfcₙ (fun z : ℝ≥0 => id z * id z) a = a * a + rw [cfcₙ_mul id id a, cfcₙ_id ℝ≥0 a] + +lemma nnrpow_three (a : A) (ha : 0 ≤ a := by cfc_tac) : a ^ (3 : ℝ≥0) = a * a * a := by + simp only [nnrpow_def, NNReal.nnrpow_def, NNReal.coe_ofNat, NNReal.rpow_ofNat, pow_three] + change cfcₙ (fun z : ℝ≥0 => id z * (id z * id z)) a = a * a * a + rw [cfcₙ_mul id _ a, cfcₙ_mul id _ a, ← mul_assoc, cfcₙ_id ℝ≥0 a] + +@[simp] +lemma zero_nnrpow {x : ℝ≥0} : (0 : A) ^ x = 0 := by simp [nnrpow_def] + +@[simp] +lemma nnrpow_nnrpow [UniqueNonUnitalContinuousFunctionalCalculus ℝ≥0 A] + {a : A} {x y : ℝ≥0} : (a ^ x) ^ y = a ^ (x * y) := by + by_cases ha : 0 ≤ a + case pos => + obtain (rfl | hx) := eq_zero_or_pos x <;> obtain (rfl | hy) := eq_zero_or_pos y + all_goals try simp + simp only [nnrpow_def, NNReal.coe_mul] + rw [← cfcₙ_comp _ _ a] + congr! 2 with u + ext + simp [Real.rpow_mul] + case neg => + simp [nnrpow_def, cfcₙ_apply_of_not_predicate a ha] + +lemma nnrpow_nnrpow_inv [UniqueNonUnitalContinuousFunctionalCalculus ℝ≥0 A] + (a : A) {x : ℝ≥0} (hx : x ≠ 0) (ha : 0 ≤ a := by cfc_tac) : (a ^ x) ^ x⁻¹ = a := by + simp [mul_inv_cancel₀ hx, nnrpow_one _ ha] + +lemma nnrpow_inv_nnrpow [UniqueNonUnitalContinuousFunctionalCalculus ℝ≥0 A] + (a : A) {x : ℝ≥0} (hx : x ≠ 0) (ha : 0 ≤ a := by cfc_tac) : (a ^ x⁻¹) ^ x = a := by + simp [inv_mul_cancel₀ hx, nnrpow_one _ ha] + +lemma nnrpow_inv_eq [UniqueNonUnitalContinuousFunctionalCalculus ℝ≥0 A] + (a b : A) {x : ℝ≥0} (hx : x ≠ 0) (ha : 0 ≤ a := by cfc_tac) (hb : 0 ≤ b := by cfc_tac) : + a ^ x⁻¹ = b ↔ b ^ x = a := + ⟨fun h ↦ nnrpow_inv_nnrpow a hx ▸ congr($(h) ^ x).symm, + fun h ↦ nnrpow_nnrpow_inv b hx ▸ congr($(h) ^ x⁻¹).symm⟩ + +/- ## `sqrt` -/ + +section sqrt + +/-- Square roots of operators, based on the non-unital continuous functional calculus. -/ +noncomputable def sqrt (a : A) : A := cfcₙ NNReal.sqrt a + +@[simp] +lemma sqrt_nonneg {a : A} : 0 ≤ sqrt a := cfcₙ_predicate _ a + +lemma sqrt_eq_nnrpow {a : A} : sqrt a = a ^ (1 / 2 : ℝ≥0) := by + simp only [sqrt, nnrpow, NNReal.coe_inv, NNReal.coe_ofNat, NNReal.rpow_eq_pow] + congr + ext + exact_mod_cast NNReal.sqrt_eq_rpow _ + +@[simp] +lemma sqrt_zero : sqrt (0 : A) = 0 := by simp [sqrt] + +variable [UniqueNonUnitalContinuousFunctionalCalculus ℝ≥0 A] + +@[simp] +lemma nnrpow_sqrt {a : A} {x : ℝ≥0} : (sqrt a) ^ x = a ^ (x / 2) := by + rw [sqrt_eq_nnrpow, nnrpow_nnrpow, one_div_mul_eq_div 2 x] + +lemma nnrpow_sqrt_two (a : A) (ha : 0 ≤ a := by cfc_tac) : (sqrt a) ^ (2 : ℝ≥0) = a := by + simp only [nnrpow_sqrt, ne_eq, OfNat.ofNat_ne_zero, not_false_eq_true, div_self] + rw [nnrpow_one a] + +lemma sqrt_mul_sqrt_self (a : A) (ha : 0 ≤ a := by cfc_tac) : sqrt a * sqrt a = a := by + rw [← nnrpow_two _, nnrpow_sqrt_two _] + +@[simp] +lemma sqrt_nnrpow {a : A} {x : ℝ≥0} : sqrt (a ^ x) = a ^ (x / 2) := by + simp [sqrt_eq_nnrpow, div_eq_mul_inv] + +lemma sqrt_nnrpow_two (a : A) (ha : 0 ≤ a := by cfc_tac) : sqrt (a ^ (2 : ℝ≥0)) = a := by + simp only [sqrt_nnrpow, ne_eq, OfNat.ofNat_ne_zero, not_false_eq_true, div_self] + rw [nnrpow_one _] + +lemma sqrt_mul_self (a : A) (ha : 0 ≤ a := by cfc_tac) : sqrt (a * a) = a := by + rw [← nnrpow_two _, sqrt_nnrpow_two _] + +lemma mul_self_eq {a b : A} (h : sqrt a = b) (ha : 0 ≤ a := by cfc_tac) : + b * b = a := + h ▸ sqrt_mul_sqrt_self _ ha + +lemma sqrt_unique {a b : A} (h : b * b = a) (hb : 0 ≤ b := by cfc_tac) : + sqrt a = b := + h ▸ sqrt_mul_self b + +lemma sqrt_eq_iff (a b : A) (ha : 0 ≤ a := by cfc_tac) (hb : 0 ≤ b := by cfc_tac) : + sqrt a = b ↔ b * b = a := + ⟨(mul_self_eq ·), (sqrt_unique ·)⟩ + +end sqrt + +end NonUnital + +section Unital + +variable {A : Type*} [PartialOrder A] [NormedRing A] [StarRing A] + [NormedAlgebra ℝ A] [ContinuousFunctionalCalculus ℝ≥0 (fun (a : A) => 0 ≤ a)] + +/- ## `rpow` -/ + +/-- Real powers of operators, based on the unital continuous functional calculus. -/ +noncomputable def rpow (a : A) (y : ℝ) : A := cfc (fun x : ℝ≥0 => x ^ y) a + +/-- Enable `a ^ y` notation for `CFC.rpow`. This is a low-priority instance to make sure it does +not take priority over other instances when they are available (such as `Pow ℝ ℝ`). -/ +noncomputable instance (priority := 100) : Pow A ℝ where + pow a y := rpow a y + +@[simp] +lemma rpow_eq_pow {a : A} {y : ℝ} : rpow a y = a ^ y := rfl + +@[simp] +lemma rpow_nonneg {a : A} {y : ℝ} : 0 ≤ a ^ y := cfc_predicate _ a + +lemma rpow_def {a : A} {y : ℝ} : a ^ y = cfc (fun x : ℝ≥0 => x ^ y) a := rfl + +lemma rpow_one (a : A) (ha : 0 ≤ a := by cfc_tac) : a ^ (1 : ℝ) = a := by + simp only [rpow_def, NNReal.coe_one, NNReal.rpow_eq_pow, NNReal.rpow_one, cfc_id' ℝ≥0 a] + +@[simp] +lemma one_rpow {x : ℝ} : (1 : A) ^ x = (1 : A) := by simp [rpow_def] + +lemma rpow_zero (a : A) (ha : 0 ≤ a := by cfc_tac) : a ^ (0 : ℝ) = 1 := by + simp [rpow_def, cfc_const_one ℝ≥0 a] + +lemma zero_rpow {x : ℝ} (hx : x ≠ 0) : rpow (0 : A) x = 0 := by simp [rpow, NNReal.zero_rpow hx] + +lemma rpow_natCast (a : A) (n : ℕ) (ha : 0 ≤ a := by cfc_tac) : a ^ (n : ℝ) = a ^ n := by + rw [← cfc_pow_id (R := ℝ≥0) a n, rpow_def] + congr + simp + +@[simp] +lemma rpow_algebraMap {x : ℝ≥0} {y : ℝ} : + (algebraMap ℝ≥0 A x) ^ y = algebraMap ℝ≥0 A (x ^ y) := by + rw [rpow_def, cfc_algebraMap ..] + +lemma rpow_add {a : A} {x y : ℝ} (ha : 0 ∉ spectrum ℝ≥0 a) : + a ^ (x + y) = a ^ x * a ^ y := by + simp only [rpow_def, NNReal.rpow_eq_pow] + rw [← cfc_mul _ _ a] + refine cfc_congr ?_ + intro z hz + have : z ≠ 0 := by aesop + simp [NNReal.rpow_add this _ _] + +-- TODO: relate to a strict positivity condition +lemma rpow_rpow [UniqueContinuousFunctionalCalculus ℝ≥0 A] + (a : A) (x y : ℝ) (ha₁ : 0 ∉ spectrum ℝ≥0 a) (hx : x ≠ 0) (ha₂ : 0 ≤ a := by cfc_tac) : + (a ^ x) ^ y = a ^ (x * y) := by + simp only [rpow_def] + rw [← cfc_comp _ _ a ha₂] + refine cfc_congr fun _ _ => ?_ + simp [NNReal.rpow_mul] + +lemma rpow_rpow_of_exponent_nonneg [UniqueContinuousFunctionalCalculus ℝ≥0 A] (a : A) (x y : ℝ) + (hx : 0 ≤ x) (hy : 0 ≤ y) (ha₂ : 0 ≤ a := by cfc_tac) : (a ^ x) ^ y = a ^ (x * y) := by + simp only [rpow_def] + rw [← cfc_comp _ _ a] + refine cfc_congr fun _ _ => ?_ + simp [NNReal.rpow_mul] + +lemma rpow_mul_rpow_neg {a : A} (x : ℝ) (ha : 0 ∉ spectrum ℝ≥0 a) + (ha' : 0 ≤ a := by cfc_tac) : a ^ x * a ^ (-x) = 1 := by + rw [← rpow_add ha, add_neg_cancel, rpow_zero a] + +lemma rpow_neg_mul_rpow {a : A} (x : ℝ) (ha : 0 ∉ spectrum ℝ≥0 a) + (ha' : 0 ≤ a := by cfc_tac) : a ^ (-x) * a ^ x = 1 := by + rw [← rpow_add ha, neg_add_cancel, rpow_zero a] + +lemma rpow_neg_one_eq_inv (a : Aˣ) (ha : (0 : A) ≤ a := by cfc_tac) : + a ^ (-1 : ℝ) = (↑a⁻¹ : A) := by + 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 [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 + rw [← cfc_inv_id (R := ℝ≥0) a, rpow_def, rpow_def, + ← cfc_comp' (fun z => z ^ x) (Inv.inv : ℝ≥0 → ℝ≥0) (a : A) h₁] + refine cfc_congr fun _ _ => ?_ + simp [NNReal.rpow_neg, NNReal.inv_rpow] + refine NNReal.continuousOn_rpow_const (.inl ?_) + rintro ⟨z, hz, hz'⟩ + exact spectrum.zero_not_mem ℝ≥0 a.isUnit <| inv_eq_zero.mp hz' ▸ hz + +lemma rpow_intCast (a : Aˣ) (n : ℤ) (ha : (0 : A) ≤ a := by cfc_tac) : + (a : A) ^ (n : ℝ) = (↑(a ^ n) : A) := by + rw [← cfc_zpow (R := ℝ≥0) a n, rpow_def] + refine cfc_congr fun _ _ => ?_ + simp + +section unital_vs_nonunital + +variable [∀ (a : A), CompactSpace (spectrum ℝ a)] + [UniqueNonUnitalContinuousFunctionalCalculus ℝ≥0 A] + +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] + +lemma sqrt_eq_rpow {a : A} : sqrt a = a ^ (1 / 2 : ℝ) := by + have : a ^ (1 / 2 : ℝ) = a ^ ((1 / 2 : ℝ≥0) : ℝ) := rfl + rw [this, ← nnrpow_eq_rpow (by norm_num), sqrt_eq_nnrpow (A := A)] + +lemma sqrt_eq_cfc {a : A} : sqrt a = cfc NNReal.sqrt a := by + unfold sqrt + rw [cfcₙ_eq_cfc] + +lemma sqrt_sq (a : A) (ha : 0 ≤ a := by cfc_tac) : sqrt (a ^ 2) = a := by + rw [pow_two, sqrt_mul_self (A := A) a] + +lemma sq_sqrt (a : A) (ha : 0 ≤ a := by cfc_tac) : (sqrt a) ^ 2 = a := by + rw [pow_two, sqrt_mul_sqrt_self (A := A) a] + +@[simp] +lemma sqrt_algebraMap {r : ℝ≥0} : sqrt (algebraMap ℝ≥0 A r) = algebraMap ℝ≥0 A (NNReal.sqrt r) := by + rw [sqrt_eq_cfc, cfc_algebraMap] + +@[simp] +lemma sqrt_one : sqrt (1 : A) = 1 := by simp [sqrt_eq_cfc] + +-- TODO: relate to a strict positivity condition +lemma sqrt_rpow [UniqueContinuousFunctionalCalculus ℝ≥0 A] {a : A} {x : ℝ} (h : 0 ∉ spectrum ℝ≥0 a) + (hx : x ≠ 0) : sqrt (a ^ x) = a ^ (x / 2) := by + by_cases hnonneg : 0 ≤ a + case pos => + simp only [sqrt_eq_rpow, div_eq_mul_inv, one_mul, rpow_rpow _ _ _ h hx] + case neg => + simp [sqrt_eq_cfc, rpow_def, cfc_apply_of_not_predicate a hnonneg] + +-- TODO: relate to a strict positivity condition +lemma rpow_sqrt [UniqueContinuousFunctionalCalculus ℝ≥0 A] (a : A) (x : ℝ) (h : 0 ∉ spectrum ℝ≥0 a) + (ha : 0 ≤ a := by cfc_tac) : (sqrt a) ^ x = a ^ (x / 2) := by + rw [sqrt_eq_rpow, div_eq_mul_inv, one_mul, + rpow_rpow _ _ _ h (by norm_num), inv_mul_eq_div] + +lemma sqrt_rpow_nnreal {a : A} {x : ℝ≥0} : sqrt (a ^ (x : ℝ)) = a ^ (x / 2 : ℝ) := by + by_cases htriv : 0 ≤ a + case neg => simp [sqrt_eq_cfc, rpow_def, cfc_apply_of_not_predicate a htriv] + case pos => + by_cases hx : x = 0 + case pos => simp [hx, rpow_zero _ htriv] + case neg => + have h₁ : 0 < x := lt_of_le_of_ne (by aesop) (Ne.symm hx) + have h₂ : (x : ℝ) / 2 = NNReal.toReal (x / 2) := rfl + have h₃ : 0 < x / 2 := by positivity + rw [← nnrpow_eq_rpow h₁, h₂, ← nnrpow_eq_rpow h₃, sqrt_nnrpow (A := A)] + +lemma rpow_sqrt_nnreal [UniqueContinuousFunctionalCalculus ℝ≥0 A] {a : A} {x : ℝ≥0} + (ha : 0 ≤ a := by cfc_tac) : (sqrt a) ^ (x : ℝ) = a ^ (x / 2 : ℝ) := by + by_cases hx : x = 0 + case pos => + have ha' : 0 ≤ sqrt a := by exact sqrt_nonneg + simp [hx, rpow_zero _ ha', rpow_zero _ ha] + case neg => + have h₁ : 0 ≤ (x : ℝ) := by exact NNReal.zero_le_coe + rw [sqrt_eq_rpow, rpow_rpow_of_exponent_nonneg _ _ _ (by norm_num) h₁, one_div_mul_eq_div] + +end unital_vs_nonunital + +end Unital + +end CFC diff --git a/Mathlib/Analysis/SpecialFunctions/Exp.lean b/Mathlib/Analysis/SpecialFunctions/Exp.lean index 33170348b5f1f..8d018a967ecb0 100644 --- a/Mathlib/Analysis/SpecialFunctions/Exp.lean +++ b/Mathlib/Analysis/SpecialFunctions/Exp.lean @@ -162,7 +162,7 @@ lemma exp_sub_sum_range_isBigO_pow (n : ℕ) : (fun x ↦ exp x - ∑ i ∈ Finset.range n, x ^ i / i !) =O[𝓝 0] (· ^ n) := by have := (Complex.exp_sub_sum_range_isBigO_pow n).comp_tendsto (Complex.continuous_ofReal.tendsto' 0 0 rfl) - simp only [(· ∘ ·)] at this + simp only [Function.comp_def] at this norm_cast at this lemma exp_sub_sum_range_succ_isLittleO_pow (n : ℕ) : @@ -213,7 +213,7 @@ namespace Real variable {α : Type*} {x y z : ℝ} {l : Filter α} theorem exp_half (x : ℝ) : exp (x / 2) = √(exp x) := by - rw [eq_comm, sqrt_eq_iff_sq_eq, sq, ← exp_add, add_halves] <;> exact (exp_pos _).le + rw [eq_comm, sqrt_eq_iff_eq_sq, sq, ← exp_add, add_halves] <;> exact (exp_pos _).le /-- The real exponential function tends to `+∞` at `+∞`. -/ theorem tendsto_exp_atTop : Tendsto exp atTop atTop := by @@ -242,7 +242,7 @@ theorem tendsto_exp_atBot : Tendsto exp atBot (𝓝 0) := congr_arg exp <| neg_neg x theorem tendsto_exp_atBot_nhdsWithin : Tendsto exp atBot (𝓝[>] 0) := - tendsto_inf.2 ⟨tendsto_exp_atBot, tendsto_principal.2 <| eventually_of_forall exp_pos⟩ + tendsto_inf.2 ⟨tendsto_exp_atBot, tendsto_principal.2 <| Eventually.of_forall exp_pos⟩ @[simp] theorem isBoundedUnder_ge_exp_comp (l : Filter α) (f : α → ℝ) : @@ -263,11 +263,11 @@ 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 - rw [Set.mem_Ici, le_div_iff (pow_pos hx₀ _), ← le_div_iff' hC₀] + rw [Set.mem_Ici, le_div_iff₀ (pow_pos hx₀ _), ← le_div_iff₀' hC₀] calc x ^ n ≤ ⌈x⌉₊ ^ n := mod_cast pow_le_pow_left hx₀.le (Nat.le_ceil _) _ _ ≤ exp ⌈x⌉₊ / (exp 1 * C) := mod_cast (hN _ (Nat.lt_ceil.2 hx).le).le @@ -315,8 +315,8 @@ theorem tendsto_div_pow_mul_exp_add_atTop (b c : ℝ) (n : ℕ) (hb : 0 ≠ b) : def expOrderIso : ℝ ≃o Ioi (0 : ℝ) := StrictMono.orderIsoOfSurjective _ (exp_strictMono.codRestrict exp_pos) <| (continuous_exp.subtype_mk _).surjective - (by simp only [tendsto_Ioi_atTop, Subtype.coe_mk, tendsto_exp_atTop]) - (by simp [tendsto_exp_atBot_nhdsWithin]) + (by rw [tendsto_Ioi_atTop]; simp only [tendsto_exp_atTop]) + (by rw [tendsto_Ioi_atBot]; simp only [tendsto_exp_atBot_nhdsWithin]) @[simp] theorem coe_expOrderIso_apply (x : ℝ) : (expOrderIso x : ℝ) = exp x := @@ -387,7 +387,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 x => exp_ne_zero _) <| by simp only [norm_eq_abs, abs_exp, ← exp_sub, isBoundedUnder_le_exp_comp, Pi.sub_def] @[simp] @@ -456,14 +456,14 @@ namespace Complex theorem comap_exp_cobounded : comap exp (cobounded ℂ) = comap re atTop := calc comap exp (cobounded ℂ) = comap re (comap Real.exp atTop) := by - simp only [← comap_norm_atTop, Complex.norm_eq_abs, comap_comap, (· ∘ ·), abs_exp] + simp only [← comap_norm_atTop, Complex.norm_eq_abs, comap_comap, Function.comp_def, abs_exp] _ = comap re atTop := by rw [Real.comap_exp_atTop] @[simp] theorem comap_exp_nhds_zero : comap exp (𝓝 0) = comap re atBot := calc comap exp (𝓝 0) = comap re (comap Real.exp (𝓝 0)) := by - simp only [comap_comap, ← comap_abs_nhds_zero, (· ∘ ·), abs_exp] + simp only [comap_comap, ← comap_abs_nhds_zero, Function.comp_def, abs_exp] _ = comap re atBot := by rw [Real.comap_exp_nhds_zero] theorem comap_exp_nhdsWithin_zero : comap exp (𝓝[≠] 0) = comap re atBot := by diff --git a/Mathlib/Analysis/SpecialFunctions/ExpDeriv.lean b/Mathlib/Analysis/SpecialFunctions/ExpDeriv.lean index 4079b96dab467..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,16 +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 n ihn - · exact contDiff_zero.2 continuous_exp - · 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 @@ -155,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 @@ -168,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 10561370fb1a4..86b3f777ce844 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gamma/Basic.lean @@ -258,7 +258,7 @@ noncomputable def GammaAux : ℕ → ℂ → ℂ theorem GammaAux_recurrence1 (s : ℂ) (n : ℕ) (h1 : -s.re < ↑n) : GammaAux n s = GammaAux n (s + 1) / s := by induction' n with n hn generalizing s - · simp only [Nat.zero_eq, CharP.cast_eq_zero, Left.neg_neg_iff] at h1 + · simp only [CharP.cast_eq_zero, Left.neg_neg_iff] at h1 dsimp only [GammaAux]; rw [GammaIntegral_add_one h1] rw [mul_comm, mul_div_cancel_right₀]; contrapose! h1; rw [h1] simp @@ -271,7 +271,7 @@ theorem GammaAux_recurrence1 (s : ℂ) (n : ℕ) (h1 : -s.re < ↑n) : theorem GammaAux_recurrence2 (s : ℂ) (n : ℕ) (h1 : -s.re < ↑n) : GammaAux n s = GammaAux (n + 1) s := by cases' n with n n - · simp only [Nat.zero_eq, CharP.cast_eq_zero, Left.neg_neg_iff] at h1 + · simp only [CharP.cast_eq_zero, Left.neg_neg_iff] at h1 dsimp only [GammaAux] rw [GammaIntegral_add_one h1, mul_div_cancel_left₀] rintro rfl @@ -343,9 +343,10 @@ theorem Gamma_zero : Gamma 0 = 0 := by /-- At `-n` for `n ∈ ℕ`, the Gamma function is undefined; by convention we assign it the value 0. -/ theorem Gamma_neg_nat_eq_zero (n : ℕ) : Gamma (-n) = 0 := by - induction' n with n IH - · rw [Nat.cast_zero, neg_zero, Gamma_zero] - · have A : -(n.succ : ℂ) ≠ 0 := by + induction n with + | zero => rw [Nat.cast_zero, neg_zero, Gamma_zero] + | succ n IH => + have A : -(n.succ : ℂ) ≠ 0 := by rw [neg_ne_zero, Nat.cast_ne_zero] apply Nat.succ_ne_zero have : -(n : ℂ) = -↑n.succ + 1 := by simp @@ -357,9 +358,10 @@ theorem Gamma_conj (s : ℂ) : Gamma (conj s) = conj (Gamma s) := by suffices ∀ (n : ℕ) (s : ℂ), GammaAux n (conj s) = conj (GammaAux n s) by simp [Gamma, this] intro n - induction' n with n IH - · rw [GammaAux]; exact GammaIntegral_conj - · intro s + induction n with + | zero => rw [GammaAux]; exact GammaIntegral_conj + | succ n IH => + intro s rw [GammaAux] dsimp only rw [div_eq_mul_inv _ s, RingHom.map_mul, conj_inv, ← div_eq_mul_inv] @@ -459,7 +461,7 @@ end GammaHasDeriv 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) + (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] @@ -551,8 +553,7 @@ lemma integral_rpow_mul_exp_neg_mul_Ioi {a r : ℝ} (ha : 0 < a) (hr : 0 < r) : 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 ↦ ?_) 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`. -/ @@ -580,11 +581,13 @@ theorem Gamma_ne_zero {s : ℝ} (hs : ∀ m : ℕ, s ≠ -m) : Gamma s ≠ 0 := rw [neg_lt, Nat.cast_add, Nat.cast_one] exact Nat.lt_floor_add_one _ intro n - induction' n with _ n_ih generalizing s - · intro hs + induction n generalizing s with + | zero => + intro hs refine (Gamma_pos_of_pos ?_).ne' rwa [Nat.cast_zero, neg_zero] at hs - · intro hs' + | succ _ n_ih => + intro hs' have : Gamma (s + 1) ≠ 0 := by apply n_ih · intro m diff --git a/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean b/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean index 486e57156cc16..f449779354eda 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gamma/Beta.lean @@ -123,7 +123,7 @@ theorem betaIntegral_scaled (s t : ℂ) {a : ℝ} (ha : 0 < a) : push_cast rw [mul_sub, mul_one, mul_div_cancel₀ _ ha'] -/-- Relation between Beta integral and Gamma function. -/ +/-- Relation between Beta integral and Gamma function. -/ theorem Gamma_mul_Gamma_eq_betaIntegral {s t : ℂ} (hs : 0 < re s) (ht : 0 < re t) : Gamma s * Gamma t = Gamma (s + t) * betaIntegral s t := by -- Note that we haven't proved (yet) that the Gamma function has no zeroes, so we can't formulate @@ -183,11 +183,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 @@ -270,7 +270,7 @@ theorem GammaSeq_eq_approx_Gamma_integral {s : ℂ} (hs : 0 < re s) {n : ℕ} (h mul_cpow_ofReal_nonneg hx.1.le (Nat.cast_pos.mpr (Nat.pos_of_ne_zero hn)).le] rw [A, B, cpow_natCast]; ring -/-- The main techical lemma for `GammaSeq_tendsto_Gamma`, expressing the integral defining the +/-- The main technical lemma for `GammaSeq_tendsto_Gamma`, expressing the integral defining the Gamma function for `0 < re s` as the limit of a sequence of integrals over finite intervals. -/ theorem approx_Gamma_integral_tendsto_Gamma_integral {s : ℂ} (hs : 0 < re s) : Tendsto (fun n : ℕ => ∫ x : ℝ in (0)..n, ((1 - x / n) ^ n : ℝ) * (x : ℂ) ^ (s - 1)) atTop @@ -328,7 +328,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 @@ -350,7 +350,7 @@ theorem GammaSeq_tendsto_Gamma (s : ℂ) : Tendsto (GammaSeq s) atTop (𝓝 <| G rw [Nat.cast_zero, neg_zero] at hs rw [← Gamma_eq_GammaAux] · refine Tendsto.congr' ?_ (approx_Gamma_integral_tendsto_Gamma_integral hs) - refine (eventually_ne_atTop 0).mp (eventually_of_forall fun n hn => ?_) + refine (eventually_ne_atTop 0).mp (Eventually.of_forall fun n hn => ?_) exact (GammaSeq_eq_approx_Gamma_integral hs hn).symm · rwa [Nat.cast_zero, neg_lt_zero] · -- Induction step: use recurrence formulae in `s` for Gamma and GammaSeq @@ -358,7 +358,7 @@ theorem GammaSeq_tendsto_Gamma (s : ℂ) : Tendsto (GammaSeq s) atTop (𝓝 <| G rw [Nat.cast_succ, neg_add, ← sub_eq_add_neg, sub_lt_iff_lt_add, ← one_re, ← add_re] at hs rw [GammaAux] have := @Tendsto.congr' _ _ _ ?_ _ _ - ((eventually_ne_atTop 0).mp (eventually_of_forall fun n hn => ?_)) ((IH _ hs).div_const s) + ((eventually_ne_atTop 0).mp (Eventually.of_forall fun n hn => ?_)) ((IH _ hs).div_const s) pick_goal 3; · exact GammaSeq_add_one_left s hn -- doesn't work if inlined? conv at this => arg 1; intro n; rw [mul_comm] rwa [← mul_one (GammaAux m (s + 1) / s), tendsto_mul_iff_of_ne_zero _ (one_ne_zero' ℂ)] at this @@ -407,7 +407,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 @@ -416,7 +416,7 @@ theorem Gamma_mul_Gamma_one_sub (z : ℂ) : Gamma z * Gamma (1 - z) = π / sin ( Complex.Gamma_neg_nat_eq_zero, mul_zero] refine tendsto_nhds_unique ((GammaSeq_tendsto_Gamma z).mul (GammaSeq_tendsto_Gamma <| 1 - z)) ?_ have : ↑π / sin (↑π * z) = 1 * (π / sin (π * z)) := by rw [one_mul] - convert Tendsto.congr' ((eventually_ne_atTop 0).mp (eventually_of_forall fun n hn => + convert Tendsto.congr' ((eventually_ne_atTop 0).mp (Eventually.of_forall fun n hn => (GammaSeq_mul z hn).symm)) (Tendsto.mul _ _) · convert tendsto_natCast_div_add_atTop (1 - z) using 1; ext1 n; rw [add_sub_assoc] · have : ↑π / sin (↑π * z) = 1 / (sin (π * z) / π) := by field_simp @@ -547,13 +547,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 _) @@ -562,10 +562,10 @@ theorem Gamma_mul_Gamma_add_half (s : ℂ) : have h3 : Tendsto ((↑) : ℝ → ℂ) (𝓝[≠] 1) (𝓝[≠] 1) := by 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 ?_) + · exact eventually_nhdsWithin_iff.mpr (Eventually.of_forall fun t ht => ofReal_ne_one.mpr ht) + 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 => ?_) + 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, ← ofReal_mul, Gamma_mul_Gamma_add_half_of_pos ht, ofReal_mul, ofReal_mul, ← Gamma_ofReal, mul_inv, mul_inv, (by norm_num : 2 * (t : ℂ) = ↑(2 * t)), Gamma_ofReal, diff --git a/Mathlib/Analysis/SpecialFunctions/Gamma/BohrMollerup.lean b/Mathlib/Analysis/SpecialFunctions/Gamma/BohrMollerup.lean index 62fae42a39804..f3bd9a9a2e9a4 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gamma/BohrMollerup.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gamma/BohrMollerup.lean @@ -185,7 +185,7 @@ theorem f_add_nat_ge (hf_conv : ConvexOn ℝ (Ioi 0) f) -- nth_rw_rhs 1 [(by ring : (n : ℝ) = ↑n - 1 + 1)] -- rw [hf_feq npos, add_sub_cancel] rw [eq_sub_iff_add_eq, ← hf_feq npos, sub_add_cancel] - rwa [this, le_div_iff hx, sub_sub_cancel, le_sub_iff_add_le, mul_comm _ x, add_comm] at c + rwa [this, le_div_iff₀ hx, sub_sub_cancel, le_sub_iff_add_le, mul_comm _ x, add_comm] at c theorem logGammaSeq_add_one (x : ℝ) (n : ℕ) : logGammaSeq (x + 1) n = logGammaSeq x (n + 1) + log x - (x + 1) * (log (n + 1) - log n) := by @@ -261,7 +261,7 @@ theorem tendsto_logGammaSeq (hf_conv : ConvexOn ℝ (Ioi 0) f) ∀ᶠ n : ℕ in atTop, logGammaSeq (x - 1) n = logGammaSeq x (n - 1) + x * (log (↑(n - 1) + 1) - log ↑(n - 1)) - log (x - 1) := by - refine Eventually.mp (eventually_ge_atTop 1) (eventually_of_forall fun n hn => ?_) + refine Eventually.mp (eventually_ge_atTop 1) (Eventually.of_forall fun n hn => ?_) have := logGammaSeq_add_one (x - 1) (n - 1) rw [sub_add_cancel, Nat.sub_add_cancel hn] at this rw [this] diff --git a/Mathlib/Analysis/SpecialFunctions/Gamma/Deligne.lean b/Mathlib/Analysis/SpecialFunctions/Gamma/Deligne.lean index 817d564da1c98..d21123c3a6d31 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gamma/Deligne.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gamma/Deligne.lean @@ -28,7 +28,6 @@ This file defines these functions, and proves some elementary properties, includ formula which is an important input in functional equations of (un-completed) Dirichlet L-functions. -/ - open Filter Topology Asymptotics Real Set MeasureTheory open Complex hiding abs_of_nonneg diff --git a/Mathlib/Analysis/SpecialFunctions/Gaussian/FourierTransform.lean b/Mathlib/Analysis/SpecialFunctions/Gaussian/FourierTransform.lean index 4c44d7abdb5dd..89db8290e3687 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gaussian/FourierTransform.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gaussian/FourierTransform.lean @@ -41,7 +41,7 @@ namespace GaussianFourier variable {b : ℂ} /-- The integral of the Gaussian function over the vertical edges of a rectangle -with vertices at `(±T, 0)` and `(±T, c)`. -/ +with vertices at `(±T, 0)` and `(±T, c)`. -/ def verticalIntegral (b : ℂ) (c T : ℝ) : ℂ := ∫ y : ℝ in (0 : ℝ)..c, I * (cexp (-b * (T + y * I) ^ 2) - cexp (-b * (T - y * I) ^ 2)) @@ -111,9 +111,9 @@ theorem tendsto_verticalIntegral (hb : 0 < b.re) (c : ℝ) : rw [tendsto_zero_iff_norm_tendsto_zero] refine tendsto_of_tendsto_of_tendsto_of_le_of_le' tendsto_const_nhds ?_ - (eventually_of_forall fun _ => norm_nonneg _) + (Eventually.of_forall fun _ => norm_nonneg _) ((eventually_ge_atTop (0 : ℝ)).mp - (eventually_of_forall fun T hT => verticalIntegral_norm_le hb c hT)) + (Eventually.of_forall fun T hT => verticalIntegral_norm_le hb c hT)) rw [(by ring : 0 = 2 * |c| * 0)] refine (tendsto_exp_atBot.comp (tendsto_neg_atTop_atBot.comp ?_)).const_mul _ apply tendsto_atTop_add_const_right @@ -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 e2a7aed0ba9c4..163d700eb16bb 100644 --- a/Mathlib/Analysis/SpecialFunctions/Gaussian/GaussianIntegral.lean +++ b/Mathlib/Analysis/SpecialFunctions/Gaussian/GaussianIntegral.lean @@ -109,7 +109,7 @@ theorem integrable_rpow_mul_exp_neg_mul_sq {b : ℝ} (hb : 0 < b) {s : ℝ} (hs refine ⟨?_, integrableOn_rpow_mul_exp_neg_mul_sq hb hs⟩ rw [← (Measure.measurePreserving_neg (volume : Measure ℝ)).integrableOn_comp_preimage (Homeomorph.neg ℝ).measurableEmbedding] - simp only [Function.comp, neg_sq, neg_preimage, preimage_neg_Iio, neg_neg, neg_zero] + simp only [Function.comp_def, neg_sq, neg_preimage, preimage_neg_Iio, neg_neg, neg_zero] apply Integrable.mono' (integrableOn_rpow_mul_exp_neg_mul_sq hb hs) · apply Measurable.aestronglyMeasurable exact (measurable_id'.neg.pow measurable_const).mul @@ -185,7 +185,7 @@ theorem integral_mul_cexp_neg_mul_sq {b : ℂ} (hb : 0 < b.re) : convert integral_Ioi_of_hasDerivAt_of_tendsto' (fun x _ => (A ↑x).comp_ofReal) (integrable_mul_cexp_neg_mul_sq hb).integrableOn B using 1 simp only [mul_zero, ofReal_zero, zero_pow, Ne, Nat.one_ne_zero, - not_false_iff, Complex.exp_zero, mul_one, sub_neg_eq_add, zero_add] + not_false_iff, Complex.exp_zero, mul_one, sub_neg_eq_add, zero_add, reduceCtorEq] /-- The *square* of the Gaussian integral `∫ x:ℝ, exp (-b * x^2)` is equal to `π / b`. -/ theorem integral_gaussian_sq_complex {b : ℂ} (hb : 0 < b.re) : @@ -249,7 +249,7 @@ theorem continuousAt_gaussian_integral (b : ℂ) (hb : 0 < re b) : gcongr exact le_of_lt hc exact - continuousAt_of_dominated (eventually_of_forall f_meas) f_le_bd (integrable_exp_neg_mul_sq hd) + continuousAt_of_dominated (Eventually.of_forall f_meas) f_le_bd (integrable_exp_neg_mul_sq hd) (ae_of_all _ f_cts) theorem integral_gaussian_complex {b : ℂ} (hb : 0 < re b) : diff --git a/Mathlib/Analysis/SpecialFunctions/Gaussian/PoissonSummation.lean b/Mathlib/Analysis/SpecialFunctions/Gaussian/PoissonSummation.lean index 9e3205f0be961..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 : ℝ) : @@ -57,12 +55,12 @@ lemma cexp_neg_quadratic_isLittleO_abs_rpow_cocompact {a : ℂ} (ha : a.re < 0) rw [cocompact_eq_atBot_atTop, isLittleO_sup] constructor · refine ((cexp_neg_quadratic_isLittleO_rpow_atTop ha (-b) s).comp_tendsto - Filter.tendsto_neg_atBot_atTop).congr' (eventually_of_forall fun x ↦ ?_) ?_ + Filter.tendsto_neg_atBot_atTop).congr' (Eventually.of_forall fun x ↦ ?_) ?_ · simp only [neg_mul, Function.comp_apply, ofReal_neg, neg_sq, mul_neg, neg_neg] - · refine (eventually_lt_atBot 0).mp (eventually_of_forall fun x hx ↦ ?_) + · refine (eventually_lt_atBot 0).mp (Eventually.of_forall fun x hx ↦ ?_) simp only [Function.comp_apply, abs_of_neg hx] · refine (cexp_neg_quadratic_isLittleO_rpow_atTop ha b s).congr' EventuallyEq.rfl ?_ - refine (eventually_gt_atTop 0).mp (eventually_of_forall fun x hx ↦ ?_) + refine (eventually_gt_atTop 0).mp (Eventually.of_forall fun x hx ↦ ?_) simp_rw [abs_of_pos hx] theorem tendsto_rpow_abs_mul_exp_neg_mul_sq_cocompact {a : ℝ} (ha : 0 < a) (s : ℝ) : diff --git a/Mathlib/Analysis/SpecialFunctions/ImproperIntegrals.lean b/Mathlib/Analysis/SpecialFunctions/ImproperIntegrals.lean index 07c0aa8d4bd29..3ef729e02e9f1 100644 --- a/Mathlib/Analysis/SpecialFunctions/ImproperIntegrals.lean +++ b/Mathlib/Analysis/SpecialFunctions/ImproperIntegrals.lean @@ -152,7 +152,7 @@ theorem integral_Ioi_cpow_of_lt {a : ℂ} (ha : a.re < -1) {c : ℝ} (hc : 0 < c suffices Tendsto (fun x : ℝ => ((x : ℂ) ^ (a + 1) - (c : ℂ) ^ (a + 1)) / (a + 1)) atTop (𝓝 <| -c ^ (a + 1) / (a + 1)) by - refine this.congr' ((eventually_gt_atTop 0).mp (eventually_of_forall fun x hx => ?_)) + refine this.congr' ((eventually_gt_atTop 0).mp (Eventually.of_forall fun x hx => ?_)) dsimp only rw [integral_cpow, id] refine Or.inr ⟨?_, not_mem_uIcc_of_lt hc hx⟩ @@ -164,7 +164,7 @@ theorem integral_Ioi_cpow_of_lt {a : ℂ} (ha : a.re < -1) {c : ℝ} (hc : 0 < c rw [tendsto_zero_iff_norm_tendsto_zero] refine (tendsto_rpow_neg_atTop (by linarith : 0 < -(a.re + 1))).congr' - ((eventually_gt_atTop 0).mp (eventually_of_forall fun x hx => ?_)) + ((eventually_gt_atTop 0).mp (Eventually.of_forall fun x hx => ?_)) simp_rw [neg_neg, Complex.norm_eq_abs, Complex.abs_cpow_eq_rpow_re_of_pos hx, Complex.add_re, Complex.one_re] diff --git a/Mathlib/Analysis/SpecialFunctions/Integrals.lean b/Mathlib/Analysis/SpecialFunctions/Integrals.lean index ca08532bc9736..31f51791cdb31 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 @@ -117,7 +117,7 @@ theorem intervalIntegrable_cpow {r : ℂ} (h : 0 ≤ r.re ∨ (0 : ℝ) ∉ [[a, · -- Easy case #1: 0 ∉ [a, b] -- use continuity. refine (ContinuousAt.continuousOn 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 _ _ @@ -580,8 +580,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 54269e1cd03fc..5b9cbab201ab2 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] @@ -95,14 +95,14 @@ theorem finite_integral_one_add_norm {r : ℝ} (hnr : (finrank ℝ E : ℝ) < r) -- We start by applying the layer cake formula have h_meas : Measurable fun ω : E => (1 + ‖ω‖) ^ (-r) := by fun_prop have h_pos : ∀ x : E, 0 ≤ (1 + ‖x‖) ^ (-r) := fun x ↦ by positivity - rw [lintegral_eq_lintegral_meas_le μ (eventually_of_forall h_pos) h_meas.aemeasurable] + rw [lintegral_eq_lintegral_meas_le μ (Eventually.of_forall h_pos) h_meas.aemeasurable] have h_int : ∀ t, 0 < t → μ {a : E | t ≤ (1 + ‖a‖) ^ (-r)} = μ (Metric.closedBall (0 : E) (t ^ (-r⁻¹) - 1)) := fun t ht ↦ by congr 1 ext x simp only [mem_setOf_eq, mem_closedBall_zero_iff] exact le_rpow_one_add_norm_iff_norm_le hr (mem_Ioi.mp ht) x - rw [setLIntegral_congr_fun measurableSet_Ioi (eventually_of_forall h_int)] + rw [setLIntegral_congr_fun measurableSet_Ioi (Eventually.of_forall h_int)] set f := fun t : ℝ ↦ μ (Metric.closedBall (0 : E) (t ^ (-r⁻¹) - 1)) set mB := μ (Metric.ball (0 : E) 1) -- the next two inequalities are in fact equalities but we don't need that @@ -119,7 +119,7 @@ theorem finite_integral_one_add_norm {r : ℝ} (hnr : (finrank ℝ E : ℝ) < r) rw [setLIntegral_congr_fun measurableSet_Ioc (ae_of_all _ h_int'), lintegral_mul_const' _ _ measure_ball_lt_top.ne] exact ENNReal.mul_lt_top - (finite_integral_rpow_sub_one_pow_aux (finrank ℝ E) hnr).ne measure_ball_lt_top.ne + (finite_integral_rpow_sub_one_pow_aux (finrank ℝ E) hnr) measure_ball_lt_top · -- The integral from 1 to ∞ is zero: have h_int'' : ∀ t ∈ Ioi (1 : ℝ), f t = 0 := fun t ht => by simp only [f, closedBall_rpow_sub_one_eq_empty_aux E hr ht, measure_empty] @@ -142,7 +142,7 @@ theorem integrable_rpow_neg_one_add_norm_sq {r : ℝ} (hnr : (finrank ℝ E : Integrable (fun x ↦ ((1 : ℝ) + ‖x‖ ^ 2) ^ (-r / 2)) μ := by have hr : 0 < r := lt_of_le_of_lt (finrank ℝ E).cast_nonneg hnr refine ((integrable_one_add_norm hnr).const_mul <| (2 : ℝ) ^ (r / 2)).mono' - ?_ (eventually_of_forall fun x => ?_) + ?_ (Eventually.of_forall fun x => ?_) · apply Measurable.aestronglyMeasurable (by fun_prop) refine (abs_of_pos ?_).trans_le (rpow_neg_one_add_norm_sq_le x hr) positivity diff --git a/Mathlib/Analysis/SpecialFunctions/Log/Base.lean b/Mathlib/Analysis/SpecialFunctions/Log/Base.lean index 5c8d9e5532473..f7fafb38f92f6 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/Base.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/Base.lean @@ -47,6 +47,12 @@ theorem logb_zero : logb b 0 = 0 := by simp [logb] @[simp] theorem logb_one : logb b 1 = 0 := by simp [logb] +@[simp] +theorem logb_zero_left : logb 0 x = 0 := by simp only [← log_div_log, log_zero, div_zero] + +@[simp] +theorem logb_one_left : logb 1 x = 0 := by simp only [← log_div_log, log_one, div_zero] + @[simp] lemma logb_self_eq_one (hb : 1 < b) : logb b b = 1 := div_self (log_pos hb).ne' @@ -89,7 +95,7 @@ theorem logb_div_base {a b : ℝ} (h₁ : a ≠ 0) (h₂ : b ≠ 0) (c : ℝ) : theorem mul_logb {a b c : ℝ} (h₁ : b ≠ 0) (h₂ : b ≠ 1) (h₃ : b ≠ -1) : logb a b * logb b c = logb a c := by unfold logb - rw [mul_comm, div_mul_div_cancel _ (log_ne_zero.mpr ⟨h₁, h₂, h₃⟩)] + rw [mul_comm, div_mul_div_cancel₀ (log_ne_zero.mpr ⟨h₁, h₂, h₃⟩)] theorem div_logb {a b c : ℝ} (h₁ : c ≠ 0) (h₂ : c ≠ 1) (h₃ : c ≠ -1) : logb a c / logb b c = logb a b := @@ -342,36 +348,50 @@ theorem tendsto_logb_atTop_of_base_lt_one : Tendsto (logb b) atTop atBot := by end BPosAndBLtOne -theorem floor_logb_natCast {b : ℕ} {r : ℝ} (hb : 1 < b) (hr : 0 ≤ r) : +theorem floor_logb_natCast {b : ℕ} {r : ℝ} (hr : 0 ≤ r) : ⌊logb b r⌋ = Int.log b r := by obtain rfl | hr := hr.eq_or_lt · rw [logb_zero, Int.log_zero_right, Int.floor_zero] - have hb1' : 1 < (b : ℝ) := Nat.one_lt_cast.mpr hb - apply le_antisymm - · rw [← Int.zpow_le_iff_le_log hb hr, ← rpow_intCast b] - refine le_of_le_of_eq ?_ (rpow_logb (zero_lt_one.trans hb1') hb1'.ne' hr) - exact rpow_le_rpow_of_exponent_le hb1'.le (Int.floor_le _) - · rw [Int.le_floor, le_logb_iff_rpow_le hb1' hr, rpow_intCast] - exact Int.zpow_log_le_self hb hr + by_cases hb : 1 < b + · have hb1' : 1 < (b : ℝ) := Nat.one_lt_cast.mpr hb + apply le_antisymm + · rw [← Int.zpow_le_iff_le_log hb hr, ← rpow_intCast b] + refine le_of_le_of_eq ?_ (rpow_logb (zero_lt_one.trans hb1') hb1'.ne' hr) + exact rpow_le_rpow_of_exponent_le hb1'.le (Int.floor_le _) + · rw [Int.le_floor, le_logb_iff_rpow_le hb1' hr, rpow_intCast] + exact Int.zpow_log_le_self hb hr + · rw [Nat.one_lt_iff_ne_zero_and_ne_one, ← or_iff_not_and_not] at hb + cases hb + · simp_all only [CharP.cast_eq_zero, logb_zero_left, Int.floor_zero, Int.log_zero_left] + · simp_all only [Nat.cast_one, logb_one_left, Int.floor_zero, Int.log_one_left] @[deprecated (since := "2024-04-17")] alias floor_logb_nat_cast := floor_logb_natCast -theorem ceil_logb_natCast {b : ℕ} {r : ℝ} (hb : 1 < b) (hr : 0 ≤ r) : +theorem ceil_logb_natCast {b : ℕ} {r : ℝ} (hr : 0 ≤ r) : ⌈logb b r⌉ = Int.clog b r := by obtain rfl | hr := hr.eq_or_lt · rw [logb_zero, Int.clog_zero_right, Int.ceil_zero] - have hb1' : 1 < (b : ℝ) := Nat.one_lt_cast.mpr hb - apply le_antisymm - · rw [Int.ceil_le, logb_le_iff_le_rpow hb1' hr, rpow_intCast] - exact Int.self_le_zpow_clog hb r - · rw [← Int.le_zpow_iff_clog_le hb hr, ← rpow_intCast b] - refine (rpow_logb (zero_lt_one.trans hb1') hb1'.ne' hr).symm.trans_le ?_ - exact rpow_le_rpow_of_exponent_le hb1'.le (Int.le_ceil _) + by_cases hb : 1 < b + · have hb1' : 1 < (b : ℝ) := Nat.one_lt_cast.mpr hb + apply le_antisymm + · rw [Int.ceil_le, logb_le_iff_le_rpow hb1' hr, rpow_intCast] + exact Int.self_le_zpow_clog hb r + · rw [← Int.le_zpow_iff_clog_le hb hr, ← rpow_intCast b] + refine (rpow_logb (zero_lt_one.trans hb1') hb1'.ne' hr).symm.trans_le ?_ + exact rpow_le_rpow_of_exponent_le hb1'.le (Int.le_ceil _) + · rw [Nat.one_lt_iff_ne_zero_and_ne_one, ← or_iff_not_and_not] at hb + cases hb + · simp_all only [CharP.cast_eq_zero, logb_zero_left, Int.ceil_zero, Int.clog_zero_left] + · simp_all only [Nat.cast_one, logb_one_left, Int.ceil_zero, Int.clog_one_left] @[deprecated (since := "2024-04-17")] alias ceil_logb_nat_cast := ceil_logb_natCast +lemma natLog_le_logb (a b : ℕ) : Nat.log b a ≤ Real.logb b a := by + apply le_trans _ (Int.floor_le ((b : ℝ).logb a)) + rw [Real.floor_logb_natCast (Nat.cast_nonneg a), Int.log_natCast, Int.cast_natCast] + @[simp] theorem logb_eq_zero : logb b x = 0 ↔ b = 0 ∨ b = 1 ∨ b = -1 ∨ x = 0 ∨ x = 1 ∨ x = -1 := by simp_rw [logb, div_eq_zero_iff, log_eq_zero] @@ -403,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 3593e3aa57d9e..ccc7141a90155 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean @@ -6,6 +6,7 @@ Authors: Chris Hughes, Abhimanyu Pallavi Sudhir, Jean Lo, Calle Sönne import Mathlib.Analysis.SpecialFunctions.Exp import Mathlib.Data.Nat.Factorization.Defs import Mathlib.Analysis.NormedSpace.Real +import Mathlib.Data.Rat.Cast.CharZero /-! # Real logarithm @@ -123,7 +124,7 @@ theorem log_le_log_iff (h : 0 < x) (h₁ : 0 < y) : log x ≤ log y ↔ x ≤ y lemma log_le_log (hx : 0 < x) (hxy : x ≤ y) : log x ≤ log y := (log_le_log_iff hx (hx.trans_le hxy)).2 hxy -@[gcongr] +@[gcongr, bound] theorem log_lt_log (hx : 0 < x) (h : x < y) : log x < log y := by rwa [← exp_lt_exp, exp_log hx, exp_log (lt_trans hx h)] @@ -142,6 +143,7 @@ theorem log_pos_iff (hx : 0 < x) : 0 < log x ↔ 1 < x := by rw [← log_one] exact log_lt_log_iff zero_lt_one hx +@[bound] theorem log_pos (hx : 1 < x) : 0 < log x := (log_pos_iff (lt_trans zero_lt_one hx)).2 hx @@ -154,6 +156,7 @@ theorem log_neg_iff (h : 0 < x) : log x < 0 ↔ x < 1 := by rw [← log_one] exact log_lt_log_iff h zero_lt_one +@[bound] theorem log_neg (h0 : 0 < x) (h1 : x < 1) : log x < 0 := (log_neg_iff h0).2 h1 @@ -176,6 +179,7 @@ theorem log_nonpos_iff' (hx : 0 ≤ x) : log x ≤ 0 ↔ x ≤ 1 := by · simp [le_refl, zero_le_one] exact log_nonpos_iff hx +@[bound] theorem log_nonpos (hx : 0 ≤ x) (h'x : x ≤ 1) : log x ≤ 0 := (log_nonpos_iff' hx).2 h'x @@ -252,11 +256,12 @@ theorem log_ne_zero {x : ℝ} : log x ≠ 0 ↔ x ≠ 0 ∧ x ≠ 1 ∧ x ≠ -1 @[simp] theorem log_pow (x : ℝ) (n : ℕ) : log (x ^ n) = n * log x := by - induction' n with n ih - · simp - rcases eq_or_ne x 0 with (rfl | hx) - · simp - rw [pow_succ, log_mul (pow_ne_zero _ hx) hx, ih, Nat.cast_succ, add_mul, one_mul] + induction n with + | zero => simp + | succ n ih => + rcases eq_or_ne x 0 with (rfl | hx) + · simp + · rw [pow_succ, log_mul (pow_ne_zero _ hx) hx, ih, Nat.cast_succ, add_mul, one_mul] @[simp] theorem log_zpow (x : ℝ) (n : ℤ) : log (x ^ n) = n * log x := by @@ -273,17 +278,30 @@ theorem log_le_sub_one_of_pos {x : ℝ} (hx : 0 < x) : log x ≤ x - 1 := by convert add_one_le_exp (log x) rw [exp_log hx] +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/Deriv.lean b/Mathlib/Analysis/SpecialFunctions/Log/Deriv.lean index 7817f8158e5eb..958e650ae3268 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/Deriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/Deriv.lean @@ -47,7 +47,7 @@ theorem hasStrictDerivAt_log (hx : x ≠ 0) : HasStrictDerivAt log x⁻¹ x := b theorem hasDerivAt_log (hx : x ≠ 0) : HasDerivAt log x⁻¹ x := (hasStrictDerivAt_log hx).hasDerivAt -theorem differentiableAt_log (hx : x ≠ 0) : DifferentiableAt ℝ log x := +@[fun_prop] theorem differentiableAt_log (hx : x ≠ 0) : DifferentiableAt ℝ log x := (hasDerivAt_log hx).differentiableAt theorem differentiableOn_log : DifferentiableOn ℝ log {0}ᶜ := fun _x hx => @@ -140,7 +140,7 @@ theorem DifferentiableWithinAt.log (hf : DifferentiableWithinAt ℝ f s x) (hx : DifferentiableWithinAt ℝ (fun x => log (f x)) s x := (hf.hasFDerivWithinAt.log hx).differentiableWithinAt -@[simp] +@[simp, fun_prop] theorem DifferentiableAt.log (hf : DifferentiableAt ℝ f x) (hx : f x ≠ 0) : DifferentiableAt ℝ (fun x => log (f x)) x := (hf.hasFDerivAt.log hx).differentiableAt @@ -160,10 +160,11 @@ theorem ContDiff.log {n} (hf : ContDiff ℝ n f) (h : ∀ x, f x ≠ 0) : ContDiff ℝ n fun x => log (f x) := contDiff_iff_contDiffAt.2 fun x => hf.contDiffAt.log (h x) +@[fun_prop] theorem DifferentiableOn.log (hf : DifferentiableOn ℝ f s) (hx : ∀ x ∈ s, f x ≠ 0) : DifferentiableOn ℝ (fun x => log (f x)) s := fun x h => (hf x h).log (hx x h) -@[simp] +@[simp, fun_prop] theorem Differentiable.log (hf : Differentiable ℝ f) (hx : ∀ x, f x ≠ 0) : Differentiable ℝ fun x => log (f x) := fun x => (hf x).log (hx x) @@ -191,7 +192,7 @@ theorem tendsto_mul_log_one_plus_div_atTop (t : ℝ) : (((hasDerivAt_id (0 : ℝ)).const_mul t).const_add 1).log (by simp) have h₂ : Tendsto (fun x : ℝ => x⁻¹) atTop (𝓝[≠] 0) := tendsto_inv_atTop_zero'.mono_right (nhdsWithin_mono _ fun x hx => (Set.mem_Ioi.mp hx).ne') - simpa only [(· ∘ ·), inv_inv] using h₁.comp h₂ + simpa only [Function.comp_def, inv_inv] using h₁.comp h₂ /-- A crude lemma estimating the difference between `log (1-x)` and its Taylor series at `0`, where the main point of the bound is that it tends to `0`. The goal is to deduce the series diff --git a/Mathlib/Analysis/SpecialFunctions/Log/ENNRealLog.lean b/Mathlib/Analysis/SpecialFunctions/Log/ENNRealLog.lean index 18a40a93e64f5..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,38 +154,34 @@ 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)] - · have xy_real := Real.mul_pos x_real y_real - rw [← ENNReal.toReal_mul] at xy_real - rw_mod_cast [log_pos_real' xy_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)) + · 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 x_real.ne' y_real.ne' + rw [toReal_mul] + positivity 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/Monotone.lean b/Mathlib/Analysis/SpecialFunctions/Log/Monotone.lean index 7242d130a008d..c7eaabb0c3580 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/Monotone.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/Monotone.lean @@ -41,8 +41,8 @@ theorem log_div_self_antitoneOn : AntitoneOn (fun x : ℝ => log x / x) { x | ex have x_pos : 0 < x := (exp_pos 1).trans_le hex have y_pos : 0 < y := (exp_pos 1).trans_le hey have hlogx : 1 ≤ log x := by rwa [le_log_iff_exp_le x_pos] - have hyx : 0 ≤ y / x - 1 := by rwa [le_sub_iff_add_le, le_div_iff x_pos, zero_add, one_mul] - rw [div_le_iff y_pos, ← sub_le_sub_iff_right (log x)] + have hyx : 0 ≤ y / x - 1 := by rwa [le_sub_iff_add_le, le_div_iff₀ x_pos, zero_add, one_mul] + rw [div_le_iff₀ y_pos, ← sub_le_sub_iff_right (log x)] calc log y - log x = log (y / x) := by rw [log_div y_pos.ne' x_pos.ne'] _ ≤ y / x - 1 := log_le_sub_one_of_pos (div_pos y_pos x_pos) diff --git a/Mathlib/Analysis/SpecialFunctions/Log/NegMulLog.lean b/Mathlib/Analysis/SpecialFunctions/Log/NegMulLog.lean index 66773834ae8aa..681792d6a3f5e 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/NegMulLog.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/NegMulLog.lean @@ -23,6 +23,7 @@ open scoped Topology namespace Real +@[fun_prop] lemma continuous_mul_log : Continuous fun x ↦ x * log x := by rw [continuous_iff_continuousAt] intro x @@ -39,6 +40,10 @@ lemma continuous_mul_log : Continuous fun x ↦ x * log x := by · convert tendsto_pure_nhds (fun x ↦ log x * x) 0 simp +@[fun_prop] +lemma Continuous.mul_log {α : Type*} [TopologicalSpace α] {f : α → ℝ} (hf : Continuous f) : + Continuous fun a ↦ f a * log (f a) := continuous_mul_log.comp hf + lemma differentiableOn_mul_log : DifferentiableOn ℝ (fun x ↦ x * log x) {0}ᶜ := differentiable_id'.differentiableOn.mul differentiableOn_log @@ -131,7 +136,7 @@ lemma negMulLog_mul (x y : ℝ) : negMulLog (x * y) = y * negMulLog x + x * negM rw [log_mul hx hy] ring -lemma continuous_negMulLog : Continuous negMulLog := by +@[fun_prop] lemma continuous_negMulLog : Continuous negMulLog := by simpa only [negMulLog_eq_neg] using continuous_mul_log.neg lemma differentiableOn_negMulLog : DifferentiableOn ℝ negMulLog {0}ᶜ := by @@ -151,6 +156,8 @@ lemma differentiableAt_negMulLog_iff {x : ℝ} : DifferentiableAt ℝ negMulLog <;> simp_all only [ne_eq, Set.mem_compl_iff, Set.mem_singleton_iff, not_false_eq_true, compl_singleton_mem_nhds_iff] +@[fun_prop] alias ⟨_, differentiableAt_negMulLog⟩ := differentiableAt_negMulLog_iff + lemma deriv_negMulLog {x : ℝ} (hx : x ≠ 0) : deriv negMulLog x = - log x - 1 := by rw [negMulLog_eq_neg, deriv.neg, deriv_mul_log hx] ring diff --git a/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean b/Mathlib/Analysis/SpecialFunctions/PolarCoord.lean index e11dde25a0bad..62dafde2c1433 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] diff --git a/Mathlib/Analysis/SpecialFunctions/Polynomials.lean b/Mathlib/Analysis/SpecialFunctions/Polynomials.lean index 757dc664c8c4d..b69d21ca69f57 100644 --- a/Mathlib/Analysis/SpecialFunctions/Polynomials.lean +++ b/Mathlib/Analysis/SpecialFunctions/Polynomials.lean @@ -81,7 +81,7 @@ theorem abs_tendsto_atTop (hdeg : 0 < P.degree) : theorem abs_isBoundedUnder_iff : (IsBoundedUnder (· ≤ ·) atTop fun x => |eval x P|) ↔ P.degree ≤ 0 := by - refine ⟨fun h => ?_, fun h => ⟨|P.coeff 0|, eventually_map.mpr (eventually_of_forall + refine ⟨fun h => ?_, fun h => ⟨|P.coeff 0|, eventually_map.mpr (Eventually.of_forall (forall_imp (fun _ => le_of_eq) fun x => congr_arg abs <| _root_.trans (congr_arg (eval x) (eq_C_of_degree_le_zero h)) eval_C))⟩⟩ contrapose! h diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Asymptotics.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Asymptotics.lean index 0e75a747d5f90..58b6a5277c22c 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Asymptotics.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Asymptotics.lean @@ -62,7 +62,7 @@ lemma tendsto_rpow_atTop_of_base_lt_one (b : ℝ) (hb₀ : -1 < b) (hb₁ : b < linarith case cos => rw [isBigO_iff] - exact ⟨1, eventually_of_forall fun x => by simp [Real.abs_cos_le_one]⟩ + exact ⟨1, Eventually.of_forall fun x => by simp [Real.abs_cos_le_one]⟩ case inr.inl => -- b = 0 refine Tendsto.mono_right ?_ (Iff.mpr pure_le_nhds_iff rfl) rw [tendsto_pure] @@ -166,7 +166,7 @@ theorem ENNReal.tendsto_rpow_at_top {y : ℝ} (hy : 0 < y) : lift a to ℝ≥0 using ha' -- Porting note: reduced defeq abuse simp only [Set.mem_Ioi, coe_lt_coe] at ha hc - rw [ENNReal.coe_rpow_of_nonneg _ hy.le] + rw [← ENNReal.coe_rpow_of_nonneg _ hy.le] exact mod_cast hc a ha end Limits @@ -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|) : diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Complex.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Complex.lean index 0560cfa53a183..c9a10865fd507 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Complex.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Complex.lean @@ -175,8 +175,8 @@ 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 [← le_div_iff' (Nat.cast_pos.2 h₀.bot_lt)] + · 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) (hle : x.arg ≤ π / OfNat.ofNat n) : diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean index 03ef52c7d48f1..841d4fc4de757 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Continuity.lean @@ -299,7 +299,7 @@ theorem continuousAt_cpow_zero_of_re_pos {z : ℂ} (hz : 0 < z.re) : (continuous_fst.norm.tendsto ((0 : ℂ), z)).rpow ((continuous_re.comp continuous_snd).tendsto _) _ <;> simp [hz, Real.zero_rpow hz.ne'] - · simp only [Function.comp, Real.norm_eq_abs, abs_of_pos (Real.exp_pos _)] + · simp only [Function.comp_def, Real.norm_eq_abs, abs_of_pos (Real.exp_pos _)] rcases exists_gt |im z| with ⟨C, hC⟩ refine ⟨Real.exp (π * C), eventually_map.2 ?_⟩ refine @@ -332,8 +332,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 +340,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 +391,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 @@ -417,6 +414,19 @@ theorem continuousAt_rpow_const {x : ℝ≥0} {y : ℝ} (h : x ≠ 0 ∨ 0 ≤ y theorem continuous_rpow_const {y : ℝ} (h : 0 ≤ y) : Continuous fun x : ℝ≥0 => x ^ y := continuous_iff_continuousAt.2 fun _ => continuousAt_rpow_const (Or.inr h) +@[fun_prop] +theorem continuousOn_rpow_const_compl_zero {r : ℝ} : + ContinuousOn (fun z : ℝ≥0 => z ^ r) {0}ᶜ := + fun _ h => ContinuousAt.continuousWithinAt <| NNReal.continuousAt_rpow_const (.inl h) + +-- even though this follows from `ContinuousOn.mono` and the previous lemma, we include it for +-- automation purposes with `fun_prop`, because the side goal `0 ∉ s ∨ 0 ≤ r` is often easy to check +@[fun_prop] +theorem continuousOn_rpow_const {r : ℝ} {s : Set ℝ≥0} + (h : 0 ∉ s ∨ 0 ≤ r) : ContinuousOn (fun z : ℝ≥0 => z ^ r) s := + h.elim (fun _ ↦ ContinuousOn.mono (s := {0}ᶜ) (by fun_prop) (by aesop)) + (NNReal.continuous_rpow_const · |>.continuousOn) + end NNReal /-! ## Continuity for `ℝ≥0∞` powers -/ @@ -428,11 +438,11 @@ theorem eventually_pow_one_div_le {x : ℝ≥0∞} (hx : x ≠ ∞) {y : ℝ≥0 ∀ᶠ n : ℕ in atTop, x ^ (1 / n : ℝ) ≤ y := by lift x to ℝ≥0 using hx by_cases h : y = ∞ - · exact eventually_of_forall fun n => h.symm ▸ le_top + · exact Eventually.of_forall fun n => h.symm ▸ le_top · lift y to ℝ≥0 using h have := NNReal.eventually_pow_one_div_le x (mod_cast hy : 1 < y) - refine this.congr (eventually_of_forall fun n => ?_) - rw [coe_rpow_of_nonneg x (by positivity : 0 ≤ (1 / n : ℝ)), coe_le_coe] + refine this.congr (Eventually.of_forall fun n => ?_) + rw [← coe_rpow_of_nonneg x (by positivity : 0 ≤ (1 / n : ℝ)), coe_le_coe] private theorem continuousAt_rpow_const_of_pos {x : ℝ≥0∞} {y : ℝ} (h : 0 < y) : ContinuousAt (fun a : ℝ≥0∞ => a ^ y) x := by @@ -444,7 +454,7 @@ private theorem continuousAt_rpow_const_of_pos {x : ℝ≥0∞} {y : ℝ} (h : 0 rw [continuousAt_coe_iff] convert continuous_coe.continuousAt.comp (NNReal.continuousAt_rpow_const (Or.inr h.le)) using 1 ext1 x - simp [coe_rpow_of_nonneg _ h.le] + simp [← coe_rpow_of_nonneg _ h.le] @[continuity, fun_prop] theorem continuous_rpow_const {y : ℝ} : Continuous fun a : ℝ≥0∞ => a ^ y := by diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/NNReal.lean b/Mathlib/Analysis/SpecialFunctions/Pow/NNReal.lean index 957d08e87a3bb..d2306464d57ff 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/NNReal.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/NNReal.lean @@ -24,7 +24,7 @@ open Real NNReal ENNReal ComplexConjugate open Finset Function Set namespace NNReal -variable {w x y z : ℝ} +variable {x : ℝ≥0} {w y z : ℝ} /-- The nonnegative real power function `x^y`, defined for `x : ℝ≥0` and `y : ℝ` as the restriction of the real power function. For `x > 0`, it is equal to `exp (y log x)`. For `x = 0`, @@ -52,6 +52,8 @@ theorem rpow_eq_zero_iff {x : ℝ≥0} {y : ℝ} : x ^ y = 0 ↔ x = 0 ∧ y ≠ rw [← NNReal.coe_inj, coe_rpow, ← NNReal.coe_eq_zero] exact Real.rpow_eq_zero_iff_of_nonneg x.2 +lemma rpow_eq_zero (hy : y ≠ 0) : x ^ y = 0 ↔ x = 0 := by simp [hy] + @[simp] theorem zero_rpow {x : ℝ} (h : x ≠ 0) : (0 : ℝ≥0) ^ x = 0 := NNReal.eq <| Real.zero_rpow h @@ -60,6 +62,18 @@ theorem zero_rpow {x : ℝ} (h : x ≠ 0) : (0 : ℝ≥0) ^ x = 0 := theorem rpow_one (x : ℝ≥0) : x ^ (1 : ℝ) = x := NNReal.eq <| Real.rpow_one _ +lemma rpow_neg (x : ℝ≥0) (y : ℝ) : x ^ (-y) = (x ^ y)⁻¹ := + NNReal.eq <| Real.rpow_neg x.2 _ + +@[simp, norm_cast] +lemma rpow_natCast (x : ℝ≥0) (n : ℕ) : x ^ (n : ℝ) = x ^ n := + NNReal.eq <| by simpa only [coe_rpow, coe_pow] using Real.rpow_natCast x n + +@[simp, norm_cast] +lemma rpow_intCast (x : ℝ≥0) (n : ℤ) : x ^ (n : ℝ) = x ^ n := by + cases n <;> simp only [Int.ofNat_eq_coe, Int.cast_natCast, rpow_natCast, zpow_natCast, + Int.cast_negSucc, rpow_neg, zpow_negSucc] + @[simp] theorem one_rpow (x : ℝ) : (1 : ℝ≥0) ^ x = 1 := NNReal.eq <| Real.one_rpow _ @@ -67,9 +81,45 @@ theorem one_rpow (x : ℝ) : (1 : ℝ≥0) ^ x = 1 := 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) _ _ -theorem rpow_add' (x : ℝ≥0) {y z : ℝ} (h : y + z ≠ 0) : x ^ (y + z) = x ^ y * x ^ z := +theorem rpow_add' (h : y + z ≠ 0) (x : ℝ≥0) : x ^ (y + z) = x ^ y * x ^ z := NNReal.eq <| Real.rpow_add' x.2 h +lemma rpow_add_intCast (hx : x ≠ 0) (y : ℝ) (n : ℤ) : x ^ (y + n) = x ^ y * x ^ n := by + ext; exact Real.rpow_add_intCast (mod_cast hx) _ _ + +lemma rpow_add_natCast (hx : x ≠ 0) (y : ℝ) (n : ℕ) : x ^ (y + n) = x ^ y * x ^ n := by + ext; exact Real.rpow_add_natCast (mod_cast hx) _ _ + +lemma rpow_sub_intCast (hx : x ≠ 0) (y : ℝ) (n : ℕ) : x ^ (y - n) = x ^ y / x ^ n := by + ext; exact Real.rpow_sub_intCast (mod_cast hx) _ _ + +lemma rpow_sub_natCast (hx : x ≠ 0) (y : ℝ) (n : ℕ) : x ^ (y - n) = x ^ y / x ^ n := by + ext; exact Real.rpow_sub_natCast (mod_cast hx) _ _ + +lemma rpow_add_intCast' {n : ℤ} (h : y + n ≠ 0) (x : ℝ≥0) : x ^ (y + n) = x ^ y * x ^ n := by + ext; exact Real.rpow_add_intCast' (mod_cast x.2) h + +lemma rpow_add_natCast' {n : ℕ} (h : y + n ≠ 0) (x : ℝ≥0) : x ^ (y + n) = x ^ y * x ^ n := by + ext; exact Real.rpow_add_natCast' (mod_cast x.2) h + +lemma rpow_sub_intCast' {n : ℤ} (h : y - n ≠ 0) (x : ℝ≥0) : x ^ (y - n) = x ^ y / x ^ n := by + ext; exact Real.rpow_sub_intCast' (mod_cast x.2) h + +lemma rpow_sub_natCast' {n : ℕ} (h : y - n ≠ 0) (x : ℝ≥0) : x ^ (y - n) = x ^ y / x ^ n := by + ext; exact Real.rpow_sub_natCast' (mod_cast x.2) h + +lemma rpow_add_one (hx : x ≠ 0) (y : ℝ) : x ^ (y + 1) = x ^ y * x := by + simpa using rpow_add_natCast hx y 1 + +lemma rpow_sub_one (hx : x ≠ 0) (y : ℝ) : x ^ (y - 1) = x ^ y / x := by + simpa using rpow_sub_natCast hx y 1 + +lemma rpow_add_one' (h : y + 1 ≠ 0) (x : ℝ≥0) : x ^ (y + 1) = x ^ y * x := by + rw [rpow_add' h, rpow_one] + +lemma rpow_one_add' (h : 1 + y ≠ 0) (x : ℝ≥0) : x ^ (1 + y) = x * x ^ y := by + rw [rpow_add' h, rpow_one] + theorem rpow_add_of_nonneg (x : ℝ≥0) {y z : ℝ} (hy : 0 ≤ y) (hz : 0 ≤ z) : x ^ (y + z) = x ^ y * x ^ z := by ext; exact Real.rpow_add_of_nonneg x.2 hy hz @@ -81,17 +131,32 @@ lemma rpow_of_add_eq (x : ℝ≥0) (hw : w ≠ 0) (h : y + z = w) : x ^ w = x ^ theorem rpow_mul (x : ℝ≥0) (y z : ℝ) : x ^ (y * z) = (x ^ y) ^ z := NNReal.eq <| Real.rpow_mul x.2 y z -theorem rpow_neg (x : ℝ≥0) (y : ℝ) : x ^ (-y) = (x ^ y)⁻¹ := - NNReal.eq <| Real.rpow_neg x.2 _ +lemma rpow_natCast_mul (x : ℝ≥0) (n : ℕ) (z : ℝ) : x ^ (n * z) = (x ^ n) ^ z := by + rw [rpow_mul, rpow_natCast] + +lemma rpow_mul_natCast (x : ℝ≥0) (y : ℝ) (n : ℕ) : x ^ (y * n) = (x ^ y) ^ n := by + rw [rpow_mul, rpow_natCast] + +lemma rpow_intCast_mul (x : ℝ≥0) (n : ℤ) (z : ℝ) : x ^ (n * z) = (x ^ n) ^ z := by + rw [rpow_mul, rpow_intCast] + +lemma rpow_mul_intCast (x : ℝ≥0) (y : ℝ) (n : ℤ) : x ^ (y * n) = (x ^ y) ^ n := by + rw [rpow_mul, rpow_intCast] 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 -theorem rpow_sub' (x : ℝ≥0) {y z : ℝ} (h : y - z ≠ 0) : x ^ (y - z) = x ^ y / x ^ 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 +lemma rpow_sub_one' (h : y - 1 ≠ 0) (x : ℝ≥0) : x ^ (y - 1) = x ^ y / x := by + rw [rpow_sub' h, rpow_one] + +lemma rpow_one_sub' (h : 1 - y ≠ 0) (x : ℝ≥0) : x ^ (1 - y) = x / x ^ y := by + rw [rpow_sub' h, rpow_one] + theorem rpow_inv_rpow_self {y : ℝ} (hy : y ≠ 0) (x : ℝ≥0) : (x ^ y) ^ (1 / y) = x := by field_simp [← rpow_mul] @@ -109,10 +174,6 @@ theorem sqrt_eq_rpow (x : ℝ≥0) : sqrt x = x ^ (1 / (2 : ℝ)) := by push_cast exact Real.sqrt_eq_rpow x.1 -@[simp, norm_cast] -theorem rpow_natCast (x : ℝ≥0) (n : ℕ) : x ^ (n : ℝ) = x ^ n := - NNReal.eq <| by simpa only [coe_rpow, coe_pow] using Real.rpow_natCast x n - @[deprecated (since := "2024-04-17")] alias rpow_nat_cast := rpow_natCast @@ -219,6 +280,47 @@ theorem lt_rpow_inv_iff {x y : ℝ≥0} {z : ℝ} (hz : 0 < z) : x < y ^ z⁻¹ theorem rpow_inv_lt_iff {x y : ℝ≥0} {z : ℝ} (hz : 0 < z) : x ^ z⁻¹ < y ↔ x < y ^ z := by simp only [← not_le, le_rpow_inv_iff hz] +section +variable {y : ℝ≥0} + +lemma rpow_lt_rpow_of_neg (hx : 0 < x) (hxy : x < y) (hz : z < 0) : y ^ z < x ^ z := + Real.rpow_lt_rpow_of_neg hx hxy hz + +lemma rpow_le_rpow_of_nonpos (hx : 0 < x) (hxy : x ≤ y) (hz : z ≤ 0) : y ^ z ≤ x ^ z := + Real.rpow_le_rpow_of_nonpos hx hxy hz + +lemma rpow_lt_rpow_iff_of_neg (hx : 0 < x) (hy : 0 < y) (hz : z < 0) : x ^ z < y ^ z ↔ y < x := + Real.rpow_lt_rpow_iff_of_neg hx hy hz + +lemma rpow_le_rpow_iff_of_neg (hx : 0 < x) (hy : 0 < y) (hz : z < 0) : x ^ z ≤ y ^ z ↔ y ≤ x := + Real.rpow_le_rpow_iff_of_neg hx hy hz + +lemma le_rpow_inv_iff_of_pos (hy : 0 ≤ y) (hz : 0 < z) (x : ℝ≥0) : x ≤ y ^ z⁻¹ ↔ x ^ z ≤ y := + Real.le_rpow_inv_iff_of_pos x.2 hy hz + +lemma rpow_inv_le_iff_of_pos (hy : 0 ≤ y) (hz : 0 < z) (x : ℝ≥0) : x ^ z⁻¹ ≤ y ↔ x ≤ y ^ z := + Real.rpow_inv_le_iff_of_pos x.2 hy hz + +lemma lt_rpow_inv_iff_of_pos (hy : 0 ≤ y) (hz : 0 < z) (x : ℝ≥0) : x < y ^ z⁻¹ ↔ x ^ z < y := + Real.lt_rpow_inv_iff_of_pos x.2 hy hz + +lemma rpow_inv_lt_iff_of_pos (hy : 0 ≤ y) (hz : 0 < z) (x : ℝ≥0) : x ^ z⁻¹ < y ↔ x < y ^ z := + Real.rpow_inv_lt_iff_of_pos x.2 hy hz + +lemma le_rpow_inv_iff_of_neg (hx : 0 < x) (hy : 0 < y) (hz : z < 0) : x ≤ y ^ z⁻¹ ↔ y ≤ x ^ z := + Real.le_rpow_inv_iff_of_neg hx hy hz + +lemma lt_rpow_inv_iff_of_neg (hx : 0 < x) (hy : 0 < y) (hz : z < 0) : x < y ^ z⁻¹ ↔ y < x ^ z := + Real.lt_rpow_inv_iff_of_neg hx hy hz + +lemma rpow_inv_lt_iff_of_neg (hx : 0 < x) (hy : 0 < y) (hz : z < 0) : x ^ z⁻¹ < y ↔ y ^ z < x := + Real.rpow_inv_lt_iff_of_neg hx hy hz + +lemma rpow_inv_le_iff_of_neg (hx : 0 < x) (hy : 0 < y) (hz : z < 0) : x ^ z⁻¹ ≤ y ↔ y ^ z ≤ x := + Real.rpow_inv_le_iff_of_neg hx hy hz + +end + @[gcongr] theorem rpow_lt_rpow_of_exponent_lt {x : ℝ≥0} {y z : ℝ} (hx : 1 < x) (hyz : y < z) : x ^ y < x ^ z := Real.rpow_lt_rpow_of_exponent_lt hx hyz @@ -407,13 +509,13 @@ theorem zero_rpow_mul_self (y : ℝ) : (0 : ℝ≥0∞) ^ y * (0 : ℝ≥0∞) ^ exacts [zero_mul _, one_mul _, top_mul_top] @[norm_cast] -theorem coe_rpow_of_ne_zero {x : ℝ≥0} (h : x ≠ 0) (y : ℝ) : (x : ℝ≥0∞) ^ y = (x ^ y : ℝ≥0) := by +theorem coe_rpow_of_ne_zero {x : ℝ≥0} (h : x ≠ 0) (y : ℝ) : (↑(x ^ y) : ℝ≥0∞) = x ^ y := by rw [← ENNReal.some_eq_coe] dsimp only [(· ^ ·), Pow.pow, rpow] simp [h] @[norm_cast] -theorem coe_rpow_of_nonneg (x : ℝ≥0) {y : ℝ} (h : 0 ≤ y) : (x : ℝ≥0∞) ^ y = (x ^ y : ℝ≥0) := by +theorem coe_rpow_of_nonneg (x : ℝ≥0) {y : ℝ} (h : 0 ≤ y) : ↑(x ^ y) = (x : ℝ≥0∞) ^ y := by by_cases hx : x = 0 · rcases le_iff_eq_or_lt.1 h with (H | H) · simp [hx, H.symm] @@ -434,7 +536,7 @@ theorem rpow_one (x : ℝ≥0∞) : x ^ (1 : ℝ) = x := by @[simp] theorem one_rpow (x : ℝ) : (1 : ℝ≥0∞) ^ x = 1 := by - rw [← coe_one, coe_rpow_of_ne_zero one_ne_zero] + rw [← coe_one, ← coe_rpow_of_ne_zero one_ne_zero] simp @[simp] @@ -445,7 +547,7 @@ theorem rpow_eq_zero_iff {x : ℝ≥0∞} {y : ℝ} : x ^ y = 0 ↔ x = 0 ∧ 0 · by_cases h : x = 0 · rcases lt_trichotomy y 0 with (H | H | H) <;> simp [h, H, zero_rpow_of_neg, zero_rpow_of_pos, le_of_lt] - · simp [coe_rpow_of_ne_zero h, h] + · simp [← coe_rpow_of_ne_zero h, h] lemma rpow_eq_zero_iff_of_pos {x : ℝ≥0∞} {y : ℝ} (hy : 0 < y) : x ^ y = 0 ↔ x = 0 := by simp [hy, hy.not_lt] @@ -458,7 +560,7 @@ theorem rpow_eq_top_iff {x : ℝ≥0∞} {y : ℝ} : x ^ y = ⊤ ↔ x = 0 ∧ y · by_cases h : x = 0 · rcases lt_trichotomy y 0 with (H | H | H) <;> simp [h, H, zero_rpow_of_neg, zero_rpow_of_pos, le_of_lt] - · simp [coe_rpow_of_ne_zero h, h] + · simp [← coe_rpow_of_ne_zero h, h] theorem rpow_eq_top_iff_of_pos {x : ℝ≥0∞} {y : ℝ} (hy : 0 < y) : x ^ y = ⊤ ↔ x = ⊤ := by simp [rpow_eq_top_iff, hy, asymm hy] @@ -484,7 +586,7 @@ theorem rpow_add {x : ℝ≥0∞} (y z : ℝ) (hx : x ≠ 0) (h'x : x ≠ ⊤) : cases' x with x · exact (h'x rfl).elim have : x ≠ 0 := fun h => by simp [h] at hx - simp [coe_rpow_of_ne_zero this, NNReal.rpow_add this] + simp [← coe_rpow_of_ne_zero this, NNReal.rpow_add this] theorem rpow_add_of_nonneg {x : ℝ≥0∞} (y z : ℝ) (hy : 0 ≤ y) (hz : 0 ≤ z) : x ^ (y + z) = x ^ y * x ^ z := by @@ -494,7 +596,7 @@ theorem rpow_add_of_nonneg {x : ℝ≥0∞} (y z : ℝ) (hy : 0 ≤ y) (hz : 0 rcases hz.eq_or_lt with rfl|hz · rw [rpow_zero, mul_one, add_zero] simp [top_rpow_of_pos, hy, hz, add_pos hy hz] - simp [coe_rpow_of_nonneg, hy, hz, add_nonneg hy hz, NNReal.rpow_add_of_nonneg _ hy hz] + simp [← coe_rpow_of_nonneg, hy, hz, add_nonneg hy hz, NNReal.rpow_add_of_nonneg _ hy hz] theorem rpow_neg (x : ℝ≥0∞) (y : ℝ) : x ^ (-y) = (x ^ y)⁻¹ := by cases' x with x @@ -504,7 +606,7 @@ theorem rpow_neg (x : ℝ≥0∞) (y : ℝ) : x ^ (-y) = (x ^ y)⁻¹ := by · rcases lt_trichotomy y 0 with (H | H | H) <;> simp [h, zero_rpow_of_pos, zero_rpow_of_neg, H, neg_pos.mpr] · have A : x ^ y ≠ 0 := by simp [h] - simp [coe_rpow_of_ne_zero h, ← coe_inv A, NNReal.rpow_neg] + simp [← coe_rpow_of_ne_zero h, ← coe_inv A, NNReal.rpow_neg] theorem rpow_sub {x : ℝ≥0∞} (y z : ℝ) (hx : x ≠ 0) (h'x : x ≠ ⊤) : x ^ (y - z) = x ^ y / x ^ z := by rw [sub_eq_add_neg, rpow_add _ _ hx h'x, rpow_neg, div_eq_mul_inv] @@ -523,13 +625,13 @@ theorem rpow_mul (x : ℝ≥0∞) (y z : ℝ) : x ^ (y * z) = (x ^ y) ^ z := by simp [h, Hy, Hz, zero_rpow_of_neg, zero_rpow_of_pos, top_rpow_of_neg, top_rpow_of_pos, mul_pos_of_neg_of_neg, mul_neg_of_neg_of_pos, mul_neg_of_pos_of_neg] · have : x ^ y ≠ 0 := by simp [h] - simp [coe_rpow_of_ne_zero h, coe_rpow_of_ne_zero this, NNReal.rpow_mul] + simp [← coe_rpow_of_ne_zero, h, this, NNReal.rpow_mul] @[simp, norm_cast] theorem rpow_natCast (x : ℝ≥0∞) (n : ℕ) : x ^ (n : ℝ) = x ^ n := by cases x · cases n <;> simp [top_rpow_of_pos (Nat.cast_add_one_pos _), top_pow (Nat.succ_pos _)] - · simp [coe_rpow_of_nonneg _ (Nat.cast_nonneg n)] + · simp [← coe_rpow_of_nonneg _ (Nat.cast_nonneg n)] @[deprecated (since := "2024-04-17")] alias rpow_nat_cast := rpow_natCast @@ -564,9 +666,9 @@ 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] + rw [← coe_rpow_of_ne_zero (mul_ne_zero hx0 hy0), NNReal.mul_rpow] norm_cast theorem mul_rpow_of_ne_top {x y : ℝ≥0∞} (hx : x ≠ ⊤) (hy : y ≠ ⊤) (z : ℝ) : @@ -595,7 +697,7 @@ theorem prod_rpow_of_ne_top {ι} {s : Finset ι} {f : ι → ℝ≥0∞} (hf : | @insert i s hi ih => have h2f : ∀ i ∈ s, f i ≠ ∞ := fun i hi ↦ hf i <| mem_insert_of_mem hi rw [prod_insert hi, prod_insert hi, ih h2f, ← mul_rpow_of_ne_top <| hf i <| mem_insert_self ..] - apply prod_lt_top h2f |>.ne + apply prod_ne_top h2f theorem prod_rpow_of_nonneg {ι} {s : Finset ι} {f : ι → ℝ≥0∞} {r : ℝ} (hr : 0 ≤ r) : ∏ i ∈ s, f i ^ r = (∏ i ∈ s, f i) ^ r := by @@ -619,9 +721,9 @@ theorem strictMono_rpow_of_pos {z : ℝ} (h : 0 < z) : StrictMono fun x : ℝ≥ intro x y hxy lift x to ℝ≥0 using ne_top_of_lt hxy rcases eq_or_ne y ∞ with (rfl | hy) - · simp only [top_rpow_of_pos h, coe_rpow_of_nonneg _ h.le, coe_lt_top] + · simp only [top_rpow_of_pos h, ← coe_rpow_of_nonneg _ h.le, coe_lt_top] · lift y to ℝ≥0 using hy - simp only [coe_rpow_of_nonneg _ h.le, NNReal.rpow_lt_rpow (coe_lt_coe.1 hxy) h, coe_lt_coe] + simp only [← coe_rpow_of_nonneg _ h.le, NNReal.rpow_lt_rpow (coe_lt_coe.1 hxy) h, coe_lt_coe] theorem monotone_rpow_of_nonneg {z : ℝ} (h : 0 ≤ z) : Monotone fun x : ℝ≥0∞ => x ^ z := h.eq_or_lt.elim (fun h0 => h0 ▸ by simp only [rpow_zero, monotone_const]) fun h0 => @@ -693,7 +795,7 @@ theorem rpow_lt_rpow_of_exponent_lt {x : ℝ≥0∞} {y z : ℝ} (hx : 1 < x) (h x ^ y < x ^ z := by lift x to ℝ≥0 using hx' rw [one_lt_coe_iff] at hx - simp [coe_rpow_of_ne_zero (ne_of_gt (lt_trans zero_lt_one hx)), + simp [← coe_rpow_of_ne_zero (ne_of_gt (lt_trans zero_lt_one hx)), NNReal.rpow_lt_rpow_of_exponent_lt hx hyz] @[gcongr] theorem rpow_le_rpow_of_exponent_le {x : ℝ≥0∞} {y z : ℝ} (hx : 1 ≤ x) (hyz : y ≤ z) : @@ -704,14 +806,14 @@ theorem rpow_lt_rpow_of_exponent_lt {x : ℝ≥0∞} {y z : ℝ} (hx : 1 < x) (h simp [Hy, Hz, top_rpow_of_neg, top_rpow_of_pos, le_refl] <;> linarith · simp only [one_le_coe_iff, some_eq_coe] at hx - simp [coe_rpow_of_ne_zero (ne_of_gt (lt_of_lt_of_le zero_lt_one hx)), + simp [← coe_rpow_of_ne_zero (ne_of_gt (lt_of_lt_of_le zero_lt_one hx)), NNReal.rpow_le_rpow_of_exponent_le hx hyz] theorem rpow_lt_rpow_of_exponent_gt {x : ℝ≥0∞} {y z : ℝ} (hx0 : 0 < x) (hx1 : x < 1) (hyz : z < y) : x ^ y < x ^ z := by lift x to ℝ≥0 using ne_of_lt (lt_of_lt_of_le hx1 le_top) simp only [coe_lt_one_iff, coe_pos] at hx0 hx1 - simp [coe_rpow_of_ne_zero (ne_of_gt hx0), NNReal.rpow_lt_rpow_of_exponent_gt hx0 hx1 hyz] + simp [← coe_rpow_of_ne_zero (ne_of_gt hx0), NNReal.rpow_lt_rpow_of_exponent_gt hx0 hx1 hyz] theorem rpow_le_rpow_of_exponent_ge {x : ℝ≥0∞} {y z : ℝ} (hx1 : x ≤ 1) (hyz : z ≤ y) : x ^ y ≤ x ^ z := by @@ -722,7 +824,7 @@ theorem rpow_le_rpow_of_exponent_ge {x : ℝ≥0∞} {y z : ℝ} (hx1 : x ≤ 1) simp [Hy, Hz, h, zero_rpow_of_neg, zero_rpow_of_pos, le_refl] <;> linarith · rw [coe_le_one_iff] at hx1 - simp [coe_rpow_of_ne_zero h, + simp [← coe_rpow_of_ne_zero h, NNReal.rpow_le_rpow_of_exponent_ge (bot_lt_iff_ne_bot.mpr h) hx1 hyz] theorem rpow_le_self_of_le_one {x : ℝ≥0∞} {z : ℝ} (hx : x ≤ 1) (h_one_le : 1 ≤ z) : x ^ z ≤ x := by @@ -750,63 +852,63 @@ theorem rpow_pos {p : ℝ} {x : ℝ≥0∞} (hx_pos : 0 < x) (hx_ne_top : x ≠ theorem rpow_lt_one {x : ℝ≥0∞} {z : ℝ} (hx : x < 1) (hz : 0 < z) : x ^ z < 1 := by lift x to ℝ≥0 using ne_of_lt (lt_of_lt_of_le hx le_top) simp only [coe_lt_one_iff] at hx - simp [coe_rpow_of_nonneg _ (le_of_lt hz), NNReal.rpow_lt_one hx hz] + simp [← coe_rpow_of_nonneg _ (le_of_lt hz), NNReal.rpow_lt_one hx hz] theorem rpow_le_one {x : ℝ≥0∞} {z : ℝ} (hx : x ≤ 1) (hz : 0 ≤ z) : x ^ z ≤ 1 := by lift x to ℝ≥0 using ne_of_lt (lt_of_le_of_lt hx coe_lt_top) simp only [coe_le_one_iff] at hx - simp [coe_rpow_of_nonneg _ hz, NNReal.rpow_le_one hx hz] + simp [← coe_rpow_of_nonneg _ hz, NNReal.rpow_le_one hx hz] theorem rpow_lt_one_of_one_lt_of_neg {x : ℝ≥0∞} {z : ℝ} (hx : 1 < x) (hz : z < 0) : x ^ z < 1 := by cases x · simp [top_rpow_of_neg hz, zero_lt_one] · simp only [some_eq_coe, one_lt_coe_iff] at hx - simp [coe_rpow_of_ne_zero (ne_of_gt (lt_trans zero_lt_one hx)), + simp [← coe_rpow_of_ne_zero (ne_of_gt (lt_trans zero_lt_one hx)), NNReal.rpow_lt_one_of_one_lt_of_neg hx hz] theorem rpow_le_one_of_one_le_of_neg {x : ℝ≥0∞} {z : ℝ} (hx : 1 ≤ x) (hz : z < 0) : x ^ z ≤ 1 := by cases x · simp [top_rpow_of_neg hz, zero_lt_one] · simp only [one_le_coe_iff, some_eq_coe] at hx - simp [coe_rpow_of_ne_zero (ne_of_gt (lt_of_lt_of_le zero_lt_one hx)), + simp [← coe_rpow_of_ne_zero (ne_of_gt (lt_of_lt_of_le zero_lt_one hx)), NNReal.rpow_le_one_of_one_le_of_nonpos hx (le_of_lt hz)] theorem one_lt_rpow {x : ℝ≥0∞} {z : ℝ} (hx : 1 < x) (hz : 0 < z) : 1 < x ^ z := by cases x · simp [top_rpow_of_pos hz] · simp only [some_eq_coe, one_lt_coe_iff] at hx - simp [coe_rpow_of_nonneg _ (le_of_lt hz), NNReal.one_lt_rpow hx hz] + simp [← coe_rpow_of_nonneg _ (le_of_lt hz), NNReal.one_lt_rpow hx hz] theorem one_le_rpow {x : ℝ≥0∞} {z : ℝ} (hx : 1 ≤ x) (hz : 0 < z) : 1 ≤ x ^ z := by cases x · simp [top_rpow_of_pos hz] · simp only [one_le_coe_iff, some_eq_coe] at hx - simp [coe_rpow_of_nonneg _ (le_of_lt hz), NNReal.one_le_rpow hx (le_of_lt hz)] + simp [← coe_rpow_of_nonneg _ (le_of_lt hz), NNReal.one_le_rpow hx (le_of_lt hz)] theorem one_lt_rpow_of_pos_of_lt_one_of_neg {x : ℝ≥0∞} {z : ℝ} (hx1 : 0 < x) (hx2 : x < 1) (hz : z < 0) : 1 < x ^ z := by lift x to ℝ≥0 using ne_of_lt (lt_of_lt_of_le hx2 le_top) simp only [coe_lt_one_iff, coe_pos] at hx1 hx2 ⊢ - simp [coe_rpow_of_ne_zero (ne_of_gt hx1), NNReal.one_lt_rpow_of_pos_of_lt_one_of_neg hx1 hx2 hz] + simp [← coe_rpow_of_ne_zero (ne_of_gt hx1), NNReal.one_lt_rpow_of_pos_of_lt_one_of_neg hx1 hx2 hz] theorem one_le_rpow_of_pos_of_le_one_of_neg {x : ℝ≥0∞} {z : ℝ} (hx1 : 0 < x) (hx2 : x ≤ 1) (hz : z < 0) : 1 ≤ x ^ z := by lift x to ℝ≥0 using ne_of_lt (lt_of_le_of_lt hx2 coe_lt_top) simp only [coe_le_one_iff, coe_pos] at hx1 hx2 ⊢ - simp [coe_rpow_of_ne_zero (ne_of_gt hx1), + simp [← coe_rpow_of_ne_zero (ne_of_gt hx1), NNReal.one_le_rpow_of_pos_of_le_one_of_nonpos hx1 hx2 (le_of_lt hz)] -theorem toNNReal_rpow (x : ℝ≥0∞) (z : ℝ) : x.toNNReal ^ z = (x ^ z).toNNReal := by +@[simp] lemma toNNReal_rpow (x : ℝ≥0∞) (z : ℝ) : (x ^ z).toNNReal = x.toNNReal ^ z := by rcases lt_trichotomy z 0 with (H | H | H) · cases' x with x · simp [H, ne_of_lt] by_cases hx : x = 0 · simp [hx, H, ne_of_lt] - · simp [coe_rpow_of_ne_zero hx] + · simp [← coe_rpow_of_ne_zero hx] · simp [H] · cases x · simp [H, ne_of_gt] - simp [coe_rpow_of_nonneg _ (le_of_lt H)] + simp [← coe_rpow_of_nonneg _ (le_of_lt H)] theorem toReal_rpow (x : ℝ≥0∞) (z : ℝ) : x.toReal ^ z = (x ^ z).toReal := by rw [ENNReal.toReal, ENNReal.toReal, ← NNReal.coe_rpow, ENNReal.toNNReal_rpow] @@ -814,7 +916,7 @@ theorem toReal_rpow (x : ℝ≥0∞) (z : ℝ) : x.toReal ^ z = (x ^ z).toReal : theorem ofReal_rpow_of_pos {x p : ℝ} (hx_pos : 0 < x) : ENNReal.ofReal x ^ p = ENNReal.ofReal (x ^ p) := by simp_rw [ENNReal.ofReal] - rw [coe_rpow_of_ne_zero, coe_inj, Real.toNNReal_rpow_of_nonneg hx_pos.le] + rw [← coe_rpow_of_ne_zero, coe_inj, Real.toNNReal_rpow_of_nonneg hx_pos.le] simp [hx_pos] theorem ofReal_rpow_of_nonneg {x p : ℝ} (hx_nonneg : 0 ≤ x) (hp_nonneg : 0 ≤ p) : diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean index f36e3a7733dc3..b712f2e3cd568 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 @@ -372,37 +388,46 @@ theorem rpow_mul {x : ℝ} (hx : 0 ≤ x) (y z : ℝ) : x ^ (y * z) = (x ^ y) ^ simp only [(Complex.ofReal_mul _ _).symm, (Complex.ofReal_log hx).symm, Complex.ofReal_im, neg_lt_zero, pi_pos, le_of_lt pi_pos] -theorem rpow_add_int {x : ℝ} (hx : x ≠ 0) (y : ℝ) (n : ℤ) : x ^ (y + n) = x ^ y * x ^ n := by +lemma rpow_add_intCast {x : ℝ} (hx : x ≠ 0) (y : ℝ) (n : ℤ) : x ^ (y + n) = x ^ y * x ^ n := by rw [rpow_def, rpow_def, Complex.ofReal_add, Complex.cpow_add _ _ (Complex.ofReal_ne_zero.mpr hx), Complex.ofReal_intCast, Complex.cpow_intCast, ← Complex.ofReal_zpow, mul_comm, Complex.re_ofReal_mul, mul_comm] -theorem rpow_add_nat {x : ℝ} (hx : x ≠ 0) (y : ℝ) (n : ℕ) : x ^ (y + n) = x ^ y * x ^ n := by - simpa using rpow_add_int hx y n +lemma rpow_add_natCast {x : ℝ} (hx : x ≠ 0) (y : ℝ) (n : ℕ) : x ^ (y + n) = x ^ y * x ^ n := by + simpa using rpow_add_intCast hx y n -theorem rpow_sub_int {x : ℝ} (hx : x ≠ 0) (y : ℝ) (n : ℕ) : x ^ (y - n) = x ^ y / x ^ n := by - simpa using rpow_add_int hx y (-n) +lemma rpow_sub_intCast {x : ℝ} (hx : x ≠ 0) (y : ℝ) (n : ℕ) : x ^ (y - n) = x ^ y / x ^ n := by + simpa using rpow_add_intCast hx y (-n) -theorem rpow_sub_nat {x : ℝ} (hx : x ≠ 0) (y : ℝ) (n : ℕ) : x ^ (y - n) = x ^ y / x ^ n := by - simpa using rpow_sub_int hx y n +lemma rpow_sub_natCast {x : ℝ} (hx : x ≠ 0) (y : ℝ) (n : ℕ) : x ^ (y - n) = x ^ y / x ^ n := by + simpa using rpow_sub_intCast hx y n -lemma rpow_add_int' (hx : 0 ≤ x) {n : ℤ} (h : y + n ≠ 0) : x ^ (y + n) = x ^ y * x ^ n := by +lemma rpow_add_intCast' (hx : 0 ≤ x) {n : ℤ} (h : y + n ≠ 0) : x ^ (y + n) = x ^ y * x ^ n := by rw [rpow_add' hx h, rpow_intCast] -lemma rpow_add_nat' (hx : 0 ≤ x) (h : y + n ≠ 0) : x ^ (y + n) = x ^ y * x ^ n := by +lemma rpow_add_natCast' (hx : 0 ≤ x) (h : y + n ≠ 0) : x ^ (y + n) = x ^ y * x ^ n := by rw [rpow_add' hx h, rpow_natCast] -lemma rpow_sub_int' (hx : 0 ≤ x) {n : ℤ} (h : y - n ≠ 0) : x ^ (y - n) = x ^ y / x ^ n := by +lemma rpow_sub_intCast' (hx : 0 ≤ x) {n : ℤ} (h : y - n ≠ 0) : x ^ (y - n) = x ^ y / x ^ n := by rw [rpow_sub' hx h, rpow_intCast] -lemma rpow_sub_nat' (hx : 0 ≤ x) (h : y - n ≠ 0) : x ^ (y - n) = x ^ y / x ^ n := by +lemma rpow_sub_natCast' (hx : 0 ≤ x) (h : y - n ≠ 0) : x ^ (y - n) = x ^ y / x ^ n := by rw [rpow_sub' hx h, rpow_natCast] +@[deprecated (since := "2024-08-28")] alias rpow_add_int := rpow_add_intCast +@[deprecated (since := "2024-08-28")] alias rpow_add_nat := rpow_add_natCast +@[deprecated (since := "2024-08-28")] alias rpow_sub_int := rpow_sub_intCast +@[deprecated (since := "2024-08-28")] alias rpow_sub_nat := rpow_sub_natCast +@[deprecated (since := "2024-08-28")] alias rpow_add_int' := rpow_add_intCast' +@[deprecated (since := "2024-08-28")] alias rpow_add_nat' := rpow_add_natCast' +@[deprecated (since := "2024-08-28")] alias rpow_sub_int' := rpow_sub_intCast' +@[deprecated (since := "2024-08-28")] alias rpow_sub_nat' := rpow_sub_natCast' + theorem rpow_add_one {x : ℝ} (hx : x ≠ 0) (y : ℝ) : x ^ (y + 1) = x ^ y * x := by - simpa using rpow_add_nat hx y 1 + simpa using rpow_add_natCast hx y 1 theorem rpow_sub_one {x : ℝ} (hx : x ≠ 0) (y : ℝ) : x ^ (y - 1) = x ^ y / x := by - simpa using rpow_sub_nat hx y 1 + simpa using rpow_sub_natCast hx y 1 lemma rpow_add_one' (hx : 0 ≤ x) (h : y + 1 ≠ 0) : x ^ (y + 1) = x ^ y * x := by rw [rpow_add' hx h, rpow_one] @@ -503,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 @@ -567,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) : @@ -694,23 +719,103 @@ lemma rpow_inv_eq (hx : 0 ≤ x) (hy : 0 ≤ y) (hz : z ≠ 0) : x ^ z⁻¹ = y lemma eq_rpow_inv (hx : 0 ≤ x) (hy : 0 ≤ y) (hz : z ≠ 0) : x = y ^ z⁻¹ ↔ x ^ z = y := by rw [← rpow_left_inj hx _ hz, rpow_inv_rpow hy hz]; positivity -theorem le_rpow_iff_log_le (hx : 0 < x) (hy : 0 < y) : x ≤ y ^ z ↔ Real.log x ≤ z * Real.log y := by - rw [← Real.log_le_log_iff hx (Real.rpow_pos_of_pos hy z), Real.log_rpow hy] +theorem le_rpow_iff_log_le (hx : 0 < x) (hy : 0 < y) : x ≤ y ^ z ↔ log x ≤ z * log y := by + rw [← log_le_log_iff hx (rpow_pos_of_pos hy z), log_rpow hy] + +lemma le_pow_iff_log_le (hx : 0 < x) (hy : 0 < y) : x ≤ y ^ n ↔ log x ≤ n * log y := + rpow_natCast _ _ ▸ le_rpow_iff_log_le hx hy + +lemma le_zpow_iff_log_le {n : ℤ} (hx : 0 < x) (hy : 0 < y) : x ≤ y ^ n ↔ log x ≤ n * log y := + rpow_intCast _ _ ▸ le_rpow_iff_log_le hx hy + +lemma le_rpow_of_log_le (hy : 0 < y) (h : log x ≤ z * log y) : x ≤ y ^ z := by + obtain hx | hx := le_or_lt x 0 + · exact hx.trans (rpow_pos_of_pos hy _).le + · exact (le_rpow_iff_log_le hx hy).2 h + +lemma le_pow_of_log_le (hy : 0 < y) (h : log x ≤ n * log y) : x ≤ y ^ n := + rpow_natCast _ _ ▸ le_rpow_of_log_le hy h + +lemma le_zpow_of_log_le {n : ℤ} (hy : 0 < y) (h : log x ≤ n * log y) : x ≤ y ^ n := + rpow_intCast _ _ ▸ le_rpow_of_log_le hy h + +theorem lt_rpow_iff_log_lt (hx : 0 < x) (hy : 0 < y) : x < y ^ z ↔ log x < z * log y := by + rw [← log_lt_log_iff hx (rpow_pos_of_pos hy z), log_rpow hy] + +lemma lt_pow_iff_log_lt (hx : 0 < x) (hy : 0 < y) : x < y ^ n ↔ log x < n * log y := + rpow_natCast _ _ ▸ lt_rpow_iff_log_lt hx hy + +lemma lt_zpow_iff_log_lt {n : ℤ} (hx : 0 < x) (hy : 0 < y) : x < y ^ n ↔ log x < n * log y := + rpow_intCast _ _ ▸ lt_rpow_iff_log_lt hx hy + +lemma lt_rpow_of_log_lt (hy : 0 < y) (h : log x < z * log y) : x < y ^ z := by + obtain hx | hx := le_or_lt x 0 + · exact hx.trans_lt (rpow_pos_of_pos hy _) + · exact (lt_rpow_iff_log_lt hx hy).2 h + +lemma lt_pow_of_log_lt (hy : 0 < y) (h : log x < n * log y) : x < y ^ n := + rpow_natCast _ _ ▸ lt_rpow_of_log_lt hy h + +lemma lt_zpow_of_log_lt {n : ℤ} (hy : 0 < y) (h : log x < n * log y) : x < y ^ n := + rpow_intCast _ _ ▸ lt_rpow_of_log_lt hy h -theorem le_rpow_of_log_le (hx : 0 ≤ x) (hy : 0 < y) (h : Real.log x ≤ z * Real.log y) : - x ≤ y ^ z := by - obtain hx | rfl := hx.lt_or_eq +lemma rpow_le_iff_le_log (hx : 0 < x) (hy : 0 < y) : x ^ z ≤ y ↔ z * log x ≤ log y := by + rw [← log_le_log_iff (rpow_pos_of_pos hx _) hy, log_rpow hx] + +lemma pow_le_iff_le_log (hx : 0 < x) (hy : 0 < y) : x ^ n ≤ y ↔ n * log x ≤ log y := by + rw [← rpow_le_iff_le_log hx hy, rpow_natCast] + +lemma zpow_le_iff_le_log {n : ℤ} (hx : 0 < x) (hy : 0 < y) : x ^ n ≤ y ↔ n * log x ≤ log y := by + rw [← rpow_le_iff_le_log hx hy, rpow_intCast] + +lemma le_log_of_rpow_le (hx : 0 < x) (h : x ^ z ≤ y) : z * log x ≤ log y := + log_rpow hx _ ▸ log_le_log (by positivity) h + +lemma le_log_of_pow_le (hx : 0 < x) (h : x ^ n ≤ y) : n * log x ≤ log y := + le_log_of_rpow_le hx (rpow_natCast _ _ ▸ h) + +lemma le_log_of_zpow_le {n : ℤ} (hx : 0 < x) (h : x ^ n ≤ y) : n * log x ≤ log y := + le_log_of_rpow_le hx (rpow_intCast _ _ ▸ h) + +lemma rpow_le_of_le_log (hy : 0 < y) (h : log x ≤ z * log y) : x ≤ y ^ z := by + obtain hx | hx := le_or_lt x 0 + · exact hx.trans (rpow_pos_of_pos hy _).le · exact (le_rpow_iff_log_le hx hy).2 h - exact (Real.rpow_pos_of_pos hy z).le -theorem lt_rpow_iff_log_lt (hx : 0 < x) (hy : 0 < y) : x < y ^ z ↔ Real.log x < z * Real.log y := by - rw [← Real.log_lt_log_iff hx (Real.rpow_pos_of_pos hy z), Real.log_rpow hy] +lemma pow_le_of_le_log (hy : 0 < y) (h : log x ≤ n * log y) : x ≤ y ^ n := + rpow_natCast _ _ ▸ rpow_le_of_le_log hy h + +lemma zpow_le_of_le_log {n : ℤ} (hy : 0 < y) (h : log x ≤ n * log y) : x ≤ y ^ n := + rpow_intCast _ _ ▸ rpow_le_of_le_log hy h + +lemma rpow_lt_iff_lt_log (hx : 0 < x) (hy : 0 < y) : x ^ z < y ↔ z * log x < log y := by + rw [← log_lt_log_iff (rpow_pos_of_pos hx _) hy, log_rpow hx] -theorem lt_rpow_of_log_lt (hx : 0 ≤ x) (hy : 0 < y) (h : Real.log x < z * Real.log y) : - x < y ^ z := by - obtain hx | rfl := hx.lt_or_eq +lemma pow_lt_iff_lt_log (hx : 0 < x) (hy : 0 < y) : x ^ n < y ↔ n * log x < log y := by + rw [← rpow_lt_iff_lt_log hx hy, rpow_natCast] + +lemma zpow_lt_iff_lt_log {n : ℤ} (hx : 0 < x) (hy : 0 < y) : x ^ n < y ↔ n * log x < log y := by + rw [← rpow_lt_iff_lt_log hx hy, rpow_intCast] + +lemma lt_log_of_rpow_lt (hx : 0 < x) (h : x ^ z < y) : z * log x < log y := + log_rpow hx _ ▸ log_lt_log (by positivity) h + +lemma lt_log_of_pow_lt (hx : 0 < x) (h : x ^ n < y) : n * log x < log y := + lt_log_of_rpow_lt hx (rpow_natCast _ _ ▸ h) + +lemma lt_log_of_zpow_lt {n : ℤ} (hx : 0 < x) (h : x ^ n < y) : n * log x < log y := + lt_log_of_rpow_lt hx (rpow_intCast _ _ ▸ h) + +lemma rpow_lt_of_lt_log (hy : 0 < y) (h : log x < z * log y) : x < y ^ z := by + obtain hx | hx := le_or_lt x 0 + · exact hx.trans_lt (rpow_pos_of_pos hy _) · exact (lt_rpow_iff_log_lt hx hy).2 h - exact Real.rpow_pos_of_pos hy z + +lemma pow_lt_of_lt_log (hy : 0 < y) (h : log x < n * log y) : x < y ^ n := + rpow_natCast _ _ ▸ rpow_lt_of_lt_log hy h + +lemma zpow_lt_of_lt_log {n : ℤ} (hy : 0 < y) (h : log x < n * log y) : x < y ^ n := + rpow_intCast _ _ ▸ rpow_lt_of_lt_log hy h theorem rpow_le_one_iff_of_pos (hx : 0 < x) : x ^ y ≤ 1 ↔ 1 ≤ x ∧ y ≤ 0 ∨ x ≤ 1 ∧ 0 ≤ y := by rw [rpow_def_of_pos hx, exp_le_one_iff, mul_nonpos_iff, log_nonneg_iff hx, log_nonpos_iff hx] @@ -718,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 @@ -726,7 +831,7 @@ theorem abs_log_mul_self_rpow_lt (x t : ℝ) (h1 : 0 < x) (h2 : x ≤ 1) (ht : 0 lemma log_le_rpow_div {x ε : ℝ} (hx : 0 ≤ x) (hε : 0 < ε) : log x ≤ x ^ ε / ε := by rcases hx.eq_or_lt with rfl | h · rw [log_zero, zero_rpow hε.ne', zero_div] - rw [le_div_iff' hε] + rw [le_div_iff₀' hε] exact (log_rpow h ε).symm.trans_le <| (log_le_sub_one_of_pos <| rpow_pos_of_pos h ε).trans (sub_one_lt _).le 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 6dd45e6fe5610..c5ed691712471 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Angle.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Angle.lean @@ -204,7 +204,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 +252,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 @@ -554,8 +554,8 @@ 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', - le_div_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} : ((2 : ℕ) • θ).toReal = 2 * θ.toReal ↔ θ.toReal ∈ Set.Ioc (-π / 2) (π / 2) := @@ -585,7 +585,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 @@ -597,7 +597,7 @@ theorem two_nsmul_toReal_eq_two_mul_add_two_pi {θ : Angle} : rw [← coe_nsmul, two_nsmul, ← two_mul, toReal_coe_eq_self_add_two_pi_iff, Set.mem_Ioc] refine ⟨fun h => by linarith, fun h => - ⟨by linarith [pi_pos, neg_pi_lt_toReal θ], (le_div_iff' (zero_lt_two' ℝ)).1 h⟩⟩ + ⟨by linarith [pi_pos, neg_pi_lt_toReal θ], (le_div_iff₀' (zero_lt_two' ℝ)).1 h⟩⟩ theorem two_zsmul_toReal_eq_two_mul_add_two_pi {θ : Angle} : ((2 : ℤ) • θ).toReal = 2 * θ.toReal + 2 * π ↔ θ.toReal ≤ -π / 2 := by diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean index 47d4af9b30a03..6919f9dcbb728 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean @@ -72,7 +72,7 @@ theorem continuousOn_tan_Ioo : ContinuousOn tan (Ioo (-(π / 2)) (π / 2)) := by rw [hxr_eq, ← one_mul (π / 2), mul_div_assoc, ge_iff_le, neg_mul_eq_neg_mul, mul_le_mul_right (half_pos pi_pos)] have hr_le : r ≤ -1 := by rwa [Int.lt_iff_add_one_le, ← le_neg_iff_add_nonpos_right] at h - rw [← le_sub_iff_add_le, mul_comm, ← le_div_iff] + rw [← le_sub_iff_add_le, mul_comm, ← le_div_iff₀] · norm_num rw [← Int.cast_one, ← Int.cast_neg]; norm_cast · exact zero_lt_two @@ -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 c9617df307a4e..ff16ee4d5471a 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 @@ -301,6 +302,10 @@ theorem cos_antiperiodic : Function.Antiperiodic cos π := by simp [cos_add] theorem cos_periodic : Function.Periodic cos (2 * π) := cos_antiperiodic.periodic_two_mul +@[simp] +theorem abs_cos_int_mul_pi (k : ℤ) : |cos (k * π)| = 1 := by + simp [abs_cos_eq_sqrt_one_sub_sin_sq] + @[simp] theorem cos_add_pi (x : ℝ) : cos (x + π) = -cos x := cos_antiperiodic x @@ -513,7 +518,7 @@ 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 @@ -657,7 +662,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, @@ -679,14 +684,14 @@ theorem sin_sq_pi_over_two_pow_succ (n : ℕ) : @[simp] theorem sin_pi_over_two_pow_succ (n : ℕ) : sin (π / 2 ^ (n + 2)) = √(2 - sqrtTwoAddSeries 0 n) / 2 := by - rw [eq_div_iff_mul_eq two_ne_zero, eq_comm, sqrt_eq_iff_sq_eq, mul_pow, + rw [eq_div_iff_mul_eq two_ne_zero, eq_comm, sqrt_eq_iff_eq_sq, mul_pow, sin_sq_pi_over_two_pow_succ, sub_mul] · congr <;> norm_num · rw [sub_nonneg] 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 @@ -791,6 +796,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 cc9089213f44b..f3a9858bddf37 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Bounds.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Bounds.lean @@ -1,8 +1,9 @@ /- Copyright (c) 2022 David Loeffler. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: David Loeffler, Yaël Dillies +Authors: David Loeffler, Yaël Dillies, Bhavik Mehta -/ +import Mathlib.Analysis.Convex.SpecificFunctions.Deriv import Mathlib.Analysis.SpecialFunctions.Trigonometric.ArctanDeriv /-! @@ -54,79 +55,94 @@ lemma sin_le (hx : 0 ≤ x) : sin x ≤ x := by lemma lt_sin (hx : x < 0) : x < sin x := by simpa using sin_lt <| neg_pos.2 hx lemma le_sin (hx : x ≤ 0) : x ≤ sin x := by simpa using sin_le <| neg_nonneg.2 hx -lemma one_sub_sq_div_two_le_cos : 1 - x ^ 2 / 2 ≤ cos x := by +theorem lt_sin_mul {x : ℝ} (hx : 0 < x) (hx' : x < 1) : x < sin (π / 2 * x) := by + simpa [mul_comm x] using + strictConcaveOn_sin_Icc.2 ⟨le_rfl, pi_pos.le⟩ ⟨pi_div_two_pos.le, half_le_self pi_pos.le⟩ + pi_div_two_pos.ne (sub_pos.2 hx') hx + +theorem le_sin_mul {x : ℝ} (hx : 0 ≤ x) (hx' : x ≤ 1) : x ≤ sin (π / 2 * x) := by + simpa [mul_comm x] using + strictConcaveOn_sin_Icc.concaveOn.2 ⟨le_rfl, pi_pos.le⟩ + ⟨pi_div_two_pos.le, half_le_self pi_pos.le⟩ (sub_nonneg.2 hx') hx + +theorem mul_lt_sin {x : ℝ} (hx : 0 < x) (hx' : x < π / 2) : 2 / π * x < sin x := by + rw [← inv_div] + simpa [-inv_div, mul_inv_cancel_left₀ pi_div_two_pos.ne'] using @lt_sin_mul ((π / 2)⁻¹ * x) + (mul_pos (inv_pos.2 pi_div_two_pos) hx) (by rwa [← div_eq_inv_mul, div_lt_one pi_div_two_pos]) + +/-- One half of **Jordan's inequality**. + +In the range `[0, π / 2]`, we have a linear lower bound on `sin`. The other half is given by +`Real.sin_le`. +-/ +theorem mul_le_sin {x : ℝ} (hx : 0 ≤ x) (hx' : x ≤ π / 2) : 2 / π * x ≤ sin x := by + rw [← inv_div] + simpa [-inv_div, mul_inv_cancel_left₀ pi_div_two_pos.ne'] using @le_sin_mul ((π / 2)⁻¹ * x) + (mul_nonneg (inv_nonneg.2 pi_div_two_pos.le) hx) + (by rwa [← div_eq_inv_mul, div_le_one pi_div_two_pos]) + +/-- Half of **Jordan's inequality** for negative values. -/ +lemma sin_le_mul (hx : -(π / 2) ≤ x) (hx₀ : x ≤ 0) : sin x ≤ 2 / π * x := by + simpa using mul_le_sin (neg_nonneg.2 hx₀) (neg_le.2 hx) + +/-- Half of **Jordan's inequality** for absolute values. -/ +lemma mul_abs_le_abs_sin (hx : |x| ≤ π / 2) : 2 / π * |x| ≤ |sin x| := by wlog hx₀ : 0 ≤ x - · simpa using this $ neg_nonneg.2 $ le_of_not_le hx₀ - suffices MonotoneOn (fun x ↦ cos x + x ^ 2 / 2) (Ici 0) by - simpa using this left_mem_Ici hx₀ hx₀ - refine monotoneOn_of_hasDerivWithinAt_nonneg - (convex_Ici _) (by fun_prop) - (fun x _ ↦ ((hasDerivAt_cos ..).add <| (hasDerivAt_pow ..).div_const _).hasDerivWithinAt) - fun x hx ↦ ?_ - simpa [mul_div_cancel_left₀] using sin_le <| interior_subset hx - -/-- **Jordan's inequality**. -/ -lemma two_div_pi_mul_le_sin (hx₀ : 0 ≤ x) (hx : x ≤ π / 2) : 2 / π * x ≤ sin x := by - rw [← sub_nonneg] - suffices ConcaveOn ℝ (Icc 0 (π / 2)) (fun x ↦ sin x - 2 / π * x) by - refine (le_min ?_ ?_).trans $ this.min_le_of_mem_Icc ⟨hx₀, hx⟩ <;> field_simp - exact concaveOn_of_hasDerivWithinAt2_nonpos (convex_Icc ..) - (Continuous.continuousOn $ by fun_prop) - (fun x _ ↦ ((hasDerivAt_sin ..).sub $ (hasDerivAt_id ..).const_mul (2 / π)).hasDerivWithinAt) - (fun x _ ↦ (hasDerivAt_cos ..).hasDerivWithinAt.sub_const _) - fun x hx ↦ neg_nonpos.2 $ sin_nonneg_of_mem_Icc $ Icc_subset_Icc_right (by linarith) $ - interior_subset hx - -/-- **Jordan's inequality** for negative values. -/ -lemma sin_le_two_div_pi_mul (hx : -(π / 2) ≤ x) (hx₀ : x ≤ 0) : sin x ≤ 2 / π * x := by - simpa using two_div_pi_mul_le_sin (neg_nonneg.2 hx₀) (neg_le.2 hx) - -/-- **Jordan's inequality** for `cos`. -/ -lemma one_sub_two_div_pi_mul_le_cos (hx₀ : 0 ≤ x) (hx : x ≤ π / 2) : 1 - 2 / π * x ≤ cos x := by - simpa [sin_pi_div_two_sub, mul_sub, div_mul_div_comm, mul_comm π, div_self two_pi_pos.ne'] - using two_div_pi_mul_le_sin (x := π / 2 - x) (by simpa) (by simpa) - -lemma cos_quadratic_upper_bound (hx : |x| ≤ π) : cos x ≤ 1 - 2 / π ^ 2 * x ^ 2 := by + case inr => simpa using this (by rwa [abs_neg]) <| neg_nonneg.2 <| le_of_not_le hx₀ + rw [abs_of_nonneg hx₀] at hx ⊢ + exact (mul_le_sin hx₀ hx).trans (le_abs_self _) + +lemma sin_sq_lt_sq (hx : x ≠ 0) : sin x ^ 2 < x ^ 2 := by + wlog hx₀ : 0 < x + case inr => + simpa using this (neg_ne_zero.2 hx) <| neg_pos_of_neg <| hx.lt_of_le <| le_of_not_lt hx₀ + rcases le_or_lt x 1 with hxπ | hxπ + case inl => + exact pow_lt_pow_left (sin_lt hx₀) + (sin_nonneg_of_nonneg_of_le_pi hx₀.le (by linarith [two_le_pi])) (by simp) + case inr => + exact (sin_sq_le_one _).trans_lt (by rwa [one_lt_sq_iff hx₀.le]) + +lemma sin_sq_le_sq : sin x ^ 2 ≤ x ^ 2 := by + rcases eq_or_ne x 0 with rfl | hx + case inl => simp + case inr => exact (sin_sq_lt_sq hx).le + +lemma abs_sin_lt_abs (hx : x ≠ 0) : |sin x| < |x| := sq_lt_sq.1 (sin_sq_lt_sq hx) +lemma abs_sin_le_abs : |sin x| ≤ |x| := sq_le_sq.1 sin_sq_le_sq + +lemma one_sub_sq_div_two_lt_cos (hx : x ≠ 0) : 1 - x ^ 2 / 2 < cos x := by + have := (sin_sq_lt_sq (by positivity)).trans_eq' (sin_sq_eq_half_sub (x / 2)).symm + ring_nf at this + linarith + +lemma one_sub_sq_div_two_le_cos : 1 - x ^ 2 / 2 ≤ cos x := by + rcases eq_or_ne x 0 with rfl | hx + case inl => simp + case inr => exact (one_sub_sq_div_two_lt_cos hx).le + +/-- Half of **Jordan's inequality** for `cos`. -/ +lemma one_sub_mul_le_cos (hx₀ : 0 ≤ x) (hx : x ≤ π / 2) : 1 - 2 / π * x ≤ cos x := by + simpa [sin_pi_div_two_sub, mul_sub, div_mul_div_comm, mul_comm π, pi_pos.ne'] + using mul_le_sin (x := π / 2 - x) (by simpa) (by simpa) + +/-- Half of **Jordan's inequality** for `cos` and negative values. -/ +lemma one_add_mul_le_cos (hx₀ : -(π / 2) ≤ x) (hx : x ≤ 0) : 1 + 2 / π * x ≤ cos x := by + simpa using one_sub_mul_le_cos (x := -x) (by linarith) (by linarith) + +lemma cos_le_one_sub_mul_cos_sq (hx : |x| ≤ π) : cos x ≤ 1 - 2 / π ^ 2 * x ^ 2 := by wlog hx₀ : 0 ≤ x - · simpa using this (by rwa [abs_neg]) $ neg_nonneg.2 $ le_of_not_le hx₀ + case inr => simpa using this (by rwa [abs_neg]) <| neg_nonneg.2 <| le_of_not_le hx₀ rw [abs_of_nonneg hx₀] at hx - -- TODO: `compute_deriv` tactic? - have hderiv (x) : HasDerivAt (fun x ↦ 1 - 2 / π ^ 2 * x ^ 2 - cos x) _ x := - (((hasDerivAt_pow ..).const_mul _).const_sub _).sub $ hasDerivAt_cos _ - simp only [Nat.cast_ofNat, Nat.succ_sub_succ_eq_sub, tsub_zero, pow_one, ← neg_sub', neg_sub, - ← mul_assoc] at hderiv - have hmono : MonotoneOn (fun x ↦ 1 - 2 / π ^ 2 * x ^ 2 - cos x) (Icc 0 (π / 2)) := by - -- Compiles without this option, but somewhat slower. - set_option tactic.skipAssignedInstances false in - refine monotoneOn_of_hasDerivWithinAt_nonneg - (convex_Icc ..) - (Continuous.continuousOn $ by fun_prop) - (fun x _ ↦ (hderiv _).hasDerivWithinAt) - fun x hx ↦ sub_nonneg.2 ?_ - have ⟨hx₀, hx⟩ := interior_subset hx - calc 2 / π ^ 2 * 2 * x - = 2 / π * (2 / π * x) := by ring - _ ≤ 1 * sin x := by - gcongr; exacts [div_le_one_of_le two_le_pi (by positivity), two_div_pi_mul_le_sin hx₀ hx] - _ = sin x := one_mul _ - have hconc : ConcaveOn ℝ (Icc (π / 2) π) (fun x ↦ 1 - 2 / π ^ 2 * x ^ 2 - cos x) := by - -- Compiles without this option, but somewhat slower. - set_option tactic.skipAssignedInstances false in - refine concaveOn_of_hasDerivWithinAt2_nonpos (convex_Icc ..) - (Continuous.continuousOn $ by fun_prop) (fun x _ ↦ (hderiv _).hasDerivWithinAt) - (fun x _ ↦ ((hasDerivAt_sin ..).sub $ (hasDerivAt_id ..).const_mul _).hasDerivWithinAt) - fun x hx ↦ ?_ - have ⟨hx, hx'⟩ := interior_subset hx - calc - _ ≤ (0 : ℝ) - 0 := by - gcongr - · exact cos_nonpos_of_pi_div_two_le_of_le hx $ hx'.trans $ by linarith - · positivity - _ = 0 := sub_zero _ - rw [← sub_nonneg] - obtain hx' | hx' := le_total x (π / 2) - · simpa using hmono (left_mem_Icc.2 $ by positivity) ⟨hx₀, hx'⟩ hx₀ - · refine (le_min ?_ ?_).trans $ hconc.min_le_of_mem_Icc ⟨hx', hx⟩ <;> field_simp <;> norm_num + have : x / π ≤ sin (x / 2) := by simpa using mul_le_sin (x := x / 2) (by positivity) (by linarith) + have := (pow_le_pow_left (by positivity) this 2).trans_eq (sin_sq_eq_half_sub _) + ring_nf at this ⊢ + linarith + +@[deprecated (since := "2024-08-29")] alias two_div_pi_mul_le_sin := mul_le_sin +@[deprecated (since := "2024-08-29")] alias sin_le_two_div_pi_mul := sin_le_mul +@[deprecated (since := "2024-08-29")] alias one_sub_two_div_pi_mul_le_cos := one_sub_mul_le_cos +@[deprecated (since := "2024-08-29")] alias cos_quadratic_upper_bound := cos_le_one_sub_mul_cos_sq /-- For 0 < x ≤ 1 we have x - x ^ 3 / 4 < sin x. @@ -157,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 @@ -170,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 @@ -179,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 b4ed209b1d7de..34180b091bfb1 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Complex.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Complex.lean @@ -4,7 +4,6 @@ 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.Convex.SpecificFunctions.Deriv import Mathlib.Analysis.SpecialFunctions.Pow.Complex /-! @@ -59,7 +58,7 @@ theorem sin_ne_zero_iff {θ : ℂ} : sin θ ≠ 0 ↔ ∀ k : ℤ, θ ≠ k * π iff this number is equal to `k * π / 2` for an integer `k`. Note that this lemma takes into account that we use zero as the junk value for division by zero. -See also `Complex.tan_eq_zero_iff'`. -/ +See also `Complex.tan_eq_zero_iff'`. -/ theorem tan_eq_zero_iff {θ : ℂ} : tan θ = 0 ↔ ∃ k : ℤ, k * π / 2 = θ := by rw [tan, div_eq_zero_iff, ← mul_eq_zero, ← mul_right_inj' two_ne_zero, mul_zero, ← mul_assoc, ← sin_two_mul, sin_eq_zero_iff] @@ -118,8 +117,7 @@ theorem tan_add {x y : ℂ} tan (x + y) = (tan x + tan y) / (1 - tan x * tan y) := by rcases h with (⟨h1, h2⟩ | ⟨⟨k, rfl⟩, ⟨l, rfl⟩⟩) · rw [tan, sin_add, cos_add, ← - div_div_div_cancel_right (sin x * cos y + cos x * sin y) - (mul_ne_zero (cos_ne_zero_iff.mpr h1) (cos_ne_zero_iff.mpr h2)), + div_div_div_cancel_right₀ (mul_ne_zero (cos_ne_zero_iff.mpr h1) (cos_ne_zero_iff.mpr h2)), add_div, sub_div] simp only [← div_mul_div_comm, tan, mul_one, one_mul, div_self (cos_ne_zero_iff.mpr h1), div_self (cos_ne_zero_iff.mpr h2)] @@ -174,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⟩ @@ -237,27 +235,4 @@ theorem tan_eq_zero_iff' {θ : ℝ} (hθ : cos θ ≠ 0) : tan θ = 0 ↔ ∃ k theorem tan_ne_zero_iff {θ : ℝ} : tan θ ≠ 0 ↔ ∀ k : ℤ, k * π / 2 ≠ θ := mod_cast @Complex.tan_ne_zero_iff θ -theorem lt_sin_mul {x : ℝ} (hx : 0 < x) (hx' : x < 1) : x < sin (π / 2 * x) := by - simpa [mul_comm x] using - strictConcaveOn_sin_Icc.2 ⟨le_rfl, pi_pos.le⟩ ⟨pi_div_two_pos.le, half_le_self pi_pos.le⟩ - pi_div_two_pos.ne (sub_pos.2 hx') hx - -theorem le_sin_mul {x : ℝ} (hx : 0 ≤ x) (hx' : x ≤ 1) : x ≤ sin (π / 2 * x) := by - simpa [mul_comm x] using - strictConcaveOn_sin_Icc.concaveOn.2 ⟨le_rfl, pi_pos.le⟩ - ⟨pi_div_two_pos.le, half_le_self pi_pos.le⟩ (sub_nonneg.2 hx') hx - -theorem mul_lt_sin {x : ℝ} (hx : 0 < x) (hx' : x < π / 2) : 2 / π * x < sin x := by - rw [← inv_div] - simpa [-inv_div, mul_inv_cancel_left₀ pi_div_two_pos.ne'] using @lt_sin_mul ((π / 2)⁻¹ * x) - (mul_pos (inv_pos.2 pi_div_two_pos) hx) (by rwa [← div_eq_inv_mul, div_lt_one pi_div_two_pos]) - -/-- In the range `[0, π / 2]`, we have a linear lower bound on `sin`. This inequality forms one half -of Jordan's inequality, the other half is `Real.sin_lt` -/ -theorem mul_le_sin {x : ℝ} (hx : 0 ≤ x) (hx' : x ≤ π / 2) : 2 / π * x ≤ sin x := by - rw [← inv_div] - simpa [-inv_div, mul_inv_cancel_left₀ pi_div_two_pos.ne'] using @le_sin_mul ((π / 2)⁻¹ * x) - (mul_nonneg (inv_nonneg.2 pi_div_two_pos.le) hx) - (by rwa [← div_eq_inv_mul, div_le_one pi_div_two_pos]) - end Real diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/ComplexDeriv.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/ComplexDeriv.lean index 6d74a3ace85b2..e414b1421381a 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/ComplexDeriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/ComplexDeriv.lean @@ -4,6 +4,7 @@ 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.Analysis.SpecialFunctions.Trigonometric.Complex +import Mathlib.Analysis.SpecialFunctions.Trigonometric.Deriv /-! # Complex trigonometric functions 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/SpecialFunctions/Trigonometric/EulerSineProd.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/EulerSineProd.lean index 7b8d099c1e98a..fc6711228b07f 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/EulerSineProd.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/EulerSineProd.lean @@ -141,7 +141,7 @@ theorem integral_sin_mul_sin_mul_cos_pow_eq (hn : 2 ≤ n) (hz : z ≠ 0) : · apply Continuous.intervalIntegrable exact Complex.continuous_sin.comp (continuous_const.mul Complex.continuous_ofReal) -/-- Note this also holds for `z = 0`, but we do not need this case for `sin_pi_mul_eq`. -/ +/-- Note this also holds for `z = 0`, but we do not need this case for `sin_pi_mul_eq`. -/ theorem integral_cos_mul_cos_pow (hn : 2 ≤ n) (hz : z ≠ 0) : (((1 : ℂ) - (4 : ℂ) * z ^ 2 / (n : ℂ) ^ 2) * ∫ x in (0 : ℝ)..π / 2, Complex.cos (2 * z * x) * (cos x : ℂ) ^ n) = diff --git a/Mathlib/Analysis/SpecificLimits/Basic.lean b/Mathlib/Analysis/SpecificLimits/Basic.lean index 903a92a213646..c0a2df7d23e61 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 @@ -99,7 +99,7 @@ statement simultaneously on `ℚ`, `ℝ` and `ℂ`. -/ theorem tendsto_natCast_div_add_atTop {𝕜 : Type*} [DivisionRing 𝕜] [TopologicalSpace 𝕜] [CharZero 𝕜] [Algebra ℝ 𝕜] [ContinuousSMul ℝ 𝕜] [TopologicalDivisionRing 𝕜] (x : 𝕜) : Tendsto (fun n : ℕ ↦ (n : 𝕜) / (n + x)) atTop (𝓝 1) := by - convert Tendsto.congr' ((eventually_ne_atTop 0).mp (eventually_of_forall fun n hn ↦ _)) _ + convert Tendsto.congr' ((eventually_ne_atTop 0).mp (Eventually.of_forall fun n hn ↦ _)) _ · exact fun n : ℕ ↦ 1 / (1 + x / n) · field_simp [Nat.cast_ne_zero.mpr hn] · have : 𝓝 (1 : 𝕜) = 𝓝 (1 / (1 + x * (0 : 𝕜))) := by @@ -119,7 +119,7 @@ theorem tendsto_natCast_div_add_atTop {𝕜 : Type*} [DivisionRing 𝕜] [Topolo theorem tendsto_add_one_pow_atTop_atTop_of_pos [LinearOrderedSemiring α] [Archimedean α] {r : α} (h : 0 < r) : Tendsto (fun n : ℕ ↦ (r + 1) ^ n) atTop atTop := - tendsto_atTop_atTop_of_monotone' (fun _ _ ↦ pow_le_pow_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 +137,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 @@ -167,7 +167,7 @@ theorem tendsto_pow_atTop_nhdsWithin_zero_of_lt_one {𝕜 : Type*} [LinearOrdere Tendsto (fun n : ℕ ↦ r ^ n) atTop (𝓝[>] 0) := tendsto_inf.2 ⟨tendsto_pow_atTop_nhds_zero_of_lt_one h₁.le h₂, - tendsto_principal.2 <| eventually_of_forall fun _ ↦ pow_pos h₁ _⟩ + tendsto_principal.2 <| Eventually.of_forall fun _ ↦ pow_pos h₁ _⟩ @[deprecated (since := "2024-01-31")] alias tendsto_pow_atTop_nhdsWithin_0_of_lt_1 := tendsto_pow_atTop_nhdsWithin_zero_of_lt_one @@ -252,13 +252,13 @@ 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 simpa [← ENNReal.inv_pow] using obs <| ENNReal.inv_lt_one.mpr r_gt_one -/-! ### Geometric series-/ +/-! ### Geometric series -/ section Geometric @@ -360,7 +360,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 +513,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 -/ @@ -605,7 +605,7 @@ theorem tendsto_factorial_div_pow_self_atTop : Tendsto (fun n ↦ n ! / (n : ℝ) ^ n : ℕ → ℝ) atTop (𝓝 0) := tendsto_of_tendsto_of_tendsto_of_le_of_le' tendsto_const_nhds (tendsto_const_div_atTop_nhds_zero_nat 1) - (eventually_of_forall fun n ↦ + (Eventually.of_forall fun n ↦ div_nonneg (mod_cast n.factorial_pos.le) (pow_nonneg (mod_cast n.zero_le) _)) (by @@ -654,12 +654,12 @@ theorem tendsto_nat_floor_mul_div_atTop {a : R} (ha : 0 ≤ a) : rw [sub_zero] at A apply tendsto_of_tendsto_of_tendsto_of_le_of_le' A tendsto_const_nhds · refine eventually_atTop.2 ⟨1, fun x hx ↦ ?_⟩ - simp only [le_div_iff (zero_lt_one.trans_le hx), _root_.sub_mul, + simp only [le_div_iff₀ (zero_lt_one.trans_le hx), _root_.sub_mul, inv_mul_cancel₀ (zero_lt_one.trans_le hx).ne'] have := Nat.lt_floor_add_one (a * x) linarith · refine eventually_atTop.2 ⟨1, fun x hx ↦ ?_⟩ - rw [div_le_iff (zero_lt_one.trans_le hx)] + rw [div_le_iff₀ (zero_lt_one.trans_le hx)] simp [Nat.floor_le (mul_nonneg ha (zero_le_one.trans hx))] theorem tendsto_nat_floor_div_atTop : Tendsto (fun x ↦ (⌊x⌋₊ : R) / x) atTop (𝓝 1) := by @@ -672,10 +672,10 @@ theorem tendsto_nat_ceil_mul_div_atTop {a : R} (ha : 0 ≤ a) : rw [add_zero] at A apply tendsto_of_tendsto_of_tendsto_of_le_of_le' tendsto_const_nhds A · refine eventually_atTop.2 ⟨1, fun x hx ↦ ?_⟩ - rw [le_div_iff (zero_lt_one.trans_le hx)] + rw [le_div_iff₀ (zero_lt_one.trans_le hx)] exact Nat.le_ceil _ · refine eventually_atTop.2 ⟨1, fun x hx ↦ ?_⟩ - simp [div_le_iff (zero_lt_one.trans_le hx), inv_mul_cancel₀ (zero_lt_one.trans_le hx).ne', + simp [div_le_iff₀ (zero_lt_one.trans_le hx), inv_mul_cancel₀ (zero_lt_one.trans_le hx).ne', (Nat.ceil_lt_add_one (mul_nonneg ha (zero_le_one.trans hx))).le, add_mul] theorem tendsto_nat_ceil_div_atTop : Tendsto (fun x ↦ (⌈x⌉₊ : R) / x) atTop (𝓝 1) := by diff --git a/Mathlib/Analysis/SpecificLimits/FloorPow.lean b/Mathlib/Analysis/SpecificLimits/FloorPow.lean index 1000c3b72484d..0d410a3b11645 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 @@ -212,7 +211,7 @@ theorem tendsto_div_of_monotone_of_tendsto_div_floor_pow (u : ℕ → ℝ) (l : field_simp [(zero_lt_one.trans (cone k)).ne', (H n).ne'] ring filter_upwards [(tendsto_order.1 B).2 a hk] with n hn - exact (div_le_iff (H n)).1 hn.le + exact (div_le_iff₀ (H n)).1 hn.le /-- The sum of `1/(c^i)^2` above a threshold `j` is comparable to `1/j^2`, up to a multiplicative constant. -/ @@ -223,21 +222,21 @@ theorem sum_div_pow_sq_le_div_sq (N : ℕ) {j : ℝ} (hj : 0 < j) {c : ℝ} (hc 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 ∈ 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,7 +270,7 @@ theorem mul_pow_le_nat_floor_pow {c : ℝ} (hc : 1 < c) (i : ℕ) : (1 - c⁻¹) (1 - c⁻¹) * c ^ i = c ^ i - c ^ i * c⁻¹ := by ring _ ≤ c ^ i - 1 := by 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 @@ -280,7 +279,7 @@ theorem sum_div_nat_floor_pow_sq_le_div_sq (N : ℕ) {j : ℝ} (hj : 0 < j) {c : (∑ i ∈ (range N).filter (j < ⌊c ^ ·⌋₊), (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 @@ -292,11 +291,11 @@ theorem sum_div_nat_floor_pow_sq_le_div_sq (N : ℕ) {j : ℝ} (hj : 0 < j) {c : 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 - rw [← div_eq_inv_mul, le_div_iff A, mul_comm] + rw [← div_eq_inv_mul, le_div_iff₀ A, mul_comm] exact mul_pow_le_nat_floor_pow hc i _ ≤ (1 - c⁻¹)⁻¹ ^ 2 * (c ^ 3 * (c - 1)⁻¹) / j ^ 2 := by rw [← mul_sum, ← mul_div_assoc'] diff --git a/Mathlib/Analysis/SpecificLimits/Normed.lean b/Mathlib/Analysis/SpecificLimits/Normed.lean index 21ee99951f714..ba7281ba264e2 100644 --- a/Mathlib/Analysis/SpecificLimits/Normed.lean +++ b/Mathlib/Analysis/SpecificLimits/Normed.lean @@ -4,31 +4,29 @@ 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.Order.Filter.ModEq +import Mathlib.Algebra.Order.Field.Power 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.Analysis.Normed.Module.Basic +import Mathlib.Data.Nat.Choose.Bounds +import Mathlib.Order.Filter.AtTopBot.ModEq +import Mathlib.RingTheory.Polynomial.Pochhammer +import Mathlib.Tactic.NoncommRing /-! # A collection of specific limit computations 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 Set Function Filter Finset Metric Asymptotics Topology Nat NNReal ENNReal -open scoped Classical -open Topology Nat uniformity NNReal ENNReal - -variable {α : Type*} {β : Type*} {ι : Type*} +variable {α β ι : Type*} theorem tendsto_norm_atTop_atTop : Tendsto (norm : ℝ → ℝ) atTop atTop := tendsto_abs_atTop_atTop @@ -126,52 +124,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 → ∞`. -/ @@ -208,7 +197,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) : @@ -221,7 +210,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' @@ -258,8 +247,115 @@ theorem tendsto_pow_atTop_nhds_zero_of_abs_lt_one {r : ℝ} (h : |r| < 1) : @[deprecated (since := "2024-01-31")] alias tendsto_pow_atTop_nhds_0_of_abs_lt_1 := tendsto_pow_atTop_nhds_zero_of_abs_lt_one -/-! ### Geometric series-/ +/-! ### 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 @@ -278,8 +374,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 @@ -327,55 +423,162 @@ end Geometric section MulGeometric -theorem summable_norm_pow_mul_geometric_of_norm_lt_one {R : Type*} [NormedRing R] (k : ℕ) {r : R} - (hr : ‖r‖ < 1) : Summable fun n : ℕ ↦ ‖((n : R) ^ k * r ^ n : R)‖ := by +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⟩ - exact summable_of_isBigO_nat (summable_geometric_of_lt_one ((norm_nonneg _).trans hrr'.le) h) - (isLittleO_pow_const_mul_const_pow_const_pow_of_norm_lt _ hrr').isBigO.norm_left + rw [← norm_norm] at hrr' + apply summable_of_isBigO_nat (summable_geometric_of_lt_one ((norm_nonneg _).trans hrr'.le) h) + calc + fun n ↦ ‖↑(u n) * r ^ n‖ + _ =O[atTop] fun n ↦ u n * ‖r‖ ^ n := by + apply (IsBigOWith.of_bound (c := ‖(1 : R)‖) ?_).isBigO + filter_upwards [eventually_norm_pow_le r] with n hn + simp only [norm_norm, norm_mul, Real.norm_eq_abs, abs_cast, norm_pow, abs_norm] + 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 (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 (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 : R} + (hr : ‖r‖ < 1) : Summable fun n : ℕ ↦ ‖(r ^ n : R)‖ := by + simpa using summable_norm_pow_mul_geometric_of_norm_lt_one 0 hr + +variable [HasSummableGeomSeries R] + +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_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 + apply isBigO_iff.2 ⟨2 ^ k, ?_⟩ + filter_upwards [Ioi_mem_atTop k] with n (hn : k < n) + simp only [Real.norm_eq_abs, abs_cast, cast_pow, norm_pow] + norm_cast + calc (n + k).choose k + _ ≤ (2 * n).choose k := choose_le_choose k (by omega) + _ ≤ (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) 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 [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 : R} (hr : ‖r‖ < 1) : + Summable (fun n ↦ (n + k).choose k * r ^ n) := + (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) := + (hasSum_choose_mul_geometric_of_norm_lt_one k hr).tsum_eq + +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 : 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 : 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 + let P : Polynomial ℕ := (ascPochhammer ℕ k).comp (Polynomial.X + C 1) + refine ⟨fun i ↦ P.coeff i, fun n ↦ ?_⟩ + have mP : Monic P := Monic.comp_X_add_C (monic_ascPochhammer ℕ k) _ + have dP : P.natDegree = k := by + simp only [P, natDegree_comp, ascPochhammer_natDegree, mul_one, natDegree_X_add_C] + have A : (n + k).descFactorial k = P.eval n := by + have : n + 1 + k - 1 = n + k := by omega + simp [P, ascPochhammer_nat_eq_descFactorial, this] + conv_lhs => rw [A, mP.as_sum, dP] + simp [eval_finset_sum] + have : Summable (fun n ↦ (n + k).descFactorial k * r ^ n + - ∑ i ∈ range k, a i * n ^ (i : ℕ) * r ^ n) := by + apply (summable_descFactorial_mul_geometric_of_norm_lt_one k hr).sub + apply summable_sum (fun i hi ↦ ?_) + simp_rw [mul_assoc] + simp only [Finset.mem_range] at hi + exact (hk _ hi).mul_left _ + convert this using 1 + 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 -theorem summable_pow_mul_geometric_of_norm_lt_one {R : Type*} [NormedRing R] [CompleteSpace R] - (k : ℕ) {r : R} (hr : ‖r‖ < 1) : Summable (fun n ↦ (n : R) ^ k * r ^ n : ℕ → R) := - .of_norm <| summable_norm_pow_mul_geometric_of_norm_lt_one _ hr - @[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 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 : ℕ) ↦ 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 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 {𝕜 : Type*} [NormedDivisionRing 𝕜] [CompleteSpace 𝕜] - {r : 𝕜} (hr : ‖r‖ < 1) : HasSum (fun n ↦ n * r ^ n : ℕ → 𝕜) (r / (1 - r) ^ 2) := by - have A : Summable (fun n ↦ (n : 𝕜) * r ^ n : ℕ → 𝕜) := by - simpa only [pow_one] using summable_pow_mul_geometric_of_norm_lt_one 1 hr - have B : HasSum (r ^ · : ℕ → 𝕜) (1 - r)⁻¹ := hasSum_geometric_of_norm_lt_one hr - refine A.hasSum_iff.2 ?_ - have hr' : r ≠ 1 := by - rintro rfl - simp [lt_irrefl] at hr - set s : 𝕜 := ∑' n : ℕ, n * r ^ n - have : Commute (1 - r) s := - .tsum_right _ fun _ => - .sub_left (.one_left _) (.mul_right (Nat.commute_cast _ _) (.pow_right (.refl _) _)) - calc - s = s * (1 - r) / (1 - r) := (mul_div_cancel_right₀ _ (sub_ne_zero.2 hr'.symm)).symm - _ = (1 - r) * s / (1 - r) := by rw [this.eq] - _ = (s - r * s) / (1 - r) := by rw [_root_.sub_mul, one_mul] - _ = (((0 : ℕ) * r ^ 0 + ∑' n : ℕ, (n + 1 : ℕ) * r ^ (n + 1)) - r * s) / (1 - r) := by - rw [← tsum_eq_zero_add A] - _ = ((r * ∑' n : ℕ, ↑(n + 1) * r ^ n) - r * s) / (1 - r) := by - simp only [cast_zero, pow_zero, mul_one, _root_.pow_succ', (Nat.cast_commute _ r).left_comm, - _root_.tsum_mul_left, zero_add] - _ = r / (1 - r) ^ 2 := by - simp [add_mul, tsum_add A B.summable, mul_add, B.tsum_eq, ← div_eq_mul_inv, sq, - div_mul_eq_div_div_swap] +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 {𝕜 : Type*} [NormedDivisionRing 𝕜] [CompleteSpace 𝕜] - {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")] @@ -459,67 +662,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 α] @@ -548,7 +690,7 @@ theorem summable_of_ratio_test_tendsto_lt_one {α : Type*} [NormedAddCommGroup rcases exists_between hl₁ with ⟨r, hr₀, hr₁⟩ refine summable_of_ratio_norm_eventually_le hr₁ ?_ filter_upwards [eventually_le_of_tendsto_lt hr₀ h, hf] with _ _ h₁ - rwa [← div_le_iff (norm_pos_iff.mpr h₁)] + rwa [← div_le_iff₀ (norm_pos_iff.mpr h₁)] theorem not_summable_of_ratio_norm_eventually_ge {α : Type*} [SeminormedAddCommGroup α] {f : ℕ → α} {r : ℝ} (hr : 1 < r) (hf : ∃ᶠ n in atTop, ‖f n‖ ≠ 0) @@ -581,7 +723,7 @@ theorem not_summable_of_ratio_test_tendsto_gt_one {α : Type*} [SeminormedAddCom rcases exists_between hl with ⟨r, hr₀, hr₁⟩ refine not_summable_of_ratio_norm_eventually_ge hr₀ key.frequently ?_ filter_upwards [eventually_ge_of_tendsto_gt hr₁ h, key] with _ _ h₁ - rwa [← le_div_iff (lt_of_le_of_ne (norm_nonneg _) h₁.symm)] + rwa [← le_div_iff₀ (lt_of_le_of_ne (norm_nonneg _) h₁.symm)] section NormedDivisionRing @@ -597,7 +739,7 @@ theorem summable_powerSeries_of_norm_lt {w z : α} refine cauchySeq_finset_of_geometric_bound (r := ‖z‖ / ‖w‖) (C := C) ((div_lt_one hw).mpr hz) (fun n ↦ ?_) rw [norm_mul, norm_pow, div_pow, ← mul_comm_div] - conv at hC => enter [n]; rw [norm_mul, norm_pow, ← _root_.le_div_iff (by positivity)] + conv at hC => enter [n]; rw [norm_mul, norm_pow, ← _root_.le_div_iff₀ (by positivity)] exact mul_le_mul_of_nonneg_right (hC n) (pow_nonneg (norm_nonneg z) n) /-- If a power series converges at 1, it converges absolutely at all `z` of smaller norm. -/ @@ -624,7 +766,7 @@ theorem Monotone.cauchySeq_series_mul_of_tendsto_zero_of_bounded (hfa : Monotone simp_rw [Finset.sum_range_by_parts _ _ (Nat.succ _), sub_eq_add_neg, Nat.succ_sub_succ_eq_sub, tsub_zero] apply (NormedField.tendsto_zero_smul_of_tendsto_zero_of_bounded hf0 - ⟨b, eventually_map.mpr <| eventually_of_forall fun n ↦ hgb <| n + 1⟩).cauchySeq.add + ⟨b, eventually_map.mpr <| Eventually.of_forall fun n ↦ hgb <| n + 1⟩).cauchySeq.add refine CauchySeq.neg ?_ refine cauchySeq_range_of_norm_bounded _ ?_ (fun n ↦ ?_ : ∀ n, ‖(f (n + 1) + -f n) • (Finset.range (n + 1)).sum z‖ ≤ b * |f (n + 1) - f n|) @@ -766,6 +908,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/Subadditive.lean b/Mathlib/Analysis/Subadditive.lean index e3104ca58d187..8b9b5336d51ef 100644 --- a/Mathlib/Analysis/Subadditive.lean +++ b/Mathlib/Analysis/Subadditive.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.Instances.Real -import Mathlib.Order.Filter.Archimedean +import Mathlib.Order.Filter.AtTopBot.Archimedean /-! # Convergence of subadditive sequences @@ -46,7 +46,7 @@ theorem lim_le_div (hbdd : BddBelow (range fun n => u n / n)) {n : ℕ} (hn : n include h in theorem apply_mul_add_le (k n r) : u (k * n + r) ≤ k * u n + u r := by induction k with - | zero => simp only [Nat.zero_eq, Nat.cast_zero, zero_mul, zero_add]; rfl + | zero => simp only [Nat.cast_zero, zero_mul, zero_add]; rfl | succ k IH => calc u ((k + 1) * n + r) = u (n + (k * n + r)) := by congr 1; ring @@ -67,7 +67,7 @@ theorem eventually_div_lt_of_div_lt {L : ℝ} {n : ℕ} (hn : n ≠ 0) (hL : u n have B : Tendsto (fun x => (x * u n + u r) / (x * n + r)) atTop (𝓝 (u n / n)) := by rw [add_zero, add_zero] at A refine A.congr' <| (eventually_ne_atTop 0).mono fun x hx => ?_ - simp only [(· ∘ ·), add_div' _ _ _ hx, div_div_div_cancel_right _ hx, mul_comm] + simp only [(· ∘ ·), add_div' _ _ _ hx, div_div_div_cancel_right₀ hx, mul_comm] refine ((B.comp tendsto_natCast_atTop_atTop).eventually (gt_mem_nhds hL)).mono fun k hk => ?_ /- Finally, we use an upper estimate on `u (k * n + r)` to get an estimate on `u (k * n + r) / (k * n + r)`. -/ diff --git a/Mathlib/Analysis/SumOverResidueClass.lean b/Mathlib/Analysis/SumOverResidueClass.lean index 92432ccab72a0..d0109a33064e6 100644 --- a/Mathlib/Analysis/SumOverResidueClass.lean +++ b/Mathlib/Analysis/SumOverResidueClass.lean @@ -3,9 +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.Analysis.Normed.Field.Basic import Mathlib.Data.ZMod.Basic import Mathlib.Topology.Instances.ENNReal -import Mathlib.Analysis.Normed.Field.Basic /-! # Sums over residue classes @@ -92,3 +92,14 @@ lemma summable_indicator_mod_iff {m : ℕ} [NeZero m] {f : ℕ → ℝ} (hf : An convert summable_sum (s := Finset.univ) fun a _ ↦ summable_indicator_mod_iff_summable_indicator_mod hf a H simp only [Finset.sum_apply] + +open ZMod + +/-- If `f` is a summable function on `ℕ`, and `0 < N`, then we may compute `∑' n : ℕ, f n` by +summing each residue class mod `N` separately. -/ +lemma Nat.sumByResidueClasses {R : Type*} [AddCommGroup R] [UniformSpace R] [UniformAddGroup R] + [CompleteSpace R] [T0Space R] {f : ℕ → R} (hf : Summable f) (N : ℕ) [NeZero N] : + ∑' n, f n = ∑ j : ZMod N, ∑' m, f (j.val + N * m) := by + rw [← (residueClassesEquiv N).symm.tsum_eq f, tsum_prod, tsum_fintype, residueClassesEquiv, + Equiv.coe_fn_symm_mk] + exact hf.comp_injective (residueClassesEquiv N).symm.injective diff --git a/Mathlib/Analysis/VonNeumannAlgebra/Basic.lean b/Mathlib/Analysis/VonNeumannAlgebra/Basic.lean index 6486b7bbab466..0d05481d7f037 100644 --- a/Mathlib/Analysis/VonNeumannAlgebra/Basic.lean +++ b/Mathlib/Analysis/VonNeumannAlgebra/Basic.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.Analysis.Normed.Module.Dual import Mathlib.Analysis.Complex.Basic 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/DiagramLemmas/Four.lean b/Mathlib/CategoryTheory/Abelian/DiagramLemmas/Four.lean index 1919022e9a035..5812a21f56858 100644 --- a/Mathlib/CategoryTheory/Abelian/DiagramLemmas/Four.lean +++ b/Mathlib/CategoryTheory/Abelian/DiagramLemmas/Four.lean @@ -87,8 +87,6 @@ theorem mono_of_epi_of_mono_of_mono (hR₁ : R₁.Exact) (hR₂ : R₂.Exact) (by simpa only [R₁.map'_comp 0 1 2] using hR₁.toIsComplex.zero 0) (hR₁.exact 1).exact_toComposableArrows (hR₂.exact 0).exact_toComposableArrows h₀ h₁ h₃ -attribute [local instance] epi_comp - theorem epi_of_epi_of_epi_of_mono' (hR₁ : (mk₂ (R₁.map' 1 2) (R₁.map' 2 3)).Exact) (hR₂ : (mk₂ (R₂.map' 0 1) (R₂.map' 1 2)).Exact) (hR₂' : R₂.map' 1 3 = 0) diff --git a/Mathlib/CategoryTheory/Abelian/Exact.lean b/Mathlib/CategoryTheory/Abelian/Exact.lean index cfc118215dd0f..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 @@ -240,14 +234,14 @@ theorem preservesMonomorphisms_of_map_exact : L.PreservesMonomorphisms where preserves f hf := by apply ((Abelian.tfae_mono (L.map f) (L.obj 0)).out 2 0).mp refine ShortComplex.exact_of_iso ?_ (hL _ (((tfae_mono f 0).out 0 2).mp hf)) - exact ShortComplex.isoMk (Iso.refl _) (Iso.refl _) (Iso.refl _) + exact ShortComplex.isoMk (Iso.refl _) (Iso.refl _) (Iso.refl _) /-- A functor which preserves exactness preserves epimorphisms. -/ theorem preservesEpimorphisms_of_map_exact : L.PreservesEpimorphisms where preserves f hf := by apply ((Abelian.tfae_epi (L.map f) (L.obj 0)).out 2 0).mp refine ShortComplex.exact_of_iso ?_ (hL _ (((tfae_epi f 0).out 0 2).mp hf)) - exact ShortComplex.isoMk (Iso.refl _) (Iso.refl _) (Iso.refl _) + exact ShortComplex.isoMk (Iso.refl _) (Iso.refl _) (Iso.refl _) /-- A functor which preserves the exactness of short complexes preserves homology. -/ def preservesHomologyOfMapExact : L.PreservesHomology where 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..ff25be4567c6f --- /dev/null +++ b/Mathlib/CategoryTheory/Abelian/GrothendieckAxioms.lean @@ -0,0 +1,93 @@ +/- +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.Filtered +import Mathlib.CategoryTheory.Limits.Preserves.Finite + +/-! + +# 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`. + +## 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' + +variable (C : Type u) [Category.{v} C] + +/-- +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 + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Abelian/Images.lean b/Mathlib/CategoryTheory/Abelian/Images.lean index 58a0dcda3e32b..c753cc0c81887 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 diff --git a/Mathlib/CategoryTheory/Abelian/InjectiveResolution.lean b/Mathlib/CategoryTheory/Abelian/InjectiveResolution.lean index a7565550d51fd..675ab43cfcce7 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 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 c8c9e63e83d6f..680956963fe88 100644 --- a/Mathlib/CategoryTheory/Abelian/NonPreadditive.lean +++ b/Mathlib/CategoryTheory/Abelian/NonPreadditive.lean @@ -109,7 +109,6 @@ instance : Epi (Abelian.factorThruImage f) := _ fun R (g : I ⟶ R) (hpg : p ≫ g = 0) => by -- Since C is abelian, u := ker g ≫ i is the kernel of some morphism h. let u := kernel.ι g ≫ i - haveI : Mono u := mono_comp _ _ haveI hu := normalMonoOfMono u let h := hu.g -- By hypothesis, p factors through the kernel of g via some t. @@ -146,7 +145,6 @@ instance : Mono (Abelian.factorThruCoimage f) := NormalEpiCategory.mono_of_cancel_zero _ fun R (g : R ⟶ I) (hgi : g ≫ i = 0) => by -- Since C is abelian, u := p ≫ coker g is the cokernel of some morphism h. let u := p ≫ cokernel.π g - haveI : Epi u := epi_comp _ _ haveI hu := normalEpiOfEpi u let h := hu.g -- By hypothesis, i factors through the cokernel of g via some t. 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/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 1948ebfb7f9a6..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 @@ -128,7 +128,7 @@ def coimageIsoImage (i : F ⋙ G ≅ 𝟭 C) (adj : G ⊣ F) {X Y : C} (f : X _ ≅ Abelian.image f := Iso.refl _ -- The account of this proof in the Stacks project omits this calculation. -theorem coimageIsoImage_hom (i : F ⋙ G ≅ 𝟭 C) (adj : G ⊣ F) {X Y : C} (f : X ⟶ Y) : +theorem coimageIsoImage_hom (i : F ⋙ G ≅ 𝟭 C) (adj : G ⊣ F) {X Y : C} (f : X ⟶ Y) : (coimageIsoImage F G i adj f).hom = Abelian.coimageImageComparison f := by dsimp [coimageIsoImage, cokernelIso, cokernelEpiComp, cokernelCompIsIso_inv, coimageIsoImageAux, kernelCompMono] 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 64158bfaf6b47..3d5e083b0ab9b 100644 --- a/Mathlib/CategoryTheory/Adjunction/AdjointFunctorTheorems.lean +++ b/Mathlib/CategoryTheory/Adjunction/AdjointFunctorTheorems.lean @@ -6,7 +6,7 @@ Authors: Bhavik Mehta import Mathlib.CategoryTheory.Generator import Mathlib.CategoryTheory.Limits.ConeCategory import Mathlib.CategoryTheory.Limits.Constructions.WeaklyInitial -import Mathlib.CategoryTheory.Limits.FunctorCategory +import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic import Mathlib.CategoryTheory.Subobject.Comma /-! @@ -62,7 +62,7 @@ section GeneralAdjointFunctorTheorem variable {D : Type u} [Category.{v} D] variable (G : D ⥤ C) -/-- If `G : D ⥤ C` is a right adjoint it satisfies the solution set condition. -/ +/-- If `G : D ⥤ C` is a right adjoint it satisfies the solution set condition. -/ theorem solutionSetCondition_of_isRightAdjoint [G.IsRightAdjoint] : SolutionSetCondition G := by intro A refine diff --git a/Mathlib/CategoryTheory/Adjunction/Basic.lean b/Mathlib/CategoryTheory/Adjunction/Basic.lean index ad3d1b46c9181..3d9c1506b6275 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,28 +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.Opposites`. +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 - -- Porting note: It's strange that this `Prop` is being flagged by the `docBlame` linter - /-- Naturality of the unit of an adjunction -/ - homEquiv_unit : ∀ {X Y f}, (homEquiv X Y) f = (unit : _ ⟶ _).app X ≫ G.map f := by aesop_cat - -- Porting note: It's strange that this `Prop` is being flagged by the `docBlame` linter - /-- Naturality of the counit 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 @@ -105,11 +148,23 @@ noncomputable def Adjunction.ofIsRightAdjoint (right : C ⥤ D) [right.IsRightAd namespace Adjunction --- Porting note: Workaround not needed in Lean 4 --- restate_axiom homEquiv_unit' +attribute [reassoc (attr := simp)] left_triangle_components right_triangle_components --- restate_axiom homEquiv_counit' +/-- The hom set equivalence associated to an adjunction. -/ +@[simps] +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 [← assoc, ← Functor.comp_map, ← adj.unit.naturality, assoc] +alias homEquiv_unit := homEquiv_apply +alias homEquiv_counit := homEquiv_symm_apply attribute [simp] homEquiv_unit homEquiv_counit section @@ -132,35 +187,23 @@ theorem homEquiv_id (X : C) : adj.homEquiv X _ (𝟙 _) = adj.unit.app X := by s theorem homEquiv_symm_id (X : D) : (adj.homEquiv _ X).symm (𝟙 _) = adj.counit.app X := by simp -/- -Porting note: `nolint simpNF` as the linter was complaining that this was provable using `simp` -but it is in fact not. Also the `docBlame` linter expects a docstring even though this is `Prop` -valued --/ -@[simp, nolint simpNF] theorem homEquiv_naturality_left_symm (f : X' ⟶ X) (g : X ⟶ G.obj Y) : (adj.homEquiv X' Y).symm (f ≫ g) = F.map f ≫ (adj.homEquiv X Y).symm g := by - rw [homEquiv_counit, F.map_comp, assoc, adj.homEquiv_counit.symm] + simp --- Porting note: Same as above -@[simp, nolint simpNF] theorem homEquiv_naturality_left (f : X' ⟶ X) (g : F.obj X ⟶ Y) : (adj.homEquiv X' Y) (F.map f ≫ g) = f ≫ (adj.homEquiv X Y) g := by rw [← Equiv.eq_symm_apply] - simp only [Equiv.symm_apply_apply,eq_self_iff_true,homEquiv_naturality_left_symm] + simp only [Equiv.symm_apply_apply, eq_self_iff_true, homEquiv_naturality_left_symm] --- Porting note: Same as above -@[simp, nolint simpNF] theorem homEquiv_naturality_right (f : F.obj X ⟶ Y) (g : Y ⟶ Y') : (adj.homEquiv X Y') (f ≫ g) = (adj.homEquiv X Y) f ≫ G.map g := by - rw [homEquiv_unit, G.map_comp, ← assoc, ← homEquiv_unit] + simp --- Porting note: Same as above -@[simp, nolint simpNF] theorem homEquiv_naturality_right_symm (f : X ⟶ G.obj Y) (g : Y ⟶ Y') : (adj.homEquiv X Y').symm (f ≫ G.map g) = (adj.homEquiv X Y).symm f ≫ g := by rw [Equiv.symm_apply_eq] - simp only [homEquiv_naturality_right,eq_self_iff_true,Equiv.apply_symm_apply] + simp only [homEquiv_naturality_right, eq_self_iff_true, Equiv.apply_symm_apply] @[reassoc] theorem homEquiv_naturality_left_square (f : X' ⟶ X) (g : F.obj X ⟶ Y') @@ -192,29 +235,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 - erw [← 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 - erw [← 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) : @@ -226,21 +251,21 @@ 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 end @@ -248,6 +273,28 @@ 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 + +namespace CoreHomEquivUnitCounit + +attribute [simp] homEquiv_unit homEquiv_counit + +end CoreHomEquivUnitCounit + /-- This is an auxiliary data structure useful for constructing adjunctions. See `Adjunction.mkOfHomEquiv`. This structure won't typically be used anywhere else. @@ -270,31 +317,14 @@ structure CoreHomEquiv (F : C ⥤ D) (G : D ⥤ C) where namespace CoreHomEquiv --- Porting note: Workaround not needed in Lean 4. --- restate_axiom homEquiv_naturality_left_symm' - --- restate_axiom homEquiv_naturality_right' - attribute [simp] homEquiv_naturality_left_symm homEquiv_naturality_right variable {F : C ⥤ D} {G : D ⥤ C} (adj : CoreHomEquiv F G) {X' X : C} {Y Y' : D} -@[simp] -theorem homEquiv_naturality_left_aux (f : X' ⟶ X) (g : F.obj X ⟶ Y) : - (adj.homEquiv X' (F.obj X)) (F.map f) ≫ G.map g = f ≫ (adj.homEquiv X Y) g := by - rw [← homEquiv_naturality_right, ← Equiv.eq_symm_apply]; simp - --- @[simp] -- Porting note: LHS simplifies, added aux lemma above theorem homEquiv_naturality_left (f : X' ⟶ X) (g : F.obj X ⟶ Y) : (adj.homEquiv X' Y) (F.map f ≫ g) = f ≫ (adj.homEquiv X Y) g := by rw [← Equiv.eq_symm_apply]; simp -@[simp] -theorem homEquiv_naturality_right_symm_aux (f : X ⟶ G.obj Y) (g : Y ⟶ Y') : - F.map f ≫ (adj.homEquiv (G.obj Y) Y').symm (G.map g) = (adj.homEquiv X Y).symm f ≫ g := by - rw [← homEquiv_naturality_left_symm, Equiv.symm_apply_eq]; simp - --- @[simp] -- Porting note: LHS simplifies, added aux lemma above theorem homEquiv_naturality_right_symm (f : X ⟶ G.obj Y) (g : Y ⟶ Y') : (adj.homEquiv X Y').symm (f ≫ G.map g) = (adj.homEquiv X Y).symm f ≫ g := by rw [Equiv.symm_apply_eq]; simp @@ -333,62 +363,66 @@ end CoreUnitCounit variable {F : C ⥤ D} {G : D ⥤ C} +/-- +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 := - -- See note [dsimp, simp]. - { adj with + mk' { unit := { app := fun X => (adj.homEquiv X (F.obj X)) (𝟙 (F.obj X)) naturality := by intros - erw [← adj.homEquiv_naturality_left, ← adj.homEquiv_naturality_right] - dsimp; simp } + simp [← adj.homEquiv_naturality_left, ← adj.homEquiv_naturality_right] } counit := { app := fun Y => (adj.homEquiv _ _).invFun (𝟙 (G.obj Y)) naturality := by intros - erw [← adj.homEquiv_naturality_left_symm, ← adj.homEquiv_naturality_right_symm] - dsimp; simp } - homEquiv_unit := @fun X Y f => by erw [← adj.homEquiv_naturality_right]; simp - homEquiv_counit := @fun X Y f => by erw [← adj.homEquiv_naturality_left_symm]; simp - } + simp [← adj.homEquiv_naturality_left_symm, ← adj.homEquiv_naturality_right_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] } + +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 } } - -/- Porting note: simpNF linter claims these are solved by simp but that -is not true -/ -attribute [nolint simpNF] CategoryTheory.Adjunction.mkOfUnitCounit_homEquiv_symm_apply -attribute [nolint simpNF] CategoryTheory.Adjunction.mkOfUnitCounit_homEquiv_apply +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 := 𝟙 _ @@ -424,6 +458,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} @@ -433,11 +483,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) : @@ -449,6 +500,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 @@ -488,12 +543,7 @@ def adjunctionOfEquivLeft : leftAdjointOfEquiv e he ⊣ G := have {X : C} {Y Y' : D} (f : X ⟶ G.obj Y) (g : Y ⟶ Y') : (e X Y').symm (f ≫ G.map g) = (e X Y).symm f ≫ g := by rw [Equiv.symm_apply_eq, he]; simp - erw [← this, ← Equiv.apply_eq_iff_eq (e X' Y)] - simp only [leftAdjointOfEquiv_obj, Equiv.apply_symm_apply, assoc] - congr - rw [← he] - simp - } + simp [← this, ← Equiv.apply_eq_iff_eq (e X' Y), ← he] } end ConstructLeft @@ -530,10 +580,10 @@ def adjunctionOfEquivRight (he : ∀ X' X Y f g, e X' Y (F.map f ≫ g) = f ≫ mkOfHomEquiv { homEquiv := e homEquiv_naturality_left_symm := by - intro X X' Y f g; rw [Equiv.symm_apply_eq]; dsimp; rw [he]; simp + intro X X' Y f g; rw [Equiv.symm_apply_eq]; simp [he] homEquiv_naturality_right := by intro X Y Y' g h - erw [← he, Equiv.apply_eq_iff_eq, ← assoc, he'' e he, comp_id, Equiv.symm_apply_apply] } + simp [← he, reassoc_of% (he'' e)] } end ConstructRight @@ -568,18 +618,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 - dsimp - simp only [id_comp] - exact e.functor_unit_comp _, by - ext - dsimp - simp only [id_comp] - exact e.unit_inverse_comp _⟩ +@[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..b74e9b326b43d 100644 --- a/Mathlib/CategoryTheory/Adjunction/Comma.lean +++ b/Mathlib/CategoryTheory/Adjunction/Comma.lean @@ -132,10 +132,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 +141,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 4109f1e41211b..9fa052e5ca51b 100644 --- a/Mathlib/CategoryTheory/Adjunction/Evaluation.lean +++ b/Mathlib/CategoryTheory/Adjunction/Evaluation.lean @@ -73,7 +73,9 @@ def evaluationAdjunctionRight (c : C) : evaluationLeftAdjoint D c ⊣ (evaluatio instance evaluationIsRightAdjoint (c : C) : ((evaluation _ D).obj c).IsRightAdjoint := ⟨_, ⟨evaluationAdjunctionRight _ _⟩⟩ -theorem NatTrans.mono_iff_mono_app {F G : C ⥤ D} (η : F ⟶ G) : Mono η ↔ ∀ c, Mono (η.app c) := by +/-- See also the file `CategoryTheory.Limits.FunctorCategoryEpiMono` +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 · intro h c exact (inferInstance : Mono (((evaluation _ _).obj c).map η)) @@ -128,7 +130,10 @@ def evaluationAdjunctionLeft (c : C) : (evaluation _ _).obj c ⊣ evaluationRigh instance evaluationIsLeftAdjoint (c : C) : ((evaluation _ D).obj c).IsLeftAdjoint := ⟨_, ⟨evaluationAdjunctionLeft _ _⟩⟩ -theorem NatTrans.epi_iff_epi_app {F G : C ⥤ D} (η : F ⟶ G) : Epi η ↔ ∀ c, Epi (η.app c) := by + +/-- See also the file `CategoryTheory.Limits.FunctorCategoryEpiMono` +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 · intro h c exact (inferInstance : Epi (((evaluation _ _).obj c).map η)) diff --git a/Mathlib/CategoryTheory/Adjunction/FullyFaithful.lean b/Mathlib/CategoryTheory/Adjunction/FullyFaithful.lean index c1e9ac499f5a3..2bdec90917b38 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 diff --git a/Mathlib/CategoryTheory/Adjunction/Lifting.lean b/Mathlib/CategoryTheory/Adjunction/Lifting/Left.lean similarity index 86% rename from Mathlib/CategoryTheory/Adjunction/Lifting.lean rename to Mathlib/CategoryTheory/Adjunction/Lifting/Left.lean index d175dc78fa3e1..e4d139ca0cb2b 100644 --- a/Mathlib/CategoryTheory/Adjunction/Lifting.lean +++ b/Mathlib/CategoryTheory/Adjunction/Lifting/Left.lean @@ -3,8 +3,6 @@ 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.CategoryTheory.Limits.Shapes.Equalizers -import Mathlib.CategoryTheory.Limits.Shapes.Reflexive import Mathlib.CategoryTheory.Monad.Adjunction import Mathlib.CategoryTheory.Monad.Coequalizer @@ -13,23 +11,26 @@ import Mathlib.CategoryTheory.Monad.Coequalizer This file gives two constructions for building left adjoints: the adjoint triangle theorem and the adjoint lifting theorem. + The adjoint triangle theorem concerns a functor `U : B ⥤ C` with a left adjoint `F` such that `ε_X : FUX ⟶ X` is a regular epi. Then for any category `A` with coequalizers of reflexive pairs, a functor `R : A ⥤ B` has a left adjoint if (and only if) the composite `R ⋙ U` does. Note that the condition on `U` regarding `ε_X` is automatically satisfied in the case when `U` is -a monadic functor, giving the corollary: `monadicAdjointTriangleLift`, i.e. if `U` is monadic, -`A` has reflexive coequalizers then `R : A ⥤ B` has a left adjoint provided `R ⋙ U` does. +a monadic functor, giving the corollary: `isRightAdjoint_triangle_lift_monadic`, i.e. if `U` is +monadic, `A` has reflexive coequalizers then `R : A ⥤ B` has a left adjoint provided `R ⋙ U` does. The adjoint lifting theorem says that given a commutative square of functors (up to isomorphism): +``` Q A → B U ↓ ↓ V C → D R +``` -where `U` and `V` are monadic and `A` has reflexive coequalizers, then if `R` has a left adjoint -then `Q` has a left adjoint. +where `V` is monadic, `U` has a left adjoint, and `A` has reflexive coequalizers, then if `R` has a +left adjoint then `Q` has a left adjoint. ## Implementation @@ -38,10 +39,14 @@ than just a functor known to be a right adjoint. In docstrings, we write `(η, and counit of the adjunction `adj₁ : F ⊣ U` and `(ι, δ)` for the unit and counit of the adjunction `adj₂ : F' ⊣ R ⋙ U`. +This file has been adapted to `Mathlib.CategoryTheory.Adjunction.Lifting.Right`. +Please try to keep them in sync. + ## TODO -Dualise to lift right adjoints through comonads (by reversing 1-cells) and dualise to lift right -adjoints through monads (by reversing 2-cells), and the combination. +- Dualise to lift right adjoints through monads (by reversing 2-cells). +- Investigate whether it is possible to give a more explicit description of the lifted adjoint, + especially in the case when the isomorphism `comm` is `Iso.refl _` ## References * https://ncatlab.org/nlab/show/adjoint+triangle+theorem @@ -61,7 +66,7 @@ variable {A : Type u₁} {B : Type u₂} {C : Type u₃} variable [Category.{v₁} A] [Category.{v₂} B] [Category.{v₃} C] -- Hide implementation details in this namespace -namespace LiftAdjoint +namespace LiftLeftAdjoint variable {U : B ⥤ C} {F : C ⥤ B} (R : A ⥤ B) (F' : C ⥤ A) variable (adj₁ : F ⊣ U) (adj₂ : F' ⊣ R ⋙ U) @@ -96,7 +101,7 @@ def otherMap (X) : F'.obj (U.obj (F.obj (U.obj X))) ⟶ F'.obj (U.obj X) := F'.map (U.map (F.map (adj₂.unit.app _) ≫ adj₁.counit.app _)) ≫ adj₂.counit.app _ /-- `(F'Uε_X, otherMap X)` is a reflexive pair: in particular if `A` has reflexive coequalizers then -it has a coequalizer. +this pair has a coequalizer. -/ instance (X : B) : IsReflexivePair (F'.map (U.map (adj₁.counit.app X))) (otherMap _ _ adj₁ adj₂ X) := @@ -159,7 +164,7 @@ noncomputable def constructLeftAdjoint [∀ X : B, RegularEpi (adj₁.counit.app -- This used to be `simp`, but we need `aesop_cat` after leanprover/lean4#2644 aesop_cat -end LiftAdjoint +end LiftLeftAdjoint /-- The adjoint triangle theorem: Suppose `U : B ⥤ C` has a left adjoint `F` such that each counit `ε_X : FUX ⟶ X` is a regular epimorphism. Then if a category `A` has coequalizers of reflexive @@ -168,18 +173,18 @@ pairs, then a functor `R : A ⥤ B` has a left adjoint if the composite `R ⋙ U Note the converse is true (with weaker assumptions), by `Adjunction.comp`. See https://ncatlab.org/nlab/show/adjoint+triangle+theorem -/ -lemma adjointTriangleLift {U : B ⥤ C} {F : C ⥤ B} (R : A ⥤ B) (adj₁ : F ⊣ U) +lemma isRightAdjoint_triangle_lift {U : B ⥤ C} {F : C ⥤ B} (R : A ⥤ B) (adj₁ : F ⊣ U) [∀ X : B, RegularEpi (adj₁.counit.app X)] [HasReflexiveCoequalizers A] [(R ⋙ U).IsRightAdjoint ] : R.IsRightAdjoint where exists_leftAdjoint := - ⟨LiftAdjoint.constructLeftAdjoint R _ adj₁ (Adjunction.ofIsRightAdjoint _), + ⟨LiftLeftAdjoint.constructLeftAdjoint R _ adj₁ (Adjunction.ofIsRightAdjoint _), ⟨Adjunction.adjunctionOfEquivLeft _ _⟩⟩ /-- If `R ⋙ U` has a left adjoint, the domain of `R` has reflexive coequalizers and `U` is a monadic functor, then `R` has a left adjoint. -This is a special case of `adjointTriangleLift` which is often more useful in practice. +This is a special case of `isRightAdjoint_triangle_lift` which is often more useful in practice. -/ -lemma monadicAdjointTriangleLift (U : B ⥤ C) [MonadicRightAdjoint U] {R : A ⥤ B} +lemma isRightAdjoint_triangle_lift_monadic (U : B ⥤ C) [MonadicRightAdjoint U] {R : A ⥤ B} [HasReflexiveCoequalizers A] [(R ⋙ U).IsRightAdjoint] : R.IsRightAdjoint := by let R' : A ⥤ _ := R ⋙ Monad.comparison (monadicAdjunction U) rsuffices : R'.IsRightAdjoint @@ -195,18 +200,20 @@ lemma monadicAdjointTriangleLift (U : B ⥤ C) [MonadicRightAdjoint U] {R : A intro X simp only [Monad.adj_counit] exact ⟨_, _, _, _, Monad.beckAlgebraCoequalizer X⟩ - exact adjointTriangleLift R' (Monad.adj _) + exact isRightAdjoint_triangle_lift R' (Monad.adj _) variable {D : Type u₄} variable [Category.{v₄} D] /-- Suppose we have a commutative square of functors +``` Q A → B U ↓ ↓ V C → D R +``` where `U` has a left adjoint, `A` has reflexive coequalizers and `V` has a left adjoint such that each component of the counit is a regular epi. @@ -214,30 +221,32 @@ Then `Q` has a left adjoint if `R` has a left adjoint. See https://ncatlab.org/nlab/show/adjoint+lifting+theorem -/ -lemma adjointSquareLift (Q : A ⥤ B) (V : B ⥤ D) (U : A ⥤ C) (R : C ⥤ D) +lemma isRightAdjoint_square_lift (Q : A ⥤ B) (V : B ⥤ D) (U : A ⥤ C) (R : C ⥤ D) (comm : U ⋙ R ≅ Q ⋙ V) [U.IsRightAdjoint] [V.IsRightAdjoint] [R.IsRightAdjoint] [∀ X, RegularEpi ((Adjunction.ofIsRightAdjoint V).counit.app X)] [HasReflexiveCoequalizers A] : Q.IsRightAdjoint := have := ((Adjunction.ofIsRightAdjoint (U ⋙ R)).ofNatIsoRight comm).isRightAdjoint - adjointTriangleLift Q (Adjunction.ofIsRightAdjoint V) + isRightAdjoint_triangle_lift Q (Adjunction.ofIsRightAdjoint V) /-- Suppose we have a commutative square of functors +``` Q A → B U ↓ ↓ V C → D R +``` where `U` has a left adjoint, `A` has reflexive coequalizers and `V` is monadic. Then `Q` has a left adjoint if `R` has a left adjoint. See https://ncatlab.org/nlab/show/adjoint+lifting+theorem -/ -lemma monadicAdjointSquareLift (Q : A ⥤ B) (V : B ⥤ D) (U : A ⥤ C) (R : C ⥤ D) +lemma isRightAdjoint_square_lift_monadic (Q : A ⥤ B) (V : B ⥤ D) (U : A ⥤ C) (R : C ⥤ D) (comm : U ⋙ R ≅ Q ⋙ V) [U.IsRightAdjoint] [MonadicRightAdjoint V] [R.IsRightAdjoint] [HasReflexiveCoequalizers A] : Q.IsRightAdjoint := have := ((Adjunction.ofIsRightAdjoint (U ⋙ R)).ofNatIsoRight comm).isRightAdjoint - monadicAdjointTriangleLift V + isRightAdjoint_triangle_lift_monadic V end CategoryTheory diff --git a/Mathlib/CategoryTheory/Adjunction/Lifting/Right.lean b/Mathlib/CategoryTheory/Adjunction/Lifting/Right.lean new file mode 100644 index 0000000000000..3d3893abeac50 --- /dev/null +++ b/Mathlib/CategoryTheory/Adjunction/Lifting/Right.lean @@ -0,0 +1,245 @@ +/- +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.Monad.Adjunction +import Mathlib.CategoryTheory.Monad.Equalizer + +/-! +# Adjoint lifting + +This file gives two constructions for building right adjoints: the adjoint triangle theorem and the +adjoint lifting theorem. + +The adjoint triangle theorem concerns a functor `F : B ⥤ A` with a right adjoint `U` such +that `η_X : X ⟶ UFX` is a regular mono. Then for any category `C` with equalizers of coreflexive +pairs, a functor `L : C ⥤ B` has a right adjoint if (and only if) the composite `L ⋙ F` does. +Note that the condition on `F` regarding `η_X` is automatically satisfied in the case when `F` is +a comonadic functor, giving the corollary: `isLeftAdjoint_triangle_lift_comonadic`, i.e. if `F` is +comonadic, `C` has coreflexive equalizers then `L : C ⥤ B` has a right adjoint provided `L ⋙ F` +does. + +The adjoint lifting theorem says that given a commutative square of functors (up to isomorphism): + +``` + Q + A → B + U ↓ ↓ V + C → D + L +``` + +where `V` is comonadic, `U` has a right adjoint, and `A` has coreflexive equalizers, then if `L` has +a right adjoint then `Q` has a right adjoint. + +## Implementation + +It is more convenient to prove this theorem by assuming we are given the explicit adjunction rather +than just a functor known to be a right adjoint. In docstrings, we write `(η, ε)` for the unit +and counit of the adjunction `adj₁ : F ⊣ U` and `(ι, δ)` for the unit and counit of the adjunction +`adj₂ : L ⋙ F ⊣ U'`. + +This file has been adapted from `Mathlib.CategoryTheory.Adjunction.Lifting.Left`. +Please try to keep them in sync. + +## TODO + +- Dualise to lift left adjoints through comonads (by reversing 2-cells). +- Investigate whether it is possible to give a more explicit description of the lifted adjoint, + especially in the case when the isomorphism `comm` is `Iso.refl _` + +## References +* https://ncatlab.org/nlab/show/adjoint+triangle+theorem +* https://ncatlab.org/nlab/show/adjoint+lifting+theorem +* Adjoint Lifting Theorems for Categories of Algebras (PT Johnstone, 1975) +* A unified approach to the lifting of adjoints (AJ Power, 1988) +-/ + + +namespace CategoryTheory + +open Category Limits + +universe v₁ v₂ v₃ v₄ u₁ u₂ u₃ u₄ + +variable {A : Type u₁} {B : Type u₂} {C : Type u₃} +variable [Category.{v₁} A] [Category.{v₂} B] [Category.{v₃} C] + +-- Hide implementation details in this namespace +namespace LiftRightAdjoint + +variable {U : A ⥤ B} {F : B ⥤ A} (L : C ⥤ B) (U' : A ⥤ C) +variable (adj₁ : F ⊣ U) (adj₂ : L ⋙ F ⊣ U') + +/-- To show that `η_X` is an equalizer for `(UFη_X, η_UFX)`, it suffices to assume it's always an +equalizer of something (i.e. a regular mono). +-/ +def unitEqualises [∀ X : B, RegularMono (adj₁.unit.app X)] (X : B) : + IsLimit (Fork.ofι (adj₁.unit.app X) (adj₁.unit_naturality _)) := + Fork.IsLimit.mk' _ fun s => by + refine ⟨(RegularMono.lift' (adj₁.unit.app X) s.ι ?_).1, ?_, ?_⟩ + · rw [← cancel_mono (adj₁.unit.app (RegularMono.Z (adj₁.unit.app X)))] + rw [assoc, ← adj₁.unit_naturality RegularMono.left] + dsimp only [Functor.comp_obj] + erw [← assoc, ← s.condition, assoc, ← U.map_comp, ← F.map_comp, RegularMono.w, F.map_comp, + U.map_comp, s.condition_assoc, assoc, ← adj₁.unit_naturality RegularMono.right] + rfl + · apply (RegularMono.lift' (adj₁.unit.app X) s.ι _).2 + · intro m hm + rw [← cancel_mono (adj₁.unit.app X)] + apply hm.trans (RegularMono.lift' (adj₁.unit.app X) s.ι _).2.symm + +/-- (Implementation) +To construct the right adjoint, we use the equalizer of `U' F η_X` with the composite + +`U' F X ⟶ U' F L U' F X ⟶ U' F U F L U' F X ⟶ U' F U F X` + +where the first morphism is `ι_U'FX`, the second is `U' F η_LU'FX` and the third is `U' F U δ_FX`. +We will show that this equalizer exists and that it forms the object map for a right adjoint to `L`. +-/ +def otherMap (X : B) : U'.obj (F.obj X) ⟶ U'.obj (F.obj (U.obj (F.obj X))) := + adj₂.unit.app _ ≫ U'.map (F.map (adj₁.unit.app _ ≫ (U.map (adj₂.counit.app _)))) + +/-- `(U'Fη_X, otherMap X)` is a coreflexive pair: in particular if `C` has coreflexive equalizers +then this pair has an equalizer. +-/ +instance (X : B) : + IsCoreflexivePair (U'.map (F.map (adj₁.unit.app X))) (otherMap _ _ adj₁ adj₂ X) := + IsCoreflexivePair.mk' (U'.map (adj₁.counit.app (F.obj X))) + (by simp [← Functor.map_comp]) + (by simp only [otherMap, assoc, ← Functor.map_comp]; simp) + +variable [HasCoreflexiveEqualizers C] + +/-- Construct the object part of the desired right adjoint as the equalizer of `U'Fη_Y` with +`otherMap`. +-/ +noncomputable def constructRightAdjointObj (Y : B) : C := + equalizer (U'.map (F.map (adj₁.unit.app Y))) (otherMap _ _ adj₁ adj₂ Y) + +/-- The homset equivalence which helps show that `L` is a left adjoint. -/ +@[simps!] +noncomputable def constructRightAdjointEquiv [∀ X : B, RegularMono (adj₁.unit.app X)] (Y : C) + (X : B) : (Y ⟶ constructRightAdjointObj _ _ adj₁ adj₂ X) ≃ (L.obj Y ⟶ X) := + calc + (Y ⟶ constructRightAdjointObj _ _ adj₁ adj₂ X) ≃ + { f : Y ⟶ U'.obj (F.obj X) // + f ≫ U'.map (F.map (adj₁.unit.app X)) = f ≫ (otherMap _ _ adj₁ adj₂ X) } := + Fork.IsLimit.homIso (limit.isLimit _) _ + _ ≃ { g : F.obj (L.obj Y) ⟶ F.obj X // F.map (adj₁.unit.app _≫ U.map g) = + g ≫ F.map (adj₁.unit.app _) } := by + apply (adj₂.homEquiv _ _).symm.subtypeEquiv _ + intro f + rw [← (adj₂.homEquiv _ _).injective.eq_iff, eq_comm, otherMap, + ← adj₂.homEquiv_naturality_right_symm, adj₂.homEquiv_unit, ← adj₂.unit_naturality_assoc, + adj₂.homEquiv_counit] + simp + _ ≃ { z : L.obj Y ⟶ U.obj (F.obj X) // + z ≫ U.map (F.map (adj₁.unit.app X)) = z ≫ adj₁.unit.app (U.obj (F.obj X)) } := by + apply (adj₁.homEquiv _ _).subtypeEquiv + intro g + rw [← (adj₁.homEquiv _ _).injective.eq_iff, adj₁.homEquiv_unit, + adj₁.homEquiv_unit, adj₁.homEquiv_unit, eq_comm] + simp + _ ≃ (L.obj Y ⟶ X) := (Fork.IsLimit.homIso (unitEqualises adj₁ X) _).symm + +/-- Construct the right adjoint to `L`, with object map `constructRightAdjointObj`. -/ +noncomputable def constructRightAdjoint [∀ X : B, RegularMono (adj₁.unit.app X)] : B ⥤ C := by + refine Adjunction.rightAdjointOfEquiv + (fun X Y => (constructRightAdjointEquiv L _ adj₁ adj₂ X Y).symm) ?_ + intro X Y Y' g h + rw [constructRightAdjointEquiv_symm_apply, constructRightAdjointEquiv_symm_apply, + Equiv.symm_apply_eq, Subtype.ext_iff] + dsimp + 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] + simp + +end LiftRightAdjoint + +/-- The adjoint triangle theorem: Suppose `U : A ⥤ B` has a left adjoint `F` such that each unit +`η_X : X ⟶ UFX` is a regular monomorphism. Then if a category `C` has equalizers of coreflexive +pairs, then a functor `L : C ⥤ B` has a right adjoint if the composite `L ⋙ F` does. + +Note the converse is true (with weaker assumptions), by `Adjunction.comp`. +See https://ncatlab.org/nlab/show/adjoint+triangle+theorem +-/ +lemma isLeftAdjoint_triangle_lift {U : A ⥤ B} {F : B ⥤ A} (L : C ⥤ B) (adj₁ : F ⊣ U) + [∀ X, RegularMono (adj₁.unit.app X)] [HasCoreflexiveEqualizers C] + [(L ⋙ F).IsLeftAdjoint ] : L.IsLeftAdjoint where + exists_rightAdjoint := + ⟨LiftRightAdjoint.constructRightAdjoint L _ adj₁ (Adjunction.ofIsLeftAdjoint _), + ⟨Adjunction.adjunctionOfEquivRight _ _⟩⟩ + +/-- If `L ⋙ F` has a right adjoint, the domain of `L` has coreflexive equalizers and `F` is a +comonadic functor, then `L` has a right adjoint. +This is a special case of `isLeftAdjoint_triangle_lift` which is often more useful in practice. +-/ +lemma isLeftAdjoint_triangle_lift_comonadic (F : B ⥤ A) [ComonadicLeftAdjoint F] {L : C ⥤ B} + [HasCoreflexiveEqualizers C] [(L ⋙ F).IsLeftAdjoint] : L.IsLeftAdjoint := by + let L' : _ ⥤ _ := L ⋙ Comonad.comparison (comonadicAdjunction F) + rsuffices : L'.IsLeftAdjoint + · let this : (L' ⋙ (Comonad.comparison (comonadicAdjunction F)).inv).IsLeftAdjoint := by + infer_instance + refine ((Adjunction.ofIsLeftAdjoint + (L' ⋙ (Comonad.comparison (comonadicAdjunction F)).inv)).ofNatIsoLeft ?_).isLeftAdjoint + exact isoWhiskerLeft L (Comonad.comparison _).asEquivalence.unitIso.symm ≪≫ L.leftUnitor + let this : (L' ⋙ Comonad.forget (comonadicAdjunction F).toComonad).IsLeftAdjoint := by + refine ((Adjunction.ofIsLeftAdjoint (L ⋙ F)).ofNatIsoLeft ?_).isLeftAdjoint + exact isoWhiskerLeft L (Comonad.comparisonForget (comonadicAdjunction F)).symm + let this : ∀ X, RegularMono ((Comonad.adj (comonadicAdjunction F).toComonad).unit.app X) := by + intro X + simp only [Comonad.adj_unit] + exact ⟨_, _, _, _, Comonad.beckCoalgebraEqualizer X⟩ + exact isLeftAdjoint_triangle_lift L' (Comonad.adj _) + +variable {D : Type u₄} +variable [Category.{v₄} D] + +/-- Suppose we have a commutative square of functors + +``` + Q + A → B + U ↓ ↓ V + C → D + R +``` + +where `U` has a right adjoint, `A` has coreflexive equalizers and `V` has a right adjoint such that +each component of the counit is a regular mono. +Then `Q` has a right adjoint if `L` has a right adjoint. + +See https://ncatlab.org/nlab/show/adjoint+lifting+theorem +-/ +lemma isLeftAdjoint_square_lift (Q : A ⥤ B) (V : B ⥤ D) (U : A ⥤ C) (L : C ⥤ D) + (comm : U ⋙ L ≅ Q ⋙ V) [U.IsLeftAdjoint] [V.IsLeftAdjoint] [L.IsLeftAdjoint] + [∀ X, RegularMono ((Adjunction.ofIsLeftAdjoint V).unit.app X)] [HasCoreflexiveEqualizers A] : + Q.IsLeftAdjoint := + have := ((Adjunction.ofIsLeftAdjoint (U ⋙ L)).ofNatIsoLeft comm).isLeftAdjoint + isLeftAdjoint_triangle_lift Q (Adjunction.ofIsLeftAdjoint V) + +/-- Suppose we have a commutative square of functors + +``` + Q + A → B + U ↓ ↓ V + C → D + R +``` + +where `U` has a right adjoint, `A` has reflexive equalizers and `V` is comonadic. +Then `Q` has a right adjoint if `L` has a right adjoint. + +See https://ncatlab.org/nlab/show/adjoint+lifting+theorem +-/ +lemma isLeftAdjoint_square_lift_comonadic (Q : A ⥤ B) (V : B ⥤ D) (U : A ⥤ C) (L : C ⥤ D) + (comm : U ⋙ L ≅ Q ⋙ V) [U.IsLeftAdjoint] [ComonadicLeftAdjoint V] [L.IsLeftAdjoint] + [HasCoreflexiveEqualizers A] : Q.IsLeftAdjoint := + have := ((Adjunction.ofIsLeftAdjoint (U ⋙ L)).ofNatIsoLeft comm).isLeftAdjoint + isLeftAdjoint_triangle_lift_comonadic V + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Adjunction/Limits.lean b/Mathlib/CategoryTheory/Adjunction/Limits.lean index e66f18e83e81d..6a2f33e8ce6ad 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] : diff --git a/Mathlib/CategoryTheory/Adjunction/Mates.lean b/Mathlib/CategoryTheory/Adjunction/Mates.lean index cacbc727a8ab8..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. @@ -45,8 +47,8 @@ open Category Functor Adjunction NatTrans section mateEquiv -variable {C : Type u₁} {D : Type u₂}{E : Type u₃} {F : Type u₄} -variable [Category.{v₁} C] [Category.{v₂} D][Category.{v₃} E] [Category.{v₄} F] +variable {C : Type u₁} {D : Type u₂} {E : Type u₃} {F : Type u₄} +variable [Category.{v₁} C] [Category.{v₂} D] [Category.{v₃} E] [Category.{v₄} F] variable {G : C ⥤ E} {H : D ⥤ F} {L₁ : C ⥤ D} {R₁ : D ⥤ C} {L₂ : E ⥤ F} {R₂ : F ⥤ E} variable (adj₁ : L₁ ⊣ R₁) (adj₂ : L₂ ⊣ R₂) @@ -119,9 +121,7 @@ theorem unit_mateEquiv (α : G ⋙ L₂ ⟶ L₁ ⋙ H) (c : C) : rw [← R₂.map_comp, ← Functor.comp_map G L₂, α.naturality] rw [R₂.map_comp] slice_lhs 3 4 => - { - rw [← R₂.map_comp, Functor.comp_map L₁ H, ← H.map_comp, left_triangle_components] - } + rw [← R₂.map_comp, Functor.comp_map L₁ H, ← H.map_comp, left_triangle_components] simp only [comp_obj, map_id, comp_id] /-- A component of a transposed version of the inverse mates correspondence. -/ @@ -136,10 +136,10 @@ end mateEquiv section mateEquivVComp variable {A : Type u₁} {B : Type u₂} {C : Type u₃} {D : Type u₄} {E : Type u₅} {F : Type u₆} -variable [Category.{v₁} A] [Category.{v₂} B][Category.{v₃} C] -variable [Category.{v₄} D] [Category.{v₅} E][Category.{v₆} F] -variable {G₁ : A ⥤ C}{G₂ : C ⥤ E}{H₁ : B ⥤ D}{H₂ : D ⥤ F} -variable {L₁ : A ⥤ B}{R₁ : B ⥤ A} {L₂ : C ⥤ D}{R₂ : D ⥤ C}{L₃ : E ⥤ F}{R₃ : F ⥤ E} +variable [Category.{v₁} A] [Category.{v₂} B] [Category.{v₃} C] +variable [Category.{v₄} D] [Category.{v₅} E] [Category.{v₆} F] +variable {G₁ : A ⥤ C} {G₂ : C ⥤ E} {H₁ : B ⥤ D} {H₂ : D ⥤ F} +variable {L₁ : A ⥤ B} {R₁ : B ⥤ A} {L₂ : C ⥤ D} {R₂ : D ⥤ C} {L₃ : E ⥤ F} {R₃ : F ⥤ E} variable (adj₁ : L₁ ⊣ R₁) (adj₂ : L₂ ⊣ R₂) (adj₃ : L₃ ⊣ R₃) /-- Squares between left adjoints can be composed "vertically" by pasting. -/ @@ -162,32 +162,21 @@ theorem mateEquiv_vcomp 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, whiskerRight_twice] - slice_rhs 1 4 => - { - rw [← assoc, ← assoc, ← unit_naturality (adj₃)] - } + slice_rhs 1 4 => rw [← assoc, ← assoc, ← unit_naturality (adj₃)] rw [L₃.map_comp, R₃.map_comp] slice_rhs 2 4 => - { - rw [← R₃.map_comp, ← R₃.map_comp, ← assoc, ← L₃.map_comp, ← G₂.map_comp, ← G₂.map_comp] - rw [← Functor.comp_map G₂ L₃, β.naturality] - } + rw [← R₃.map_comp, ← R₃.map_comp, ← assoc, ← L₃.map_comp, ← G₂.map_comp, ← G₂.map_comp] + rw [← Functor.comp_map G₂ L₃, β.naturality] rw [(L₂ ⋙ H₂).map_comp, R₃.map_comp, R₃.map_comp] slice_rhs 4 5 => - { - rw [← R₃.map_comp, Functor.comp_map L₂ _, ← Functor.comp_map _ L₂, ← H₂.map_comp] - rw [adj₂.counit.naturality] - } + rw [← R₃.map_comp, Functor.comp_map L₂ _, ← Functor.comp_map _ L₂, ← H₂.map_comp] + rw [adj₂.counit.naturality] simp only [comp_obj, Functor.comp_map, map_comp, id_obj, Functor.id_map, assoc] slice_rhs 4 5 => - { - rw [← R₃.map_comp, ← H₂.map_comp, ← Functor.comp_map _ L₂, adj₂.counit.naturality] - } + rw [← R₃.map_comp, ← H₂.map_comp, ← Functor.comp_map _ L₂, adj₂.counit.naturality] simp only [comp_obj, id_obj, Functor.id_map, map_comp, assoc] slice_rhs 3 4 => - { - rw [← R₃.map_comp, ← H₂.map_comp, left_triangle_components] - } + rw [← R₃.map_comp, ← H₂.map_comp, left_triangle_components] simp only [map_id, id_comp] end mateEquivVComp @@ -195,11 +184,11 @@ end mateEquivVComp section mateEquivHComp variable {A : Type u₁} {B : Type u₂} {C : Type u₃} {D : Type u₄} {E : Type u₅} {F : Type u₆} -variable [Category.{v₁} A] [Category.{v₂} B][Category.{v₃} C] -variable [Category.{v₄} D] [Category.{v₅} E][Category.{v₆} F] -variable {G : A ⥤ D}{H : B ⥤ E}{K : C ⥤ F} -variable {L₁ : A ⥤ B}{R₁ : B ⥤ A} {L₂ : D ⥤ E}{R₂ : E ⥤ D} -variable {L₃ : B ⥤ C}{R₃ : C ⥤ B} {L₄ : E ⥤ F}{R₄ : F ⥤ E} +variable [Category.{v₁} A] [Category.{v₂} B] [Category.{v₃} C] +variable [Category.{v₄} D] [Category.{v₅} E] [Category.{v₆} F] +variable {G : A ⥤ D} {H : B ⥤ E} {K : C ⥤ F} +variable {L₁ : A ⥤ B} {R₁ : B ⥤ A} {L₂ : D ⥤ E} {R₂ : E ⥤ D} +variable {L₃ : B ⥤ C} {R₃ : C ⥤ B} {L₄ : E ⥤ F} {R₄ : F ⥤ E} variable (adj₁ : L₁ ⊣ R₁) (adj₂ : L₂ ⊣ R₂) (adj₃ : L₃ ⊣ R₃) (adj₄ : L₄ ⊣ R₄) /-- Squares between left adjoints can be composed "horizontally" by pasting. -/ @@ -219,18 +208,14 @@ 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₄)] - } + rw [← R₂.map_comp, ← R₂.map_comp, ← assoc, ← unit_naturality (adj₄)] rw [R₂.map_comp, L₄.map_comp, R₄.map_comp, R₂.map_comp] slice_rhs 4 5 => - { - rw [← R₂.map_comp, ← R₄.map_comp, ← Functor.comp_map _ L₄ , β.naturality] - } + rw [← R₂.map_comp, ← R₄.map_comp, ← Functor.comp_map _ L₄ , β.naturality] simp only [comp_obj, Functor.comp_map, map_comp, assoc] end mateEquivHComp @@ -240,9 +225,9 @@ section mateEquivSquareComp variable {A : Type u₁} {B : Type u₂} {C : Type u₃} variable {D : Type u₄} {E : Type u₅} {F : Type u₆} variable {X : Type u₇} {Y : Type u₈} {Z : Type u₉} -variable [Category.{v₁} A] [Category.{v₂} B][Category.{v₃} C] -variable [Category.{v₄} D] [Category.{v₅} E][Category.{v₆} F] -variable [Category.{v₇} X] [Category.{v₈} Y][Category.{v₉} Z] +variable [Category.{v₁} A] [Category.{v₂} B] [Category.{v₃} C] +variable [Category.{v₄} D] [Category.{v₅} E] [Category.{v₆} F] +variable [Category.{v₇} X] [Category.{v₈} Y] [Category.{v₉} Z] variable {G₁ : A ⥤ D} {H₁ : B ⥤ E} {K₁ : C ⥤ F} {G₂ : D ⥤ X} {H₂ : E ⥤ Y} {K₂ : F ⥤ Z} variable {L₁ : A ⥤ B} {R₁ : B ⥤ A} {L₂ : B ⥤ C} {R₂ : C ⥤ B} {L₃ : D ⥤ E} {R₃ : E ⥤ D} variable {L₄ : E ⥤ F} {R₄ : F ⥤ E} {L₅ : X ⥤ Y} {R₅ : Y ⥤ X} {L₆ : Y ⥤ Z} {R₆ : Z ⥤ Y} @@ -275,9 +260,7 @@ theorem leftAdjointSquare.comp_hvcomp ext a simp only [comp_obj, comp_app, map_comp, assoc] slice_rhs 2 3 => - { - rw [← Functor.comp_map _ L₆, δ.naturality] - } + rw [← Functor.comp_map _ L₆, δ.naturality] simp only [comp_obj, Functor.comp_map, assoc] /-- Squares of squares between right adjoints can be composed by iterating vertical and horizontal @@ -306,9 +289,7 @@ theorem rightAdjointSquare.comp_hvcomp ext c simp only [comp_obj, comp_app, map_comp, assoc] slice_rhs 2 3 => - { - rw [← Functor.comp_map _ R₅, ← γ.naturality] - } + rw [← Functor.comp_map _ R₅, ← γ.naturality] simp only [comp_obj, Functor.comp_map, assoc] /-- The mates equivalence commutes with composition of squares of squares. These results form the @@ -349,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 @@ -422,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 @@ -435,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 @@ -445,7 +429,7 @@ theorem conjugateEquiv_comm {α : L₂ ⟶ L₁} {β : L₁ ⟶ L₂} (βα : β conjugateEquiv adj₁ adj₂ α ≫ conjugateEquiv adj₂ adj₁ β = 𝟙 _ := by rw [conjugateEquiv_comp, βα, conjugateEquiv_id] -theorem conjugateEquiv_symm_comm {α : R₁ ⟶ R₂}{β : R₂ ⟶ R₁} (αβ : α ≫ β = 𝟙 _) : +theorem conjugateEquiv_symm_comm {α : R₁ ⟶ R₂} {β : R₂ ⟶ R₁} (αβ : α ≫ β = 𝟙 _) : (conjugateEquiv adj₂ adj₁).symm β ≫ (conjugateEquiv adj₁ adj₂).symm α = 𝟙 _ := by rw [conjugateEquiv_symm_comp, αβ, conjugateEquiv_symm_id] @@ -494,20 +478,27 @@ 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 end ConjugateIsomorphism section IteratedmateEquiv -variable {A : Type u₁} {B : Type u₂}{C : Type u₃} {D : Type u₄} -variable [Category.{v₁} A] [Category.{v₂} B][Category.{v₃} C] [Category.{v₄} D] -variable {F₁ : A ⥤ C}{U₁ : C ⥤ A} {F₂ : B ⥤ D} {U₂ : D ⥤ B} +variable {A : Type u₁} {B : Type u₂} {C : Type u₃} {D : Type u₄} +variable [Category.{v₁} A] [Category.{v₂} B] [Category.{v₃} C] [Category.{v₄} D] +variable {F₁ : A ⥤ C} {U₁ : C ⥤ A} {F₂ : B ⥤ D} {U₂ : D ⥤ B} variable {L₁ : A ⥤ B} {R₁ : B ⥤ A} {L₂ : C ⥤ D} {R₂ : D ⥤ C} -variable (adj₁ : L₁ ⊣ R₁) (adj₂ : L₂ ⊣ R₂) (adj₃ : F₁ ⊣ U₁)(adj₄ : F₂ ⊣ U₂) +variable (adj₁ : L₁ ⊣ R₁) (adj₂ : L₂ ⊣ R₂) (adj₃ : F₁ ⊣ U₁) (adj₄ : F₂ ⊣ U₂) /-- When all four functors in a sequare are left adjoints, the mates operation can be iterated: @@ -526,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 α) = @@ -542,11 +529,11 @@ end IteratedmateEquiv section mateEquivconjugateEquivVComp -variable {A : Type u₁} {B : Type u₂} {C : Type u₃}{D : Type u₄} -variable [Category.{v₁} A] [Category.{v₂} B][Category.{v₃} C] +variable {A : Type u₁} {B : Type u₂} {C : Type u₃} {D : Type u₄} +variable [Category.{v₁} A] [Category.{v₂} B] [Category.{v₃} C] variable [Category.{v₄} D] variable {G : A ⥤ C} {H : B ⥤ D} -variable {L₁ : A ⥤ B} {R₁ : B ⥤ A} {L₂ : C ⥤ D} {R₂ : D ⥤ C} {L₃ : C ⥤ D}{R₃ : D ⥤ C} +variable {L₁ : A ⥤ B} {R₁ : B ⥤ A} {L₂ : C ⥤ D} {R₂ : D ⥤ C} {L₃ : C ⥤ D} {R₃ : D ⥤ C} variable (adj₁ : L₁ ⊣ R₁) (adj₂ : L₂ ⊣ R₂) (adj₃ : L₃ ⊣ R₃) /-- Composition of a squares between left adjoints with a conjugate square. -/ @@ -581,8 +568,8 @@ end mateEquivconjugateEquivVComp section conjugateEquivmateEquivVComp -variable {A : Type u₁} {B : Type u₂} {C : Type u₃}{D : Type u₄} -variable [Category.{v₁} A] [Category.{v₂} B][Category.{v₃} C] +variable {A : Type u₁} {B : Type u₂} {C : Type u₃} {D : Type u₄} +variable [Category.{v₁} A] [Category.{v₂} B] [Category.{v₃} C] variable [Category.{v₄} D] variable {G : A ⥤ C} {H : B ⥤ D} variable {L₁ : A ⥤ B} {R₁ : B ⥤ A} {L₂ : A ⥤ B} {R₂ : B ⥤ A} {L₃ : C ⥤ D} {R₃ : D ⥤ C} diff --git a/Mathlib/CategoryTheory/Adjunction/Opposites.lean b/Mathlib/CategoryTheory/Adjunction/Opposites.lean index 9cbae02e88e30..f4362585c27a4 100644 --- a/Mathlib/CategoryTheory/Adjunction/Opposites.lean +++ b/Mathlib/CategoryTheory/Adjunction/Opposites.lean @@ -28,10 +28,6 @@ variable {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D] namespace CategoryTheory.Adjunction /-- If `G.op` is adjoint to `F.op` then `F` is adjoint to `G`. -/ --- Porting note: in mathlib3 we generated all the default `simps` lemmas. --- However the `simpNF` linter correctly flags some of these as unsuitable simp lemmas. --- `unit_app` and `counit_app` appear to suffice (tested in mathlib3). --- See also the porting note on opAdjointOpOfAdjoint @[simps! unit_app counit_app] def adjointOfOpAdjointOp (F : C ⥤ D) (G : D ⥤ C) (h : G.op ⊣ F.op) : F ⊣ G := Adjunction.mkOfHomEquiv { @@ -39,21 +35,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 := @@ -69,30 +61,20 @@ def unopAdjointUnopOfAdjoint (F : Cᵒᵖ ⥤ Dᵒᵖ) (G : Dᵒᵖ ⥤ Cᵒᵖ) /-- If `G` is adjoint to `F` then `F.op` is adjoint to `G.op`. -/ @[simps! unit_app counit_app] --- Porting note: in mathlib3 we generated all the default `simps` lemmas. --- However the `simpNF` linter correctly flags some of these as unsuitable simp lemmas. --- `unit_app` and `counit_app` appear to suffice (tested in mathlib3). --- See also the porting note on adjointOfOpAdjointOp def opAdjointOpOfAdjoint (F : C ⥤ D) (G : D ⥤ C) (h : G ⊣ F) : F.op ⊣ G.op := Adjunction.mkOfHomEquiv { homEquiv := fun X Y => (opEquiv _ Y).trans ((h.homEquiv _ _).symm.trans (opEquiv X (Opposite.op _)).symm) 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` aren't firing. + intros + simp [opEquiv] homEquiv_naturality_right := 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_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` aren't firing. + intros + simp [opEquiv] } /-- If `G` is adjoint to `F.unop` then `F` is adjoint to `G.op`. -/ def adjointOpOfAdjointUnop (F : Cᵒᵖ ⥤ Dᵒᵖ) (G : D ⥤ C) (h : G ⊣ F.unop) : F ⊣ G.op := diff --git a/Mathlib/CategoryTheory/Adjunction/Reflective.lean b/Mathlib/CategoryTheory/Adjunction/Reflective.lean index fd2b0d3f2dcf4..2ddd0414b0f2f 100644 --- a/Mathlib/CategoryTheory/Adjunction/Reflective.lean +++ b/Mathlib/CategoryTheory/Adjunction/Reflective.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Bhavik Mehta -/ import Mathlib.CategoryTheory.Adjunction.FullyFaithful -import Mathlib.CategoryTheory.Functor.ReflectsIso +import Mathlib.CategoryTheory.Functor.EpiMono import Mathlib.CategoryTheory.HomCongr /-! @@ -153,60 +153,20 @@ instance [Reflective i] (X : Functor.EssImageSubcategory i) : IsIso (NatTrans.app (reflectorAdjunction i).unit X.obj) := Functor.essImage.unit_isIso X.property --- Porting note: the following auxiliary definition and the next two lemmas were --- introduced in order to ease the port -/-- The counit isomorphism of the equivalence `D ≌ i.EssImageSubcategory` given -by `equivEssImageOfReflective` when the functor `i` is reflective. -/ -def equivEssImageOfReflective_counitIso_app [Reflective i] (X : Functor.EssImageSubcategory i) : - ((Functor.essImageInclusion i ⋙ reflector i) ⋙ Functor.toEssImage i).obj X ≅ X := by - refine Iso.symm (@asIso _ _ X _ ((reflectorAdjunction i).unit.app X.obj) ?_) - refine @isIso_of_reflects_iso _ _ _ _ _ _ _ i.essImageInclusion ?_ _ - dsimp - exact inferInstance - -lemma equivEssImageOfReflective_map_counitIso_app_hom [Reflective i] - (X : Functor.EssImageSubcategory i) : - (Functor.essImageInclusion i).map (equivEssImageOfReflective_counitIso_app X).hom = - inv (NatTrans.app (reflectorAdjunction i).unit X.obj) := by - simp only [Functor.comp_obj, Functor.essImageInclusion_obj, Functor.toEssImage_obj_obj, - equivEssImageOfReflective_counitIso_app, asIso, Iso.symm_mk, Functor.essImageInclusion_map, - Functor.id_obj] - rfl - -lemma equivEssImageOfReflective_map_counitIso_app_inv [Reflective i] - (X : Functor.EssImageSubcategory i) : - (Functor.essImageInclusion i).map (equivEssImageOfReflective_counitIso_app X).inv = - (NatTrans.app (reflectorAdjunction i).unit X.obj) := rfl - +-- These attributes are necessary to make automation work in `equivEssImageOfReflective`. +-- Making them global doesn't break anything elsewhere, but this is enough for now. +-- TODO: investigate further. +attribute [local simp 900] Functor.essImageInclusion_map in +attribute [local ext] Functor.essImage_ext in /-- If `i : D ⥤ C` is reflective, the inverse functor of `i ≌ F.essImage` can be explicitly defined by the reflector. -/ @[simps] def equivEssImageOfReflective [Reflective i] : D ≌ i.EssImageSubcategory where functor := i.toEssImage inverse := i.essImageInclusion ⋙ reflector i - unitIso := - NatIso.ofComponents (fun X => (asIso <| (reflectorAdjunction i).counit.app X).symm) - (by - intro X Y f - dsimp - rw [IsIso.comp_inv_eq, Category.assoc, IsIso.eq_inv_comp] - exact ((reflectorAdjunction i).counit.naturality f).symm) - counitIso := - NatIso.ofComponents equivEssImageOfReflective_counitIso_app - (by - intro X Y f - apply (Functor.essImageInclusion i).map_injective - have h := ((reflectorAdjunction i).unit.naturality f).symm - rw [Functor.id_map] at h - erw [Functor.map_comp, Functor.map_comp, - equivEssImageOfReflective_map_counitIso_app_hom, - equivEssImageOfReflective_map_counitIso_app_hom, - IsIso.comp_inv_eq, assoc, ← h, IsIso.inv_hom_id_assoc, Functor.comp_map]) - functor_unitIso_comp := fun X => by - -- Porting note: this proof was automatically handled by the automation in mathlib - apply (Functor.essImageInclusion i).map_injective - erw [Functor.map_comp, equivEssImageOfReflective_map_counitIso_app_hom] - aesop_cat + unitIso := (asIso <| (reflectorAdjunction i).counit).symm + counitIso := Functor.fullyFaithfulCancelRight i.essImageInclusion <| + NatIso.ofComponents (fun X ↦ (asIso ((reflectorAdjunction i).unit.app X.obj)).symm) /-- A functor is *coreflective*, or *a coreflective inclusion*, if it is fully faithful and left diff --git a/Mathlib/CategoryTheory/Adjunction/Restrict.lean b/Mathlib/CategoryTheory/Adjunction/Restrict.lean index e433f14102099..d3e8258ab5062 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 @@ -69,6 +69,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 new file mode 100644 index 0000000000000..d1ee7a410b19f --- /dev/null +++ b/Mathlib/CategoryTheory/Adjunction/Triple.lean @@ -0,0 +1,55 @@ +/- +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.Unique +import Mathlib.CategoryTheory.Monad.Adjunction +/-! + +# Adjoint triples + +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. +-/ + +namespace CategoryTheory.Adjunction + +variable {C D : Type*} [Category C] [Category D] +variable {F H : C ⥤ D} {G : D ⥤ C} +variable (adj₁ : F ⊣ G) (adj₂ : G ⊣ H) + +lemma isIso_unit_iff_isIso_counit : IsIso adj₁.unit ↔ IsIso adj₂.counit := by + let adj : F ⋙ G ⊣ H ⋙ G := adj₁.comp adj₂ + constructor + · intro h + let idAdj : 𝟭 C ⊣ H ⋙ G := adj.ofNatIsoLeft (asIso adj₁.unit).symm + exact adj₂.isIso_counit_of_iso (idAdj.rightAdjointUniq id) + · intro h + let adjId : F ⋙ G ⊣ 𝟭 C := adj.ofNatIsoRight (asIso 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 +right adjoint `H` is fully faithful. +-/ +noncomputable def fullyFaithfulEquiv : F.FullyFaithful ≃ H.FullyFaithful where + toFun h := + haveI := h.full + haveI := h.faithful + haveI : IsIso adj₂.counit := by + rw [← adj₁.isIso_unit_iff_isIso_counit adj₂] + infer_instance + adj₂.fullyFaithfulROfIsIsoCounit + invFun h := + haveI := h.full + haveI := h.faithful + haveI : IsIso adj₁.unit := by + rw [adj₁.isIso_unit_iff_isIso_counit adj₂] + infer_instance + adj₁.fullyFaithfulLOfIsIsoUnit + left_inv _ := Subsingleton.elim _ _ + right_inv _ := Subsingleton.elim _ _ + +end CategoryTheory.Adjunction diff --git a/Mathlib/CategoryTheory/Adjunction/Unique.lean b/Mathlib/CategoryTheory/Adjunction/Unique.lean index e89f8f0cac695..9c4b07886fc7d 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,15 +11,13 @@ 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. * `Adjunction.rightAdjointUniq` : If `G` and `G'` are both right adjoint to `F`, then they are naturally isomorphic. + -/ open CategoryTheory @@ -28,89 +26,9 @@ 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 - /-- 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) @@ -134,9 +52,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 @@ -173,7 +92,7 @@ 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) @@ -185,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 @@ -236,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 acb01f1bd07bb..8721c45df98f3 100644 --- a/Mathlib/CategoryTheory/Bicategory/Coherence.lean +++ b/Mathlib/CategoryTheory/Bicategory/Coherence.lean @@ -204,11 +204,11 @@ def normalizeUnitIso (a b : FreeBicategory B) : def normalizeEquiv (a b : B) : Hom a b ≌ Discrete (Path.{v + 1} a b) := Equivalence.mk ((normalize _).mapFunctor a b) (inclusionPath a b) (normalizeUnitIso a b) (Discrete.natIso fun f => eqToIso (by - induction' f with f - induction' f with _ _ _ _ ih - -- Porting note: `tidy` closes the goal in mathlib3 but `aesop` doesn't here. - · rfl - · ext1 + obtain ⟨f⟩ := f + induction f with + | nil => rfl + | cons _ _ ih => + ext1 -- Porting note: `tidy` closes the goal in mathlib3 but `aesop` doesn't here. injection ih with ih conv_rhs => rw [← ih] rfl)) diff --git a/Mathlib/CategoryTheory/Bicategory/End.lean b/Mathlib/CategoryTheory/Bicategory/End.lean index 1caa7d9c14e97..8210d2a2cdcd0 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 diff --git a/Mathlib/CategoryTheory/Bicategory/Free.lean b/Mathlib/CategoryTheory/Bicategory/Free.lean index 2063a717cc38f..e423dd24b31be 100644 --- a/Mathlib/CategoryTheory/Bicategory/Free.lean +++ b/Mathlib/CategoryTheory/Bicategory/Free.lean @@ -334,19 +334,16 @@ def lift : Pseudofunctor (FreeBicategory B) C where -- in mathlib3 `tidy` did these inductions for us. map₂_comp := by intros a b f g h η θ - apply Quot.rec _ _ η - · intro η - apply Quot.rec _ _ θ - · intro θ; rfl - · intros; rfl - · intros; rfl + induction η using Quot.rec + · induction θ using Quot.rec <;> rfl + · rfl -- Porting note: still borked from here. The infoview doesn't update properly for me. map₂_whisker_left := by intro a b c f g h η - apply Quot.rec _ _ η - · intros; aesop_cat - · intros; rfl - map₂_whisker_right := by intro _ _ _ _ _ η h; dsimp; apply Quot.rec _ _ η <;> aesop_cat + induction η using Quot.rec + · aesop_cat + · rfl + map₂_whisker_right := by intro _ _ _ _ _ η h; dsimp; induction η using Quot.rec <;> aesop_cat end diff --git a/Mathlib/CategoryTheory/Bicategory/Functor/Lax.lean b/Mathlib/CategoryTheory/Bicategory/Functor/Lax.lean index 616625791af23..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 @@ -58,24 +59,24 @@ structure LaxFunctor (B: Type u₁) [Bicategory.{w₁, v₁} B] (C : Type u₂) mapId (a : B) : 𝟙 (obj a) ⟶ map (𝟙 a) /-- The 2-morphism underlying the lax functoriality constraint. -/ mapComp {a b c : B} (f : a ⟶ b) (g : b ⟶ c) : map f ≫ map g ⟶ map (f ≫ g) - /-- Naturality of the lax functoriality constraight, on the left. -/ + /-- Naturality of the lax functoriality constraint, on the left. -/ mapComp_naturality_left : ∀ {a b c : B} {f f' : a ⟶ b} (η : f ⟶ f') (g : b ⟶ c), mapComp f g ≫ map₂ (η ▷ g) = map₂ η ▷ map g ≫ mapComp f' g:= by aesop_cat - /-- Naturality of the lax functoriality constraight, on the right. -/ + /-- Naturality of the lax functoriality constraint, on the right. -/ mapComp_naturality_right : ∀ {a b c : B} (f : a ⟶ b) {g g' : b ⟶ c} (η : g ⟶ g'), mapComp f g ≫ map₂ (f ◁ η) = map f ◁ map₂ η ≫ mapComp f g' := by aesop_cat - /-- Lax associativity -/ + /-- Lax associativity. -/ map₂_associator : ∀ {a b c d : B} (f : a ⟶ b) (g : b ⟶ c) (h : c ⟶ d), mapComp f g ▷ map h ≫ mapComp (f ≫ g) h ≫ map₂ (α_ f g h).hom = (α_ (map f) (map g) (map h)).hom ≫ map f ◁ mapComp g h ≫ mapComp f (g ≫ h) := by aesop_cat - /-- Lax left unity -/ + /-- Lax left unity. -/ map₂_leftUnitor : ∀ {a b : B} (f : a ⟶ b), map₂ (λ_ f).inv = (λ_ (map f)).inv ≫ mapId a ▷ map f ≫ mapComp (𝟙 a) f := by aesop_cat - /-- Lax right unity -/ + /-- Lax right unity. -/ map₂_rightUnitor : ∀ {a b : B} (f : a ⟶ b), map₂ (ρ_ f).inv = (ρ_ (map f)).inv ≫ map f ◁ mapId b ≫ mapComp f (𝟙 b) := by aesop_cat @@ -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,23 +161,22 @@ 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. See `Pseudofunctor.mkOfLax`. -/ structure PseudoCore (F : LaxFunctor B C) where + /-- The isomorphism giving rise to the lax unity constraint -/ mapIdIso (a : B) : F.map (𝟙 a) ≅ 𝟙 (F.obj a) + /-- The isomorphism giving rise to the lax functoriality constraint -/ mapCompIso {a b c : B} (f : a ⟶ b) (g : b ⟶ c) : F.map (f ≫ g) ≅ F.map f ≫ F.map g + /-- `mapIdIso` gives rise to the lax unity constraint -/ mapIdIso_inv {a : B} : (mapIdIso a).inv = F.mapId a := by aesop_cat + /-- `mapCompIso` gives rise to the lax functoriality constraint -/ mapCompIso_inv {a b c : B} (f : a ⟶ b) (g : b ⟶ c) : (mapCompIso f g).inv = F.mapComp f g := by aesop_cat -attribute [nolint docBlame] CategoryTheory.LaxFunctor.PseudoCore.mapIdIso - CategoryTheory.LaxFunctor.PseudoCore.mapCompIso - CategoryTheory.LaxFunctor.PseudoCore.mapIdIso_inv - CategoryTheory.LaxFunctor.PseudoCore.mapCompIso_inv - attribute [simp] PseudoCore.mapIdIso_inv PseudoCore.mapCompIso_inv end LaxFunctor diff --git a/Mathlib/CategoryTheory/Bicategory/Functor/Oplax.lean b/Mathlib/CategoryTheory/Bicategory/Functor/Oplax.lean index bc1c66a21dae8..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 @@ -36,17 +37,6 @@ section variable {B : Type u₁} [Bicategory.{w₁, v₁} B] {C : Type u₂} [Bicategory.{w₂, v₂} C] variable {D : Type u₃} [Bicategory.{w₃, v₃} D] --- Porting note: in Lean 3 the below auxiliary definition was only used once, in the definition --- of oplax functor, with a comment that it had to be used to fix a timeout. The timeout is --- not present in Lean 4, however Lean 4 is not as good at seeing through the definition, --- meaning that `simp` wasn't functioning as well as it should. I have hence removed --- the auxiliary definition. ---@[simp] ---def OplaxFunctor.Map₂AssociatorAux (obj : B → C) (map : ∀ {X Y : B}, (X ⟶ Y) → (obj X ⟶ obj Y)) --- (map₂ : ∀ {a b : B} {f g : a ⟶ b}, (f ⟶ g) → (map f ⟶ map g)) --- (map_comp : ∀ {a b c : B} (f : a ⟶ b) (g : b ⟶ c), map (f ≫ g) ⟶ map f ≫ map g) {a b c d : B} --- (f : a ⟶ b) (g : b ⟶ c) (h : c ⟶ d) : Prop := ... - /-- An oplax functor `F` between bicategories `B` and `C` consists of a function between objects `F.obj`, a function between 1-morphisms `F.map`, and a function between 2-morphisms `F.map₂`. @@ -60,28 +50,32 @@ of 2-morphisms. -/ structure OplaxFunctor (B : Type u₁) [Bicategory.{w₁, v₁} B] (C : Type u₂) [Bicategory.{w₂, v₂} C] extends PrelaxFunctor B C where + /-- The 2-morphism underlying the oplax unity constraint. -/ mapId (a : B) : map (𝟙 a) ⟶ 𝟙 (obj a) + /-- The 2-morphism underlying the oplax functoriality constraint. -/ mapComp {a b c : B} (f : a ⟶ b) (g : b ⟶ c) : map (f ≫ g) ⟶ map f ≫ map g + /-- Naturality of the oplax functoriality constraint, on the left. -/ mapComp_naturality_left : ∀ {a b c : B} {f f' : a ⟶ b} (η : f ⟶ f') (g : b ⟶ c), map₂ (η ▷ g) ≫ mapComp f' g = mapComp f g ≫ map₂ η ▷ map g := by aesop_cat + /-- Naturality of the lax functoriality constraight, on the right. -/ mapComp_naturality_right : ∀ {a b c : B} (f : a ⟶ b) {g g' : b ⟶ c} (η : g ⟶ g'), map₂ (f ◁ η) ≫ mapComp f g' = mapComp f g ≫ map f ◁ map₂ η := by aesop_cat - -- Porting note: `map₂_associator_aux` was used here in lean 3, but this was a hack - -- to avoid a timeout; we revert this hack here (because it was causing other problems - -- and was not necessary in lean 4) + /-- Oplax associativity. -/ map₂_associator : ∀ {a b c d : B} (f : a ⟶ b) (g : b ⟶ c) (h : c ⟶ d), map₂ (α_ f g h).hom ≫ 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 + /-- Oplax left unity. -/ map₂_leftUnitor : ∀ {a b : B} (f : a ⟶ b), map₂ (λ_ f).hom = mapComp (𝟙 a) f ≫ mapId a ▷ map f ≫ (λ_ (map f)).hom := by aesop_cat + /-- Oplax right unity. -/ map₂_rightUnitor : ∀ {a b : B} (f : a ⟶ b), map₂ (ρ_ f).hom = mapComp f (𝟙 b) ≫ map f ◁ mapId b ≫ (ρ_ (map f)).hom := by @@ -91,49 +85,32 @@ 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 /-- The underlying prelax functor. -/ add_decl_doc OplaxFunctor.toPrelaxFunctor -attribute [nolint docBlame] CategoryTheory.OplaxFunctor.mapId - CategoryTheory.OplaxFunctor.mapComp - CategoryTheory.OplaxFunctor.mapComp_naturality_left - CategoryTheory.OplaxFunctor.mapComp_naturality_right - CategoryTheory.OplaxFunctor.map₂_associator - CategoryTheory.OplaxFunctor.map₂_leftUnitor - CategoryTheory.OplaxFunctor.map₂_rightUnitor - 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 ≫ (α_ (F.map f) (F.map g) (F.map h)).hom := by - rw [← @map₂_associator, ← F.map₂_comp_assoc] + 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 ≫ (α_ (F.map f) (F.map g) (F.map h)).inv := by simp --- Porting note: `to_prelax_eq_coe` and `to_prelaxFunctor_obj` are --- syntactic tautologies in lean 4 - --- Porting note: removed lemma `to_prelaxFunctor_map` relating the now --- nonexistent `PrelaxFunctor.map` and `OplaxFunctor.map` - --- Porting note: removed lemma `to_prelaxFunctor_map₂` relating --- `PrelaxFunctor.map₂` to nonexistent `OplaxFunctor.map₂` - /-- The identity oplax functor. -/ @[simps] def id (B : Type u₁) [Bicategory.{w₁, v₁} B] : OplaxFunctor B B where @@ -161,10 +138,8 @@ def comp (F : OplaxFunctor B C) (G : OplaxFunctor C D) : OplaxFunctor B D where mapComp_naturality_right, assoc] map₂_associator := fun f g h => by dsimp - -- Porting note: if you use the `map₂_associator_aux` hack in the definition of - -- `map₂_associator` then the `simp only` call below does not seem to apply `map₂_associator` 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 @@ -174,27 +149,24 @@ 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. -See `Pseudofunctor.mkOfOplax`. --/ + +See `Pseudofunctor.mkOfOplax`. -/ -- Porting note(#5171): linter not ported yet -- @[nolint has_nonempty_instance] --- Porting note: removing primes in structure name because --- my understanding is that they're no longer needed structure PseudoCore (F : OplaxFunctor B C) where + /-- The isomorphism giving rise to the oplax unity constraint -/ mapIdIso (a : B) : F.map (𝟙 a) ≅ 𝟙 (F.obj a) + /-- The isomorphism giving rise to the oplax functoriality constraint -/ mapCompIso {a b c : B} (f : a ⟶ b) (g : b ⟶ c) : F.map (f ≫ g) ≅ F.map f ≫ F.map g + /-- `mapIdIso` gives rise to the oplax unity constraint -/ mapIdIso_hom : ∀ {a : B}, (mapIdIso a).hom = F.mapId a := by aesop_cat + /-- `mapCompIso` gives rise to the oplax functoriality constraint -/ mapCompIso_hom : ∀ {a b c : B} (f : a ⟶ b) (g : b ⟶ c), (mapCompIso f g).hom = F.mapComp f g := by aesop_cat -attribute [nolint docBlame] CategoryTheory.OplaxFunctor.PseudoCore.mapIdIso - CategoryTheory.OplaxFunctor.PseudoCore.mapCompIso - CategoryTheory.OplaxFunctor.PseudoCore.mapIdIso_hom - CategoryTheory.OplaxFunctor.PseudoCore.mapCompIso_hom - attribute [simp] PseudoCore.mapIdIso_hom PseudoCore.mapCompIso_hom end 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/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/LocallyDiscrete.lean b/Mathlib/CategoryTheory/Bicategory/LocallyDiscrete.lean index 4bce6d2322466..3ddbc22d951aa 100644 --- a/Mathlib/CategoryTheory/Bicategory/LocallyDiscrete.lean +++ b/Mathlib/CategoryTheory/Bicategory/LocallyDiscrete.lean @@ -106,6 +106,9 @@ instance locallyDiscreteBicategory.strict : Strict (LocallyDiscrete C) where 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] /-- diff --git a/Mathlib/CategoryTheory/Bicategory/NaturalTransformation/Oplax.lean b/Mathlib/CategoryTheory/Bicategory/NaturalTransformation/Oplax.lean index 5a1b8b335b237..d6c4159d767cf 100644 --- a/Mathlib/CategoryTheory/Bicategory/NaturalTransformation/Oplax.lean +++ b/Mathlib/CategoryTheory/Bicategory/NaturalTransformation/Oplax.lean @@ -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') : @@ -221,7 +221,7 @@ 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] + simp_rw [← Bicategory.whiskerLeft_comp, naturality] @[reassoc (attr := simp)] theorem whiskerRight_naturality (f : a ⟶ b) (g : G.obj b ⟶ a') : diff --git a/Mathlib/CategoryTheory/Bicategory/NaturalTransformation/Strong.lean b/Mathlib/CategoryTheory/Bicategory/NaturalTransformation/Strong.lean index ae37a41743113..28d84af3a9c06 100644 --- a/Mathlib/CategoryTheory/Bicategory/NaturalTransformation/Strong.lean +++ b/Mathlib/CategoryTheory/Bicategory/NaturalTransformation/Strong.lean @@ -116,7 +116,7 @@ variable (F : OplaxFunctor B C) /-- The identity strong natural transformation. -/ @[simps!] def id : StrongOplaxNatTrans F F := - mkOfOplax (OplaxNatTrans.id F) { naturality := λ f ↦ (ρ_ (F.map f)) ≪≫ (λ_ (F.map f)).symm } + mkOfOplax (OplaxNatTrans.id F) { naturality := fun f ↦ (ρ_ (F.map f)) ≪≫ (λ_ (F.map f)).symm } @[simp] lemma id.toOplax : (id F).toOplax = OplaxNatTrans.id F := @@ -183,7 +183,7 @@ end @[simps!] def vcomp (η : StrongOplaxNatTrans F G) (θ : StrongOplaxNatTrans G H) : StrongOplaxNatTrans F H := mkOfOplax (OplaxNatTrans.vcomp η.toOplax θ.toOplax) - { naturality := λ {a b} f ↦ + { naturality := fun {a b} f ↦ (α_ _ _ _).symm ≪≫ whiskerRightIso (η.naturality f) (θ.app b) ≪≫ (α_ _ _ _) ≪≫ whiskerLeftIso (η.app a) (θ.naturality f) ≪≫ (α_ _ _ _).symm } end diff --git a/Mathlib/CategoryTheory/Bicategory/SingleObj.lean b/Mathlib/CategoryTheory/Bicategory/SingleObj.lean index 7619fce58c22c..73341c73d8e16 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 diff --git a/Mathlib/CategoryTheory/Bicategory/Strict.lean b/Mathlib/CategoryTheory/Bicategory/Strict.lean index 7e0bd006126ab..1edfaa816f646 100644 --- a/Mathlib/CategoryTheory/Bicategory/Strict.lean +++ b/Mathlib/CategoryTheory/Bicategory/Strict.lean @@ -50,15 +50,6 @@ class Bicategory.Strict : Prop where ∀ {a b c d : B} (f : a ⟶ b) (g : b ⟶ c) (h : c ⟶ d), α_ f g h = eqToIso (assoc f g h) := by aesop_cat --- Porting note: not adding simp to: --- Bicategory.Strict.id_comp --- Bicategory.Strict.comp_id --- Bicategory.Strict.assoc -attribute [simp] - Bicategory.Strict.leftUnitor_eqToIso - Bicategory.Strict.rightUnitor_eqToIso - Bicategory.Strict.associator_eqToIso - -- see Note [lower instance priority] /-- Category structure on a strict bicategory -/ instance (priority := 100) StrictBicategory.category [Bicategory.Strict B] : Category B where diff --git a/Mathlib/CategoryTheory/Category/Basic.lean b/Mathlib/CategoryTheory/Category/Basic.lean index 7ec4a03391b45..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 @@ -260,10 +261,18 @@ instance (X : C) : Mono (𝟙 X) := theorem cancel_epi (f : X ⟶ Y) [Epi f] {g h : Y ⟶ Z} : f ≫ g = f ≫ h ↔ g = h := ⟨fun p => Epi.left_cancellation g h p, congr_arg _⟩ +theorem cancel_epi_assoc_iff (f : X ⟶ Y) [Epi f] {g h : Y ⟶ Z} {W : C} {k l : Z ⟶ W} : + (f ≫ g) ≫ k = (f ≫ h) ≫ l ↔ g ≫ k = h ≫ l := + ⟨fun p => (cancel_epi f).1 <| by simpa using p, fun p => by simp only [Category.assoc, p]⟩ + theorem cancel_mono (f : X ⟶ Y) [Mono f] {g h : Z ⟶ X} : g ≫ f = h ≫ f ↔ g = h := -- Porting note: in Lean 3 we could just write `congr_arg _` here. ⟨fun p => Mono.right_cancellation g h p, congr_arg (fun k => k ≫ f)⟩ +theorem cancel_mono_assoc_iff (f : X ⟶ Y) [Mono f] {g h : Z ⟶ X} {W : C} {k l : W ⟶ Z} : + k ≫ (g ≫ f) = l ≫ (h ≫ f) ↔ k ≫ g = l ≫ h := + ⟨fun p => (cancel_mono f).1 <| by simpa using p, fun p => by simp only [← Category.assoc, p]⟩ + theorem cancel_epi_id (f : X ⟶ Y) [Epi f] {h : Y ⟶ Y} : f ≫ h = f ↔ h = 𝟙 Y := by convert cancel_epi f simp @@ -272,40 +281,21 @@ theorem cancel_mono_id (f : X ⟶ Y) [Mono f] {g : X ⟶ X} : g ≫ f = f ↔ g convert cancel_mono f simp -theorem epi_comp {X Y Z : C} (f : X ⟶ Y) [Epi f] (g : Y ⟶ Z) [Epi g] : Epi (f ≫ g) := by - constructor - intro Z a b w - apply (cancel_epi g).1 - apply (cancel_epi f).1 - simpa using w - -theorem mono_comp {X Y Z : C} (f : X ⟶ Y) [Mono f] (g : Y ⟶ Z) [Mono g] : Mono (f ≫ g) := by - constructor - intro Z a b w - apply (cancel_mono f).1 - apply (cancel_mono g).1 - simpa using w - -theorem mono_of_mono {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z) [Mono (f ≫ g)] : Mono f := by - constructor - intro Z a b w - replace w := congr_arg (fun k => k ≫ g) w - dsimp at w - rw [Category.assoc, Category.assoc] at w - exact (cancel_mono _).1 w +instance epi_comp {X Y Z : C} (f : X ⟶ Y) [Epi f] (g : Y ⟶ Z) [Epi g] : Epi (f ≫ g) := + ⟨fun _ _ w => (cancel_epi g).1 <| (cancel_epi_assoc_iff f).1 w⟩ + +instance mono_comp {X Y Z : C} (f : X ⟶ Y) [Mono f] (g : Y ⟶ Z) [Mono g] : Mono (f ≫ g) := + ⟨fun _ _ w => (cancel_mono f).1 <| (cancel_mono_assoc_iff g).1 w⟩ + +theorem mono_of_mono {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z) [Mono (f ≫ g)] : Mono f := + ⟨fun _ _ w => (cancel_mono (f ≫ g)).1 <| by simp only [← Category.assoc, w]⟩ theorem mono_of_mono_fac {X Y Z : C} {f : X ⟶ Y} {g : Y ⟶ Z} {h : X ⟶ Z} [Mono h] (w : f ≫ g = h) : Mono f := by - subst h - exact mono_of_mono f g - -theorem epi_of_epi {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z) [Epi (f ≫ g)] : Epi g := by - constructor - intro Z a b w - replace w := congr_arg (fun k => f ≫ k) w - dsimp at w - rw [← Category.assoc, ← Category.assoc] at w - exact (cancel_epi _).1 w + subst h; exact mono_of_mono f g + +theorem epi_of_epi {X Y Z : C} (f : X ⟶ Y) (g : Y ⟶ Z) [Epi (f ≫ g)] : Epi g := + ⟨fun _ _ w => (cancel_epi (f ≫ g)).1 <| by simp only [Category.assoc, w]⟩ theorem epi_of_epi_fac {X Y Z : C} {f : X ⟶ Y} {g : Y ⟶ Z} {h : X ⟶ Z} [Epi h] (w : f ≫ g = h) : Epi g := by diff --git a/Mathlib/CategoryTheory/Category/Bipointed.lean b/Mathlib/CategoryTheory/Category/Bipointed.lean index ec8c5cb5122de..e85c5549e371d 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. -/ @@ -93,14 +90,11 @@ def swap : Bipointed ⥤ Bipointed where /-- The equivalence between `Bipointed` and itself induced by `Prod.swap` both ways. -/ @[simps!] -def swapEquiv : Bipointed ≌ Bipointed := - CategoryTheory.Equivalence.mk swap swap - (NatIso.ofComponents fun X => - { hom := ⟨id, rfl, rfl⟩ - inv := ⟨id, rfl, rfl⟩ }) - (NatIso.ofComponents fun X => - { hom := ⟨id, rfl, rfl⟩ - inv := ⟨id, rfl, rfl⟩ }) +def swapEquiv : Bipointed ≌ Bipointed where + functor := swap + inverse := swap + unitIso := Iso.refl _ + counitIso := Iso.refl _ @[simp] theorem swapEquiv_symm : swapEquiv.symm = swapEquiv := diff --git a/Mathlib/CategoryTheory/Category/Cat.lean b/Mathlib/CategoryTheory/Category/Cat.lean index 480b844a54dda..9838804baf16f 100644 --- a/Mathlib/CategoryTheory/Category/Cat.lean +++ b/Mathlib/CategoryTheory/Category/Cat.lean @@ -74,6 +74,10 @@ instance bicategory.strict : Bicategory.Strict Cat.{v, u} where instance category : LargeCategory.{max v u} Cat.{v, u} := StrictBicategory.category Cat.{v, u} +@[simp] +theorem id_obj {C : Cat} (X : C) : (𝟙 C : C ⥤ C).obj X = X := + rfl + @[simp] theorem id_map {C : Cat} {X Y : C} (f : X ⟶ Y) : (𝟙 C : C ⥤ C).map f = f := rfl @@ -87,6 +91,13 @@ theorem comp_map {C D E : Cat} (F : C ⟶ D) (G : D ⟶ E) {X Y : C} (f : X ⟶ (F ≫ G).map f = G.map (F.map f) := rfl +@[simp] +theorem id_app {C D : Cat} (F : C ⟶ D) (X : C) : (𝟙 F : F ⟶ F).app X = 𝟙 (F.obj X) := rfl + +@[simp] +theorem comp_app {C D : Cat} {F G H : C ⟶ D} (α : F ⟶ G) (β : G ⟶ H) (X : C) : + (α ≫ β).app X = α.app X ≫ β.app X := rfl + @[simp] lemma whiskerLeft_app {C D E : Cat} (F : C ⟶ D) {G H : D ⟶ E} (η : G ⟶ H) (X : C) : (F ◁ η).app X = η.app (F.obj X) := @@ -97,6 +108,11 @@ lemma whiskerRight_app {C D E : Cat} {F G : C ⟶ D} (H : D ⟶ E) (η : F ⟶ G (η ▷ H).app X = H.map (η.app X) := rfl +@[simp] +theorem eqToHom_app {C D : Cat} (F G : C ⟶ D) (h : F = G) (X : C) : + (eqToHom h).app X = eqToHom (Functor.congr_obj h X) := + CategoryTheory.eqToHom_app h X + lemma leftUnitor_hom_app {B C : Cat} (F : B ⟶ C) (X : B) : (λ_ F).hom.app X = eqToHom (by simp) := rfl @@ -117,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 8d930249e4120..229d0fbddea78 100644 --- a/Mathlib/CategoryTheory/Category/Cat/Adjunction.lean +++ b/Mathlib/CategoryTheory/Category/Cat/Adjunction.lean @@ -39,35 +39,39 @@ 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 obj C := ConnectedComponents C - map F := - Quotient.lift (Quotient.mk (Zigzag.setoid _) ∘ F.obj) - (fun _ _ ↦ Quot.sound ∘ zigzag_obj_of_zigzag F) - map_id _ := funext fun x ↦ (Quotient.exists_rep x).elim (fun _ h ↦ by simp [<- h]; rfl) - map_comp _ _ := funext fun x ↦ (Quotient.exists_rep x).elim (fun _ h => by simp [<- h]) + map F := Functor.mapConnectedComponents F + map_id _ := funext fun x ↦ (Quotient.exists_rep x).elim (fun _ h ↦ by subst h; rfl) + 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..8fb276edac4be 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 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/Init.lean b/Mathlib/CategoryTheory/Category/Init.lean index bb562ef63fef7..9c42b8ce10881 100644 --- a/Mathlib/CategoryTheory/Category/Init.lean +++ b/Mathlib/CategoryTheory/Category/Init.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jannis Limperg -/ +import Mathlib.Init import Aesop /-! diff --git a/Mathlib/CategoryTheory/Category/Pairwise.lean b/Mathlib/CategoryTheory/Category/Pairwise.lean index ec1161abbddc2..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 @@ -109,15 +109,11 @@ def diagramMap : ∀ {o₁ o₂ : Pairwise ι} (_ : o₁ ⟶ o₂), diagramObj U | _, _, left _ _ => homOfLE inf_le_left | _, _, right _ _ => homOfLE inf_le_right --- Porting note: the fields map_id and map_comp were filled by hand, as generating them by `aesop` --- causes a PANIC. /-- Given a function `U : ι → α` for `[SemilatticeInf α]`, we obtain a functor `Pairwise ι ⥤ α`, sending `single i` to `U i` and `pair i j` to `U i ⊓ U j`, and the morphisms to the obvious inequalities. -/ --- Porting note: We want `@[simps]` here, but this causes a PANIC in the linter. --- (Which, worryingly, does not cause a linter failure!) --- @[simps] +@[simps] def diagram : Pairwise ι ⥤ α where obj := diagramObj U map := diagramMap U diff --git a/Mathlib/CategoryTheory/Category/PartialFun.lean b/Mathlib/CategoryTheory/Category/PartialFun.lean index b0c1ab026a13c..b448e2cf2a62f 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* @@ -46,8 +44,6 @@ instance : CoeSort PartialFun Type* := def of : Type* → PartialFun := id --- Porting note: removed this lemma which is useless because of the expansion of coercions - instance : Inhabited PartialFun := ⟨Type*⟩ @@ -82,6 +78,7 @@ def typeToPartialFun : Type u ⥤ PartialFun where instance : typeToPartialFun.Faithful where map_injective {_ _} := PFun.lift_injective +-- b ∈ PFun.toSubtype (fun x ↦ x ≠ X.point) Subtype.val a ↔ b ∈ Part.some a /-- The functor which deletes the point of a pointed type. In return, this makes the maps partial. This is the computable part of the equivalence `PartialFunEquivPointed`. -/ @[simps obj map] @@ -89,7 +86,8 @@ 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 => PFun.mem_toSubtype_iff.trans (Subtype.coe_inj.trans Part.mem_some_iff.symm) + PFun.ext fun a 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 apply PFun.ext _ @@ -119,9 +117,10 @@ noncomputable def partialFunToPointed : PartialFun ⥤ Pointed := by /-- The equivalence induced by `PartialFunToPointed` and `PointedToPartialFun`. `Part.equivOption` made functorial. -/ @[simps!] -noncomputable def partialFunEquivPointed : PartialFun.{u} ≌ Pointed := - CategoryTheory.Equivalence.mk partialFunToPointed pointedToPartialFun - (NatIso.ofComponents (fun X => PartialFun.Iso.mk +noncomputable def partialFunEquivPointed : PartialFun.{u} ≌ Pointed where + functor := partialFunToPointed + inverse := pointedToPartialFun + 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 _ _ @@ -145,13 +144,19 @@ noncomputable def partialFunEquivPointed : PartialFun.{u} ≌ Pointed := · intro h split_ifs at h with ha rw [some_inj] at h - exact ⟨b, ⟨ha, h.symm⟩, rfl⟩) $ + exact ⟨b, ⟨ha, h.symm⟩, rfl⟩ + counitIso := NatIso.ofComponents (fun X ↦ Pointed.Iso.mk (by classical exact Equiv.optionSubtypeNe X.point) (by rfl)) fun {X Y} f ↦ Pointed.Hom.ext <| funext fun a ↦ by obtain _ | ⟨a, ha⟩ := a · exact f.map_point.symm simp_all [Option.casesOn'_eq_elim, Part.elim_toOption] + functor_unitIso_comp X := by + ext (_ | x) + · rfl + · simp + rfl /-- Forgetting that maps are total and making them total again by adding a point is the same as just adding a point. -/ diff --git a/Mathlib/CategoryTheory/Category/Pointed.lean b/Mathlib/CategoryTheory/Category/Pointed.lean index a1f720281f992..8e963c0fc6da9 100644 --- a/Mathlib/CategoryTheory/Category/Pointed.lean +++ b/Mathlib/CategoryTheory/Category/Pointed.lean @@ -22,8 +22,6 @@ open CategoryTheory universe u -variable {α β : Type*} - /-- The category of pointed types. -/ structure Pointed : Type (u + 1) where /-- the underlying type -/ diff --git a/Mathlib/CategoryTheory/Category/Preorder.lean b/Mathlib/CategoryTheory/Category/Preorder.lean index e1c432d48fc49..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 @@ -85,14 +85,7 @@ theorem leOfHom {x y : X} (h : x ⟶ y) : x ≤ y := @[nolint defLemma, inherit_doc leOfHom] abbrev _root_.Quiver.Hom.le := @leOfHom --- Porting note: why does this lemma exist? With proof irrelevance, we don't need to simplify proofs --- @[simp] -theorem leOfHom_homOfLE {x y : X} (h : x ≤ y) : h.hom.le = h := - rfl - --- Porting note: linter gives: "Left-hand side does not simplify, when using the simp lemma on --- itself. This usually means that it will never apply." removing simp? It doesn't fire --- @[simp] +@[simp] theorem homOfLE_leOfHom {x y : X} (h : x ⟶ y) : h.le.hom = h := rfl diff --git a/Mathlib/CategoryTheory/Category/Quiv.lean b/Mathlib/CategoryTheory/Category/Quiv.lean index 40f840da97067..be83ad9b038c2 100644 --- a/Mathlib/CategoryTheory/Category/Quiv.lean +++ b/Mathlib/CategoryTheory/Category/Quiv.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.Adjunction.Basic import Mathlib.CategoryTheory.Category.Cat @@ -11,10 +11,8 @@ import Mathlib.CategoryTheory.PathCategory # 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 b505cec20e646..7136d606db093 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 @@ -27,7 +27,7 @@ universe u -- This file is about Lean 3 declaration "Rel". -/-- A type synonym for `Type`, which carries the category instance for which +/-- A type synonym for `Type u`, which carries the category instance for which morphisms are binary relations. -/ def RelCat := Type u @@ -83,9 +83,9 @@ instance graphFunctor_essSurj : graphFunctor.EssSurj := graphFunctor.essSurj_of_surj Function.surjective_id /-- A relation is an isomorphism in `RelCat` iff it is the image of an isomorphism in -`Type`. -/ +`Type u`. -/ theorem rel_iso_iff {X Y : RelCat} (r : X ⟶ Y) : - IsIso (C := RelCat) r ↔ ∃ f : (Iso (C := Type) X Y), graphFunctor.map f.hom = r := by + IsIso (C := RelCat) r ↔ ∃ f : (Iso (C := Type u) X Y), graphFunctor.map f.hom = r := by constructor · intro h have h1 := congr_fun₂ h.hom_inv_id @@ -93,7 +93,7 @@ theorem rel_iso_iff {X Y : RelCat} (r : X ⟶ Y) : simp only [RelCat.Hom.rel_comp_apply₂, RelCat.Hom.rel_id_apply₂, eq_iff_iff] at h1 h2 obtain ⟨f, hf⟩ := Classical.axiomOfChoice (fun a => (h1 a a).mpr rfl) obtain ⟨g, hg⟩ := Classical.axiomOfChoice (fun a => (h2 a a).mpr rfl) - suffices hif : IsIso (C := Type) f by + suffices hif : IsIso (C := Type u) f by use asIso f ext x y simp only [asIso_hom, graphFunctor_map] diff --git a/Mathlib/CategoryTheory/Category/TwoP.lean b/Mathlib/CategoryTheory/Category/TwoP.lean index a866c977c18f0..9a4f129f06e4e 100644 --- a/Mathlib/CategoryTheory/Category/TwoP.lean +++ b/Mathlib/CategoryTheory/Category/TwoP.lean @@ -77,14 +77,11 @@ noncomputable def swap : TwoP ⥤ TwoP where /-- The equivalence between `TwoP` and itself induced by `Prod.swap` both ways. -/ @[simps!] -noncomputable def swapEquiv : TwoP ≌ TwoP := - CategoryTheory.Equivalence.mk swap swap - (NatIso.ofComponents fun X => - { hom := ⟨id, rfl, rfl⟩ - inv := ⟨id, rfl, rfl⟩ }) - (NatIso.ofComponents fun X => - { hom := ⟨id, rfl, rfl⟩ - inv := ⟨id, rfl, rfl⟩ }) +noncomputable def swapEquiv : TwoP ≌ TwoP where + functor := swap + inverse := swap + unitIso := Iso.refl _ + counitIso := Iso.refl _ @[simp] theorem swapEquiv_symm : swapEquiv.symm = swapEquiv := diff --git a/Mathlib/CategoryTheory/ChosenFiniteProducts.lean b/Mathlib/CategoryTheory/ChosenFiniteProducts.lean index 94e7ecaf158cf..7ae5f97b5511b 100644 --- a/Mathlib/CategoryTheory/ChosenFiniteProducts.lean +++ b/Mathlib/CategoryTheory/ChosenFiniteProducts.lean @@ -103,6 +103,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 _ _) diff --git a/Mathlib/CategoryTheory/ChosenFiniteProducts/Cat.lean b/Mathlib/CategoryTheory/ChosenFiniteProducts/Cat.lean new file mode 100644 index 0000000000000..b78443a4100e4 --- /dev/null +++ b/Mathlib/CategoryTheory/ChosenFiniteProducts/Cat.lean @@ -0,0 +1,98 @@ +/- +Copyright (c) 2024 Nicolas Rolland. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Nicolas Rolland +-/ +import Mathlib.CategoryTheory.ChosenFiniteProducts +/-! +# Chosen finite products in `Cat` + +This file proves that the cartesian product of a pair of categories agrees with the +product in `Cat`, and provides the associated `ChosenFiniteProducts` instance. +-/ + +universe v u + +namespace CategoryTheory + +namespace Cat + +open Limits + +/-- The chosen terminal object in `Cat`. -/ +abbrev chosenTerminal : Cat := Cat.of (ULift (ULiftHom (Discrete Unit))) + +/-- The chosen terminal object in `Cat` is terminal. -/ +def chosenTerminalIsTerminal : IsTerminal chosenTerminal := + IsTerminal.ofUniqueHom (fun _ ↦ (Functor.const _).obj ⟨⟨⟨⟩⟩⟩) fun _ _ ↦ rfl + +/-- The chosen product of categories `C × D` yields a product cone in `Cat`. -/ +def prodCone (C D : Cat.{v,u}) : BinaryFan C D := + .mk (P := .of (C × D)) (Prod.fst _ _) (Prod.snd _ _) + +/-- The product cone in `Cat` is indeed a product. -/ +def isLimitProdCone (X Y : Cat) : IsLimit (prodCone X Y) := BinaryFan.isLimitMk + (fun S => S.fst.prod' S.snd) (fun _ => rfl) (fun _ => rfl) (fun _ _ h1 h2 => + Functor.hext + (fun _ ↦ Prod.ext (by simp [← h1]) (by simp [← h2])) + (fun _ _ _ ↦ by dsimp; rw [← h1, ← h2]; rfl)) + +instance : ChosenFiniteProducts Cat where + product (X Y : Cat) := { isLimit := isLimitProdCone X Y } + terminal := { isLimit := chosenTerminalIsTerminal } + +/-- A monoidal instance for Cat is provided through monoidalOfChosenFiniteProducts -/ +example : MonoidalCategory Cat := by infer_instance + +/-- A symmetric monoidal instance for Cat is provided through symmetricOfChosenFiniteProducts -/ +example : SymmetricCategory Cat := by infer_instance + +end Cat + +namespace Monoidal + +open MonoidalCategory + +lemma tensorObj (C : Cat) (D : Cat) : C ⊗ D = Cat.of (C × D) := rfl + +lemma whiskerLeft (X : Cat) {A : Cat} {B : Cat} (f : A ⟶ B) : + X ◁ f = (𝟭 X).prod f := rfl + +lemma whiskerLeft_fst (X : Cat) {A : Cat} {B : Cat} (f : A ⟶ B) : + (X ◁ f) ⋙ Prod.fst _ _ = Prod.fst _ _ := rfl + +lemma whiskerLeft_snd (X : Cat) {A : Cat} {B : Cat} (f : A ⟶ B) : + (X ◁ f) ⋙ Prod.snd _ _ = Prod.snd _ _ ⋙ f := rfl + +lemma whiskerRight {A : Cat} {B : Cat} (f : A ⟶ B) (X : Cat) : + f ▷ X = f.prod (𝟭 X) := rfl + +lemma whiskerRight_fst {A : Cat} {B : Cat} (f : A ⟶ B) (X : Cat) : + (f ▷ X) ⋙ Prod.fst _ _ = Prod.fst _ _ ⋙ f := rfl + +lemma whiskerRight_snd {A : Cat} {B : Cat} (f : A ⟶ B) (X : Cat) : + (f ▷ X) ⋙ Prod.snd _ _ = Prod.snd _ _ := rfl + +lemma tensorHom {A : Cat} {B : Cat} (f : A ⟶ B) {X : Cat} {Y : Cat} (g : X ⟶ Y) : + f ⊗ g = f.prod g := rfl + +lemma tensorUnit : 𝟙_ Cat = Cat.chosenTerminal := rfl + +lemma associator_hom (X : Cat) (Y : Cat) (Z : Cat) : + (associator X Y Z).hom = Functor.prod' (Prod.fst (X × Y) Z ⋙ Prod.fst X Y) + ((Functor.prod' ((Prod.fst (X × Y) Z ⋙ Prod.snd X Y)) + (Prod.snd (X × Y) Z : (X × Y) × Z ⥤ Z))) := rfl + +lemma associator_inv (X : Cat) (Y : Cat) (Z : Cat) : + (associator X Y Z).inv = Functor.prod' (Functor.prod' (Prod.fst X (Y × Z) : X × (Y × Z) ⥤ X) + (Prod.snd X (Y × Z) ⋙ Prod.fst Y Z)) (Prod.snd X (Y × Z) ⋙ Prod.snd Y Z) := rfl + +lemma leftUnitor_hom (C : Cat) : (λ_ C).hom = Prod.snd _ _ := rfl + +lemma leftUnitor_inv (C : Cat) : (λ_ C).inv = Prod.sectr ⟨⟨⟨⟩⟩⟩ _ := rfl + +lemma rightUnitor_hom (C : Cat) : (ρ_ C).hom = Prod.fst _ _ := rfl + +lemma rightUnitor_inv (C : Cat) : (ρ_ C).inv = Prod.sectl _ ⟨⟨⟨⟩⟩⟩ := rfl + +end CategoryTheory.Monoidal diff --git a/Mathlib/CategoryTheory/ChosenFiniteProducts/FunctorCategory.lean b/Mathlib/CategoryTheory/ChosenFiniteProducts/FunctorCategory.lean index e50ed06042114..c95c9da1f310e 100644 --- a/Mathlib/CategoryTheory/ChosenFiniteProducts/FunctorCategory.lean +++ b/Mathlib/CategoryTheory/ChosenFiniteProducts/FunctorCategory.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Joël Riou -/ import Mathlib.CategoryTheory.ChosenFiniteProducts -import Mathlib.CategoryTheory.Limits.FunctorCategory +import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic /-! # Functor categories have chosen finite products diff --git a/Mathlib/CategoryTheory/Closed/Cartesian.lean b/Mathlib/CategoryTheory/Closed/Cartesian.lean index 4253d1f338112..e25efebbe63d0 100644 --- a/Mathlib/CategoryTheory/Closed/Cartesian.lean +++ b/Mathlib/CategoryTheory/Closed/Cartesian.lean @@ -31,7 +31,7 @@ for closed monoidal categories, and these could be generalised. -/ -universe v u u₂ +universe v v₂ u u₂ noncomputable section @@ -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 := @@ -308,7 +302,7 @@ def powZero {I : C} (t : IsInitial I) [CartesianClosed C] : I ⟹ B ≅ ⊤_ C w rw [← curry_natural_left, curry_eq_iff, ← cancel_epi (mulZero t).inv] apply t.hom_ext --- TODO: Generalise the below to its commutated variants. +-- TODO: Generalise the below to its commuted variants. -- TODO: Define a distributive category, so that zero_mul and friends can be derived from this. /-- In a CCC with binary coproducts, the distribution morphism is an isomorphism. -/ def prodCoprodDistrib [HasBinaryCoproducts C] [CartesianClosed C] (X Y Z : C) : @@ -335,8 +329,9 @@ This actually shows a slightly stronger version: any morphism to an initial obje exponentiable object is an isomorphism. -/ theorem strict_initial {I : C} (t : IsInitial I) (f : A ⟶ I) : IsIso f := by - haveI : Mono (prod.lift (𝟙 A) f ≫ (zeroMul t).hom) := mono_comp _ _ - rw [zeroMul_hom, prod.lift_snd] at this + haveI : Mono f := by + rw [← prod.lift_snd (𝟙 A) f, ← zeroMul_hom t] + exact mono_comp _ _ haveI : IsSplitEpi f := IsSplitEpi.mk' ⟨t.to _, t.hom_ext _ _⟩ apply isIso_of_mono_of_isSplitEpi @@ -353,7 +348,7 @@ theorem initial_mono {I : C} (B : C) (t : IsInitial I) [CartesianClosed C] : Mon instance Initial.mono_to [HasInitial C] (B : C) [CartesianClosed C] : Mono (initial.to B) := initial_mono B initialIsInitial -variable {D : Type u₂} [Category.{v} D] +variable {D : Type u₂} [Category.{v₂} D] section Functor diff --git a/Mathlib/CategoryTheory/Closed/FunctorCategory.lean b/Mathlib/CategoryTheory/Closed/FunctorCategory.lean index 49176e1f107a3..a304a8071b6d1 100644 --- a/Mathlib/CategoryTheory/Closed/FunctorCategory.lean +++ b/Mathlib/CategoryTheory/Closed/FunctorCategory.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..da5c0efda1a01 100644 --- a/Mathlib/CategoryTheory/Closed/Ideal.lean +++ b/Mathlib/CategoryTheory/Closed/Ideal.lean @@ -202,7 +202,7 @@ 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.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 · rw [Limits.prod.map_fst, assoc, assoc, prodComparison_fst, ← i.map_comp, prodComparison_fst] @@ -217,9 +217,9 @@ 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] + 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..43af4d461c0de 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,8 +291,17 @@ 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 end MonoidalClosed diff --git a/Mathlib/CategoryTheory/Closed/Types.lean b/Mathlib/CategoryTheory/Closed/Types.lean index 3a05fc2cb4c52..503e71b9441cf 100644 --- a/Mathlib/CategoryTheory/Closed/Types.lean +++ b/Mathlib/CategoryTheory/Closed/Types.lean @@ -32,27 +32,17 @@ 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 Z xf => xf.2 xf.1 } instance (X : Type v₁) : (Types.binaryProductFunctor.obj X).IsLeftAdjoint := ⟨_, ⟨Types.binaryProductAdjunction X⟩⟩ --- Porting note: this instance should be moved to a higher file. -instance : HasFiniteProducts (Type v₁) := - hasFiniteProducts_of_hasProducts.{v₁} _ - instance : CartesianClosed (Type v₁) := CartesianClosed.mk _ (fun X => Exponentiable.mk _ _ ((Types.binaryProductAdjunction X).ofNatIsoLeft (Types.binaryProductIsoProd.app X))) --- Porting note: in mathlib3, the assertion was for `(C ⥤ Type u₁)`, but then Lean4 was --- confused with universes. It makes no harm to relax the universe assumptions here. -instance {C : Type u₁} [Category.{v₁} C] : HasFiniteProducts (C ⥤ Type u₂) := - hasFiniteProducts_of_hasProducts _ - instance {C : Type v₁} [SmallCategory C] : CartesianClosed (C ⥤ Type v₁) := CartesianClosed.mk _ (fun F => by @@ -60,6 +50,31 @@ instance {C : Type v₁} [SmallCategory C] : CartesianClosed (C ⥤ Type v₁) : have := Presheaf.isLeftAdjoint_of_preservesColimits (prod.functor.obj F) exact Exponentiable.mk _ _ (Adjunction.ofIsLeftAdjoint (prod.functor.obj F))) +-- TODO: once we have `MonoidalClosed` instances for functor categories into general monoidal +-- closed categories, replace this with that, as it will be a more explicit construction. +/-- This is not a good instance because of the universe levels. Below is the instance where the +target category is `Type (max u₁ v₁)`. -/ +def cartesianClosedFunctorToTypes {C : Type u₁} [Category.{v₁} C] : + CartesianClosed (C ⥤ Type (max u₁ v₁ u₂)) := + let e : (ULiftHom.{max u₁ v₁ u₂} (ULift.{max u₁ v₁ u₂} C)) ⥤ Type (max u₁ v₁ u₂) ≌ + C ⥤ Type (max u₁ v₁ u₂) := + Functor.asEquivalence ((whiskeringLeft _ _ _).obj + (ULift.equivalence.trans ULiftHom.equiv).functor) + cartesianClosedOfEquiv e + +-- TODO: once we have `MonoidalClosed` instances for functor categories into general monoidal +-- closed categories, replace this with that, as it will be a more explicit construction. +instance {C : Type u₁} [Category.{v₁} C] : CartesianClosed (C ⥤ Type (max u₁ v₁)) := + cartesianClosedFunctorToTypes + +-- TODO: once we have `MonoidalClosed` instances for functor categories into general monoidal +-- closed categories, replace this with that, as it will be a more explicit construction. +instance {C : Type u₁} [Category.{v₁} C] [EssentiallySmall.{v₁} C] : + CartesianClosed (C ⥤ Type v₁) := + let e : (SmallModel C) ⥤ Type v₁ ≌ C ⥤ Type v₁ := + Functor.asEquivalence ((whiskeringLeft _ _ _).obj (equivSmallModel _).functor) + cartesianClosedOfEquiv e + end CartesianClosed end diff --git a/Mathlib/CategoryTheory/Closed/Zero.lean b/Mathlib/CategoryTheory/Closed/Zero.lean index 4c6d8edac4a37..459ba941f8d89 100644 --- a/Mathlib/CategoryTheory/Closed/Zero.lean +++ b/Mathlib/CategoryTheory/Closed/Zero.lean @@ -54,13 +54,14 @@ attribute [local instance] uniqueHomsetOfZero /-- A cartesian closed category with a zero object is equivalent to the category with one object and one morphism. -/ -def equivPUnit [HasZeroObject C] : C ≌ Discrete PUnit.{w + 1} := - Equivalence.mk (Functor.star C) (Functor.fromPUnit 0) - (NatIso.ofComponents +def equivPUnit [HasZeroObject C] : C ≌ Discrete PUnit.{w + 1} where + functor := Functor.star C + inverse := Functor.fromPUnit 0 + unitIso := NatIso.ofComponents (fun X => { hom := default inv := default }) - fun f => Subsingleton.elim _ _) - (Functor.punitExt _ _) + fun f => Subsingleton.elim _ _ + counitIso := Functor.punitExt _ _ end CategoryTheory diff --git a/Mathlib/CategoryTheory/CofilteredSystem.lean b/Mathlib/CategoryTheory/CofilteredSystem.lean index eb69db1cc53a2..2424d1f7ae761 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 @@ -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..f40df65859a4d 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 diff --git a/Mathlib/CategoryTheory/Comma/Arrow.lean b/Mathlib/CategoryTheory/Comma/Arrow.lean index 1f396ae0ab27c..9ab800f7f7cc4 100644 --- a/Mathlib/CategoryTheory/Comma/Arrow.lean +++ b/Mathlib/CategoryTheory/Comma/Arrow.lean @@ -34,7 +34,7 @@ variable (T) def Arrow := Comma.{v, v, v} (𝟭 T) (𝟭 T) -/- Porting note: could not derive `Category` above so this instance works in its place-/ +/- Porting note: could not derive `Category` above so this instance works in its place -/ instance : Category (Arrow T) := commaCategory -- Satisfying the inhabited linter @@ -152,7 +152,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 := diff --git a/Mathlib/CategoryTheory/Comma/Basic.lean b/Mathlib/CategoryTheory/Comma/Basic.lean index 23c4e18177717..c88e7997a1eeb 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 @@ -60,7 +60,7 @@ variable {B' : Type u₅} [Category.{v₅} B'] variable {T' : Type u₆} [Category.{v₆} T'] /-- The objects of the comma category are triples of an object `left : A`, an object - `right : B` and a morphism `hom : L.obj left ⟶ R.obj right`. -/ + `right : B` and a morphism `hom : L.obj left ⟶ R.obj right`. -/ structure Comma (L : A ⥤ T) (R : B ⥤ T) : Type max u₁ u₂ v₃ where left : A right : B @@ -313,10 +313,11 @@ def mapLeftEq (l l' : L₁ ⟶ L₂) (h : l = l') : mapLeft R l ≅ mapLeft R l' /-- A natural isomorphism `L₁ ≅ L₂` induces an equivalence of categories `Comma L₁ R ≌ Comma L₂ R`. -/ @[simps!] -def mapLeftIso (i : L₁ ≅ L₂) : Comma L₁ R ≌ Comma L₂ R := - Equivalence.mk (mapLeft _ i.inv) (mapLeft _ i.hom) - ((mapLeftId _ _).symm ≪≫ mapLeftEq _ _ _ i.hom_inv_id.symm ≪≫ mapLeftComp _ _ _) - ((mapLeftComp _ _ _).symm ≪≫ mapLeftEq _ _ _ i.inv_hom_id ≪≫ mapLeftId _ _) +def mapLeftIso (i : L₁ ≅ L₂) : Comma L₁ R ≌ Comma L₂ R where + functor := mapLeft _ i.inv + inverse := mapLeft _ i.hom + unitIso := (mapLeftId _ _).symm ≪≫ mapLeftEq _ _ _ i.hom_inv_id.symm ≪≫ mapLeftComp _ _ _ + counitIso := (mapLeftComp _ _ _).symm ≪≫ mapLeftEq _ _ _ i.inv_hom_id ≪≫ mapLeftId _ _ /-- A natural transformation `R₁ ⟶ R₂` induces a functor `Comma L R₁ ⥤ Comma L R₂`. -/ @[simps] @@ -352,10 +353,11 @@ def mapRightEq (r r' : R₁ ⟶ R₂) (h : r = r') : mapRight L r ≅ mapRight L /-- A natural isomorphism `R₁ ≅ R₂` induces an equivalence of categories `Comma L R₁ ≌ Comma L R₂`. -/ @[simps!] -def mapRightIso (i : R₁ ≅ R₂) : Comma L R₁ ≌ Comma L R₂ := - Equivalence.mk (mapRight _ i.hom) (mapRight _ i.inv) - ((mapRightId _ _).symm ≪≫ mapRightEq _ _ _ i.hom_inv_id.symm ≪≫ mapRightComp _ _ _) - ((mapRightComp _ _ _).symm ≪≫ mapRightEq _ _ _ i.inv_hom_id ≪≫ mapRightId _ _) +def mapRightIso (i : R₁ ≅ R₂) : Comma L R₁ ≌ Comma L R₂ where + functor := mapRight _ i.hom + inverse := mapRight _ i.inv + unitIso := (mapRightId _ _).symm ≪≫ mapRightEq _ _ _ i.hom_inv_id.symm ≪≫ mapRightComp _ _ _ + counitIso := (mapRightComp _ _ _).symm ≪≫ mapRightEq _ _ _ i.inv_hom_id ≪≫ mapRightId _ _ end @@ -453,10 +455,11 @@ def fromProd (L : A ⥤ Discrete PUnit) (R : B ⥤ Discrete PUnit) : is equivalent to their product. -/ @[simps!] def equivProd (L : A ⥤ Discrete PUnit) (R : B ⥤ Discrete PUnit) : - Comma L R ≌ A × B := - Equivalence.mk ((fst L R).prod' (snd L R)) (fromProd L R) - { hom := 𝟙 _, inv := 𝟙 _ } - { hom := 𝟙 _, inv := 𝟙 _ } + Comma L R ≌ A × B where + functor := (fst L R).prod' (snd L R) + inverse := fromProd L R + unitIso := Iso.refl _ + counitIso := Iso.refl _ /-- Taking the comma category of a functor into `A ⥤ Discrete PUnit` and the identity `Discrete PUnit ⥤ Discrete PUnit` results in a category equivalent to `A`. -/ diff --git a/Mathlib/CategoryTheory/Comma/Over.lean b/Mathlib/CategoryTheory/Comma/Over.lean index a1d85c11217fa..12c572b50df5c 100644 --- a/Mathlib/CategoryTheory/Comma/Over.lean +++ b/Mathlib/CategoryTheory/Comma/Over.lean @@ -29,6 +29,7 @@ universe v₁ v₂ u₁ u₂ -- morphism levels before object levels. See note [CategoryTheory universes]. variable {T : Type u₁} [Category.{v₁} T] +variable {D : Type u₂} [Category.{v₂} D] /-- The over category has as objects arrows in `T` with codomain `X` and as morphisms commutative triangles. @@ -65,7 +66,7 @@ theorem over_right (U : Over X) : U.right = ⟨⟨⟩⟩ := by simp only 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 @@ -311,10 +312,6 @@ theorem iteratedSliceBackward_forget_forget : end IteratedSlice -section - -variable {D : Type u₂} [Category.{v₂} D] - /-- A functor `F : T ⥤ D` induces a functor `Over X ⥤ Over (F.obj X)` in the obvious way. -/ @[simps] def post (F : T ⥤ D) : Over X ⥤ Over (F.obj X) where @@ -322,14 +319,10 @@ def post (F : T ⥤ D) : Over X ⥤ Over (F.obj X) where map f := Over.homMk (F.map f.left) (by simp only [Functor.id_obj, mk_left, Functor.const_obj_obj, mk_hom, ← F.map_comp, w]) -end - end Over namespace CostructuredArrow -variable {D : Type u₂} [Category.{v₂} D] - /-- Reinterpreting an `F`-costructured arrow `F.obj d ⟶ X` as an arrow over `X` induces a functor `CostructuredArrow F X ⥤ Over X`. -/ @[simps!] @@ -572,10 +565,6 @@ instance epi_right_of_epi {f g : Under X} (k : f ⟶ g) [Epi k] : Epi k.right := suffices l' = (homMk m : g ⟶ mk (g.hom ≫ m)) by apply congrArg CommaMorphism.right this rw [← cancel_epi k]; ext; apply a -section - -variable {D : Type u₂} [Category.{v₂} D] - /-- A functor `F : T ⥤ D` induces a functor `Under X ⥤ Under (F.obj X)` in the obvious way. -/ @[simps] def post {X : T} (F : T ⥤ D) : Under X ⥤ Under (F.obj X) where @@ -583,8 +572,6 @@ def post {X : T} (F : T ⥤ D) : Under X ⥤ Under (F.obj X) where map f := Under.homMk (F.map f.right) (by simp only [Functor.id_obj, Functor.const_obj_obj, mk_right, mk_hom, ← F.map_comp, w]) -end - end Under namespace StructuredArrow @@ -638,7 +625,7 @@ lemma toOver_comp_forget (F : S ⥤ T) (X : T) (f : (Y : S) → F.obj Y ⟶ X) /-- Given `X : T`, to upgrade a functor `F : S ⥤ T` to a functor `S ⥤ Under X`, it suffices to provide maps `X ⟶ F.obj Y` for all `Y` making the obvious triangles involving all `F.map g` - commute. -/ + commute. -/ @[simps! obj_right map_right] def toUnder (F : S ⥤ T) (X : T) (f : (Y : S) → X ⟶ F.obj Y) (h : ∀ {Y Z : S} (g : Y ⟶ Z), f Y ≫ F.map g = f Z) : S ⥤ Under X := @@ -657,4 +644,136 @@ lemma toUnder_comp_forget (F : S ⥤ T) (X : T) (f : (Y : S) → X ⟶ F.obj Y) end Functor +namespace StructuredArrow + +/-- A functor from the structured arrow category on the projection functor for any structured +arrow category. -/ +@[simps!] +def ofStructuredArrowProjEquivalence.functor (F : D ⥤ T) (Y : T) (X : D) : + StructuredArrow X (StructuredArrow.proj Y F) ⥤ StructuredArrow Y (Under.forget X ⋙ F) := + Functor.toStructuredArrow + (Functor.toUnder (StructuredArrow.proj X _ ⋙ StructuredArrow.proj Y _) _ + (fun g => by exact g.hom) (fun m => by have := m.w; aesop_cat)) _ _ + (fun f => f.right.hom) (by simp) + +/-- The inverse functor of `ofStructuredArrowProjEquivalence.functor`. -/ +@[simps!] +def ofStructuredArrowProjEquivalence.inverse (F : D ⥤ T) (Y : T) (X : D) : + StructuredArrow Y (Under.forget X ⋙ F) ⥤ StructuredArrow X (StructuredArrow.proj Y F) := + Functor.toStructuredArrow + (Functor.toStructuredArrow (StructuredArrow.proj Y _ ⋙ Under.forget X) _ _ + (fun g => by exact g.hom) (fun m => by have := m.w; aesop_cat)) _ _ + (fun f => f.right.hom) (by simp) + +/-- Characterization of the structured arrow category on the projection functor of any +structured arrow category. -/ +def ofStructuredArrowProjEquivalence (F : D ⥤ T) (Y : T) (X : D) : + StructuredArrow X (StructuredArrow.proj Y F) ≌ StructuredArrow Y (Under.forget X ⋙ F) where + functor := ofStructuredArrowProjEquivalence.functor F Y X + inverse := ofStructuredArrowProjEquivalence.inverse F Y X + unitIso := NatIso.ofComponents (fun _ => Iso.refl _) (by simp) + 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 structured arrow category on `Under.forget`. -/ +@[simps!] +def ofDiagEquivalence.functor (X : T × T) : + StructuredArrow X (Functor.diag _) ⥤ StructuredArrow X.2 (Under.forget X.1) := + Functor.toStructuredArrow + (Functor.toUnder (StructuredArrow.proj X _) _ + (fun f => by exact f.hom.1) (fun m => by have := m.w; aesop_cat)) _ _ + (fun f => f.hom.2) (fun m => by have := m.w; aesop_cat) + +/-- The inverse functor of `ofDiagEquivalence.functor`. -/ +@[simps!] +def ofDiagEquivalence.inverse (X : T × T) : + StructuredArrow X.2 (Under.forget X.1) ⥤ StructuredArrow X (Functor.diag _) := + Functor.toStructuredArrow (StructuredArrow.proj _ _ ⋙ Under.forget _) _ _ + (fun f => (f.right.hom, f.hom)) (fun m => by have := m.w; aesop_cat) + +/-- Characterization of the structured arrow category on the diagonal functor `T ⥤ T × T`. -/ +def ofDiagEquivalence (X : T × T) : + StructuredArrow X (Functor.diag _) ≌ StructuredArrow X.2 (Under.forget X.1) where + functor := ofDiagEquivalence.functor X + inverse := ofDiagEquivalence.inverse X + unitIso := NatIso.ofComponents (fun _ => Iso.refl _) (by simp) + counitIso := NatIso.ofComponents (fun _ => Iso.refl _) (by aesop_cat) + +/-- A version of `StructuredArrow.ofDiagEquivalence` with the roles of the first and second +projection swapped. -/ +def ofDiagEquivalence' (X : T × T) : + StructuredArrow X (Functor.diag _) ≌ StructuredArrow X.1 (Under.forget X.2) := + (ofDiagEquivalence X).trans <| + (ofStructuredArrowProjEquivalence (𝟭 T) X.1 X.2).trans <| + StructuredArrow.mapNatIso (Under.forget X.2).rightUnitor + +end StructuredArrow + +namespace CostructuredArrow + +/-- A functor from the costructured arrow category on the projection functor for any costructured +arrow category. -/ +@[simps!] +def ofCostructuredArrowProjEquivalence.functor (F : T ⥤ D) (Y : D) (X : T) : + CostructuredArrow (CostructuredArrow.proj F Y) X ⥤ CostructuredArrow (Over.forget X ⋙ F) Y := + Functor.toCostructuredArrow + (Functor.toOver (CostructuredArrow.proj _ X ⋙ CostructuredArrow.proj F Y) _ + (fun g => by exact g.hom) (fun m => by have := m.w; aesop_cat)) _ _ + (fun f => f.left.hom) (by simp) + +/-- The inverse functor of `ofCostructuredArrowProjEquivalence.functor`. -/ +@[simps!] +def ofCostructuredArrowProjEquivalence.inverse (F : T ⥤ D) (Y : D) (X : T) : + CostructuredArrow (Over.forget X ⋙ F) Y ⥤ CostructuredArrow (CostructuredArrow.proj F Y) X := + Functor.toCostructuredArrow + (Functor.toCostructuredArrow (CostructuredArrow.proj _ Y ⋙ Over.forget X) _ _ + (fun g => by exact g.hom) (fun m => by have := m.w; aesop_cat)) _ _ + (fun f => f.left.hom) (by simp) + +/-- Characterization of the costructured arrow category on the projection functor of any +costructured arrow category. -/ +def ofCostructuredArrowProjEquivalence (F : T ⥤ D) (Y : D) (X : T) : + CostructuredArrow (CostructuredArrow.proj F Y) X + ≌ CostructuredArrow (Over.forget X ⋙ F) Y where + functor := ofCostructuredArrowProjEquivalence.functor F Y X + inverse := ofCostructuredArrowProjEquivalence.inverse F Y X + unitIso := NatIso.ofComponents (fun _ => Iso.refl _) (by simp) + 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 costructured arrow category on `Under.forget`. -/ +@[simps!] +def ofDiagEquivalence.functor (X : T × T) : + CostructuredArrow (Functor.diag _) X ⥤ CostructuredArrow (Over.forget X.1) X.2 := + Functor.toCostructuredArrow + (Functor.toOver (CostructuredArrow.proj _ X) _ + (fun g => by exact g.hom.1) (fun m => by have := congrArg (·.1) m.w; aesop_cat)) + _ _ + (fun f => f.hom.2) (fun m => by have := congrArg (·.2) m.w; aesop_cat) + +/-- The inverse functor of `ofDiagEquivalence.functor`. -/ +@[simps!] +def ofDiagEquivalence.inverse (X : T × T) : + CostructuredArrow (Over.forget X.1) X.2 ⥤ CostructuredArrow (Functor.diag _) X := + Functor.toCostructuredArrow (CostructuredArrow.proj _ _ ⋙ Over.forget _) _ X + (fun f => (f.left.hom, f.hom)) (fun m => by have := m.w; aesop_cat) + +/-- Characterization of the costructured arrow category on the diagonal functor `T ⥤ T × T`. -/ +def ofDiagEquivalence (X : T × T) : + CostructuredArrow (Functor.diag _) X ≌ CostructuredArrow (Over.forget X.1) X.2 where + functor := ofDiagEquivalence.functor X + inverse := ofDiagEquivalence.inverse X + unitIso := NatIso.ofComponents (fun _ => Iso.refl _) (by simp) + counitIso := NatIso.ofComponents (fun _ => Iso.refl _) (by aesop_cat) + +/-- A version of `CostructuredArrow.ofDiagEquivalence` with the roles of the first and second +projection swapped. -/ +def ofDiagEquivalence' (X : T × T) : + CostructuredArrow (Functor.diag _) X ≌ CostructuredArrow (Over.forget X.2) X.1 := + (ofDiagEquivalence X).trans <| + (ofCostructuredArrowProjEquivalence (𝟭 T) X.1 X.2).trans <| + CostructuredArrow.mapNatIso (Over.forget X.2).rightUnitor + +end CostructuredArrow + end CategoryTheory diff --git a/Mathlib/CategoryTheory/Comma/StructuredArrow.lean b/Mathlib/CategoryTheory/Comma/StructuredArrow.lean index e59aa9a52ccbd..3ee2b719536a8 100644 --- a/Mathlib/CategoryTheory/Comma/StructuredArrow.lean +++ b/Mathlib/CategoryTheory/Comma/StructuredArrow.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: Adam Topaz, Scott Morrison +Authors: Adam Topaz, Kim Morrison -/ import Mathlib.CategoryTheory.Comma.Basic import Mathlib.CategoryTheory.PUnit @@ -111,7 +111,7 @@ def homMk {f f' : StructuredArrow S T} (g : f.right ⟶ f'.right) simpa using w.symm /- Porting note: it appears the simp lemma is not getting generated but the linter -picks up on it (seems like a bug). Either way simp solves it. -/ +picks up on it (seems like a bug). Either way simp solves it. -/ attribute [-simp, nolint simpNF] homMk_left theorem homMk_surjective {f f' : StructuredArrow S T} (φ : f ⟶ f') : @@ -120,7 +120,7 @@ theorem homMk_surjective {f f' : StructuredArrow S T} (φ : f ⟶ f') : ⟨φ.right, StructuredArrow.w φ, rfl⟩ /-- Given a structured arrow `X ⟶ T(Y)`, and an arrow `Y ⟶ Y'`, we can construct a morphism of - structured arrows given by `(X ⟶ T(Y)) ⟶ (X ⟶ T(Y) ⟶ T(Y'))`. -/ + structured arrows given by `(X ⟶ T(Y)) ⟶ (X ⟶ T(Y) ⟶ T(Y'))`. -/ @[simps] def homMk' (f : StructuredArrow S T) (g : f.right ⟶ Y') : f ⟶ mk (f.hom ≫ T.map g) where left := 𝟙 _ @@ -856,37 +856,104 @@ end CostructuredArrow is contravariantly equivalent to the category of costructured arrows `F.op.obj c ⟶ op d`. -/ def structuredArrowOpEquivalence (F : C ⥤ D) (d : D) : - (StructuredArrow d F)ᵒᵖ ≌ CostructuredArrow F.op (op d) := - Equivalence.mk (StructuredArrow.toCostructuredArrow F d) - (CostructuredArrow.toStructuredArrow' F d).rightOp - (NatIso.ofComponents + (StructuredArrow d F)ᵒᵖ ≌ CostructuredArrow F.op (op d) where + functor := StructuredArrow.toCostructuredArrow F d + inverse := (CostructuredArrow.toStructuredArrow' F d).rightOp + unitIso := NatIso.ofComponents (fun X => (StructuredArrow.isoMk (Iso.refl _)).op) fun {X Y} f => Quiver.Hom.unop_inj <| by apply CommaMorphism.ext <;> - dsimp [StructuredArrow.isoMk, Comma.isoMk,StructuredArrow.homMk]; simp) - (NatIso.ofComponents + dsimp [StructuredArrow.isoMk, Comma.isoMk,StructuredArrow.homMk]; simp + counitIso := NatIso.ofComponents (fun X => CostructuredArrow.isoMk (Iso.refl _)) fun {X Y} f => by apply CommaMorphism.ext <;> - dsimp [CostructuredArrow.isoMk, Comma.isoMk, CostructuredArrow.homMk]; simp) + dsimp [CostructuredArrow.isoMk, Comma.isoMk, CostructuredArrow.homMk]; simp /-- For a functor `F : C ⥤ D` and an object `d : D`, the category of costructured arrows `F.obj c ⟶ d` is contravariantly equivalent to the category of structured arrows `op d ⟶ F.op.obj c`. -/ def costructuredArrowOpEquivalence (F : C ⥤ D) (d : D) : - (CostructuredArrow F d)ᵒᵖ ≌ StructuredArrow (op d) F.op := - Equivalence.mk (CostructuredArrow.toStructuredArrow F d) - (StructuredArrow.toCostructuredArrow' F d).rightOp - (NatIso.ofComponents + (CostructuredArrow F d)ᵒᵖ ≌ StructuredArrow (op d) F.op where + functor := CostructuredArrow.toStructuredArrow F d + inverse := (StructuredArrow.toCostructuredArrow' F d).rightOp + unitIso := NatIso.ofComponents (fun X => (CostructuredArrow.isoMk (Iso.refl _)).op) fun {X Y} f => Quiver.Hom.unop_inj <| by apply CommaMorphism.ext <;> - dsimp [CostructuredArrow.isoMk, CostructuredArrow.homMk, Comma.isoMk]; simp) - (NatIso.ofComponents + dsimp [CostructuredArrow.isoMk, CostructuredArrow.homMk, Comma.isoMk]; simp + counitIso := NatIso.ofComponents (fun X => StructuredArrow.isoMk (Iso.refl _)) fun {X Y} f => by apply CommaMorphism.ext <;> - dsimp [StructuredArrow.isoMk, StructuredArrow.homMk, Comma.isoMk]; simp) + 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/ComposableArrows.lean b/Mathlib/CategoryTheory/ComposableArrows.lean index d7b5a70f49f70..49706164e2037 100644 --- a/Mathlib/CategoryTheory/ComposableArrows.lean +++ b/Mathlib/CategoryTheory/ComposableArrows.lean @@ -8,6 +8,7 @@ import Mathlib.CategoryTheory.EqToHom import Mathlib.CategoryTheory.Functor.Const import Mathlib.Order.Fin.Basic import Mathlib.Tactic.FinCases +import Mathlib.Tactic.SuppressCompilation /-! # Composable arrows @@ -184,7 +185,7 @@ def homMk {F G : ComposableArrows C n} (app : ∀ i, F.obj i ⟶ G.obj i) intro k induction' k with k hk · intro i j hj hj' - simp only [Nat.zero_eq, add_zero] at hj + simp only [add_zero] at hj obtain rfl := hj rw [F.map'_self i, G.map'_self i, id_comp, comp_id] · intro i j hj hj' @@ -549,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₀ := @@ -888,6 +889,7 @@ lemma mkOfObjOfMapSucc_arrow (i : ℕ) (hi : i < n := by valid) : end mkOfObjOfMapSucc +suppress_compilation in variable (C n) in /-- The equivalence `(ComposableArrows C n)ᵒᵖ ≌ ComposableArrows Cᵒᵖ n` obtained by reversing the arrows. -/ @@ -914,6 +916,7 @@ def Functor.mapComposableArrows : ComposableArrows C n ⥤ ComposableArrows D n := (whiskeringRight _ _ _).obj G +suppress_compilation in /-- The functor `ComposableArrows C n ⥤ ComposableArrows D n` induced by `G : C ⥤ D` commutes with `opEquivalence`. -/ def Functor.mapComposableArrowsOpIso : diff --git a/Mathlib/CategoryTheory/ConcreteCategory/Basic.lean b/Mathlib/CategoryTheory/ConcreteCategory/Basic.lean index 6482fc883f061..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 @@ -84,8 +84,6 @@ attribute [local instance] ConcreteCategory.hasCoeToSort variable {C : Type u} [Category.{v} C] [ConcreteCategory.{w} C] --- Porting note: forget_obj_eq_coe has become a syntactic tautology. - /-- In any concrete category, `(forget C).map` is injective. -/ abbrev ConcreteCategory.instFunLike {X Y : C} : FunLike (X ⟶ Y) X Y where coe f := (forget C).map f diff --git a/Mathlib/CategoryTheory/ConcreteCategory/Bundled.lean b/Mathlib/CategoryTheory/ConcreteCategory/Bundled.lean index b97cff90ac9d4..1fe01ebf2d14a 100644 --- a/Mathlib/CategoryTheory/ConcreteCategory/Bundled.lean +++ b/Mathlib/CategoryTheory/ConcreteCategory/Bundled.lean @@ -1,8 +1,9 @@ /- -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 /-! @@ -21,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. -/ @@ -51,20 +52,8 @@ instance coeSort : CoeSort (Bundled c) (Type u) := theorem coe_mk (α) (str) : (@Bundled.mk c α str : Type u) = α := rfl -/- -`Bundled.map` is reducible so that, if we define a category - - def Ring : Type (u+1) := induced_category SemiRing (bundled.map @ring.to_semiring) - -instance search is able to "see" that a morphism R ⟶ S in Ring is really -a (semi)ring homomorphism from R.α to S.α, and not merely from -`(Bundled.map @Ring.toSemiring R).α` to `(Bundled.map @Ring.toSemiring S).α`. - -TODO: Once at least one use of this has been ported, check if this still needs to be reducible in -Lean 4. --/ /-- Map over the bundled structure -/ -def map (f : ∀ {α}, c α → d α) (b : Bundled c) : Bundled d := +abbrev map (f : ∀ {α}, c α → d α) (b : Bundled c) : Bundled d := ⟨b, f b.str⟩ end Bundled diff --git a/Mathlib/CategoryTheory/ConcreteCategory/BundledHom.lean b/Mathlib/CategoryTheory/ConcreteCategory/BundledHom.lean index 201557ff6bf23..e4763010998ab 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 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/ConnectedComponents.lean b/Mathlib/CategoryTheory/ConnectedComponents.lean index 6f018d34805a0..0d205fcbb0170 100644 --- a/Mathlib/CategoryTheory/ConnectedComponents.lean +++ b/Mathlib/CategoryTheory/ConnectedComponents.lean @@ -36,6 +36,16 @@ variable {J : Type u₁} [Category.{v₁} J] def ConnectedComponents (J : Type u₁) [Category.{v₁} J] : Type u₁ := Quotient (Zigzag.setoid J) +/-- The map `ConnectedComponents J → ConnectedComponents K` induced by a functor `J ⥤ K`. -/ +def Functor.mapConnectedComponents {K : Type u₂} [Category.{v₂} K] (F : J ⥤ K) + (x : ConnectedComponents J) : ConnectedComponents K := + x |> Quotient.lift (Quotient.mk (Zigzag.setoid _) ∘ F.obj) + (fun _ _ ↦ Quot.sound ∘ zigzag_obj_of_zigzag F) + +@[simp] +lemma Functor.mapConnectedComponents_mk {K : Type u₂} [Category.{v₂} K] (F : J ⥤ K) (j : J) : + F.mapConnectedComponents (Quotient.mk _ j) = Quotient.mk _ (F.obj j) := rfl + instance [Inhabited J] : Inhabited (ConnectedComponents J) := ⟨Quotient.mk'' default⟩ @@ -46,7 +56,7 @@ def ConnectedComponents.functorToDiscrete (X : Type*) map g := Discrete.eqToHom (congrArg f (Quotient.sound (Zigzag.of_hom g))) /-- Every functor to a discrete category gives a function from connected components -/ -def ConnectedComponents.liftFunctor (J) [Category J] {X : Type*} (F :J ⥤ Discrete X) : +def ConnectedComponents.liftFunctor (J) [Category J] {X : Type*} (F :J ⥤ Discrete X) : (ConnectedComponents J → X) := Quotient.lift (fun c => (F.obj c).as) (fun _ _ h => eq_of_zigzag X (zigzag_obj_of_zigzag F h)) @@ -106,7 +116,7 @@ instance (j : ConnectedComponents J) : IsConnected (Component j) := by -- Everything in our chosen zigzag from `j₁` to `j₂` has a zigzag to `j₂`. have hf : ∀ a : J, a ∈ l → Zigzag a j₂ := by intro i hi - apply List.Chain.induction (fun t => Zigzag t j₂) _ hl₁ hl₂ _ _ _ (List.mem_of_mem_tail hi) + apply hl₁.backwards_induction (fun t => Zigzag t j₂) _ hl₂ _ _ _ (List.mem_of_mem_tail hi) · intro j k apply Relation.ReflTransGen.head · apply Relation.ReflTransGen.refl @@ -114,7 +124,7 @@ instance (j : ConnectedComponents J) : IsConnected (Component j) := by refine ⟨l.pmap f hf, ?_, ?_⟩ · refine @List.chain_pmap_of_chain _ _ _ _ _ f (fun x y _ _ h => ?_) _ _ hl₁ h₁₂ _ exact zag_of_zag_obj (Component.ι _) h - · erw [List.getLast_pmap _ f (j₁ :: l) (by simpa [h₁₂] using hf) (List.cons_ne_nil _ _)] + · erw [List.getLast_pmap f (j₁ :: l) (by simpa [h₁₂] using hf) (List.cons_ne_nil _ _)] exact FullSubcategory.ext hl₂ /-- The disjoint union of `J`s connected components, written explicitly as a sigma-type with the diff --git a/Mathlib/CategoryTheory/Core.lean b/Mathlib/CategoryTheory/Core.lean index e124cbff9a5bc..e7b1e69ea7ddc 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 diff --git a/Mathlib/CategoryTheory/DifferentialObject.lean b/Mathlib/CategoryTheory/DifferentialObject.lean index ffd8546c41068..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 @@ -181,8 +181,8 @@ def mapDifferentialObject (F : C ⥤ D) slice_lhs 2 3 => rw [← Functor.comp_map F (shiftFunctor D (1 : S)), ← η.naturality f.f] slice_lhs 1 2 => rw [Functor.comp_map, ← F.map_comp, f.comm, F.map_comp] rw [Category.assoc] } - map_id := by intros; ext; simp [autoParam] - map_comp := by intros; ext; simp [autoParam] + map_id := by intros; ext; simp + map_comp := by intros; ext; simp end Functor @@ -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 480c69f86cce5..59798018c9623 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 @@ -270,9 +270,10 @@ open Opposite @[simps! functor_obj_as inverse_obj] protected def opposite (α : Type u₁) : (Discrete α)ᵒᵖ ≌ Discrete α := let F : Discrete α ⥤ (Discrete α)ᵒᵖ := Discrete.functor fun x => op (Discrete.mk x) - Equivalence.mk F.leftOp F - (NatIso.ofComponents fun ⟨X⟩ => Iso.refl _) - (Discrete.natIso fun ⟨X⟩ => Iso.refl _) + { functor := F.leftOp + inverse := F + unitIso := NatIso.ofComponents fun ⟨X⟩ => Iso.refl _ + counitIso := Discrete.natIso fun ⟨X⟩ => Iso.refl _ } variable {C : Type u₂} [Category.{v₂} C] diff --git a/Mathlib/CategoryTheory/EffectiveEpi/Basic.lean b/Mathlib/CategoryTheory/EffectiveEpi/Basic.lean index 6291d2e13bde1..4259ae6bf495b 100644 --- a/Mathlib/CategoryTheory/EffectiveEpi/Basic.lean +++ b/Mathlib/CategoryTheory/EffectiveEpi/Basic.lean @@ -24,7 +24,7 @@ then these definitions are equivalent, see the file `CategoryTheory/EffectiveEpi/RegularEpi.lean` See [nlab: *Effective Epimorphism*](https://ncatlab.org/nlab/show/effective+epimorphism) and [Stacks 00WP](https://stacks.math.columbia.edu/tag/00WP) for the standard definitions. Note that -our notion of `EffectiveEpi` is often called "strict epi" in the literature. +our notion of `EffectiveEpi` is often called "strict epi" in the literature. ## References - [Elephant]: *Sketches of an Elephant*, P. T. Johnstone: C2.1, Example 2.1.12. @@ -45,7 +45,7 @@ This structure encodes the data required for a morphism to be an effective epimo structure EffectiveEpiStruct {X Y : C} (f : Y ⟶ X) where /-- For every `W` with a morphism `e : Y ⟶ W` that coequalizes every pair of morphisms - `g₁ g₂ : Z ⟶ Y` which `f` coequalizes, `desc e h` is a morphism `X ⟶ W`...  + `g₁ g₂ : Z ⟶ Y` which `f` coequalizes, `desc e h` is a morphism `X ⟶ W`... -/ desc : ∀ {W : C} (e : Y ⟶ W), (∀ {Z : C} (g₁ g₂ : Z ⟶ Y), g₁ ≫ f = g₂ ≫ f → g₁ ≫ e = g₂ ≫ e) → (X ⟶ W) @@ -65,7 +65,7 @@ If `f` has a kernel pair, then this is equivalent to showing that the correspond a colimit. -/ class EffectiveEpi {X Y : C} (f : Y ⟶ X) : Prop where - /-- `f` is an effective epimorphism if there exists an `EffectiveEpiStruct` for `f`. -/ + /-- `f` is an effective epimorphism if there exists an `EffectiveEpiStruct` for `f`. -/ effectiveEpi : Nonempty (EffectiveEpiStruct f) /-- Some chosen `EffectiveEpiStruct` associated to an effective epi. -/ @@ -107,7 +107,7 @@ structure EffectiveEpiFamilyStruct {B : C} {α : Type*} /-- For every `W` with a family of morphisms `e a : Y a ⟶ W` that coequalizes every pair of morphisms `g₁ : Z ⟶ Y a₁`, `g₂ : Z ⟶ Y a₂` which the family `π` coequalizes, `desc e h` is a morphism - `X ⟶ W`...  + `X ⟶ W`... -/ desc : ∀ {W} (e : (a : α) → (X a ⟶ W)), (∀ {Z : C} (a₁ a₂ : α) (g₁ : Z ⟶ X a₁) (g₂ : Z ⟶ X a₂), @@ -129,7 +129,7 @@ provided that the `π a` exhibit `B` as a colimit of the diagram of all "relatio `R → X a₁`, `R ⟶ X a₂` for all `a₁ a₂ : α`. -/ class EffectiveEpiFamily {B : C} {α : Type*} (X : α → C) (π : (a : α) → (X a ⟶ B)) : Prop where - /-- `π` is an effective epimorphic family if there exists an `EffectiveEpiFamilyStruct` for `π` -/ + /-- `π` is an effective epimorphic family if there exists an `EffectiveEpiFamilyStruct` for `π` -/ effectiveEpiFamily : Nonempty (EffectiveEpiFamilyStruct X π) /-- Some chosen `EffectiveEpiFamilyStruct` associated to an effective epi family. -/ @@ -186,7 +186,7 @@ instance {B X : C} (f : X ⟶ B) [EffectiveEpi f] : EffectiveEpiFamily (fun () ⟨⟨effectiveEpiFamilyStructSingletonOfEffectiveEpi f⟩⟩ /-- -A single element `EffectiveEpiFamily` constists of an `EffectiveEpi` +A single element `EffectiveEpiFamily` consists of an `EffectiveEpi` -/ noncomputable def effectiveEpiStructOfEffectiveEpiFamilySingleton {B X : C} (f : X ⟶ B) diff --git a/Mathlib/CategoryTheory/EffectiveEpi/Comp.lean b/Mathlib/CategoryTheory/EffectiveEpi/Comp.lean index 94fd3321440d7..a8b4353556eb6 100644 --- a/Mathlib/CategoryTheory/EffectiveEpi/Comp.lean +++ b/Mathlib/CategoryTheory/EffectiveEpi/Comp.lean @@ -8,7 +8,7 @@ import Mathlib.CategoryTheory.EffectiveEpi.Basic # Composition of effective epimorphisms -This file provides `EffectiveEpi` instances for certain compositions. +This file provides `EffectiveEpi` instances for certain compositions. -/ diff --git a/Mathlib/CategoryTheory/EffectiveEpi/Coproduct.lean b/Mathlib/CategoryTheory/EffectiveEpi/Coproduct.lean index 85b4dfd1e7fc3..80a53351c358d 100644 --- a/Mathlib/CategoryTheory/EffectiveEpi/Coproduct.lean +++ b/Mathlib/CategoryTheory/EffectiveEpi/Coproduct.lean @@ -56,7 +56,7 @@ example {B : C} {α : Type*} (X : α → C) (π : (a : α) → (X a ⟶ B)) [Eff /-- This is an auxiliary lemma used twice in the definition of `EffectiveEpiFamilyOfEffectiveEpiDesc`. -It is the `h` hypothesis of `EffectiveEpi.desc` and `EffectiveEpi.fac`.  +It is the `h` hypothesis of `EffectiveEpi.desc` and `EffectiveEpi.fac`. -/ theorem effectiveEpiFamilyStructOfEffectiveEpiDesc_aux {B : C} {α : Type*} {X : α → C} {π : (a : α) → X a ⟶ B} [HasCoproduct X] diff --git a/Mathlib/CategoryTheory/EffectiveEpi/Enough.lean b/Mathlib/CategoryTheory/EffectiveEpi/Enough.lean index 1c4b96149fb57..dc7f679ddd6fb 100644 --- a/Mathlib/CategoryTheory/EffectiveEpi/Enough.lean +++ b/Mathlib/CategoryTheory/EffectiveEpi/Enough.lean @@ -8,7 +8,7 @@ import Mathlib.CategoryTheory.EffectiveEpi.Basic # Effectively enough objects in the image of a functor -We define the class `F.EffectivelyEnough` on a functor `F : C ⥤ D` which says that for every object +We define the class `F.EffectivelyEnough` on a functor `F : C ⥤ D` which says that for every object in `D`, there exists an effective epi to it from an object in the image of `F`. -/ @@ -21,11 +21,11 @@ variable {C D : Type*} [Category C] [Category D] (F : C ⥤ D) namespace Functor /-- -An effective presentation of an object `X` with respect to a functor `F` is the data of an effective +An effective presentation of an object `X` with respect to a functor `F` is the data of an effective epimorphism of the form `F.obj p ⟶ X`. -/ structure EffectivePresentation (X : D) where - /-- The object of `C` giving the source of the effective epi -/ + /-- The object of `C` giving the source of the effective epi -/ p : C /-- The morphism `F.obj p ⟶ X` -/ f : F.obj p ⟶ X @@ -33,11 +33,11 @@ structure EffectivePresentation (X : D) where effectiveEpi : EffectiveEpi f /-- -`D` has *effectively enough objects with respect to the functor `F` if every object has an +`D` has *effectively enough objects with respect to the functor `F` if every object has an effective presentation. -/ class EffectivelyEnough : Prop where - /-- For every `X : D`, there exists an object `p` of `C` with an effective epi `F.obj p ⟶ X`. -/ + /-- For every `X : D`, there exists an object `p` of `C` with an effective epi `F.obj p ⟶ X`. -/ presentation : ∀ (X : D), Nonempty (F.EffectivePresentation X) variable [F.EffectivelyEnough] diff --git a/Mathlib/CategoryTheory/EffectiveEpi/Extensive.lean b/Mathlib/CategoryTheory/EffectiveEpi/Extensive.lean index 433f695391d2d..00ace33a89767 100644 --- a/Mathlib/CategoryTheory/EffectiveEpi/Extensive.lean +++ b/Mathlib/CategoryTheory/EffectiveEpi/Extensive.lean @@ -11,7 +11,7 @@ import Mathlib.CategoryTheory.Limits.Preserves.Finite # Preserving and reflecting effective epis on extensive categories -We prove that a functor between `FinitaryPreExtensive` categories preserves (resp. reflects) finite +We prove that a functor between `FinitaryPreExtensive` categories preserves (resp. reflects) finite effective epi families if it preserves (resp. reflects) effective epis. -/ diff --git a/Mathlib/CategoryTheory/EffectiveEpi/RegularEpi.lean b/Mathlib/CategoryTheory/EffectiveEpi/RegularEpi.lean index 8f471641e5b1f..9272c878d3ca1 100644 --- a/Mathlib/CategoryTheory/EffectiveEpi/RegularEpi.lean +++ b/Mathlib/CategoryTheory/EffectiveEpi/RegularEpi.lean @@ -19,7 +19,7 @@ open Limits RegularEpi variable {C : Type*} [Category C] -/-- The data of an `EffectiveEpi` structure on a `RegularEpi`. -/ +/-- The data of an `EffectiveEpi` structure on a `RegularEpi`. -/ def effectiveEpiStructOfRegularEpi {B X : C} (f : X ⟶ B) [RegularEpi f] : EffectiveEpiStruct f where desc _ h := Cofork.IsColimit.desc isColimit _ (h _ _ w) diff --git a/Mathlib/CategoryTheory/Elements.lean b/Mathlib/CategoryTheory/Elements.lean index 35d3b67264029..3ff60562fdb11 100644 --- a/Mathlib/CategoryTheory/Elements.lean +++ b/Mathlib/CategoryTheory/Elements.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.Comma.StructuredArrow import Mathlib.CategoryTheory.Groupoid @@ -64,6 +64,18 @@ instance categoryOfElements (F : C ⥤ Type w) : Category.{v} F.Elements where id p := ⟨𝟙 p.1, by aesop_cat⟩ comp {X Y Z} f g := ⟨f.val ≫ g.val, by simp [f.2, g.2]⟩ +/-- Natural transformations are mapped to functors between category of elements -/ +@[simps] +def NatTrans.mapElements {F G : C ⥤ Type w} (φ : F ⟶ G) : F.Elements ⥤ G.Elements where + obj := fun ⟨X, x⟩ ↦ ⟨_, φ.app X x⟩ + map {p q} := fun ⟨f, h⟩ ↦ ⟨f, by have hb := congrFun (φ.naturality f) p.2; aesop_cat⟩ + +/-- The functor mapping functors `C ⥤ Type w` to their category of elements -/ +@[simps] +def Functor.elementsFunctor : (C ⥤ Type w) ⥤ Cat where + obj F := Cat.of F.Elements + map n := NatTrans.mapElements n + namespace CategoryOfElements /-- Constructor for morphisms in the category of elements of a functor to types. -/ @@ -89,6 +101,13 @@ theorem id_val {F : C ⥤ Type w} {p : F.Elements} : (𝟙 p : p ⟶ p).val = theorem map_snd {F : C ⥤ Type w} {p q : F.Elements} (f : p ⟶ q) : (F.map f.val) p.2 = q.2 := f.property +/-- Constructor for isomorphisms in the category of elements of a functor to types. -/ +@[simps] +def isoMk {F : C ⥤ Type w} (x y : F.Elements) (e : x.1 ≅ y.1) (he : F.map e.hom x.snd = y.snd) : + x ≅ y where + hom := homMk x y e.hom he + inv := homMk y x e.inv (by rw [← he, FunctorToTypes.map_inv_map_hom_apply]) + end CategoryOfElements instance groupoidOfElements {G : Type u} [Groupoid.{v} G] (F : G ⥤ Type w) : @@ -169,12 +188,12 @@ theorem fromStructuredArrow_map {X Y} (f : X ⟶ Y) : /-- The equivalence between the category of elements `F.Elements` and the comma category `(*, F)`. -/ -@[simps! functor_obj functor_map inverse_obj inverse_map unitIso_hom - unitIso_inv counitIso_hom counitIso_inv] -def structuredArrowEquivalence : F.Elements ≌ StructuredArrow PUnit F := - Equivalence.mk (toStructuredArrow F) (fromStructuredArrow F) - (NatIso.ofComponents fun X => eqToIso (by aesop_cat)) - (NatIso.ofComponents fun X => StructuredArrow.isoMk (Iso.refl _)) +@[simps] +def structuredArrowEquivalence : F.Elements ≌ StructuredArrow PUnit F where + functor := toStructuredArrow F + inverse := fromStructuredArrow F + unitIso := Iso.refl _ + counitIso := Iso.refl _ open Opposite @@ -204,55 +223,27 @@ 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) : (fromCostructuredArrow F).obj (op (CostructuredArrow.mk f)) = ⟨op X, yonedaEquiv.1 f⟩ := rfl -/-- The unit of the equivalence `F.Elementsᵒᵖ ≅ (yoneda, F)` is indeed iso. -/ -theorem from_toCostructuredArrow_eq (F : Cᵒᵖ ⥤ Type v) : - (toCostructuredArrow F).rightOp ⋙ fromCostructuredArrow F = 𝟭 _ := by - refine Functor.ext ?_ ?_ - · intro X - exact Functor.Elements.ext _ _ rfl (by simp [yonedaEquiv]) - · intro X Y f - have : ∀ {a b : F.Elements} (H : a = b), - (eqToHom H).1 = eqToHom (show a.fst = b.fst by cases H; rfl) := by - rintro _ _ rfl - simp - ext - simp [this] - -/-- The counit of the equivalence `F.Elementsᵒᵖ ≅ (yoneda, F)` is indeed iso. -/ -theorem to_fromCostructuredArrow_eq (F : Cᵒᵖ ⥤ Type v) : - (fromCostructuredArrow F).rightOp ⋙ toCostructuredArrow F = 𝟭 _ := by - refine Functor.ext ?_ ?_ - · intro X - cases' X with X_left X_right X_hom - cases X_right - simp only [Functor.id_obj, Functor.rightOp_obj, toCostructuredArrow_obj, Functor.comp_obj, - CostructuredArrow.mk] - congr - ext x f - convert congr_fun (X_hom.naturality f.op).symm (𝟙 X_left) - simp - · aesop - /-- The equivalence `F.Elementsᵒᵖ ≅ (yoneda, F)` given by yoneda lemma. -/ -@[simps! functor_obj functor_map inverse_obj inverse_map unitIso_inv counitIso_hom counitIso_inv] +@[simps] def costructuredArrowYonedaEquivalence (F : Cᵒᵖ ⥤ Type v) : - F.Elementsᵒᵖ ≌ CostructuredArrow yoneda F := - Equivalence.mk (toCostructuredArrow F) (fromCostructuredArrow F).rightOp - (NatIso.op (eqToIso (from_toCostructuredArrow_eq F))) (eqToIso <| to_fromCostructuredArrow_eq F) - --- Porting note: --- Running `@[simps! unitIso_hom]` is mysteriously slow. --- We separate it out to avoid needing to increase the maxHeartbeats. -attribute [simps! unitIso_hom] costructuredArrowYonedaEquivalence + F.Elementsᵒᵖ ≌ CostructuredArrow yoneda F where + functor := toCostructuredArrow F + inverse := (fromCostructuredArrow F).rightOp + unitIso := + NatIso.ofComponents + (fun X ↦ Iso.op (CategoryOfElements.isoMk _ _ (Iso.refl _) (by simp))) (by + rintro ⟨x⟩ ⟨y⟩ ⟨f : y ⟶ x⟩ + exact Quiver.Hom.unop_inj (by ext; simp)) + counitIso := NatIso.ofComponents (fun X ↦ CostructuredArrow.isoMk (Iso.refl _)) /-- The equivalence `(-.Elements)ᵒᵖ ≅ (yoneda, -)` of is actually a natural isomorphism of functors. -/ @@ -265,7 +256,7 @@ theorem costructuredArrow_yoneda_equivalence_naturality {F₁ F₂ : Cᵒᵖ ⥤ congr ext _ f simpa using congr_fun (α.naturality f.op).symm (unop X).snd - · simp [autoParam] + · simp /-- The equivalence `F.elementsᵒᵖ ≌ (yoneda, F)` is compatible with the forgetful functors. -/ @[simps!] 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..59d61ad43c4c1 100644 --- a/Mathlib/CategoryTheory/Endofunctor/Algebra.lean +++ b/Mathlib/CategoryTheory/Endofunctor/Algebra.lean @@ -1,7 +1,7 @@ /- 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 diff --git a/Mathlib/CategoryTheory/Endomorphism.lean b/Mathlib/CategoryTheory/Endomorphism.lean index 30f789b4ad257..93109c730da29 100644 --- a/Mathlib/CategoryTheory/Endomorphism.lean +++ b/Mathlib/CategoryTheory/Endomorphism.lean @@ -1,7 +1,7 @@ /- 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 diff --git a/Mathlib/CategoryTheory/Enriched/Basic.lean b/Mathlib/CategoryTheory/Enriched/Basic.lean index 325790ef8b742..f8f9518c24feb 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 diff --git a/Mathlib/CategoryTheory/EpiMono.lean b/Mathlib/CategoryTheory/EpiMono.lean index a9cd25cb109d7..13cfd3e4ad1b3 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 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..0f2676be1e1e8 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 diff --git a/Mathlib/CategoryTheory/EssentialImage.lean b/Mathlib/CategoryTheory/EssentialImage.lean index 083afcf335209..a9a14f0935a2b 100644 --- a/Mathlib/CategoryTheory/EssentialImage.lean +++ b/Mathlib/CategoryTheory/EssentialImage.lean @@ -89,6 +89,10 @@ instance : Full (essImageInclusion F) := instance : Faithful (essImageInclusion F) := (inferInstance : Faithful (fullSubcategoryInclusion _)) +lemma essImage_ext (F : C ⥤ D) {X Y : F.EssImageSubcategory} (f g : X ⟶ Y) + (h : F.essImageInclusion.map f = F.essImageInclusion.map g) : f = g := by + simpa using h + /-- Given a functor `F : C ⥤ D`, we have an (essentially surjective) functor from `C` to the essential image of `F`. diff --git a/Mathlib/CategoryTheory/EssentiallySmall.lean b/Mathlib/CategoryTheory/EssentiallySmall.lean index 6be51da1c9899..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 @@ -61,6 +61,9 @@ noncomputable def equivSmallModel (C : Type u) [Category.{v} C] [EssentiallySmal Nonempty.some (Classical.choose_spec (Classical.choose_spec (@EssentiallySmall.equiv_smallCategory C _ _))) +instance (C : Type u) [Category.{v} C] [EssentiallySmall.{w} C] : EssentiallySmall.{w} Cᵒᵖ := + EssentiallySmall.mk' (equivSmallModel C).op + theorem essentiallySmall_congr {C : Type u} [Category.{v} C] {D : Type u'} [Category.{v'} D] (e : C ≌ D) : EssentiallySmall.{w} C ↔ EssentiallySmall.{w} D := by fconstructor @@ -164,11 +167,12 @@ noncomputable def inverse : ShrinkHoms C ⥤ C where /-- The categorical equivalence between `C` and `ShrinkHoms C`, when `C` is locally small. -/ -@[simps!] -noncomputable def equivalence : C ≌ ShrinkHoms C := - Equivalence.mk (functor C) (inverse C) - (NatIso.ofComponents fun X => Iso.refl X) - (NatIso.ofComponents fun X => Iso.refl X) +@[simps] +noncomputable def equivalence : C ≌ ShrinkHoms C where + functor := functor C + inverse := inverse C + unitIso := NatIso.ofComponents (fun _ ↦ Iso.refl _) + counitIso := NatIso.ofComponents (fun _ ↦ Iso.refl _) end ShrinkHoms diff --git a/Mathlib/CategoryTheory/Extensive.lean b/Mathlib/CategoryTheory/Extensive.lean index be20dc8fc8fae..94619f08a21bb 100644 --- a/Mathlib/CategoryTheory/Extensive.lean +++ b/Mathlib/CategoryTheory/Extensive.lean @@ -7,7 +7,7 @@ import Mathlib.CategoryTheory.Limits.Shapes.Pullback.CommSq import Mathlib.CategoryTheory.Limits.Shapes.StrictInitial import Mathlib.CategoryTheory.Limits.Shapes.Types import Mathlib.Topology.Category.TopCat.Limits.Pullbacks -import Mathlib.CategoryTheory.Limits.FunctorCategory +import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic import Mathlib.CategoryTheory.Limits.Constructions.FiniteProductsOfBinaryProducts import Mathlib.CategoryTheory.Limits.VanKampen @@ -79,7 +79,7 @@ and binary coproducts are universal. -/ class FinitaryPreExtensive (C : Type u) [Category.{v} C] : Prop where [hasFiniteCoproducts : HasFiniteCoproducts C] [hasPullbacksOfInclusions : HasPullbacksOfInclusions C] - /-- In a finitary extensive category, all coproducts are van Kampen-/ + /-- In a finitary extensive category, all coproducts are van Kampen -/ universal' : ∀ {X Y : C} (c : BinaryCofan X Y), IsColimit c → IsUniversalColimit c attribute [instance] FinitaryPreExtensive.hasFiniteCoproducts @@ -90,7 +90,7 @@ and binary coproducts are van Kampen. -/ class FinitaryExtensive (C : Type u) [Category.{v} C] : Prop where [hasFiniteCoproducts : HasFiniteCoproducts C] [hasPullbacksOfInclusions : HasPullbacksOfInclusions C] - /-- In a finitary extensive category, all coproducts are van Kampen-/ + /-- In a finitary extensive category, all coproducts are van Kampen -/ van_kampen' : ∀ {X Y : C} (c : BinaryCofan X Y), IsColimit c → IsVanKampenColimit c attribute [instance] FinitaryExtensive.hasFiniteCoproducts @@ -426,15 +426,12 @@ theorem FinitaryPreExtensive.isUniversal_finiteCoproducts_Fin [FinitaryPreExtens Functor.hext (fun _ ↦ rfl) (by rintro ⟨i⟩ ⟨j⟩ ⟨⟨rfl : i = j⟩⟩; simp [f]) clear_value f subst this - induction' n with n IH - · exact (isVanKampenColimit_of_isEmpty _ hc).isUniversal - · apply IsUniversalColimit.of_iso _ + induction n with + | zero => exact (isVanKampenColimit_of_isEmpty _ hc).isUniversal + | succ n IH => + refine IsUniversalColimit.of_iso (@isUniversalColimit_extendCofan _ _ _ _ _ _ + (IH _ (coproductIsCoproduct _)) (FinitaryPreExtensive.universal' _ (coprodIsCoprod _ _)) ?_) ((extendCofanIsColimit f (coproductIsCoproduct _) (coprodIsCoprod _ _)).uniqueUpToIso hc) - apply @isUniversalColimit_extendCofan _ _ _ _ _ _ _ _ ?_ - · apply IH - exact coproductIsCoproduct _ - · apply FinitaryPreExtensive.universal' - exact coprodIsCoprod _ _ · dsimp infer_instance @@ -530,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 π)) : @@ -539,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 59aa7b055409e..bfcd82955db95 100644 --- a/Mathlib/CategoryTheory/FiberedCategory/BasedCategory.lean +++ b/Mathlib/CategoryTheory/FiberedCategory/BasedCategory.lean @@ -14,7 +14,7 @@ import Mathlib.CategoryTheory.Functor.ReflectsIso In this file we define the type `BasedCategory 𝒮`, and give it the structure of a strict bicategory. Given a category `𝒮`, we define the type `BasedCategory 𝒮` as the type of categories -`𝒳` equiped with a functor `𝒳.p : 𝒳 ⥤ 𝒮`. +`𝒳` equipped with a functor `𝒳.p : 𝒳 ⥤ 𝒮`. We also define a type of functors between based categories `𝒳` and `𝒴`, which we call `BasedFunctor 𝒳 𝒴` and denote as `𝒳 ⥤ᵇ 𝒴`. These are defined as functors between the underlying @@ -222,7 +222,7 @@ def id (F : 𝒳 ⥤ᵇ 𝒴) : F ≅ F where variable {F G : 𝒳 ⥤ᵇ 𝒴} -/-- The inverse of a based natural transformation whose underlying natural tranformation is an +/-- The inverse of a based natural transformation whose underlying natural transformation is an isomorphism. -/ def mkNatIso (α : F.toFunctor ≅ G.toFunctor) (isHomLift' : ∀ a : 𝒳.obj, IsHomLift 𝒴.p (𝟙 (𝒳.p.obj a)) (α.hom.app a)) : F ≅ G where diff --git a/Mathlib/CategoryTheory/FiberedCategory/Cartesian.lean b/Mathlib/CategoryTheory/FiberedCategory/Cartesian.lean index 9f1ffd4abcba6..b6f222bcedcbc 100644 --- a/Mathlib/CategoryTheory/FiberedCategory/Cartesian.lean +++ b/Mathlib/CategoryTheory/FiberedCategory/Cartesian.lean @@ -12,6 +12,8 @@ import Mathlib.CategoryTheory.FiberedCategory.HomLift This file defines cartesian resp. strongly cartesian morphisms with respect to a functor `p : 𝒳 ⥤ 𝒮`. +This file has been adapted to `FiberedCategory/Cocartesian`, please try to change them in sync. + ## Main definitions `IsCartesian p f φ` expresses that `φ` is a cartesian morphism lying over `f` with respect to `p` in @@ -46,18 +48,26 @@ section variable {R S : 𝒮} {a b : 𝒳} (f : R ⟶ S) (φ : a ⟶ b) -/-- The proposition that a morphism `φ : a ⟶ b` in `𝒳` lying over `f : R ⟶ S` in `𝒮` is a -cartesian morphism. +/-- A morphism `φ : a ⟶ b` in `𝒳` lying over `f : R ⟶ S` in `𝒮` is cartesian if for all +morphisms `φ' : a' ⟶ b`, also lying over `f`, there exists a unique morphism `χ : a' ⟶ a` lifting +`𝟙 R` such that `φ' = χ ≫ φ`. See SGA 1 VI 5.1. -/ class IsCartesian extends IsHomLift p f φ : Prop where universal_property {a' : 𝒳} (φ' : a' ⟶ b) [IsHomLift p f φ'] : ∃! χ : a' ⟶ a, IsHomLift p (𝟙 R) χ ∧ χ ≫ φ = φ' -/-- The proposition that a morphism `φ : a ⟶ b` in `𝒳` lying over `f : R ⟶ S` in `𝒮` is a -strongly cartesian morphism. +/-- A morphism `φ : a ⟶ b` in `𝒳` lying over `f : R ⟶ S` in `𝒮` is strongly cartesian if for +all morphisms `φ' : a' ⟶ b` and all diagrams of the form +``` +a' a --φ--> b +| | | +v v v +R' --g--> R --f--> S +``` +such that `φ'` lifts `g ≫ f`, there exists a lift `χ` of `g` such that `φ' = χ ≫ φ`. -See -/ +See . -/ class IsStronglyCartesian extends IsHomLift p f φ : Prop where universal_property' {a' : 𝒳} (g : p.obj a' ⟶ R) (φ' : a' ⟶ b) [IsHomLift p (g ≫ f) φ'] : ∃! χ : a' ⟶ a, IsHomLift p g χ ∧ χ ≫ φ = φ' @@ -109,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 φ' φ @@ -121,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 @@ -222,16 +241,31 @@ lemma map_self : map p f φ (id_comp f).symm φ = 𝟙 a := by apply map_uniq simp only [id_comp] -/-- When its possible to compare the two, the composition of two `IsCocartesian.map` will also be -given by a `IsCocartesian.map`. In other words, given diagrams +/-- When its possible to compare the two, the composition of two `IsStronglyCartesian.map` will also +be given by a `IsStronglyCartesian.map`. In other words, given diagrams ``` -a'' a' a --φ--> b a' --φ'--> b a'' --φ''--> b -| | | | and | | and | | -v v v v v v v v -R'' --g'--> R' --g--> R --f--> S R' --f'--> S R'' --f''--> S +a'' a' a --φ--> b +| | | | +v v v v +R'' --g'--> R' --g--> R --f--> S ``` -such that `φ` and `φ'` are strongly cartesian morphisms. Then composing the induced map from -`a'' ⟶ a'` with the induced map from `a' ⟶ a` gives the induced map from `a'' ⟶ a`. -/ +and +``` +a' --φ'--> b +| | +v v +R' --f'--> S +``` +and +``` +a'' --φ''--> b +| | +v v +R'' --f''--> S +``` +such that `φ` and `φ'` are strongly cartesian morphisms, and such that `f' = g ≫ f` and +`f'' = g' ≫ f'`. Then composing the induced map from `a'' ⟶ a'` with the induced map from +`a' ⟶ a` gives the induced map from `a'' ⟶ a`. -/ @[reassoc (attr := simp)] lemma map_comp_map {R' R'' : 𝒮} {a' a'' : 𝒳} {f' : R' ⟶ S} {f'' : R'' ⟶ S} {g : R' ⟶ R} {g' : R'' ⟶ R'} (H : f' = g ≫ f) (H' : f'' = g' ≫ f') (φ' : a' ⟶ b) (φ'' : a'' ⟶ b) @@ -326,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/Cocartesian.lean b/Mathlib/CategoryTheory/FiberedCategory/Cocartesian.lean new file mode 100644 index 0000000000000..d2e2b408959c9 --- /dev/null +++ b/Mathlib/CategoryTheory/FiberedCategory/Cocartesian.lean @@ -0,0 +1,364 @@ +/- +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.FiberedCategory.HomLift + +/-! +# Cocartesian morphisms + +This file defines cocartesian resp. strongly cocartesian morphisms with respect to a functor +`p : 𝒳 ⥤ 𝒮`. + +This file has been adapted from `FiberedCategory/Cartesian`, please try to change them in sync. + +## Main definitions + +`IsCocartesian p f φ` expresses that `φ` is a cocartesian morphism lying over `f : R ⟶ S` with +respect to `p`. This means that for any morphism `φ' : a ⟶ b'` lying over `f` there +is a unique morphism `τ : b ⟶ b'` lying over `𝟙 S`, such that `φ' = φ ≫ τ`. + +`IsStronglyCocartesian p f φ` expresses that `φ` is a strongly cocartesian morphism lying over `f` +with respect to `p`. + +## Implementation + +The constructor of `IsStronglyCocartesian` has been named `universal_property'`, and is mainly +intended to be used for constructing instances of this class. To use the universal property, we +generally recommended to use the lemma `IsStronglyCocartesian.universal_property` instead. The +difference between the two is that the latter is more flexible with respect to non-definitional +equalities. + +-/ + +universe v₁ v₂ u₁ u₂ + +open CategoryTheory Functor Category IsHomLift + +namespace CategoryTheory.Functor + +variable {𝒮 : Type u₁} {𝒳 : Type u₂} [Category.{v₁} 𝒮] [Category.{v₂} 𝒳] (p : 𝒳 ⥤ 𝒮) + +section + +variable {R S : 𝒮} {a b : 𝒳} (f : R ⟶ S) (φ : a ⟶ b) + +/-- A morphism `φ : a ⟶ b` in `𝒳` lying over `f : R ⟶ S` in `𝒮` is cocartesian if for all +morphisms `φ' : a ⟶ b'`, also lying over `f`, there exists a unique morphism `χ : b ⟶ b'` lifting +`𝟙 S` such that `φ' = φ ≫ χ`. -/ +class IsCocartesian extends IsHomLift p f φ : Prop where + universal_property {b' : 𝒳} (φ' : a ⟶ b') [IsHomLift p f φ'] : + ∃! χ : b ⟶ b', IsHomLift p (𝟙 S) χ ∧ φ ≫ χ = φ' + +/-- A morphism `φ : a ⟶ b` in `𝒳` lying over `f : R ⟶ S` in `𝒮` is strongly cocartesian if for +all morphisms `φ' : a ⟶ b'` and all diagrams of the form +``` +a --φ--> b b' +| | | +v v v +R --f--> S --g--> S' +``` +such that `φ'` lifts `f ≫ g`, there exists a lift `χ` of `g` such that `φ' = χ ≫ φ`. + +See . -/ +class IsStronglyCocartesian extends IsHomLift p f φ : Prop where + universal_property' {b' : 𝒳} (g : S ⟶ p.obj b') (φ' : a ⟶ b') [IsHomLift p (f ≫ g) φ'] : + ∃! χ : b ⟶ b', IsHomLift p g χ ∧ φ ≫ χ = φ' + +end + +namespace IsCocartesian + +variable {R S : 𝒮} {a b : 𝒳} (f : R ⟶ S) (φ : a ⟶ b) [IsCocartesian p f φ] + +section + +variable {b' : 𝒳} (φ' : a ⟶ b') [IsHomLift p f φ'] + +/-- Given a cocartesian morphism `φ : a ⟶ b` lying over `f : R ⟶ S` in `𝒳`, and another morphism +`φ' : a ⟶ b'` which also lifts `f`, then `IsCocartesian.map f φ φ'` is the morphism `b ⟶ b'` lying +over `𝟙 S` obtained from the universal property of `φ`. -/ +protected noncomputable def map : b ⟶ b' := + Classical.choose <| IsCocartesian.universal_property (p:=p) (f:=f) (φ:=φ) φ' + +instance map_isHomLift : IsHomLift p (𝟙 S) (IsCocartesian.map p f φ φ') := + (Classical.choose_spec <| IsCocartesian.universal_property (p:=p) (f:=f) (φ:=φ) φ').1.1 + +@[reassoc (attr := simp)] +lemma fac : φ ≫ IsCocartesian.map p f φ φ' = φ' := + (Classical.choose_spec <| IsCocartesian.universal_property (p:=p) (f:=f) (φ:=φ) φ').1.2 + +/-- Given a cocartesian morphism `φ : a ⟶ b` lying over `f : R ⟶ S` in `𝒳`, and another morphism +`φ' : a ⟶ b'` which also lifts `f`. Then any morphism `ψ : b ⟶ b'` lifting `𝟙 S` such that +`g ≫ ψ = φ'` must equal the map induced by the universal property of `φ`. -/ +lemma map_uniq (ψ : b ⟶ b') [IsHomLift p (𝟙 S) ψ] (hψ : φ ≫ ψ = φ') : + ψ = IsCocartesian.map p f φ φ' := + (Classical.choose_spec <| IsCocartesian.universal_property (p:=p) (f:=f) (φ:=φ) φ').2 + ψ ⟨inferInstance, hψ⟩ + +end + +/-- Given a cocartesian morphism `φ : a ⟶ b` lying over `f : R ⟶ S` in `𝒳`, and two morphisms +`ψ ψ' : b ⟶ b'` lifting `𝟙 S` such that `φ ≫ ψ = φ ≫ ψ'`. Then we must have `ψ = ψ'`. -/ +protected lemma ext (φ : a ⟶ b) [IsCocartesian p f φ] {b' : 𝒳} (ψ ψ' : b ⟶ b') + [IsHomLift p (𝟙 S) ψ] [IsHomLift p (𝟙 S) ψ'] (h : φ ≫ ψ = φ ≫ ψ') : ψ = ψ' := by + rw [map_uniq p f φ (φ ≫ ψ) ψ rfl, map_uniq p f φ (φ ≫ ψ) ψ' h.symm] + +@[simp] +lemma map_self : IsCocartesian.map p f φ φ = 𝟙 b := by + subst_hom_lift p f φ; symm + apply map_uniq + simp only [comp_id] + +/-- The canonical isomorphism between the codomains of two cocartesian morphisms +lying over the same object. -/ +noncomputable def codomainUniqueUpToIso {b' : 𝒳} (φ' : a ⟶ b') [IsCocartesian p f φ'] : + b ≅ b' where + hom := IsCocartesian.map p f φ φ' + inv := IsCocartesian.map p f φ' φ + hom_inv_id := by + subst_hom_lift p f φ + apply IsCocartesian.ext p (p.map φ) φ + simp only [fac_assoc, fac, comp_id] + inv_hom_id := by + subst_hom_lift p f φ' + apply IsCocartesian.ext p (p.map φ') φ' + simp only [fac_assoc, fac, comp_id] + +/-- Postcomposing a cocartesian morphism with an isomorphism lifting the identity is cocartesian. -/ +instance of_comp_iso {b' : 𝒳} (φ' : b ≅ b') [IsHomLift p (𝟙 S) φ'.hom] : + IsCocartesian p f (φ ≫ φ'.hom) where + universal_property := by + intro c ψ hψ + use φ'.inv ≫ IsCocartesian.map p f φ ψ + refine ⟨⟨inferInstance, by simp⟩, ?_⟩ + rintro τ ⟨hτ₁, hτ₂⟩ + rw [Iso.eq_inv_comp] + apply map_uniq + exact ((assoc φ _ _) ▸ hτ₂) + +/-- Precomposing a cocartesian morphism with an isomorphism lifting the identity is cocartesian. -/ +instance of_iso_comp {a' : 𝒳} (φ' : a' ≅ a) [IsHomLift p (𝟙 R) φ'.hom] : + IsCocartesian p f (φ'.hom ≫ φ) where + universal_property := by + intro c ψ hψ + use IsCocartesian.map p f φ (φ'.inv ≫ ψ) + refine ⟨⟨inferInstance, by simp⟩, ?_⟩ + rintro τ ⟨hτ₁, hτ₂⟩ + apply map_uniq + simp only [Iso.eq_inv_comp, ← assoc, hτ₂] + +end IsCocartesian + +namespace IsStronglyCocartesian + +section + +variable {R S : 𝒮} {a b : 𝒳} (f : R ⟶ S) (φ : a ⟶ b) [IsStronglyCocartesian p f φ] + +/-- The universal property of a strongly cocartesian morphism. + +This lemma is more flexible with respect to non-definitional equalities than the field +`universal_property'` of `IsStronglyCocartesian`. -/ +lemma universal_property {S' : 𝒮} {b' : 𝒳} (g : S ⟶ S') (f' : R ⟶ S') (hf' : f' = f ≫ g) + (φ' : a ⟶ b') [IsHomLift p f' φ'] : ∃! χ : b ⟶ b', IsHomLift p g χ ∧ φ ≫ χ = φ' := by + subst_hom_lift p f' φ'; clear a b R S + have : p.IsHomLift (f ≫ g) φ' := (hf' ▸ inferInstance) + apply IsStronglyCocartesian.universal_property' f + +instance isCocartesian_of_isStronglyCocartesian [p.IsStronglyCocartesian f φ] : + p.IsCocartesian f φ where + universal_property := fun φ' => universal_property p f φ (𝟙 S) f (comp_id f).symm φ' + +section + +variable {S' : 𝒮} {b' : 𝒳} {g : S ⟶ S'} {f' : R ⟶ S'} (hf' : f' = f ≫ g) (φ' : a ⟶ b') + [IsHomLift p f' φ'] + +/-- Given a diagram +``` +a --φ--> b b' +| | | +v v v +R --f--> S --g--> S' +``` +such that `φ` is strongly cocartesian, and a morphism `φ' : a ⟶ b'`. Then `map` is the map +`b ⟶ b'` lying over `g` obtained from the universal property of `φ`. -/ +noncomputable def map : b ⟶ b' := + Classical.choose <| universal_property p f φ _ _ hf' φ' + +instance map_isHomLift : IsHomLift p g (map p f φ hf' φ') := + (Classical.choose_spec <| universal_property p f φ _ _ hf' φ').1.1 + +@[reassoc (attr := simp)] +lemma fac : φ ≫ (map p f φ hf' φ') = φ' := + (Classical.choose_spec <| universal_property p f φ _ _ hf' φ').1.2 + + +/-- Given a diagram +``` +a --φ--> b b' +| | | +v v v +R --f--> S --g--> S' +``` +such that `φ` is strongly cocartesian, and morphisms `φ' : a ⟶ b'`, `ψ : b ⟶ b'` such that +`g ≫ ψ = φ'`. Then `ψ` is the map induced by the universal property. -/ +lemma map_uniq (ψ : b ⟶ b') [IsHomLift p g ψ] (hψ : φ ≫ ψ = φ') : ψ = map p f φ hf' φ' := + (Classical.choose_spec <| universal_property p f φ _ _ hf' φ').2 ψ ⟨inferInstance, hψ⟩ + +end + +/-- Given a diagram +``` +a --φ--> b b' +| | | +v v v +R --f--> S --g--> S' +``` +such that `φ` is strongly cocartesian, and morphisms `ψ ψ' : b ⟶ b'` such that +`g ≫ ψ = φ' = g ≫ ψ'`. Then we have that `ψ = ψ'`. -/ +protected lemma ext (φ : a ⟶ b) [IsStronglyCocartesian p f φ] {S' : 𝒮} {b' : 𝒳} (g : S ⟶ S') + {ψ ψ' : b ⟶ b'} [IsHomLift p g ψ] [IsHomLift p g ψ'] (h : φ ≫ ψ = φ ≫ ψ') : ψ = ψ' := by + rw [map_uniq p f φ (g := g) rfl (φ ≫ ψ) ψ rfl, map_uniq p f φ (g := g) rfl (φ ≫ ψ) ψ' h.symm] + +@[simp] +lemma map_self : map p f φ (comp_id f).symm φ = 𝟙 b := by + subst_hom_lift p f φ; symm + apply map_uniq + simp only [comp_id] + +/-- When its possible to compare the two, the composition of two `IsStronglyCocartesian.map` will +also be given by a `IsStronglyCocartesian.map`. In other words, given diagrams +``` +a --φ--> b b' b'' +| | | | +v v v v +R --f--> S --g--> S' --g'--> S' +``` +and +``` +a --φ'--> b' +| | +v v +R --f'--> S' + +``` +and +``` +a --φ''--> b'' +| | +v v +R --f''--> S'' +``` +such that `φ` and `φ'` are strongly cocartesian morphisms, and such that `f' = f ≫ g` and +`f'' = f' ≫ g'`. Then composing the induced map from `b ⟶ b'` with the induced map from +`b' ⟶ b''` gives the induced map from `b ⟶ b''`. -/ +@[reassoc (attr := simp)] +lemma map_comp_map {S' S'' : 𝒮} {b' b'' : 𝒳} {f' : R ⟶ S'} {f'' : R ⟶ S''} {g : S ⟶ S'} + {g' : S' ⟶ S''} (H : f' = f ≫ g) (H' : f'' = f' ≫ g') (φ' : a ⟶ b') (φ'' : a ⟶ b'') + [IsStronglyCocartesian p f' φ'] [IsHomLift p f'' φ''] : + map p f φ H φ' ≫ map p f' φ' H' φ'' = + map p f φ (show f'' = f ≫ (g ≫ g') by rwa [← assoc, ← H]) φ'' := by + apply map_uniq p f φ + simp only [fac_assoc, fac] + +end + +section + +variable {R S T : 𝒮} {a b c : 𝒳} {f : R ⟶ S} {g : S ⟶ T} {φ : a ⟶ b} {ψ : b ⟶ c} + +/-- Given two strongly cocartesian morphisms `φ`, `ψ` as follows +``` +a --φ--> b --ψ--> c +| | | +v v v +R --f--> S --g--> T +``` +Then the composite `φ ≫ ψ` is also strongly cocartesian. -/ +instance comp [IsStronglyCocartesian p f φ] [IsStronglyCocartesian p g ψ] : + IsStronglyCocartesian p (f ≫ g) (φ ≫ ψ) where + universal_property' := by + intro c' h τ hτ + use map p g ψ (f' := g ≫ h) rfl <| map p f φ (assoc f g h) τ + refine ⟨⟨inferInstance, ?_⟩, ?_⟩ + · simp only [assoc, fac] + · intro π' ⟨hπ'₁, hπ'₂⟩ + apply map_uniq + apply map_uniq + simp only [← hπ'₂, assoc] + +/-- Given two commutative squares +``` +a --φ--> b --ψ--> c +| | | +v v v +R --f--> S --g--> T +``` +such that `φ ≫ ψ` and `φ` are strongly cocartesian, then so is `ψ`. -/ +protected lemma of_comp [IsStronglyCocartesian p f φ] [IsStronglyCocartesian p (f ≫ g) (φ ≫ ψ)] + [IsHomLift p g ψ] : IsStronglyCocartesian p g ψ where + universal_property' := by + intro c' h τ hτ + have h₁ : IsHomLift p (f ≫ g ≫ h) (φ ≫ τ) := by simpa using IsHomLift.comp p f (g ≫ h) φ τ + /- We get a morphism `π : c ⟶ c'` such that `(φ ≫ ψ) ≫ π = φ ≫ τ` from the universal property + of `φ ≫ ψ`. This will be the morphism induced by `φ`. -/ + use map p (f ≫ g) (φ ≫ ψ) (f' := f ≫ g ≫ h) (assoc f g h).symm (φ ≫ τ) + refine ⟨⟨inferInstance, ?_⟩, ?_⟩ + /- The fact that `ψ ≫ π = τ` follows from `φ ≫ ψ ≫ π = φ ≫ τ` and the universal property of + `φ`. -/ + · apply IsStronglyCocartesian.ext p f φ (g ≫ h) <| by simp only [← assoc, fac] + -- Finally, uniqueness of `π` comes from the universal property of `φ ≫ ψ`. + · intro π' ⟨hπ'₁, hπ'₂⟩ + apply map_uniq + simp [hπ'₂.symm] + +end + +section + +variable {R S : 𝒮} {a b : 𝒳} (f : R ⟶ S) + +instance of_iso (φ : a ≅ b) [IsHomLift p f φ.hom] : IsStronglyCocartesian p f φ.hom where + universal_property' := by + intro b' g τ hτ + use φ.inv ≫ τ + refine ⟨?_, by aesop_cat⟩ + simpa [← assoc] using (IsHomLift.comp p (isoOfIsoLift p f φ).inv (f ≫ g) φ.inv τ) + +instance of_isIso (φ : a ⟶ b) [IsHomLift p f φ] [IsIso φ] : IsStronglyCocartesian p f φ := + @IsStronglyCocartesian.of_iso _ _ _ _ p _ _ _ _ f (asIso φ) (by aesop) + +/-- A strongly cocartesian arrow lying over an isomorphism is an isomorphism. -/ +lemma isIso_of_base_isIso (φ : a ⟶ b) [IsStronglyCocartesian p f φ] [IsIso f] : IsIso φ := by + subst_hom_lift p f φ; clear a b R S + -- Let `φ'` be the morphism induced by applying universal property to `𝟙 a` lying over `f ≫ f⁻¹`. + let φ' := map p (p.map φ) φ (IsIso.hom_inv_id (p.map φ)).symm (𝟙 a) + use φ' + -- `φ ≫ φ' = 𝟙 a` follows immediately from the universal property. + have inv_hom : φ ≫ φ' = 𝟙 a := fac p (p.map φ) φ _ (𝟙 a) + refine ⟨inv_hom, ?_⟩ + -- We will now show that `φ' ≫ φ = 𝟙 b` by showing that `φ ≫ (φ' ≫ φ) = φ ≫ 𝟙 b`. + have h₁ : IsHomLift p (𝟙 (p.obj b)) (φ' ≫ φ) := by + rw [← IsIso.inv_hom_id (p.map φ)] + apply IsHomLift.comp + apply IsStronglyCocartesian.ext p (p.map φ) φ (𝟙 (p.obj b)) + simp only [← assoc, inv_hom, comp_id, id_comp] + +end + +/-- The canonical isomorphism between the codomains of two strongly cocartesian arrows lying over +isomorphic objects. -/ +noncomputable def codomainIsoOfBaseIso {R S S' : 𝒮} {a b b' : 𝒳} {f : R ⟶ S} {f' : R ⟶ S'} + {g : S ≅ S'} (h : f' = f ≫ g.hom) (φ : a ⟶ b) (φ' : a ⟶ b') [IsStronglyCocartesian p f φ] + [IsStronglyCocartesian p f' φ'] : b ≅ b' where + hom := map p f φ h φ' + inv := @map _ _ _ _ p _ _ _ _ f' φ' _ _ _ _ _ (congrArg (· ≫ g.inv) h.symm) φ + (by simp; infer_instance) + +end IsStronglyCocartesian + +end CategoryTheory.Functor diff --git a/Mathlib/CategoryTheory/FiberedCategory/Fibered.lean b/Mathlib/CategoryTheory/FiberedCategory/Fibered.lean new file mode 100644 index 0000000000000..b826fc429e660 --- /dev/null +++ b/Mathlib/CategoryTheory/FiberedCategory/Fibered.lean @@ -0,0 +1,186 @@ +/- +Copyright (c) 2024 Paul Lezeau. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Paul Lezeau, Calle Sönne +-/ + +import Mathlib.CategoryTheory.FiberedCategory.Cartesian + +/-! + +# Fibered categories + +This file defines what it means for a functor `p : 𝒳 ⥤ 𝒮` to be (pre)fibered. + +## Main definitions + +- `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 +when wanting to apply this condition, it is recommended to instead use the lemma +`exists_isCartesian` (without the prime), which is more applicable with respect to non-definitional +equalities. + +## References +* [A. Grothendieck, M. Raynaud, *SGA 1*](https://arxiv.org/abs/math/0206203) + +-/ + +universe v₁ v₂ u₁ u₂ + +open CategoryTheory Functor Category IsHomLift + +namespace CategoryTheory + +variable {𝒮 : Type u₁} {𝒳 : Type u₂} [Category.{v₁} 𝒮] [Category.{v₂} 𝒳] + +/-- Definition of a prefibered category. + +See SGA 1 VI.6.1. -/ +class Functor.IsPreFibered (p : 𝒳 ⥤ 𝒮) : Prop where + exists_isCartesian' {a : 𝒳} {R : 𝒮} (f : R ⟶ p.obj a) : ∃ (b : 𝒳) (φ : b ⟶ a), IsCartesian p f φ + +protected lemma IsPreFibered.exists_isCartesian (p : 𝒳 ⥤ 𝒮) [p.IsPreFibered] {a : 𝒳} {R S : 𝒮} + (ha : p.obj a = S) (f : R ⟶ S) : ∃ (b : 𝒳) (φ : b ⟶ a), IsCartesian p f φ := by + subst ha; exact IsPreFibered.exists_isCartesian' f + +/-- 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 + +variable {p : 𝒳 ⥤ 𝒮} [IsPreFibered p] {R S : 𝒮} {a : 𝒳} (ha : p.obj a = S) (f : R ⟶ S) + +/-- Given a fibered category `p : 𝒳 ⥤ 𝒫`, a morphism `f : R ⟶ S` and an object `a` lying over `S`, +then `pullbackObj` is the domain of some choice of a cartesian morphism lying over `f` with +codomain `a`. -/ +noncomputable def pullbackObj : 𝒳 := + Classical.choose (IsPreFibered.exists_isCartesian p ha f) + +/-- Given a fibered category `p : 𝒳 ⥤ 𝒫`, a morphism `f : R ⟶ S` and an object `a` lying over `S`, +then `pullbackMap` is a choice of a cartesian morphism lying over `f` with codomain `a`. -/ +noncomputable def pullbackMap : pullbackObj ha f ⟶ a := + Classical.choose (Classical.choose_spec (IsPreFibered.exists_isCartesian p ha f)) + +instance pullbackMap.IsCartesian : IsCartesian p f (pullbackMap ha f) := + Classical.choose_spec (Classical.choose_spec (IsPreFibered.exists_isCartesian p ha f)) + +lemma pullbackObj_proj : p.obj (pullbackObj ha f) = R := + domain_eq p f (pullbackMap ha f) + +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 d8ac3d794f3a7..8de8bf2c92401 100644 --- a/Mathlib/CategoryTheory/FiberedCategory/HomLift.lean +++ b/Mathlib/CategoryTheory/FiberedCategory/HomLift.lean @@ -18,7 +18,7 @@ does not make sense when the domain and/or codomain of `φ` and `f` are not defi ## Main definition Given morphism `φ : a ⟶ b` in `𝒳` and `f : R ⟶ S` in `𝒮`, `p.IsHomLift f φ` is a class, defined -using the auxillary inductive type `IsHomLiftAux` which expresses the fact that `f = p(φ)`. +using the auxiliary inductive type `IsHomLiftAux` which expresses the fact that `f = p(φ)`. We also define a macro `subst_hom_lift p f φ` which can be used to substitute `f` with `p(φ)` in a goal, this tactic is just short for `obtain ⟨⟩ := Functor.IsHomLift.cond (p:=p) (f:=f) (φ:=φ)`, and @@ -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 `𝒮`-/ @@ -142,7 +142,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 diff --git a/Mathlib/CategoryTheory/Filtered/Basic.lean b/Mathlib/CategoryTheory/Filtered/Basic.lean index f4da1d923d0e6..688a1d9ce43a8 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 diff --git a/Mathlib/CategoryTheory/Filtered/Final.lean b/Mathlib/CategoryTheory/Filtered/Final.lean index eb3ef28ce871c..23d7d5c9ec781 100644 --- a/Mathlib/CategoryTheory/Filtered/Final.lean +++ b/Mathlib/CategoryTheory/Filtered/Final.lean @@ -18,10 +18,13 @@ final can be restated. We show: * `final_iff_isFiltered_structuredArrow`: `F` is final if and only if `StructuredArrow d F` is filtered for all `d : D`, which strengthens the usual statement that `F` is final if and only if `StructuredArrow d F` is connected for all `d : D`. - -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. +* Under categories of objects of filtered categories are filtered and their forgetful functors + are 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 @@ -164,6 +167,40 @@ theorem Functor.initial_of_exists_of_isCofiltered_of_fullyFaithful [IsCofiltered obtain ⟨c, ⟨f⟩⟩ := h d.unop exact ⟨op c, ⟨f.op⟩⟩ +/-- Any under category on a filtered or empty category is filtered. +(Note that under categories are always cofiltered since they have an initial object.) -/ +instance IsFiltered.under [IsFilteredOrEmpty C] (c : C) : IsFiltered (Under c) := + isFiltered_structuredArrow_of_isFiltered_of_exists _ + (fun c' => ⟨c', ⟨𝟙 _⟩⟩) + (fun s s' => IsFilteredOrEmpty.cocone_maps s s') c + +/-- Any over category on a cofiltered or empty category is cofiltered. +(Note that over categories are always filtered since they have a terminal object.) -/ +instance IsCofiltered.over [IsCofilteredOrEmpty C] (c : C) : IsCofiltered (Over c) := + isCofiltered_costructuredArrow_of_isCofiltered_of_exists _ + (fun c' => ⟨c', ⟨𝟙 _⟩⟩) + (fun s s' => IsCofilteredOrEmpty.cone_maps s s') c + +/-- The forgetful functor of the under category on any filtered or empty category is final. -/ +instance Under.final_forget [IsFilteredOrEmpty C] (c : C) : Final (Under.forget c) := + final_of_exists_of_isFiltered _ + (fun c' => ⟨mk (IsFiltered.leftToMax c c'), ⟨IsFiltered.rightToMax c c'⟩⟩) + (fun {_} {x} s s' => by + use mk (x.hom ≫ IsFiltered.coeqHom s s') + use homMk (IsFiltered.coeqHom s s') (by simp) + simp only [forget_obj, id_obj, mk_right, const_obj_obj, forget_map, homMk_right] + rw [IsFiltered.coeq_condition]) + +/-- The forgetful functor of the over category on any cofiltered or empty category is initial. -/ +instance Over.initial_forget [IsCofilteredOrEmpty C] (c : C) : Initial (Over.forget c) := + initial_of_exists_of_isCofiltered _ + (fun c' => ⟨mk (IsCofiltered.minToLeft c c'), ⟨IsCofiltered.minToRight c c'⟩⟩) + (fun {_} {x} s s' => by + use mk (IsCofiltered.eqHom s s' ≫ x.hom) + use homMk (IsCofiltered.eqHom s s') (by simp) + simp only [forget_obj, mk_left, forget_map, homMk_left] + rw [IsCofiltered.eq_condition]) + end ArbitraryUniverses section LocallySmall @@ -228,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 @@ -241,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 @@ -250,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/Filtered/Small.lean b/Mathlib/CategoryTheory/Filtered/Small.lean index 7948241296129..5206fd8c67956 100644 --- a/Mathlib/CategoryTheory/Filtered/Small.lean +++ b/Mathlib/CategoryTheory/Filtered/Small.lean @@ -56,11 +56,11 @@ namespace FilteredClosureSmall in `C`. This would require some kind of inductive-recursive definition, which Lean does not allow. Our solution is to define a function `ℕ → Σ t : Type (max v w), t → C` by (strong) induction and then take the union over all natural numbers, mimicking what one would do in a - set-theoretic setting. -/ + set-theoretic setting. -/ /-- One step of the inductive procedure consists of adjoining all maxima and coequalizers of all objects and morphisms obtained so far. This is quite redundant, picking up many objects which we - already hit in earlier iterations, but this is easier to work with later. -/ + already hit in earlier iterations, but this is easier to work with later. -/ private inductive InductiveStep (n : ℕ) (X : ∀ (k : ℕ), k < n → Σ t : Type (max v w), t → C) : Type (max v w) | max : {k k' : ℕ} → (hk : k < n) → (hk' : k' < n) → (X _ hk).1 → (X _ hk').1 → InductiveStep n X @@ -78,7 +78,7 @@ private noncomputable def inductiveStepRealization (n : ℕ) as a function of `ℕ`. The function is defined by well-founded recursion, but we really want to use its - definitional equalities in the proofs below, so lets make it semireducible. -/ + definitional equalities in the proofs below, so lets make it semireducible. -/ @[semireducible] private noncomputable def bundledAbstractFilteredClosure : ℕ → Σ t : Type (max v w), t → C | 0 => ⟨ULift.{v} α, f ∘ ULift.down⟩ @@ -211,7 +211,7 @@ private noncomputable def inductiveStepRealization (n : ℕ) `EssentiallySmall.{max v w} (FullSubcategory (CofilteredClosure f))`. The function is defined by well-founded recursion, but we really want to use its - definitional equalities in the proofs below, so lets make it semireducible. -/ + definitional equalities in the proofs below, so lets make it semireducible. -/ @[semireducible] private noncomputable def bundledAbstractCofilteredClosure : ℕ → Σ t : Type (max v w), t → C | 0 => ⟨ULift.{v} α, f ∘ ULift.down⟩ diff --git a/Mathlib/CategoryTheory/FinCategory/AsType.lean b/Mathlib/CategoryTheory/FinCategory/AsType.lean index 714344cab1db2..1ba7c2d3cd220 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 @@ -61,10 +61,11 @@ noncomputable def objAsTypeToAsType : ObjAsType α ⥤ AsType α where map {X Y} := Fintype.equivFin _ /-- The constructed category (`AsType α`) is equivalent to `ObjAsType α`. -/ -noncomputable def asTypeEquivObjAsType : AsType α ≌ ObjAsType α := - Equivalence.mk (asTypeToObjAsType α) (objAsTypeToAsType α) - (NatIso.ofComponents Iso.refl) - (NatIso.ofComponents Iso.refl) +noncomputable def asTypeEquivObjAsType : AsType α ≌ ObjAsType α where + functor := asTypeToObjAsType α + inverse := objAsTypeToAsType α + unitIso := NatIso.ofComponents Iso.refl + counitIso := NatIso.ofComponents Iso.refl noncomputable instance asTypeFinCategory : FinCategory (AsType α) where fintypeHom := fun _ _ => show Fintype (Fin _) from inferInstance 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..30efd8e330d9f 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.Basic /-! # 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 49bfb77d86356..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 @@ -97,9 +97,9 @@ See . We do not define 'strictly full -/ @[ext] structure FullSubcategory where - /-- The category of which this is a full subcategory-/ + /-- The category of which this is a full subcategory -/ obj : C - /-- The predicate satisfied by all objects in this subcategory-/ + /-- The predicate satisfied by all objects in this subcategory -/ property : Z obj instance FullSubcategory.category : Category.{v} (FullSubcategory Z) := 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..e1f0445ab692b 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 diff --git a/Mathlib/CategoryTheory/Functor/Const.lean b/Mathlib/CategoryTheory/Functor/Const.lean index 006504deb58b6..5c783b8742f00 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 diff --git a/Mathlib/CategoryTheory/Functor/Currying.lean b/Mathlib/CategoryTheory/Functor/Currying.lean index c5a8da1caf5d5..e130aedb422c8 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 /-! @@ -76,12 +77,16 @@ def curry : (C × D ⥤ E) ⥤ C ⥤ D ⥤ E where /-- The equivalence of functor categories given by currying/uncurrying. -/ @[simps!] -def currying : C ⥤ D ⥤ E ≌ C × D ⥤ E := - Equivalence.mk uncurry curry - (NatIso.ofComponents fun F => - NatIso.ofComponents fun X => NatIso.ofComponents fun Y => Iso.refl _) - (NatIso.ofComponents fun F => NatIso.ofComponents (fun X => eqToIso (by simp)) - (by intros X Y f; cases X; cases Y; cases f; dsimp at *; rw [← F.map_comp]; simp)) +def currying : C ⥤ D ⥤ E ≌ C × D ⥤ E where + functor := uncurry + inverse := curry + unitIso := NatIso.ofComponents (fun _ ↦ NatIso.ofComponents + (fun _ ↦ NatIso.ofComponents (fun _ ↦ Iso.refl _))) + counitIso := NatIso.ofComponents + (fun F ↦ NatIso.ofComponents (fun _ ↦ Iso.refl _) (by + rintro ⟨X₁, X₂⟩ ⟨Y₁, Y₂⟩ ⟨f₁, f₂⟩ + dsimp at f₁ f₂ ⊢ + simp only [← F.map_comp, prod_comp, Category.comp_id, Category.id_comp])) /-- `F.flip` is isomorphic to uncurrying `F`, swapping the variables, and currying. -/ @[simps!] diff --git a/Mathlib/CategoryTheory/Functor/Derived/RightDerived.lean b/Mathlib/CategoryTheory/Functor/Derived/RightDerived.lean index c926a1b32013f..8acc96f8e2d2d 100644 --- a/Mathlib/CategoryTheory/Functor/Derived/RightDerived.lean +++ b/Mathlib/CategoryTheory/Functor/Derived/RightDerived.lean @@ -97,7 +97,7 @@ lemma rightDerived_ext (G : D ⥤ H) (γ₁ γ₂ : RF ⟶ G) RF.hom_ext_of_isLeftKanExtension α γ₁ γ₂ hγ /-- The natural transformation `RF ⟶ RF'` on right derived functors that is -induced by a natural transformation `F ⟶ F'`. -/ +induced by a natural transformation `F ⟶ F'`. -/ noncomputable def rightDerivedNatTrans (τ : F ⟶ F') : RF ⟶ RF' := RF.rightDerivedDesc α W RF' (τ ≫ α') @@ -128,7 +128,7 @@ lemma rightDerivedNatTrans_comp (τ : F ⟶ F') (τ' : F' ⟶ F'') : rightDerived_ext RF α W _ _ _ (by aesop_cat) /-- The natural isomorphism `RF ≅ RF'` on right derived functors that is -induced by a natural isomorphism `F ≅ F'`. -/ +induced by a natural isomorphism `F ≅ F'`. -/ @[simps] noncomputable def rightDerivedNatIso (τ : F ≅ F') : RF ≅ RF' where diff --git a/Mathlib/CategoryTheory/Functor/EpiMono.lean b/Mathlib/CategoryTheory/Functor/EpiMono.lean index 0f25145dea713..428607bf319fa 100644 --- a/Mathlib/CategoryTheory/Functor/EpiMono.lean +++ b/Mathlib/CategoryTheory/Functor/EpiMono.lean @@ -103,8 +103,7 @@ theorem reflectsMonomorphisms_of_preserves_of_reflects (F : C ⥤ D) (G : D ⥤ theorem preservesMonomorphisms.of_iso {F G : C ⥤ D} [PreservesMonomorphisms F] (α : F ≅ G) : PreservesMonomorphisms G := { preserves := fun {X} {Y} f h => by - haveI : Mono (F.map f ≫ (α.app Y).hom) := mono_comp _ _ - convert (mono_comp _ _ : Mono ((α.app X).inv ≫ F.map f ≫ (α.app Y).hom)) + suffices G.map f = (α.app X).inv ≫ F.map f ≫ (α.app Y).hom from this ▸ mono_comp _ _ rw [Iso.eq_inv_comp, Iso.app_hom, Iso.app_hom, NatTrans.naturality] } theorem preservesMonomorphisms.iso_iff {F G : C ⥤ D} (α : F ≅ G) : @@ -114,8 +113,7 @@ theorem preservesMonomorphisms.iso_iff {F G : C ⥤ D} (α : F ≅ G) : theorem preservesEpimorphisms.of_iso {F G : C ⥤ D} [PreservesEpimorphisms F] (α : F ≅ G) : PreservesEpimorphisms G := { preserves := fun {X} {Y} f h => by - haveI : Epi (F.map f ≫ (α.app Y).hom) := epi_comp _ _ - convert (epi_comp _ _ : Epi ((α.app X).inv ≫ F.map f ≫ (α.app Y).hom)) + suffices G.map f = (α.app X).inv ≫ F.map f ≫ (α.app Y).hom from this ▸ epi_comp _ _ rw [Iso.eq_inv_comp, Iso.app_hom, Iso.app_hom, NatTrans.naturality] } theorem preservesEpimorphisms.iso_iff {F G : C ⥤ D} (α : F ≅ G) : @@ -126,8 +124,7 @@ theorem reflectsMonomorphisms.of_iso {F G : C ⥤ D} [ReflectsMonomorphisms F] ( ReflectsMonomorphisms G := { reflects := fun {X} {Y} f h => by apply F.mono_of_mono_map - haveI : Mono (G.map f ≫ (α.app Y).inv) := mono_comp _ _ - convert (mono_comp _ _ : Mono ((α.app X).hom ≫ G.map f ≫ (α.app Y).inv)) + suffices F.map f = (α.app X).hom ≫ G.map f ≫ (α.app Y).inv from this ▸ mono_comp _ _ rw [← Category.assoc, Iso.eq_comp_inv, Iso.app_hom, Iso.app_hom, NatTrans.naturality] } theorem reflectsMonomorphisms.iso_iff {F G : C ⥤ D} (α : F ≅ G) : @@ -138,8 +135,7 @@ theorem reflectsEpimorphisms.of_iso {F G : C ⥤ D} [ReflectsEpimorphisms F] (α ReflectsEpimorphisms G := { reflects := fun {X} {Y} f h => by apply F.epi_of_epi_map - haveI : Epi (G.map f ≫ (α.app Y).inv) := epi_comp _ _ - convert (epi_comp _ _ : Epi ((α.app X).hom ≫ G.map f ≫ (α.app Y).inv)) + suffices F.map f = (α.app X).hom ≫ G.map f ≫ (α.app Y).inv from this ▸ epi_comp _ _ rw [← Category.assoc, Iso.eq_comp_inv, Iso.app_hom, Iso.app_hom, NatTrans.naturality] } theorem reflectsEpimorphisms.iso_iff {F G : C ⥤ D} (α : F ≅ G) : @@ -272,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/FullyFaithful.lean b/Mathlib/CategoryTheory/Functor/FullyFaithful.lean index a637719323dad..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 @@ -171,6 +171,15 @@ lemma full : F.Full where lemma faithful : F.Faithful where map_injective := hF.map_injective +instance : Subsingleton F.FullyFaithful where + allEq h₁ h₂ := by + have := h₁.faithful + cases h₁ with | mk f₁ hf₁ _ => cases h₂ with | mk f₂ hf₂ _ => + simp only [Functor.FullyFaithful.mk.injEq] + ext + apply F.map_injective + rw [hf₁, hf₂] + /-- The unique isomorphism `X ≅ Y` which induces an isomorphism `F.obj X ≅ F.obj Y` when `hF : F.FullyFaithful`. -/ @[simps] @@ -240,7 +249,7 @@ variable {D : Type u₂} [Category.{v₂} D] {E : Type u₃} [Category.{v₃} E] variable (F F' : C ⥤ D) (G : D ⥤ E) instance Faithful.comp [F.Faithful] [G.Faithful] : - (F ⋙ G).Faithful where map_injective p := F.map_injective (G.map_injective p) + (F ⋙ G).Faithful where map_injective p := F.map_injective (G.map_injective p) theorem Faithful.of_comp [(F ⋙ G).Faithful] : F.Faithful := -- Porting note: (F ⋙ G).map_injective.of_comp has the incorrect type diff --git a/Mathlib/CategoryTheory/Functor/FunctorHom.lean b/Mathlib/CategoryTheory/Functor/FunctorHom.lean new file mode 100644 index 0000000000000..bd8ab6a9e031e --- /dev/null +++ b/Mathlib/CategoryTheory/Functor/FunctorHom.lean @@ -0,0 +1,208 @@ +/- +Copyright (c) 2024 Jack McKoen. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jack McKoen, Joël Riou +-/ +import Mathlib.CategoryTheory.Monoidal.FunctorCategory +import Mathlib.CategoryTheory.Monoidal.Types.Basic +import Mathlib.CategoryTheory.Enriched.Basic + +/-! +# Internal hom in functor categories + +Given functors `F G : C ⥤ D`, define a functor `functorHom F G` from `C` to `Type max v' v u`, +which is a proxy for the "internal hom" functor Hom(F ⊗ coyoneda(-), G). This is used to show +that the functor category `C ⥤ D` is enriched over `C ⥤ Type max v' v u`. This is also useful +for showing that `C ⥤ Type max w v u` is monoidal closed. + +See `Mathlib.CategoryTheory.Closed.FunctorToTypes`. + +-/ + + +universe w v' v u u' + +open CategoryTheory MonoidalCategory + +variable {C : Type u} [Category.{v} C] {D : Type u'} [Category.{v'} D] + +variable (F G : C ⥤ D) + +namespace CategoryTheory.Functor + +/-- Given functors `F G : C ⥤ D`, `HomObj F G A` is a proxy for the type +of "morphisms" `F ⊗ A ⟶ G`, where `A : C ⥤ Type w` (`w` an arbitrary universe). -/ +@[ext] +structure HomObj (A : C ⥤ Type w) where + /-- The morphism `F.obj c ⟶ G.obj c` associated with `a : A.obj c`. -/ + app (c : C) (a : A.obj c) : F.obj c ⟶ G.obj c + naturality {c d : C} (f : c ⟶ d) (a : A.obj c) : + F.map f ≫ app d (A.map f a) = app c a ≫ G.map f := by aesop_cat + +/-- 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⟩ + erw [congr_fun (a.naturality f y) x] + rfl ⟩ + invFun a := ⟨fun X y x ↦ a.app X (x, y), fun φ y ↦ by + ext x + erw [congr_fun (a.naturality φ) (x, y)] + rfl ⟩ + left_inv _ := by aesop + right_inv _ := by aesop + +namespace HomObj + +attribute [reassoc (attr := simp)] naturality + +variable {F G} {A : C ⥤ Type w} + +lemma congr_app {f g : HomObj F G A} (h : f = g) (X : C) + (a : A.obj X) : f.app X a = g.app X a := by subst h; rfl + +/-- Given a natural transformation `F ⟶ G`, get a term of `HomObj F G A` by "ignoring" `A`. -/ +@[simps] +def ofNatTrans (f : F ⟶ G) : HomObj F G A where + app X _ := f.app X + +/-- The identity `HomObj F F A`. -/ +@[simps!] +def id (A : C ⥤ Type w) : HomObj F F A := ofNatTrans (𝟙 F) + +/-- Composition of `f : HomObj F G A` with `g : HomObj G M A`. -/ +@[simps] +def comp {M : C ⥤ D} (f : HomObj F G A) (g : HomObj G M A) : HomObj F M A where + app X a := f.app X a ≫ g.app X a + +/-- Given a morphism `A' ⟶ A`, send a term of `HomObj F G A` to a term of `HomObj F G A'`. -/ +@[simps] +def map {A' : C ⥤ Type w} (f : A' ⟶ A) (x : HomObj F G A) : HomObj F G A' where + app Δ a := x.app Δ (f.app Δ a) + naturality {Δ Δ'} φ a := by + dsimp + rw [← x.naturality φ (f.app Δ a), FunctorToTypes.naturality _ _ f φ a] + +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 := + { app := fun X a ↦ x.app X (f.unop.app _ a) + naturality := fun {X Y} φ a ↦ by + dsimp + rw [← HomObj.naturality] + congr 2 + exact congr_fun (f.unop.naturality φ) a } + +/-- Composition of `homObjFunctor` with the co-Yoneda embedding, i.e. Hom(F ⊗ coyoneda(-), G). +When `F G : C ⥤ Type max v' v u`, this is the internal hom of `F` and `G`: see +`Mathlib.CategoryTheory.Closed.FunctorToTypes`. -/ +def functorHom (F G : C ⥤ D) : C ⥤ Type max v' v u := coyoneda.rightOp ⋙ homObjFunctor.{v} F G + +variable {F G} in +@[ext] +lemma functorHom_ext {X : C} {x y : (F.functorHom G).obj X} + (h : ∀ (Y : C) (f : X ⟶ Y), x.app Y f = y.app Y f) : x = y := + 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 (𝟙 _) + naturality := fun {X Y} f a => by + rw [← (φ.app X a).naturality f (𝟙 _)] + have := HomObj.congr_app (congr_fun (φ.naturality f) a) Y (𝟙 _) + dsimp [functorHom, homObjFunctor] at this + aesop } + invFun x := + { app := fun X a ↦ { app := fun Y f => x.app Y (A.map f a) } + naturality := fun X Y f => by + ext + dsimp only [types_comp_apply] + rw [← FunctorToTypes.map_comp_apply] + rfl } + left_inv φ := by + ext X a Y f + exact (HomObj.congr_app (congr_fun (φ.naturality f) a) Y (𝟙 _)).trans + (congr_arg ((φ.app X a).app Y) (by simp)) + right_inv x := by aesop + +variable {F G} in +/-- Morphisms `(𝟙_ (C ⥤ Type max v' v u) ⟶ F.functorHom G)` are in bijection with +morphisms `F ⟶ G`. -/ +@[simps] +def natTransEquiv : (𝟙_ (C ⥤ Type max v' v u) ⟶ F.functorHom G) ≃ (F ⟶ G) where + toFun f := ⟨fun X ↦ (f.app X (PUnit.unit)).app X (𝟙 _), by + intro X Y φ + rw [← (f.app X (PUnit.unit)).naturality φ] + congr 1 + have := HomObj.congr_app (congr_fun (f.naturality φ) PUnit.unit) Y (𝟙 Y) + dsimp [functorHom, homObjFunctor] at this + aesop ⟩ + invFun f := ⟨fun _ _ ↦ HomObj.ofNatTrans f, _⟩ + left_inv f := by + ext X a Y φ + have := HomObj.congr_app (congr_fun (f.naturality φ) PUnit.unit) Y (𝟙 Y) + dsimp [functorHom, homObjFunctor] at this + aesop + right_inv _ := rfl + +end CategoryTheory.Functor + +open Functor + +namespace CategoryTheory.Enriched.Functor + +@[simp] +lemma natTransEquiv_symm_app_app_apply (F G : C ⥤ D) (f : F ⟶ G) + {X : C} {a : (𝟙_ (C ⥤ Type (max v' v u))).obj X} (Y : C) {φ : X ⟶ Y} : + ((natTransEquiv.symm f).app X a).app Y φ = f.app Y := rfl + +@[simp] +lemma natTransEquiv_symm_whiskerRight_functorHom_app (K L : C ⥤ D) (X : C) (f : K ⟶ K) + (x : 𝟙_ _ ⊗ (K.functorHom L).obj X) : + ((natTransEquiv.symm f ▷ K.functorHom L).app X x) = + (HomObj.ofNatTrans f, x.2) := rfl + +@[simp] +lemma functorHom_whiskerLeft_natTransEquiv_symm_app (K L : C ⥤ D) (X : C) (f : L ⟶ L) + (x : (K.functorHom L).obj X ⊗ 𝟙_ _) : + ((K.functorHom L ◁ natTransEquiv.symm f).app X x) = + (x.1, HomObj.ofNatTrans f) := rfl + +@[simp] +lemma whiskerLeft_app_apply (K L M N : C ⥤ D) + (g : L.functorHom M ⊗ M.functorHom N ⟶ L.functorHom N) + {X : C} (a : (K.functorHom L ⊗ L.functorHom M ⊗ M.functorHom N).obj X) : + (K.functorHom L ◁ g).app X a = ⟨a.1, g.app X a.2⟩ := rfl + +@[simp] +lemma whiskerRight_app_apply (K L M N : C ⥤ D) + (f : K.functorHom L ⊗ L.functorHom M ⟶ K.functorHom M) + {X : C} (a : ((K.functorHom L ⊗ L.functorHom M) ⊗ M.functorHom N).obj X) : + (f ▷ M.functorHom N).app X a = ⟨f.app X a.1, a.2⟩ := rfl + +@[simp] +lemma associator_inv_apply (K L M N : C ⥤ D) {X : C} + (x : ((K.functorHom L) ⊗ (L.functorHom M) ⊗ (M.functorHom N)).obj X) : + (α_ ((K.functorHom L).obj X) ((L.functorHom M).obj X) ((M.functorHom N).obj X)).inv x = + ⟨⟨x.1, x.2.1⟩, x.2.2⟩ := rfl + +@[simp] +lemma associator_hom_apply (K L M N : C ⥤ D) {X : C} + (x : (((K.functorHom L) ⊗ (L.functorHom M)) ⊗ (M.functorHom N)).obj X) : + (α_ ((K.functorHom L).obj X) ((L.functorHom M).obj X) ((M.functorHom N).obj X)).hom x = + ⟨x.1.1, x.1.2, x.2⟩ := rfl + +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 } + +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..fe8433c905fb7 100644 --- a/Mathlib/CategoryTheory/Functor/KanExtension/Adjunction.lean +++ b/Mathlib/CategoryTheory/Functor/KanExtension/Adjunction.lean @@ -168,7 +168,7 @@ 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 diff --git a/Mathlib/CategoryTheory/Functor/KanExtension/Pointwise.lean b/Mathlib/CategoryTheory/Functor/KanExtension/Pointwise.lean index cf9297f47d979..9d4cb7a6c2ea1 100644 --- a/Mathlib/CategoryTheory/Functor/KanExtension/Pointwise.lean +++ b/Mathlib/CategoryTheory/Functor/KanExtension/Pointwise.lean @@ -343,6 +343,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 +442,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/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..a0cd79ac0d2fe 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,6 +139,12 @@ 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 _ @@ -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 G := 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..367dfd4597ae6 100644 --- a/Mathlib/CategoryTheory/Galois/Decomposition.lean +++ b/Mathlib/CategoryTheory/Galois/Decomposition.lean @@ -308,6 +308,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..a3bbd1400e05c 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 @@ -96,6 +92,10 @@ noncomputable instance : FiberFunctor (Action.forget FintypeCat (MonCat.of G)) w preservesQuotientsByFiniteGroups _ _ _ := inferInstance reflectsIsos := ⟨fun f (h : 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 hasFiberFunctor := ⟨Action.forget FintypeCat (MonCat.of G), ⟨inferInstance⟩⟩ @@ -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 1ceed246f266d..25fbc42d60592 100644 --- a/Mathlib/CategoryTheory/Galois/GaloisObjects.lean +++ b/Mathlib/CategoryTheory/Galois/GaloisObjects.lean @@ -35,7 +35,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. -/ @@ -83,7 +83,7 @@ theorem isGalois_iff_pretransitive (X : C) [IsConnected X] : rw [isGalois_iff_aux, Equiv.nonempty_congr <| quotientByAutTerminalEquivUniqueQuotient F X] exact (MulAction.pretransitive_iff_unique_quotient_of_nonempty (Aut X) (F.obj X)).symm -/-- If `X` is Galois, the quotient `X / Aut X` is terminal. -/ +/-- If `X` is Galois, the quotient `X / Aut X` is terminal. -/ noncomputable def isTerminalQuotientOfIsGalois (X : C) [IsGalois X] : IsTerminal <| colimit <| SingleObj.functor <| Aut.toEnd X := Nonempty.some IsGalois.quotientByAutTerminal @@ -95,6 +95,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..7e9841375b05f --- /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 X Y 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 f8261a14065e9..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 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] @@ -189,7 +218,7 @@ noncomputable def autGaloisSystem : PointedGaloisObject F ⥤ Grp.{u₂} where ext (σ : Aut A.obj) simp -/-- The limit of `autGaloisSystem`. -/ +/-- The limit of `autGaloisSystem`. -/ noncomputable def AutGalois : Type (max u₁ u₂) := (autGaloisSystem F ⋙ forget _).sections @@ -246,7 +275,7 @@ We first establish the isomorphism between `End F` and `AutGalois F`, from which - `endEquivSectionsFibers : End F ≅ (incl F ⋙ F').sections`: the endomorphisms of `F` are isomorphic to the limit over `F.obj A` for all Galois objects `A`. - This is obtained as the composition (slighty simplified): + This is obtained as the composition (slightly simplified): `End F ≅ (colimit ((incl F).op ⋙ coyoneda) ⟶ F) ≅ (incl F ⋙ F).sections` @@ -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..06ad6569ca157 --- /dev/null +++ b/Mathlib/CategoryTheory/Galois/Topology.lean @@ -0,0 +1,183 @@ +/- +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_closedEmbedding : ClosedEmbedding (autEmbedding F) where + induced := rfl + inj := autEmbedding_injective F + isClosed_range := autEmbedding_range_isClosed F + +instance : CompactSpace (Aut F) := ClosedEmbedding.compactSpace (autEmbedding_closedEmbedding F) + +instance : T2Space (Aut F) := + T2Space.of_injective_continuous (autEmbedding_injective F) continuous_induced_dom + +instance : TotallyDisconnectedSpace (Aut F) := + (Embedding.isTotallyDisconnected_range (autEmbedding_closedEmbedding F).embedding).mp + (isTotallyDisconnected_of_totallyDisconnectedSpace _) + +instance : ContinuousMul (Aut F) := + Inducing.continuousMul (autEmbedding F) + (autEmbedding_closedEmbedding F).toInducing + +instance : ContinuousInv (Aut F) := + Inducing.continuousInv (autEmbedding_closedEmbedding F).toInducing (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 c6219a587e428..bd219bca91faa 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 @@ -310,7 +306,8 @@ theorem wellPowered_of_isDetecting [HasPullbacks C] {𝒢 : Set C} [Small.{v₁} (h𝒢 : IsDetecting 𝒢) : WellPowered C := ⟨fun X => @small_of_injective _ _ _ (fun P : Subobject X => { f : ΣG : 𝒢, G.1 ⟶ X | P.Factors f.2 }) - fun P Q h => Subobject.eq_of_isDetecting h𝒢 _ _ (by simpa [Set.ext_iff] using h)⟩ + fun P Q h => Subobject.eq_of_isDetecting h𝒢 _ _ + (by simpa [Set.ext_iff, Sigma.forall] using h)⟩ end WellPowered diff --git a/Mathlib/CategoryTheory/GlueData.lean b/Mathlib/CategoryTheory/GlueData.lean index 672861742b53b..826e0567ead86 100644 --- a/Mathlib/CategoryTheory/GlueData.lean +++ b/Mathlib/CategoryTheory/GlueData.lean @@ -388,7 +388,7 @@ structure GlueData' where cocycle : ∀ i j k hij hik hjk, t' i j k hij hik hjk ≫ t' j k i hjk hij.symm hik.symm ≫ t' k i j hik.symm hjk.symm hij = 𝟙 _ -attribute [local instance] GlueData'.f_mono GlueData'.f_hasPullback mono_comp +attribute [local instance] GlueData'.f_mono GlueData'.f_hasPullback attribute [reassoc (attr := simp)] GlueData'.t_inv GlueData'.cocycle diff --git a/Mathlib/CategoryTheory/GradedObject.lean b/Mathlib/CategoryTheory/GradedObject.lean index fcee74c33d22f..c3fd1e2c4e0aa 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 diff --git a/Mathlib/CategoryTheory/GradedObject/Bifunctor.lean b/Mathlib/CategoryTheory/GradedObject/Bifunctor.lean index 7d642ffec1ca6..735f21eb95ec0 100644 --- a/Mathlib/CategoryTheory/GradedObject/Bifunctor.lean +++ b/Mathlib/CategoryTheory/GradedObject/Bifunctor.lean @@ -46,7 +46,6 @@ variable {I J K : Type*} (p : I × J → K) /-- Given a bifunctor `F : C₁ ⥤ C₂ ⥤ C₃`, graded objects `X : GradedObject I C₁` and `Y : GradedObject J C₂` and a map `p : I × J → K`, this is the `K`-graded object sending `k` to the coproduct of `(F.obj (X i)).obj (Y j)` for `p ⟨i, j⟩ = k`. -/ -@[simp] noncomputable def mapBifunctorMapObj (X : GradedObject I C₁) (Y : GradedObject J C₂) [HasMap (((mapBifunctor F I J).obj X).obj Y) p] : GradedObject K C₃ := (((mapBifunctor F I J).obj X).obj Y).mapObj p diff --git a/Mathlib/CategoryTheory/GradedObject/Braiding.lean b/Mathlib/CategoryTheory/GradedObject/Braiding.lean new file mode 100644 index 0000000000000..303a59d11668e --- /dev/null +++ b/Mathlib/CategoryTheory/GradedObject/Braiding.lean @@ -0,0 +1,180 @@ +/- +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.GradedObject.Monoidal +import Mathlib.CategoryTheory.Monoidal.Braided.Basic +/-! +# The braided and symmetric category structures on graded objects + +In this file, we construct the braiding +`GradedObject.Monoidal.braiding : tensorObj X Y ≅ tensorObj Y X` +for two objects `X` and `Y` in `GradedObject I C`, when `I` is a commutative +additive monoid (and suitable coproducts exist in a braided category `C`). + +When `C` is a braided category and suitable assumptions are made, we obtain the braided category +structure on `GradedObject I C` and show that it is symmetric if `C` is symmetric. + +-/ + +namespace CategoryTheory + +open Category Limits + +variable {I : Type*} [AddCommMonoid I] {C : Type*} [Category C] [MonoidalCategory C] + +namespace GradedObject + +namespace Monoidal + +variable (X Y Z : GradedObject I C) + +section Braided + +variable [BraidedCategory C] + +/-- The braiding `tensorObj X Y ≅ tensorObj Y X` when `X` and `Y` are graded objects +indexed by a commutative additive monoid. -/ +noncomputable def braiding [HasTensor X Y] [HasTensor Y X] : tensorObj X Y ≅ tensorObj Y X where + hom k := tensorObjDesc (fun i j hij => (β_ _ _).hom ≫ + ιTensorObj Y X j i k (by simpa only [add_comm j i] using hij)) + inv k := tensorObjDesc (fun i j hij => (β_ _ _).inv ≫ + ιTensorObj X Y j i k (by simpa only [add_comm j i] using hij)) + +variable {Y Z} in +lemma braiding_naturality_right [HasTensor X Y] [HasTensor Y X] [HasTensor X Z] [HasTensor Z X] + (f : Y ⟶ Z) : + whiskerLeft X f ≫ (braiding X Z).hom = (braiding X Y).hom ≫ whiskerRight f X := by + dsimp [braiding] + aesop_cat + +variable {X Y} in +lemma braiding_naturality_left [HasTensor Y Z] [HasTensor Z Y] [HasTensor X Z] [HasTensor Z X] + (f : X ⟶ Y) : + whiskerRight f Z ≫ (braiding Y Z).hom = (braiding X Z).hom ≫ whiskerLeft Z f := by + dsimp [braiding] + aesop_cat + +lemma hexagon_forward [HasTensor X Y] [HasTensor Y X] [HasTensor Y Z] + [HasTensor Z X] [HasTensor X Z] + [HasTensor (tensorObj X Y) Z] [HasTensor X (tensorObj Y Z)] + [HasTensor (tensorObj Y Z) X] [HasTensor Y (tensorObj Z X)] + [HasTensor (tensorObj Y X) Z] [HasTensor Y (tensorObj X Z)] + [HasGoodTensor₁₂Tensor X Y Z] [HasGoodTensorTensor₂₃ X Y Z] + [HasGoodTensor₁₂Tensor Y Z X] [HasGoodTensorTensor₂₃ Y Z X] + [HasGoodTensor₁₂Tensor Y X Z] [HasGoodTensorTensor₂₃ Y X Z] : + (associator X Y Z).hom ≫ (braiding X (tensorObj Y Z)).hom ≫ (associator Y Z X).hom = + whiskerRight (braiding X Y).hom Z ≫ (associator Y X Z).hom ≫ + whiskerLeft Y (braiding X Z).hom := by + ext k i₁ i₂ i₃ h + dsimp [braiding] + conv_lhs => rw [ιTensorObj₃'_associator_hom_assoc, ιTensorObj₃_eq X Y Z i₁ i₂ i₃ k h _ rfl, + assoc, ι_tensorObjDesc_assoc, assoc, ← MonoidalCategory.id_tensorHom, + BraidedCategory.braiding_naturality_assoc, + BraidedCategory.braiding_tensor_right, assoc, assoc, assoc, assoc, Iso.hom_inv_id_assoc, + MonoidalCategory.tensorHom_id, + ← ιTensorObj₃'_eq_assoc Y Z X i₂ i₃ i₁ k (by rw [add_comm _ i₁, ← add_assoc, h]) _ rfl, + ιTensorObj₃'_associator_hom, Iso.inv_hom_id_assoc] + conv_rhs => rw [ιTensorObj₃'_eq X Y Z i₁ i₂ i₃ k h _ rfl, assoc, ι_tensorHom_assoc, + ← MonoidalCategory.tensorHom_id, + ← MonoidalCategory.tensor_comp_assoc, id_comp, ι_tensorObjDesc, + categoryOfGradedObjects_id, MonoidalCategory.comp_tensor_id, assoc, + MonoidalCategory.tensorHom_id, MonoidalCategory.tensorHom_id, + ← ιTensorObj₃'_eq_assoc Y X Z i₂ i₁ i₃ k + (by rw [add_comm i₂ i₁, h]) (i₁ + i₂) (add_comm i₂ i₁), + ιTensorObj₃'_associator_hom_assoc, + ιTensorObj₃_eq Y X Z i₂ i₁ i₃ k (by rw [add_comm i₂ i₁, h]) _ rfl, assoc, + ι_tensorHom, categoryOfGradedObjects_id, ← MonoidalCategory.tensorHom_id, + ← MonoidalCategory.id_tensorHom, + ← MonoidalCategory.id_tensor_comp_assoc, + ι_tensorObjDesc, MonoidalCategory.id_tensor_comp, assoc, + ← MonoidalCategory.id_tensor_comp_assoc, MonoidalCategory.tensorHom_id, + MonoidalCategory.id_tensorHom, MonoidalCategory.whiskerLeft_comp, assoc, + ← ιTensorObj₃_eq Y Z X i₂ i₃ i₁ k (by rw [add_comm _ i₁, ← add_assoc, h]) + (i₁ + i₃) (add_comm _ _ )] + +lemma hexagon_reverse [HasTensor X Y] [HasTensor Y Z] [HasTensor Z X] + [HasTensor Z Y] [HasTensor X Z] + [HasTensor (tensorObj X Y) Z] [HasTensor X (tensorObj Y Z)] + [HasTensor Z (tensorObj X Y)] [HasTensor (tensorObj Z X) Y] + [HasTensor X (tensorObj Z Y)] [HasTensor (tensorObj X Z) Y] + [HasGoodTensor₁₂Tensor X Y Z] [HasGoodTensorTensor₂₃ X Y Z] + [HasGoodTensor₁₂Tensor Z X Y] [HasGoodTensorTensor₂₃ Z X Y] + [HasGoodTensor₁₂Tensor X Z Y] [HasGoodTensorTensor₂₃ X Z Y]: + (associator X Y Z).inv ≫ (braiding (tensorObj X Y) Z).hom ≫ (associator Z X Y).inv = + whiskerLeft X (braiding Y Z).hom ≫ (associator X Z Y).inv ≫ + whiskerRight (braiding X Z).hom Y := by + ext k i₁ i₂ i₃ h + dsimp [braiding] + conv_lhs => rw [ιTensorObj₃_associator_inv_assoc, ιTensorObj₃'_eq X Y Z i₁ i₂ i₃ k h _ rfl, assoc, + ι_tensorObjDesc_assoc, assoc, ← MonoidalCategory.tensorHom_id, + BraidedCategory.braiding_naturality_assoc, + BraidedCategory.braiding_tensor_left, assoc, assoc, assoc, assoc, Iso.inv_hom_id_assoc, + MonoidalCategory.id_tensorHom, + ← ιTensorObj₃_eq_assoc Z X Y i₃ i₁ i₂ k (by rw [add_assoc, add_comm i₃, h]) _ rfl, + ιTensorObj₃_associator_inv, Iso.hom_inv_id_assoc] + conv_rhs => rw [ιTensorObj₃_eq X Y Z i₁ i₂ i₃ k h _ rfl, assoc, ι_tensorHom_assoc, + ← MonoidalCategory.id_tensorHom, + ← MonoidalCategory.tensor_comp_assoc, id_comp, ι_tensorObjDesc, + categoryOfGradedObjects_id, MonoidalCategory.id_tensor_comp, assoc, + MonoidalCategory.id_tensorHom, MonoidalCategory.id_tensorHom, + ← ιTensorObj₃_eq_assoc X Z Y i₁ i₃ i₂ k + (by rw [add_assoc, add_comm i₃, ← add_assoc, h]) (i₂ + i₃) (add_comm _ _), + ιTensorObj₃_associator_inv_assoc, + ιTensorObj₃'_eq X Z Y i₁ i₃ i₂ k (by rw [add_assoc, add_comm i₃, ← add_assoc, h]) _ rfl, + assoc, ι_tensorHom, categoryOfGradedObjects_id, ← MonoidalCategory.tensorHom_id, + ← MonoidalCategory.comp_tensor_id_assoc, + ι_tensorObjDesc, MonoidalCategory.comp_tensor_id, assoc, + MonoidalCategory.tensorHom_id, MonoidalCategory.tensorHom_id, + ← ιTensorObj₃'_eq Z X Y i₃ i₁ i₂ k (by rw [add_assoc, add_comm i₃, h]) + (i₁ + i₃) (add_comm _ _)] + +end Braided + +@[reassoc (attr := simp)] +lemma symmetry [SymmetricCategory C] [HasTensor X Y] [HasTensor Y X] : + (braiding X Y).hom ≫ (braiding Y X).hom = 𝟙 _ := by + dsimp [braiding] + aesop_cat + +end Monoidal + +section Instances + +variable + [∀ (X₁ X₂ : GradedObject I C), HasTensor X₁ X₂] + [∀ (X₁ X₂ X₃ : GradedObject I C), HasGoodTensor₁₂Tensor X₁ X₂ X₃] + [∀ (X₁ X₂ X₃ : GradedObject I C), HasGoodTensorTensor₂₃ X₁ X₂ X₃] + [DecidableEq I] [HasInitial C] + [∀ X₁, PreservesColimit (Functor.empty.{0} C) + ((MonoidalCategory.curriedTensor C).obj X₁)] + [∀ X₂, PreservesColimit (Functor.empty.{0} C) + ((MonoidalCategory.curriedTensor C).flip.obj X₂)] + [∀ (X₁ X₂ X₃ X₄ : GradedObject I C), HasTensor₄ObjExt X₁ X₂ X₃ X₄] + +noncomputable instance braidedCategory [BraidedCategory C] : + BraidedCategory (GradedObject I C) where + braiding X Y := Monoidal.braiding X Y + braiding_naturality_left _ _:= Monoidal.braiding_naturality_left _ _ + braiding_naturality_right _ _ _ _ := Monoidal.braiding_naturality_right _ _ + hexagon_forward _ _ _ := Monoidal.hexagon_forward _ _ _ + hexagon_reverse _ _ _ := Monoidal.hexagon_reverse _ _ _ + +noncomputable instance symmetricCategory [SymmetricCategory C] : + SymmetricCategory (GradedObject I C) where + symmetry _ _ := Monoidal.symmetry _ _ + +/-! +The braided/symmetric monoidal category structure on `GradedObject ℕ C` can +be inferred from the assumptions `[HasFiniteCoproducts C]`, +`[∀ (X : C), PreservesFiniteCoproducts ((curriedTensor C).obj X)]` and +`[∀ (X : C), PreservesFiniteCoproducts ((curriedTensor C).flip.obj X)]`. +This requires importing `Mathlib.CategoryTheory.Limits.Preserves.Finite`. +-/ + +end Instances + +end GradedObject + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/GradedObject/Monoidal.lean b/Mathlib/CategoryTheory/GradedObject/Monoidal.lean index 88a32f2bf3bcd..b005a034c6b49 100644 --- a/Mathlib/CategoryTheory/GradedObject/Monoidal.lean +++ b/Mathlib/CategoryTheory/GradedObject/Monoidal.lean @@ -292,7 +292,14 @@ lemma associator_naturality (f₁ : X₁ ⟶ Y₁) (f₂ : X₂ ⟶ Y₂) (f₃ [HasGoodTensor₁₂Tensor X₁ X₂ X₃] [HasGoodTensorTensor₂₃ X₁ X₂ X₃] [HasGoodTensor₁₂Tensor Y₁ Y₂ Y₃] [HasGoodTensorTensor₂₃ Y₁ Y₂ Y₃] : tensorHom (tensorHom f₁ f₂) f₃ ≫ (associator Y₁ Y₂ Y₃).hom = - (associator X₁ X₂ X₃).hom ≫ tensorHom f₁ (tensorHom f₂ f₃) := by aesop_cat + (associator X₁ X₂ X₃).hom ≫ tensorHom f₁ (tensorHom f₂ f₃) := by + #adaptation_note + /-- this used to be aesop_cat, but that broke with + https://github.com/leanprover/lean4/pull/4154 -/ + ext x i₁ i₂ i₃ h : 2 + simp only [categoryOfGradedObjects_comp, ιTensorObj₃'_tensorHom_assoc, + associator_conjugation, ιTensorObj₃'_associator_hom, assoc, Iso.inv_hom_id_assoc, + ιTensorObj₃'_associator_hom_assoc, ιTensorObj₃_tensorHom] end @@ -318,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 @@ -399,10 +406,10 @@ lemma pentagon_inv : tensorHom (associator X₁ X₂ X₃).inv (𝟙 X₄) = (associator X₁ X₂ (tensorObj X₃ X₄)).inv ≫ (associator (tensorObj X₁ X₂) X₃ X₄).inv := by ext j i₁ i₂ i₃ i₄ h - dsimp + dsimp only [categoryOfGradedObjects_comp] conv_lhs => rw [ιTensorObj₄_eq X₁ X₂ X₃ X₄ i₁ i₂ i₃ i₄ j h _ rfl, assoc, ι_tensorHom_assoc] - dsimp + dsimp only [categoryOfGradedObjects_id, id_eq, eq_mpr_eq_cast, cast_eq] rw [id_tensorHom, ← MonoidalCategory.whiskerLeft_comp_assoc, ιTensorObj₃_associator_inv, ιTensorObj₃'_eq X₂ X₃ X₄ i₂ i₃ i₄ _ rfl _ rfl, MonoidalCategory.whiskerLeft_comp_assoc, MonoidalCategory.whiskerLeft_comp_assoc, @@ -410,7 +417,7 @@ lemma pentagon_inv : (by simp only [← add_assoc, h]) _ rfl, ιTensorObj₃_associator_inv_assoc, ιTensorObj₃'_eq_assoc X₁ (tensorObj X₂ X₃) X₄ i₁ (i₂ + i₃) i₄ j (by simp only [← add_assoc, h]) (i₁ + i₂ + i₃) (by rw [add_assoc]), ι_tensorHom] - dsimp + dsimp only [id_eq, eq_mpr_eq_cast, categoryOfGradedObjects_id] rw [tensorHom_id, whisker_assoc_symm_assoc, Iso.hom_inv_id_assoc, ← MonoidalCategory.comp_whiskerRight_assoc, ← MonoidalCategory.comp_whiskerRight_assoc, ← ιTensorObj₃_eq X₁ X₂ X₃ i₁ i₂ i₃ _ rfl _ rfl, ιTensorObj₃_associator_inv, diff --git a/Mathlib/CategoryTheory/GradedObject/Trifunctor.lean b/Mathlib/CategoryTheory/GradedObject/Trifunctor.lean index fa00a95c23594..b0d783ab327b1 100644 --- a/Mathlib/CategoryTheory/GradedObject/Trifunctor.lean +++ b/Mathlib/CategoryTheory/GradedObject/Trifunctor.lean @@ -215,13 +215,17 @@ 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₄` sending `X₁ : GradedObject I₁ C₁`, `X₂ : GradedObject I₂ C₂` and `X₃ : GradedObject I₃ C₃` to the `J`-graded object sending `j` to the coproduct of `((F.obj (X₁ i₁)).obj (X₂ i₂)).obj (X₃ i₃)` for `p ⟨i₁, i₂, i₃⟩ = j`. -/ -@[simps] noncomputable def mapTrifunctorMap [∀ X₁ X₂ X₃, HasMap ((((mapTrifunctor F I₁ I₂ I₃).obj X₁).obj X₂).obj X₃) p] : GradedObject I₁ C₁ ⥤ GradedObject I₂ C₂ ⥤ GradedObject I₃ C₃ ⥤ GradedObject J C₄ where @@ -243,6 +247,8 @@ noncomputable def mapTrifunctorMap NatTrans.id_app, ι_mapTrifunctorMapMap, id_comp, NatTrans.naturality_app_assoc] } +attribute [simps] mapTrifunctorMap + end section @@ -253,7 +259,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₁₂` -/ @@ -268,7 +274,7 @@ variable {r} (ρ₁₂ : BifunctorComp₁₂IndexData r) /-- Given bifunctors `F₁₂ : C₁ ⥤ C₂ ⥤ C₁₂`, `G : C₁₂ ⥤ C₃ ⥤ C₄`, graded objects `X₁ : GradedObject I₁ C₁`, `X₂ : GradedObject I₂ C₂`, `X₃ : GradedObject I₃ C₃` and `ρ₁₂ : BifunctorComp₁₂IndexData r`, this asserts that for all `i₁₂ : ρ₁₂.I₁₂` and `i₃ : I₃`, -the functor `G(-, X₃ i₃)` commutes wich the coproducts of the `F₁₂(X₁ i₁, X₂ i₂)` +the functor `G(-, X₃ i₃)` commutes with the coproducts of the `F₁₂(X₁ i₁, X₂ i₂)` such that `ρ₁₂.p ⟨i₁, i₂⟩ = i₁₂`. -/ abbrev HasGoodTrifunctor₁₂Obj := ∀ (i₁₂ : ρ₁₂.I₁₂) (i₃ : I₃), PreservesColimit @@ -361,7 +367,7 @@ section variable [HasMap ((((mapTrifunctor (bifunctorComp₁₂ F₁₂ G) I₁ I₂ I₃).obj X₁).obj X₂).obj X₃) r] /-- The action on graded objects of a trifunctor obtained by composition of two -bifunctors can be computed as a composition of the actions of these two bifunctors. -/ +bifunctors can be computed as a composition of the actions of these two bifunctors. -/ noncomputable def mapBifunctorComp₁₂MapObjIso : mapTrifunctorMapObj (bifunctorComp₁₂ F₁₂ G) r X₁ X₂ X₃ ≅ mapBifunctorMapObj G ρ₁₂.q (mapBifunctorMapObj F₁₂ ρ₁₂.p X₁ X₂) X₃ := @@ -433,7 +439,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₂₃` -/ @@ -448,7 +454,7 @@ variable {r} (ρ₂₃ : BifunctorComp₂₃IndexData r) /-- Given bifunctors `F : C₁ ⥤ C₂₃ ⥤ C₄`, `G₂₃ : C₂ ⥤ C₃ ⥤ C₂₃`, graded objects `X₁ : GradedObject I₁ C₁`, `X₂ : GradedObject I₂ C₂`, `X₃ : GradedObject I₃ C₃` and `ρ₂₃ : BifunctorComp₂₃IndexData r`, this asserts that for all `i₁ : I₁` and `i₂₃ : ρ₂₃.I₂₃`, -the functor `F(X₁ i₁, _)` commutes wich the coproducts of the `G₂₃(X₂ i₂, X₃ i₃)` +the functor `F(X₁ i₁, _)` commutes with the coproducts of the `G₂₃(X₂ i₂, X₃ i₃)` such that `ρ₂₃.p ⟨i₂, i₃⟩ = i₂₃`. -/ abbrev HasGoodTrifunctor₂₃Obj := ∀ (i₁ : I₁) (i₂₃ : ρ₂₃.I₂₃), PreservesColimit (Discrete.functor @@ -539,7 +545,7 @@ section variable [HasMap ((((mapTrifunctor (bifunctorComp₂₃ F G₂₃) I₁ I₂ I₃).obj X₁).obj X₂).obj X₃) r] /-- The action on graded objects of a trifunctor obtained by composition of two -bifunctors can be computed as a composition of the actions of these two bifunctors. -/ +bifunctors can be computed as a composition of the actions of these two bifunctors. -/ noncomputable def mapBifunctorComp₂₃MapObjIso : mapTrifunctorMapObj (bifunctorComp₂₃ F G₂₃) r X₁ X₂ X₃ ≅ mapBifunctorMapObj F ρ₂₃.q X₁ (mapBifunctorMapObj G₂₃ ρ₂₃.p X₂ X₃) := diff --git a/Mathlib/CategoryTheory/GradedObject/Unitor.lean b/Mathlib/CategoryTheory/GradedObject/Unitor.lean index 265f2b3635c67..6b90c959e367c 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] @@ -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 a4c2ef1ad1a44..59e0d242c7d00 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 @@ -166,18 +166,13 @@ def map (α : F ⟶ G) : Grothendieck F ⥤ Grothendieck G where map {X Y} f := { base := f.base fiber := (eqToHom (α.naturality f.base).symm).app X.fiber ≫ (α.app Y.base).map f.fiber } - map_id X := by - simp only [Cat.comp_obj, id_fiber', eqToHom_map] - congr 1 - rw [eqToHom_app, eqToHom_trans] + map_id X := by simp only [Cat.eqToHom_app, id_fiber', eqToHom_map, eqToHom_trans]; rfl map_comp {X Y Z} f g := by dsimp congr 1 simp only [comp_fiber' f g, ← Category.assoc, Functor.map_comp, eqToHom_map] congr 1 - simp only [Cat.comp_obj, eqToHom_trans, eqToHom_map, Cat.comp_map, eqToHom_trans_assoc, - Category.assoc] - rw [eqToHom_app, eqToHom_app, eqToHom_app] + simp only [Cat.eqToHom_app, Cat.comp_obj, eqToHom_trans, eqToHom_map, Category.assoc] erw [Functor.congr_hom (α.naturality g.base).symm f.fiber] simp @@ -198,9 +193,7 @@ theorem map_id_eq : map (𝟙 F) = 𝟙 (Cat.of <| Grothendieck <| F) := by rfl · intro X Y f simp [map_map] - congr - rw [NatTrans.id_app] - simp + rfl /-- Making the equality of functors into an isomorphism. Note: we should avoid equality of functors if possible, and we should prefer `map_id_iso` to `map_id_eq` whenever we can. -/ @@ -218,9 +211,7 @@ theorem map_comp_eq (α : F ⟶ G) (β : G ⟶ H) : eqToHom_refl, Functor.comp_map, Functor.map_comp, Category.comp_id, Category.id_comp] fapply Grothendieck.ext · rfl - · simp only [eqToHom_refl, Category.id_comp] - erw [eqToHom_app, eqToHom_app, eqToHom_app, eqToHom_map] - simp only [Cat.comp_obj, eqToHom_trans_assoc] + · simp /-- Making the equality of functors into an isomorphism. Note: we should avoid equality of functors if possible, and we should prefer `map_comp_iso` to `map_comp_eq` whenever we can. -/ diff --git a/Mathlib/CategoryTheory/Groupoid.lean b/Mathlib/CategoryTheory/Groupoid.lean index 7bf9c52f3bc73..4799bc3879317 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 diff --git a/Mathlib/CategoryTheory/Groupoid/FreeGroupoid.lean b/Mathlib/CategoryTheory/Groupoid/FreeGroupoid.lean index 2521a5e952967..79f597c240e2e 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 /-! # Free groupoid on a quiver @@ -80,10 +75,11 @@ theorem congr_reverse {X Y : Paths <| Quiver.Symmetrify V} (p q : X ⟶ Y) : Quiver.Path.reverse_comp, Quiver.reverse_reverse, Quiver.Path.reverse_toPath, Quiver.Path.comp_assoc] using this +open Relation in theorem congr_comp_reverse {X Y : Paths <| Quiver.Symmetrify V} (p : X ⟶ Y) : Quot.mk (@Quotient.CompClosure _ _ redStep _ _) (p ≫ p.reverse) = Quot.mk (@Quotient.CompClosure _ _ redStep _ _) (𝟙 X) := by - apply Quot.EqvGen_sound + apply Quot.eqvGen_sound induction' p with a b q f ih · apply EqvGen.refl · simp only [Quiver.Path.reverse] @@ -136,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 b2efc306cfa42..54c934333769c 100644 --- a/Mathlib/CategoryTheory/Groupoid/Subgroupoid.lean +++ b/Mathlib/CategoryTheory/Groupoid/Subgroupoid.lean @@ -139,7 +139,7 @@ theorem coe_inv_coe' {c d : S.objs} (p : c ⟶ d) : (CategoryTheory.inv p).val = CategoryTheory.inv p.val := by simp only [← inv_eq_inv, coe_inv_coe] -/-- The embedding of the coerced subgroupoid to its parent-/ +/-- The embedding of the coerced subgroupoid to its parent -/ def hom : S.objs ⥤ C where obj c := c.val map f := f.val @@ -292,7 +292,7 @@ theorem IsWide.id_mem {S : Subgroupoid C} (Sw : S.IsWide) (c : C) : 𝟙 c ∈ S theorem IsWide.eqToHom_mem {S : Subgroupoid C} (Sw : S.IsWide) {c d : C} (h : c = d) : eqToHom h ∈ S.arrows c d := by cases h; simp only [eqToHom_refl]; apply Sw.id_mem c -/-- A subgroupoid is normal if it is wide and satisfies the expected stability under conjugacy. -/ +/-- A subgroupoid is normal if it is wide and satisfies the expected stability under conjugacy. -/ structure IsNormal extends IsWide S : Prop where conj : ∀ {c d} (p : c ⟶ d) {γ : c ⟶ c}, γ ∈ S.arrows c c → Groupoid.inv p ≫ γ ≫ p ∈ S.arrows d d @@ -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/Idempotents/FunctorCategories.lean b/Mathlib/CategoryTheory/Idempotents/FunctorCategories.lean index ebcbb63e295ad..aa1af4a9269f3 100644 --- a/Mathlib/CategoryTheory/Idempotents/FunctorCategories.lean +++ b/Mathlib/CategoryTheory/Idempotents/FunctorCategories.lean @@ -58,7 +58,7 @@ instance functor_category_isIdempotentComplete [IsIdempotentComplete C] : have hC := (isIdempotentComplete_iff_hasEqualizer_of_id_and_idempotent C).mp inferInstance haveI : ∀ j : J, HasEqualizer (𝟙 _) (p.app j) := fun j => hC _ _ (congr_app hp j) /- We construct the direct factor `Y` associated to `p : F ⟶ F` by computing - the equalizer of the identity and `p.app j` on each object `(j : J)`. -/ + the equalizer of the identity and `p.app j` on each object `(j : J)`. -/ let Y : J ⥤ C := { obj := fun j => Limits.equalizer (𝟙 _) (p.app j) map := fun {j j'} φ => @@ -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 0fbbb2cf5e249..4c4de5bce5d99 100644 --- a/Mathlib/CategoryTheory/Idempotents/FunctorExtension.lean +++ b/Mathlib/CategoryTheory/Idempotents/FunctorExtension.lean @@ -106,8 +106,12 @@ 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)`. -/ -@[simps!] def KaroubiUniversal₁.counitIso : (whiskeringLeft C (Karoubi C) (Karoubi D)).obj (toKaroubi C) ⋙ functorExtension₁ C D ≅ 𝟭 _ := NatIso.ofComponents @@ -144,6 +148,8 @@ def KaroubiUniversal₁.counitIso : simp only [Functor.map_comp, comp_f, assoc] rfl) +attribute [simps!] KaroubiUniversal₁.counitIso + /-- The equivalence of categories `(C ⥤ Karoubi D) ≌ (Karoubi C ⥤ Karoubi D)`. -/ @[simps] def karoubiUniversal₁ : C ⥤ Karoubi D ≌ Karoubi C ⥤ Karoubi D where diff --git a/Mathlib/CategoryTheory/Idempotents/Karoubi.lean b/Mathlib/CategoryTheory/Idempotents/Karoubi.lean index 121e9a8862368..a0cd003efe419 100644 --- a/Mathlib/CategoryTheory/Idempotents/Karoubi.lean +++ b/Mathlib/CategoryTheory/Idempotents/Karoubi.lean @@ -248,12 +248,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/Iso.lean b/Mathlib/CategoryTheory/Iso.lean index c30a8089b8795..af07a00e52f8d 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 @@ -100,7 +100,7 @@ theorem symm_mk {X Y : C} (hom : X ⟶ Y) (inv : Y ⟶ X) (hom_inv_id) (inv_hom_ rfl @[simp] -theorem symm_symm_eq {X Y : C} (α : X ≅ Y) : α.symm.symm = α := by cases α; rfl +theorem symm_symm_eq {X Y : C} (α : X ≅ Y) : α.symm.symm = α := rfl @[simp] theorem symm_eq_iff {X Y : C} {α β : X ≅ Y} : α.symm = β.symm ↔ α = β := @@ -332,7 +332,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 @@ -344,12 +344,18 @@ because `f.hom` is defeq to `(fun x ↦ x) ≫ f.hom`, triggering a loop. -/ instance (priority := 900) comp_isIso [IsIso f] [IsIso h] : IsIso (f ≫ h) := (asIso f ≪≫ asIso h).isIso_hom +/-- +The composition of isomorphisms is an isomorphism. Here the arguments of type `IsIso` are +explicit, to make this easier to use with the `refine` tactic, for instance. +-/ +lemma comp_isIso' (_ : IsIso f) (_ : IsIso h) : IsIso (f ≫ h) := inferInstance + @[simp] 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 @@ -413,7 +419,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) @@ -503,7 +509,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/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 39aab04c6e510..23386c1aed4c1 100644 --- a/Mathlib/CategoryTheory/Limits/ColimitLimit.lean +++ b/Mathlib/CategoryTheory/Limits/ColimitLimit.lean @@ -1,11 +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.CategoryTheory.Limits.Types import Mathlib.CategoryTheory.Functor.Currying -import Mathlib.CategoryTheory.Limits.FunctorCategory +import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic /-! # The morphism comparing a colimit of limits with the corresponding limit of colimits. 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/ConcreteCategory/WithAlgebraicStructures.lean b/Mathlib/CategoryTheory/Limits/ConcreteCategory/WithAlgebraicStructures.lean index 8a6c50484bdcd..dd4c4c861c62c 100644 --- a/Mathlib/CategoryTheory/Limits/ConcreteCategory/WithAlgebraicStructures.lean +++ b/Mathlib/CategoryTheory/Limits/ConcreteCategory/WithAlgebraicStructures.lean @@ -70,8 +70,8 @@ lemma colimit_no_zero_smul_divisor obtain ⟨j'', H⟩ := H simpa [elementwise_of% (colimit.w F), map_zero] using congr(colimit.ι F _ $(H (IsFiltered.sup {j, j', j''} { ⟨j, j', by simp, by simp, i⟩ }) - (IsFiltered.toSup _ _ $ by simp) - (F.map (IsFiltered.toSup _ _ $ by simp) x) + (IsFiltered.toSup _ _ <| by simp) + (F.map (IsFiltered.toSup _ _ <| by simp) x) (by rw [← IsFiltered.toSup_commutes (f := i) (mY := by simp) (mf := by simp), F.map_comp, comp_apply, ← map_smul, ← map_smul, h, map_zero]))) diff --git a/Mathlib/CategoryTheory/Limits/ConeCategory.lean b/Mathlib/CategoryTheory/Limits/ConeCategory.lean index 11acfcd801749..dd971c3b5c792 100644 --- a/Mathlib/CategoryTheory/Limits/ConeCategory.lean +++ b/Mathlib/CategoryTheory/Limits/ConeCategory.lean @@ -138,20 +138,14 @@ def Cone.fromCostructuredArrow (F : J ⥤ C) : CostructuredArrow (const J) F ⥤ dsimp simp } -/- -Porting note: -`simps!` alone generated lemmas of the form `_ = _` where `_` are proofs of some proposition. -This caused the simpNF linter to complain. -We therefore explicitly tell simps! to avoid applying projections for `PLift` and `ULift`. -Similarly for `Cocone.equivStructuredArrow`. --/ /-- The category of cones on `F` is just the comma category `(Δ ↓ F)`, where `Δ` is the constant functor. -/ -@[simps! (config := { notRecursive := [`PLift, `ULift] })] -def Cone.equivCostructuredArrow (F : J ⥤ C) : Cone F ≌ CostructuredArrow (const J) F := - Equivalence.mk (Cone.toCostructuredArrow F) (Cone.fromCostructuredArrow F) - (NatIso.ofComponents Cones.eta) - (NatIso.ofComponents fun c => (CostructuredArrow.eta _).symm) +@[simps] +def Cone.equivCostructuredArrow (F : J ⥤ C) : Cone F ≌ CostructuredArrow (const J) F where + functor := Cone.toCostructuredArrow F + inverse := Cone.fromCostructuredArrow F + unitIso := NatIso.ofComponents Cones.eta + counitIso := NatIso.ofComponents fun c => (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 := @@ -305,11 +299,12 @@ def Cocone.fromStructuredArrow (F : J ⥤ C) : StructuredArrow F (const J) ⥤ C /-- The category of cocones on `F` is just the comma category `(F ↓ Δ)`, where `Δ` is the constant functor. -/ -@[simps! (config := { notRecursive := [`PLift, `ULift] })] -def Cocone.equivStructuredArrow (F : J ⥤ C) : Cocone F ≌ StructuredArrow F (const J) := - Equivalence.mk (Cocone.toStructuredArrow F) (Cocone.fromStructuredArrow F) - (NatIso.ofComponents Cocones.eta) - (NatIso.ofComponents fun c => (StructuredArrow.eta _).symm) +@[simps] +def Cocone.equivStructuredArrow (F : J ⥤ C) : Cocone F ≌ StructuredArrow F (const J) where + functor := Cocone.toStructuredArrow F + inverse := Cocone.fromStructuredArrow F + unitIso := NatIso.ofComponents Cocones.eta + counitIso := NatIso.ofComponents fun c => (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 := diff --git a/Mathlib/CategoryTheory/Limits/Cones.lean b/Mathlib/CategoryTheory/Limits/Cones.lean index 1d468d8221bd1..157d042f4667c 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 @@ -668,7 +668,7 @@ def mapCone (c : Cone F) : Cone (F ⋙ H) := def mapCocone (c : Cocone F) : Cocone (F ⋙ H) := (Cocones.functoriality F H).obj c -/-- Given a cone morphism `c ⟶ c'`, construct a cone morphism on the mapped cones functorially. -/ +/-- Given a cone morphism `c ⟶ c'`, construct a cone morphism on the mapped cones functorially. -/ def mapConeMorphism {c c' : Cone F} (f : c ⟶ c') : H.mapCone c ⟶ H.mapCone c' := (Cones.functoriality F H).map f diff --git a/Mathlib/CategoryTheory/Limits/Constructions/Filtered.lean b/Mathlib/CategoryTheory/Limits/Constructions/Filtered.lean index 109be53d93b7b..38bfd50516c2a 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 } } 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,34 @@ 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 + +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 CoproductsFromFiniteFiltered + end CategoryTheory.Limits diff --git a/Mathlib/CategoryTheory/Limits/Constructions/FiniteProductsOfBinaryProducts.lean b/Mathlib/CategoryTheory/Limits/Constructions/FiniteProductsOfBinaryProducts.lean index a194496163cb3..83fd7abbab1b6 100644 --- a/Mathlib/CategoryTheory/Limits/Constructions/FiniteProductsOfBinaryProducts.lean +++ b/Mathlib/CategoryTheory/Limits/Constructions/FiniteProductsOfBinaryProducts.lean @@ -157,12 +157,12 @@ def preservesShapeFinOfPreservesBinaryAndTerminal (n : ℕ) : apply preservesLimitOfIsoDiagram F that /-- If `F` preserves the terminal object and binary products then it preserves finite products. -/ -def preservesFiniteProductsOfPreservesBinaryAndTerminal (J : Type) [Fintype J] : +def preservesFiniteProductsOfPreservesBinaryAndTerminal (J : Type*) [Fintype J] : PreservesLimitsOfShape (Discrete J) F := by classical let e := Fintype.equivFin J haveI := preservesShapeFinOfPreservesBinaryAndTerminal F (Fintype.card J) - apply preservesLimitsOfShapeOfEquiv.{0, 0} (Discrete.equivalence e).symm + apply preservesLimitsOfShapeOfEquiv (Discrete.equivalence e).symm end Preserves @@ -288,12 +288,12 @@ def preservesShapeFinOfPreservesBinaryAndInitial (n : ℕ) : apply preservesColimitOfIsoDiagram F that /-- If `F` preserves the initial object and binary coproducts then it preserves finite products. -/ -def preservesFiniteCoproductsOfPreservesBinaryAndInitial (J : Type) [Fintype J] : +def preservesFiniteCoproductsOfPreservesBinaryAndInitial (J : Type*) [Fintype J] : PreservesColimitsOfShape (Discrete J) F := by classical let e := Fintype.equivFin J haveI := preservesShapeFinOfPreservesBinaryAndInitial F (Fintype.card J) - apply preservesColimitsOfShapeOfEquiv.{0, 0} (Discrete.equivalence e).symm + apply preservesColimitsOfShapeOfEquiv (Discrete.equivalence e).symm end Preserves diff --git a/Mathlib/CategoryTheory/Limits/Constructions/LimitsOfProductsAndEqualizers.lean b/Mathlib/CategoryTheory/Limits/Constructions/LimitsOfProductsAndEqualizers.lean index 824a394d211e9..5cf6eebed9923 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. 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/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 70bc2fb14a714..64975ca699d17 100644 --- a/Mathlib/CategoryTheory/Limits/Final.lean +++ b/Mathlib/CategoryTheory/Limits/Final.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.Comma.StructuredArrow import Mathlib.CategoryTheory.IsConnected @@ -358,7 +358,7 @@ variable {C : Type v} [Category.{v} C] {D : Type u₁} [Category.{v} D] (F : C namespace Final theorem zigzag_of_eqvGen_quot_rel {F : C ⥤ D} {d : D} {f₁ f₂ : ΣX, d ⟶ F.obj X} - (t : EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) : + (t : Relation.EqvGen (Types.Quot.Rel.{v, v} (F ⋙ coyoneda.obj (op d))) f₁ f₂) : Zigzag (StructuredArrow.mk f₁.2) (StructuredArrow.mk f₂.2) := by induction t with | rel x y r => @@ -813,4 +813,28 @@ 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 + end CategoryTheory diff --git a/Mathlib/CategoryTheory/Limits/Final/ParallelPair.lean b/Mathlib/CategoryTheory/Limits/Final/ParallelPair.lean index b75d801a67a5d..938e98c7e64e6 100644 --- a/Mathlib/CategoryTheory/Limits/Final/ParallelPair.lean +++ b/Mathlib/CategoryTheory/Limits/Final/ParallelPair.lean @@ -6,10 +6,10 @@ Authors: Dagur Asgeirsson, Joël Riou import Mathlib.CategoryTheory.Limits.Final /-! -# Conditions for `parallelPair` to be initial +# Conditions for `parallelPair` to be initial -In this file we give sufficient conditions on a category `C` and parallel morphisms `f g : X ⟶ Y`  -in `C` so that `parallelPair f g` becomes an initial functor. +In this file we give sufficient conditions on a category `C` and parallel morphisms `f g : X ⟶ Y` +in `C` so that `parallelPair f g` becomes an initial functor. The conditions are that there is a morphism out of `X` to every object of `C` and that any two parallel morphisms out of `X` factor through the parallel pair `f`, `g` diff --git a/Mathlib/CategoryTheory/Limits/FintypeCat.lean b/Mathlib/CategoryTheory/Limits/FintypeCat.lean index 34a080b4ccb92..db0a572fc3b92 100644 --- a/Mathlib/CategoryTheory/Limits/FintypeCat.lean +++ b/Mathlib/CategoryTheory/Limits/FintypeCat.lean @@ -4,11 +4,9 @@ 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 /-! # (Co)limits in the category of finite types @@ -60,6 +58,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 +119,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 0af28f9325260..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 @@ -368,7 +368,7 @@ theorem limitFlipCompLimIsoLimitCompLim_hom_π_π (j) (k) : (limitFlipCompLimIsoLimitCompLim F).hom ≫ limit.π _ j ≫ limit.π _ k = (limit.π _ k ≫ limit.π _ j : limit (_ ⋙ lim) ⟶ _) := by dsimp [limitFlipCompLimIsoLimitCompLim] - simp + simp [Equivalence.counit] -- Porting note: Added type annotation `limit (_ ⋙ lim) ⟶ _` -- See note [dsimp, simp] @@ -402,7 +402,7 @@ theorem colimitFlipCompColimIsoColimitCompColim_ι_ι_hom (j) (k) : (colimit.ι _ k ≫ colimit.ι (F ⋙ colim) j : _ ⟶ colimit (F⋙ colim)) := by dsimp [colimitFlipCompColimIsoColimitCompColim] slice_lhs 1 3 => simp only [] - simp + simp [Equivalence.unit] @[simp, reassoc] theorem colimitFlipCompColimIsoColimitCompColim_ι_ι_inv (k) (j) : @@ -411,7 +411,7 @@ theorem colimitFlipCompColimIsoColimitCompColim_ι_ι_inv (k) (j) : (colimit.ι _ j ≫ colimit.ι (F.flip ⋙ colim) k : _ ⟶ colimit (F.flip ⋙ colim)) := by dsimp [colimitFlipCompColimIsoColimitCompColim] slice_lhs 1 3 => simp only [] - simp + simp [Equivalence.counitInv] end @@ -507,15 +507,11 @@ noncomputable def limitCurrySwapCompLimIsoLimitCurryCompLim : theorem limitCurrySwapCompLimIsoLimitCurryCompLim_hom_π_π {j} {k} : (limitCurrySwapCompLimIsoLimitCurryCompLim G).hom ≫ limit.π _ j ≫ limit.π _ k = (limit.π _ k ≫ limit.π _ j : limit (_ ⋙ lim) ⟶ _) := by - dsimp [limitCurrySwapCompLimIsoLimitCurryCompLim] - simp only [Iso.refl_hom, Prod.braiding_counitIso_hom_app, Limits.HasLimit.isoOfEquivalence_hom_π, - Iso.refl_inv, limitIsoLimitCurryCompLim_hom_π_π, eqToIso_refl, Category.assoc] - erw [NatTrans.id_app] - -- Why can't `simp` do this? - dsimp - -- Porting note: the original proof only had `simp`. - -- However, now `CategoryTheory.Bifunctor.map_id` does not get used by `simp` - rw [CategoryTheory.Bifunctor.map_id] + dsimp [limitCurrySwapCompLimIsoLimitCurryCompLim, Equivalence.counit] + rw [Category.assoc, Category.assoc, limitIsoLimitCurryCompLim_hom_π_π, + HasLimit.isoOfEquivalence_hom_π] + dsimp [Equivalence.counit] + rw [← prod_id, G.map_id] simp -- Porting note: Added type annotation `limit (_ ⋙ lim) ⟶ _` @@ -523,12 +519,7 @@ theorem limitCurrySwapCompLimIsoLimitCurryCompLim_hom_π_π {j} {k} : theorem limitCurrySwapCompLimIsoLimitCurryCompLim_inv_π_π {j} {k} : (limitCurrySwapCompLimIsoLimitCurryCompLim G).inv ≫ limit.π _ k ≫ limit.π _ j = (limit.π _ j ≫ limit.π _ k : limit (_ ⋙ lim) ⟶ _) := by - dsimp [limitCurrySwapCompLimIsoLimitCurryCompLim] - simp only [Iso.refl_hom, Prod.braiding_counitIso_hom_app, Limits.HasLimit.isoOfEquivalence_inv_π, - Iso.refl_inv, limitIsoLimitCurryCompLim_hom_π_π, eqToIso_refl, Category.assoc] - erw [NatTrans.id_app] - -- Porting note (#10618): `simp` can do this in lean 4. - simp + simp [limitCurrySwapCompLimIsoLimitCurryCompLim] end @@ -567,11 +558,9 @@ theorem colimitCurrySwapCompColimIsoColimitCurryCompColim_ι_ι_inv {j} {k} : _ ⟶ colimit (curry.obj (Prod.swap K J ⋙ G) ⋙ colim)) := by dsimp [colimitCurrySwapCompColimIsoColimitCurryCompColim] slice_lhs 1 3 => simp only [] - simp only [colimitIsoColimitCurryCompColim_ι_ι_inv, HasColimit.isoOfEquivalence_inv_π, - Functor.id_obj, Functor.comp_obj, Prod.braiding_inverse_obj, Prod.braiding_functor_obj, - Prod.braiding_counitIso_inv_app, Prod.swap_obj, Iso.refl_hom, NatTrans.id_app, Category.id_comp, - Category.assoc, colimitIsoColimitCurryCompColim_ι_hom, curry_obj_obj_obj] - erw [CategoryTheory.Bifunctor.map_id] + rw [colimitIsoColimitCurryCompColim_ι_ι_inv, HasColimit.isoOfEquivalence_inv_π] + dsimp [Equivalence.counitInv] + rw [CategoryTheory.Bifunctor.map_id] simp end diff --git a/Mathlib/CategoryTheory/Limits/FunctorCategory.lean b/Mathlib/CategoryTheory/Limits/FunctorCategory/Basic.lean similarity index 90% rename from Mathlib/CategoryTheory/Limits/FunctorCategory.lean rename to Mathlib/CategoryTheory/Limits/FunctorCategory/Basic.lean index b212bc76981ba..0b2e0d72e2f6e 100644 --- a/Mathlib/CategoryTheory/Limits/FunctorCategory.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,20 @@ theorem limit_obj_ext {H : J ⥤ K ⥤ C} [HasLimitsOfShape J C] {k : K} {W : C} ext j simpa using w j +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`. diff --git a/Mathlib/CategoryTheory/Limits/FunctorCategory/EpiMono.lean b/Mathlib/CategoryTheory/Limits/FunctorCategory/EpiMono.lean new file mode 100644 index 0000000000000..c7af38879846e --- /dev/null +++ b/Mathlib/CategoryTheory/Limits/FunctorCategory/EpiMono.lean @@ -0,0 +1,61 @@ +/- +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.Constructions.EpiMono +import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic + +/-! +# Monomorphisms and epimorphisms in functor categories + +A natural transformation `f : F ⟶ G` between functors `K ⥤ C` +is a mono (resp. epi) iff for all `k : K`, `f.app k` is, +at least when `C` has pullbacks (resp. pushouts), +see `NatTrans.mono_iff_mono_app` and `NatTrans.epi_iff_epi_app`. + +-/ + +universe v v' v'' u u' u'' + +namespace CategoryTheory + +open Limits + +variable {K : Type u} [Category.{v} K] {C : Type u'} [Category.{v'} C] + {D : Type u''} [Category.{v''} D] {F G : K ⥤ C} (f : F ⟶ G) +section + +variable [HasPullbacks C] + +instance [Mono f] (k : K) : Mono (f.app k) := + inferInstanceAs (Mono (((evaluation K C).obj k).map f)) + +lemma NatTrans.mono_iff_mono_app : Mono f ↔ ∀ (k : K), Mono (f.app k) := + ⟨fun _ ↦ inferInstance, fun _ ↦ mono_of_mono_app _⟩ + +instance [Mono f] (H : C ⥤ D) [H.PreservesMonomorphisms] : + Mono (whiskerRight f H) := by + have : ∀ X, Mono ((whiskerRight f H).app X) := by intros; dsimp; infer_instance + apply NatTrans.mono_of_mono_app + +end + +section + +variable [HasPushouts C] + +instance [Epi f] (k : K) : Epi (f.app k) := + inferInstanceAs (Epi (((evaluation K C).obj k).map f)) + +lemma NatTrans.epi_iff_epi_app : Epi f ↔ ∀ (k : K), Epi (f.app k) := + ⟨fun _ ↦ inferInstance, fun _ ↦ epi_of_epi_app _⟩ + +instance [Epi f] (H : C ⥤ D) [H.PreservesEpimorphisms] : + Epi (whiskerRight f H) := by + have : ∀ X, Epi ((whiskerRight f H).app X) := by intros; dsimp; infer_instance + apply NatTrans.epi_of_epi_app + +end + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Limits/FunctorCategory/Finite.lean b/Mathlib/CategoryTheory/Limits/FunctorCategory/Finite.lean new file mode 100644 index 0000000000000..d1be7bb8d6da3 --- /dev/null +++ b/Mathlib/CategoryTheory/Limits/FunctorCategory/Finite.lean @@ -0,0 +1,28 @@ +/- +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.Limits.FunctorCategory.Basic +import Mathlib.CategoryTheory.Limits.Shapes.FiniteProducts +/-! + +# Functor categories have finite limits when the target category does + +These declarations cannot be in the file `Mathlib.CategoryTheory.Limits.FunctorCategory` because +that file shouldn't import `Mathlib.CategoryTheory.Limits.Shapes.FiniteProducts`. +-/ + +namespace CategoryTheory.Limits + +variable {C : Type*} [Category C] {K : Type*} [Category K] + +instance [HasFiniteLimits C] : HasFiniteLimits (K ⥤ C) := ⟨fun _ ↦ inferInstance⟩ + +instance [HasFiniteProducts C] : HasFiniteProducts (K ⥤ C) := ⟨inferInstance⟩ + +instance [HasFiniteColimits C] : HasFiniteColimits (K ⥤ C) := ⟨fun _ ↦ inferInstance⟩ + +instance [HasFiniteCoproducts C] : HasFiniteCoproducts (K ⥤ C) := ⟨inferInstance⟩ + +end CategoryTheory.Limits diff --git a/Mathlib/CategoryTheory/Limits/FunctorToTypes.lean b/Mathlib/CategoryTheory/Limits/FunctorToTypes.lean index e6121ee7bfd64..ba9abc78c25d6 100644 --- a/Mathlib/CategoryTheory/Limits/FunctorToTypes.lean +++ b/Mathlib/CategoryTheory/Limits/FunctorToTypes.lean @@ -3,7 +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.Limits.FunctorCategory +import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic import Mathlib.CategoryTheory.Limits.Types /-! @@ -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 a2ac485b93211..5478f806f7e4b 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 @@ -489,23 +489,16 @@ def limYoneda : lim ⋙ yoneda ⋙ (whiskeringRight _ _ _).obj uliftFunctor.{u₁} ≅ CategoryTheory.cones J C := 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 := +/-- The constant functor and limit functor are adjoint to each other -/ +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.π _ _ } 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 + 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 [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 c => colimit.desc _ ⟨_, 𝟙 _⟩ } } instance : IsLeftAdjoint (colim : (J ⥤ C) ⥤ C) := ⟨_, ⟨colimConstAdj⟩⟩ diff --git a/Mathlib/CategoryTheory/Limits/IsConnected.lean b/Mathlib/CategoryTheory/Limits/IsConnected.lean index 7dcd61474ff13..a0e0dd26b49f2 100644 --- a/Mathlib/CategoryTheory/Limits/IsConnected.lean +++ b/Mathlib/CategoryTheory/Limits/IsConnected.lean @@ -85,7 +85,7 @@ noncomputable def colimitConstPUnitIsoPUnit [IsConnected C] : /-- Let `F` be a `Type`-valued functor. If two elements `a : F c` and `b : F d` represent the same element of `colimit F`, then `c` and `d` are related by a `Zigzag`. -/ theorem zigzag_of_eqvGen_quot_rel (F : C ⥤ Type w) (c d : Σ j, F.obj j) - (h : EqvGen (Quot.Rel F) c d) : Zigzag c.1 d.1 := by + (h : Relation.EqvGen (Quot.Rel F) c d) : Zigzag c.1 d.1 := by induction h with | rel _ _ h => exact Zigzag.of_hom <| Exists.choose h | refl _ => exact Zigzag.refl _ diff --git a/Mathlib/CategoryTheory/Limits/IsLimit.lean b/Mathlib/CategoryTheory/Limits/IsLimit.lean index c8f15dd3b038b..76802822f383d 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 @@ -60,9 +60,6 @@ structure IsLimit (t : Cone F) where uniq : ∀ (s : Cone F) (m : s.pt ⟶ t.pt) (_ : ∀ j : J, m ≫ t.π.app j = s.π.app j), m = lift s := by aesop_cat --- Porting note (#10618): simp can prove this. Linter complains it still exists -attribute [-simp, nolint simpNF] IsLimit.mk.injEq - attribute [reassoc (attr := simp)] IsLimit.fac namespace IsLimit @@ -516,9 +513,6 @@ structure IsColimit (t : Cocone F) where attribute [reassoc (attr := simp)] IsColimit.fac --- Porting note (#10618): simp can prove this. Linter claims it still is tagged with simp -attribute [-simp, nolint simpNF] IsColimit.mk.injEq - namespace IsColimit instance subsingleton {t : Cocone F} : Subsingleton (IsColimit t) := diff --git a/Mathlib/CategoryTheory/Limits/Lattice.lean b/Mathlib/CategoryTheory/Limits/Lattice.lean index 882daf68cd30e..ccf7e6cf11624 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 diff --git a/Mathlib/CategoryTheory/Limits/Opposites.lean b/Mathlib/CategoryTheory/Limits/Opposites.lean index fab462149abac..a988e6bc1335d 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 @@ -322,11 +322,11 @@ instance : HasProduct (op <| Z ·) := hasLimitOfIso (Discrete.opposite α).inverse ⋙ (Discrete.functor Z).op ≅ Discrete.functor (op <| Z ·)) -/-- A `Cofan` gives a `Fan` in the opposite category. -/ +/-- A `Cofan` gives a `Fan` in the opposite category. -/ @[simp] def Cofan.op (c : Cofan Z) : Fan (op <| Z ·) := Fan.mk _ (fun a ↦ (c.inj a).op) -/-- If a `Cofan` is colimit, then its opposite is limit. -/ +/-- If a `Cofan` is colimit, then its opposite is limit. -/ def Cofan.IsColimit.op {c : Cofan Z} (hc : IsColimit c) : IsLimit c.op := by let e : Discrete.functor (Opposite.op <| Z ·) ≅ (Discrete.opposite α).inverse ⋙ (Discrete.functor Z).op := Discrete.natIso (fun _ ↦ Iso.refl _) @@ -422,7 +422,7 @@ instance : HasCoproduct (op <| Z ·) := hasColimitOfIso @[simp] def Fan.op (f : Fan Z) : Cofan (op <| Z ·) := Cofan.mk _ (fun a ↦ (f.proj a).op) -/-- If a `Fan` is limit, then its opposite is colimit. -/ +/-- If a `Fan` is limit, then its opposite is colimit. -/ def Fan.IsLimit.op {f : Fan Z} (hf : IsLimit f) : IsColimit f.op := by let e : Discrete.functor (Opposite.op <| Z ·) ≅ (Discrete.opposite α).inverse ⋙ (Discrete.functor Z).op := Discrete.natIso (fun _ ↦ Iso.refl _) 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..0926bbae01d71 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 diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Filtered.lean b/Mathlib/CategoryTheory/Limits/Preserves/Filtered.lean index 1eb21050d5910..932826e7f60e0 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 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 f595d3f9ba751..0d33dbbf72e5a 100644 --- a/Mathlib/CategoryTheory/Limits/Preserves/FunctorCategory.lean +++ b/Mathlib/CategoryTheory/Limits/Preserves/FunctorCategory.lean @@ -3,8 +3,9 @@ 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.CategoryTheory.Limits.FunctorCategory +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 @@ -104,4 +105,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..10c785ddbe059 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 @@ -148,10 +148,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] + rw [ι_colimMap_assoc] simp only [ι_preservesColimitsIso_inv, whiskerRight_app, Category.assoc, ι_preservesColimitsIso_inv_assoc, ← G.map_comp] - erw [ι_colimMap]) + rw [ι_colimMap]) end 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/Biproducts.lean b/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Biproducts.lean index c5f4f3bd95437..c3d4d473c6c16 100644 --- a/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Biproducts.lean +++ b/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Biproducts.lean @@ -224,7 +224,7 @@ theorem ι_biproductComparison' (j : J) : variable [PreservesZeroMorphisms F] /-- The composition in the opposite direction is equal to the identity if and only if `F` preserves - the biproduct, see `preservesBiproduct_of_monoBiproductComparison`. -/ + the biproduct, see `preservesBiproduct_of_monoBiproductComparison`. -/ @[reassoc (attr := simp)] theorem biproductComparison'_comp_biproductComparison : biproductComparison' F f ≫ biproductComparison F f = 𝟙 (⨁ F.obj ∘ f) := by diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Kernels.lean b/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Kernels.lean index e273955285c7a..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 @@ -176,7 +176,7 @@ def isColimitMapCoconeEquiv : /-- A colimit cokernel cofork is mapped to a colimit cokernel cofork by a functor `G` when this functor preserves the corresponding colimit. -/ -def mapIsColimit (hc : IsColimit c) (G : C ⥤ D) +def mapIsColimit (hc : IsColimit c) (G : C ⥤ D) [Functor.PreservesZeroMorphisms G] [PreservesColimit (parallelPair f 0) G] : IsColimit (c.map G) := c.isColimitMapCoconeEquiv G (isColimitOfPreserves G hc) 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/Ulift.lean b/Mathlib/CategoryTheory/Limits/Preserves/Ulift.lean index 9bab8cb39bdb4..e11c09ddc138d 100644 --- a/Mathlib/CategoryTheory/Limits/Preserves/Ulift.lean +++ b/Mathlib/CategoryTheory/Limits/Preserves/Ulift.lean @@ -23,8 +23,8 @@ universe v w w' u namespace CategoryTheory.Limits.Types /-- -The equivalence between `K.sections` and `(K ⋙ uliftFunctor.{v, u}).sections`. This is used to show -that `uliftFunctor` preserves limits that are potentially too large to exist in the source +The equivalence between `K.sections` and `(K ⋙ uliftFunctor.{v, u}).sections`. This is used to show +that `uliftFunctor` preserves limits that are potentially too large to exist in the source category. -/ def sectionsEquiv {J : Type*} [Category J] (K : J ⥤ Type u) : diff --git a/Mathlib/CategoryTheory/Limits/Presheaf.lean b/Mathlib/CategoryTheory/Limits/Presheaf.lean index e6f648acb64ad..8dd0215926fc0 100644 --- a/Mathlib/CategoryTheory/Limits/Presheaf.lean +++ b/Mathlib/CategoryTheory/Limits/Presheaf.lean @@ -6,12 +6,8 @@ Authors: Bhavik Mehta, Joël Riou import Mathlib.CategoryTheory.Comma.Presheaf 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 import Mathlib.CategoryTheory.Limits.Over -import Mathlib.CategoryTheory.Limits.Shapes.Terminal -import Mathlib.CategoryTheory.Limits.Types /-! # Colimit of representables @@ -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] } diff --git a/Mathlib/CategoryTheory/Limits/Shapes/BinaryProducts.lean b/Mathlib/CategoryTheory/Limits/Shapes/BinaryProducts.lean index 160d8386ff9bc..1c442221fe532 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) := @@ -461,12 +469,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 +484,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 +509,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,20 +529,22 @@ 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 @@ -581,30 +591,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] @@ -706,7 +716,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 +857,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 +948,7 @@ theorem prod.triangle [HasBinaryProducts C] (X Y : C) : end -section +noncomputable section variable {C} variable [HasBinaryCoproducts C] @@ -1001,7 +1011,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] @@ -1022,7 +1032,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] @@ -1042,7 +1052,7 @@ def coprod.functorLeftComp (X Y : C) : end CoprodFunctor -section ProdComparison +noncomputable section ProdComparison universe w w' u₃ @@ -1126,7 +1136,7 @@ theorem prodComparison_comp : end ProdComparison -section CoprodComparison +noncomputable section CoprodComparison universe w @@ -1208,13 +1218,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 ecb6dfd87d021..7a16ef661d0bf 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 @@ -386,7 +386,7 @@ theorem hasBiproductsOfShape_of_equiv {K : Type w'} [HasBiproductsOfShape K C] ( let ⟨⟨h⟩⟩ := HasBiproductsOfShape.has_biproduct (F ∘ e.symm) let ⟨c, hc⟩ := h HasBiproduct.mk <| by - simpa only [(· ∘ ·), e.symm_apply_apply] using + simpa only [Function.comp_def, e.symm_apply_apply] using LimitBicone.mk (c.whisker e) ((c.whiskerIsBilimitIff _).2 hc)⟩ instance (priority := 100) hasBiproductsOfShape_finite [HasFiniteBiproducts C] [Finite J] : @@ -403,6 +403,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 +555,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 @@ -640,6 +659,7 @@ lemma biproduct.whiskerEquiv_inv_eq_lift {f : J → C} {g : K → C} (e : J ≃ · rintro rfl simp at h +attribute [local simp] Sigma.forall in instance {ι} (f : ι → Type*) (g : (i : ι) → (f i) → C) [∀ i, HasBiproduct (g i)] [HasBiproduct fun i => ⨁ g i] : HasBiproduct fun p : Σ i, f i => g p.1 p.2 where @@ -839,7 +859,7 @@ 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ᶜ) @@ -1275,7 +1295,7 @@ abbrev toBinaryBicone {X Y : C} (b : Bicone (pairFunction X Y)) : BinaryBicone X toBinaryBiconeFunctor.obj b /-- A bicone over a pair is a limit cone if and only if the corresponding binary bicone is a limit - cone. -/ + cone. -/ def toBinaryBiconeIsLimit {X Y : C} (b : Bicone (pairFunction X Y)) : IsLimit b.toBinaryBicone.toCone ≃ IsLimit b.toCone := IsLimit.equivIsoLimit <| Cones.ext (Iso.refl _) fun j => by rcases j with ⟨⟨⟩⟩ <;> simp @@ -1761,7 +1781,7 @@ def biprod.fstKernelFork : KernelFork (biprod.fst : X ⊞ Y ⟶ X) := theorem biprod.fstKernelFork_ι : Fork.ι (biprod.fstKernelFork X Y) = (biprod.inr : Y ⟶ X ⊞ Y) := rfl -/-- The fork `biprod.fstKernelFork` is indeed a limit. -/ +/-- The fork `biprod.fstKernelFork` is indeed a limit. -/ def biprod.isKernelFstKernelFork : IsLimit (biprod.fstKernelFork X Y) := BinaryBicone.isLimitFstKernelFork (BinaryBiproduct.isLimit _ _) @@ -1774,7 +1794,7 @@ def biprod.sndKernelFork : KernelFork (biprod.snd : X ⊞ Y ⟶ Y) := theorem biprod.sndKernelFork_ι : Fork.ι (biprod.sndKernelFork X Y) = (biprod.inl : X ⟶ X ⊞ Y) := rfl -/-- The fork `biprod.sndKernelFork` is indeed a limit. -/ +/-- The fork `biprod.sndKernelFork` is indeed a limit. -/ def biprod.isKernelSndKernelFork : IsLimit (biprod.sndKernelFork X Y) := BinaryBicone.isLimitSndKernelFork (BinaryBiproduct.isLimit _ _) @@ -1787,7 +1807,7 @@ def biprod.inlCokernelCofork : CokernelCofork (biprod.inl : X ⟶ X ⊞ Y) := theorem biprod.inlCokernelCofork_π : Cofork.π (biprod.inlCokernelCofork X Y) = biprod.snd := rfl -/-- The cofork `biprod.inlCokernelFork` is indeed a colimit. -/ +/-- The cofork `biprod.inlCokernelFork` is indeed a colimit. -/ def biprod.isCokernelInlCokernelFork : IsColimit (biprod.inlCokernelCofork X Y) := BinaryBicone.isColimitInlCokernelCofork (BinaryBiproduct.isColimit _ _) @@ -1800,7 +1820,7 @@ def biprod.inrCokernelCofork : CokernelCofork (biprod.inr : Y ⟶ X ⊞ Y) := theorem biprod.inrCokernelCofork_π : Cofork.π (biprod.inrCokernelCofork X Y) = biprod.fst := rfl -/-- The cofork `biprod.inrCokernelFork` is indeed a colimit. -/ +/-- The cofork `biprod.inrCokernelFork` is indeed a colimit. -/ def biprod.isCokernelInrCokernelFork : IsColimit (biprod.inrCokernelCofork X Y) := BinaryBicone.isColimitInrCokernelCofork (BinaryBiproduct.isColimit _ _) @@ -1996,3 +2016,5 @@ theorem isIso_right_of_isIso_biprod_map {W X Y Z : C} (f : W ⟶ Y) (g : X ⟶ Z isIso_left_of_isIso_biprod_map g f end CategoryTheory + +set_option linter.style.longFile 2100 diff --git a/Mathlib/CategoryTheory/Limits/Shapes/CombinedProducts.lean b/Mathlib/CategoryTheory/Limits/Shapes/CombinedProducts.lean index 1d6c74aed120e..4563605f05c24 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/CombinedProducts.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/CombinedProducts.lean @@ -41,7 +41,7 @@ abbrev combPairHoms : (i : ι₁ ⊕ ι₂) → bc.pt ⟶ Sum.elim f₁ f₂ i variable {c₁ c₂ bc} /-- If `c₁` and `c₂` are limit fans and `bc` is a limit binary fan on their cone -points, then the fan constructed from `combPairHoms` is a limit cone. -/ +points, then the fan constructed from `combPairHoms` is a limit cone. -/ def combPairIsLimit : IsLimit (Fan.mk bc.pt (combPairHoms c₁ c₂ bc)) := mkFanLimit _ (fun s ↦ Fan.IsLimit.desc h <| fun i ↦ by @@ -76,7 +76,7 @@ abbrev combPairHoms : (i : ι₁ ⊕ ι₂) → Sum.elim f₁ f₂ i ⟶ bc.pt variable {c₁ c₂ bc} /-- If `c₁` and `c₂` are colimit cofans and `bc` is a colimit binary cofan on their cocone -points, then the cofan constructed from `combPairHoms` is a colimit cocone. -/ +points, then the cofan constructed from `combPairHoms` is a colimit cocone. -/ def combPairIsColimit : IsColimit (Cofan.mk bc.pt (combPairHoms c₁ c₂ bc)) := mkCofanColimit _ (fun s ↦ Cofan.IsColimit.desc h <| fun i ↦ by diff --git a/Mathlib/CategoryTheory/Limits/Shapes/ConcreteCategory.lean b/Mathlib/CategoryTheory/Limits/Shapes/ConcreteCategory.lean index d1f39b75f730a..3388588964ed5 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 diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Countable.lean b/Mathlib/CategoryTheory/Limits/Shapes/Countable.lean index 4893ab194160b..a50342b46d933 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Countable.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Countable.lean @@ -17,7 +17,7 @@ limits, see `sequentialFunctor_initial`. ## Projects -* There is a series of `proof_wanted` at the bottom of this file, implying that all cofiltered +* There is a series of `proof_wanted` at the bottom of this file, implying that all cofiltered limits over countable categories are isomorphic to sequential limits. * Prove the dual result for filtered colimits. @@ -36,7 +36,7 @@ instance and `J : Type` has a limit. -/ class HasCountableLimits : Prop where /-- `C` has all limits over any type `J` whose objects and morphisms lie in the same universe - and which has countably many objects and morphisms-/ + and which has countably many objects and morphisms -/ out (J : Type) [SmallCategory J] [CountableCategory J] : HasLimitsOfShape J C instance (priority := 100) hasFiniteLimits_of_hasCountableLimits [HasCountableLimits C] : @@ -58,7 +58,7 @@ instance and `J : Type` has a colimit. -/ class HasCountableColimits : Prop where /-- `C` has all limits over any type `J` whose objects and morphisms lie in the same universe - and which has countably many objects and morphisms-/ + and which has countably many objects and morphisms -/ out (J : Type) [SmallCategory J] [CountableCategory J] : HasColimitsOfShape J C instance (priority := 100) hasFiniteColimits_of_hasCountableColimits [HasCountableColimits C] : @@ -102,10 +102,10 @@ noncomputable def sequentialFunctor : ℕᵒᵖ ⥤ J where theorem sequentialFunctor_initial_aux (j : J) : ∃ (n : ℕ), sequentialFunctor_obj J n ≤ j := by obtain ⟨m, h⟩ := (exists_surjective_nat _).choose_spec j refine ⟨m + 1, ?_⟩ - simpa [h] using leOfHom (IsCofilteredOrEmpty.cone_objs ((exists_surjective_nat _).choose m) + simpa only [h] using leOfHom (IsCofilteredOrEmpty.cone_objs ((exists_surjective_nat _).choose m) (sequentialFunctor_obj J m)).choose_spec.choose -instance sequentialFunctor_initial : (sequentialFunctor J).Initial where +instance sequentialFunctor_initial : (sequentialFunctor J).Initial where out d := by obtain ⟨n, (g : (sequentialFunctor J).obj ⟨n⟩ ≤ d)⟩ := sequentialFunctor_initial_aux J d have : Nonempty (CostructuredArrow (sequentialFunctor J) d) := @@ -113,7 +113,7 @@ instance sequentialFunctor_initial : (sequentialFunctor J).Initial where apply isConnected_of_zigzag refine fun i j ↦ ⟨[j], ?_⟩ simp only [List.chain_cons, Zag, List.Chain.nil, and_true, ne_eq, not_false_eq_true, - List.getLast_cons, not_true_eq_false, List.getLast_singleton'] + List.getLast_cons, not_true_eq_false, List.getLast_singleton', reduceCtorEq] clear! C wlog h : (unop i.left) ≤ (unop j.left) · exact or_comm.1 (this J d n g inferInstance j i (le_of_lt (not_le.mp h))) @@ -127,7 +127,7 @@ proof_wanted preorder_of_cofiltered (J : Type*) [Category J] [IsCofiltered J] : ∃ (I : Type*) (_ : Preorder I) (_ : IsCofiltered I) (F : I ⥤ J), F.Initial /-- -The proof of `preorder_of_cofiltered` should give a countable `I` in the case that `J` is a +The proof of `preorder_of_cofiltered` should give a countable `I` in the case that `J` is a countable category. -/ proof_wanted preorder_of_cofiltered_countable diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Equalizers.lean b/Mathlib/CategoryTheory/Limits/Shapes/Equalizers.lean index bb067d0c9eef4..05a92677fd909 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 @@ -925,7 +925,7 @@ variable {f g} def idCofork (h : f = g) : Cofork f g := Cofork.ofπ (𝟙 Y) <| h ▸ rfl -/-- The identity on `Y` is a coequalizer of `(f, g)`, where `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 convert h diff --git a/Mathlib/CategoryTheory/Limits/Shapes/FiniteLimits.lean b/Mathlib/CategoryTheory/Limits/Shapes/FiniteLimits.lean index 154159c993a8c..812d28171a0d8 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 @@ -36,7 +36,7 @@ This is often called 'finitely complete'. -/ class HasFiniteLimits : Prop where /-- `C` has all limits over any type `J` whose objects and morphisms lie in the same universe - and which has `FinType` objects and morphisms-/ + and which has `FinType` objects and morphisms -/ out (J : Type) [𝒥 : SmallCategory J] [@FinCategory J 𝒥] : @HasLimitsOfShape J 𝒥 C _ instance (priority := 100) hasLimitsOfShape_of_hasFiniteLimits (J : Type w) [SmallCategory J] @@ -85,7 +85,7 @@ This is often called 'finitely cocomplete'. -/ class HasFiniteColimits : Prop where /-- `C` has all colimits over any type `J` whose objects and morphisms lie in the same universe - and which has `Fintype` objects and morphisms-/ + and which has `Fintype` objects and morphisms -/ out (J : Type) [𝒥 : SmallCategory J] [@FinCategory J 𝒥] : @HasColimitsOfShape J 𝒥 C _ instance (priority := 100) hasColimitsOfShape_of_hasFiniteColimits (J : Type w) [SmallCategory J] 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 c3548f395baed..0303e8d18d601 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/FunctorCategory.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/FunctorCategory.lean @@ -1,10 +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.CategoryTheory.Limits.Shapes.FiniteLimits -import Mathlib.CategoryTheory.Limits.FunctorCategory +import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic /-! # If `D` has finite (co)limits, so do the functor categories `C ⥤ D`. diff --git a/Mathlib/CategoryTheory/Limits/Shapes/FunctorToTypes.lean b/Mathlib/CategoryTheory/Limits/Shapes/FunctorToTypes.lean index 50c0f9fd9c4df..a369f31f98a9d 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/FunctorToTypes.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/FunctorToTypes.lean @@ -3,7 +3,7 @@ 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.Limits.FunctorCategory +import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic import Mathlib.CategoryTheory.Limits.Types /-! diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Images.lean b/Mathlib/CategoryTheory/Limits/Shapes/Images.lean index b403910cf1751..10e2d68009de0 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. -/ @@ -391,7 +389,7 @@ theorem image.ext [HasImage f] {W : C} {g h : image f ⟶ W} [HasLimit (parallel let F' : MonoFactorisation f := { I := equalizer g h m := q ≫ image.ι f - m_mono := by apply mono_comp + m_mono := mono_comp _ _ e := e' } let v := image.lift F' have t₀ : v ≫ q ≫ image.ι f = image.ι f := image.lift_fac F' diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Kernels.lean b/Mathlib/CategoryTheory/Limits/Shapes/Kernels.lean index ec4bee1404520..b829a05e80be7 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,7 +79,7 @@ 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 @@ -435,7 +435,7 @@ def kernel.zeroKernelFork : KernelFork f where def kernel.isLimitConeZeroCone [Mono f] : IsLimit (kernel.zeroKernelFork f) := Fork.IsLimit.mk _ (fun s => 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 _ 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/Products.lean b/Mathlib/CategoryTheory/Limits/Shapes/Products.lean index 35398449274fd..aa816cb1ee4da 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 @@ -258,7 +258,7 @@ instance {f : β → C} [HasCoproduct f] : IsIso (Sigma.desc (fun a ↦ Sigma.ι ext simp -/-- A version of `Cocones.ext` for `Cofan`s. -/ +/-- A version of `Cocones.ext` for `Cofan`s. -/ @[simps!] def Cofan.ext {f : β → C} {c₁ c₂ : Cofan f} (e : c₁.pt ≅ c₂.pt) (w : ∀ (b : β), c₁.inj b ≫ e.hom = c₂.inj b := by aesop_cat) : c₁ ≅ c₂ := @@ -481,6 +481,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. -/ @@ -507,7 +551,8 @@ instance {ι : Type*} (f : ι → Type*) (g : (i : ι) → (f i) → C) exists_limit := Nonempty.intro { cone := Fan.mk (∏ᶜ fun i => ∏ᶜ g i) (fun X => Pi.π (fun i => ∏ᶜ g i) X.1 ≫ Pi.π (g X.1) X.2) isLimit := mkFanLimit _ (fun s => Pi.lift fun b => Pi.lift fun c => s.proj ⟨b, c⟩) - (by aesop_cat) (by intro s m w; simp only [Fan.mk_pt]; symm; ext i x; simp_all) } + (by aesop_cat) + (by intro s m w; simp only [Fan.mk_pt]; symm; ext i x; simp_all [Sigma.forall]) } /-- An iterated product is a product over a sigma type. -/ @[simps] @@ -527,7 +572,8 @@ instance {ι : Type*} (f : ι → Type*) (g : (i : ι) → (f i) → C) (fun X => Sigma.ι (g X.1) X.2 ≫ Sigma.ι (fun i => ∐ g i) X.1) isColimit := mkCofanColimit _ (fun s => Sigma.desc fun b => Sigma.desc fun c => s.inj ⟨b, c⟩) - (by aesop_cat) (by intro s m w; simp only [Cofan.mk_pt]; symm; ext i x; simp_all) } + (by aesop_cat) + (by intro s m w; simp only [Cofan.mk_pt]; symm; ext i x; simp_all [Sigma.forall]) } /-- An iterated coproduct is a coproduct over a sigma type. -/ @[simps] diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Assoc.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Assoc.lean index b6008f36b9768..541f09bc26155 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 -/ diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/CommSq.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/CommSq.lean index 665866bf2883a..423fed53f4080 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/CommSq.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/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, Calle Sönne +Authors: Kim Morrison, Joël Riou, Calle Sönne -/ import Mathlib.CategoryTheory.CommSq import Mathlib.CategoryTheory.Limits.Opposites @@ -280,22 +280,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 @@ -468,22 +468,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 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/HasPullback.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/HasPullback.lean index a2698096b0e00..f6455c517bc0b 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 @@ -16,7 +16,7 @@ pullacks. express the fact that a given pair of morphisms has a pullback. * `HasPullbacks`: expresses the fact that `C` admits all pullbacks, it is implemented as an - abbrevation for `HasLimitsOfShape WalkingCospan C` + abbreviation for `HasLimitsOfShape WalkingCospan C` * `pullback f g`: Given a `HasPullback f g` instance, this function returns the choice of a limit object corresponding to the pullback of `f` and `g`. It fits into the following diagram: @@ -33,7 +33,7 @@ pullback.snd f g g * `HasPushout f g`: this is an abbreviation for `HasColimit (span f g)`, and is a typeclass used to express the fact that a given pair of morphisms has a pushout. * `HasPushouts`: expresses the fact that `C` admits all pushouts, it is implemented as an -abbrevation for `HasColimitsOfShape WalkingSpan C` +abbreviation for `HasColimitsOfShape WalkingSpan C` * `pushout f g`: Given a `HasPushout f g` instance, this function returns the choice of a colimit object corresponding to the pushout of `f` and `g`. It fits into the following diagram: ``` diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Iso.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Iso.lean index 0aec735dd25af..3007f243e923c 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 -/ diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Mono.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Mono.lean index 17d8d712cac9a..5393b03bb61a3 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 -/ @@ -79,7 +79,7 @@ theorem mono_of_isLimitMkIdId (f : X ⟶ Y) (t : IsLimit (mk (𝟙 X) (𝟙 X) r /-- Suppose `f` and `g` are two morphisms with a common codomain and `s` is a limit cone over the diagram formed by `f` and `g`. Suppose `f` and `g` both factor through a monomorphism `h` via `x` and `y`, respectively. Then `s` is also a limit cone over the diagram formed by `x` and - `y`. -/ + `y`. -/ def isLimitOfFactors (f : X ⟶ Z) (g : Y ⟶ Z) (h : W ⟶ Z) [Mono h] (x : X ⟶ W) (y : Y ⟶ W) (hxh : x ≫ h = f) (hyh : y ≫ h = g) (s : PullbackCone f g) (hs : IsLimit s) : IsLimit @@ -250,7 +250,7 @@ theorem epi_of_isColimitMkIdId (f : X ⟶ Y) /-- Suppose `f` and `g` are two morphisms with a common domain and `s` is a colimit cocone over the diagram formed by `f` and `g`. Suppose `f` and `g` both factor through an epimorphism `h` via `x` and `y`, respectively. Then `s` is also a colimit cocone over the diagram formed by `x` and - `y`. -/ + `y`. -/ def isColimitOfFactors (f : X ⟶ Y) (g : X ⟶ Z) (h : X ⟶ W) [Epi h] (x : W ⟶ Y) (y : W ⟶ Z) (hhx : h ≫ x = f) (hhy : h ≫ y = g) (s : PushoutCocone f g) (hs : IsColimit s) : have reassoc₁ : h ≫ x ≫ inl s = f ≫ inl s := by -- Porting note: working around reassoc diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Pasting.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Pasting.lean index adb760c265945..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 -/ @@ -55,19 +55,22 @@ where `t₁` denotes the cone corresponding to the left square, and `t₂` denot corresponding to the right square. -/ -variable {X₃ Y₁ Y₂ Y₃ : C} {g₁ : Y₁ ⟶ Y₂} {g₂ : Y₂ ⟶ Y₃} {i₃ : X₃ ⟶ Y₃} (t₂ : PullbackCone g₂ i₃) -variable {i₂ : t₂.pt ⟶ Y₂} (t₁ : PullbackCone g₁ i₂) (hi₂ : i₂ = t₂.fst) +variable {X₃ Y₁ Y₂ Y₃ : C} {g₁ : Y₁ ⟶ Y₂} {g₂ : Y₂ ⟶ Y₃} {i₃ : X₃ ⟶ Y₃} + +/-- The `PullbackCone` obtained by pasting two `PullbackCone`'s horizontally -/ +abbrev PullbackCone.pasteHoriz + (t₂ : PullbackCone g₂ i₃) {i₂ : t₂.pt ⟶ Y₂} (t₁ : PullbackCone g₁ i₂) (hi₂ : i₂ = t₂.fst) : + PullbackCone (g₁ ≫ g₂) i₃ := + PullbackCone.mk t₁.fst (t₁.snd ≫ t₂.snd) + (by rw [reassoc_of% t₁.condition, Category.assoc, ← t₂.condition, ← hi₂]) + +variable (t₂ : PullbackCone g₂ i₃) {i₂ : t₂.pt ⟶ Y₂} (t₁ : PullbackCone g₁ i₂) (hi₂ : i₂ = t₂.fst) local notation "f₂" => t₂.snd local notation "X₁" => t₁.pt local notation "i₁" => t₁.fst local notation "f₁" => t₁.snd -/-- The `PullbackCone` obtained by pasting two `PullbackCone`'s horizontally -/ -abbrev PullbackCone.pasteHoriz : PullbackCone (g₁ ≫ g₂) i₃ := - PullbackCone.mk i₁ (f₁ ≫ f₂) - (by rw [reassoc_of% t₁.condition, Category.assoc, ← t₂.condition, ← hi₂]) - variable {t₁} {t₂} /-- Given @@ -154,8 +157,15 @@ to the top square. -/ variable {X₁ X₂ X₃ Y₁ : C} {f₁ : X₂ ⟶ X₁} {f₂ : X₃ ⟶ X₂} {i₁ : Y₁ ⟶ X₁} -variable (t₁ : PullbackCone i₁ f₁) {i₂ : t₁.pt ⟶ X₂} (t₂ : PullbackCone i₂ f₂) - (hi₂ : i₂ = t₁.snd) + +/-- The `PullbackCone` obtained by pasting two `PullbackCone`'s vertically -/ +abbrev PullbackCone.pasteVert + (t₁ : PullbackCone i₁ f₁) {i₂ : t₁.pt ⟶ X₂} (t₂ : PullbackCone i₂ f₂) (hi₂ : i₂ = t₁.snd) : + PullbackCone i₁ (f₂ ≫ f₁) := + PullbackCone.mk (t₂.fst ≫ t₁.fst) t₂.snd + (by rw [← reassoc_of% t₂.condition, Category.assoc, t₁.condition, ← hi₂]) + +variable (t₁ : PullbackCone i₁ f₁) {i₂ : t₁.pt ⟶ X₂} (t₂ : PullbackCone i₂ f₂) (hi₂ : i₂ = t₁.snd) local notation "Y₂" => t₁.pt local notation "g₁" => t₁.fst @@ -164,11 +174,6 @@ local notation "Y₃" => t₂.pt local notation "g₂" => t₂.fst local notation "i₃" => t₂.snd -/-- The `PullbackCone` obtained by pasting two `PullbackCone`'s vertically -/ -abbrev PullbackCone.pasteVert : PullbackCone i₁ (f₂ ≫ f₁) := - PullbackCone.mk (g₂ ≫ g₁) i₃ - (by rw [← reassoc_of% t₂.condition, Category.assoc, t₁.condition, ← hi₂]) - /-- Pasting two pullback cones vertically is isomorphic to the pullback cone obtained by flipping them, pasting horizontally, and then flipping the result again. -/ def PullbackCone.pasteVertFlip : (t₁.pasteVert t₂ hi₂).flip ≅ (t₁.flip.pasteHoriz t₂.flip hi₂) := @@ -237,8 +242,15 @@ Y₁ - g₁ -> Y₂ - g₂ -> Y₃ where `t₁` denotes the left pushout cocone, and `t₂` denotes the right pushout cocone. -/ variable {X₁ X₂ X₃ Y₁ : C} {f₁ : X₁ ⟶ X₂} {f₂ : X₂ ⟶ X₃} {i₁ : X₁ ⟶ Y₁} -variable (t₁ : PushoutCocone i₁ f₁) {i₂ : X₂ ⟶ t₁.pt} (t₂ : PushoutCocone i₂ f₂) -variable (hi₂ : i₂ = t₁.inr) + +/-- The pushout cocone obtained by pasting two pushout cocones horizontally. -/ +abbrev PushoutCocone.pasteHoriz + (t₁ : PushoutCocone i₁ f₁) {i₂ : X₂ ⟶ t₁.pt} (t₂ : PushoutCocone i₂ f₂) (hi₂ : i₂ = t₁.inr) : + PushoutCocone i₁ (f₁ ≫ f₂) := + PushoutCocone.mk (t₁.inl ≫ t₂.inl) t₂.inr + (by rw [reassoc_of% t₁.condition, Category.assoc, ← t₂.condition, ← hi₂]) + +variable (t₁ : PushoutCocone i₁ f₁) {i₂ : X₂ ⟶ t₁.pt} (t₂ : PushoutCocone i₂ f₂) (hi₂ : i₂ = t₁.inr) local notation "Y₂" => t₁.pt local notation "g₁" => t₁.inl @@ -247,11 +259,6 @@ local notation "Y₃" => t₂.pt local notation "g₂" => t₂.inl local notation "i₃" => t₂.inr -/-- The pushout cocone obtained by pasting two pushout cocones horizontally. -/ -abbrev PushoutCocone.pasteHoriz : PushoutCocone i₁ (f₁ ≫ f₂) := - PushoutCocone.mk (g₁ ≫ g₂) i₃ - (by rw [reassoc_of% t₁.condition, Category.assoc, ← t₂.condition, ← hi₂]) - variable {t₁} {t₂} /-- Given @@ -343,6 +350,13 @@ variable {Y₃ Y₂ Y₁ X₃ : C} {g₂ : Y₃ ⟶ Y₂} {g₁ : Y₂ ⟶ Y₁} variable (t₁ : PushoutCocone g₂ i₃) {i₂ : Y₂ ⟶ t₁.pt} (t₂ : PushoutCocone g₁ i₂) (hi₂ : i₂ = t₁.inl) +/-- The `PullbackCone` obtained by pasting two `PullbackCone`'s vertically -/ +abbrev PushoutCocone.pasteVert + (t₁ : PushoutCocone g₂ i₃) {i₂ : Y₂ ⟶ t₁.pt} (t₂ : PushoutCocone g₁ i₂) (hi₂ : i₂ = t₁.inl) : + PushoutCocone (g₂ ≫ g₁) i₃ := + PushoutCocone.mk t₂.inl (t₁.inr ≫ t₂.inr) + (by rw [← reassoc_of% t₁.condition, Category.assoc, t₂.condition, ← hi₂]) + local notation "X₂" => t₁.pt local notation "f₂" => t₁.inr local notation "i₂" => t₁.inl @@ -350,11 +364,6 @@ local notation "X₁" => t₂.pt local notation "f₁" => t₂.inr local notation "i₁" => t₂.inl -/-- The `PullbackCone` obtained by pasting two `PullbackCone`'s vertically -/ -abbrev PushoutCocone.pasteVert : PushoutCocone (g₂ ≫ g₁) i₃ := - PushoutCocone.mk i₁ (f₂ ≫ f₁) - (by rw [← reassoc_of% t₁.condition, Category.assoc, t₂.condition, ← hi₂]) - /-- Pasting two pushout cocones vertically is isomorphic to the pushout cocone obtained by flipping them, pasting horizontally, and then flipping the result again. -/ def PushoutCocone.pasteVertFlip : (t₁.pasteVert t₂ hi₂).flip ≅ (t₁.flip.pasteHoriz t₂.flip hi₂) := diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/PullbackCone.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/PullbackCone.lean index f56d21c18f129..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 @@ -23,7 +23,7 @@ t.pt ---t.snd---> Y v v X -----f------> Z ``` -The type `PullbackCone f g` is implemented as an abbrevation for `Cone (cospan f g)`, so general +The type `PullbackCone f g` is implemented as an abbreviation for `Cone (cospan f g)`, so general results about cones are also available for `PullbackCone f g`. * `PushoutCone f g`: Given morphisms `f : X ⟶ Y` and `g : X ⟶ Z`, a term `t : PushoutCone f g` diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Square.lean b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Square.lean index 1584c6cc90a0d..2564e52fc6070 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Square.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Pullback/Square.lean @@ -3,6 +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.MorphismProperty.Limits import Mathlib.CategoryTheory.Square import Mathlib.CategoryTheory.Limits.Shapes.Pullback.CommSq @@ -11,7 +12,9 @@ import Mathlib.CategoryTheory.Limits.Shapes.Pullback.CommSq In this file, we translate the `IsPushout` and `IsPullback` API for the objects of the category `Square C` of commutative -squares in a category `C`. +squares in a category `C`. We also obtain lemmas which states +in this language that a pullback of a monomorphism is +a monomorphism (and similarly for pushouts of epimorphisms). -/ @@ -105,6 +108,40 @@ lemma IsPullback.op {sq : Square C} (h : sq.IsPullback) : sq.op.IsPushout := lemma IsPullback.unop {sq : Square Cᵒᵖ} (h : sq.IsPullback) : sq.unop.IsPushout := CategoryTheory.IsPullback.unop h.flip +namespace IsPullback + +variable (h : sq.IsPullback) + +include h + +lemma flip : sq.flip.IsPullback := CategoryTheory.IsPullback.flip h + +lemma mono_f₁₃ [Mono sq.f₂₄] : Mono sq.f₁₃ := + (MorphismProperty.StableUnderBaseChange.monomorphisms C) h (by assumption) + +lemma mono_f₁₂ [Mono sq.f₃₄] : Mono sq.f₁₂ := by + have : Mono sq.flip.f₂₄ := by dsimp; infer_instance + exact h.flip.mono_f₁₃ + +end IsPullback + +namespace IsPushout + +variable (h : sq.IsPushout) + +include h + +lemma flip : sq.flip.IsPushout := CategoryTheory.IsPushout.flip h + +lemma epi_f₂₄ [Epi sq.f₁₃] : Epi sq.f₂₄ := + (MorphismProperty.StableUnderCobaseChange.epimorphisms C) h (by assumption) + +lemma epi_f₃₄ [Epi sq.f₁₂] : Epi sq.f₃₄ := by + have : Epi sq.flip.f₁₃ := by dsimp; infer_instance + exact h.flip.epi_f₂₄ + +end IsPushout + end Square 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 5168baa185fa4..e501871d0f757 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/SingleObj.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/SingleObj.lean @@ -72,7 +72,7 @@ section Colimits variable {G : Type v} [Group G] (J : SingleObj G ⥤ Type u) /-- The relation used to construct colimits in types for `J : SingleObj G ⥤ Type u` is -equivalent to the `MulAction.orbitRel` equivalence relation on `J.obj (SingleObj.star G)`. -/ +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 diff --git a/Mathlib/CategoryTheory/Limits/Shapes/StrongEpi.lean b/Mathlib/CategoryTheory/Limits/Shapes/StrongEpi.lean index 413d4b2416447..ba11c501a2ea9 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/StrongEpi.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/StrongEpi.lean @@ -136,8 +136,7 @@ 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 := { epi := by rw [Arrow.iso_w' e] - haveI := epi_comp f e.hom.right - apply epi_comp + infer_instance llp := fun {X Y} z => by intro apply HasLiftingProperty.of_arrow_iso_left e z } @@ -146,8 +145,7 @@ theorem StrongMono.of_arrow_iso {A B A' B' : C} {f : A ⟶ B} {g : A' ⟶ B'} (e : Arrow.mk f ≅ Arrow.mk g) [h : StrongMono f] : StrongMono g := { mono := by rw [Arrow.iso_w' e] - haveI := mono_comp f e.hom.right - apply mono_comp + infer_instance rlp := fun {X Y} z => by intro apply HasLiftingProperty.of_arrow_iso_right z e } diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Terminal.lean b/Mathlib/CategoryTheory/Limits/Shapes/Terminal.lean index c9f8914c57de7..37a4e622da924 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Terminal.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Terminal.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.PEmpty import Mathlib.CategoryTheory.Limits.HasLimits diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Types.lean b/Mathlib/CategoryTheory/Limits/Shapes/Types.lean index 80021b7b4364e..5f9021a6e2f50 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 @@ -553,7 +553,7 @@ theorem coequalizer_preimage_image_eq_of_preimage_eq (π : Y ⟶ Z) (e : f ≫ (mono_iff_injective (h.coconePointUniqueUpToIso (coequalizerColimit f g).isColimit).inv).mp inferInstance e' - exact (eqv.eqvGen_iff.mp (EqvGen.mono lem (Quot.exact _ e'))).mp hy + exact (eqv.eqvGen_iff.mp (Relation.EqvGen.mono lem (Quot.eqvGen_exact e'))).mp hy · exact fun hx => ⟨_, hx, rfl⟩ /-- The categorical coequalizer in `Type u` is the quotient by `f g ~ g x`. -/ @@ -585,8 +585,8 @@ instance : HasPullbacks.{u} (Type u) := instance : HasPushouts.{u} (Type u) := hasPushouts_of_hasWidePushouts.{u} (Type u) -variable {X Y Z : Type u} -variable (f : X ⟶ Z) (g : Y ⟶ Z) +variable {X Y Z : Type u} {X' Y' Z' : Type v} +variable (f : X ⟶ Z) (g : Y ⟶ Z) (f' : X' ⟶ Z') (g' : Y' ⟶ Z') -- porting note (#5171): removed @[nolint has_nonempty_instance] /-- The usual explicit pullback in the category of types, as a subtype of the product. diff --git a/Mathlib/CategoryTheory/Limits/Shapes/WideEqualizers.lean b/Mathlib/CategoryTheory/Limits/Shapes/WideEqualizers.lean index c39731729d5e1..6193cbb5c6587 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/WideEqualizers.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/WideEqualizers.lean @@ -138,7 +138,7 @@ def diagramIsoParallelFamily (F : WalkingParallelFamily J ⥤ C) : rintro _ _ (_|_) <;> aesop_cat /-- `WalkingParallelPair` as a category is equivalent to a special case of -`WalkingParallelFamily`. -/ +`WalkingParallelFamily`. -/ @[simps!] def walkingParallelFamilyEquivWalkingParallelPair : WalkingParallelFamily.{w} (ULift Bool) ≌ WalkingParallelPair where diff --git a/Mathlib/CategoryTheory/Limits/Shapes/ZeroMorphisms.lean b/Mathlib/CategoryTheory/Limits/Shapes/ZeroMorphisms.lean index 6aa46f0c5a128..259375ddca69a 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 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/Types.lean b/Mathlib/CategoryTheory/Limits/Types.lean index 1b69256ba80da..b67691c5eca11 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 @@ -548,7 +548,7 @@ theorem colimit_sound' {j j' : J} {x : F.obj j} {x' : F.obj j'} {j'' : J} variable {F} in theorem colimit_eq {j j' : J} {x : F.obj j} {x' : F.obj j'} (w : colimit.ι F j x = colimit.ι F j' x') : - EqvGen (Quot.Rel F) ⟨j, x⟩ ⟨j', x'⟩ := by + Relation.EqvGen (Quot.Rel F) ⟨j, x⟩ ⟨j', x'⟩ := by apply Quot.eq.1 simpa using congr_arg (colimitEquivQuot F) w @@ -632,7 +632,7 @@ 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) (hF : ∀ n, Function.Surjective (F.map (homOfLE (Nat.le_succ n)).op)) diff --git a/Mathlib/CategoryTheory/Limits/TypesFiltered.lean b/Mathlib/CategoryTheory/Limits/TypesFiltered.lean index 48b2c53fe834a..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 @@ -27,7 +27,7 @@ attribute [local instance] small_quot_of_hasColimit /- For filtered colimits of types, we can give an explicit description of the equivalence relation generated by the relation used to form - the colimit. -/ + the colimit. -/ /-- An alternative relation on `Σ j, F.obj j`, which generates the same equivalence relation as we use to define the colimit in `Type` above, @@ -44,10 +44,10 @@ theorem rel_of_quot_rel (x y : Σ j, F.obj j) : fun ⟨f, h⟩ => ⟨y.1, f, 𝟙 y.1, by rw [← h, FunctorToTypes.map_id_apply]⟩ theorem eqvGen_quot_rel_of_rel (x y : Σ j, F.obj j) : - FilteredColimit.Rel.{v, u} F x y → EqvGen (Quot.Rel F) x y := fun ⟨k, f, g, h⟩ => by - refine EqvGen.trans _ ⟨k, F.map f x.2⟩ _ ?_ ?_ - · exact (EqvGen.rel _ _ ⟨f, rfl⟩) - · exact (EqvGen.symm _ _ (EqvGen.rel _ _ ⟨g, h⟩)) + FilteredColimit.Rel.{v, u} F x y → Relation.EqvGen (Quot.Rel F) x y := fun ⟨k, f, g, h⟩ => by + refine Relation.EqvGen.trans _ ⟨k, F.map f x.2⟩ _ ?_ ?_ + · exact (Relation.EqvGen.rel _ _ ⟨f, rfl⟩) + · exact (Relation.EqvGen.symm _ _ (Relation.EqvGen.rel _ _ ⟨g, h⟩)) /-- Recognizing filtered colimits of types. -/ noncomputable def isColimitOf (t : Cocone F) (hsurj : ∀ x : t.pt, ∃ i xi, x = t.ι.app i xi) @@ -92,12 +92,12 @@ protected theorem rel_equiv : _root_.Equivalence (FilteredColimit.Rel.{v, u} F) _ = F.map (g' ≫ gl ≫ n) z.2 := by simp⟩ protected theorem rel_eq_eqvGen_quot_rel : - FilteredColimit.Rel.{v, u} F = EqvGen (Quot.Rel F) := by + FilteredColimit.Rel.{v, u} F = Relation.EqvGen (Quot.Rel F) := by ext ⟨j, x⟩ ⟨j', y⟩ constructor · apply eqvGen_quot_rel_of_rel · rw [← (FilteredColimit.rel_equiv F).eqvGen_iff] - exact EqvGen.mono (rel_of_quot_rel F) + exact Relation.EqvGen.mono (rel_of_quot_rel F) variable [HasColimit F] 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 783314187e22d..429dea9a1687b 100644 --- a/Mathlib/CategoryTheory/Limits/VanKampen.lean +++ b/Mathlib/CategoryTheory/Limits/VanKampen.lean @@ -7,7 +7,7 @@ import Mathlib.CategoryTheory.Adjunction.FullyFaithful import Mathlib.CategoryTheory.Adjunction.Limits import Mathlib.CategoryTheory.Limits.Shapes.Pullback.CommSq import Mathlib.CategoryTheory.Limits.Shapes.StrictInitial -import Mathlib.CategoryTheory.Limits.FunctorCategory +import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic import Mathlib.CategoryTheory.Limits.Constructions.FiniteProductsOfBinaryProducts /-! @@ -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 1e0a5bb19da0e..2442748a1c2e5 100644 --- a/Mathlib/CategoryTheory/Limits/Yoneda.lean +++ b/Mathlib/CategoryTheory/Limits/Yoneda.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, Bhavik Mehta +Authors: Kim Morrison, Bhavik Mehta -/ -import Mathlib.CategoryTheory.Limits.FunctorCategory +import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic import Mathlib.CategoryTheory.Limits.Types import Mathlib.Util.AssertExists @@ -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..5f724dcf36cb9 100644 --- a/Mathlib/CategoryTheory/Linear/Basic.lean +++ b/Mathlib/CategoryTheory/Linear/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.Algebra.Algebra.Defs import Mathlib.Algebra.Module.Equiv.Defs diff --git a/Mathlib/CategoryTheory/Linear/FunctorCategory.lean b/Mathlib/CategoryTheory/Linear/FunctorCategory.lean index 5ecd51cc0413a..54207426b1605 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,6 +21,11 @@ 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/CalculusOfFractions.lean b/Mathlib/CategoryTheory/Localization/CalculusOfFractions.lean index b6cc4f0377426..07d49115d1bb7 100644 --- a/Mathlib/CategoryTheory/Localization/CalculusOfFractions.lean +++ b/Mathlib/CategoryTheory/Localization/CalculusOfFractions.lean @@ -226,7 +226,7 @@ lemma LeftFraction.rightFraction_fac [W.HasRightCalculusOfFractions] {X Y : C} /-- The equivalence relation on left fractions for a morphism property `W`. -/ def LeftFractionRel {X Y : C} (z₁ z₂ : W.LeftFraction X Y) : Prop := - ∃ (Z : C) (t₁ : z₁.Y' ⟶ Z) (t₂ : z₂.Y' ⟶ Z) (_ : z₁.s ≫ t₁ = z₂.s ≫ t₂) + ∃ (Z : C) (t₁ : z₁.Y' ⟶ Z) (t₂ : z₂.Y' ⟶ Z) (_ : z₁.s ≫ t₁ = z₂.s ≫ t₂) (_ : z₁.f ≫ t₁ = z₂.f ≫ t₂), W (z₁.s ≫ t₁) namespace LeftFractionRel @@ -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₂) : @@ -877,7 +877,7 @@ instance (W : MorphismProperty Cᵒᵖ) [h : W.HasRightCalculusOfFractions] : /-- The equivalence relation on right fractions for a morphism property `W`. -/ def RightFractionRel {X Y : C} (z₁ z₂ : W.RightFraction X Y) : Prop := - ∃ (Z : C) (t₁ : Z ⟶ z₁.X') (t₂ : Z ⟶ z₂.X') (_ : t₁ ≫ z₁.s = t₂ ≫ z₂.s) + ∃ (Z : C) (t₁ : Z ⟶ z₁.X') (t₂ : Z ⟶ z₂.X') (_ : t₁ ≫ z₁.s = t₂ ≫ z₂.s) (_ : t₁ ≫ z₁.f = t₂ ≫ z₂.f), W (t₁ ≫ z₁.s) lemma RightFractionRel.op {X Y : C} {z₁ z₂ : W.RightFraction X Y} diff --git a/Mathlib/CategoryTheory/Localization/CalculusOfFractions/Fractions.lean b/Mathlib/CategoryTheory/Localization/CalculusOfFractions/Fractions.lean index bf5ec2d0d65aa..465d603552c31 100644 --- a/Mathlib/CategoryTheory/Localization/CalculusOfFractions/Fractions.lean +++ b/Mathlib/CategoryTheory/Localization/CalculusOfFractions/Fractions.lean @@ -87,7 +87,7 @@ variable {W} for a morphism property `W`. The fact it is an equivalence relation is not formalized, but it would follow easily from `LeftFraction₂.map_eq_iff`. -/ def LeftFraction₂Rel {X Y : C} (z₁ z₂ : W.LeftFraction₂ X Y) : Prop := - ∃ (Z : C) (t₁ : z₁.Y' ⟶ Z) (t₂ : z₂.Y' ⟶ Z) (_ : z₁.s ≫ t₁ = z₂.s ≫ t₂) + ∃ (Z : C) (t₁ : z₁.Y' ⟶ Z) (t₂ : z₂.Y' ⟶ Z) (_ : z₁.s ≫ t₁ = z₂.s ≫ t₂) (_ : z₁.f ≫ t₁ = z₂.f ≫ t₂) (_ : z₁.f' ≫ t₁ = z₂.f' ≫ t₂), W (z₁.s ≫ t₁) namespace LeftFraction₂ diff --git a/Mathlib/CategoryTheory/Localization/DerivabilityStructure/Constructor.lean b/Mathlib/CategoryTheory/Localization/DerivabilityStructure/Constructor.lean index 916c45adea7b8..2adefbca8f183 100644 --- a/Mathlib/CategoryTheory/Localization/DerivabilityStructure/Constructor.lean +++ b/Mathlib/CategoryTheory/Localization/DerivabilityStructure/Constructor.lean @@ -87,7 +87,7 @@ lemma isConnected : refine ⟨RightResolution.mk ρ.w.left ρ.hw.1, ?_⟩ have := zigzag_obj_of_zigzag (fromRightResolution Φ L x ⋙ w.costructuredArrowDownwardsPrecomp x y g fac) - (isPreconnected_zigzag (RightResolution.mk (𝟙 _) (W₂.id_mem _)) + (isPreconnected_zigzag (RightResolution.mk (𝟙 _) (W₂.id_mem _)) (RightResolution.mk ρ.w.right ρ.hw.2)) refine Zigzag.trans ?_ (Zigzag.trans this ?_) · exact Zigzag.of_hom (eqToHom (by aesop)) diff --git a/Mathlib/CategoryTheory/Localization/HasLocalization.lean b/Mathlib/CategoryTheory/Localization/HasLocalization.lean index 4078cb38e28f0..76deb68f57da1 100644 --- a/Mathlib/CategoryTheory/Localization/HasLocalization.lean +++ b/Mathlib/CategoryTheory/Localization/HasLocalization.lean @@ -46,7 +46,7 @@ variable (W : MorphismProperty C) namespace MorphismProperty /-- The data of a localized category with a given universe -for the morphisms. -/ +for the morphisms. -/ class HasLocalization where /-- the objects of the localized category. -/ {D : Type u} 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 0b955a5df9ff8..dd06454204670 100644 --- a/Mathlib/CategoryTheory/Localization/Predicate.lean +++ b/Mathlib/CategoryTheory/Localization/Predicate.lean @@ -369,7 +369,7 @@ lemma compLeft_iso (W) (F : D ⥤ E) : Localization.Lifting.iso L W (L ⋙ F) F /-- Given a localization functor `L : C ⥤ D` for `W : MorphismProperty C`, if `F₁' : D ⥤ E` lifts a functor `F₁ : C ⥤ D`, then a functor `F₂'` which -is isomorphic to `F₁'` also lifts a functor `F₂` that is isomorphic to `F₁`. -/ +is isomorphic to `F₁'` also lifts a functor `F₂` that is isomorphic to `F₁`. -/ @[simps] def ofIsos {F₁ F₂ : C ⥤ E} {F₁' F₂' : D ⥤ E} (e : F₁ ≅ F₂) (e' : F₁' ≅ F₂') [Lifting L W F₁ F₁'] : Lifting L W F₂ F₂' := diff --git a/Mathlib/CategoryTheory/Localization/Prod.lean b/Mathlib/CategoryTheory/Localization/Prod.lean index a5cffe4cf9a59..adb58aa11fea4 100644 --- a/Mathlib/CategoryTheory/Localization/Prod.lean +++ b/Mathlib/CategoryTheory/Localization/Prod.lean @@ -128,7 +128,7 @@ variable [W₁.ContainsIdentities] [W₂.ContainsIdentities] /-- If `L₁ : C₁ ⥤ D₁` and `L₂ : C₂ ⥤ D₂` are localization functors for `W₁ : MorphismProperty C₁` and `W₂ : MorphismProperty C₂` respectively, -and if both `W₁` and `W₂` contain identites, then the product +and if both `W₁` and `W₂` contain identities, then the product functor `L₁.prod L₂ : C₁ × C₂ ⥤ D₁ × D₂` is a localization functor for `W₁.prod W₂`. -/ instance prod [L₁.IsLocalization W₁] [L₂.IsLocalization W₂] : (L₁.prod L₂).IsLocalization (W₁.prod W₂) := by diff --git a/Mathlib/CategoryTheory/Localization/Resolution.lean b/Mathlib/CategoryTheory/Localization/Resolution.lean index 8afa0c3016b5f..33a2ffe3bd749 100644 --- a/Mathlib/CategoryTheory/Localization/Resolution.lean +++ b/Mathlib/CategoryTheory/Localization/Resolution.lean @@ -19,7 +19,7 @@ A right resolution consists of an object `X₁ : C₁` and a morphism The type of right resolutions `Φ.RightResolution X₂` is endowed with a category structure when the morphism property `W₁` is multiplicative. -Similiar definitions are done from left resolutions. +Similar definitions are done from left resolutions. ## Future works diff --git a/Mathlib/CategoryTheory/Localization/SmallHom.lean b/Mathlib/CategoryTheory/Localization/SmallHom.lean index 4f7063c5ba725..bb6cb9ad83759 100644 --- a/Mathlib/CategoryTheory/Localization/SmallHom.lean +++ b/Mathlib/CategoryTheory/Localization/SmallHom.lean @@ -71,6 +71,17 @@ lemma hasSmallLocalizedHom_iff_of_isos {X' Y' : C} (e : X ≅ X') (e' : Y ≅ Y' simp only [hasSmallLocalizedHom_iff W W.Q] exact small_congr (Iso.homCongr (W.Q.mapIso e) (W.Q.mapIso e')) +variable (X) in +lemma hasSmallLocalizedHom_iff_target {Y Y' : C} (f : Y ⟶ Y') (hf : W f): + HasSmallLocalizedHom.{w} W X Y ↔ HasSmallLocalizedHom.{w} W X Y' := by + simp only [hasSmallLocalizedHom_iff W W.Q] + exact small_congr (Iso.homCongr (Iso.refl _) (Localization.isoOfHom W.Q W f hf)) + +lemma hasSmallLocalizedHom_iff_source {X' : C} (f : X ⟶ X') (hf : W f) (Y : C) : + HasSmallLocalizedHom.{w} W X Y ↔ HasSmallLocalizedHom.{w} W X' Y := by + simp only [hasSmallLocalizedHom_iff W W.Q] + exact small_congr (Iso.homCongr (Localization.isoOfHom W.Q W f hf) (Iso.refl _)) + end /-- The type of morphisms from `X` to `Y` in the localized category @@ -238,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/SmallShiftedHom.lean b/Mathlib/CategoryTheory/Localization/SmallShiftedHom.lean index 378b267f05134..0b4eb64c1f24f 100644 --- a/Mathlib/CategoryTheory/Localization/SmallShiftedHom.lean +++ b/Mathlib/CategoryTheory/Localization/SmallShiftedHom.lean @@ -36,15 +36,14 @@ namespace Localization section variable (X Y : C) +variable (M) -variable (M) in /-- Given objects `X` and `Y` in a category `C`, this is the property that all the types of morphisms from `X⟦a⟧` to `Y⟦b⟧` are `w`-small in the localized category with respect to a class of morphisms `W`. -/ abbrev HasSmallLocalizedShiftedHom : Prop := ∀ (a b : M), HasSmallLocalizedHom.{w} W (X⟦a⟧) (Y⟦b⟧) -variable (M) in lemma hasSmallLocalizedShiftedHom_iff (L : C ⥤ D) [L.IsLocalization W] [L.CommShift M] (X Y : C) : HasSmallLocalizedShiftedHom.{w} W M X Y ↔ @@ -55,15 +54,30 @@ lemma hasSmallLocalizedShiftedHom_iff dsimp at eq simp only [hasSmallLocalizedHom_iff _ L, eq] +variable {Y} in +lemma hasSmallLocalizedShiftedHom_iff_target [W.IsCompatibleWithShift M] + {Y' : C} (f : Y ⟶ Y') (hf : W f) : + HasSmallLocalizedShiftedHom.{w} W M X Y ↔ HasSmallLocalizedShiftedHom.{w} W M X Y' := + forall_congr' (fun a ↦ forall_congr' (fun b ↦ + hasSmallLocalizedHom_iff_target W (X⟦a⟧) (f⟦b⟧') (W.shift hf b))) + +variable {X} in +lemma hasSmallLocalizedShiftedHom_iff_source [W.IsCompatibleWithShift M] + {X' : C} (f : X ⟶ X') (hf : W f) (Y : C) : + HasSmallLocalizedShiftedHom.{w} W M X Y ↔ HasSmallLocalizedShiftedHom.{w} W M X' Y := + forall_congr' (fun a ↦ forall_congr' (fun b ↦ + hasSmallLocalizedHom_iff_source W (f⟦a⟧') (W.shift hf a) (Y⟦b⟧))) + variable [HasSmallLocalizedShiftedHom.{w} W M X Y] include M in -variable (M) in lemma hasSmallLocalizedHom_of_hasSmallLocalizedShiftedHom₀ : HasSmallLocalizedHom.{w} W X Y := (hasSmallLocalizedHom_iff_of_isos W ((shiftFunctorZero C M).app X) ((shiftFunctorZero C M).app Y)).1 inferInstance +variable {M} + instance (m : M) : HasSmallLocalizedHom.{w} W X (Y⟦m⟧) := (hasSmallLocalizedHom_iff_of_isos W ((shiftFunctorZero C M).app X) (Iso.refl (Y⟦m⟧))).1 inferInstance diff --git a/Mathlib/CategoryTheory/Monad/Adjunction.lean b/Mathlib/CategoryTheory/Monad/Adjunction.lean index ca2bf35b6796b..ebd45343a99da 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 @@ -73,7 +73,7 @@ def toComonad (h : L ⊣ R) : Comonad D where rw [← L.map_comp] simp -/-- The monad induced by the Eilenberg-Moore adjunction is the original monad. -/ +/-- 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 _) @@ -84,7 +84,7 @@ def adjToComonadIso (G : Comonad C) : G.adj.toComonad ≅ G := ComonadIso.mk (NatIso.ofComponents fun X => Iso.refl _) /-- -Given an adjunction `L ⊣ R`, if `L ⋙ R` is abstractly isomorphic to the identity functor, then the +Given an adjunction `L ⊣ R`, if `L ⋙ R` is abstractly isomorphic to the identity functor, then the unit is an isomorphism. -/ def unitAsIsoOfIso (adj : L ⊣ R) (i : L ⋙ R ≅ 𝟭 C) : 𝟭 C ≅ L ⋙ R where @@ -100,11 +100,11 @@ def unitAsIsoOfIso (adj : L ⊣ R) (i : L ⋙ R ≅ 𝟭 C) : 𝟭 C ≅ L ⋙ R ext X exact (adj.toMonad.transport i).right_unit X -lemma isIso_unit_of_iso (adj : L ⊣ R) (i : L ⋙ R ≅ 𝟭 C) : IsIso adj.unit := +lemma isIso_unit_of_iso (adj : L ⊣ R) (i : L ⋙ R ≅ 𝟭 C) : IsIso adj.unit := (inferInstanceAs (IsIso (unitAsIsoOfIso adj i).hom)) /-- -Given an adjunction `L ⊣ R`, if `L ⋙ R` is isomorphic to the identity functor, then `L` is +Given an adjunction `L ⊣ R`, if `L ⋙ R` is isomorphic to the identity functor, then `L` is fully faithful. -/ noncomputable def fullyFaithfulLOfCompIsoId (adj : L ⊣ R) (i : L ⋙ R ≅ 𝟭 C) : L.FullyFaithful := @@ -112,7 +112,7 @@ noncomputable def fullyFaithfulLOfCompIsoId (adj : L ⊣ R) (i : L ⋙ R ≅ adj.fullyFaithfulLOfIsIsoUnit /-- -Given an adjunction `L ⊣ R`, if `R ⋙ L` is abstractly isomorphic to the identity functor, then the +Given an adjunction `L ⊣ R`, if `R ⋙ L` is abstractly isomorphic to the identity functor, then the counit is an isomorphism. -/ def counitAsIsoOfIso (adj : L ⊣ R) (j : R ⋙ L ≅ 𝟭 D) : R ⋙ L ≅ 𝟭 D where @@ -132,7 +132,7 @@ lemma isIso_counit_of_iso (adj : L ⊣ R) (j : R ⋙ L ≅ 𝟭 D) : IsIso adj.c inferInstanceAs (IsIso (counitAsIsoOfIso adj j).hom) /-- -Given an adjunction `L ⊣ R`, if `R ⋙ L` is isomorphic to the identity functor, then `R` is +Given an adjunction `L ⊣ R`, if `R ⋙ L` is isomorphic to the identity functor, then `R` is fully faithful. -/ noncomputable def fullyFaithfulROfCompIsoId (adj : L ⊣ R) (j : R ⋙ L ≅ 𝟭 D) : R.FullyFaithful := @@ -268,7 +268,7 @@ from `C` to the category of Eilenberg-Moore algebras for the adjunction is an eq class ComonadicLeftAdjoint (L : C ⥤ D) where /-- a choice of right adjoint for `L` -/ R : D ⥤ C - /-- `L` is a right adjoint -/ + /-- `L` is a left adjoint -/ adj : L ⊣ R eqv : (Comonad.comparison adj).IsEquivalence 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 911f458280a80..6a82f3d208edd 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 @@ -250,7 +250,7 @@ variable {C} -/ /- Porting note: removed `@[simps (config := { rhsMd := semireducible })]` -and replaced with `@[simps]` in the two declarations below-/ +and replaced with `@[simps]` in the two declarations below -/ @[simps!] def MonadIso.toNatIso {M N : Monad C} (h : M ≅ N) : (M : C ⥤ C) ≅ N := (monadToFunctor C).mapIso h diff --git a/Mathlib/CategoryTheory/Monad/Comonadicity.lean b/Mathlib/CategoryTheory/Monad/Comonadicity.lean new file mode 100644 index 0000000000000..7aeb43cea5361 --- /dev/null +++ b/Mathlib/CategoryTheory/Monad/Comonadicity.lean @@ -0,0 +1,399 @@ +/- +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.Limits.Preserves.Shapes.Equalizers +import Mathlib.CategoryTheory.Limits.Shapes.Reflexive +import Mathlib.CategoryTheory.Monad.Equalizer +import Mathlib.CategoryTheory.Monad.Limits + +/-! +# Comonadicity theorems + +We prove comonadicity theorems which can establish a given functor is comonadic. In particular, we +show three versions of Beck's comonadicity theorem, and the coreflexive (crude) +comonadicity theorem: + +`F` is a comonadic left adjoint if it has a right adjoint, and: + +* `C` has, `F` preserves and reflects `F`-split equalizers, see + `CategoryTheory.Monad.comonadicOfHasPreservesReflectsFSplitEqualizers` +* `F` creates `F`-split coequalizers, see + `CategoryTheory.Monad.comonadicOfCreatesFSplitEqualizers` + (The converse of this is also shown, see + `CategoryTheory.Monad.createsFSplitEqualizersOfComonadic`) +* `C` has and `F` preserves `F`-split equalizers, and `F` reflects isomorphisms, see + `CategoryTheory.Monad.comonadicOfHasPreservesFSplitEqualizersOfReflectsIsomorphisms` +* `C` has and `F` preserves coreflexive equalizers, and `F` reflects isomorphisms, see + `CategoryTheory.Monad.comonadicOfHasPreservesCoreflexiveEqualizersOfReflectsIsomorphisms` + +This file has been adapted from `Mathlib.CategoryTheory.Monad.Monadicity`. +Please try to keep them in sync. + +## Tags + +Beck, comonadicity, descent + +-/ + +universe v₁ v₂ u₁ u₂ + +namespace CategoryTheory + +namespace Comonad + +open Limits + +noncomputable section + +-- Hide the implementation details in this namespace. +namespace ComonadicityInternal + +variable {C : Type u₁} {D : Type u₂} +variable [Category.{v₁} C] [Category.{v₁} D] +variable {F : C ⥤ D} {G : D ⥤ C} (adj : F ⊣ G) + +/-- The "main pair" for a coalgebra `(A, α)` is the pair of morphisms `(G α, η_GA)`. It is always a +coreflexive pair, and will be used to construct the left adjoint to the comparison functor and show +it is an equivalence. +-/ +instance main_pair_coreflexive (A : adj.toComonad.Coalgebra) : + IsCoreflexivePair (G.map A.a) (adj.unit.app (G.obj A.A)) := by + apply IsCoreflexivePair.mk' (G.map (adj.counit.app _)) _ _ + · rw [← G.map_comp, ← G.map_id] + exact congr_arg G.map A.counit + · rw [adj.right_triangle_components] + rfl + +/-- The "main pair" for a coalgebra `(A, α)` is the pair of morphisms `(G α, η_GA)`. It is always a +`G`-cosplit pair, and will be used to construct the right adjoint to the comparison functor and show +it is an equivalence. +-/ +instance main_pair_F_cosplit (A : adj.toComonad.Coalgebra) : + F.IsCosplitPair (G.map A.a) + (adj.unit.app (G.obj A.A)) where + splittable := ⟨_, _, ⟨beckSplitEqualizer A⟩⟩ + +/-- The object function for the right adjoint to the comparison functor. -/ +def comparisonRightAdjointObj (A : adj.toComonad.Coalgebra) + [HasEqualizer (G.map A.a) (adj.unit.app _)] : C := + equalizer (G.map A.a) (adj.unit.app _) + +/-- +We have a bijection of homsets which will be used to construct the right adjoint to the comparison +functor. +-/ +@[simps!] +def comparisonRightAdjointHomEquiv (A : adj.toComonad.Coalgebra) (B : C) + [HasEqualizer (G.map A.a) (adj.unit.app (G.obj A.A))] : + ((comparison adj).obj B ⟶ A) ≃ (B ⟶ comparisonRightAdjointObj adj A) where + toFun f := by + refine equalizer.lift (adj.homEquiv _ _ f.f) ?_ + simp only [Adjunction.toComonad_coe, Functor.comp_obj, Adjunction.homEquiv_unit, + Functor.id_obj, Category.assoc, ← G.map_comp, ← f.h, comparison_obj_A, comparison_obj_a] + rw [Functor.comp_map, Functor.map_comp, Adjunction.unit_naturality_assoc, + Adjunction.unit_naturality] + invFun f := by + refine ⟨(adj.homEquiv _ _).symm (f ≫ (equalizer.ι _ _)), (adj.homEquiv _ _).injective ?_⟩ + simp only [Adjunction.toComonad_coe, Functor.comp_obj, comparison_obj_A, comparison_obj_a, + Adjunction.homEquiv_counit, Functor.id_obj, Functor.map_comp, Category.assoc, + Functor.comp_map, Adjunction.homEquiv_unit, Adjunction.unit_naturality_assoc, + Adjunction.unit_naturality, Adjunction.right_triangle_components_assoc] + congr 1 + exact (equalizer.condition _ _).symm + left_inv f := by aesop + right_inv f := by apply equalizer.hom_ext; simp + +/-- Construct the adjunction to the comparison functor. +-/ +def rightAdjointComparison + [∀ A : adj.toComonad.Coalgebra, HasEqualizer (G.map A.a) + (adj.unit.app (G.obj A.A))] : + adj.toComonad.Coalgebra ⥤ C := by + refine + Adjunction.rightAdjointOfEquiv (F := comparison adj) + (G_obj := fun A => comparisonRightAdjointObj adj A) (fun A B => ?_) ?_ + · apply comparisonRightAdjointHomEquiv + · intro A B B' g h + apply equalizer.hom_ext + simp + +/-- Provided we have the appropriate equalizers, we have an adjunction to the comparison functor. +-/ +@[simps! counit] +def comparisonAdjunction + [∀ A : adj.toComonad.Coalgebra, HasEqualizer (G.map A.a) + (adj.unit.app (G.obj A.A))] : + comparison adj ⊣ rightAdjointComparison adj := + Adjunction.adjunctionOfEquivRight _ _ + +variable {adj} + +theorem comparisonAdjunction_counit_f_aux + [∀ A : adj.toComonad.Coalgebra, HasEqualizer (G.map A.a) + (adj.unit.app (G.obj A.A))] + (A : adj.toComonad.Coalgebra) : + ((comparisonAdjunction adj).counit.app A).f = + (adj.homEquiv _ A.A).symm (equalizer.ι (G.map A.a) (adj.unit.app (G.obj A.A))) := + congr_arg (adj.homEquiv _ _).symm (Category.id_comp _) + +/-- This is a fork which is helpful for establishing comonadicity: the morphism from this fork to +the Beck equalizer is the counit for the adjunction on the comparison functor. +-/ +@[simps! pt] +def counitFork (A : adj.toComonad.Coalgebra) + [HasEqualizer (G.map A.a) (adj.unit.app (G.obj A.A))] : + Fork (F.map (G.map A.a)) (F.map (adj.unit.app (G.obj A.A))) := + Fork.ofι (F.map (equalizer.ι (G.map A.a) (adj.unit.app (G.obj A.A)))) + (by + change _ = F.map _ ≫ _ + rw [← F.map_comp, equalizer.condition, F.map_comp]) + +@[simp] +theorem unitFork_ι (A : adj.toComonad.Coalgebra) + [HasEqualizer (G.map A.a) (adj.unit.app (G.obj A.A))] : + (counitFork A).ι = F.map (equalizer.ι (G.map A.a) (adj.unit.app (G.obj A.A))) := + rfl + +theorem comparisonAdjunction_counit_f + [∀ A : adj.toComonad.Coalgebra, HasEqualizer (G.map A.a) + (adj.unit.app (G.obj A.A))] + (A : adj.toComonad.Coalgebra) : + ((comparisonAdjunction adj).counit.app A).f = (beckEqualizer A).lift (counitFork A) := by + simp + +variable (adj) + +/-- The fork which describes the unit of the adjunction: the morphism from this fork to the +the equalizer of this pair is the unit. +-/ +@[simps!] +def unitFork (B : C) : + Fork (G.map (F.map (adj.unit.app B))) + (adj.unit.app (G.obj (F.obj B))) := + Fork.ofι (adj.unit.app B) (adj.unit_naturality _) + +variable {adj} in +/-- The counit fork is a limit provided `F` preserves it. -/ +def counitLimitOfPreservesEqualizer (A : adj.toComonad.Coalgebra) + [HasEqualizer (G.map A.a) (adj.unit.app (G.obj A.A))] + [PreservesLimit (parallelPair (G.map A.a) (adj.unit.app (G.obj A.A))) F] : + IsLimit (counitFork (G := G) A) := + isLimitOfHasEqualizerOfPreservesLimit F _ _ + +/-- The unit fork is a limit provided `F` coreflects it. -/ +def unitEqualizerOfCoreflectsEqualizer (B : C) + [ReflectsLimit (parallelPair (G.map (F.map (adj.unit.app B))) + (adj.unit.app (G.obj (F.obj B)))) F] : + IsLimit (unitFork (adj := adj) B) := + isLimitOfIsLimitForkMap F _ (beckEqualizer ((comparison adj).obj B)) + +instance + [∀ A : adj.toComonad.Coalgebra, HasEqualizer (G.map A.a) (adj.unit.app (G.obj A.A))] + (B : C) : HasLimit (parallelPair + (G.map (F.map (NatTrans.app adj.unit B))) + (NatTrans.app adj.unit (G.obj (F.obj B)))) := + inferInstanceAs <| HasEqualizer + (G.map ((comparison adj).obj B).a) + (adj.unit.app (G.obj ((comparison adj).obj B).A)) + +theorem comparisonAdjunction_unit_app + [∀ A : adj.toComonad.Coalgebra, HasEqualizer (G.map A.a) (adj.unit.app (G.obj A.A))] (B : C) : + (comparisonAdjunction adj).unit.app B = limit.lift _ (unitFork adj B) := by + apply equalizer.hom_ext + change + equalizer.lift ((adj.homEquiv B _) (𝟙 _)) _ ≫ equalizer.ι _ _ = + equalizer.lift _ _ ≫ equalizer.ι _ _ + simp + +end ComonadicityInternal + +open CategoryTheory Adjunction Comonad ComonadicityInternal + +variable {C : Type u₁} {D : Type u₂} +variable [Category.{v₁} C] [Category.{v₁} D] +variable {F : C ⥤ D} {G : D ⥤ C} (adj : F ⊣ G) + +variable (G) in +/-- +If `F` is comonadic, it creates limits of `F`-cosplit pairs. This is the "boring" direction of +Beck's comonadicity theorem, the converse is given in `comonadicOfCreatesFSplitEqualizers`. +-/ +def createsFSplitEqualizersOfComonadic [ComonadicLeftAdjoint F] ⦃A B⦄ (f g : A ⟶ B) + [F.IsCosplitPair f g] : CreatesLimit (parallelPair f g) F := by + apply (config := {allowSynthFailures := true}) comonadicCreatesLimitOfPreservesLimit + · apply @preservesLimitOfIsoDiagram _ _ _ _ _ _ _ _ _ (diagramIsoParallelPair.{v₁} _).symm ?_ + dsimp + infer_instance + · apply @preservesLimitOfIsoDiagram _ _ _ _ _ _ _ _ _ (diagramIsoParallelPair.{v₁} _).symm ?_ + dsimp + infer_instance + +section BeckComonadicity + +/-- Dual to `Monad.HasCoequalizerOfIsSplitPair`. -/ +class HasEqualizerOfIsCosplitPair (F : C ⥤ D) : Prop where + /-- If `f, g` is an `F`-cosplit pair, then they have an equalizer. -/ + out : ∀ {A B} (f g : A ⟶ B) [F.IsCosplitPair f g], HasEqualizer f g + +instance [HasEqualizerOfIsCosplitPair F] : ∀ (A : Coalgebra adj.toComonad), + HasEqualizer (G.map A.a) + (adj.unit.app (G.obj A.A)) := + fun _ => HasEqualizerOfIsCosplitPair.out F _ _ + +/-- Dual to `Monad.PreservesColimitOfIsSplitPair`. -/ +class PreservesLimitOfIsCosplitPair (F : C ⥤ D) where + /-- If `f, g` is an `F`-cosplit pair, then `F` preserves limits of `parallelPair f g`. -/ + out : ∀ {A B} (f g : A ⟶ B) [F.IsCosplitPair f g], PreservesLimit (parallelPair f g) F + +instance {A B} (f g : A ⟶ B) [F.IsCosplitPair f g] [PreservesLimitOfIsCosplitPair F] : + PreservesLimit (parallelPair f g) F := PreservesLimitOfIsCosplitPair.out f g + +instance [PreservesLimitOfIsCosplitPair F] : ∀ (A : Coalgebra adj.toComonad), + PreservesLimit (parallelPair (G.map A.a) + (NatTrans.app adj.unit (G.obj A.A))) F := + fun _ => PreservesLimitOfIsCosplitPair.out _ _ + +/-- Dual to `Monad.ReflectsColimitOfIsSplitPair`. -/ +class ReflectsLimitOfIsCosplitPair (F : C ⥤ D) where + /-- If `f, g` is an `F`-cosplit pair, then `F` reflects limits for `parallelPair f g`. -/ + out : ∀ {A B} (f g : A ⟶ B) [F.IsCosplitPair f g], ReflectsLimit (parallelPair f g) F + +instance {A B} (f g : A ⟶ B) [F.IsCosplitPair f g] [ReflectsLimitOfIsCosplitPair F] : + ReflectsLimit (parallelPair f g) F := ReflectsLimitOfIsCosplitPair.out f g + +instance [ReflectsLimitOfIsCosplitPair F] : ∀ (A : Coalgebra adj.toComonad), + ReflectsLimit (parallelPair (G.map A.a) + (NatTrans.app adj.unit (G.obj A.A))) F := + fun _ => ReflectsLimitOfIsCosplitPair.out _ _ + +/-- To show `F` is a comonadic left adjoint, we can show it preserves and reflects `F`-split +equalizers, and `C` has them. +-/ +def comonadicOfHasPreservesReflectsFSplitEqualizers [HasEqualizerOfIsCosplitPair F] + [PreservesLimitOfIsCosplitPair F] [ReflectsLimitOfIsCosplitPair F] : + ComonadicLeftAdjoint F where + adj := adj + eqv := by + have : ∀ (X : Coalgebra adj.toComonad), IsIso ((comparisonAdjunction adj).counit.app X) := by + intro X + apply @isIso_of_reflects_iso _ _ _ _ _ _ _ (Comonad.forget adj.toComonad) ?_ _ + · change IsIso ((comparisonAdjunction adj).counit.app X).f + rw [comparisonAdjunction_counit_f] + change + IsIso + (IsLimit.conePointUniqueUpToIso (beckEqualizer X) + (counitLimitOfPreservesEqualizer X)).inv + exact (IsLimit.conePointUniqueUpToIso _ _).isIso_inv + have : ∀ (Y : C), IsIso ((comparisonAdjunction adj).unit.app Y) := by + intro Y + rw [comparisonAdjunction_unit_app] + change IsIso (IsLimit.conePointUniqueUpToIso _ ?_).inv + infer_instance + apply @unitEqualizerOfCoreflectsEqualizer _ _ _ _ _ _ _ _ ?_ + letI _ : + F.IsCosplitPair (G.map (F.map (adj.unit.app Y))) + (adj.unit.app (G.obj (F.obj Y))) := + ComonadicityInternal.main_pair_F_cosplit _ ((comparison adj).obj Y) + infer_instance + exact (comparisonAdjunction adj).toEquivalence.symm.isEquivalence_inverse + +/-- Dual to `Monad.CreatesColimitOfIsSplitPair`. -/ +class CreatesLimitOfIsCosplitPair (F : C ⥤ D) where + /-- If `f, g` is an `F`-cosplit pair, then `F` creates limits of `parallelPair f g`. -/ + out : ∀ {A B} (f g : A ⟶ B) [F.IsCosplitPair f g], CreatesLimit (parallelPair f g) F + +instance {A B} (f g : A ⟶ B) [F.IsCosplitPair f g] [CreatesLimitOfIsCosplitPair F] : + CreatesLimit (parallelPair f g) F := CreatesLimitOfIsCosplitPair.out f g + +instance [CreatesLimitOfIsCosplitPair F] : ∀ (A : Coalgebra adj.toComonad), + CreatesLimit (parallelPair (G.map A.a) + (NatTrans.app adj.unit (G.obj A.A))) F := + fun _ => CreatesLimitOfIsCosplitPair.out _ _ + +/-- +Beck's comonadicity theorem. If `F` has a right adjoint and creates equalizers of `F`-cosplit pairs, +then it is comonadic. +This is the converse of `createsFSplitEqualizersOfComonadic`. +-/ +def comonadicOfCreatesFSplitEqualizers [CreatesLimitOfIsCosplitPair F] : + ComonadicLeftAdjoint F := by + let I {A B} (f g : A ⟶ B) [F.IsCosplitPair f g] : HasLimit (parallelPair f g ⋙ F) := by + apply @hasLimitOfIso _ _ _ _ _ _ ?_ (diagramIsoParallelPair.{v₁} _).symm + exact inferInstanceAs <| HasEqualizer (F.map f) (F.map g) + have : HasEqualizerOfIsCosplitPair F := ⟨fun _ _ => hasLimit_of_created (parallelPair _ _) F⟩ + have : PreservesLimitOfIsCosplitPair F := ⟨by intros; infer_instance⟩ + have : ReflectsLimitOfIsCosplitPair F := ⟨by intros; infer_instance⟩ + exact comonadicOfHasPreservesReflectsFSplitEqualizers adj + +/-- An alternate version of Beck's comonadicity theorem. If `F` reflects isomorphisms, preserves +equalizers of `F`-cosplit pairs and `C` has equalizers of `F`-cosplit pairs, then it is comonadic. +-/ +def comonadicOfHasPreservesFSplitEqualizersOfReflectsIsomorphisms [F.ReflectsIsomorphisms] + [HasEqualizerOfIsCosplitPair F] [PreservesLimitOfIsCosplitPair F] : + ComonadicLeftAdjoint F := by + have : ReflectsLimitOfIsCosplitPair F := ⟨fun f g _ => by + have := HasEqualizerOfIsCosplitPair.out F f g + apply reflectsLimitOfReflectsIsomorphisms⟩ + apply comonadicOfHasPreservesReflectsFSplitEqualizers adj + +end BeckComonadicity + +section CoreflexiveComonadicity + +variable [HasCoreflexiveEqualizers C] [F.ReflectsIsomorphisms] + +/-- Dual to `Monad.PreservesColimitOfIsReflexivePair`. -/ +class PreservesLimitOfIsCoreflexivePair (F : C ⥤ D) where + /-- `f, g` is a coreflexive pair, then `F` preserves limits of `parallelPair f g`. -/ + out : ∀ ⦃A B⦄ (f g : A ⟶ B) [IsCoreflexivePair f g], PreservesLimit (parallelPair f g) F + +instance {A B} (f g : A ⟶ B) [IsCoreflexivePair f g] [PreservesLimitOfIsCoreflexivePair F] : + PreservesLimit (parallelPair f g) F := PreservesLimitOfIsCoreflexivePair.out f g + +instance [PreservesLimitOfIsCoreflexivePair F] : ∀ X : Coalgebra adj.toComonad, + PreservesLimit (parallelPair (G.map X.a) + (NatTrans.app adj.unit (G.obj X.A))) F := + fun _ => PreservesLimitOfIsCoreflexivePair.out _ _ + +variable [PreservesLimitOfIsCoreflexivePair F] + +/-- Coreflexive (crude) comonadicity theorem. If `F` has a right adjoint, `C` has and `F` preserves +coreflexive equalizers and `F` reflects isomorphisms, then `F` is comonadic. +-/ +def comonadicOfHasPreservesCoreflexiveEqualizersOfReflectsIsomorphisms : + ComonadicLeftAdjoint F where + adj := adj + eqv := by + have : ∀ (X : adj.toComonad.Coalgebra), IsIso ((comparisonAdjunction adj).counit.app X) := by + intro X + apply + @isIso_of_reflects_iso _ _ _ _ _ _ _ (Comonad.forget adj.toComonad) ?_ _ + · change IsIso ((comparisonAdjunction adj).counit.app X).f + rw [comparisonAdjunction_counit_f] + exact (IsLimit.conePointUniqueUpToIso (beckEqualizer X) + (counitLimitOfPreservesEqualizer X)).isIso_inv + have : ∀ (Y : C), IsIso ((comparisonAdjunction adj).unit.app Y) := by + intro Y + rw [comparisonAdjunction_unit_app] + change IsIso (IsLimit.conePointUniqueUpToIso _ ?_).inv + infer_instance + have : IsCoreflexivePair (G.map (F.map (adj.unit.app Y))) + (adj.unit.app (G.obj (F.obj Y))) := by + apply IsCoreflexivePair.mk' (G.map (adj.counit.app _)) _ _ + · rw [← G.map_comp, ← G.map_id] + exact congr_arg G.map (adj.left_triangle_components Y) + · rw [← G.map_id] + simp + apply @unitEqualizerOfCoreflectsEqualizer _ _ _ _ _ _ _ _ ?_ + apply reflectsLimitOfReflectsIsomorphisms + exact (comparisonAdjunction adj).toEquivalence.symm.isEquivalence_inverse + +end CoreflexiveComonadicity + +end + +end Comonad + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Monad/Kleisli.lean b/Mathlib/CategoryTheory/Monad/Kleisli.lean index 7b0bfe3c11446..1bea86e9b33ad 100644 --- a/Mathlib/CategoryTheory/Monad/Kleisli.lean +++ b/Mathlib/CategoryTheory/Monad/Kleisli.lean @@ -75,7 +75,7 @@ def fromKleisli : Kleisli T ⥤ C where -- 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)`. @@ -159,7 +159,7 @@ 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. -/ diff --git a/Mathlib/CategoryTheory/Monad/Limits.lean b/Mathlib/CategoryTheory/Monad/Limits.lean index f447048e82490..1e1128d105453 100644 --- a/Mathlib/CategoryTheory/Monad/Limits.lean +++ b/Mathlib/CategoryTheory/Monad/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, Bhavik Mehta, Jack McKoen +Authors: Kim Morrison, Bhavik Mehta, Jack McKoen -/ import Mathlib.CategoryTheory.Monad.Adjunction import Mathlib.CategoryTheory.Adjunction.Limits diff --git a/Mathlib/CategoryTheory/Monad/Monadicity.lean b/Mathlib/CategoryTheory/Monad/Monadicity.lean index 00f33ae1bf954..5dbca1937d5e9 100644 --- a/Mathlib/CategoryTheory/Monad/Monadicity.lean +++ b/Mathlib/CategoryTheory/Monad/Monadicity.lean @@ -14,7 +14,7 @@ import Mathlib.CategoryTheory.Monad.Limits We prove monadicity theorems which can establish a given functor is monadic. In particular, we show three versions of Beck's monadicity theorem, and the reflexive (crude) monadicity theorem: -`G` is a monadic right adjoint if it has a right adjoint, and: +`G` is a monadic right adjoint if it has a left adjoint, and: * `D` has, `G` preserves and reflects `G`-split coequalizers, see `CategoryTheory.Monad.monadicOfHasPreservesReflectsGSplitCoequalizers` @@ -27,13 +27,13 @@ show three versions of Beck's monadicity theorem, and the reflexive (crude) mona * `D` has and `G` preserves reflexive coequalizers, and `G` reflects isomorphisms, see `CategoryTheory.Monad.monadicOfHasPreservesReflexiveCoequalizersOfReflectsIsomorphisms` +This file has been adapted to `Mathlib.CategoryTheory.Monad.Comonadicity`. +Please try to keep them in sync. + ## Tags Beck, monadicity, descent -## TODO - -Dualise to show comonadicity theorems. -/ universe v₁ v₂ u₁ u₂ @@ -187,7 +187,7 @@ def counitCofork (B : D) : Cofork.ofπ (adj.counit.app B) (adj.counit_naturality _) variable {adj} in -/-- The unit cofork is a colimit provided `G` preserves it. -/ +/-- The unit cofork is a colimit provided `G` preserves it. -/ def unitColimitOfPreservesCoequalizer (A : adj.toMonad.Algebra) [HasCoequalizer (F.map A.a) (adj.counit.app (F.obj A.A))] [PreservesColimit (parallelPair (F.map A.a) (adj.counit.app (F.obj A.A))) G] : @@ -288,7 +288,7 @@ instance [ReflectsColimitOfIsSplitPair G] : ∀ (A : Algebra adj.toMonad), fun _ => ReflectsColimitOfIsSplitPair.out _ _ /-- To show `G` is a monadic right adjoint, we can show it preserves and reflects `G`-split -coequalizers, and `C` has them. +coequalizers, and `D` has them. -/ def monadicOfHasPreservesReflectsGSplitCoequalizers [HasCoequalizerOfIsSplitPair G] [PreservesColimitOfIsSplitPair G] [ReflectsColimitOfIsSplitPair G] : @@ -334,9 +334,9 @@ instance [CreatesColimitOfIsSplitPair G] : ∀ (A : Algebra adj.toMonad), fun _ => CreatesColimitOfIsSplitPair.out _ _ /-- -Beck's monadicity theorem. If `G` has a right adjoint and creates coequalizers of `G`-split pairs, +Beck's monadicity theorem. If `G` has a left adjoint and creates coequalizers of `G`-split pairs, then it is monadic. -This is the converse of `createsGSplitOfMonadic`. +This is the converse of `createsGSplitCoequalizersOfMonadic`. -/ def monadicOfCreatesGSplitCoequalizers [CreatesColimitOfIsSplitPair G] : MonadicRightAdjoint G := by diff --git a/Mathlib/CategoryTheory/Monoidal/Bimod.lean b/Mathlib/CategoryTheory/Monoidal/Bimod.lean index a29f338d9a4d7..b4118c7d293bf 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_ @@ -201,13 +201,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 +224,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 +240,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 +484,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 +510,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 +529,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 +550,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 +605,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 +659,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 +764,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 +926,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 9d5818ef51531..109f528c80123 100644 --- a/Mathlib/CategoryTheory/Monoidal/Bimon_.lean +++ b/Mathlib/CategoryTheory/Monoidal/Bimon_.lean @@ -14,8 +14,6 @@ as comonoid objects in the category of monoid objects in `C`. We verify that this is equivalent to the monoid objects in the category of comonoid objects. ## TODO -* Define Hopf monoids, which in a cartesian monoidal category are exactly group objects, - and use this to define group schemes. * Construct the category of modules, and show that it is monoidal with a monoidal forgetful functor to `C`. * Some form of Tannaka reconstruction: @@ -112,4 +110,71 @@ def equivMon_Comon_ : Bimon_ C ≌ Mon_ (Comon_ C) where unitIso := NatIso.ofComponents (fun _ => Comon_.mkIso (Mon_.mkIso (Iso.refl _))) counitIso := NatIso.ofComponents (fun _ => Mon_.mkIso (Comon_.mkIso (Iso.refl _))) +/-! # The trivial bimonoid -/ + +/-- The trivial bimonoid object. -/ +@[simps!] +def trivial : Bimon_ C := Comon_.trivial (Mon_ C) + +/-- The bimonoid morphism from the trivial bimonoid to any bimonoid. -/ +@[simps] +def trivial_to (A : Bimon_ C) : trivial C ⟶ A := + { hom := (default : Mon_.trivial C ⟶ A.X), } + +/-- The bimonoid morphism from any bimonoid to the trivial bimonoid. -/ +@[simps!] +def to_trivial (A : Bimon_ C) : A ⟶ trivial C := + (default : @Quiver.Hom (Comon_ (Mon_ C)) _ A (Comon_.trivial (Mon_ C))) + +/-! # Additional lemmas -/ + +variable {C} + +@[reassoc] +theorem one_comul (M : Bimon_ C) : + M.X.one ≫ M.comul.hom = (λ_ _).inv ≫ (M.X.one ⊗ M.X.one) := by + simp + +@[reassoc] +theorem mul_counit (M : Bimon_ C) : + M.X.mul ≫ M.counit.hom = (M.counit.hom ⊗ M.counit.hom) ≫ (λ_ _).hom := by + simp + +/-- Compatibility of the monoid and comonoid structures, in terms of morphisms in `C`. -/ +@[reassoc (attr := simp)] theorem compatibility (M : Bimon_ C) : + (M.comul.hom ⊗ M.comul.hom) ≫ + (α_ _ _ (M.X.X ⊗ M.X.X)).hom ≫ M.X.X ◁ (α_ _ _ _).inv ≫ + M.X.X ◁ (β_ M.X.X M.X.X).hom ▷ M.X.X ≫ + M.X.X ◁ (α_ _ _ _).hom ≫ (α_ _ _ _).inv ≫ + (M.X.mul ⊗ M.X.mul) = + M.X.mul ≫ M.comul.hom := by + have := (Mon_.Hom.mul_hom M.comul).symm + simpa [-Mon_.Hom.mul_hom, tensor_μ] using this + +@[reassoc (attr := simp)] theorem comul_counit_hom (M : Bimon_ C) : + M.comul.hom ≫ (_ ◁ M.counit.hom) = (ρ_ _).inv := by + simpa [- Comon_.comul_counit] using congr_arg Mon_.Hom.hom M.comul_counit + +@[reassoc (attr := simp)] theorem counit_comul_hom (M : Bimon_ C) : + M.comul.hom ≫ (M.counit.hom ▷ _) = (λ_ _).inv := by + simpa [- Comon_.counit_comul] using congr_arg Mon_.Hom.hom M.counit_comul + +@[reassoc (attr := simp)] theorem comul_assoc_hom (M : Bimon_ C) : + M.comul.hom ≫ (M.X.X ◁ M.comul.hom) = + M.comul.hom ≫ (M.comul.hom ▷ M.X.X) ≫ (α_ M.X.X M.X.X M.X.X).hom := by + simpa [- Comon_.comul_assoc] using congr_arg Mon_.Hom.hom M.comul_assoc + +@[reassoc] theorem comul_assoc_flip_hom (M : Bimon_ C) : + M.comul.hom ≫ (M.comul.hom ▷ M.X.X) = + M.comul.hom ≫ (M.X.X ◁ M.comul.hom) ≫ (α_ M.X.X M.X.X M.X.X).inv := by + simp + +@[reassoc] theorem hom_comul_hom {M N : Bimon_ C} (f : M ⟶ N) : + f.hom.hom ≫ N.comul.hom = M.comul.hom ≫ (f.hom.hom ⊗ f.hom.hom) := by + simpa [- Comon_.Hom.hom_comul] using congr_arg Mon_.Hom.hom f.hom_comul + +@[reassoc] theorem hom_counit_hom {M N : Bimon_ C} (f : M ⟶ N) : + f.hom.hom ≫ N.counit.hom = M.counit.hom := by + simpa [- Comon_.Hom.hom_counit] using congr_arg Mon_.Hom.hom f.hom_counit + end Bimon_ diff --git a/Mathlib/CategoryTheory/Monoidal/Braided/Basic.lean b/Mathlib/CategoryTheory/Monoidal/Braided/Basic.lean index f0ba170eb47a1..ecac5bcd3be12 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 @@ -455,8 +455,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 := @@ -504,18 +502,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 +531,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 +562,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/Category.lean b/Mathlib/CategoryTheory/Monoidal/Category.lean index 53371440fcf7e..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 @@ -279,15 +280,6 @@ theorem tensorHom_def' {X₁ Y₁ X₂ Y₂ : C} (f : X₁ ⟶ Y₁) (g : X₂ f ⊗ g = X₁ ◁ g ≫ f ▷ Y₂ := whisker_exchange f g ▸ tensorHom_def f g -end MonoidalCategory - -open scoped MonoidalCategory -open MonoidalCategory - -variable {C : Type u} [𝒞 : Category.{v} C] [MonoidalCategory C] - -namespace MonoidalCategory - @[reassoc (attr := simp)] theorem whiskerLeft_hom_inv (X : C) {Y Z : C} (f : Y ≅ Z) : X ◁ f.hom ≫ X ◁ f.inv = 𝟙 (X ⊗ Y) := by @@ -384,11 +376,9 @@ lemma whiskerRightIso_trans {X Y Z : C} (f : X ≅ Y) (g : Y ≅ Z) (W : C) : lemma whiskerRightIso_symm {X Y : C} (f : X ≅ Y) (W : C) : (whiskerRightIso f W).symm = whiskerRightIso f.symm W := rfl -end MonoidalCategory - /-- The tensor product of two isomorphisms is an isomorphism. -/ @[simps] -def tensorIso {C : Type u} {X Y X' Y' : C} [Category.{v} C] [MonoidalCategory.{v} C] (f : X ≅ Y) +def tensorIso {X Y X' Y' : C} (f : X ≅ Y) (g : X' ≅ Y') : X ⊗ X' ≅ Y ⊗ Y' where hom := f.hom ⊗ g.hom inv := f.inv ⊗ g.inv @@ -398,11 +388,13 @@ def tensorIso {C : Type u} {X Y X' Y' : C} [Category.{v} C] [MonoidalCategory.{v /-- Notation for `tensorIso`, the tensor product of isomorphisms -/ infixr:70 " ⊗ " => tensorIso -namespace MonoidalCategory +theorem tensorIso_def {X Y X' Y' : C} (f : X ≅ Y) (g : X' ≅ Y') : + f ⊗ g = whiskerRightIso f X' ≪≫ whiskerLeftIso Y g := + Iso.ext (tensorHom_def f.hom g.hom) -section - -variable {C : Type u} [Category.{v} C] [MonoidalCategory.{v} C] +theorem tensorIso_def' {X Y X' Y' : C} (f : X ≅ Y) (g : X' ≅ Y') : + f ⊗ g = whiskerLeftIso X g ≪≫ whiskerRightIso f Y' := + Iso.ext (tensorHom_def' f.hom g.hom) instance tensor_isIso {W X Y Z : C} (f : W ⟶ X) [IsIso f] (g : Y ⟶ Z) [IsIso g] : IsIso (f ⊗ g) := (asIso f ⊗ asIso g).isIso_hom @@ -759,8 +751,6 @@ theorem tensor_left_iff {X Y : C} (f g : X ⟶ Y) : 𝟙 (𝟙_ C) ⊗ f = 𝟙 theorem tensor_right_iff {X Y : C} (f g : X ⟶ Y) : f ⊗ 𝟙 (𝟙_ C) = g ⊗ 𝟙 (𝟙_ C) ↔ f = g := by simp -end - section variable (C) diff --git a/Mathlib/CategoryTheory/Monoidal/Center.lean b/Mathlib/CategoryTheory/Monoidal/Center.lean index 4d27a6af5c4be..5eab3c67802ba 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) : 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..b8a3c549ea911 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_ diff --git a/Mathlib/CategoryTheory/Monoidal/Comon_.lean b/Mathlib/CategoryTheory/Monoidal/Comon_.lean index 7da6f2e2289d8..61c63c58ac902 100644 --- a/Mathlib/CategoryTheory/Monoidal/Comon_.lean +++ b/Mathlib/CategoryTheory/Monoidal/Comon_.lean @@ -59,9 +59,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⟩ @@ -79,7 +79,7 @@ theorem comul_counit_hom {Z : C} (f : M.X ⟶ Z) : M.comul ≫ (f ⊗ M.counit) @[reassoc] theorem comul_assoc_flip : M.comul ≫ (M.comul ▷ M.X) = M.comul ≫ (M.X ◁ M.comul) ≫ (α_ M.X M.X M.X).inv := by - simp [← comul_assoc] + simp /-- A morphism of comonoid objects. -/ @[ext] @@ -156,11 +156,11 @@ def mkIso {M N : Comon_ C} (f : M.X ≅ N.X) (f_counit : f.hom ≫ N.counit = M. slice_rhs 1 2 => rw [f_comul] simp } +@[simps] instance uniqueHomToTrivial (A : Comon_ C) : Unique (A ⟶ trivial C) where default := { hom := A.counit - hom_counit := by dsimp; simp - hom_comul := by dsimp; simp [A.comul_counit, unitors_inv_equal] } + hom_comul := by simp [A.comul_counit, unitors_inv_equal] } uniq f := by ext; simp rw [← Category.comp_id f.hom] @@ -243,7 +243,8 @@ 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] @@ -260,7 +261,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 +270,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] diff --git a/Mathlib/CategoryTheory/Monoidal/Discrete.lean b/Mathlib/CategoryTheory/Monoidal/Discrete.lean index dbd834083cb6e..9ff8e09d5151e 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 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/Coherence.lean b/Mathlib/CategoryTheory/Monoidal/Free/Coherence.lean index 4752b8432ea1e..267ea5f8e51c9 100644 --- a/Mathlib/CategoryTheory/Monoidal/Free/Coherence.lean +++ b/Mathlib/CategoryTheory/Monoidal/Free/Coherence.lean @@ -185,7 +185,7 @@ def normalizeIsoApp : | tensor X a, n => (α_ _ _ _).symm ≪≫ whiskerRightIso (normalizeIsoApp X n) a ≪≫ normalizeIsoApp _ _ -/-- Almost non-definitionally equall to `normalizeIsoApp`, but has a better definitional property +/-- Almost non-definitionally equal to `normalizeIsoApp`, but has a better definitional property in the proof of `normalize_naturality`. -/ @[simp] def normalizeIsoApp' : diff --git a/Mathlib/CategoryTheory/Monoidal/Functor.lean b/Mathlib/CategoryTheory/Monoidal/Functor.lean index 8bf05788f4dbd..1cd5fbc682a6c 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 @@ -365,6 +365,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 @@ -699,12 +715,10 @@ noncomputable def monoidalAdjoint : instance [F.IsEquivalence] : IsIso (monoidalAdjoint F h).ε := by dsimp - rw [Adjunction.homEquiv_unit] infer_instance instance (X Y : D) [F.IsEquivalence] : IsIso ((monoidalAdjoint F h).μ X Y) := by dsimp - rw [Adjunction.homEquiv_unit] infer_instance /-- If a monoidal functor `F` is an equivalence of categories then its inverse is also monoidal. -/ diff --git a/Mathlib/CategoryTheory/Monoidal/FunctorCategory.lean b/Mathlib/CategoryTheory/Monoidal/FunctorCategory.lean index 90286ae948670..5a69edb48708b 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 diff --git a/Mathlib/CategoryTheory/Monoidal/Functorial.lean b/Mathlib/CategoryTheory/Monoidal/Functorial.lean index 26bd834c33628..5f9d7be6fbb24 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 diff --git a/Mathlib/CategoryTheory/Monoidal/Hopf_.lean b/Mathlib/CategoryTheory/Monoidal/Hopf_.lean new file mode 100644 index 0000000000000..4bf50784e7cc7 --- /dev/null +++ b/Mathlib/CategoryTheory/Monoidal/Hopf_.lean @@ -0,0 +1,466 @@ +/- +Copyright (c) 2024 Lean FRO LLC. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kim Morrison +-/ +import Mathlib.CategoryTheory.Monoidal.Bimon_ +import Mathlib.CategoryTheory.Monoidal.Conv + +/-! +# The category of Hopf monoids in a braided monoidal category. + + +## TODO + +* Show that in a cartesian monoidal category Hopf monoids are exactly group objects. +* Show that `Hopf_ (ModuleCat R) ≌ HopfAlgebraCat R`. +-/ + +noncomputable section + +universe v₁ v₂ u₁ u₂ u + +open CategoryTheory MonoidalCategory + +variable (C : Type u₁) [Category.{v₁} C] [MonoidalCategory.{v₁} C] [BraidedCategory C] + +/-- +A Hopf monoid in a braided category `C` is a bimonoid object in `C` equipped with an antipode. +-/ +structure Hopf_ where + /-- The underlying bimonoid of a Hopf monoid. -/ + X : Bimon_ C + /-- The antipode is an endomorphism of the underlying object of the Hopf monoid. -/ + antipode : X.X.X ⟶ X.X.X + antipode_left : X.comul.hom ≫ (antipode ▷ X.X.X) ≫ X.X.mul = X.counit.hom ≫ X.X.one + antipode_right : X.comul.hom ≫ (X.X.X ◁ antipode) ≫ X.X.mul = X.counit.hom ≫ X.X.one + +attribute [reassoc (attr := simp)] Hopf_.antipode_left Hopf_.antipode_right + +namespace Hopf_ + +/-- +Morphisms of Hopf monoids are just morphisms of the underlying bimonoids. +In fact they automatically intertwine the antipodes, proved below. +-/ +instance : Category (Hopf_ C) := inferInstanceAs <| Category (InducedCategory (Bimon_ C) Hopf_.X) + +variable {C} + +/-- Morphisms of Hopf monoids intertwine the antipodes. -/ +theorem hom_antipode {A B : Hopf_ C} (f : A ⟶ B) : + f.hom.hom ≫ B.antipode = A.antipode ≫ f.hom.hom := by + -- We show these elements are equal by exhibiting an element in the convolution algebra + -- between `A` (as a comonoid) and `B` (as a monoid), + -- such that the LHS is a left inverse, and the RHS is a right inverse. + apply left_inv_eq_right_inv + (M := Conv ((Bimon_.toComon_ C).obj A.X) B.X.X) + (a := f.hom.hom) + · erw [Conv.mul_eq, Conv.one_eq] + simp only [Bimon_.toComon__obj_X, Bimon_.toComon__obj_comul, comp_whiskerRight, Category.assoc, + Bimon_.toComon__obj_counit] + slice_lhs 3 4 => + rw [← whisker_exchange] + slice_lhs 2 3 => + rw [← tensorHom_def] + slice_lhs 1 2 => + rw [← Bimon_.hom_comul_hom f] + slice_lhs 2 4 => + rw [B.antipode_left] + slice_lhs 1 2 => + rw [Bimon_.hom_counit_hom f] + · erw [Conv.mul_eq, Conv.one_eq] + simp only [Bimon_.toComon__obj_X, Bimon_.toComon__obj_comul, MonoidalCategory.whiskerLeft_comp, + Category.assoc, Bimon_.toComon__obj_counit] + slice_lhs 2 3 => + rw [← whisker_exchange] + slice_lhs 3 4 => + rw [← tensorHom_def] + slice_lhs 3 4 => + rw [← f.hom.mul_hom] + slice_lhs 1 3 => + rw [A.antipode_right] + slice_lhs 2 3 => + rw [f.hom.one_hom] + +@[reassoc (attr := simp)] +theorem one_antipode (A : Hopf_ C) : A.X.X.one ≫ A.antipode = A.X.X.one := by + have := (rfl : A.X.X.one ≫ A.X.comul.hom ≫ (A.antipode ▷ A.X.X.X) ≫ A.X.X.mul = _) + conv at this => + rhs + rw [A.antipode_left] + rw [A.X.one_comul_assoc, tensorHom_def, Category.assoc, whisker_exchange_assoc] at this + simpa [unitors_inv_equal] + +@[reassoc (attr := simp)] +theorem antipode_counit (A : Hopf_ C) : A.antipode ≫ A.X.counit.hom = A.X.counit.hom := by + have := (rfl : A.X.comul.hom ≫ (A.antipode ▷ A.X.X.X) ≫ A.X.X.mul ≫ A.X.counit.hom = _) + conv at this => + rhs + rw [A.antipode_left_assoc] + rw [A.X.mul_counit, tensorHom_def', Category.assoc, ← whisker_exchange_assoc] at this + simpa [unitors_equal] + +/-! +## The antipode is an antihomomorphism with respect to both the monoid and comonoid structures. +-/ + +theorem antipode_comul₁ (A : Hopf_ C) : + A.X.comul.hom ≫ + A.antipode ▷ A.X.X.X ≫ + A.X.comul.hom ▷ A.X.X.X ≫ + (α_ A.X.X.X A.X.X.X A.X.X.X).hom ≫ + A.X.X.X ◁ A.X.X.X ◁ A.X.comul.hom ≫ + A.X.X.X ◁ (α_ A.X.X.X A.X.X.X A.X.X.X).inv ≫ + A.X.X.X ◁ (β_ A.X.X.X A.X.X.X).hom ▷ A.X.X.X ≫ + A.X.X.X ◁ (α_ A.X.X.X A.X.X.X A.X.X.X).hom ≫ + (α_ A.X.X.X A.X.X.X (A.X.X.X ⊗ A.X.X.X)).inv ≫ + (A.X.X.mul ⊗ A.X.X.mul) = + A.X.counit.hom ≫ (λ_ (𝟙_ C)).inv ≫ (A.X.X.one ⊗ A.X.X.one) := by + dsimp + slice_lhs 3 5 => + rw [← associator_naturality_right, ← Category.assoc, ← tensorHom_def] + slice_lhs 3 9 => + erw [Bimon_.compatibility] + slice_lhs 1 3 => + erw [A.antipode_left] + simp + +/-- +Auxiliary calculation for `antipode_comul`. +This calculation calls for some ASCII art out of This Week's Finds. + + | | + n n + | \ / | + | / | + | / \ | + | | S S + | | \ / + | | / + | | / \ + \ / \ / + v v + \ / + v + | + +We move the left antipode up through the crossing, +the right antipode down through the crossing, +the right multiplication down across the strand, +reassociate the comultiplications, +then use `antipode_right` then `antipode_left` to simplify. +-/ +theorem antipode_comul₂ (A : Hopf_ C) : + A.X.comul.hom ≫ + A.X.comul.hom ▷ A.X.X.X ≫ + (α_ A.X.X.X A.X.X.X A.X.X.X).hom ≫ + A.X.X.X ◁ A.X.X.X ◁ A.X.comul.hom ≫ + A.X.X.X ◁ A.X.X.X ◁ (β_ A.X.X.X A.X.X.X).hom ≫ + A.X.X.X ◁ A.X.X.X ◁ (A.antipode ⊗ A.antipode) ≫ + A.X.X.X ◁ (α_ A.X.X.X A.X.X.X A.X.X.X).inv ≫ + A.X.X.X ◁ (β_ A.X.X.X A.X.X.X).hom ▷ A.X.X.X ≫ + A.X.X.X ◁ (α_ A.X.X.X A.X.X.X A.X.X.X).hom ≫ + (α_ A.X.X.X A.X.X.X (A.X.X.X ⊗ A.X.X.X)).inv ≫ + (A.X.X.mul ⊗ A.X.X.mul) = + A.X.counit.hom ≫ (λ_ (𝟙_ C)).inv ≫ (A.X.X.one ⊗ A.X.X.one) := by + -- We should write a version of `slice_lhs` that zooms through whiskerings. + slice_lhs 6 6 => + simp only [tensorHom_def', MonoidalCategory.whiskerLeft_comp] + slice_lhs 7 8 => + rw [← MonoidalCategory.whiskerLeft_comp, associator_inv_naturality_middle, + MonoidalCategory.whiskerLeft_comp] + slice_lhs 8 9 => + rw [← MonoidalCategory.whiskerLeft_comp, ← comp_whiskerRight, + BraidedCategory.braiding_naturality_right, + comp_whiskerRight, MonoidalCategory.whiskerLeft_comp] + slice_lhs 9 10 => + rw [← MonoidalCategory.whiskerLeft_comp, + associator_naturality_left, + MonoidalCategory.whiskerLeft_comp] + slice_lhs 5 6 => + rw [← MonoidalCategory.whiskerLeft_comp, ← MonoidalCategory.whiskerLeft_comp, + ← BraidedCategory.braiding_naturality_left, + MonoidalCategory.whiskerLeft_comp, MonoidalCategory.whiskerLeft_comp] + slice_lhs 11 12 => + rw [tensorHom_def', ← Category.assoc, ← associator_inv_naturality_right] + slice_lhs 10 11 => + rw [← MonoidalCategory.whiskerLeft_comp, ← whisker_exchange, + MonoidalCategory.whiskerLeft_comp] + slice_lhs 6 10 => + simp only [← MonoidalCategory.whiskerLeft_comp] + rw [← BraidedCategory.hexagon_reverse_assoc, Iso.inv_hom_id_assoc, + ← BraidedCategory.braiding_naturality_left] + simp only [MonoidalCategory.whiskerLeft_comp] + rw [Bimon_.comul_assoc_flip_hom_assoc, Iso.inv_hom_id_assoc] + slice_lhs 2 3 => + simp only [← MonoidalCategory.whiskerLeft_comp] + rw [Bimon_.comul_assoc_hom] + simp only [MonoidalCategory.whiskerLeft_comp] + slice_lhs 3 7 => + simp only [← MonoidalCategory.whiskerLeft_comp] + rw [← associator_naturality_middle_assoc, Iso.hom_inv_id_assoc] + simp only [← comp_whiskerRight] + rw [antipode_right] + simp only [comp_whiskerRight] + simp only [MonoidalCategory.whiskerLeft_comp] + slice_lhs 2 3 => + simp only [← MonoidalCategory.whiskerLeft_comp] + rw [Bimon_.counit_comul_hom] + simp only [MonoidalCategory.whiskerLeft_comp] + slice_lhs 3 4 => + simp only [← MonoidalCategory.whiskerLeft_comp] + rw [BraidedCategory.braiding_naturality_left] + simp only [MonoidalCategory.whiskerLeft_comp] + slice_lhs 4 5 => + simp only [← MonoidalCategory.whiskerLeft_comp] + rw [whisker_exchange] + simp only [MonoidalCategory.whiskerLeft_comp] + slice_lhs 5 7 => + rw [associator_inv_naturality_right_assoc, whisker_exchange] + simp only [Mon_.monMonoidalStruct_tensorObj_X, Mon_.tensorUnit_X, braiding_tensorUnit_left, + MonoidalCategory.whiskerLeft_comp, whiskerLeft_rightUnitor_inv, + 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] + monoidal + +theorem antipode_comul (A : Hopf_ C) : + A.antipode ≫ A.X.comul.hom = A.X.comul.hom ≫ (β_ _ _).hom ≫ (A.antipode ⊗ A.antipode) := by + -- Again, it is a "left inverse equals right inverse" argument in the convolution monoid. + apply left_inv_eq_right_inv + (M := Conv ((Bimon_.toComon_ C).obj A.X) (A.X.X ⊗ A.X.X)) + (a := A.X.comul.hom) + · erw [Conv.mul_eq, Conv.one_eq] + simp only [Bimon_.toComon__obj_X, Mon_.monMonoidalStruct_tensorObj_X, Bimon_.toComon__obj_comul, + comp_whiskerRight, tensor_whiskerLeft, Mon_.tensorObj_mul, Category.assoc, + Bimon_.toComon__obj_counit, Mon_.tensorObj_one] + simp only [tensor_μ] + simp only [Category.assoc, Iso.inv_hom_id_assoc] + exact antipode_comul₁ A + · erw [Conv.mul_eq, Conv.one_eq] + simp only [Bimon_.toComon__obj_X, Mon_.monMonoidalStruct_tensorObj_X, Bimon_.toComon__obj_comul, + MonoidalCategory.whiskerLeft_comp, tensor_whiskerLeft, Category.assoc, Iso.inv_hom_id_assoc, + Mon_.tensorObj_mul, Bimon_.toComon__obj_counit, Mon_.tensorObj_one] + simp only [tensor_μ] + simp only [Category.assoc, Iso.inv_hom_id_assoc] + exact antipode_comul₂ A + +theorem mul_antipode₁ (A : Hopf_ C) : + (A.X.comul.hom ⊗ A.X.comul.hom) ≫ + (α_ A.X.X.X A.X.X.X (A.X.X.X ⊗ A.X.X.X)).hom ≫ + A.X.X.X ◁ (α_ A.X.X.X A.X.X.X A.X.X.X).inv ≫ + A.X.X.X ◁ (β_ A.X.X.X A.X.X.X).hom ▷ A.X.X.X ≫ + (α_ A.X.X.X (A.X.X.X ⊗ A.X.X.X) A.X.X.X).inv ≫ + (α_ A.X.X.X A.X.X.X A.X.X.X).inv ▷ A.X.X.X ≫ + A.X.X.mul ▷ A.X.X.X ▷ A.X.X.X ≫ + A.antipode ▷ A.X.X.X ▷ A.X.X.X ≫ + (α_ A.X.X.X A.X.X.X A.X.X.X).hom ≫ + A.X.X.X ◁ A.X.X.mul ≫ + A.X.X.mul = + (A.X.counit.hom ⊗ A.X.counit.hom) ≫ (λ_ (𝟙_ C)).hom ≫ A.X.X.one := by + slice_lhs 8 9 => + rw [associator_naturality_left] + slice_lhs 9 10 => + rw [← whisker_exchange] + slice_lhs 7 8 => + rw [associator_naturality_left] + slice_lhs 8 9 => + rw [← tensorHom_def] + simp only [Mon_.monMonoidalStruct_tensorObj_X, Category.assoc, pentagon_inv_inv_hom_hom_inv_assoc, + Mon_.tensorUnit_X] + slice_lhs 1 7 => + erw [Bimon_.compatibility] + slice_lhs 2 4 => + rw [antipode_left] + simp + + +/-- +Auxiliary calculation for `mul_antipode`. + + | + n + / \ + | n + | / \ + | S S + | \ / + n / + / \ / \ + | / | + \ / \ / + v v + | | + +We move the leftmost multiplication up, so we can reassociate. +We then move the rightmost comultiplication under the strand, +and simplify using `antipode_right`. +-/ +theorem mul_antipode₂ (A : Hopf_ C) : + (A.X.comul.hom ⊗ A.X.comul.hom) ≫ + (α_ A.X.X.X A.X.X.X (A.X.X.X ⊗ A.X.X.X)).hom ≫ + A.X.X.X ◁ (α_ A.X.X.X A.X.X.X A.X.X.X).inv ≫ + A.X.X.X ◁ (β_ A.X.X.X A.X.X.X).hom ▷ A.X.X.X ≫ + (α_ A.X.X.X (A.X.X.X ⊗ A.X.X.X) A.X.X.X).inv ≫ + (α_ A.X.X.X A.X.X.X A.X.X.X).inv ▷ A.X.X.X ≫ + A.X.X.mul ▷ A.X.X.X ▷ A.X.X.X ≫ + (α_ A.X.X.X A.X.X.X A.X.X.X).hom ≫ + A.X.X.X ◁ (β_ A.X.X.X A.X.X.X).hom ≫ + A.X.X.X ◁ (A.antipode ⊗ A.antipode) ≫ + A.X.X.X ◁ A.X.X.mul ≫ A.X.X.mul = + (A.X.counit.hom ⊗ A.X.counit.hom) ≫ (λ_ (𝟙_ C)).hom ≫ A.X.X.one := by + slice_lhs 7 8 => + rw [associator_naturality_left] + slice_lhs 8 9 => + rw [← whisker_exchange] + slice_lhs 9 10 => + rw [← whisker_exchange] + slice_lhs 11 12 => + rw [Mon_.mul_assoc_flip] + slice_lhs 10 11 => + rw [associator_inv_naturality_left] + slice_lhs 11 12 => + simp only [← comp_whiskerRight] + rw [Mon_.mul_assoc] + simp only [comp_whiskerRight] + rw [tensorHom_def] + rw [tensor_whiskerLeft] + rw [pentagon_inv_inv_hom_hom_inv_assoc] + slice_lhs 7 8 => + rw [Iso.inv_hom_id] + rw [Category.id_comp] + slice_lhs 5 7 => + simp only [← MonoidalCategory.whiskerLeft_comp] + rw [← BraidedCategory.hexagon_forward] + simp only [MonoidalCategory.whiskerLeft_comp] + simp only [Mon_.monMonoidalStruct_tensorObj_X, tensor_whiskerLeft, + MonoidalCategory.whiskerLeft_comp, Category.assoc, + whiskerLeft_inv_hom, Category.comp_id, whiskerLeft_hom_inv_assoc, Iso.inv_hom_id_assoc, + pentagon_inv_inv_hom_inv_inv, whisker_assoc, Mon_.mul_assoc, Mon_.tensorUnit_X] + slice_lhs 4 5 => + simp only [← MonoidalCategory.whiskerLeft_comp] + rw [Iso.inv_hom_id] + simp only [MonoidalCategory.whiskerLeft_comp] + rw [MonoidalCategory.whiskerLeft_id, Category.id_comp] + slice_lhs 3 4 => + simp only [← MonoidalCategory.whiskerLeft_comp] + rw [BraidedCategory.braiding_naturality_right] + simp only [MonoidalCategory.whiskerLeft_comp] + rw [tensorHom_def'] + simp only [MonoidalCategory.whiskerLeft_comp] + slice_lhs 5 6 => + simp only [← MonoidalCategory.whiskerLeft_comp] + rw [← associator_naturality_right] + simp only [MonoidalCategory.whiskerLeft_comp] + slice_lhs 4 5 => + simp only [← MonoidalCategory.whiskerLeft_comp] + rw [← whisker_exchange] + simp only [MonoidalCategory.whiskerLeft_comp] + slice_lhs 5 9 => + simp only [← MonoidalCategory.whiskerLeft_comp] + rw [associator_inv_naturality_middle_assoc, Iso.hom_inv_id_assoc] + simp only [← comp_whiskerRight] + rw [antipode_right] + simp only [comp_whiskerRight] + simp only [MonoidalCategory.whiskerLeft_comp] + slice_lhs 6 7 => + simp only [← MonoidalCategory.whiskerLeft_comp] + rw [A.X.X.one_mul] + simp only [MonoidalCategory.whiskerLeft_comp] + slice_lhs 3 4 => + simp only [← MonoidalCategory.whiskerLeft_comp] + rw [← BraidedCategory.braiding_naturality_left] + simp only [MonoidalCategory.whiskerLeft_comp] + slice_lhs 4 5 => + simp only [← MonoidalCategory.whiskerLeft_comp] + rw [← BraidedCategory.braiding_naturality_right] + simp only [MonoidalCategory.whiskerLeft_comp] + rw [← associator_naturality_middle_assoc] + simp only [Mon_.tensorUnit_X, braiding_tensorUnit_right, MonoidalCategory.whiskerLeft_comp] + slice_lhs 6 7 => + simp only [← MonoidalCategory.whiskerLeft_comp] + rw [Iso.inv_hom_id] + simp only [MonoidalCategory.whiskerLeft_comp] + simp only [MonoidalCategory.whiskerLeft_id, Category.id_comp] + slice_lhs 5 6 => + rw [whiskerLeft_rightUnitor, Category.assoc, ← rightUnitor_naturality] + rw [associator_inv_naturality_right_assoc, Iso.hom_inv_id_assoc] + slice_lhs 3 4 => + rw [whisker_exchange] + slice_lhs 1 3 => + simp only [← comp_whiskerRight] + rw [antipode_right] + simp only [comp_whiskerRight] + slice_lhs 2 3 => + rw [← whisker_exchange] + slice_lhs 1 2 => + dsimp + rw [← tensorHom_def] + slice_lhs 2 3 => + rw [rightUnitor_naturality] + simp only [Mon_.tensorUnit_X] + monoidal + +theorem mul_antipode (A : Hopf_ C) : + A.X.X.mul ≫ A.antipode = (A.antipode ⊗ A.antipode) ≫ (β_ _ _).hom ≫ A.X.X.mul := by + -- Again, it is a "left inverse equals right inverse" argument in the convolution monoid. + apply left_inv_eq_right_inv + (M := Conv (((Bimon_.toComon_ C).obj A.X) ⊗ ((Bimon_.toComon_ C).obj A.X)) A.X.X) + (a := A.X.X.mul) + · -- Unfold the algebra structure in the convolution monoid, + -- then `simp?, simp only [tensor_μ], simp?`. + erw [Conv.mul_eq, Conv.one_eq] + simp only [Monoidal.transportStruct_tensorObj, Equivalence.symm_functor, + Comon_.Comon_EquivMon_OpOp_inverse, Equivalence.symm_inverse, + Comon_.Comon_EquivMon_OpOp_functor, Comon_.Comon_ToMon_OpOp_obj, Comon_.Mon_OpOpToComon__obj, + unop_tensorObj, Comon_.Mon_OpOpToComon_obj'_X, Mon_.monMonoidalStruct_tensorObj_X, + Comon_.Comon_ToMon_OpOp_obj'_X, Bimon_.toComon__obj_X, Comon_.Mon_OpOpToComon_obj'_comul, + Mon_.tensorObj_mul, Comon_.Comon_ToMon_OpOp_obj'_mul, Bimon_.toComon__obj_comul, unop_comp, + unop_tensorHom, Quiver.Hom.unop_op, whiskerRight_tensor, comp_whiskerRight, Category.assoc, + Comon_.Mon_OpOpToComon_obj'_counit, Mon_.tensorObj_one, Comon_.Comon_ToMon_OpOp_obj'_one, + Bimon_.toComon__obj_counit, unop_tensorUnit, unop_inv_leftUnitor] + simp only [tensor_μ] + simp only [unop_comp, unop_tensorObj, unop_inv_associator, unop_whiskerLeft, + unop_hom_associator, unop_whiskerRight, unop_hom_braiding, Category.assoc, + pentagon_hom_inv_inv_inv_inv_assoc] + exact mul_antipode₁ A + · erw [Conv.mul_eq, Conv.one_eq] + simp only [Monoidal.transportStruct_tensorObj, Equivalence.symm_functor, + Comon_.Comon_EquivMon_OpOp_inverse, Equivalence.symm_inverse, + Comon_.Comon_EquivMon_OpOp_functor, Comon_.Comon_ToMon_OpOp_obj, Comon_.Mon_OpOpToComon__obj, + unop_tensorObj, Comon_.Mon_OpOpToComon_obj'_X, Mon_.monMonoidalStruct_tensorObj_X, + Comon_.Comon_ToMon_OpOp_obj'_X, Bimon_.toComon__obj_X, Comon_.Mon_OpOpToComon_obj'_comul, + Mon_.tensorObj_mul, Comon_.Comon_ToMon_OpOp_obj'_mul, Bimon_.toComon__obj_comul, unop_comp, + unop_tensorHom, Quiver.Hom.unop_op, whiskerRight_tensor, + BraidedCategory.braiding_naturality_assoc, MonoidalCategory.whiskerLeft_comp, Category.assoc, + Comon_.Mon_OpOpToComon_obj'_counit, Mon_.tensorObj_one, Comon_.Comon_ToMon_OpOp_obj'_one, + Bimon_.toComon__obj_counit, unop_tensorUnit, unop_inv_leftUnitor] + simp only [tensor_μ] + simp only [unop_comp, unop_tensorObj, unop_inv_associator, unop_whiskerLeft, + unop_hom_associator, unop_whiskerRight, unop_hom_braiding, Category.assoc, + pentagon_hom_inv_inv_inv_inv_assoc] + exact mul_antipode₂ A + +/-- +In a commutative Hopf algebra, the antipode squares to the identity. +-/ +theorem antipode_antipode (A : Hopf_ C) (comm : (β_ _ _).hom ≫ A.X.X.mul = A.X.X.mul) : + A.antipode ≫ A.antipode = 𝟙 A.X.X.X := by + -- Again, it is a "left inverse equals right inverse" argument in the convolution monoid. + apply left_inv_eq_right_inv + (M := Conv ((Bimon_.toComon_ C).obj A.X) A.X.X) + (a := A.antipode) + · -- Unfold the algebra structure in the convolution monoid, + -- then `simp?`. + erw [Conv.mul_eq, Conv.one_eq] + simp only [Bimon_.toComon__obj_X, Bimon_.toComon__obj_comul, comp_whiskerRight, Category.assoc, + Bimon_.toComon__obj_counit] + rw [← comm, ← tensorHom_def_assoc, ← mul_antipode] + simp + · erw [Conv.mul_eq, Conv.one_eq] + simp + +end Hopf_ + +end diff --git a/Mathlib/CategoryTheory/Monoidal/Internal/FunctorCategory.lean b/Mathlib/CategoryTheory/Monoidal/Internal/FunctorCategory.lean index 19c7811649daf..6d90406b86532 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_ 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..2e6df6e377f89 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 diff --git a/Mathlib/CategoryTheory/Monoidal/Internal/Types.lean b/Mathlib/CategoryTheory/Monoidal/Internal/Types.lean index 1c8d1b2ee61fc..00d58af2f33d2 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_ diff --git a/Mathlib/CategoryTheory/Monoidal/Limits.lean b/Mathlib/CategoryTheory/Monoidal/Limits.lean index 4ddc2b63e9618..e13b3fa646109 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 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..bee5d1a324c2f 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_ diff --git a/Mathlib/CategoryTheory/Monoidal/Mon_.lean b/Mathlib/CategoryTheory/Monoidal/Mon_.lean index c19a846886021..2202d88535f6a 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 @@ -57,8 +57,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⟩ @@ -154,10 +154,11 @@ def mkIso {M N : Mon_ C} (f : M.X ≅ N.X) (one_f : M.one ≫ f.hom = N.one := b slice_rhs 2 3 => rw [mul_f] simp } +@[simps] instance uniqueHomFromTrivial (A : Mon_ C) : Unique (trivial C ⟶ A) where default := { hom := A.one - mul_hom := by dsimp; simp [A.one_mul, unitors_equal] } + mul_hom := by simp [A.one_mul, unitors_equal] } uniq f := by ext simp only [trivial_X] @@ -349,30 +350,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] @@ -381,12 +382,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] @@ -396,7 +397,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] @@ -405,7 +406,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] @@ -418,7 +419,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 } @@ -456,7 +457,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) : @@ -491,7 +492,7 @@ 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] @@ -513,7 +514,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..37d92020f5dfd 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 @@ -189,9 +189,8 @@ def monoidalCounit : unit := by 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] + rw [map_inv, map_comp, assoc, assoc, map_inv, ← cancel_mono F.ε, assoc, assoc, assoc, ← eq, + IsIso.inv_hom_id_assoc, Adjunction.left_triangle_components, comp_id, id_comp] instance [F.IsEquivalence] : IsIso (monoidalUnit F h) := by 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..813049284961d 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 @@ -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..3866aa1f3735a 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 @@ -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 @@ -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..7133ba4faabc0 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 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 new file mode 100644 index 0000000000000..6e6d9d68e265d --- /dev/null +++ b/Mathlib/CategoryTheory/Monoidal/Rigid/Braided.lean @@ -0,0 +1,101 @@ +/- +Copyright (c) 2024 Gareth Ma. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Gareth Ma +-/ +import Mathlib.CategoryTheory.Monoidal.Rigid.Basic +import Mathlib.CategoryTheory.Monoidal.Braided.Basic + +/-! +# Deriving `RigidCategory` instance for braided and left/right rigid categories. +-/ + +open CategoryTheory Category BraidedCategory MonoidalCategory + +variable {C : Type*} [Category C] [MonoidalCategory C] [BraidedCategory C] {X Y : C} + +namespace CategoryTheory.BraidedCategory + +/-- coevaluation_evaluation' field of `ExactPairing Y X` in a braided category -/ +private theorem coevaluation_evaluation_braided' [inst : ExactPairing X Y] : + X ◁ (η_ X Y ≫ (β_ Y X).inv) ≫ (α_ X Y X).inv ≫ ((β_ X Y).hom ≫ ε_ X Y) ▷ X + = (ρ_ X).hom ≫ (λ_ X).inv := by + /- Rearrange into _ = 𝟙 _ -/ + rw [Iso.eq_comp_inv, ← Iso.inv_comp_eq_id] + /- 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 + 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'_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] + simpa using yang_baxter X Y X + _ = 𝟙 X ⊗≫ (X ◁ η_ X Y ≫ (β_ X (X ⊗ Y)).hom) ⊗≫ ((β_ (Y ⊗ X) X).inv ≫ ε_ X Y ▷ X) ⊗≫ 𝟙 X := by + simp [monoidalComp, braiding_tensor_right, braiding_inv_tensor_left] + _ = _ := by + rw [braiding_naturality_right, ← braiding_inv_naturality_right] + simp [monoidalComp] + +/-- evaluation_coevaluation' field of `ExactPairing Y X` in a braided category -/ +private theorem evaluation_coevaluation_braided' [inst : ExactPairing X Y] : + (η_ X Y ≫ (β_ Y X).inv) ▷ Y ≫ (α_ Y X Y).hom ≫ Y ◁ ((β_ X Y).hom ≫ ε_ X Y) = + (λ_ Y).hom ≫ (ρ_ Y).inv := by + 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 + 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 + all_goals simp [monoidalComp] + iterate 2 rw [← IsIso.eq_inv_comp] + repeat rw [← assoc] + iterate 4 rw [← IsIso.comp_inv_eq] + simpa using (yang_baxter Y X Y).symm + _ = 𝟙 Y ⊗≫ (η_ X Y ▷ Y ≫ (β_ (X ⊗ Y) Y).hom) ⊗≫ ((β_ Y (Y ⊗ X)).inv ≫ Y ◁ ε_ X Y) ⊗≫ 𝟙 Y := by + simp [monoidalComp, braiding_tensor_left, braiding_inv_tensor_right] + _ = _ := by + rw [braiding_naturality_left, ← braiding_inv_naturality_left] + simp [monoidalComp] + +/-- If `X` and `Y` forms an exact pairing in a braided category, then so does `Y` and `X` +by composing the coevaluation and evaluation morphisms with associators. -/ +def exactPairing_swap (X Y : C) [ExactPairing X Y] : ExactPairing Y X where + coevaluation' := η_ X Y ≫ (β_ Y X).inv + evaluation' := (β_ X Y).hom ≫ ε_ X Y + coevaluation_evaluation' := coevaluation_evaluation_braided' + evaluation_coevaluation' := evaluation_coevaluation_braided' + +/-- If `X` has a right dual in a braided category, then it has a left dual. -/ +def hasLeftDualOfHasRightDual [HasRightDual X] : HasLeftDual X where + leftDual := Xᘁ + exact := exactPairing_swap X Xᘁ + +/-- If `X` has a left dual in a braided category, then it has a right dual. -/ +def hasRightDualOfHasLeftDual [HasLeftDual X] : HasRightDual X where + rightDual := ᘁX + exact := exactPairing_swap ᘁX X + +instance leftRigidCategoryOfRightRigidCategory [RightRigidCategory C] : LeftRigidCategory C where + leftDual X := hasLeftDualOfHasRightDual (X := X) + +instance rightRigidCategoryOfLeftRigidCategory [LeftRigidCategory C] : RightRigidCategory C where + rightDual X := hasRightDualOfHasLeftDual (X := X) + +/-- If `C` is a braided and right rigid category, then it is a rigid category. --/ +instance rigidCategoryOfRightRigidCategory [RightRigidCategory C] : RigidCategory C where + rightDual := inferInstance + leftDual := inferInstance + +/-- If `C` is a braided and left rigid category, then it is a rigid category. --/ +instance rigidCategoryOfLeftRigidCategory [LeftRigidCategory C] : RigidCategory C where + rightDual := inferInstance + leftDual := inferInstance + +end CategoryTheory.BraidedCategory diff --git a/Mathlib/CategoryTheory/Monoidal/Rigid/FunctorCategory.lean b/Mathlib/CategoryTheory/Monoidal/Rigid/FunctorCategory.lean index d458fd401af64..f520a501aff97 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 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..5e77ff34ecfb7 100644 --- a/Mathlib/CategoryTheory/Monoidal/Subcategory.lean +++ b/Mathlib/CategoryTheory/Monoidal/Subcategory.lean @@ -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 } 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] } } + 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..19d755f6f034b 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,16 +144,17 @@ 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 := diff --git a/Mathlib/CategoryTheory/Monoidal/Types/Basic.lean b/Mathlib/CategoryTheory/Monoidal/Types/Basic.lean index 0d62b9cef4f8b..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 @@ -101,6 +101,6 @@ of a type to the image of that type, tensored with the image of the nth cartesia noncomputable def MonoidalFunctor.mapPi {C : Type*} [Category C] [MonoidalCategory C] (F : MonoidalFunctor (Type _) C) (n : ℕ) (β : Type*) : F.obj (Fin (n + 1) → β) ≅ F.obj β ⊗ F.obj (Fin n → β) := - Functor.mapIso _ (Equiv.piFinSucc n β).toIso ≪≫ (asIso (F.μ β (Fin n → β))).symm + Functor.mapIso _ (Fin.consEquiv _).symm.toIso ≪≫ (asIso (F.μ β (Fin n → β))).symm end CategoryTheory diff --git a/Mathlib/CategoryTheory/Monoidal/Types/Coyoneda.lean b/Mathlib/CategoryTheory/Monoidal/Types/Coyoneda.lean index 633d6872c7ad0..475acc453b566 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 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 2590d4b476d56..0a3a382da8016 100644 --- a/Mathlib/CategoryTheory/MorphismProperty/Basic.lean +++ b/Mathlib/CategoryTheory/MorphismProperty/Basic.lean @@ -13,8 +13,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. -/ @@ -83,7 +86,7 @@ lemma inverseImage_iff (P : MorphismProperty D) (F : C ⥤ D) {X Y : C} (f : X /-- The image (up to isomorphisms) of a `MorphismProperty C` by a functor `C ⥤ D` -/ def map (P : MorphismProperty C) (F : C ⥤ D) : MorphismProperty D := fun _ _ f => - ∃ (X' Y' : C) (f' : X' ⟶ Y') (_ : P f'), Nonempty (Arrow.mk (F.map f') ≅ Arrow.mk f) + ∃ (X' Y' : C) (f' : X' ⟶ Y') (_ : P f'), Nonempty (Arrow.mk (F.map f') ≅ Arrow.mk f) lemma map_mem_map (P : MorphismProperty C) (F : C ⥤ D) {X Y : C} (f : X ⟶ Y) (hf : P f) : (P.map F) (F.map f) := ⟨X, Y, f, hf, ⟨Iso.refl _⟩⟩ @@ -93,22 +96,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 +179,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,11 +190,11 @@ 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⟩ theorem arrow_iso_iff (P : MorphismProperty C) [RespectsIso P] {f g : Arrow C} (e : f ≅ g) : P f.hom ↔ P g.hom := by @@ -146,16 +206,13 @@ theorem arrow_mk_iso_iff (P : MorphismProperty C) [RespectsIso P] {W X Y Z : C} 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 +284,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 +331,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,25 +359,25 @@ 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 - infer_instance + exact IsIso.comp_isIso @[deprecated (since := "2024-07-02")] alias RespectsIso.cancel_left_isIso := cancel_left_of_respectsIso diff --git a/Mathlib/CategoryTheory/MorphismProperty/Composition.lean b/Mathlib/CategoryTheory/MorphismProperty/Composition.lean index 056a5add8631c..aff2f87e7acc0 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) @@ -63,7 +63,7 @@ instance Pi.containsIdentities {J : Type w} {C : J → Type u} /-- 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] @@ -91,9 +91,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 +129,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 diff --git a/Mathlib/CategoryTheory/MorphismProperty/Limits.lean b/Mathlib/CategoryTheory/MorphismProperty/Limits.lean index 67abe688058ef..7352e3fdd289a 100644 --- a/Mathlib/CategoryTheory/MorphismProperty/Limits.lean +++ b/Mathlib/CategoryTheory/MorphismProperty/Limits.lean @@ -52,6 +52,19 @@ theorem StableUnderBaseChange.mk {P : MorphismProperty C} [HasPullbacks C] [Resp rw [← P.cancel_left_of_respectsIso e.inv, sq.flip.isoPullback_inv_fst] exact hP₂ _ _ _ f g hg +variable (C) in +lemma StableUnderBaseChange.monomorphisms : + (monomorphisms C).StableUnderBaseChange := by + intro X Y Y' S f g f' g' h hg + have : Mono g := hg + constructor + intro Z f₁ f₂ h₁₂ + apply PullbackCone.IsLimit.hom_ext h.isLimit + · rw [← cancel_mono g] + dsimp + simp only [Category.assoc, h.w, reassoc_of% h₁₂] + · exact h₁₂ + theorem StableUnderBaseChange.respectsIso {P : MorphismProperty C} (hP : StableUnderBaseChange P) : RespectsIso P := by apply RespectsIso.of_respects_arrow_iso @@ -112,6 +125,19 @@ theorem StableUnderCobaseChange.mk {P : MorphismProperty C} [HasPushouts C] [Res rw [← P.cancel_right_of_respectsIso _ e.hom, sq.flip.inr_isoPushout_hom] exact hP₂ _ _ _ f g hf +variable (C) in +lemma StableUnderCobaseChange.epimorphisms : + (epimorphisms C).StableUnderCobaseChange := by + intro X Y Y' S f g f' g' h hf + have : Epi f := hf + constructor + intro Z f₁ f₂ h₁₂ + apply PushoutCocone.IsColimit.hom_ext h.isColimit + · exact h₁₂ + · rw [← cancel_epi f] + dsimp + simp only [← reassoc_of% h.w, h₁₂] + theorem StableUnderCobaseChange.respectsIso {P : MorphismProperty C} (hP : StableUnderCobaseChange P) : RespectsIso P := RespectsIso.of_respects_arrow_iso _ fun _ _ e => hP (IsPushout.of_horiz_isIso (CommSq.mk e.hom.w)) @@ -164,7 +190,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)) @@ -177,7 +203,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 @@ -199,7 +225,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 _ @@ -234,7 +260,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 new file mode 100644 index 0000000000000..91bf09c44907e --- /dev/null +++ b/Mathlib/CategoryTheory/MorphismProperty/Representable.lean @@ -0,0 +1,291 @@ +/- +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, Joël Riou, Ravi Vakil +-/ + +import Mathlib.CategoryTheory.MorphismProperty.Limits + +/-! + +# Relatively representable morphisms + +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 +`g : yoneda.obj X ⟶ G`, there exists a pullback square of the following form +``` + yoneda.obj Y --yoneda.map snd--> yoneda.obj X + | | + fst g + | | + v v + F ------------ f --------------> G +``` + +In this file, we define a notion of relative representability which works with respect to any +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 +``` + F.obj b --F.map snd--> F.obj a + | | + fst g + | | + v v + X ------- f --------> Y +``` + +## API + +Given `hf : relativelyRepresentable f`, with `f : X ⟶ Y` and `g : F.obj a ⟶ Y`, we provide: +* `hf.pullback g` which is the object in `C` such that `F.obj (hf.pullback g)` is a + pullback of `f` and `g`. +* `hf.snd g` is the morphism `hf.pullback g ⟶ F.obj a` +* `hf.fst g` is the morphism `F.obj (hf.pullback g) ⟶ X` +* If `F` is full, and `f` is of type `F.obj c ⟶ G`, we also have `hf.fst' g : hf.pullback g ⟶ X` +which is the preimage under `F` of `hf.fst g`. +* `hom_ext`, `hom_ext'`, `lift`, `lift'` are variants of the universal property of + `F.obj (hf.pullback g)`, where as much as possible has been formulated internally to `C`. + For these theorems we also need that `F` is full and/or faithful. +* `symmetry` and `symmetryIso` are variants of the fact that pullbacks are symmetric for + representable morphisms, formulated internally to `C`. We assume that `F` is fully faithful here. + +## Main results + +* `relativelyRepresentable.isMultiplicative`: The class of relatively representable morphisms is + multiplicative. +* `relativelyRepresentable.stableUnderBaseChange`: Being relatively representable is stable under + base change. +* `relativelyRepresentable.of_isIso`: Isomorphisms are relatively representable. + +-/ + +namespace CategoryTheory + +open Category Limits MorphismProperty + +universe v₁ v₂ u₁ u₂ + +variable {C : Type u₁} [Category.{v₁} C] {D : Type u₂} [Category.{v₂} D] (F : C ⥤ D) + +/-- A morphism `f : X ⟶ Y` in `D` is said to be relatively representable 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 + | | + fst g + | | + v v + X ------- f --------> Y +``` +-/ +def Functor.relativelyRepresentable : MorphismProperty D := + fun X Y f ↦ ∀ ⦃a : C⦄ (g : F.obj a ⟶ Y), ∃ (b : C) (snd : b ⟶ a) + (fst : F.obj b ⟶ X), IsPullback fst (F.map snd) f g + +namespace Functor.relativelyRepresentable + +section + +variable {F} +variable {X Y : D} {f : X ⟶ Y} (hf : F.relativelyRepresentable f) + {b : C} {f' : F.obj b ⟶ Y} (hf' : F.relativelyRepresentable f') + {a : C} (g : F.obj a ⟶ Y) (hg : F.relativelyRepresentable g) + +/-- Let `f : X ⟶ Y` be a relatively representable morphism in `D`. Then, for any +`g : F.obj a ⟶ Y`, `hf.pullback g` denotes the (choice of) a corresponding object in `C` such that +there is a pullback square of the following form +``` +hf.pullback g --F.map snd--> F.obj a + | | + fst g + | | + v v + X ---------- f ----------> Y +``` -/ +noncomputable def pullback : C := + (hf g).choose + +/-- Given a representable morphism `f : X ⟶ Y`, then for any `g : F.obj a ⟶ Y`, `hf.snd g` +denotes the morphism in `C` giving rise to the following diagram +``` +hf.pullback g --F.map (hf.snd g)--> F.obj a + | | + fst g + | | + v v + X -------------- f -------------> Y +``` -/ +noncomputable abbrev snd : hf.pullback g ⟶ a := + (hf g).choose_spec.choose + +/-- Given a relatively representable morphism `f : X ⟶ Y`, then for any `g : F.obj a ⟶ Y`, +`hf.fst g` denotes the first projection in the following diagram, given by the defining property +of `f` being relatively representable +``` +hf.pullback g --F.map (hf.snd g)--> F.obj a + | | +hf.fst g g + | | + v v + X -------------- f -------------> Y +``` -/ +noncomputable abbrev fst : F.obj (hf.pullback g) ⟶ X := + (hf g).choose_spec.choose_spec.choose + +/-- When `F` is full, given a representable morphism `f' : F.obj b ⟶ Y`, then `hf'.fst' g` denotes +the preimage of `hf'.fst g` under `F`. -/ +noncomputable abbrev fst' [Full F] : hf'.pullback g ⟶ b := + F.preimage (hf'.fst g) + +lemma map_fst' [Full F] : F.map (hf'.fst' g) = hf'.fst g := + F.map_preimage _ + +lemma isPullback : IsPullback (hf.fst g) (F.map (hf.snd g)) f g := + (hf g).choose_spec.choose_spec.choose_spec + +@[reassoc] +lemma w : hf.fst g ≫ f = F.map (hf.snd g) ≫ g := (hf.isPullback g).w + +/-- Variant of the pullback square when `F` is full, and given `f' : F.obj b ⟶ Y`. -/ +lemma isPullback' [Full F] : IsPullback (F.map (hf'.fst' g)) (F.map (hf'.snd g)) f' g := + (hf'.map_fst' _) ▸ hf'.isPullback g + +@[reassoc] +lemma w' {X Y Z : C} {f : X ⟶ Z} (hf : F.relativelyRepresentable (F.map f)) (g : Y ⟶ Z) + [Full F] [Faithful F] : hf.fst' (F.map g) ≫ f = hf.snd (F.map g) ≫ g := + F.map_injective <| by simp [(hf.w (F.map g))] + +lemma isPullback_of_map {X Y Z : C} {f : X ⟶ Z} (hf : F.relativelyRepresentable (F.map f)) + (g : Y ⟶ Z) [Full F] [Faithful F] : + IsPullback (hf.fst' (F.map g)) (hf.snd (F.map g)) f g := + IsPullback.of_map F (hf.w' g) (hf.isPullback' (F.map g)) + +variable {g} + +/-- Two morphisms `a b : c ⟶ hf.pullback g` are equal if +* Their compositions (in `C`) with `hf.snd g : hf.pullback ⟶ X` are equal. +* The compositions of `F.map a` and `F.map b` with `hf.fst g` are equal. -/ +@[ext 100] +lemma hom_ext [Faithful F] {c : C} {a b : c ⟶ hf.pullback g} + (h₁ : F.map a ≫ hf.fst g = F.map b ≫ hf.fst g) + (h₂ : a ≫ hf.snd g = b ≫ hf.snd g) : a = b := + F.map_injective <| + PullbackCone.IsLimit.hom_ext (hf.isPullback g).isLimit h₁ (by simpa using F.congr_map h₂) + +/-- In the case of a representable morphism `f' : F.obj Y ⟶ G`, whose codomain lies +in the image of `F`, we get that two morphism `a b : Z ⟶ hf.pullback g` are equal if +* Their compositions (in `C`) with `hf'.snd g : hf.pullback ⟶ X` are equal. +* Their compositions (in `C`) with `hf'.fst' g : hf.pullback ⟶ Y` are equal. -/ +@[ext] +lemma hom_ext' [Full F] [Faithful F] {c : C} {a b : c ⟶ hf'.pullback g} + (h₁ : a ≫ hf'.fst' g = b ≫ hf'.fst' g) + (h₂ : a ≫ hf'.snd g = b ≫ hf'.snd g) : a = b := + hf'.hom_ext (by simpa [map_fst'] using F.congr_map h₁) h₂ + +section + +variable {c : C} (i : F.obj c ⟶ X) (h : c ⟶ a) (hi : i ≫ f = F.map h ≫ g) + +/-- The lift (in `C`) obtained from the universal property of `F.obj (hf.pullback g)`, in the +case when the cone point is in the image of `F.obj`. -/ +noncomputable def lift [Full F] : c ⟶ hf.pullback g := + F.preimage <| PullbackCone.IsLimit.lift (hf.isPullback g).isLimit _ _ hi + +@[reassoc (attr := simp)] +lemma lift_fst [Full F] : F.map (hf.lift i h hi) ≫ hf.fst g = i := by + simpa [lift] using PullbackCone.IsLimit.lift_fst _ _ _ _ + +@[reassoc (attr := simp)] +lemma lift_snd [Full F] [Faithful F] : hf.lift i h hi ≫ hf.snd g = h := + F.map_injective <| by simpa [lift] using PullbackCone.IsLimit.lift_snd _ _ _ _ + +end + +section + +variable {c : C} (i : c ⟶ b) (h : c ⟶ a) (hi : F.map i ≫ f' = F.map h ≫ g) + +/-- Variant of `lift` in the case when the domain of `f` lies in the image of `F.obj`. Thus, +in this case, one can obtain the lift directly by giving two morphisms in `C`. -/ +noncomputable def lift' [Full F] : c ⟶ hf'.pullback g := hf'.lift _ _ hi + +@[reassoc (attr := simp)] +lemma lift'_fst [Full F] [Faithful F] : hf'.lift' i h hi ≫ hf'.fst' g = i := + F.map_injective (by simp [map_fst', lift']) + +@[reassoc (attr := simp)] +lemma lift'_snd [Full F] [Faithful F] : hf'.lift' i h hi ≫ hf'.snd g = h := by + simp [lift'] + +end + +/-- Given two representable morphisms `f' : F.obj b ⟶ Y` and `g : F.obj a ⟶ Y`, we +obtain an isomorphism `hf'.pullback g ⟶ hg.pullback f'`. -/ +noncomputable def symmetry [Full F] : hf'.pullback g ⟶ hg.pullback f' := + hg.lift' (hf'.snd g) (hf'.fst' g) (hf'.isPullback' _).w.symm + +@[reassoc (attr := simp)] +lemma symmetry_fst [Full F] [Faithful F] : hf'.symmetry hg ≫ hg.fst' f' = hf'.snd g := by + simp [symmetry] + +@[reassoc (attr := simp)] +lemma symmetry_snd [Full F] [Faithful F] : hf'.symmetry hg ≫ hg.snd f' = hf'.fst' g := by + simp [symmetry] + +@[reassoc (attr := simp)] +lemma symmetry_symmetry [Full F] [Faithful F] : hf'.symmetry hg ≫ hg.symmetry hf' = 𝟙 _ := + hom_ext' hf' (by simp) (by simp) + +/-- The isomorphism given by `Presheaf.representable.symmetry`. -/ +@[simps] +noncomputable def symmetryIso [Full F] [Faithful F] : hf'.pullback g ≅ hg.pullback f' where + hom := hf'.symmetry hg + inv := hg.symmetry hf' + +instance [Full F] [Faithful F] : IsIso (hf'.symmetry hg) := + (hf'.symmetryIso hg).isIso_hom + +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) : + 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), ?_⟩ + apply F.map_isPullback <| IsPullback.of_hasPullback f g + +lemma of_isIso {X Y : D} (f : X ⟶ Y) [IsIso f] : F.relativelyRepresentable f := + fun a g ↦ ⟨a, 𝟙 a, g ≫ CategoryTheory.inv f, IsPullback.of_vert_isIso ⟨by simp⟩⟩ + +lemma isomorphisms_le : MorphismProperty.isomorphisms D ≤ F.relativelyRepresentable := + fun _ _ f hf ↦ letI : IsIso f := hf; of_isIso F f + +instance isMultiplicative : IsMultiplicative F.relativelyRepresentable where + id_mem _ := of_isIso F _ + comp_mem {F G H} f g hf hg := fun X h ↦ + ⟨hf.pullback (hg.fst h), hf.snd (hg.fst h) ≫ hg.snd h, hf.fst (hg.fst h), + by simpa using IsPullback.paste_vert (hf.isPullback (hg.fst h)) (hg.isPullback h)⟩ + +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₁ + +instance respectsIso : RespectsIso F.relativelyRepresentable := + (stableUnderBaseChange F).respectsIso + +end Functor.relativelyRepresentable + +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 8f3c692708837..6d4f00e441da3 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 @@ -102,7 +102,7 @@ def unopUnop : Cᵒᵖᵒᵖ ⥤ C where obj X := unop (unop X) map f := f.unop.unop -/-- The functor from a category to its double-opposite. -/ +/-- The functor from a category to its double-opposite. -/ @[simps] def opOp : C ⥤ Cᵒᵖᵒᵖ where obj X := op (op X) 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..d3c89945af0f3 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 diff --git a/Mathlib/CategoryTheory/PathCategory.lean b/Mathlib/CategoryTheory/PathCategory.lean index e27f6b40b20c9..4f0b3ec849790 100644 --- a/Mathlib/CategoryTheory/PathCategory.lean +++ b/Mathlib/CategoryTheory/PathCategory.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.EqToHom import Mathlib.CategoryTheory.Quotient @@ -59,10 +59,12 @@ def lift {C} [Category C] (φ : V ⥤q C) : Paths V ⥤ C where (fun _ f ihp => ihp ≫ φ.map f) Y f map_id X := rfl map_comp f g := by - induction' g with _ _ g' p ih _ _ _ - · rw [Category.comp_id] + induction g with + | nil => + rw [Category.comp_id] rfl - · have : f ≫ Quiver.Path.cons g' p = (f ≫ g').cons p := by apply Quiver.Path.comp_cons + | cons g' p ih => + have : f ≫ Quiver.Path.cons g' p = (f ≫ g').cons p := by apply Quiver.Path.comp_cons rw [this] simp only at ih ⊢ rw [ih, Category.assoc] @@ -98,10 +100,12 @@ theorem lift_unique {C} [Category C] (φ : V ⥤q C) (Φ : Paths V ⥤ C) rfl · rintro X Y f dsimp [lift] - induction' f with _ _ p f' ih - · simp only [Category.comp_id] + induction f with + | nil => + simp only [Category.comp_id] apply Functor.map_id - · simp only [Category.comp_id, Category.id_comp] at ih ⊢ + | cons p f' ih => + simp only [Category.comp_id, Category.id_comp] at ih ⊢ -- Porting note: Had to do substitute `p.cons f'` and `f'.toPath` by their fully qualified -- versions in this `have` clause (elsewhere too). have : Φ.map (Quiver.Path.cons p f') = Φ.map p ≫ Φ.map (Quiver.Hom.toPath f') := by diff --git a/Mathlib/CategoryTheory/Pi/Basic.lean b/Mathlib/CategoryTheory/Pi/Basic.lean index caa1341b3caf6..166b83c21ef2a 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 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/Biproducts.lean b/Mathlib/CategoryTheory/Preadditive/Biproducts.lean index 2ea69885313e3..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 @@ -195,7 +195,7 @@ section HasBiproduct variable {J : Type} [Fintype J] {f : J → C} [HasBiproduct f] -/-- In any preadditive category, any biproduct satsifies +/-- In any preadditive category, any biproduct satisfies `∑ j : J, biproduct.π f j ≫ biproduct.ι f j = 𝟙 (⨁ f)` -/ @[simp] @@ -415,7 +415,7 @@ section variable {X Y : C} [HasBinaryBiproduct X Y] -/-- In any preadditive category, any binary biproduct satsifies +/-- In any preadditive category, any binary biproduct satisfies `biprod.fst ≫ biprod.inl + biprod.snd ≫ biprod.inr = 𝟙 (X ⊞ Y)`. -/ @[simp] 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/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..3b33277d8bf28 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 diff --git a/Mathlib/CategoryTheory/Preadditive/InjectiveResolution.lean b/Mathlib/CategoryTheory/Preadditive/InjectiveResolution.lean index 4c932bdd5de89..9f756b5cdb943 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 diff --git a/Mathlib/CategoryTheory/Preadditive/Mat.lean b/Mathlib/CategoryTheory/Preadditive/Mat.lean index 8d93ea7d3ea5b..d3d9783dc37c7 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 @@ -184,11 +184,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' 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 8059a72c9ca40..e0900aad10375 100644 --- a/Mathlib/CategoryTheory/Preadditive/Projective.lean +++ b/Mathlib/CategoryTheory/Preadditive/Projective.lean @@ -1,14 +1,13 @@ /- 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 import Mathlib.CategoryTheory.Limits.Constructions.EpiMono -import Mathlib.CategoryTheory.Limits.Shapes.Biproducts import Mathlib.CategoryTheory.Limits.Preserves.Finite -import Mathlib.CategoryTheory.Limits.Constructions.EpiMono +import Mathlib.CategoryTheory.Limits.Shapes.Biproducts /-! # Projective objects and categories with enough projectives diff --git a/Mathlib/CategoryTheory/Preadditive/ProjectiveResolution.lean b/Mathlib/CategoryTheory/Preadditive/ProjectiveResolution.lean index 8d947ea5ca55e..1447ce251a876 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 diff --git a/Mathlib/CategoryTheory/Preadditive/Schur.lean b/Mathlib/CategoryTheory/Preadditive/Schur.lean index b8b9cfef7f7c0..2fd3b980f6f59 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,9 +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 qsmul := _ + qsmul_def := fun q a => 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..3e19f976a5b18 100644 --- a/Mathlib/CategoryTheory/Preadditive/Yoneda/Basic.lean +++ b/Mathlib/CategoryTheory/Preadditive/Yoneda/Basic.lean @@ -39,7 +39,7 @@ object `X` to the `End Y`-module of morphisms `X ⟶ Y`. @[simps] def preadditiveYonedaObj (Y : C) : Cᵒᵖ ⥤ ModuleCat.{v} (End Y) where obj X := ModuleCat.of _ (X.unop ⟶ Y) - map f := ModuleCat.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 _ _ _ } @@ -66,7 +66,7 @@ object `Y` to the `End X`-module of morphisms `X ⟶ Y`. @[simps] def preadditiveCoyonedaObj (X : Cᵒᵖ) : C ⥤ ModuleCat.{v} (End X) where obj Y := ModuleCat.of _ (unop X ⟶ Y) - map f := ModuleCat.ofHom + map f := ModuleCat.asHom { toFun := fun g => g ≫ f map_add' := fun g g' => add_comp _ _ _ _ _ _ map_smul' := fun r g => Category.assoc _ _ _ } 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 1505c70e6c3bd..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 @@ -35,10 +35,12 @@ def inverseAssociator : C × D × E ⥤ (C × D) × E where /-- The equivalence of categories expressing associativity of products of categories. -/ -def associativity : (C × D) × E ≌ C × D × E := - Equivalence.mk (associator C D E) (inverseAssociator C D E) - (NatIso.ofComponents fun X => eqToIso (by simp)) - (NatIso.ofComponents fun X => eqToIso (by simp)) +@[simps] +def associativity : (C × D) × E ≌ C × D × E where + functor := associator C D E + inverse := inverseAssociator C D E + unitIso := Iso.refl _ + counitIso := Iso.refl _ instance associatorIsEquivalence : (associator C D E).IsEquivalence := (by infer_instance : (associativity C D E).functor.IsEquivalence) diff --git a/Mathlib/CategoryTheory/Products/Basic.lean b/Mathlib/CategoryTheory/Products/Basic.lean index 9d7207874a88a..58958ff88a2de 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 @@ -147,11 +146,12 @@ def symmetry : swap C D ⋙ swap D C ≅ 𝟭 (C × D) where /-- The equivalence, given by swapping factors, between `C × D` and `D × C`. -/ -@[simps!] -def braiding : C × D ≌ D × C := - Equivalence.mk (swap C D) (swap D C) - (NatIso.ofComponents fun X => eqToIso (by simp)) - (NatIso.ofComponents fun X => eqToIso (by simp)) +@[simps] +def braiding : C × D ≌ D × C where + functor := swap C D + inverse := swap D C + unitIso := Iso.refl _ + counitIso := Iso.refl _ instance swapIsEquivalence : (swap C D).IsEquivalence := (by infer_instance : (braiding C D).functor.IsEquivalence) @@ -263,6 +263,12 @@ def prod {F G : A ⥤ B} {H I : C ⥤ D} (α : F ⟶ G) (β : H ⟶ I) : F.prod use instead `α.prod β` or `NatTrans.prod α β`. -/ end NatTrans +/-- The cartesian product functor between functor categories -/ +@[simps] +def prodFunctor : (A ⥤ B) × (C ⥤ D) ⥤ A × C ⥤ B × D where + obj FG := FG.1.prod FG.2 + map nm := NatTrans.prod nm.1 nm.2 + namespace NatIso /-- The cartesian product of two natural isomorphisms. -/ @@ -289,7 +295,18 @@ 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 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/Products/Unitor.lean b/Mathlib/CategoryTheory/Products/Unitor.lean index f436f1074f993..7cb26c8bc22cf 100644 --- a/Mathlib/CategoryTheory/Products/Unitor.lean +++ b/Mathlib/CategoryTheory/Products/Unitor.lean @@ -42,7 +42,7 @@ def rightInverseUnitor : C ⥤ C × Discrete (PUnit : Type w) where obj X := ⟨X, ⟨PUnit.unit⟩⟩ map f := ⟨f, 𝟙 _⟩ -/-- The equivalence of categories expressing left unity of products of categories. -/ +/-- The equivalence of categories expressing left unity of products of categories. -/ @[simps] def leftUnitorEquivalence : Discrete (PUnit : Type w) × C ≌ C where functor := leftUnitor C @@ -50,7 +50,7 @@ def leftUnitorEquivalence : Discrete (PUnit : Type w) × C ≌ C where unitIso := Iso.refl _ counitIso := Iso.refl _ -/-- The equivalence of categories expressing right unity of products of categories. -/ +/-- The equivalence of categories expressing right unity of products of categories. -/ @[simps] def rightUnitorEquivalence : C × Discrete (PUnit : Type w) ≌ C where functor := rightUnitor C diff --git a/Mathlib/CategoryTheory/Shift/Basic.lean b/Mathlib/CategoryTheory/Shift/Basic.lean index d830b0b79c97d..c8b2f4ddfaec9 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 -/ import Mathlib.Algebra.Group.Basic import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Zero diff --git a/Mathlib/CategoryTheory/Shift/CommShift.lean b/Mathlib/CategoryTheory/Shift/CommShift.lean index 5f75457aa59db..e75c095dca271 100644 --- a/Mathlib/CategoryTheory/Shift/CommShift.lean +++ b/Mathlib/CategoryTheory/Shift/CommShift.lean @@ -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 ddedbb2626916..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 @@ -53,6 +53,10 @@ lemma shiftFunctor_comp_inverts (a : A) : end IsCompatibleWithShift +variable {A} in +lemma shift {X Y : C} {f : X ⟶ Y} (hf : W f) (a : A) : W (f⟦a⟧') := by + simpa only [IsCompatibleWithShift.iff W f a] using hf + variable {A} in /-- The morphism of localizer from `W` to `W` given by the functor `shiftFunctor C a` when `a : A` and `W` is compatible with the shift by `A`. -/ @@ -86,7 +90,7 @@ noncomputable def Functor.CommShift.localized : attribute [irreducible] HasShift.localized Functor.CommShift.localized -/-- The localized category `W.Localization` is endowed with the induced shift. -/ +/-- The localized category `W.Localization` is endowed with the induced shift. -/ noncomputable instance HasShift.localization : HasShift W.Localization A := HasShift.localized W.Q W A @@ -100,7 +104,7 @@ attribute [irreducible] HasShift.localization MorphismProperty.commShift_Q variable [W.HasLocalization] -/-- The localized category `W.Localization'` is endowed with the induced shift. -/ +/-- The localized category `W.Localization'` is endowed with the induced shift. -/ noncomputable instance HasShift.localization' : HasShift W.Localization' A := HasShift.localized W.Q' W A @@ -161,7 +165,7 @@ end commShiftOfLocalization /-- In the context of localization of categories, if a functor is induced by a functor which commutes with the shift, then -this functor commutes with the shift. -/ +this functor commutes with the shift. -/ noncomputable def commShiftOfLocalization : F'.CommShift A where iso := commShiftOfLocalization.iso L W F F' zero := by diff --git a/Mathlib/CategoryTheory/Shift/Quotient.lean b/Mathlib/CategoryTheory/Shift/Quotient.lean index 0aa245c4e4247..f789f82c2883c 100644 --- a/Mathlib/CategoryTheory/Shift/Quotient.lean +++ b/Mathlib/CategoryTheory/Shift/Quotient.lean @@ -17,7 +17,7 @@ for all `a : A`), then the quotient category `Quotient r` is equipped with a shift. The condition `r.IsCompatibleWithShift A` on the relation `r` is a class so that -the shift can be automatically infered on the quotient category. +the shift can be automatically inferred on the quotient category. -/ @@ -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/ShiftedHom.lean b/Mathlib/CategoryTheory/Shift/ShiftedHom.lean index 9df10e3410095..09bea544345c6 100644 --- a/Mathlib/CategoryTheory/Shift/ShiftedHom.lean +++ b/Mathlib/CategoryTheory/Shift/ShiftedHom.lean @@ -28,7 +28,7 @@ variable {C : Type*} [Category C] {D : Type*} [Category D] {E : Type*} [Category {M : Type*} [AddMonoid M] [HasShift C M] [HasShift D M] [HasShift E M] /-- In a category `C` equipped with a shift by an additive monoid, -this is the type of morphisms `X ⟶ (Y⟦n⟧)` for `m : M`. -/ +this is the type of morphisms `X ⟶ (Y⟦n⟧)` for `m : M`. -/ def ShiftedHom (X Y : C) (m : M) : Type _ := X ⟶ (Y⟦m⟧) instance [Preadditive C] (X Y : C) (n : M) : AddCommGroup (ShiftedHom X Y n) := by diff --git a/Mathlib/CategoryTheory/Simple.lean b/Mathlib/CategoryTheory/Simple.lean index 04c45673e542c..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 @@ -56,7 +56,6 @@ theorem isIso_of_mono_of_nonzero {X Y : C} [Simple Y] {f : X ⟶ Y} [Mono f] (w theorem Simple.of_iso {X Y : C} [Simple Y] (i : X ≅ Y) : Simple X := { mono_isIso_iff_nonzero := fun f m => by - haveI : Mono (f ≫ i.hom) := mono_comp _ _ constructor · intro h w have j : IsIso (f ≫ i.hom) := by infer_instance diff --git a/Mathlib/CategoryTheory/SingleObj.lean b/Mathlib/CategoryTheory/SingleObj.lean index b7e8e14ddffd6..a3e3ca9146610 100644 --- a/Mathlib/CategoryTheory/SingleObj.lean +++ b/Mathlib/CategoryTheory/SingleObj.lean @@ -242,7 +242,7 @@ def toCat : MonCat ⥤ Cat where obj x := Cat.of (SingleObj x) map {x y} f := SingleObj.mapHom x y f -instance toCat_full : toCat.Full where +instance toCat_full : toCat.Full where map_surjective := (SingleObj.mapHom _ _).surjective instance toCat_faithful : toCat.Faithful where diff --git a/Mathlib/CategoryTheory/Sites/Adjunction.lean b/Mathlib/CategoryTheory/Sites/Adjunction.lean index a2aa3e4aa6b95..334681a5529d0 100644 --- a/Mathlib/CategoryTheory/Sites/Adjunction.lean +++ b/Mathlib/CategoryTheory/Sites/Adjunction.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Adam Topaz. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Adam Topaz, Joël Riou -/ +import Mathlib.CategoryTheory.Adjunction.Restrict import Mathlib.CategoryTheory.Adjunction.Whiskering import Mathlib.CategoryTheory.Sites.PreservesSheafification @@ -35,53 +36,36 @@ namespace Sheaf noncomputable section -/-- An auxiliary definition to be used in defining `CategoryTheory.Sheaf.adjunction` below. -/ -@[simps] -def composeEquiv [HasWeakSheafify J D] [HasSheafCompose J F] (adj : G ⊣ F) - (X : Sheaf J E) (Y : Sheaf J D) : - ((composeAndSheafify J G).obj X ⟶ Y) ≃ (X ⟶ (sheafCompose J F).obj Y) := - let A := adj.whiskerRight Cᵒᵖ - { toFun := fun η => ⟨A.homEquiv _ _ (toSheafify J _ ≫ η.val)⟩ - invFun := fun γ => ⟨sheafifyLift J ((A.homEquiv _ _).symm ((sheafToPresheaf _ _).map γ)) Y.2⟩ - left_inv := by - intro η - ext1 - dsimp - symm - apply sheafifyLift_unique - rw [Equiv.symm_apply_apply] - right_inv := by - intro γ - ext1 - dsimp - -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 - erw [toSheafify_sheafifyLift, Equiv.apply_symm_apply] } - --- These lemmas have always been bad (#7657), but leanprover/lean4#2644 made `simp` start noticing -attribute [nolint simpNF] CategoryTheory.Sheaf.composeEquiv_apply_val - CategoryTheory.Sheaf.composeEquiv_symm_apply_val - /-- An adjunction `adj : G ⊣ F` with `F : D ⥤ E` and `G : E ⥤ D` induces an adjunction between `Sheaf J D` and `Sheaf J E`, in contexts where one can sheafify `D`-valued presheaves, -and `F` preserves the correct limits. -/ -@[simps! unit_app_val counit_app_val] +and postcomposing with `F` preserves the property of being a sheaf. -/ def adjunction [HasWeakSheafify J D] [HasSheafCompose J F] (adj : G ⊣ F) : composeAndSheafify J G ⊣ sheafCompose J F := - Adjunction.mkOfHomEquiv - { homEquiv := composeEquiv J adj - homEquiv_naturality_left_symm := fun f g => by - ext1 - dsimp [composeEquiv] - rw [sheafifyMap_sheafifyLift] - erw [Adjunction.homEquiv_naturality_left_symm] - rw [whiskeringRight_obj_map] - rfl - homEquiv_naturality_right := fun f g => by - ext - dsimp [composeEquiv] - erw [Adjunction.homEquiv_unit, Adjunction.homEquiv_unit] - dsimp - simp } + Adjunction.restrictFullyFaithful ((adj.whiskerRight Cᵒᵖ).comp (sheafificationAdjunction J D)) + (fullyFaithfulSheafToPresheaf J E) (Functor.FullyFaithful.id _) (Iso.refl _) (Iso.refl _) + +@[simp] +lemma adjunction_unit_app_val [HasWeakSheafify J D] [HasSheafCompose J F] (adj : G ⊣ F) + (X : Sheaf J E) : ((adjunction J adj).unit.app X).val = + (adj.whiskerRight Cᵒᵖ).unit.app _ ≫ whiskerRight (toSheafify J (X.val ⋙ G)) F := by + change (sheafToPresheaf _ _).map ((adjunction J adj).unit.app X) = _ + simp only [Functor.id_obj, Functor.comp_obj, whiskeringRight_obj_obj, adjunction, + Adjunction.map_restrictFullyFaithful_unit_app, Adjunction.comp_unit_app, + sheafificationAdjunction_unit_app, whiskeringRight_obj_map, Iso.refl_hom, NatTrans.id_app, + Functor.comp_map, Functor.map_id, whiskerRight_id', Category.comp_id] + rfl + +@[simp] +lemma adjunction_counit_app_val [HasWeakSheafify J D] [HasSheafCompose J F] (adj : G ⊣ F) + (Y : Sheaf J D) : ((adjunction J adj).counit.app Y).val = + sheafifyLift J (((adj.whiskerRight Cᵒᵖ).counit.app Y.val)) Y.cond := by + change ((𝟭 (Sheaf _ _)).map ((adjunction J adj).counit.app Y)).val = _ + simp only [Functor.comp_obj, sheafToPresheaf_obj, sheafCompose_obj_val, whiskeringRight_obj_obj, + adjunction, Adjunction.map_restrictFullyFaithful_counit_app, Iso.refl_inv, NatTrans.id_app, + Functor.comp_map, whiskeringRight_obj_map, Adjunction.comp_counit_app, + instCategorySheaf_comp_val, instCategorySheaf_id_val, sheafificationAdjunction_counit_app_val, + sheafifyMap_sheafifyLift, Functor.id_obj, whiskerRight_id', Category.comp_id, Category.id_comp] + instance [HasWeakSheafify J D] [F.IsRightAdjoint] : (sheafCompose J F).IsRightAdjoint := (adjunction J (Adjunction.ofIsRightAdjoint F)).isRightAdjoint @@ -100,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) @@ -126,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] @@ -136,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 756cf0d75719f..ec5fdd447f5e9 100644 --- a/Mathlib/CategoryTheory/Sites/Canonical.lean +++ b/Mathlib/CategoryTheory/Sites/Canonical.lean @@ -80,11 +80,7 @@ theorem isSheafFor_bind (P : Cᵒᵖ ⥤ Type v) (U : Sieve X) (B : ∀ ⦃Y⦄ intro Y l hl apply (hB' hf (l ≫ h)).ext intro M m hm - have : bind U B (m ≫ l ≫ h ≫ f) := by - -- Porting note: had to make explicit the parameter `((m ≫ l ≫ h) ≫ f)` and - -- using `by exact` - have : bind U B ((m ≫ l ≫ h) ≫ f) := by exact Presieve.bind_comp f hf hm - simpa using this + have : bind U B (m ≫ l ≫ h ≫ f) := by simpa using (Presieve.bind_comp f hf hm : bind U B _) trans s (m ≫ l ≫ h ≫ f) this · have := ht (U.downward_closed hf h) _ ((B _).downward_closed hl m) rw [op_comp, FunctorToTypes.map_comp_apply] at this @@ -207,7 +203,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 _) @@ -228,9 +224,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} @@ -242,7 +238,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/CartesianClosed.lean b/Mathlib/CategoryTheory/Sites/CartesianClosed.lean new file mode 100644 index 0000000000000..130f67e3c181c --- /dev/null +++ b/Mathlib/CategoryTheory/Sites/CartesianClosed.lean @@ -0,0 +1,25 @@ +/- +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.Closed.Ideal +import Mathlib.CategoryTheory.Limits.FunctorCategory.Finite +import Mathlib.CategoryTheory.Sites.Limits +/-! + +# Sheaf categories are cartesian closed + +...if the underlying presheaf category is cartesian closed, the target category has finite products, +and there exists a sheafification functor. +-/ + +noncomputable section + +open CategoryTheory Limits + +variable {C : Type*} [Category C] (J : GrothendieckTopology C) (A : Type*) [Category A] + +instance [HasSheafify J A] [HasFiniteProducts A] [CartesianClosed (Cᵒᵖ ⥤ A)] : + CartesianClosed (Sheaf J A) := + cartesianClosedOfReflective (sheafToPresheaf _ _) diff --git a/Mathlib/CategoryTheory/Sites/Coherent/CoherentSheaves.lean b/Mathlib/CategoryTheory/Sites/Coherent/CoherentSheaves.lean index 9a132e3a51e8b..3525e9600b95a 100644 --- a/Mathlib/CategoryTheory/Sites/Coherent/CoherentSheaves.lean +++ b/Mathlib/CategoryTheory/Sites/Coherent/CoherentSheaves.lean @@ -15,8 +15,8 @@ This file characterises sheaves for the coherent topology ## Main result * `isSheaf_coherent`: a presheaf of types for the is a sheaf for the coherent topology if and only - if it satisfies the sheaf condition with respect to every presieve consiting of a finite effective - epimorphic family. + if it satisfies the sheaf condition with respect to every presieve consisting of a finite + effective epimorphic family. -/ namespace CategoryTheory diff --git a/Mathlib/CategoryTheory/Sites/Coherent/CoherentTopology.lean b/Mathlib/CategoryTheory/Sites/Coherent/CoherentTopology.lean index bd53932b0ed07..e3d81579f0701 100644 --- a/Mathlib/CategoryTheory/Sites/Coherent/CoherentTopology.lean +++ b/Mathlib/CategoryTheory/Sites/Coherent/CoherentTopology.lean @@ -29,7 +29,7 @@ Note: This is one direction of `mem_sieves_iff_hasEffectiveEpiFamily`, but is ne theorem coherentTopology.mem_sieves_of_hasEffectiveEpiFamily (S : Sieve X) : (∃ (α : Type) (_ : Finite α) (Y : α → C) (π : (a : α) → (Y a ⟶ X)), EffectiveEpiFamily Y π ∧ (∀ a : α, (S.arrows) (π a)) ) → - (S ∈ GrothendieckTopology.sieves (coherentTopology C) X) := by + (S ∈ (coherentTopology C) X) := by intro ⟨α, _, Y, π, hπ⟩ apply (coherentCoverage C).mem_toGrothendieck_sieves_of_superset (R := Presieve.ofArrows Y π) · exact fun _ _ h ↦ by cases h; exact hπ.2 _ @@ -49,7 +49,7 @@ theorem EffectiveEpiFamily.transitive_of_finite {α : Type} [Finite α] {Y : α (fun (c : Σ a, β a) => Y_n c.fst c.snd) (fun c => π_n c.fst c.snd ≫ π c.fst) := by rw [← Sieve.effectiveEpimorphic_family] suffices h₂ : (Sieve.generate (Presieve.ofArrows (fun (⟨a, b⟩ : Σ _, β _) => Y_n a b) - (fun ⟨a,b⟩ => π_n a b ≫ π a))) ∈ GrothendieckTopology.sieves (coherentTopology C) X by + (fun ⟨a,b⟩ => π_n a b ≫ π a))) ∈ (coherentTopology C) X by change Nonempty _ rw [← Sieve.forallYonedaIsSheaf_iff_colimit] exact fun W => coherentTopology.isSheaf_yoneda_obj W _ h₂ @@ -80,18 +80,21 @@ A sieve belongs to the coherent topology if and only if it contains a finite `EffectiveEpiFamily`. -/ theorem coherentTopology.mem_sieves_iff_hasEffectiveEpiFamily (S : Sieve X) : - (S ∈ GrothendieckTopology.sieves (coherentTopology C) X) ↔ + (S ∈ (coherentTopology C) X) ↔ (∃ (α : Type) (_ : Finite α) (Y : α → C) (π : (a : α) → (Y a ⟶ X)), EffectiveEpiFamily Y π ∧ (∀ a : α, (S.arrows) (π a)) ) := by constructor · intro h - induction' h with Y T hS Y Y R S _ _ a b - · obtain ⟨a, h, Y', π, h', _⟩ := hS + induction h with + | of Y T hS => + obtain ⟨a, h, Y', π, h', _⟩ := hS refine ⟨a, h, Y', π, inferInstance, fun a' ↦ ?_⟩ obtain ⟨rfl, _⟩ := h' exact ⟨Y' a', 𝟙 Y' a', π a', Presieve.ofArrows.mk a', by simp⟩ - · exact ⟨Unit, inferInstance, fun _ => Y, fun _ => (𝟙 Y), inferInstance, by simp⟩ - · obtain ⟨α, w, Y₁, π, ⟨h₁,h₂⟩⟩ := a + | top Y => + exact ⟨Unit, inferInstance, fun _ => Y, fun _ => (𝟙 Y), inferInstance, by simp⟩ + | transitive Y R S _ _ a b => + obtain ⟨α, w, Y₁, π, ⟨h₁,h₂⟩⟩ := a choose β _ Y_n π_n H using fun a => b (h₂ a) exact ⟨(Σ a, β a), inferInstance, fun ⟨a,b⟩ => Y_n a b, fun ⟨a, b⟩ => (π_n a b) ≫ (π a), EffectiveEpiFamily.transitive_of_finite _ h₁ _ (fun a => (H a).1), diff --git a/Mathlib/CategoryTheory/Sites/Coherent/Comparison.lean b/Mathlib/CategoryTheory/Sites/Coherent/Comparison.lean index 7c93c78272de3..f0f439fb8e122 100644 --- a/Mathlib/CategoryTheory/Sites/Coherent/Comparison.lean +++ b/Mathlib/CategoryTheory/Sites/Coherent/Comparison.lean @@ -78,9 +78,9 @@ theorem extensive_regular_generate_coherent [Preregular C] [FinitaryPreExtensive Set.mem_setOf_eq] exact Or.inr ⟨_, Sigma.desc f, ⟨rfl, inferInstance⟩⟩ · rintro R g ⟨W, ψ, σ, ⟨⟩, rfl⟩ - change _ ∈ sieves ((extensiveCoverage C) ⊔ (regularCoverage C)).toGrothendieck _ + change _ ∈ ((extensiveCoverage C) ⊔ (regularCoverage C)).toGrothendieck _ R rw [Sieve.pullback_comp] - apply pullback_stable' + apply pullback_stable have : generate (Presieve.ofArrows X fun (i : I) ↦ Sigma.ι X i) ≤ (generate (Presieve.ofArrows X f)).pullback (Sigma.desc f) := by rintro Q q ⟨E, e, r, ⟨hq, rfl⟩⟩ diff --git a/Mathlib/CategoryTheory/Sites/Coherent/Equivalence.lean b/Mathlib/CategoryTheory/Sites/Coherent/Equivalence.lean index e66a91cfd4c63..edc55d2e3f01e 100644 --- a/Mathlib/CategoryTheory/Sites/Coherent/Equivalence.lean +++ b/Mathlib/CategoryTheory/Sites/Coherent/Equivalence.lean @@ -9,7 +9,7 @@ import Mathlib.CategoryTheory.Sites.Equivalence # Coherence and equivalence of categories -This file proves that the coherent and regular topologies transfer nicely along equivalences of +This file proves that the coherent and regular topologies transfer nicely along equivalences of categories. -/ @@ -27,7 +27,7 @@ section Coherent variable [Precoherent C] -/-- `Precoherent` is preserved by equivalence of categories. -/ +/-- `Precoherent` is preserved by equivalence of categories. -/ theorem precoherent (e : C ≌ D) : Precoherent D := e.inverse.reflects_precoherent instance [EssentiallySmall C] : @@ -75,7 +75,7 @@ section Regular variable [Preregular C] -/-- `Preregular` is preserved by equivalence of categories. -/ +/-- `Preregular` is preserved by equivalence of categories. -/ theorem preregular (e : C ≌ D) : Preregular D := e.inverse.reflects_preregular instance [EssentiallySmall C] : diff --git a/Mathlib/CategoryTheory/Sites/Coherent/ExtensiveSheaves.lean b/Mathlib/CategoryTheory/Sites/Coherent/ExtensiveSheaves.lean index 4030384a506a2..ae209ddc24c1e 100644 --- a/Mathlib/CategoryTheory/Sites/Coherent/ExtensiveSheaves.lean +++ b/Mathlib/CategoryTheory/Sites/Coherent/ExtensiveSheaves.lean @@ -62,7 +62,7 @@ instance {α : Type} [Finite α] (Z : α → C) : (ofArrows Z (fun i ↦ Sigma. /-- Every Yoneda-presheaf is a sheaf for the extensive topology. -/ theorem extensiveTopology.isSheaf_yoneda_obj (W : C) : Presieve.IsSheaf (extensiveTopology C) (yoneda.obj W) := by - erw [isSheaf_coverage] + rw [extensiveTopology, isSheaf_coverage] intro X R ⟨Y, α, Z, π, hR, hi⟩ have : IsIso (Sigma.desc (Cofan.inj (Cofan.mk X π))) := hi have : R.Extensive := ⟨Y, α, Z, π, hR, ⟨Cofan.isColimitOfIsIsoSigmaDesc (Cofan.mk X π)⟩⟩ @@ -75,19 +75,19 @@ theorem extensiveTopology.subcanonical : Sheaf.Subcanonical (extensiveTopology C variable [FinitaryExtensive C] /-- -A presheaf of sets on a category which is `FinitaryExtensive` is a sheaf iff it preserves finite +A presheaf of sets on a category which is `FinitaryExtensive` is a sheaf iff it preserves finite products. -/ theorem Presieve.isSheaf_iff_preservesFiniteProducts (F : Cᵒᵖ ⥤ Type w) : Presieve.IsSheaf (extensiveTopology C) F ↔ Nonempty (PreservesFiniteProducts F) := by refine ⟨fun hF ↦ ⟨⟨fun α _ ↦ ⟨fun {K} ↦ ?_⟩⟩⟩, fun hF ↦ ?_⟩ - · erw [Presieve.isSheaf_coverage] at hF + · rw [extensiveTopology, isSheaf_coverage] at hF let Z : α → C := fun i ↦ unop (K.obj ⟨i⟩) - have : (Presieve.ofArrows Z (Cofan.mk (∐ Z) (Sigma.ι Z)).inj).hasPullbacks := - (inferInstance : (Presieve.ofArrows Z (Sigma.ι Z)).hasPullbacks) + have : (ofArrows Z (Cofan.mk (∐ Z) (Sigma.ι Z)).inj).hasPullbacks := + inferInstanceAs (ofArrows Z (Sigma.ι Z)).hasPullbacks have : ∀ (i : α), Mono (Cofan.inj (Cofan.mk (∐ Z) (Sigma.ι Z)) i) := - (inferInstance : ∀ (i : α), Mono (Sigma.ι Z i)) + inferInstanceAs <| ∀ (i : α), Mono (Sigma.ι Z i) let i : K ≅ Discrete.functor (fun i ↦ op (Z i)) := Discrete.natIsoFunctor let _ : PreservesLimit (Discrete.functor (fun i ↦ op (Z i))) F := Presieve.preservesProductOfIsSheafFor F ?_ initialIsInitial _ (coproductIsCoproduct Z) @@ -104,14 +104,14 @@ theorem Presieve.isSheaf_iff_preservesFiniteProducts (F : Cᵒᵖ ⥤ Type w) : ext simp · let _ := hF.some - erw [Presieve.isSheaf_coverage] + rw [extensiveTopology, Presieve.isSheaf_coverage] intro X R ⟨Y, α, Z, π, hR, hi⟩ have : IsIso (Sigma.desc (Cofan.inj (Cofan.mk X π))) := hi have : R.Extensive := ⟨Y, α, Z, π, hR, ⟨Cofan.isColimitOfIsIsoSigmaDesc (Cofan.mk X π)⟩⟩ exact isSheafFor_extensive_of_preservesFiniteProducts R F /-- -A presheaf on a category which is `FinitaryExtensive` is a sheaf iff it preserves finite products. +A presheaf on a category which is `FinitaryExtensive` is a sheaf iff it preserves finite products. -/ theorem Presheaf.isSheaf_iff_preservesFiniteProducts (F : Cᵒᵖ ⥤ D) : IsSheaf (extensiveTopology C) F ↔ Nonempty (PreservesFiniteProducts F) := by diff --git a/Mathlib/CategoryTheory/Sites/Coherent/ExtensiveTopology.lean b/Mathlib/CategoryTheory/Sites/Coherent/ExtensiveTopology.lean index 5a8be00569068..1f7872d648175 100644 --- a/Mathlib/CategoryTheory/Sites/Coherent/ExtensiveTopology.lean +++ b/Mathlib/CategoryTheory/Sites/Coherent/ExtensiveTopology.lean @@ -24,7 +24,7 @@ variable {C : Type*} [Category C] [FinitaryPreExtensive C] namespace CategoryTheory lemma extensiveTopology.mem_sieves_iff_contains_colimit_cofan {X : C} (S : Sieve X) : - S ∈ (extensiveTopology C).sieves X ↔ + S ∈ (extensiveTopology C) X ↔ (∃ (α : Type) (_ : Finite α) (Y : α → C) (π : (a : α) → (Y a ⟶ X)), Nonempty (IsColimit (Cofan.mk X π)) ∧ (∀ a : α, (S.arrows) (π a))) := by constructor @@ -53,7 +53,8 @@ lemma extensiveTopology.mem_sieves_iff_contains_colimit_cofan {X : C} (S : Sieve apply (extensiveCoverage C).mem_toGrothendieck_sieves_of_superset (R := Presieve.ofArrows Y π) · exact fun _ _ hh ↦ by cases hh; exact h' _ · refine ⟨α, inferInstance, Y, π, rfl, ?_⟩ - erw [Limits.Cofan.isColimit_iff_isIso_sigmaDesc (c := Cofan.mk X π)] + rw [show IsIso (Sigma.desc π) ↔ _ from + Limits.Cofan.isColimit_iff_isIso_sigmaDesc (c := Cofan.mk X π)] exact h end CategoryTheory diff --git a/Mathlib/CategoryTheory/Sites/Coherent/LocallySurjective.lean b/Mathlib/CategoryTheory/Sites/Coherent/LocallySurjective.lean index ef1204a732163..3a79842c88fc9 100644 --- a/Mathlib/CategoryTheory/Sites/Coherent/LocallySurjective.lean +++ b/Mathlib/CategoryTheory/Sites/Coherent/LocallySurjective.lean @@ -16,14 +16,14 @@ and extensive topologies. ## Main results * `regularTopology.isLocallySurjective_iff` A morphism of presheaves `f : F ⟶ G` is locally - surjective for the regular topology iff for every object `X` of `C`, and every `y : G(X)`, there - is an effective epimorphism `φ : X' ⟶ X` and an `x : F(X)` such that `f_{X'}(x) = G(φ)(y)`. + surjective for the regular topology iff for every object `X` of `C`, and every `y : G(X)`, there + is an effective epimorphism `φ : X' ⟶ X` and an `x : F(X)` such that `f_{X'}(x) = G(φ)(y)`. * `coherentTopology.isLocallySurjective_iff` a morphism of sheaves for the coherent topology on a preregular finitary extensive category is locally surjective if and only if it is locally surjective for the regular topology. -* `extensiveTopology.isLocallySurjective_iff` a morphism of sheaves for the extensive topology on a +* `extensiveTopology.isLocallySurjective_iff` a morphism of sheaves for the extensive topology on a finitary extensive category is locally surjective iff it is objectwise surjective. -/ @@ -78,9 +78,9 @@ lemma extensiveTopology.surjective_of_isLocallySurjective_sheafOfTypes [Finitary Cofan.mk_ι_app] have : f.app ⟨Y a⟩ (y a) = G.map (π a).op x := (h' a).choose_spec change _ = G.map (π a).op x - erw [← this, ← NatTrans.naturality_apply (φ := f)] - apply congrArg - change (i.hom ≫ F.map (π a).op) y = _ + rw [← this] + erw [← NatTrans.naturality_apply (φ := f)] + change f.app _ ((i.hom ≫ F.map (π a).op) y) = _ erw [IsLimit.map_π] rfl diff --git a/Mathlib/CategoryTheory/Sites/Coherent/ReflectsPrecoherent.lean b/Mathlib/CategoryTheory/Sites/Coherent/ReflectsPrecoherent.lean index a42e9b7bca302..54bc130f05abb 100644 --- a/Mathlib/CategoryTheory/Sites/Coherent/ReflectsPrecoherent.lean +++ b/Mathlib/CategoryTheory/Sites/Coherent/ReflectsPrecoherent.lean @@ -11,8 +11,8 @@ import Mathlib.CategoryTheory.Sites.Coherent.CoherentTopology # Reflecting the property of being precoherent We prove that given a fully faithful functor `F : C ⥤ D` which preserves and reflects finite -effective epimorphic families, such that for every object `X` of `D` there exists an object `W` of -`C` with an effective epi `π : F.obj W ⟶ X`, the category `C` is `Precoherent` whenever `D` is. +effective epimorphic families, such that for every object `X` of `D` there exists an object `W` of +`C` with an effective epi `π : F.obj W ⟶ X`, the category `C` is `Precoherent` whenever `D` is. -/ namespace CategoryTheory diff --git a/Mathlib/CategoryTheory/Sites/Coherent/ReflectsPreregular.lean b/Mathlib/CategoryTheory/Sites/Coherent/ReflectsPreregular.lean index 9b3784170505c..58eef6dd8e4c3 100644 --- a/Mathlib/CategoryTheory/Sites/Coherent/ReflectsPreregular.lean +++ b/Mathlib/CategoryTheory/Sites/Coherent/ReflectsPreregular.lean @@ -11,8 +11,8 @@ import Mathlib.CategoryTheory.Sites.Coherent.RegularTopology # Reflecting the property of being preregular We prove that given a fully faithful functor `F : C ⥤ D`, with `Preregular D`, such that for every -object `X` of `D` there exists an object `W` of `C` with an effective epi `π : F.obj W ⟶ X`, the -category `C` is `Preregular`. +object `X` of `D` there exists an object `W` of `C` with an effective epi `π : F.obj W ⟶ X`, the +category `C` is `Preregular`. -/ namespace CategoryTheory diff --git a/Mathlib/CategoryTheory/Sites/Coherent/RegularSheaves.lean b/Mathlib/CategoryTheory/Sites/Coherent/RegularSheaves.lean index 0fe6215a09392..e310d8b283782 100644 --- a/Mathlib/CategoryTheory/Sites/Coherent/RegularSheaves.lean +++ b/Mathlib/CategoryTheory/Sites/Coherent/RegularSheaves.lean @@ -17,7 +17,7 @@ This file characterises sheaves for the regular topology. ## Main results -* `equalizerCondition_iff_isSheaf`: In a preregular category with pullbacks, the sheaves for the +* `equalizerCondition_iff_isSheaf`: In a preregular category with pullbacks, the sheaves for the regular topology are precisely the presheaves satisfying an equaliser condition with respect to effective epimorphisms. @@ -46,7 +46,7 @@ lemma equalizerCondition_w (P : Cᵒᵖ ⥤ D) {X B : C} {π : X ⟶ B} (c : Pul simp only [← Functor.map_comp, ← op_comp, c.condition] /-- -A contravariant functor on `C` satisifies `SingleEqualizerCondition` with respect to a morphism `π` +A contravariant functor on `C` satisfies `SingleEqualizerCondition` with respect to a morphism `π` if it takes its kernel pair to an equalizer diagram. -/ def SingleEqualizerCondition (P : Cᵒᵖ ⥤ D) ⦃X B : C⦄ (π : X ⟶ B) : Prop := @@ -54,7 +54,7 @@ def SingleEqualizerCondition (P : Cᵒᵖ ⥤ D) ⦃X B : C⦄ (π : X ⟶ B) : Nonempty (IsLimit (Fork.ofι (P.map π.op) (equalizerCondition_w P c))) /-- -A contravariant functor on `C` satisfies `EqualizerCondition` if it takes kernel pairs of effective +A contravariant functor on `C` satisfies `EqualizerCondition` if it takes kernel pairs of effective epimorphisms to equalizer diagrams. -/ def EqualizerCondition (P : Cᵒᵖ ⥤ D) : Prop := @@ -148,7 +148,7 @@ theorem equalizerCondition_iff_isIso_lift (P : Cᵒᵖ ⥤ Type*) : EqualizerCon rw [mapToEqualizer_eq_comp, ← isIso_iff_bijective] infer_instance -/-- `P` satisfies the equalizer condition iff its precomposition by an equivalence does. -/ +/-- `P` satisfies the equalizer condition iff its precomposition by an equivalence does. -/ theorem equalizerCondition_iff_of_equivalence (P : Cᵒᵖ ⥤ D) (e : C ≌ E) : EqualizerCondition P ↔ EqualizerCondition (e.op.inverse ⋙ P) := ⟨fun h ↦ equalizerCondition_precomp_of_preservesPullback P e.inverse h, fun h ↦ @@ -177,7 +177,7 @@ theorem parallelPair_pullback_initial {X B : C} (π : X ⟶ B) all_goals exact Comma.hom_ext _ _ (by erw [Over.comp_left]; simp [ij]) rfl /-- -Given a limiting pullback cone, the fork in `SingleEqualizerCondition` is limiting iff the diagram +Given a limiting pullback cone, the fork in `SingleEqualizerCondition` is limiting iff the diagram in `Presheaf.isSheaf_iff_isLimit_coverage` is limiting. -/ noncomputable def isLimit_forkOfι_equiv (P : Cᵒᵖ ⥤ D) {X B : C} (π : X ⟶ B) diff --git a/Mathlib/CategoryTheory/Sites/Coherent/RegularTopology.lean b/Mathlib/CategoryTheory/Sites/Coherent/RegularTopology.lean index f15935efeb4dc..7d62dc4654e53 100644 --- a/Mathlib/CategoryTheory/Sites/Coherent/RegularTopology.lean +++ b/Mathlib/CategoryTheory/Sites/Coherent/RegularTopology.lean @@ -28,7 +28,7 @@ regular topology. Note: This is one direction of `mem_sieves_iff_hasEffectiveEpi`, but is needed for the proof. -/ theorem mem_sieves_of_hasEffectiveEpi (S : Sieve X) : - (∃ (Y : C) (π : Y ⟶ X), EffectiveEpi π ∧ S.arrows π) → (S ∈ (regularTopology C).sieves X) := by + (∃ (Y : C) (π : Y ⟶ X), EffectiveEpi π ∧ S.arrows π) → (S ∈ (regularTopology C) X) := by rintro ⟨Y, π, h⟩ have h_le : Sieve.generate (Presieve.ofArrows (fun () ↦ Y) (fun _ ↦ π)) ≤ S := by rw [Sieve.generate_le_iff (Presieve.ofArrows _ _) S] @@ -44,8 +44,7 @@ theorem mem_sieves_of_hasEffectiveEpi (S : Sieve X) : instance {Y Y' : C} (π : Y ⟶ X) [EffectiveEpi π] (π' : Y' ⟶ Y) [EffectiveEpi π'] : EffectiveEpi (π' ≫ π) := by rw [effectiveEpi_iff_effectiveEpiFamily, ← Sieve.effectiveEpimorphic_family] - suffices h₂ : (Sieve.generate (Presieve.ofArrows _ _)) ∈ - GrothendieckTopology.sieves (regularTopology C) X by + suffices h₂ : (Sieve.generate (Presieve.ofArrows _ _)) ∈ (regularTopology C) X by change Nonempty _ rw [← Sieve.forallYonedaIsSheaf_iff_colimit] exact fun W => regularTopology.isSheaf_yoneda_obj W _ h₂ @@ -62,17 +61,19 @@ instance {Y Y' : C} (π : Y ⟶ X) [EffectiveEpi π] /-- A sieve is a cover for the regular topology if and only if it contains an `EffectiveEpi`. -/ theorem mem_sieves_iff_hasEffectiveEpi (S : Sieve X) : - (S ∈ (regularTopology C).sieves X) ↔ + (S ∈ (regularTopology C) X) ↔ ∃ (Y : C) (π : Y ⟶ X), EffectiveEpi π ∧ (S.arrows π) := by constructor · intro h - induction' h with Y T hS Y Y R S _ _ a b - · rcases hS with ⟨Y', π, h'⟩ + induction h with + | of Y T hS => + rcases hS with ⟨Y', π, h'⟩ refine ⟨Y', π, h'.2, ?_⟩ rcases h' with ⟨rfl, _⟩ exact ⟨Y', 𝟙 Y', π, Presieve.ofArrows.mk (), (by simp)⟩ - · exact ⟨Y, (𝟙 Y), inferInstance, by simp only [Sieve.top_apply, forall_const]⟩ - · rcases a with ⟨Y₁, π, ⟨h₁,h₂⟩⟩ + | top Y => exact ⟨Y, (𝟙 Y), inferInstance, by simp only [Sieve.top_apply, forall_const]⟩ + | transitive Y R S _ _ a b => + rcases a with ⟨Y₁, π, ⟨h₁,h₂⟩⟩ choose Y' π' _ H using b h₂ exact ⟨Y', π' ≫ π, inferInstance, (by simpa using H)⟩ · exact regularTopology.mem_sieves_of_hasEffectiveEpi S diff --git a/Mathlib/CategoryTheory/Sites/Coherent/SheafComparison.lean b/Mathlib/CategoryTheory/Sites/Coherent/SheafComparison.lean index 330fcdfb5f49f..a20deb1ceff5d 100644 --- a/Mathlib/CategoryTheory/Sites/Coherent/SheafComparison.lean +++ b/Mathlib/CategoryTheory/Sites/Coherent/SheafComparison.lean @@ -14,15 +14,15 @@ import Mathlib.CategoryTheory.Sites.Whiskering # Categories of coherent sheaves Given a fully faithful functor `F : C ⥤ D` into a precoherent category, which preserves and reflects -finite effective epi families, and satisfies the property `F.EffectivelyEnough` (meaning that to +finite effective epi families, and satisfies the property `F.EffectivelyEnough` (meaning that to every object in `C` there is an effective epi from an object in the image of `F`), the categories -of coherent sheaves on `C` and `D` are equivalent (see +of coherent sheaves on `C` and `D` are equivalent (see `CategoryTheory.coherentTopology.equivalence`). The main application of this equivalence is the characterisation of condensed sets as coherent sheaves on either `CompHaus`, `Profinite` or `Stonean`. See the file `Condensed/Equivalence.lean` -We give the corresonding result for the regular topology as well (see +We give the corresponding result for the regular topology as well (see `CategoryTheory.regularTopology.equivalence`). -/ @@ -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 := @@ -101,7 +109,7 @@ variable {C : Type u₁} {D : Type u₂} [Category.{v₁} C] [Category.{v₂} D] /-- The equivalence from coherent sheaves on `C` to coherent sheaves on `D`, given a fully faithful -functor `F : C ⥤ D` to a precoherent category, which preserves and reflects effective epimorphic +functor `F : C ⥤ D` to a precoherent category, which preserves and reflects effective epimorphic families, and satisfies `F.EffectivelyEnough`. -/ noncomputable @@ -124,7 +132,7 @@ variable {C : Type u₁} {D : Type u₂} [Category.{v₁} C] [Category.{v₂} D] /-- The equivalence from coherent sheaves on `C` to coherent sheaves on `D`, given a fully faithful -functor `F : C ⥤ D` to an extensive preregular category, which preserves and reflects effective +functor `F : C ⥤ D` to an extensive preregular category, which preserves and reflects effective epimorphisms and satisfies `F.EffectivelyEnough`. -/ noncomputable @@ -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 := @@ -197,7 +213,7 @@ variable {C : Type u₁} {D : Type u₂} [Category.{v₁} C] [Category.{v₂} D] /-- The equivalence from regular sheaves on `C` to regular sheaves on `D`, given a fully faithful -functor `F : C ⥤ D` to a preregular category, which preserves and reflects effective +functor `F : C ⥤ D` to a preregular category, which preserves and reflects effective epimorphisms and satisfies `F.EffectivelyEnough`. -/ noncomputable @@ -246,7 +262,7 @@ theorem isSheaf_iff_extensiveSheaf_of_projective [Preregular C] [FinitaryExtensi rw [isSheaf_iff_preservesFiniteProducts_of_projective, isSheaf_iff_preservesFiniteProducts] /-- -The categories of coherent sheaves and extensive sheaves on `C` are equivalent if `C` is +The categories of coherent sheaves and extensive sheaves on `C` are equivalent if `C` is preregular, finitary extensive, and every object is projective. -/ @[simps] diff --git a/Mathlib/CategoryTheory/Sites/CompatiblePlus.lean b/Mathlib/CategoryTheory/Sites/CompatiblePlus.lean index df5b4c90f4608..602fb9363514a 100644 --- a/Mathlib/CategoryTheory/Sites/CompatiblePlus.lean +++ b/Mathlib/CategoryTheory/Sites/CompatiblePlus.lean @@ -96,7 +96,7 @@ def plusCompIso : J.plusObj P ⋙ F ≅ J.plusObj (P ⋙ F) := ext dsimp simp only [Category.assoc] - erw [Multiequalizer.lift_ι, diagramCompIso_hom_ι, diagramCompIso_hom_ι, ← F.map_comp, + rw [Multiequalizer.lift_ι, diagramCompIso_hom_ι, diagramCompIso_hom_ι, ← F.map_comp, Multiequalizer.lift_ι]) @[reassoc (attr := simp)] diff --git a/Mathlib/CategoryTheory/Sites/CompatibleSheafification.lean b/Mathlib/CategoryTheory/Sites/CompatibleSheafification.lean index d611090b676e6..ad79a0ec8cdd5 100644 --- a/Mathlib/CategoryTheory/Sites/CompatibleSheafification.lean +++ b/Mathlib/CategoryTheory/Sites/CompatibleSheafification.lean @@ -29,9 +29,6 @@ variable {D : Type w₁} [Category.{max v u} D] variable {E : Type w₂} [Category.{max v u} E] variable (F : D ⥤ E) --- Porting note: Removed this and made whatever necessary noncomputable --- noncomputable section - variable [∀ (α β : Type max v u) (fst snd : β → α), HasLimitsOfShape (WalkingMulticospan fst snd) D] variable [∀ (α β : Type max v u) (fst snd : β → α), HasLimitsOfShape (WalkingMulticospan fst snd) E] variable [∀ X : C, HasColimitsOfShape (J.Cover X)ᵒᵖ D] diff --git a/Mathlib/CategoryTheory/Sites/ConcreteSheafification.lean b/Mathlib/CategoryTheory/Sites/ConcreteSheafification.lean index 3f6ecdafd76ae..8d46116dc8326 100644 --- a/Mathlib/CategoryTheory/Sites/ConcreteSheafification.lean +++ b/Mathlib/CategoryTheory/Sites/ConcreteSheafification.lean @@ -153,7 +153,8 @@ theorem res_mk_eq_mk_pullback {Y X : C} {P : Cᵒᵖ ⥤ D} {S : J.Cover X} (x : ext i simp only [Functor.op_obj, unop_op, pullback_obj, diagram_obj, Functor.comp_obj, diagramPullback_app, Meq.equiv_apply, Meq.pullback_apply] - erw [← comp_apply, Multiequalizer.lift_ι, Meq.equiv_symm_eq_apply] + rw [← comp_apply, Multiequalizer.lift_ι] + erw [Meq.equiv_symm_eq_apply] cases i; rfl theorem toPlus_mk {X : C} {P : Cᵒᵖ ⥤ D} (S : J.Cover X) (x : P.obj (op X)) : @@ -162,7 +163,8 @@ theorem toPlus_mk {X : C} {P : Cᵒᵖ ⥤ D} (S : J.Cover X) (x : P.obj (op X)) let e : S ⟶ ⊤ := homOfLE (OrderTop.le_top _) rw [← colimit.w _ e.op] delta Cover.toMultiequalizer - erw [comp_apply, comp_apply] + rw [comp_apply] + erw [comp_apply] apply congr_arg dsimp [diagram] apply Concrete.multiequalizer_ext @@ -347,7 +349,7 @@ theorem exists_of_sep (P : Cᵒᵖ ⥤ D) use mk w ext I dsimp [Meq.mk] - erw [ht, res_mk_eq_mk_pullback] + rw [ht, res_mk_eq_mk_pullback] -- Use the separatedness of `P⁺` to prove that this is indeed a gluing of our -- original local sections. apply sep P (T I) @@ -369,7 +371,7 @@ theorem exists_of_sep (P : Cᵒᵖ ⥤ D) ⟨I.Y, _, _, I.hf, Sieve.downward_closed _ II.hf _, rfl⟩⟩ let IB : S.Arrow := IA.fromMiddle let IC : (T IB).Arrow := IA.toMiddle - let ID : (T I).Arrow := ⟨IV.Y, IV.f ≫ II.f, Sieve.downward_closed (T I).sieve II.hf IV.f⟩ + let ID : (T I).Arrow := ⟨IV.Y, IV.f ≫ II.f, Sieve.downward_closed (T I).1 II.hf IV.f⟩ change t IB IC = t I ID apply inj IV.Y erw [toPlus_apply (T I) (t I) ID, toPlus_apply (T IB) (t IB) IC, ← ht, ← ht] @@ -589,12 +591,4 @@ instance presheaf_mono_of_mono {F G : Sheaf J D} (f : F ⟶ G) [Mono f] : Mono f theorem Sheaf.Hom.mono_iff_presheaf_mono {F G : Sheaf J D} (f : F ⟶ G) : Mono f ↔ Mono f.1 := ⟨fun m => by infer_instance, fun m => by exact Sheaf.Hom.mono_of_presheaf_mono J D f⟩ --- Porting note: added to ease the port of CategoryTheory.Sites.LeftExact --- in mathlib, this was `by refl`, but here it would timeout -@[simps! hom_app inv_app] -noncomputable -def GrothendieckTopology.sheafificationIsoPresheafToSheafCompSheafToPreasheaf : - J.sheafification D ≅ plusPlusSheaf J D ⋙ sheafToPresheaf J D := - NatIso.ofComponents fun P => Iso.refl _ - end CategoryTheory diff --git a/Mathlib/CategoryTheory/Sites/ConstantSheaf.lean b/Mathlib/CategoryTheory/Sites/ConstantSheaf.lean index 1fa5ab155f92b..46db78d658c1f 100644 --- a/Mathlib/CategoryTheory/Sites/ConstantSheaf.lean +++ b/Mathlib/CategoryTheory/Sites/ConstantSheaf.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Dagur Asgeirsson -/ import Mathlib.CategoryTheory.Sites.Sheafification - +import Mathlib.CategoryTheory.Sites.DenseSubsite /-! # The constant sheaf @@ -12,55 +12,224 @@ import Mathlib.CategoryTheory.Sites.Sheafification We define the constant sheaf functor (the sheafification of the constant presheaf) `constantSheaf : D ⥤ Sheaf J D` and prove that it is left adjoint to evaluation at a terminal object (see `constantSheafAdj`). + +We also define a predicate on sheaves, `Sheaf.IsConstant`, saying that a sheaf is in the +essential image of the constant sheaf functor. + +## Main results + +* `Sheaf.isConstant_iff_isIso_counit_app`: Provided that the constant sheaf functor is fully +faithful, a sheaf is constant if and only if the counit of the constant sheaf adjunction applied to +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 +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 -open Limits Opposite Category Functor Sheaf +open Limits Opposite Category Functor Sheaf Adjunction variable {C : Type*} [Category C] (J : GrothendieckTopology C) 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] /-- -The functor which maps an object of `D` to the constant sheaf at that object, i.e. the +The functor which maps an object of `D` to the constant sheaf at that object, i.e. the sheafification of the constant presheaf. -/ noncomputable def constantSheaf : D ⥤ Sheaf J D := Functor.const Cᵒᵖ ⋙ (presheafToSheaf J D) /-- The constant sheaf functor is left adjoint to evaluation at a terminal object. -/ +@[simps! counit_app] noncomputable def constantSheafAdj {T : C} (hT : IsTerminal T) : constantSheaf J D ⊣ (sheafSections J D).obj (op T) := (constantPresheafAdj D hT).comp (sheafificationAdjunction J D) -lemma constantSheafAdj_counit_app {T : C} (hT : IsTerminal T) (F : Sheaf J D) : - (constantSheafAdj J D hT).counit.app F = - (presheafToSheaf J D).map ((constantPresheafAdj D hT).counit.app F.val) ≫ - (sheafificationAdjunction J D).counit.app F := by +variable {D} + +namespace Sheaf + +/-- +A sheaf is constant if it is in the essential image of the constant sheaf functor. +-/ +class IsConstant (F : Sheaf J D) : Prop where + mem_essImage : F ∈ (constantSheaf J D).essImage + +lemma mem_essImage_of_isConstant (F : Sheaf J D) [IsConstant J F] : + F ∈ (constantSheaf J D).essImage := + IsConstant.mem_essImage + +lemma isConstant_congr {F G : Sheaf J D} (i : F ≅ G) [IsConstant J F] : IsConstant J G where + mem_essImage := essImage.ofIso i F.mem_essImage_of_isConstant + +lemma isConstant_of_iso {F : Sheaf J D} {X : D} (i : F ≅ (constantSheaf J D).obj X) : + IsConstant J F := ⟨_, ⟨i.symm⟩⟩ + +lemma isConstant_iff_mem_essImage {L : D ⥤ Sheaf J D} {T : C} (hT : IsTerminal T) + (adj : L ⊣ (sheafSections J D).obj ⟨T⟩) + (F : Sheaf J D) : IsConstant J F ↔ F ∈ L.essImage := by + rw [essImage_eq_of_natIso (adj.leftAdjointUniq (constantSheafAdj J D hT))] + exact ⟨fun ⟨h⟩ ↦ h, fun h ↦ ⟨h⟩⟩ + +lemma isConstant_of_isIso_counit_app (F : Sheaf J D) [HasTerminal C] + [IsIso <| (constantSheafAdj J D terminalIsTerminal).counit.app F] : IsConstant J F where + mem_essImage := ⟨_, ⟨asIso <| (constantSheafAdj J D terminalIsTerminal).counit.app F⟩⟩ + +instance [(constantSheaf J D).Faithful] [(constantSheaf J D).Full] (F : Sheaf J D) + [IsConstant J F] {T : C} (hT : IsTerminal T) : + IsIso ((constantSheafAdj J D hT).counit.app F) := by + rw [isIso_counit_app_iff_mem_essImage] + exact F.mem_essImage_of_isConstant + +/-- +If the constant sheaf functor is fully faithful, then a sheaf is constant if and only if the +counit of the constant sheaf adjunction applied to it is an isomorphism. +-/ +lemma isConstant_iff_isIso_counit_app [(constantSheaf J D).Faithful] [(constantSheaf J D).Full] + (F : Sheaf J D) {T : C} (hT : IsTerminal T) : + IsConstant J F ↔ (IsIso <| (constantSheafAdj J D hT).counit.app F) := + ⟨fun _ ↦ inferInstance, fun _ ↦ ⟨_, ⟨asIso <| (constantSheafAdj J D hT).counit.app F⟩⟩⟩ + +/-- +A variant of `isConstant_iff_isIso_counit_app` for a general left adjoint to evaluation at a +terminal object. +-/ +lemma isConstant_iff_isIso_counit_app' {L : D ⥤ Sheaf J D} {T : C} (hT : IsTerminal T) + (adj : L ⊣ (sheafSections J D).obj ⟨T⟩) + [L.Faithful] [L.Full] (F : Sheaf J D) : IsConstant J F ↔ IsIso (adj.counit.app F) := + (isConstant_iff_mem_essImage J hT adj F).trans (isIso_counit_app_iff_mem_essImage adj).symm + +end Sheaf + +section Equivalence +variable {C' : Type*} [Category C'] (K : GrothendieckTopology C') [HasWeakSheafify K D] +variable (G : C ⥤ C') [∀ (X : (C')ᵒᵖ), HasLimitsOfShape (StructuredArrow X G.op) D] + [G.IsDenseSubsite J K] {T : C} (hT : IsTerminal T) (hT' : IsTerminal (G.obj T)) + +open IsDenseSubsite + +variable (D) in +/-- +The constant sheaf functor commutes up to isomorphism the equivalence of sheaf categories induced +by a dense subsite. +-/ +noncomputable def equivCommuteConstant : + constantSheaf J D ⋙ (sheafEquiv G J K D).functor ≅ constantSheaf K D := + ((constantSheafAdj J D hT).comp (sheafEquiv G J K D).toAdjunction).leftAdjointUniq + (constantSheafAdj K D hT') + +variable (D) in +/-- +The constant sheaf functor commutes up to isomorphism the inverse equivalence of sheaf categories +induced by a dense subsite. +-/ +noncomputable def equivCommuteConstant' : + constantSheaf J D ≅ constantSheaf K D ⋙ (sheafEquiv G J K D).inverse := + isoWhiskerLeft (constantSheaf J D) (sheafEquiv G J K D).unitIso ≪≫ + isoWhiskerRight (equivCommuteConstant J D K G hT hT') (sheafEquiv G J K D).inverse + +/- TODO: find suitable assumptions for proving generalizations of `equivCommuteConstant` and +`equivCommuteConstant'` above, to commute `constantSheaf` with pullback/pushforward of sheaves. -/ + +include hT hT' in +/-- +The property of a sheaf of being constant is invariant under equivalence of sheaf +categories. +-/ +lemma Sheaf.isConstant_iff_of_equivalence (F : Sheaf K D) : + ((sheafEquiv G J K D).inverse.obj F).IsConstant J ↔ IsConstant K F := by + constructor + · exact fun ⟨Y, ⟨i⟩⟩ ↦ ⟨_, ⟨(equivCommuteConstant J D K G hT hT').symm.app _ ≪≫ + (sheafEquiv G J K D).functor.mapIso i ≪≫ (sheafEquiv G J K D).counitIso.app _⟩⟩ + · exact fun ⟨Y, ⟨i⟩⟩ ↦ ⟨_, ⟨(equivCommuteConstant' J D K G hT hT').app _ ≪≫ + (sheafEquiv G J K D).inverse.mapIso i⟩⟩ + +end Equivalence + +section Forget + +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` +preserves sheafification. +-/ +noncomputable def constantCommuteCompose : + constantSheaf J D ⋙ sheafCompose J U ≅ U ⋙ constantSheaf J B := + (isoWhiskerLeft (const Cᵒᵖ) + (sheafComposeNatIso J U (sheafificationAdjunction J D) (sheafificationAdjunction J B)).symm) ≪≫ + isoWhiskerRight (compConstIso _ _).symm _ + +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`. -/ +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)) = + ((sheafCompose J U).map ((constantSheafAdj J D hT).counit.app F)) := by apply Sheaf.hom_ext - apply sheafify_hom_ext _ _ _ F.cond - simp only [flip_obj_obj, sheafToPresheaf_obj, comp_obj, id_obj, constantSheafAdj, Adjunction.comp, - evaluation_obj_obj, constantPresheafAdj, Opposite.op_unop, Adjunction.mkOfUnitCounit_unit, - Adjunction.mkOfUnitCounit_counit, NatTrans.comp_app, associator_hom_app, whiskerLeft_app, - whiskerRight_app, instCategorySheaf_comp_val, instCategorySheaf_id_val, - sheafificationAdjunction_counit_app_val, sheafifyMap_sheafifyLift, comp_id, - toSheafify_sheafifyLift] - erw [id_comp, toSheafify_sheafifyLift] + rw [instCategorySheaf_comp_val, constantCommuteCompose_hom_app_val, assoc, Iso.inv_comp_eq] + apply sheafify_hom_ext _ _ _ ((sheafCompose J U).obj F).cond + ext + simp? says simp only [comp_obj, const_obj_obj, sheafCompose_obj_val, id_obj, + constantSheafAdj_counit_app, instCategorySheaf_comp_val, + sheafificationAdjunction_counit_app_val, sheafifyMap_sheafifyLift, comp_id, + toSheafify_sheafifyLift, NatTrans.comp_app, constComp_hom_app, + constantPresheafAdj_counit_app_app, Functor.comp_map, id_comp, flip_obj_obj, + sheafToPresheaf_obj, map_comp, sheafCompose_map_val, sheafComposeIso_hom_fac_assoc, + whiskerRight_app] + simp [← map_comp, ← NatTrans.comp_app] + +lemma Sheaf.isConstant_of_forget [constantSheaf J D |>.Faithful] [constantSheaf J D |>.Full] + [constantSheaf J B |>.Faithful] [constantSheaf J B |>.Full] + [(sheafCompose J U).ReflectsIsomorphisms] [((sheafCompose J U).obj F).IsConstant J] + {T : C} (hT : IsTerminal T) : F.IsConstant J := by + have : IsIso ((sheafCompose J U).map ((constantSheafAdj J D hT).counit.app F)) := by + rw [← constantSheafAdj_counit_w] + infer_instance + rw [F.isConstant_iff_isIso_counit_app (hT := hT)] + exact isIso_of_reflects_iso _ (sheafCompose J U) + +instance [h : F.IsConstant J] : ((sheafCompose J U).obj F).IsConstant J := by + obtain ⟨Y, ⟨i⟩⟩ := h + exact ⟨U.obj Y, ⟨(fullyFaithfulSheafToPresheaf _ _).preimageIso + (((sheafifyComposeIso J U ((const Cᵒᵖ).obj Y)).symm ≪≫ + (presheafToSheaf J B ⋙ sheafToPresheaf J B).mapIso (constComp Cᵒᵖ Y U)).symm ≪≫ + (sheafToPresheaf _ _).mapIso ((sheafCompose J U).mapIso i))⟩⟩ + +lemma Sheaf.isConstant_iff_forget [constantSheaf J D |>.Faithful] [constantSheaf J D |>.Full] + [constantSheaf J B |>.Faithful] [constantSheaf J B |>.Full] + [(sheafCompose J U).ReflectsIsomorphisms] {T : C} (hT : IsTerminal T) : + F.IsConstant J ↔ ((sheafCompose J U).obj F).IsConstant J := + ⟨fun _ ↦ inferInstance, fun _ ↦ Sheaf.isConstant_of_forget _ U F hT⟩ + +end Forget end CategoryTheory diff --git a/Mathlib/CategoryTheory/Sites/CoverLifting.lean b/Mathlib/CategoryTheory/Sites/CoverLifting.lean index fc2152f710887..14f0ea6ecb8c6 100644 --- a/Mathlib/CategoryTheory/Sites/CoverLifting.lean +++ b/Mathlib/CategoryTheory/Sites/CoverLifting.lean @@ -133,9 +133,8 @@ lemma liftAux_map {Y : C} (f : G.obj Y ⟶ X) {W : C} (g : W ⟶ Y) (i : S.Arrow liftAux hF α s f ≫ F.map g.op = s.ι i ≫ R.map h.op ≫ α.app _ := (Multifork.IsLimit.fac (hF.isLimitMultifork ⟨_, G.cover_lift J K (K.pullback_stable f S.2)⟩) _ _ - ⟨W, g, by simpa only [GrothendieckTopology.Cover.sieve, - Sieve.functorPullback_apply, functorPullback_mem, Sieve.pullback_apply, ← w] - using S.1.downward_closed i.hf h⟩).trans (by + ⟨W, g, by simpa only [Sieve.functorPullback_apply, functorPullback_mem, + Sieve.pullback_apply, ← w] using S.1.downward_closed i.hf h⟩).trans (by dsimp simp only [← Category.assoc] congr 1 diff --git a/Mathlib/CategoryTheory/Sites/Coverage.lean b/Mathlib/CategoryTheory/Sites/Coverage.lean index 8077b8d450f7f..648975e7b07ec 100644 --- a/Mathlib/CategoryTheory/Sites/Coverage.lean +++ b/Mathlib/CategoryTheory/Sites/Coverage.lean @@ -309,7 +309,7 @@ Any sieve that contains a covering presieve for a coverage is a covering sieve f Grothendieck topology. -/ theorem mem_toGrothendieck_sieves_of_superset (K : Coverage C) {X : C} {S : Sieve X} - {R : Presieve X} (h : R ≤ S) (hR : R ∈ K.covering X) : S ∈ (K.toGrothendieck C).sieves X := + {R : Presieve X} (h : R ≤ S) (hR : R ∈ K.covering X) : S ∈ (K.toGrothendieck C) X := K.saturate_of_superset ((Sieve.generate_le_iff _ _).mpr h) (Coverage.Saturate.of X _ hR) end Coverage diff --git a/Mathlib/CategoryTheory/Sites/DenseSubsite.lean b/Mathlib/CategoryTheory/Sites/DenseSubsite.lean index dba0ba9fb3362..21ae0858e76d2 100644 --- a/Mathlib/CategoryTheory/Sites/DenseSubsite.lean +++ b/Mathlib/CategoryTheory/Sites/DenseSubsite.lean @@ -173,16 +173,10 @@ theorem naturality [G.IsLocallyFull K] {X Y : C} (i : G.obj X ⟶ G.obj Y) : /-- (Implementation). Given a section of `ℱ` on `X`, we can obtain a family of elements valued in `ℱ'` that is defined on a cover generated by the images of `G`. -/ --- Porting note: removed `@[simp, nolint unused_arguments]` noncomputable def pushforwardFamily {X} (x : ℱ.obj (op X)) : FamilyOfElements ℱ'.val (coverByImage G X) := fun _ _ hf => ℱ'.val.map hf.some.lift.op <| α.app (op _) (ℱ.map hf.some.map.op x : _) --- Porting note: there are various `include` and `omit`s in this file (e.g. one is removed here), --- none of which are needed in Lean 4. - --- Porting note: `pushforward_family` was tagged `@[simp]` in Lean 3 so we add the --- equation lemma @[simp] theorem pushforwardFamily_def {X} (x : ℱ.obj (op X)) : pushforwardFamily α x = fun _ _ hf => ℱ'.val.map hf.some.lift.op <| α.app (op _) (ℱ.map hf.some.map.op x : _) := rfl @@ -266,7 +260,6 @@ noncomputable def presheafHom (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) : ℱ apply Functor.IsCoverDense.ext G intro Y' f' simp only [appHom_restrict, types_comp_apply, ← FunctorToTypes.map_comp_apply] - -- Porting note: Lean 3 proof continued with a rewrite but we're done here /-- Given a natural isomorphism `G ⋙ ℱ ≅ G ⋙ ℱ'` between presheaves of types, @@ -360,17 +353,12 @@ noncomputable def presheafIso {ℱ ℱ' : Sheaf K A} (i : G.op ⋙ ℱ.val ≅ G ℱ.val ≅ ℱ'.val := by have : ∀ X : Dᵒᵖ, IsIso ((sheafHom i.hom).app X) := by intro X - -- Porting note: somehow `apply` in Lean 3 is leaving a typeclass goal, - -- perhaps due to elaboration order. The corresponding `apply` in Lean 4 fails - -- because the instance can't yet be synthesized. I hence reorder the proof. - suffices IsIso (yoneda.map ((sheafHom i.hom).app X)) by - apply isIso_of_reflects_iso _ yoneda + rw [← isIso_iff_of_reflects_iso _ yoneda] use (sheafYonedaHom i.inv).app X constructor <;> ext x : 2 <;> simp only [sheafHom, NatTrans.comp_app, NatTrans.id_app, Functor.map_preimage] · exact ((Types.presheafIso (isoOver i (unop x))).app X).hom_inv_id · exact ((Types.presheafIso (isoOver i (unop x))).app X).inv_hom_id - -- Porting note: Lean 4 proof is finished, Lean 3 needed `inferInstance` haveI : IsIso (sheafHom i.hom) := by apply NatIso.isIso_of_isIso_app apply asIso (sheafHom i.hom) @@ -396,8 +384,7 @@ theorem sheafHom_restrict_eq (α : G.op ⋙ ℱ ⟶ G.op ⋙ ℱ'.val) : ext X apply yoneda.map_injective ext U - -- Porting note: didn't need to provide the input to `map_preimage` in Lean 3 - erw [yoneda.map_preimage ((sheafYonedaHom α).app (G.op.obj X))] + erw [yoneda.map_preimage] symm change (show (ℱ'.val ⋙ coyoneda.obj (op (unop U))).obj (op (G.obj (unop X))) from _) = _ apply sheaf_eq_amalgamation ℱ' (G.is_cover_of_isCoverDense _ _) @@ -423,10 +410,8 @@ then the result `sheaf_hom (whisker_left G.op α)` is equal to `α`. theorem sheafHom_eq (α : ℱ ⟶ ℱ'.val) : sheafHom (whiskerLeft G.op α) = α := by ext X apply yoneda.map_injective - -- Porting note: deleted next line as it's not needed in Lean 4 ext U - -- Porting note: Lean 3 didn't need to be told the explicit input to map_preimage - erw [yoneda.map_preimage ((sheafYonedaHom (whiskerLeft G.op α)).app X)] + erw [yoneda.map_preimage] symm change (show (ℱ'.val ⋙ coyoneda.obj (op (unop U))).obj (op (unop X)) from _) = _ apply sheaf_eq_amalgamation ℱ' (G.is_cover_of_isCoverDense _ _) @@ -588,10 +573,8 @@ lemma isIso_ranCounit_app_of_isDenseSubsite (Y : Sheaf J A) (U X) : apply (isPointwiseRightKanExtensionRanCounit G.op Y.1 (.op (G.obj U))).hom_ext rintro ⟨⟨⟨⟩⟩, ⟨W⟩, g⟩ obtain ⟨g, rfl⟩ : ∃ g' : G.obj W ⟶ G.obj U, g = g'.op := ⟨g.unop, rfl⟩ - simp only [id_obj, comp_obj, StructuredArrow.proj_obj, RightExtension.coneAt_pt, - RightExtension.mk_left, RightExtension.coneAt_π_app, const_obj_obj, op_obj, - whiskeringLeft_obj_obj, RightExtension.mk_hom] apply (Y.2 X _ (IsDenseSubsite.imageSieve_mem J K G g)).isSeparatedFor.ext + dsimp rintro V iVW ⟨iVU, e'⟩ have := congr($e ≫ Y.1.map iVU.op) simp only [comp_obj, yoneda_map_app, Category.assoc, coyoneda_obj_obj, comp_map, @@ -611,11 +594,16 @@ lemma isIso_ranCounit_app_of_isDenseSubsite (Y : Sheaf J A) (U X) : · simp only [const_obj_obj, op_obj, map_comp, hl] simp only [← map_comp_assoc, r.w] · simp [← map_comp, ← op_comp, hiUV] - · rintro ⟨⟨⟨⟩⟩, ⟨W₁⟩, g₁⟩ ⟨⟨⟨⟩⟩, ⟨W₂⟩, g₂⟩ ⟨⟨⟨⟨⟩⟩⟩, i, hi⟩ + · dsimp + rintro ⟨⟨⟨⟩⟩, ⟨W₁⟩, g₁⟩ ⟨⟨⟨⟩⟩, ⟨W₂⟩, g₂⟩ ⟨⟨⟨⟨⟩⟩⟩, i, hi⟩ dsimp at g₁ g₂ i hi - obtain rfl : g₂ = g₁ ≫ (G.map i.unop).op := by simpa only [Category.id_comp] using hi - obtain ⟨g, rfl⟩ : ∃ g' : G.obj W₁ ⟶ G.obj U, g₁ = g'.op := ⟨g₁.unop, rfl⟩ - obtain ⟨i, rfl⟩ : ∃ i' : W₂ ⟶ W₁, i = i'.op := ⟨i.unop, rfl⟩ + -- See issue #15781 for tracking performance regressions of `rintro` as here + have h : g₂ = g₁ ≫ (G.map i.unop).op := by simpa only [Category.id_comp] using hi + rcases h with ⟨rfl⟩ + have h : ∃ g' : G.obj W₁ ⟶ G.obj U, g₁ = g'.op := ⟨g₁.unop, rfl⟩ + rcases h with ⟨g, rfl⟩ + have h : ∃ i' : W₂ ⟶ W₁, i = i'.op := ⟨i.unop, rfl⟩ + rcases h with ⟨i, rfl⟩ simp only [const_obj_obj, id_obj, comp_obj, StructuredArrow.proj_obj, const_obj_map, op_obj, unop_comp, Quiver.Hom.unop_op, Category.id_comp, comp_map, StructuredArrow.proj_map] apply Y.2.hom_ext ⟨_, IsDenseSubsite.imageSieve_mem J K G (G.map i ≫ g)⟩ diff --git a/Mathlib/CategoryTheory/Sites/Discrete.lean b/Mathlib/CategoryTheory/Sites/Discrete.lean deleted file mode 100644 index 6998b9657e496..0000000000000 --- a/Mathlib/CategoryTheory/Sites/Discrete.lean +++ /dev/null @@ -1,283 +0,0 @@ -/- -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.FullyFaithful -import Mathlib.CategoryTheory.Sites.ConstantSheaf -import Mathlib.CategoryTheory.Sites.DenseSubsite -import Mathlib.CategoryTheory.Sites.PreservesSheafification -/-! - -# Discrete objects in sheaf categories. - -This file defines the notion of a discrete object in a sheaf category. A discrete sheaf in this -context is a sheaf `F` such that the counit `(F(*))^cst ⟶ F` is an isomorphism. Here `*` denotes -a particular chosen terminal object of the defining site, and `cst` denotes the constant sheaf. - -It is convenient to take an arbitrary terminal object; one might want to use this construction to -talk about discrete sheaves on a site which has a particularly convenient terminal object, such as -the one element space in `CompHaus`. - -## Main results - -* `isDiscrete_iff_mem_essImage` : A sheaf is discrete if and only if it is in the essential image -of the constant sheaf functor. -* `isDiscrete_iff_of_equivalence` : The property of a sheaf of being discrete is invariant under -equivalence of sheaf categories. -* `isDiscrete_iff_forget` : Given a "forgetful" functor `U : A ⥤ B` a sheaf `F : Sheaf J A` is -discrete if and only if the sheaf given by postcomposition with `U` is discrete. - -## Future work - -* Use `isDiscrete_iff_forget` to prove that a condensed module is discrete if and only if its -underlying condensed set is discrete. --/ - -open CategoryTheory Limits Functor Adjunction Opposite Category Functor - -namespace CategoryTheory.Sheaf - -variable {C : Type*} [Category C] (J : GrothendieckTopology C) {A : Type*} [Category A] - [HasWeakSheafify J A] {t : C} (ht : IsTerminal t) - -section -variable [(constantSheaf J A).Faithful] [(constantSheaf J A).Full] - -/-- -A sheaf is discrete if it is a discrete object of the "underlying object" functor from the sheaf -category to the target category. --/ -abbrev IsDiscrete (F : Sheaf J A) : Prop := IsIso ((constantSheafAdj J A ht).counit.app F) - -lemma isDiscrete_of_iso {F : Sheaf J A} {X : A} - (i : F ≅ (constantSheaf J A).obj X) : IsDiscrete J ht F := - isIso_counit_app_of_iso _ i - -lemma isDiscrete_iff_mem_essImage (F : Sheaf J A) : - F.IsDiscrete J ht ↔ F ∈ (constantSheaf J A).essImage := - (constantSheafAdj J A ht).isIso_counit_app_iff_mem_essImage - -lemma isDiscrete_iff_mem_essImage' {L : A ⥤ Sheaf J A} (adj : L ⊣ (sheafSections J A).obj ⟨t⟩) - (F : Sheaf J A) : - IsDiscrete J ht F ↔ F ∈ L.essImage := by - let e : L ≅ constantSheaf J A := adj.leftAdjointUniq (constantSheafAdj _ _ ht) - refine ⟨fun h ↦ ⟨F.val.obj ⟨t⟩, ⟨?_⟩⟩, fun ⟨Y, ⟨i⟩⟩ ↦ ?_⟩ - · exact e.app _ ≪≫ asIso ((constantSheafAdj _ _ ht).counit.app _) - · rw [isDiscrete_iff_mem_essImage] - exact ⟨Y, ⟨e.symm.app _ ≪≫ i⟩⟩ - -lemma isDiscrete_iff_isIso_counit_app {L : A ⥤ Sheaf J A} (adj : L ⊣ (sheafSections J A).obj ⟨t⟩) - (F : Sheaf J A) : - IsDiscrete J ht F ↔ IsIso (adj.counit.app F) := by - have : L.Faithful := Functor.Faithful.of_iso (adj.leftAdjointUniq (constantSheafAdj _ _ ht)).symm - have : L.Full := Functor.Full.of_iso (adj.leftAdjointUniq (constantSheafAdj _ _ ht)).symm - rw [isIso_counit_app_iff_mem_essImage] - exact isDiscrete_iff_mem_essImage' _ _ adj _ - -section Equivalence - -variable {D : Type*} [Category D] (K : GrothendieckTopology D) [HasWeakSheafify K A] -variable (G : C ⥤ D) - [∀ (X : Dᵒᵖ), HasLimitsOfShape (StructuredArrow X G.op) A] - [G.IsDenseSubsite J K] (ht' : IsTerminal (G.obj t)) - -open Functor.IsDenseSubsite - -noncomputable example : - let e : Sheaf J A ≌ Sheaf K A := - sheafEquiv G J K A - e.inverse ⋙ (sheafSections J A).obj (op t) ≅ (sheafSections K A).obj (op (G.obj t)) := - Iso.refl _ - -variable (A) in -/-- -The constant sheaf functor commutes up to isomorphism with any equivalence of sheaf categories. - -This is an auxiliary definition used to prove `Sheaf.isDiscrete_iff_of_equivalence` below, which -says that the property of a sheaf of being a discrete object is invariant under equivalence of -sheaf categories. --/ -noncomputable def equivCommuteConstant : - let e : Sheaf J A ≌ Sheaf K A := - sheafEquiv G J K A - constantSheaf J A ⋙ e.functor ≅ constantSheaf K A := - let e : Sheaf J A ≌ Sheaf K A := - sheafEquiv G J K A - (Adjunction.leftAdjointUniq ((constantSheafAdj J A ht).comp e.toAdjunction) - (constantSheafAdj K A ht')) - -variable (A) in -/-- -The constant sheaf functor commutes up to isomorphism with any equivalence of sheaf categories. - -This is an auxiliary definition used to prove `Sheaf.isDiscrete_iff_of_equivalence` below, which -says that the property of a sheaf of being a discrete object is invariant under equivalence of -sheaf categories. --/ -noncomputable def equivCommuteConstant' : - let e : Sheaf J A ≌ Sheaf K A := - sheafEquiv G J K A - constantSheaf J A ≅ constantSheaf K A ⋙ e.inverse := - let e : Sheaf J A ≌ Sheaf K A := - sheafEquiv G J K A - isoWhiskerLeft (constantSheaf J A) e.unitIso ≪≫ - isoWhiskerRight (equivCommuteConstant J A ht K G ht') e.inverse - -/-- -The property of a sheaf of being a discrete object is invariant under equivalence of sheaf -categories. --/ -lemma isDiscrete_iff_of_equivalence (F : Sheaf K A) : - let e : Sheaf J A ≌ Sheaf K A := - sheafEquiv G J K A - haveI : (constantSheaf K A).Faithful := - Functor.Faithful.of_iso (equivCommuteConstant J A ht K G ht') - haveI : (constantSheaf K A).Full := - Functor.Full.of_iso (equivCommuteConstant J A ht K G ht') - (e.inverse.obj F).IsDiscrete J ht ↔ IsDiscrete K ht' F := by - intro e - have : (constantSheaf K A).Faithful := - Functor.Faithful.of_iso (equivCommuteConstant J A ht K G ht') - have : (constantSheaf K A).Full := - Functor.Full.of_iso (equivCommuteConstant J A ht K G ht') - simp only [isDiscrete_iff_mem_essImage] - constructor - · intro ⟨Y, ⟨i⟩⟩ - let j : (constantSheaf K A).obj Y ≅ F := - (equivCommuteConstant J A ht K G ht').symm.app _ ≪≫ e.functor.mapIso i ≪≫ e.counitIso.app _ - exact ⟨_, ⟨j⟩⟩ - · intro ⟨Y, ⟨i⟩⟩ - let j : (constantSheaf J A).obj Y ≅ e.inverse.obj F := - (equivCommuteConstant' J A ht K G ht').app _ ≪≫ e.inverse.mapIso i - exact ⟨_, ⟨j⟩⟩ - -end Equivalence - -end - -section Forget - -variable {B : Type*} [Category B] (U : A ⥤ B) [HasWeakSheafify J B] - [J.PreservesSheafification U] [J.HasSheafCompose U] (F : Sheaf J A) - -open Limits - -/-- The constant sheaf functor commutes with `sheafCompose` up to isomorphism. -/ -@[simps!] -noncomputable def constantCommuteCompose : - constantSheaf J A ⋙ sheafCompose J U ≅ U ⋙ constantSheaf J B := - (isoWhiskerLeft (const Cᵒᵖ) - (sheafComposeNatIso J U (sheafificationAdjunction J A) (sheafificationAdjunction J B)).symm) ≪≫ - isoWhiskerRight (compConstIso _ _).symm _ - -lemma sheafComposeNatIso_app_counit (P : Sheaf J A) : - (sheafComposeNatIso J U (sheafificationAdjunction J A) - (sheafificationAdjunction J B)).hom.app _ ≫ (sheafCompose J U).map - ((sheafificationAdjunction J A).counit.app P) = - (sheafificationAdjunction J B).counit.app ((sheafCompose J U).obj P) := by - simp only [sheafToPresheaf_obj, Functor.comp_obj, whiskeringRight_obj_obj, Functor.id_obj, - sheafComposeNatIso, sheafComposeNatTrans, sheafCompose_obj_val, - sheafificationAdjunction_unit_app, asIso_hom] - erw [Adjunction.homEquiv_counit] - apply Sheaf.hom_ext - apply sheafify_hom_ext _ _ _ ((sheafCompose J U).obj P).cond - simp [← whiskerRight_comp] - -lemma constantCommuteComposeApp_comp_counit (F : Sheaf J A) : - ((constantCommuteCompose J U).app _).hom ≫ - (constantSheafAdj J B ht).counit.app ((sheafCompose J U).obj F) = - (sheafCompose J U).map ((constantSheafAdj J A ht).counit.app F) := by - simp only [← Iso.eq_inv_comp, constantSheafAdj_counit_app, - constantCommuteCompose, flip_obj_obj, sheafToPresheaf_obj, id_obj, NatIso.trans_app, comp_obj, - whiskeringRight_obj_obj, Iso.trans_inv, Iso.app_inv, isoWhiskerRight_inv, Iso.symm_inv, - whiskerRight_app, isoWhiskerLeft_inv, whiskerLeft_app, evaluation_obj_obj, Functor.map_comp, - assoc, sheafCompose_obj_val, ← sheafComposeNatIso_app_counit] - simp only [← assoc] - congr 1 - have : (compConstIso Cᵒᵖ U).hom.app (F.val.obj ⟨t⟩) ≫ - { app := fun Y ↦ (F.val ⋙ U).map (ht.from _).op - naturality := by intros; simp; rw [← Functor.map_comp, ← Functor.map_comp]; congr; simp } = - ((constantPresheafAdj B ht).counit.app (F.val ⋙ U)) := by ext; simp [constantPresheafAdj] - simp only [← this, assoc, Functor.map_comp] - congr 1 - apply Sheaf.hom_ext - apply sheafify_hom_ext _ _ _ ((sheafCompose J U).obj ((presheafToSheaf J A).obj F.val)).cond - simp only [sheafCompose_obj_val, instCategorySheaf_comp_val, sheafCompose_map_val, comp_obj, - whiskeringRight_obj_obj, Functor.comp_map] - erw [← toSheafify_naturality_assoc, sheafComposeIso_hom_fac, sheafComposeIso_hom_fac_assoc] - ext - simp only [comp_obj, const_obj_obj, NatTrans.comp_app, whiskerRight_app, ← Functor.map_comp] - congr 1 - simp only [constantPresheafAdj, comp_obj, evaluation_obj_obj, id_obj, Opposite.op_unop, - Adjunction.mkOfUnitCounit_counit, NatTrans.naturality] - erw [← NatTrans.comp_app, ← toSheafify_naturality] - simp only [NatTrans.comp_app, const_obj_obj, NatTrans.naturality] - -/-- Auxiliary lemma for `sheafCompose_reflects_discrete`. -/ -private lemma sheafifyComposeIso_comp_sheafCompose_map_constantSheafAdj_counit : - (sheafifyComposeIso J U ((const Cᵒᵖ).obj (F.val.obj { unop := t }))).hom ≫ - ((sheafCompose J U).map ((constantSheafAdj J A ht).counit.app F)).val = - ((presheafToSheaf J B ⋙ sheafToPresheaf J B).mapIso (constComp Cᵒᵖ _ U)).hom ≫ - ((constantSheafAdj J B ht).counit.app ((sheafCompose J U).obj F)).val := by - apply sheafify_hom_ext _ _ _ ((sheafCompose J U).obj F).cond - simp only [sheafCompose_obj_val, id_obj, comp_obj, flip_obj_obj, sheafToPresheaf_obj, - sheafComposeIso_hom_fac_assoc, mapIso_hom, Functor.comp_map, sheafToPresheaf_map] - erw [Adjunction.unit_naturality_assoc] - simp only [const_obj_obj, const_obj_map, id_obj, constComp, comp_obj, sheafToPresheaf_obj, - sheafificationAdjunction_unit_app] - ext - simp only [comp_obj, const_obj_obj, NatTrans.comp_app, whiskerRight_app, Category.id_comp, - comp_obj, flip_obj_obj, sheafToPresheaf_obj, id_obj, constantSheafAdj, - Adjunction.comp, evaluation_obj_obj, NatTrans.comp_app, associator_hom_app, whiskerLeft_app, - whiskerRight_app, map_comp, instCategorySheaf_comp_val, sheafCompose_obj_val, - sheafCompose_map_val, instCategorySheaf_id_val, sheafificationAdjunction_counit_app_val, - NatTrans.id_app, sheafifyMap_sheafifyLift, Category.comp_id, Category.id_comp] - erw [Functor.map_id, Category.id_comp, ← NatTrans.comp_app] - simp only [toSheafify_sheafifyLift, ← Functor.map_comp, ← NatTrans.comp_app, - sheafifyMap_sheafifyLift, Category.comp_id, - constantPresheafAdj, comp_obj, evaluation_obj_obj, id_obj, op_unop, - mkOfUnitCounit_counit, Functor.comp_map] - -/-- Auxiliary lemma for `sheafCompose_reflects_discrete`. -/ -private lemma constantSheafAdj_counit_w : - ((sheafifyComposeIso J U ((const Cᵒᵖ).obj (F.val.obj ⟨t⟩))).symm ≪≫ - (presheafToSheaf J B ⋙ sheafToPresheaf J B).mapIso (constComp Cᵒᵖ (F.val.obj ⟨t⟩) U)).hom ≫ - ((constantSheafAdj J B ht).counit.app ((sheafCompose J U).obj F)).val = - ((sheafCompose J U).map ((constantSheafAdj J A ht).counit.app F)).val := by - rw [← Iso.eq_inv_comp] - simp only [comp_obj, flip_obj_obj, sheafToPresheaf_obj, sheafCompose_obj_val, id_obj, - Iso.trans_inv, mapIso_inv, Functor.comp_map, sheafToPresheaf_map, - Iso.symm_inv, Category.assoc, sheafifyComposeIso_comp_sheafCompose_map_constantSheafAdj_counit, - mapIso_hom, ← instCategorySheaf_comp_val, Iso.map_inv_hom_id_assoc] - -lemma sheafCompose_reflects_discrete [(sheafCompose J U).ReflectsIsomorphisms] - [((sheafCompose J U).obj F).IsDiscrete J ht] : - F.IsDiscrete J ht := by - let f := (sheafCompose J U).map ((constantSheafAdj J A ht).counit.app F) - have : IsIso ((sheafToPresheaf J B).map f) := by - simp only [comp_obj, flip_obj_obj, sheafToPresheaf_obj, sheafCompose_obj_val, id_obj, - sheafToPresheaf_map, f, ← constantSheafAdj_counit_w] - exact inferInstanceAs (IsIso (_ ≫ ((sheafToPresheaf J B).map - ((constantSheafAdj J B ht).counit.app ((sheafCompose J U).obj F))))) - have := isIso_of_reflects_iso f (sheafToPresheaf J B) - exact isIso_of_reflects_iso _ (sheafCompose J U) - -variable [(constantSheaf J A).Full] [(constantSheaf J A).Faithful] - [(constantSheaf J B).Full] [(constantSheaf J B).Faithful] - -instance [h : F.IsDiscrete J ht] : ((sheafCompose J U).obj F).IsDiscrete J ht := by - rw [isDiscrete_iff_mem_essImage] at h ⊢ - obtain ⟨Y, ⟨i⟩⟩ := h - exact ⟨U.obj Y, ⟨(fullyFaithfulSheafToPresheaf _ _).preimageIso - (((sheafifyComposeIso J U ((const Cᵒᵖ).obj Y)).symm ≪≫ - (presheafToSheaf J B ⋙ sheafToPresheaf J B).mapIso (constComp Cᵒᵖ Y U)).symm ≪≫ - (sheafToPresheaf _ _).mapIso ((sheafCompose J U).mapIso i))⟩⟩ - -lemma isDiscrete_iff_forget [(sheafCompose J U).ReflectsIsomorphisms] : F.IsDiscrete J ht ↔ - ((sheafCompose J U).obj F).IsDiscrete J ht := - ⟨fun _ ↦ inferInstance, fun _ ↦ sheafCompose_reflects_discrete _ _ U F⟩ - -end Forget - -end CategoryTheory.Sheaf diff --git a/Mathlib/CategoryTheory/Sites/EqualizerSheafCondition.lean b/Mathlib/CategoryTheory/Sites/EqualizerSheafCondition.lean index 1466ccb25979a..44e39a7bba0c9 100644 --- a/Mathlib/CategoryTheory/Sites/EqualizerSheafCondition.lean +++ b/Mathlib/CategoryTheory/Sites/EqualizerSheafCondition.lean @@ -10,7 +10,7 @@ import Mathlib.Tactic.ApplyFun /-! # The equalizer diagram sheaf condition for a presieve -In `Mathlib/CategoryTheory/Sites/IsSheafFor.lean` it is defined what it means for a presheaf to be a +In `Mathlib/CategoryTheory/Sites/IsSheafFor.lean` it is defined what it means for a presheaf to be a sheaf *for* a particular presieve. In this file we provide equivalent conditions in terms of equalizer diagrams. @@ -228,8 +228,8 @@ theorem compatible_iff (x : FirstObj P R) : See . -/ theorem sheaf_condition : R.IsSheafFor P ↔ Nonempty (IsLimit (Fork.ofι _ (w P R))) := by - rw [Types.type_equalizer_iff_unique] - erw [← Equiv.forall_congr_right (firstObjEqFamily P R).toEquiv.symm] + rw [Types.type_equalizer_iff_unique, + ← Equiv.forall_congr_right (firstObjEqFamily P R).toEquiv.symm] simp_rw [← compatible_iff, ← Iso.toEquiv_fun, Equiv.apply_symm_apply] apply forall₂_congr intro x _ @@ -252,7 +252,7 @@ open Presieve variable {B : C} {I : Type} (X : I → C) (π : (i : I) → X i ⟶ B) [(Presieve.ofArrows X π).hasPullbacks] --- TODO: allow `I : Type w`  +-- TODO: allow `I : Type w` /-- The middle object of the fork diagram of . diff --git a/Mathlib/CategoryTheory/Sites/Equivalence.lean b/Mathlib/CategoryTheory/Sites/Equivalence.lean index 742f549874445..2408d76270ca3 100644 --- a/Mathlib/CategoryTheory/Sites/Equivalence.lean +++ b/Mathlib/CategoryTheory/Sites/Equivalence.lean @@ -63,7 +63,8 @@ instance (priority := 900) [G.IsEquivalence] : IsCoverDense G J where instance : e.functor.IsDenseSubsite J (e.inverse.inducedTopology J) := by have : J = e.functor.inducedTopology (e.inverse.inducedTopology J) := by ext X S - erw [← GrothendieckTopology.pullback_mem_iff_of_isIso (i := e.unit.app X)] + rw [show S ∈ (e.functor.inducedTopology (e.inverse.inducedTopology J)) X ↔ _ + from (GrothendieckTopology.pullback_mem_iff_of_isIso (i := e.unit.app X)).symm] congr!; ext Y f; simp nth_rw 1 [this] infer_instance @@ -71,7 +72,7 @@ instance : e.functor.IsDenseSubsite J (e.inverse.inducedTopology J) := by lemma eq_inducedTopology_of_isDenseSubsite [e.inverse.IsDenseSubsite K J] : K = e.inverse.inducedTopology J := by ext - simp [e.inverse.functorPushforward_mem_iff K J] + exact (e.inverse.functorPushforward_mem_iff K J).symm variable [e.inverse.IsDenseSubsite K J] diff --git a/Mathlib/CategoryTheory/Sites/Grothendieck.lean b/Mathlib/CategoryTheory/Sites/Grothendieck.lean index faa04b5947877..0d3552925cc54 100644 --- a/Mathlib/CategoryTheory/Sites/Grothendieck.lean +++ b/Mathlib/CategoryTheory/Sites/Grothendieck.lean @@ -86,8 +86,9 @@ structure GrothendieckTopology where namespace GrothendieckTopology -instance : CoeFun (GrothendieckTopology C) fun _ => ∀ X : C, Set (Sieve X) := - ⟨sieves⟩ +instance : DFunLike (GrothendieckTopology C) C (fun X ↦ Set (Sieve X)) where + coe J X := sieves J X + coe_injective' J₁ J₂ h := by cases J₁; cases J₂; congr variable {C} variable {X Y : C} {S R : Sieve X} @@ -98,18 +99,12 @@ We prove this explicitly rather than deriving it so that it is in terms of the c the projection `.sieves`. -/ @[ext] -theorem ext {J₁ J₂ : GrothendieckTopology C} (h : (J₁ : ∀ X : C, Set (Sieve X)) = J₂) : - J₁ = J₂ := by - cases J₁ - cases J₂ - congr +theorem ext {J₁ J₂ : GrothendieckTopology C} (h : (J₁ : ∀ X : C, Set (Sieve X)) = J₂) : J₁ = J₂ := + DFunLike.coe_injective h -/- -Porting note: This is now a syntactic tautology. @[simp] theorem mem_sieves_iff_coe : S ∈ J.sieves X ↔ S ∈ J X := Iff.rfl --/ /-- Also known as the maximality axiom. -/ @[simp] @@ -268,7 +263,13 @@ instance : InfSet (GrothendieckTopology C) where /-- 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 @@ -380,44 +381,11 @@ namespace Cover variable {J} -/- -Porting note: Lean complains that this is a dangerous instance. -I'm commenting this out since the `CoeFun` instance below is what we -use 99% of the time anyway. - -instance : Coe (J.Cover X) (Sieve X) := - ⟨fun S => S.1⟩ --/ - -/- -Porting note (#11445): Added this def as a replacement for the "dangerous" `Coe` above. --/ -/-- The sieve associated to a term of `J.Cover X`. -/ -def sieve (S : J.Cover X) : Sieve X := S.1 - -/- -Porting note: This somehow yields different behavior than the better instance below. Why?! +instance : CoeOut (J.Cover X) (Sieve X) := ⟨fun S => S.1⟩ -With this instance, we have to write `S _ f` but with the uncommented one, we can write `S f` -as expected. - -instance : CoeFun (J.Cover X) fun _ => ∀ ⦃Y⦄ (_ : Y ⟶ X), Prop := - ⟨fun S _ f => (S : Sieve X) f⟩ --/ - -instance : CoeFun (J.Cover X) fun _ => ∀ ⦃Y⦄ (_ : Y ⟶ X), Prop := - ⟨fun S => S.sieve⟩ - -/- -Porting note: This is now a syntactic tautology. - -@[simp] -theorem coe_fun_coe (S : J.Cover X) (f : Y ⟶ X) : S.sieve f = S f := - rfl --/ +instance : CoeFun (J.Cover X) fun _ => ∀ ⦃Y⦄ (_ : Y ⟶ X), Prop := ⟨fun S => (S : Sieve X)⟩ -theorem condition (S : J.Cover X) : S.sieve ∈ J X := - S.2 +theorem condition (S : J.Cover X) : (S : Sieve X) ∈ J X := S.2 @[ext] theorem ext (S T : J.Cover X) (h : ∀ ⦃Y⦄ (f : Y ⟶ X), S f ↔ T f) : S = T := @@ -430,8 +398,7 @@ instance : OrderTop (J.Cover X) := instance : SemilatticeInf (J.Cover X) := { (inferInstance : Preorder _) with - inf := fun S T => ⟨S.sieve ⊓ T.sieve, - J.intersection_covering S.condition T.condition⟩ + 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 @@ -494,7 +461,7 @@ def Arrow.Relation.map {S T : J.Cover X} {I₁ I₂ : S.Arrow} /-- Pull back a cover along a morphism. -/ def pullback (S : J.Cover X) (f : Y ⟶ X) : J.Cover Y := - ⟨Sieve.pullback f S.sieve, J.pullback_stable _ S.condition⟩ + ⟨Sieve.pullback f S, J.pullback_stable _ S.condition⟩ /-- An arrow of `S.pullback f` gives rise to an arrow of `S`. -/ @[simps] @@ -525,8 +492,8 @@ def pullbackComp {X Y Z : C} (S : J.Cover X) (f : Z ⟶ Y) (g : Y ⟶ X) : /-- Combine a family of covers over a cover. -/ def bind {X : C} (S : J.Cover X) (T : ∀ I : S.Arrow, J.Cover I.Y) : J.Cover X := - ⟨Sieve.bind S.sieve fun Y f hf => (T ⟨Y, f, hf⟩).sieve, - J.bind_covering S.condition fun _ _ _ => (T _).condition⟩ + ⟨Sieve.bind S fun Y f hf => T ⟨Y, f, hf⟩, + J.bind_covering S.condition fun _ _ _ => (T { Y := _, f := _, hf := _ }).condition⟩ /-- The canonical morphism from `S.bind T` to `T`. -/ def bindToBase {X : C} (S : J.Cover X) (T : ∀ I : S.Arrow, J.Cover I.Y) : S.bind T ⟶ S := diff --git a/Mathlib/CategoryTheory/Sites/InducedTopology.lean b/Mathlib/CategoryTheory/Sites/InducedTopology.lean index 8c1aae2362041..718bea16efa74 100644 --- a/Mathlib/CategoryTheory/Sites/InducedTopology.lean +++ b/Mathlib/CategoryTheory/Sites/InducedTopology.lean @@ -100,7 +100,7 @@ def inducedTopology : GrothendieckTopology C where @[simp] lemma mem_inducedTopology_sieves_iff {X : C} (S : Sieve X) : - S ∈ (G.inducedTopology K).sieves X ↔ (S.functorPushforward G) ∈ K.sieves (G.obj X) := + S ∈ (G.inducedTopology K) X ↔ (S.functorPushforward G) ∈ K (G.obj X) := Iff.rfl /-- `G` is cover-lifting wrt the induced topology. -/ diff --git a/Mathlib/CategoryTheory/Sites/IsSheafFor.lean b/Mathlib/CategoryTheory/Sites/IsSheafFor.lean index ccd585a8efb58..136e553138ef3 100644 --- a/Mathlib/CategoryTheory/Sites/IsSheafFor.lean +++ b/Mathlib/CategoryTheory/Sites/IsSheafFor.lean @@ -123,7 +123,7 @@ In special cases, this condition can be simplified, see `pullbackCompatible_iff` This is referred to as a "compatible family" in Definition C2.1.2 of [Elephant], and on nlab: https://ncatlab.org/nlab/show/sheaf#GeneralDefinitionInComponents -For a more explicit version in the case where `R` is of the form `Presieve.ofArrows`, see +For a more explicit version in the case where `R` is of the form `Presieve.ofArrows`, see `CategoryTheory.Presieve.Arrows.Compatible`. -/ def FamilyOfElements.Compatible (x : FamilyOfElements P R) : Prop := @@ -142,7 +142,7 @@ Equation (5). Viewing the type `FamilyOfElements` as the middle object of the fo https://stacks.math.columbia.edu/tag/00VM, this condition expresses that `pr₀* (x) = pr₁* (x)`, using the notation defined there. -For a more explicit version in the case where `R` is of the form `Presieve.ofArrows`, see +For a more explicit version in the case where `R` is of the form `Presieve.ofArrows`, see `CategoryTheory.Presieve.Arrows.PullbackCompatible`. -/ def FamilyOfElements.PullbackCompatible (x : FamilyOfElements P R) [R.hasPullbacks] : Prop := @@ -663,7 +663,7 @@ section Arrows variable {B : C} {I : Type*} {X : I → C} (π : (i : I) → X i ⟶ B) (P) /-- -A more explicit version of `FamilyOfElements.Compatible` for a `Presieve.ofArrows`. +A more explicit version of `FamilyOfElements.Compatible` for a `Presieve.ofArrows`. -/ def Arrows.Compatible (x : (i : I) → P.obj (op (X i))) : Prop := ∀ i j Z (gi : Z ⟶ X i) (gj : Z ⟶ X j), gi ≫ π i = gj ≫ π j → @@ -720,7 +720,7 @@ theorem isSheafFor_arrows_iff : (ofArrows X π).IsSheafFor P ↔ variable [(ofArrows X π).hasPullbacks] /-- -A more explicit version of `FamilyOfElements.PullbackCompatible` for a `Presieve.ofArrows`. +A more explicit version of `FamilyOfElements.PullbackCompatible` for a `Presieve.ofArrows`. -/ def Arrows.PullbackCompatible (x : (i : I) → P.obj (op (X i))) : Prop := ∀ i j, P.map (pullback.fst (π i) (π j)).op (x i) = diff --git a/Mathlib/CategoryTheory/Sites/LeftExact.lean b/Mathlib/CategoryTheory/Sites/LeftExact.lean index 4538829b60709..d12346e4674e9 100644 --- a/Mathlib/CategoryTheory/Sites/LeftExact.lean +++ b/Mathlib/CategoryTheory/Sites/LeftExact.lean @@ -245,11 +245,7 @@ instance preservesLimitsOfShape_presheafToSheaf : apply isLimitOfReflects (sheafToPresheaf J D) have : ReflectsLimitsOfShape (AsSmall.{max v u} (FinCategory.AsType K)) (forget D) := reflectsLimitsOfShapeOfReflectsIsomorphisms - -- Porting note: the mathlib proof was by `apply is_limit_of_preserves (J.sheafification D) hS` - have : PreservesLimitsOfShape (AsSmall.{max v u} (FinCategory.AsType K)) - (plusPlusSheaf J D ⋙ sheafToPresheaf J D) := - preservesLimitsOfShapeOfNatIso (J.sheafificationIsoPresheafToSheafCompSheafToPreasheaf D) - exact isLimitOfPreserves (plusPlusSheaf J D ⋙ sheafToPresheaf J D) hS + apply isLimitOfPreserves (J.sheafification D) hS instance preservesfiniteLimits_presheafToSheaf [HasFiniteLimits D] : PreservesFiniteLimits (plusPlusSheaf J D) := by @@ -259,15 +255,15 @@ instance preservesfiniteLimits_presheafToSheaf [HasFiniteLimits D] : variable (J D) -/-- `plusPlusSheaf` is isomorphic to an arbitrary choice of left adjoint. -/ +/-- `plusPlusSheaf` is isomorphic to an arbitrary choice of left adjoint. -/ def plusPlusSheafIsoPresheafToSheaf : plusPlusSheaf J D ≅ presheafToSheaf J D := (plusPlusAdjunction J D).leftAdjointUniq (sheafificationAdjunction J D) -/-- `plusPlusFunctor` is isomorphic to `sheafification`. -/ +/-- `plusPlusFunctor` is isomorphic to `sheafification`. -/ def plusPlusFunctorIsoSheafification : J.sheafification D ≅ sheafification J D := isoWhiskerRight (plusPlusSheafIsoPresheafToSheaf J D) (sheafToPresheaf J D) -/-- `plusPlus` is isomorphic to `sheafify`. -/ +/-- `plusPlus` is isomorphic to `sheafify`. -/ def plusPlusIsoSheafify (P : Cᵒᵖ ⥤ D) : J.sheafify P ≅ sheafify J P := (sheafToPresheaf J D).mapIso ((plusPlusSheafIsoPresheafToSheaf J D).app P) diff --git a/Mathlib/CategoryTheory/Sites/Limits.lean b/Mathlib/CategoryTheory/Sites/Limits.lean index d85824a7edd78..1c38d0e033185 100644 --- a/Mathlib/CategoryTheory/Sites/Limits.lean +++ b/Mathlib/CategoryTheory/Sites/Limits.lean @@ -107,7 +107,7 @@ def isLimitMultiforkOfIsLimit (F : K ⥤ Sheaf J D) (E : Cone (F ⋙ sheafToPres erw [(isLimitOfPreserves ((evaluation Cᵒᵖ D).obj (op X)) hE).fac (multiforkEvaluationCone F E X W S)] dsimp [multiforkEvaluationCone, Presheaf.isLimitOfIsSheaf] - erw [Presheaf.IsSheaf.amalgamate_map] + rw [Presheaf.IsSheaf.amalgamate_map] rfl) (by intro S m hm diff --git a/Mathlib/CategoryTheory/Sites/LocallyInjective.lean b/Mathlib/CategoryTheory/Sites/LocallyInjective.lean index a537edefc713a..782d1b84f0591 100644 --- a/Mathlib/CategoryTheory/Sites/LocallyInjective.lean +++ b/Mathlib/CategoryTheory/Sites/LocallyInjective.lean @@ -115,7 +115,7 @@ lemma isLocallyInjective_iff_equalizerSieve_mem_imp : · intro Y f hf refine J.superset_covering (Sieve.le_pullback_bind S.1 T _ hf) (equalizerSieve_mem J φ _ _ ?_) - erw [NatTrans.naturality_apply, NatTrans.naturality_apply] + rw [NatTrans.naturality_apply, NatTrans.naturality_apply] exact hf · intro hφ exact ⟨fun {X} x y h => hφ x y (by simp [h])⟩ @@ -179,7 +179,7 @@ open GrothendieckTopology.Plus instance isLocallyInjective_toPlus (P : Cᵒᵖ ⥤ Type max u v) : IsLocallyInjective J (J.toPlus P) where equalizerSieve_mem {X} x y h := by - erw [toPlus_eq_mk, toPlus_eq_mk, eq_mk_iff_exists] at h + rw [toPlus_eq_mk, toPlus_eq_mk, eq_mk_iff_exists] at h obtain ⟨W, h₁, h₂, eq⟩ := h exact J.superset_covering (fun Y f hf => congr_fun (congr_arg Subtype.val eq) ⟨Y, f, hf⟩) W.2 diff --git a/Mathlib/CategoryTheory/Sites/LocallySurjective.lean b/Mathlib/CategoryTheory/Sites/LocallySurjective.lean index 5d9ab1ddb8a9c..06a7da7304b54 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⟩ @@ -94,7 +94,7 @@ instance {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) [IsLocallySurjective J f] : theorem isLocallySurjective_iff_imagePresheaf_sheafify_eq_top {F G : Cᵒᵖ ⥤ A} (f : F ⟶ G) : IsLocallySurjective J f ↔ (imagePresheaf (whiskerRight f (forget A))).sheafify J = ⊤ := by simp only [Subpresheaf.ext_iff, Function.funext_iff, Set.ext_iff, top_subpresheaf_obj, - Set.top_eq_univ, Set.mem_univ, iff_true_iff] + 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 c0bacd71db3d6..c36e6664261b4 100644 --- a/Mathlib/CategoryTheory/Sites/MayerVietorisSquare.lean +++ b/Mathlib/CategoryTheory/Sites/MayerVietorisSquare.lean @@ -3,6 +3,8 @@ 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.Adjunctions +import Mathlib.CategoryTheory.Sites.Adjunction import Mathlib.CategoryTheory.Limits.Preserves.Shapes.Square import Mathlib.CategoryTheory.Limits.Shapes.Types import Mathlib.CategoryTheory.Sites.Sheafification @@ -39,9 +41,6 @@ Given a Mayer-Vietoris square `S` and a presheaf `P` on `C`, we introduce a sheaf condition `S.SheafCondition P` and show that it is indeed satisfied by sheaves. -## TODO -* provide constructors for `MayerVietorisSquare` - ## References * https://stacks.math.columbia.edu/tag/08GL @@ -52,10 +51,29 @@ namespace CategoryTheory open Limits Opposite +variable {C : Type u} [Category.{v} C] + {J : GrothendieckTopology C} [HasWeakSheafify J (Type v)] + +@[simp] +lemma Sheaf.isPullback_square_op_map_yoneda_presheafToSheaf_yoneda_iff + (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 + refine Square.IsPullback.iff_of_equiv _ _ + (((sheafificationAdjunction J (Type v)).homEquiv _ _).trans yonedaEquiv) + (((sheafificationAdjunction J (Type v)).homEquiv _ _).trans yonedaEquiv) + (((sheafificationAdjunction J (Type v)).homEquiv _ _).trans yonedaEquiv) + (((sheafificationAdjunction J (Type v)).homEquiv _ _).trans yonedaEquiv) ?_ ?_ ?_ ?_ + all_goals + ext x + dsimp + rw [yonedaEquiv_naturality] + erw [Adjunction.homEquiv_naturality_left] + rfl + namespace GrothendieckTopology -variable {C : Type u} [Category.{v} C] - (J : GrothendieckTopology C) [HasWeakSheafify J (Type v)] +variable (J) /-- A Mayer-Vietoris square in a category `C` equipped with a Grothendieck topology consists of a commutative square `f₁₂ ≫ f₂₄ = f₁₃ ≫ f₃₄` in `C` @@ -69,8 +87,62 @@ structure MayerVietorisSquare extends Square C where namespace MayerVietorisSquare variable {J} + +/-- Constructor for Mayer-Vietoris squares taking as an input +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₁₃] + (H : ∀ (F : Sheaf J (Type v)), (sq.op.map F.val).IsPullback) : + J.MayerVietorisSquare where + toSquare := sq + isPushout := by + rw [Square.isPushout_iff_op_map_yoneda_isPullback] + intro F + exact (F.isPullback_square_op_map_yoneda_presheafToSheaf_yoneda_iff sq).2 (H F) + +/-- Constructor for Mayer-Vietoris squares taking as an input +a pullback square `sq` such that `sq.f₂₄` and `sq.f₃₄` are two monomorphisms +which form a covering of `S.X₄`. -/ +@[simps! toSquare] +noncomputable def mk_of_isPullback (sq : Square C) [Mono sq.f₂₄] [Mono sq.f₃₄] + (h₁ : sq.IsPullback) (h₂ : Sieve.ofTwoArrows sq.f₂₄ sq.f₃₄ ∈ J sq.X₄) : + J.MayerVietorisSquare := + have : Mono sq.f₁₃ := h₁.mono_f₁₃ + mk' sq (fun F ↦ by + apply Square.IsPullback.mk + refine PullbackCone.IsLimit.mk _ + (fun s ↦ F.2.amalgamateOfArrows _ h₂ + (fun j ↦ WalkingPair.casesOn j s.fst s.snd) + (fun W ↦ by + rintro (_|_) (_|_) a b fac + · obtain rfl : a = b := by simpa only [← cancel_mono sq.f₂₄] using fac + rfl + · obtain ⟨φ, rfl, rfl⟩ := PullbackCone.IsLimit.lift' h₁.isLimit _ _ fac + simpa using s.condition =≫ F.val.map φ.op + · obtain ⟨φ, rfl, rfl⟩ := PullbackCone.IsLimit.lift' h₁.isLimit _ _ fac.symm + simpa using s.condition.symm =≫ F.val.map φ.op + · obtain rfl : a = b := by simpa only [← cancel_mono sq.f₃₄] using fac + rfl)) (fun _ ↦ ?_) (fun _ ↦ ?_) (fun s m hm₁ hm₂ ↦ ?_) + · exact F.2.amalgamateOfArrows_map _ _ _ _ WalkingPair.left + · exact F.2.amalgamateOfArrows_map _ _ _ _ WalkingPair.right + · apply F.2.hom_ext_ofArrows _ h₂ + rintro (_|_) + · rw [F.2.amalgamateOfArrows_map _ _ _ _ WalkingPair.left] + exact hm₁ + · rw [F.2.amalgamateOfArrows_map _ _ _ _ WalkingPair.right] + exact hm₂) + variable (S : J.MayerVietorisSquare) +lemma isPushoutAddCommGrpFreeSheaf [HasWeakSheafify J AddCommGrp.{v}] : + (S.map (yoneda ⋙ (whiskeringRight _ _ _).obj AddCommGrp.free ⋙ + presheafToSheaf J _)).IsPushout := + (S.isPushout.map (Sheaf.composeAndSheafify J AddCommGrp.free)).of_iso + ((Square.mapFunctor.mapIso + (presheafToSheafCompComposeAndSheafifyIso J AddCommGrp.free)).app + (S.map yoneda)) + /-- The condition that a Mayer-Vietoris square becomes a pullback square when we evaluate a presheaf on it. --/ def SheafCondition {A : Type u'} [Category.{v'} A] (P : Cᵒᵖ ⥤ A) : Prop := @@ -126,26 +198,13 @@ lemma map_f₃₄_op_glue : P.map S.f₃₄.op (h.glue u v huv) = v := end SheafCondition -private lemma sheafCondition_of_sheaf' (F : Sheaf J (Type v)) : - S.SheafCondition F.val := by - refine (S.isPushout.op.map (yoneda.obj F)).of_equiv - (((sheafificationAdjunction J (Type v)).homEquiv _ _).trans yonedaEquiv) - (((sheafificationAdjunction J (Type v)).homEquiv _ _).trans yonedaEquiv) - (((sheafificationAdjunction J (Type v)).homEquiv _ _).trans yonedaEquiv) - (((sheafificationAdjunction J (Type v)).homEquiv _ _).trans yonedaEquiv) ?_ ?_ ?_ ?_ - all_goals - ext x - dsimp - rw [yonedaEquiv_naturality] - erw [Adjunction.homEquiv_naturality_left] - rfl - lemma sheafCondition_of_sheaf {A : Type u'} [Category.{v} A] (F : Sheaf J A) : S.SheafCondition F.val := by rw [sheafCondition_iff_comp_coyoneda] intro X - exact S.sheafCondition_of_sheaf' - ⟨_, (isSheaf_iff_isSheaf_of_type _ _).2 (F.cond X.unop)⟩ + exact (Sheaf.isPullback_square_op_map_yoneda_presheafToSheaf_yoneda_iff _ S.toSquare).1 + (S.isPushout.op.map + (yoneda.obj ⟨_, (isSheaf_iff_isSheaf_of_type _ _).2 (F.cond X.unop)⟩)) end MayerVietorisSquare diff --git a/Mathlib/CategoryTheory/Sites/Plus.lean b/Mathlib/CategoryTheory/Sites/Plus.lean index 3dc4ed4575b01..9fe18afba43ba 100644 --- a/Mathlib/CategoryTheory/Sites/Plus.lean +++ b/Mathlib/CategoryTheory/Sites/Plus.lean @@ -67,24 +67,20 @@ theorem diagramNatTrans_id (X : C) (P : Cᵒᵖ ⥤ D) : J.diagramNatTrans (𝟙 P) X = 𝟙 (J.diagram P X) := by ext : 2 refine Multiequalizer.hom_ext _ _ _ (fun i => ?_) - dsimp - simp only [limit.lift_π, Multifork.ofι_pt, Multifork.ofι_π_app, Category.id_comp] - erw [Category.comp_id] + simp @[simp] theorem diagramNatTrans_zero [Preadditive D] (X : C) (P Q : Cᵒᵖ ⥤ D) : J.diagramNatTrans (0 : P ⟶ Q) X = 0 := by ext : 2 refine Multiequalizer.hom_ext _ _ _ (fun i => ?_) - dsimp - rw [zero_comp, Multiequalizer.lift_ι, comp_zero] + simp @[simp] theorem diagramNatTrans_comp {P Q R : Cᵒᵖ ⥤ D} (η : P ⟶ Q) (γ : Q ⟶ R) (X : C) : J.diagramNatTrans (η ≫ γ) X = J.diagramNatTrans η X ≫ J.diagramNatTrans γ X := by ext : 2 refine Multiequalizer.hom_ext _ _ _ (fun i => ?_) - dsimp simp variable (D) @@ -110,7 +106,7 @@ def plusObj : Cᵒᵖ ⥤ D where simp only [diagramPullback_app, colimit.ι_pre, ι_colimMap_assoc, Category.comp_id] let e := S.unop.pullbackId dsimp only [Functor.op, pullback_obj] - erw [← colimit.w _ e.inv.op, ← Category.assoc] + rw [← colimit.w _ e.inv.op, ← Category.assoc] convert Category.id_comp (colimit.ι (diagram J P (unop X)) S) refine Multiequalizer.hom_ext _ _ _ (fun I => ?_) dsimp @@ -127,7 +123,7 @@ def plusObj : Cᵒᵖ ⥤ D where Category.assoc] let e := S.unop.pullbackComp g.unop f.unop dsimp only [Functor.op, pullback_obj] - erw [← colimit.w _ e.inv.op, ← Category.assoc, ← Category.assoc] + rw [← colimit.w _ e.inv.op, ← Category.assoc, ← Category.assoc] congr 1 refine Multiequalizer.hom_ext _ _ _ (fun I => ?_) dsimp @@ -246,7 +242,7 @@ theorem isIso_toPlus_of_isSheaf (hP : Presheaf.IsSheaf J P) : IsIso (J.toPlus P) rw [Presheaf.isSheaf_iff_multiequalizer] at hP suffices ∀ X, IsIso ((J.toPlus P).app X) from NatIso.isIso_of_isIso_app _ intro X - suffices IsIso (colimit.ι (J.diagram P X.unop) (op ⊤)) from IsIso.comp_isIso + refine IsIso.comp_isIso' inferInstance ?_ suffices ∀ (S T : (J.Cover X.unop)ᵒᵖ) (f : S ⟶ T), IsIso ((J.diagram P X.unop).map f) from isIso_ι_of_isInitial (initialOpOfTerminal isTerminalTop) _ intro S T e diff --git a/Mathlib/CategoryTheory/Sites/Preserves.lean b/Mathlib/CategoryTheory/Sites/Preserves.lean index 1fdb884f4aeb3..233115606bae5 100644 --- a/Mathlib/CategoryTheory/Sites/Preserves.lean +++ b/Mathlib/CategoryTheory/Sites/Preserves.lean @@ -18,14 +18,14 @@ preserve "the corresponding products". More precisely, given a presheaf `F : Cᵒᵖ ⥤ Type*`, we have: * If `F` satisfies the sheaf condition with respect to the empty sieve on the initial object of `C`, - then `F` preserves terminal objects. + then `F` preserves terminal objects. See `preservesTerminalOfIsSheafForEmpty`. -* If `F` furthermore satisfies the sheaf condition with respect to the presieve consisting of the - inclusion arrows in a coproduct in `C`, then `F` preserves the corresponding product. +* If `F` furthermore satisfies the sheaf condition with respect to the presieve consisting of the + inclusion arrows in a coproduct in `C`, then `F` preserves the corresponding product. See `preservesProductOfIsSheafFor`. -* If `F` preserves a product, then it satisfies the sheaf condition with respect to the +* If `F` preserves a product, then it satisfies the sheaf condition with respect to the corresponding presieve of arrows. See `isSheafFor_of_preservesProduct`. -/ @@ -44,8 +44,8 @@ section Terminal variable (I) in /-- -If `F` is a presheaf which satisfies the sheaf condition with respect to the empty presieve on any -object, then `F` takes that object to the terminal object. +If `F` is a presheaf which satisfies the sheaf condition with respect to the empty presieve on any +object, then `F` takes that object to the terminal object. -/ noncomputable def isTerminal_of_isSheafFor_empty_presieve : IsTerminal (F.obj (op I)) := by @@ -54,8 +54,8 @@ def isTerminal_of_isSheafFor_empty_presieve : IsTerminal (F.obj (op I)) := by exact ⟨⟨fun _ ↦ t⟩, fun a ↦ by ext; exact h.2 _ (by tauto)⟩ /-- -If `F` is a presheaf which satisfies the sheaf condition with respect to the empty presieve on the -initial object, then `F` preserves terminal objects. +If `F` is a presheaf which satisfies the sheaf condition with respect to the empty presieve on the +initial object, then `F` preserves terminal objects. -/ noncomputable def preservesTerminalOfIsSheafForEmpty (hI : IsInitial I) : PreservesLimit (Functor.empty Cᵒᵖ) F := @@ -92,7 +92,7 @@ variable [(ofArrows X c.inj).hasPullbacks] include hc in /-- -If `F` preserves a particular product, then it `IsSheafFor` the corresponging presieve of arrows. +If `F` preserves a particular product, then it `IsSheafFor` the corresponding presieve of arrows. -/ theorem isSheafFor_of_preservesProduct [PreservesLimit (Discrete.functor (fun x ↦ op (X x))) F] : (ofArrows X c.inj).IsSheafFor F := by @@ -148,7 +148,7 @@ def preservesProductOfIsSheafFor have : HasCoproduct X := ⟨⟨c, hc⟩⟩ refine @PreservesProduct.ofIsoComparison _ _ _ _ F _ (fun x ↦ op (X x)) _ _ ?_ rw [piComparison_fac (hc := hc)] - refine @IsIso.comp_isIso _ _ _ _ _ _ _ inferInstance ?_ + refine IsIso.comp_isIso' inferInstance ?_ rw [isIso_iff_bijective, Function.bijective_iff_existsUnique] rw [Equalizer.Presieve.Arrows.sheaf_condition, Limits.Types.type_equalizer_iff_unique] at hF' exact fun b ↦ hF' b (congr_fun (firstMap_eq_secondMap F hF hI c hd) b) diff --git a/Mathlib/CategoryTheory/Sites/PreservesSheafification.lean b/Mathlib/CategoryTheory/Sites/PreservesSheafification.lean index 88823548b8066..7e02c805dd32b 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,9 +170,7 @@ 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 - dsimp only [sheafComposeNatTrans] - erw [Adjunction.homEquiv_counit, Adjunction.unit_naturality_assoc, - adj₂.right_triangle_components, comp_id] + simp [sheafComposeNatTrans, -sheafToPresheaf_obj, -sheafToPresheaf_map] lemma sheafComposeNatTrans_app_uniq (P : Cᵒᵖ ⥤ A) (α : G₂.obj (P ⋙ F) ⟶ (sheafCompose J F).obj (G₁.obj P)) diff --git a/Mathlib/CategoryTheory/Sites/Pullback.lean b/Mathlib/CategoryTheory/Sites/Pullback.lean index 967d59f82e891..335206084917e 100644 --- a/Mathlib/CategoryTheory/Sites/Pullback.lean +++ b/Mathlib/CategoryTheory/Sites/Pullback.lean @@ -37,11 +37,6 @@ variable {C : Type v₁} [SmallCategory C] {D : Type v₁} [SmallCategory D] (G variable (A : Type u₁) [Category.{v₁} A] variable (J : GrothendieckTopology C) (K : GrothendieckTopology D) --- Porting note: there was an explicit call to --- CategoryTheory.Sheaf.CategoryTheory.SheafToPresheaf.CategoryTheory.createsLimits.{u₁, v₁, v₁} --- but it is not necessary (it was not either in mathlib) -instance [HasLimits A] : CreatesLimits (sheafToPresheaf J A) := inferInstance - -- The assumptions so that we have sheafification variable [ConcreteCategory.{v₁} A] [PreservesLimits (forget A)] [HasColimits A] [HasLimits A] variable [PreservesFilteredColimits (forget A)] [(forget A).ReflectsIsomorphisms] diff --git a/Mathlib/CategoryTheory/Sites/Sheaf.lean b/Mathlib/CategoryTheory/Sites/Sheaf.lean index 2de13cf6759ad..80f0edcd7ebfb 100644 --- a/Mathlib/CategoryTheory/Sites/Sheaf.lean +++ b/Mathlib/CategoryTheory/Sites/Sheaf.lean @@ -148,7 +148,7 @@ theorem isLimit_iff_isSheafFor : rw [Classical.nonempty_pi]; constructor · intro hu E x hx specialize hu hx.cone - erw [(homEquivAmalgamation hx).uniqueCongr.nonempty_congr] at hu + rw [(homEquivAmalgamation hx).uniqueCongr.nonempty_congr] at hu exact (unique_subtype_iff_exists_unique _).1 hu · rintro h ⟨E, π⟩ let eqv := conesEquivSieveCompatibleFamily P S (op E) @@ -462,9 +462,9 @@ instance sheafHomHasNSMul : SMul ℕ (P ⟶ Q) where Sheaf.Hom.mk { app := fun U => n • f.1.app U naturality := fun U V i => by - induction' n with n ih - · simp only [zero_smul, comp_zero, zero_comp, Nat.zero_eq] - · simp only [Nat.succ_eq_add_one, add_smul, ih, one_nsmul, comp_add, + induction n with + | zero => simp only [zero_smul, comp_zero, zero_comp] + | succ n ih => simp only [Nat.succ_eq_add_one, add_smul, ih, one_nsmul, comp_add, NatTrans.naturality, add_comp] } instance : Zero (P ⟶ Q) where zero := Sheaf.Hom.mk 0 @@ -575,7 +575,6 @@ theorem isSheaf_iff_multiequalizer [∀ (X : C) (S : J.Cover X), HasMultiequaliz · intro a symm erw [IsIso.inv_comp_eq] - dsimp simp end MultiequalizerConditions diff --git a/Mathlib/CategoryTheory/Sites/SheafCohomology/Basic.lean b/Mathlib/CategoryTheory/Sites/SheafCohomology/Basic.lean index ba6a5261a40ff..630cf7424298a 100644 --- a/Mathlib/CategoryTheory/Sites/SheafCohomology/Basic.lean +++ b/Mathlib/CategoryTheory/Sites/SheafCohomology/Basic.lean @@ -5,7 +5,7 @@ Authors: Joël Riou -/ import Mathlib.Algebra.Category.Grp.Abelian import Mathlib.Algebra.Category.Grp.Adjunctions -import Mathlib.Algebra.Homology.DerivedCategory.Ext +import Mathlib.Algebra.Homology.DerivedCategory.Ext.Basic import Mathlib.CategoryTheory.Sites.Abelian import Mathlib.CategoryTheory.Sites.ConstantSheaf diff --git a/Mathlib/CategoryTheory/Sites/SheafHom.lean b/Mathlib/CategoryTheory/Sites/SheafHom.lean index aeec15f07d717..196eeab7477ac 100644 --- a/Mathlib/CategoryTheory/Sites/SheafHom.lean +++ b/Mathlib/CategoryTheory/Sites/SheafHom.lean @@ -82,7 +82,7 @@ def presheafHomSectionsEquiv : (presheafHom F G).sections ≃ (F ⟶ G) where dsimp refine Eq.trans ?_ ((s.1 ⟨X₁⟩).naturality (Over.homMk f : Over.mk f ⟶ Over.mk (𝟙 X₁)).op) - erw [← s.2 f.op, presheafHom_map_app_op_mk_id] + rw [← s.2 f.op, presheafHom_map_app_op_mk_id] rfl } invFun f := ⟨fun X => whiskerLeft _ f, fun _ => rfl⟩ left_inv s := by @@ -174,7 +174,7 @@ lemma presheafHom_isSheafFor : rintro ⟨Z : Over Y₂.left, hZ⟩ dsimp rw [assoc, assoc, app_cond hG x hx Y₂.hom Z.hom hZ, ← G.map_comp, ← op_comp] - erw [app_cond hG x hx Y₁.hom (Z.hom ≫ φ.left) (by simpa using hZ), + rw [app_cond hG x hx Y₁.hom (Z.hom ≫ φ.left) (by simpa using hZ), ← F.map_comp_assoc, op_comp] congr 3 simp }, ?_⟩ diff --git a/Mathlib/CategoryTheory/Sites/SheafOfTypes.lean b/Mathlib/CategoryTheory/Sites/SheafOfTypes.lean index db8d37ff2bf28..c2d7b20d409ae 100644 --- a/Mathlib/CategoryTheory/Sites/SheafOfTypes.lean +++ b/Mathlib/CategoryTheory/Sites/SheafOfTypes.lean @@ -13,7 +13,7 @@ Defines the notion of a sheaf of types (usually called a sheaf of sets by mathem on a category equipped with a Grothendieck topology, as well as a range of equivalent conditions useful in different situations. -In `Mathlib/CategoryTheory/Sites/IsSheafFor.lean` it is defined what it means for a presheaf to be a +In `Mathlib/CategoryTheory/Sites/IsSheafFor.lean` it is defined what it means for a presheaf to be a sheaf *for* a particular sieve. Given a Grothendieck topology `J`, `P` is a sheaf if it is a sheaf for every sieve in the topology. See `IsSheaf`. diff --git a/Mathlib/CategoryTheory/Sites/Sheafification.lean b/Mathlib/CategoryTheory/Sites/Sheafification.lean index 62cb3cf8a3dec..409605999eeb7 100644 --- a/Mathlib/CategoryTheory/Sites/Sheafification.lean +++ b/Mathlib/CategoryTheory/Sites/Sheafification.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Dagur Asgeirsson -/ import Mathlib.CategoryTheory.Adjunction.Unique -import Mathlib.CategoryTheory.Adjunction.FullyFaithful +import Mathlib.CategoryTheory.Adjunction.Reflective import Mathlib.CategoryTheory.Sites.Sheaf import Mathlib.CategoryTheory.Limits.Preserves.Finite /-! @@ -14,7 +14,7 @@ import Mathlib.CategoryTheory.Limits.Preserves.Finite Given a site `(C, J)` we define a typeclass `HasSheafify J A` saying that the inclusion functor from `A`-valued sheaves on `C` to presheaves admits a left exact left adjoint (sheafification). -Note: to access the `HasSheafify` instance for suitable concrete categories, import the file +Note: to access the `HasSheafify` instance for suitable concrete categories, import the file `Mathlib.CategoryTheory.Sites.LeftExact`. -/ @@ -37,7 +37,7 @@ abbrev HasWeakSheafify : Prop := (sheafToPresheaf J A).IsRightAdjoint left adjiont (sheafification). Given a finite limit preserving functor `F : (Cᵒᵖ ⥤ A) ⥤ Sheaf J A` and an adjunction -`adj : F ⊣ sheafToPresheaf J A`, use `HasSheafify.mk'` to construct a `HasSheafify` instance. +`adj : F ⊣ sheafToPresheaf J A`, use `HasSheafify.mk'` to construct a `HasSheafify` instance. -/ class HasSheafify : Prop where isRightAdjoint : HasWeakSheafify J A @@ -72,6 +72,12 @@ def sheafificationAdjunction [HasWeakSheafify J A] : instance [HasWeakSheafify J A] : (presheafToSheaf J A).IsLeftAdjoint := ⟨_, ⟨sheafificationAdjunction J A⟩⟩ +instance [HasWeakSheafify J A] : Reflective (sheafToPresheaf J A) where + adj := sheafificationAdjunction _ _ + +instance [HasSheafify J A] : PreservesFiniteLimits (reflector (sheafToPresheaf J A)) := + inferInstanceAs (PreservesFiniteLimits (presheafToSheaf _ _)) + end variable {D : Type*} [Category D] [HasWeakSheafify J D] @@ -135,7 +141,8 @@ theorem isIso_toSheafify {P : Cᵒᵖ ⥤ D} (hP : Presheaf.IsSheaf J P) : IsIso rfl · change (sheafToPresheaf _ _).map _ ≫ _ = _ change _ ≫ (sheafificationAdjunction J D).unit.app ((sheafToPresheaf J D).obj ⟨P, hP⟩) = _ - erw [← (sheafificationAdjunction J D).inv_counit_map (X := ⟨P, hP⟩), comp_inv_eq_id] + rw [← (sheafificationAdjunction J D).inv_counit_map (X := ⟨P, hP⟩)] + simp /-- If `P` is a sheaf, then `P` is isomorphic to `sheafify J P`. -/ noncomputable def isoSheafify {P : Cᵒᵖ ⥤ D} (hP : Presheaf.IsSheaf J P) : P ≅ sheafify J P := diff --git a/Mathlib/CategoryTheory/Sites/Sieves.lean b/Mathlib/CategoryTheory/Sites/Sieves.lean index d745ad87d9aed..172573aad9266 100644 --- a/Mathlib/CategoryTheory/Sites/Sieves.lean +++ b/Mathlib/CategoryTheory/Sites/Sieves.lean @@ -3,11 +3,7 @@ Copyright (c) 2020 Bhavik Mehta. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Bhavik Mehta, Edward Ayers -/ -import Mathlib.CategoryTheory.Comma.Over import Mathlib.CategoryTheory.Limits.Shapes.Pullback.HasPullback -import Mathlib.CategoryTheory.Yoneda -import Mathlib.Data.Set.Lattice -import Mathlib.Order.CompleteLattice /-! # Theory of sieves @@ -82,11 +78,11 @@ theorem bind_comp {S : Presieve X} {R : ∀ ⦃Y : C⦄ ⦃f : Y ⟶ X⦄, S f -- Porting note: it seems the definition of `Presieve` must be unfolded in order to define -- this inductive type, it was thus renamed `singleton'` -- Note we can't make this into `HasSingleton` because of the out-param. -/-- The singleton presieve. -/ +/-- The singleton presieve. -/ inductive singleton' : ⦃Y : C⦄ → (Y ⟶ X) → Prop | mk : singleton' f -/-- The singleton presieve. -/ +/-- The singleton presieve. -/ def singleton : Presieve X := singleton' f lemma singleton.mk {f : Y ⟶ X} : singleton f f := singleton'.mk @@ -438,6 +434,9 @@ lemma mem_ofArrows_iff {I : Type*} {X : C} (Y : I → C) (f : ∀ i, Y i ⟶ X) · rintro ⟨i, a, rfl⟩ apply downward_closed _ (ofArrows_mk Y f i) +/-- The sieve generated by two morphisms. -/ +abbrev ofTwoArrows {U V X : C} (i : U ⟶ X) (j : V ⟶ X) : Sieve X := + Sieve.ofArrows (Y := pairFunction U V) (fun k ↦ WalkingPair.casesOn k i j) /-- The sieve of `X : C` that is generated by a family of objects `Y : I → C`: it consists of morphisms to `X` which factor through at least one of the `Y i`. -/ diff --git a/Mathlib/CategoryTheory/Sites/Subsheaf.lean b/Mathlib/CategoryTheory/Sites/Subsheaf.lean index a58fe64c5db0c..198726f465d9b 100644 --- a/Mathlib/CategoryTheory/Sites/Subsheaf.lean +++ b/Mathlib/CategoryTheory/Sites/Subsheaf.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ import Mathlib.CategoryTheory.Elementwise -import Mathlib.CategoryTheory.Adjunction.Evaluation +import Mathlib.CategoryTheory.Limits.FunctorCategory.EpiMono import Mathlib.Tactic.CategoryTheory.Elementwise import Mathlib.CategoryTheory.Adhesive import Mathlib.CategoryTheory.Sites.ConcreteSheafification @@ -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 @@ -252,7 +252,7 @@ theorem Subpresheaf.sheafify_sheafify (h : Presieve.IsSheaf J F) : (G.sheafify J).sheafify J = G.sheafify J := ((Subpresheaf.eq_sheafify_iff _ h).mpr <| G.sheafify_isSheaf h).symm -/-- The lift of a presheaf morphism onto the sheafification subpresheaf. -/ +/-- 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 @@ -269,12 +269,10 @@ noncomputable def Subpresheaf.sheafifyLift (f : G.toPresheaf ⟶ F') (h : Presie change _ = F'.map (j ≫ i.unop).op _ refine Eq.trans ?_ (Presieve.IsSheafFor.valid_glue (h _ s.2) ((G.family_of_elements_compatible s.1).compPresheafMap f) (j ≫ i.unop) ?_).symm - swap -- Porting note: need to swap two goals otherwise the first goal needs to be proven - -- inside the second goal any way - · dsimp [Presieve.FamilyOfElements.compPresheafMap] at hj ⊢ - rwa [FunctorToTypes.map_comp_apply] · dsimp [Presieve.FamilyOfElements.compPresheafMap] exact congr_arg _ (Subtype.ext (FunctorToTypes.map_comp_apply _ _ _ _).symm) + · dsimp [Presieve.FamilyOfElements.compPresheafMap] at hj ⊢ + rwa [FunctorToTypes.map_comp_apply] theorem Subpresheaf.to_sheafifyLift (f : G.toPresheaf ⟶ F') (h : Presieve.IsSheaf J F') : Subpresheaf.homOfLe (G.le_sheafify J) ≫ G.sheafifyLift f h = f := by @@ -294,7 +292,7 @@ theorem Subpresheaf.to_sheafify_lift_unique (h : Presieve.IsSheaf J F') apply (h _ hs).isSeparatedFor.ext rintro V i hi dsimp at hi - erw [← FunctorToTypes.naturality, ← FunctorToTypes.naturality] + rw [← FunctorToTypes.naturality, ← FunctorToTypes.naturality] exact (congr_fun (congr_app e <| op V) ⟨_, hi⟩ : _) theorem Subpresheaf.sheafify_le (h : G ≤ G') (hF : Presieve.IsSheaf J F) @@ -307,7 +305,7 @@ theorem Subpresheaf.sheafify_le (h : G ≤ G') (hF : Presieve.IsSheaf J F) congr_arg (fun f : G.toPresheaf ⟶ G'.toPresheaf => (NatTrans.app f (op V) ⟨_, hi⟩).1) (G.to_sheafifyLift (Subpresheaf.homOfLe h) hG') convert this.symm - erw [← Subpresheaf.nat_trans_naturality] + rw [← Subpresheaf.nat_trans_naturality] rfl section Image @@ -351,14 +349,14 @@ theorem toImagePresheaf_ι (f : F' ⟶ F) : toImagePresheaf f ≫ (imagePresheaf theorem imagePresheaf_comp_le (f₁ : F ⟶ F') (f₂ : F' ⟶ F'') : imagePresheaf (f₁ ≫ f₂) ≤ imagePresheaf f₂ := fun U _ hx => ⟨f₁.app U hx.choose, hx.choose_spec⟩ -instance isIso_toImagePresheaf {F F' : Cᵒᵖ ⥤ TypeMax.{v, w}} (f : F ⟶ F') [hf : Mono f] : +instance isIso_toImagePresheaf {F F' : Cᵒᵖ ⥤ (Type (max v w))} (f : F ⟶ F') [hf : Mono f] : IsIso (toImagePresheaf f) := by have : ∀ (X : Cᵒᵖ), IsIso ((toImagePresheaf f).app X) := by intro X rw [isIso_iff_bijective] constructor · intro x y e - have := (NatTrans.mono_iff_mono_app _ _).mp hf X + have := (NatTrans.mono_iff_mono_app f).mp hf X rw [mono_iff_injective] at this exact this (congr_arg Subtype.val e : _) · rintro ⟨_, ⟨x, rfl⟩⟩ @@ -417,13 +415,12 @@ def imageMonoFactorization {F F' : Sheaf J (Type w)} (f : F ⟶ F') : Limits.Mon e := toImageSheaf f /-- The mono factorization given by `image_sheaf` for a morphism is an image. -/ -noncomputable def imageFactorization {F F' : Sheaf J TypeMax.{v, u}} (f : F ⟶ F') : +noncomputable def imageFactorization {F F' : Sheaf J (Type (max v u))} (f : F ⟶ F') : Limits.ImageFactorisation f where F := imageMonoFactorization f isImage := { lift := fun I => by - -- Porting note: need to specify the target category (TypeMax.{v, u}) for this to work. - haveI M := (Sheaf.Hom.mono_iff_presheaf_mono J TypeMax.{v, u} _).mp I.m_mono + haveI M := (Sheaf.Hom.mono_iff_presheaf_mono J (Type (max v u)) _).mp I.m_mono haveI := isIso_toImagePresheaf I.m.1 refine ⟨Subpresheaf.homOfLe ?_ ≫ inv (toImagePresheaf I.m.1)⟩ apply Subpresheaf.sheafify_le diff --git a/Mathlib/CategoryTheory/Sites/Types.lean b/Mathlib/CategoryTheory/Sites/Types.lean index 3e4363a236d3d..fca7e5d973986 100644 --- a/Mathlib/CategoryTheory/Sites/Types.lean +++ b/Mathlib/CategoryTheory/Sites/Types.lean @@ -20,8 +20,6 @@ universe u namespace CategoryTheory ---open scoped CategoryTheory.Type -- Porting note: unknown namespace - /-- A Grothendieck topology associated to the category of all types. A sieve is a covering iff it is jointly surjective. -/ def typesGrothendieckTopology : GrothendieckTopology (Type u) where @@ -140,19 +138,25 @@ theorem eval_app (S₁ S₂ : SheafOfTypes.{u} typesGrothendieckTopology) (f : S /-- `yoneda'` induces an equivalence of category between `Type u` and `SheafOfTypes typesGrothendieckTopology`. -/ @[simps!] -noncomputable def typeEquiv : Type u ≌ SheafOfTypes typesGrothendieckTopology := - Equivalence.mk yoneda' (sheafOfTypesToPresheaf _ ⋙ (evaluation _ _).obj (op PUnit)) - (NatIso.ofComponents +noncomputable def typeEquiv : Type u ≌ SheafOfTypes typesGrothendieckTopology where + functor := yoneda' + inverse := sheafOfTypesToPresheaf _ ⋙ (evaluation _ _).obj (op PUnit) + unitIso := NatIso.ofComponents (fun _α => -- α ≅ PUnit ⟶ α { hom := fun x _ => x inv := fun f => f PUnit.unit hom_inv_id := funext fun _ => rfl inv_hom_id := funext fun _ => funext fun y => PUnit.casesOn y rfl }) - fun _ => rfl) - (Iso.symm <| + fun _ => rfl + counitIso := Iso.symm <| NatIso.ofComponents (fun S => equivYoneda' S) fun {S₁ S₂} f => SheafOfTypes.Hom.ext <| NatTrans.ext <| - funext fun α => funext fun s => funext fun x => eval_app S₁ S₂ f (unop α) s x) + funext fun α => funext fun s => funext fun x => eval_app S₁ S₂ f (unop α) s x + functor_unitIso_comp X := by + ext1 + apply yonedaEquiv.injective + dsimp [yoneda', yonedaEquiv, evalEquiv] + erw [typesGlue_eval] theorem subcanonical_typesGrothendieckTopology : Sheaf.Subcanonical typesGrothendieckTopology.{u} := Sheaf.Subcanonical.of_yoneda_isSheaf _ fun _ => isSheaf_yoneda' diff --git a/Mathlib/CategoryTheory/Sites/Whiskering.lean b/Mathlib/CategoryTheory/Sites/Whiskering.lean index f80010696a0b9..17685ddf1e50a 100644 --- a/Mathlib/CategoryTheory/Sites/Whiskering.lean +++ b/Mathlib/CategoryTheory/Sites/Whiskering.lean @@ -129,10 +129,10 @@ instance hasSheafCompose_of_preservesMulticospan (F : A ⥤ B) exact ⟨Limits.IsLimit.postcomposeHomEquiv (S.multicospanComp F P) _ h⟩ /-- -Composing a sheaf with a functor preserving limits of the same size as the hom sets in `C` yields a +Composing a sheaf with a functor preserving limits of the same size as the hom sets in `C` yields a functor between sheaf categories. -Note: the size of the limit that `F` is required to preserve in +Note: the size of the limit that `F` is required to preserve in `hasSheafCompose_of_preservesMulticospan` is in general larger than this. -/ instance hasSheafCompose_of_preservesLimitsOfSize [PreservesLimitsOfSize.{v₁, max u₁ v₁} F] : diff --git a/Mathlib/CategoryTheory/Skeletal.lean b/Mathlib/CategoryTheory/Skeletal.lean index 3260b8eb2fa9b..af988c24022a5 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⟧⟩ @@ -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/Construction.lean b/Mathlib/CategoryTheory/SmallObject/Construction.lean index 808c18354da20..fe1e1fa4599e9 100644 --- a/Mathlib/CategoryTheory/SmallObject/Construction.lean +++ b/Mathlib/CategoryTheory/SmallObject/Construction.lean @@ -143,7 +143,7 @@ lemma ιFunctorObj_πFunctorObj : ιFunctorObj f πX ≫ πFunctorObj f πX = π /-- The canonical morphism `∐ (functorObjSrcFamily f πX) ⟶ ∐ (functorObjSrcFamily f πY)` induced by a morphism in `φ : X ⟶ Y` such that `φ ≫ πX = πY`. -/ -noncomputable def functorMapSrc (hφ : φ ≫ πY = πX) : +noncomputable def functorMapSrc (hφ : φ ≫ πY = πX) : ∐ (functorObjSrcFamily f πX) ⟶ ∐ functorObjSrcFamily f πY := Sigma.map' (fun x => FunctorObjIndex.mk x.i (x.t ≫ φ) x.b (by simp [hφ])) (fun _ => 𝟙 _) @@ -168,7 +168,7 @@ lemma functorMapSrc_functorObjTop : /-- The canonical morphism `∐ functorObjTgtFamily f πX ⟶ ∐ functorObjTgtFamily f πY` induced by a morphism in `φ : X ⟶ Y` such that `φ ≫ πX = πY`. -/ -noncomputable def functorMapTgt (hφ : φ ≫ πY = πX) : +noncomputable def functorMapTgt (hφ : φ ≫ πY = πX) : ∐ functorObjTgtFamily f πX ⟶ ∐ functorObjTgtFamily f πY := Sigma.map' (fun x => FunctorObjIndex.mk x.i (x.t ≫ φ) x.b (by simp [hφ])) (fun _ => 𝟙 _) diff --git a/Mathlib/CategoryTheory/SmallObject/Iteration.lean b/Mathlib/CategoryTheory/SmallObject/Iteration.lean index 4e9947245dd1b..a9470418b418d 100644 --- a/Mathlib/CategoryTheory/SmallObject/Iteration.lean +++ b/Mathlib/CategoryTheory/SmallObject/Iteration.lean @@ -123,7 +123,7 @@ lemma mapSucc_eq (i : J) (hi : i < j) : end -variable (iter₁ iter₂ iter₃ : Φ.Iteration ε j) +variable (iter₁ iter₂ : Φ.Iteration ε j) /-- A morphism between two objects `iter₁` and `iter₂` in the category `Φ.Iteration ε j` of `j`th iterations of a functor `Φ` @@ -148,7 +148,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. diff --git a/Mathlib/CategoryTheory/Square.lean b/Mathlib/CategoryTheory/Square.lean index 3db04feeca7ef..1286c1bd87b9b 100644 --- a/Mathlib/CategoryTheory/Square.lean +++ b/Mathlib/CategoryTheory/Square.lean @@ -26,7 +26,7 @@ We define the flip functor, and two equivalences with the category `Arrow (Arrow C)`, depending on whether we consider a commutative square as a horizontal morphism between two vertical maps (`arrowArrowEquivalence`) -or a vertical morphism betwen two horizontal +or a vertical morphism between two horizontal maps (`arrowArrowEquivalence'`). -/ @@ -326,6 +326,8 @@ def map (sq : Square C) (F : C ⥤ D) : Square D where end Square +variable {C} + namespace Functor /-- The functor `Square C ⥤ Square D` induced by a functor `C ⥤ D`. -/ @@ -344,4 +346,21 @@ def mapSquare (F : C ⥤ D) : Square C ⥤ Square D where end Functor +/-- The natural transformation `F.mapSquare ⟶ G.mapSquare` induces +by a natural transformation `F ⟶ G`. -/ +@[simps] +def NatTrans.mapSquare {F G : C ⥤ D} (τ : F ⟶ G) : + F.mapSquare ⟶ G.mapSquare where + app sq := + { τ₁ := τ.app _ + τ₂ := τ.app _ + τ₃ := τ.app _ + τ₄ := τ.app _ } + +/-- The functor `(C ⥤ D) ⥤ Square C ⥤ Square D`. -/ +@[simps] +def Square.mapFunctor : (C ⥤ D) ⥤ Square C ⥤ Square D where + obj F := F.mapSquare + map τ := NatTrans.mapSquare τ + end CategoryTheory diff --git a/Mathlib/CategoryTheory/Subobject/Basic.lean b/Mathlib/CategoryTheory/Subobject/Basic.lean index 076606a7a3d8f..34c23433816f0 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 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 ac8612b0e93bd..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 @@ -379,18 +379,19 @@ theorem inf_arrow_factors_right {B : C} (X Y : Subobject B) : Y.Factors (X ⊓ Y theorem finset_inf_factors {I : Type*} {A B : C} {s : Finset I} {P : I → Subobject B} (f : A ⟶ B) : (s.inf P).Factors f ↔ ∀ i ∈ s, (P i).Factors f := by classical - induction' s using Finset.induction_on with _ _ _ ih - · simp [top_factors] - · simp [ih] + induction s using Finset.induction_on with + | empty => simp [top_factors] + | insert _ ih => simp [ih] -- `i` is explicit here because often we'd like to defer a proof of `m` theorem finset_inf_arrow_factors {I : Type*} {B : C} (s : Finset I) (P : I → Subobject B) (i : I) (m : i ∈ s) : (P i).Factors (s.inf P).arrow := by classical revert i m - induction' s using Finset.induction_on with _ _ _ ih - · rintro _ ⟨⟩ - · intro _ m + induction s using Finset.induction_on with + | empty => rintro _ ⟨⟩ + | insert _ ih => + intro _ m rw [Finset.inf_insert] simp only [Finset.mem_insert] at m rcases m with (rfl | m) @@ -472,9 +473,10 @@ theorem finset_sup_factors {I : Type*} {A B : C} {s : Finset I} {P : I → Subob (h : ∃ i ∈ s, (P i).Factors f) : (s.sup P).Factors f := by classical revert h - induction' s using Finset.induction_on with _ _ _ ih - · rintro ⟨_, ⟨⟨⟩, _⟩⟩ - · rintro ⟨j, ⟨m, h⟩⟩ + induction s using Finset.induction_on with + | empty => rintro ⟨_, ⟨⟨⟩, _⟩⟩ + | insert _ ih => + rintro ⟨j, ⟨m, h⟩⟩ simp only [Finset.sup_insert] simp only [Finset.mem_insert] at m rcases m with (rfl | m) diff --git a/Mathlib/CategoryTheory/Subobject/Limits.lean b/Mathlib/CategoryTheory/Subobject/Limits.lean index 3fbcf2452701b..26f73bd07b7d2 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 @@ -333,8 +333,6 @@ section variable [HasEqualizers C] -attribute [local instance] epi_comp - /-- The morphism `imageSubobject (h ≫ f) ⟶ imageSubobject f` is an epimorphism when `h` is an epimorphism. In general this does not imply that `imageSubobject (h ≫ f) = imageSubobject f`, diff --git a/Mathlib/CategoryTheory/Subobject/MonoOver.lean b/Mathlib/CategoryTheory/Subobject/MonoOver.lean index 4236e96df2512..e2cfc4d68b330 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. -/ @@ -219,13 +219,11 @@ end Pullback section Map -attribute [instance] mono_comp - /-- We can map monomorphisms over `X` to monomorphisms over `Y` by post-composition with a monomorphism `f : X ⟶ Y`. -/ def map (f : X ⟶ Y) [Mono f] : MonoOver X ⥤ MonoOver Y := - lift (Over.map f) fun g => by apply mono_comp g.arrow f + lift (Over.map f) fun g => mono_comp g.arrow f /-- `MonoOver.map` commutes with composition (up to a natural isomorphism). -/ def mapComp (f : X ⟶ Y) (g : Y ⟶ Z) [Mono f] [Mono g] : map (f ≫ g) ≅ map f ⋙ map g := diff --git a/Mathlib/CategoryTheory/Subobject/Types.lean b/Mathlib/CategoryTheory/Subobject/Types.lean index 54ebdb2816d00..cb2e06f94b8b1 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 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/Sums/Associator.lean b/Mathlib/CategoryTheory/Sums/Associator.lean index 884c130af1617..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 @@ -112,14 +112,14 @@ theorem inverseAssociator_map_inr_inr {X Y : E} (f : inr (inr X) ⟶ inr (inr Y) /-- The equivalence of categories expressing associativity of sums of categories. -/ -def associativity : (C ⊕ D) ⊕ E ≌ C ⊕ (D ⊕ E) := - Equivalence.mk (associator C D E) (inverseAssociator C D E) - (NatIso.ofComponents (fun X => eqToIso - (by rcases X with ((_|_)|_) <;> rfl)) -- Porting note: aesop_cat fails - (by rintro ((_|_)|_) ((_|_)|_) f <;> first | cases f | aesop_cat)) - (NatIso.ofComponents (fun X => eqToIso - (by rcases X with (_|(_|_)) <;> rfl)) -- Porting note: aesop_cat fails - (by rintro (_|(_|_)) (_|(_|_)) f <;> first | cases f | aesop_cat)) +@[simps functor inverse] +def associativity : (C ⊕ D) ⊕ E ≌ C ⊕ (D ⊕ E) where + functor := associator C D E + inverse := inverseAssociator C D E + unitIso := NatIso.ofComponents (by rintro ((_ | _) | _) <;> exact Iso.refl _) (by + rintro ((_ | _) | _) ((_ | _) | _) f <;> first | cases f | aesop_cat) + counitIso := NatIso.ofComponents (by rintro (_ | (_ | _)) <;> exact Iso.refl _) (by + rintro (_ | (_ | _)) (_ | (_ | _)) f <;> first | cases f | aesop_cat) instance associatorIsEquivalence : (associator C D E).IsEquivalence := (by infer_instance : (associativity C D E).functor.IsEquivalence) diff --git a/Mathlib/CategoryTheory/Sums/Basic.lean b/Mathlib/CategoryTheory/Sums/Basic.lean index aaf7e878026f5..51c5a75bafa70 100644 --- a/Mathlib/CategoryTheory/Sums/Basic.lean +++ b/Mathlib/CategoryTheory/Sums/Basic.lean @@ -1,9 +1,9 @@ /- -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.EqToHom +import Mathlib.CategoryTheory.Equivalence /-! # Binary disjoint unions of categories @@ -31,7 +31,7 @@ section variable (C : Type u₁) [Category.{v₁} C] (D : Type u₁) [Category.{v₁} D] -/- Porting note: `aesop_cat` not firing on `assoc` where autotac in Lean 3 did-/ +/- Porting note: `aesop_cat` not firing on `assoc` where autotac in Lean 3 did -/ /-- `sum C D` gives the direct sum of two categories. -/ @@ -129,10 +129,12 @@ theorem swap_map_inr {X Y : D} {f : inr X ⟶ inr Y} : (swap C D).map f = f := namespace Swap /-- `swap` gives an equivalence between `C ⊕ D` and `D ⊕ C`. -/ -def equivalence : C ⊕ D ≌ D ⊕ C := - Equivalence.mk (swap C D) (swap D C) - (NatIso.ofComponents (fun X => eqToIso (by cases X <;> rfl))) - (NatIso.ofComponents (fun X => eqToIso (by cases X <;> rfl))) +@[simps functor inverse] +def equivalence : C ⊕ D ≌ D ⊕ C where + functor := swap C D + inverse := swap D C + unitIso := NatIso.ofComponents (by rintro (_|_) <;> exact Iso.refl _) + counitIso := NatIso.ofComponents (by rintro (_|_) <;> exact Iso.refl _) instance isEquivalence : (swap C D).IsEquivalence := (by infer_instance : (equivalence C D).functor.IsEquivalence) 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 230768841d930..9507a7937e954 100644 --- a/Mathlib/CategoryTheory/Triangulated/Functor.lean +++ b/Mathlib/CategoryTheory/Triangulated/Functor.lean @@ -71,8 +71,12 @@ 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. -/ -@[simps!] noncomputable def mapTriangleCommShiftIso (n : ℤ) : Triangle.shiftFunctor C n ⋙ F.mapTriangle ≅ F.mapTriangle ⋙ Triangle.shiftFunctor D n := NatIso.ofComponents (fun T => Triangle.isoMk _ _ @@ -85,6 +89,8 @@ noncomputable def mapTriangleCommShiftIso (n : ℤ) : simp only [comp_obj, assoc, Iso.inv_hom_id_app_assoc, ← Functor.map_comp, Iso.inv_hom_id_app, map_id, comp_id])) (by aesop_cat) +attribute [simps!] mapTriangleCommShiftIso + attribute [local simp] map_zsmul comp_zsmul zsmul_comp commShiftIso_zero commShiftIso_add commShiftIso_comp_hom_app shiftFunctorAdd'_eq_shiftFunctorAdd @@ -304,6 +310,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..3b6c664323762 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 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 3d97552da7183..39ec3c60ebdb1 100644 --- a/Mathlib/CategoryTheory/Triangulated/Yoneda.lean +++ b/Mathlib/CategoryTheory/Triangulated/Yoneda.lean @@ -17,14 +17,20 @@ functors `preadditiveCoyoneda.obj A : C ⥤ AddCommGrp` for `A : Cᵒᵖ` and -/ +open CategoryTheory Limits + +variable {C : Type*} [Category C] [Preadditive C] [HasShift C ℤ] + namespace CategoryTheory open Limits Pretriangulated.Opposite namespace Pretriangulated -variable {C : Type*} [Category C] [Preadditive C] [HasZeroObject C] [HasShift C ℤ] - [∀ (n : ℤ), (shiftFunctor C n).Additive] [Pretriangulated C] +section + +variable [HasZeroObject C] [∀ (n : ℤ), (shiftFunctor C n).Additive] + [Pretriangulated C] instance (A : Cᵒᵖ) : (preadditiveCoyoneda.obj A).IsHomological where exact T hT := by @@ -45,12 +51,13 @@ lemma preadditiveYoneda_map_distinguished ((shortComplexOfDistTriangle T hT).op.map (preadditiveYoneda.obj B)).Exact := (preadditiveYoneda.obj B).map_distinguished_op_exact T hT +end + noncomputable instance (A : Cᵒᵖ) : (preadditiveCoyoneda.obj A).ShiftSequence ℤ := Functor.ShiftSequence.tautological _ _ lemma preadditiveCoyoneda_homologySequenceδ_apply - {C : Type*} [Category C] [Preadditive C] [HasShift C ℤ] - (A : Cᵒᵖ) (T : Triangle C) (n₀ n₁ : ℤ) (h : n₀ + 1 = n₁) (x : A.unop ⟶ T.obj₃⟦n₀⟧) : + (T : Triangle C) (n₀ n₁ : ℤ) (h : n₀ + 1 = n₁) {A : Cᵒᵖ} (x : A.unop ⟶ T.obj₃⟦n₀⟧) : (preadditiveCoyoneda.obj A).homologySequenceδ T n₀ n₁ h x = x ≫ T.mor₃⟦n₀⟧' ≫ (shiftFunctorAdd' C 1 n₀ n₁ (by omega)).inv.app _ := by apply Category.assoc diff --git a/Mathlib/CategoryTheory/Types.lean b/Mathlib/CategoryTheory/Types.lean index 900107d6da37e..b2b29e06f39d9 100644 --- a/Mathlib/CategoryTheory/Types.lean +++ b/Mathlib/CategoryTheory/Types.lean @@ -1,12 +1,12 @@ /- -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 import Mathlib.Tactic.PPWithUniv -import Mathlib.Data.Set.Defs +import Mathlib.Data.Set.Operations /-! # The category `Type`. 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 9f60d4fe54f36..e225caffbde77 100644 --- a/Mathlib/CategoryTheory/Widesubcategory.lean +++ b/Mathlib/CategoryTheory/Widesubcategory.lean @@ -83,7 +83,7 @@ Structure for wide subcategories. Objects ignore the morphism property. -/ @[ext, nolint unusedArguments] structure WideSubcategory (_P : MorphismProperty C) [IsMultiplicative _P] where - /-- The category of which this is a wide subcategory-/ + /-- The category of which this is a wide subcategory -/ obj : C instance WideSubcategory.category : Category.{v₁} (WideSubcategory P) := diff --git a/Mathlib/CategoryTheory/WithTerminal.lean b/Mathlib/CategoryTheory/WithTerminal.lean index ddf52325b64cf..3c35d0efb590e 100644 --- a/Mathlib/CategoryTheory/WithTerminal.lean +++ b/Mathlib/CategoryTheory/WithTerminal.lean @@ -70,6 +70,7 @@ def Hom : WithTerminal C → WithTerminal C → Type v | of X, of Y => X ⟶ Y | star, of _ => PEmpty | _, star => PUnit +attribute [nolint simpNF] Hom.eq_3 /-- Identity morphisms for `WithTerminal C`. -/ @[simp] @@ -85,6 +86,8 @@ def comp : ∀ {X Y Z : WithTerminal C}, Hom X Y → Hom Y Z → Hom X Z | star, of _X, _ => fun f _g => PEmpty.elim f | _, star, of _Y => fun _f g => PEmpty.elim g | star, star, star => fun _ _ => PUnit.unit +attribute [nolint simpNF] comp.eq_3 +attribute [nolint simpNF] comp.eq_4 instance : Category.{v} (WithTerminal C) where Hom X Y := Hom X Y @@ -371,6 +374,7 @@ def Hom : WithInitial C → WithInitial C → Type v | of X, of Y => X ⟶ Y | of _, _ => PEmpty | star, _ => PUnit +attribute [nolint simpNF] Hom.eq_2 /-- Identity morphisms for `WithInitial C`. -/ @[simp] @@ -386,6 +390,8 @@ def comp : ∀ {X Y Z : WithInitial C}, Hom X Y → Hom Y Z → Hom X Z | _, of _X, star => fun _f g => PEmpty.elim g | of _Y, star, _ => fun f _g => PEmpty.elim f | star, star, star => fun _ _ => PUnit.unit +attribute [nolint simpNF] comp.eq_3 +attribute [nolint simpNF] comp.eq_4 instance : Category.{v} (WithInitial C) where Hom X Y := Hom X Y @@ -448,7 +454,7 @@ def mapComp {D E : Type*} [Category D] [Category E] (F : C ⥤ D) (G : D ⥤ E) | of x => Iso.refl _ | star => Iso.refl _) (by aesop_cat) -/-- From a natrual transformation of functors `C ⥤ D`, the induced natural transformation +/-- From a natural transformation of functors `C ⥤ D`, the induced natural transformation of functors `WithInitial C ⥤ WithInitial D`. -/ @[simps] def map₂ {D : Type*} [Category D] {F G : C ⥤ D} (η : F ⟶ G) : map F ⟶ map G where diff --git a/Mathlib/CategoryTheory/Yoneda.lean b/Mathlib/CategoryTheory/Yoneda.lean index f3cbf94ce4ae3..f06afc7170c1c 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₁ u₁ u₂ -- morphism levels before object levels. See note [CategoryTheory universes]. variable {C : Type u₁} [Category.{v₁} C] @@ -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 + +lemma RepresentableBy.isRepresentable {F : Cᵒᵖ ⥤ Type v} {Y : C} (e : F.RepresentableBy Y) : + F.IsRepresentable where + has_representation := ⟨Y, ⟨e⟩⟩ -instance {X : C} : Representable (yoneda.obj X) where has_representation := ⟨X, ⟨Iso.refl _⟩⟩ +/-- 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 + +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ᵒᵖ} : Corepresentable (coyoneda.obj X) where - has_corepresentation := ⟨X, ⟨Iso.refl _⟩⟩ +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 (𝟙 _) -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] +/-- 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_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 @@ -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 @@ -481,6 +628,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 diff --git a/Mathlib/Combinatorics/Additive/AP/Three/Behrend.lean b/Mathlib/Combinatorics/Additive/AP/Three/Behrend.lean index ad0a9bc39e113..076f7c450bcde 100644 --- a/Mathlib/Combinatorics/Additive/AP/Three/Behrend.lean +++ b/Mathlib/Combinatorics/Additive/AP/Three/Behrend.lean @@ -278,12 +278,12 @@ theorem log_two_mul_two_le_sqrt_log_eight : log 2 * 2 ≤ √(log 8) := by apply le_sqrt_of_sq_le rw [mul_pow, sq (log 2), mul_assoc, mul_comm] refine mul_le_mul_of_nonneg_right ?_ (log_nonneg one_le_two) - rw [← le_div_iff] + rw [← le_div_iff₀] on_goal 1 => apply log_two_lt_d9.le.trans all_goals norm_num1 theorem two_div_one_sub_two_div_e_le_eight : 2 / (1 - 2 / exp 1) ≤ 8 := by - rw [div_le_iff, mul_sub, mul_one, mul_div_assoc', le_sub_comm, div_le_iff (exp_pos _)] + rw [div_le_iff₀, mul_sub, mul_one, mul_div_assoc', le_sub_comm, div_le_iff₀ (exp_pos _)] · have : 16 < 6 * (2.7182818283 : ℝ) := by norm_num linarith [exp_one_gt_d9] rw [sub_pos, div_lt_one] <;> exact exp_one_gt_d9.trans' (by norm_num) @@ -304,7 +304,7 @@ theorem le_sqrt_log (hN : 4096 ≤ N) : log (2 / (1 - 2 / exp 1)) * (69 / 50) apply le_sqrt_of_sq_le (le_trans _ this) rw [mul_right_comm, mul_pow, sq (log 2), ← mul_assoc] apply mul_le_mul_of_nonneg_right _ (log_nonneg one_le_two) - rw [← le_div_iff'] + rw [← le_div_iff₀'] · exact log_two_lt_d9.le.trans (by norm_num1) exact sq_pos_of_ne_zero (by norm_num1) @@ -315,7 +315,7 @@ theorem exp_neg_two_mul_le {x : ℝ} (hx : 0 < x) : exp (-2 * x) < exp (2 - ⌈x _ ≤ exp (1 - x) / (x + 1) := ?_ _ ≤ exp (2 - ⌈x⌉₊) / (x + 1) := by gcongr _ < _ := by gcongr - rw [le_div_iff (add_pos hx zero_lt_one), ← le_div_iff' (exp_pos _), ← exp_sub, neg_mul, + rw [le_div_iff₀ (add_pos hx zero_lt_one), ← le_div_iff₀' (exp_pos _), ← exp_sub, neg_mul, sub_neg_eq_add, two_mul, sub_add_add_cancel, add_comm _ x] exact le_trans (le_add_of_nonneg_right zero_le_one) (add_one_le_exp _) @@ -325,7 +325,7 @@ theorem div_lt_floor {x : ℝ} (hx : 2 / (1 - 2 / exp 1) ≤ x) : x / exp 1 < ( rw [sub_pos, div_lt_one (exp_pos _)] exact lt_of_le_of_lt (by norm_num) exp_one_gt_d9 rwa [le_sub_comm, div_eq_mul_one_div x, div_eq_mul_one_div x, ← mul_sub, div_sub', ← - div_eq_mul_one_div, mul_div_assoc', one_le_div, ← div_le_iff this] + div_eq_mul_one_div, mul_div_assoc', one_le_div, ← div_le_iff₀ this] · exact zero_lt_two · exact two_ne_zero @@ -356,14 +356,14 @@ 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 theorem dValue_pos (hN₃ : 8 ≤ N) : 0 < dValue N := by have hN₀ : 0 < (N : ℝ) := cast_pos.2 (succ_pos'.trans_le hN₃) rw [dValue, floor_pos, ← log_le_log_iff zero_lt_one, log_one, log_div _ two_ne_zero, log_rpow hN₀, - inv_mul_eq_div, sub_nonneg, le_div_iff] + inv_mul_eq_div, sub_nonneg, le_div_iff₀] · have : (nValue N : ℝ) ≤ 2 * √(log N) := by apply (ceil_lt_add_one <| sqrt_nonneg _).le.trans rw [two_mul, add_le_add_iff_left] @@ -371,7 +371,7 @@ theorem dValue_pos (hN₃ : 8 ≤ N) : 0 < dValue N := by rw [one_pow, le_log_iff_exp_le hN₀] exact (exp_one_lt_d9.le.trans <| by norm_num).trans (cast_le.2 hN₃) apply (mul_le_mul_of_nonneg_left this <| log_nonneg one_le_two).trans _ - rw [← mul_assoc, ← le_div_iff (Real.sqrt_pos.2 <| log_pos <| one_lt_cast.2 _), div_sqrt] + rw [← mul_assoc, ← le_div_iff₀ (Real.sqrt_pos.2 <| log_pos <| one_lt_cast.2 _), div_sqrt] · apply log_two_mul_two_le_sqrt_log_eight.trans apply Real.sqrt_le_sqrt exact log_le_log (by norm_num) (mod_cast hN₃) @@ -391,7 +391,7 @@ theorem le_N (hN : 2 ≤ N) : (2 * dValue N - 1) ^ nValue N ≤ N := by rw [← rpow_mul (cast_nonneg _), inv_mul_cancel₀, rpow_one] rw [cast_ne_zero] apply (nValue_pos hN).ne' - rw [← le_div_iff'] + rw [← le_div_iff₀'] · exact floor_le (div_nonneg (rpow_nonneg (cast_nonneg _) _) zero_le_two) apply zero_lt_two @@ -399,7 +399,7 @@ theorem bound (hN : 4096 ≤ N) : (N : ℝ) ^ (nValue N : ℝ)⁻¹ / exp 1 < dV apply div_lt_floor _ rw [← log_le_log_iff, log_rpow, mul_comm, ← div_eq_mul_inv] · apply le_trans _ (div_le_div_of_nonneg_left _ _ (ceil_lt_mul _).le) - · rw [mul_comm, ← div_div, div_sqrt, le_div_iff] + · rw [mul_comm, ← div_div, div_sqrt, le_div_iff₀] · norm_num; exact le_sqrt_log hN · norm_num1 · apply log_nonneg @@ -414,7 +414,7 @@ theorem bound (hN : 4096 ≤ N) : (N : ℝ) ^ (nValue N : ℝ)⁻¹ / exp 1 < dV rw [← log_rpow zero_lt_two, rpow_natCast] exact log_le_log (by positivity) (mod_cast hN) refine le_trans ?_ this - rw [← div_le_iff'] + rw [← div_le_iff₀'] · exact log_two_gt_d9.le.trans' (by norm_num1) · norm_num1 · rw [cast_pos] @@ -448,8 +448,8 @@ theorem roth_lower_bound_explicit (hN : 4096 ≤ N) : rw [this] refine mul_le_mul ?_ (exp_neg_two_mul_le <| Real.sqrt_pos.2 <| log_pos ?_).le (exp_pos _).le <| rpow_nonneg (cast_nonneg _) _ - · rw [← le_log_iff_exp_le (rpow_pos_of_pos hN₀ _), log_rpow hN₀, ← le_div_iff, mul_div_assoc, - div_sqrt, neg_mul, neg_le_neg_iff, div_mul_eq_mul_div, div_le_iff hn] + · rw [← le_log_iff_exp_le (rpow_pos_of_pos hN₀ _), log_rpow hN₀, ← le_div_iff₀, mul_div_assoc, + div_sqrt, neg_mul, neg_le_neg_iff, div_mul_eq_mul_div, div_le_iff₀ hn] · exact mul_le_mul_of_nonneg_left (le_ceil _) zero_le_two refine Real.sqrt_pos.2 (log_pos ?_) rw [one_lt_cast] @@ -459,7 +459,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 @@ -474,7 +474,7 @@ theorem lower_bound_le_one' (hN : 2 ≤ N) (hN' : N ≤ 4096) : rw [← log_le_log_iff (mul_pos (cast_pos.2 (zero_lt_two.trans_le hN)) (exp_pos _)) zero_lt_one, log_one, log_mul (cast_pos.2 (zero_lt_two.trans_le hN)).ne' (exp_pos _).ne', log_exp, neg_mul, ← sub_eq_add_neg, sub_nonpos, ← - div_le_iff (Real.sqrt_pos.2 <| log_pos <| one_lt_cast.2 <| one_lt_two.trans_le hN), div_sqrt, + div_le_iff₀ (Real.sqrt_pos.2 <| log_pos <| one_lt_cast.2 <| one_lt_two.trans_le hN), div_sqrt, sqrt_le_left zero_le_four, log_le_iff_le_exp (cast_pos.2 (zero_lt_two.trans_le hN))] norm_num1 apply le_trans _ four_zero_nine_six_lt_exp_sixteen.le diff --git a/Mathlib/Combinatorics/Additive/AP/Three/Defs.lean b/Mathlib/Combinatorics/Additive/AP/Three/Defs.lean index 0046f90cc5f9e..213220d6ea296 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*} @@ -103,18 +103,18 @@ end Monoid section CommMonoid variable [CommMonoid α] [CommMonoid β] {s A : Set α} {t B : Set β} {f : α → β} {a : α} -/-- Arithmetic progressions of length three are preserved under `2`-Freiman homomorphisms. -/ +/-- Geometric progressions of length three are reflected under `2`-Freiman homomorphisms. -/ @[to_additive -"Arithmetic progressions of length three are preserved under `2`-Freiman homomorphisms."] +"Arithmetic progressions of length three are reflected under `2`-Freiman homomorphisms."] lemma ThreeGPFree.of_image (hf : IsMulFreimanHom 2 s t f) (hf' : s.InjOn f) (hAs : A ⊆ s) (hA : ThreeGPFree (f '' A)) : ThreeGPFree A := fun _ ha _ hb _ hc habc ↦ hf' (hAs ha) (hAs hb) <| hA (mem_image_of_mem _ ha) (mem_image_of_mem _ hb) (mem_image_of_mem _ hc) <| hf.mul_eq_mul (hAs ha) (hAs hc) (hAs hb) (hAs hb) habc -/-- Arithmetic progressions of length three are preserved under `2`-Freiman isomorphisms. -/ +/-- Geometric progressions of length three are unchanged under `2`-Freiman isomorphisms. -/ @[to_additive -"Arithmetic progressions of length three are preserved under `2`-Freiman isomorphisms."] +"Arithmetic progressions of length three are unchanged under `2`-Freiman isomorphisms."] lemma threeGPFree_image (hf : IsMulFreimanIso 2 s t f) (hAs : A ⊆ s) : ThreeGPFree (f '' A) ↔ ThreeGPFree A := by rw [ThreeGPFree, ThreeGPFree] @@ -125,25 +125,23 @@ lemma threeGPFree_image (hf : IsMulFreimanIso 2 s t f) (hAs : A ⊆ s) : @[to_additive] alias ⟨_, ThreeGPFree.image⟩ := threeGPFree_image -/-- Arithmetic progressions of length three are preserved under `2`-Freiman homomorphisms. -/ -@[to_additive] +/-- Geometric progressions of length three are reflected under `2`-Freiman homomorphisms. -/ +@[to_additive +"Arithmetic progressions of length three are reflected under `2`-Freiman homomorphisms."] lemma IsMulFreimanHom.threeGPFree (hf : IsMulFreimanHom 2 s t f) (hf' : s.InjOn f) (ht : ThreeGPFree t) : ThreeGPFree s := - fun _ ha _ hb _ hc habc ↦ hf' ha hb <| ht (hf.mapsTo ha) (hf.mapsTo hb) (hf.mapsTo hc) <| - hf.mul_eq_mul ha hc hb hb habc + (ht.mono hf.mapsTo.image_subset).of_image hf hf' subset_rfl -/-- Arithmetic progressions of length three are preserved under `2`-Freiman isomorphisms. -/ -@[to_additive] +/-- Geometric progressions of length three are unchanged under `2`-Freiman isomorphisms. -/ +@[to_additive +"Arithmetic progressions of length three are unchanged under `2`-Freiman isomorphisms."] lemma IsMulFreimanIso.threeGPFree_congr (hf : IsMulFreimanIso 2 s t f) : - ThreeGPFree s ↔ ThreeGPFree t where - mpr := hf.isMulFreimanHom.threeGPFree hf.bijOn.injOn - mp hs a hfa b hfb c hfc habc := by - obtain ⟨a, ha, rfl⟩ := hf.bijOn.surjOn hfa - obtain ⟨b, hb, rfl⟩ := hf.bijOn.surjOn hfb - obtain ⟨c, hc, rfl⟩ := hf.bijOn.surjOn hfc - exact congr_arg f $ hs ha hb hc $ (hf.mul_eq_mul ha hc hb hb).1 habc + ThreeGPFree s ↔ ThreeGPFree t := by + rw [← threeGPFree_image hf subset_rfl, hf.bijOn.image_eq] -@[to_additive] +/-- Geometric progressions of length three are preserved under semigroup homomorphisms. -/ +@[to_additive +"Arithmetic progressions of length three are preserved under semigroup homomorphisms."] theorem ThreeGPFree.image' [FunLike F α β] [MulHomClass F α β] (f : F) (hf : (s * s).InjOn f) (h : ThreeGPFree s) : ThreeGPFree (f '' s) := by rintro _ ⟨a, ha, rfl⟩ _ ⟨b, hb, rfl⟩ _ ⟨c, hc, rfl⟩ habc @@ -155,7 +153,7 @@ section CancelCommMonoid variable [CancelCommMonoid α] {s : Set α} {a : α} -lemma ThreeGPFree.eq_right (hs : ThreeGPFree s) : +@[to_additive] lemma ThreeGPFree.eq_right (hs : ThreeGPFree s) : ∀ ⦃a⦄, a ∈ s → ∀ ⦃b⦄, b ∈ s → ∀ ⦃c⦄, c ∈ s → a * c = b * b → b = c := by rintro a ha b hb c hc habc obtain rfl := hs ha hb hc habc @@ -184,7 +182,7 @@ lemma ThreeGPFree.eq_right (hs : ThreeGPFree s) : @[to_additive] theorem ThreeGPFree.smul_set (hs : ThreeGPFree s) : ThreeGPFree (a • s) := by rintro _ ⟨b, hb, rfl⟩ _ ⟨c, hc, rfl⟩ _ ⟨d, hd, rfl⟩ h - exact congr_arg (a • ·) $ hs hb hc hd $ by simpa [mul_mul_mul_comm _ _ a] using h + exact congr_arg (a • ·) <| hs hb hc hd <| by simpa [mul_mul_mul_comm _ _ a] using h @[to_additive] lemma threeGPFree_smul_set : ThreeGPFree (a • s) ↔ ThreeGPFree s where mp hs b hb c hc d hd h := mul_left_cancel @@ -214,7 +212,7 @@ variable [CancelCommMonoidWithZero α] [NoZeroDivisors α] {s : Set α} {a : α} lemma ThreeGPFree.smul_set₀ (hs : ThreeGPFree s) (ha : a ≠ 0) : ThreeGPFree (a • s) := by rintro _ ⟨b, hb, rfl⟩ _ ⟨c, hc, rfl⟩ _ ⟨d, hd, rfl⟩ h - exact congr_arg (a • ·) $ hs hb hc hd $ by simpa [mul_mul_mul_comm _ _ a, ha] using h + exact congr_arg (a • ·) <| hs hb hc hd <| by simpa [mul_mul_mul_comm _ _ a, ha] using h theorem threeGPFree_smul_set₀ (ha : a ≠ 0) : ThreeGPFree (a • s) ↔ ThreeGPFree s := ⟨fun hs b hb c hc d hd h ↦ @@ -275,7 +273,7 @@ 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⟩ + Nat.le_findGreatest (card_le_card h) ⟨s, h, rfl, hs⟩ @[to_additive] theorem ThreeGPFree.mulRothNumber_eq (hs : ThreeGPFree (s : Set α)) : @@ -441,7 +439,7 @@ theorem addRothNumber_Ico (a b : ℕ) : addRothNumber (Ico a b) = rothNumberNat lemma Fin.addRothNumber_eq_rothNumberNat (hkn : 2 * k ≤ n) : addRothNumber (Iio k : Finset (Fin n.succ)) = rothNumberNat k := - IsAddFreimanIso.addRothNumber_congr $ mod_cast isAddFreimanIso_Iio two_ne_zero hkn + IsAddFreimanIso.addRothNumber_congr <| mod_cast isAddFreimanIso_Iio two_ne_zero hkn lemma Fin.addRothNumber_le_rothNumberNat (k n : ℕ) (hkn : k ≤ n) : addRothNumber (Iio k : Finset (Fin n.succ)) ≤ rothNumberNat k := by diff --git a/Mathlib/Combinatorics/Additive/Corner/Defs.lean b/Mathlib/Combinatorics/Additive/Corner/Defs.lean index e9cd2b2dd2ed4..08295c48887f6 100644 --- a/Mathlib/Combinatorics/Additive/Corner/Defs.lean +++ b/Mathlib/Combinatorics/Additive/Corner/Defs.lean @@ -55,7 +55,7 @@ lemma IsCorner.mono (hAB : A ⊆ B) (hA : IsCorner A x₁ y₁ x₂ y₂) : IsCo add_eq_add := hA.add_eq_add lemma IsCornerFree.mono (hAB : A ⊆ B) (hB : IsCornerFree B) : IsCornerFree A := - fun _x₁ _y₁ _x₂ _y₂ hxyd ↦ hB $ hxyd.mono hAB + fun _x₁ _y₁ _x₂ _y₂ hxyd ↦ hB <| hxyd.mono hAB @[simp] lemma not_isCorner_empty : ¬ IsCorner ∅ x₁ y₁ x₂ y₂ := by simp [isCorner_iff] @@ -76,7 +76,7 @@ lemma IsCorner.image (hf : IsAddFreimanHom 2 s t f) (hAs : (A : Set (G × G)) lemma IsCornerFree.of_image (hf : IsAddFreimanHom 2 s t f) (hf' : s.InjOn f) (hAs : (A : Set (G × G)) ⊆ s ×ˢ s) (hA : IsCornerFree (Prod.map f f '' A)) : IsCornerFree A := fun _x₁ _y₁ _x₂ _y₂ hxy ↦ - hf' (hAs hxy.fst_fst_mem).1 (hAs hxy.snd_fst_mem).1 $ hA $ hxy.image hf hAs + hf' (hAs hxy.fst_fst_mem).1 (hAs hxy.snd_fst_mem).1 <| hA <| hxy.image hf hAs lemma isCorner_image (hf : IsAddFreimanIso 2 s t f) (hAs : A ⊆ s ×ˢ s) (hx₁ : x₁ ∈ s) (hy₁ : y₁ ∈ s) (hx₂ : x₂ ∈ s) (hy₂ : y₂ ∈ s) : diff --git a/Mathlib/Combinatorics/Additive/Corner/Roth.lean b/Mathlib/Combinatorics/Additive/Corner/Roth.lean index cc3a7145d5a4d..73840313536fa 100644 --- a/Mathlib/Combinatorics/Additive/Corner/Roth.lean +++ b/Mathlib/Combinatorics/Additive/Corner/Roth.lean @@ -53,7 +53,7 @@ private lemma noAccidental (hs : IsCornerFree (A : Set (G × G))) : NoAccidental (triangleIndices A) where eq_or_eq_or_eq a a' b b' c c' ha hb hc := by simp only [mk_mem_triangleIndices] at ha hb hc - exact .inl $ hs ⟨hc.1, hb.1, ha.1, hb.2.symm.trans ha.2⟩ + 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) : (graph <| triangleIndices A).FarFromTriangleFree (ε / 9) := by @@ -88,7 +88,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 @@ -96,7 +96,7 @@ theorem corners_theorem (ε : ℝ) (hε : 0 < ε) (hG : cornersTheoremBound ε classical have h₁ := (farFromTriangleFree_graph hAε).le_card_cliqueFinset rw [card_triangles, card_triangleIndices] at h₁ - convert h₁.trans (Nat.cast_le.2 $ card_le_univ _) using 1 <;> simp <;> ring + convert h₁.trans (Nat.cast_le.2 <| card_le_univ _) using 1 <;> simp <;> ring /-- The **corners theorem** for `ℕ`. @@ -118,8 +118,8 @@ theorem corners_theorem_nat (hε : 0 < ε) (hn : cornersTheoremBound (ε / 9) omega rw [this] at hA have := Fin.isAddFreimanIso_Iio two_ne_zero (le_refl (2 * n)) - have := hA.of_image this.isAddFreimanHom Fin.val_injective.injOn $ by - refine Set.image_subset_iff.2 $ hAn.trans fun x hx ↦ ?_ + have := hA.of_image this.isAddFreimanHom Fin.val_injective.injOn <| by + refine Set.image_subset_iff.2 <| hAn.trans fun x hx ↦ ?_ simp only [coe_range, Set.mem_prod, Set.mem_Iio] at hx exact ⟨Fin.natCast_strictMono (by omega) hx.1, Fin.natCast_strictMono (by omega) hx.2⟩ rw [← coe_image] at this @@ -155,10 +155,10 @@ theorem roth_3ap_theorem (ε : ℝ) (hε : 0 < ε) (hG : cornersTheoremBound ε ∃ x₁ y₁ x₂ y₂, y₁ - x₁ ∈ A ∧ y₂ - x₁ ∈ A ∧ y₁ - x₂ ∈ A ∧ x₁ + y₂ = x₂ + y₁ ∧ x₁ ≠ x₂ := by simpa [IsCornerFree, isCorner_iff, B, -exists_and_left, -exists_and_right] using corners_theorem ε hε hG B this - have := hA hx₂y₁ hx₁y₁ hx₁y₂ $ by -- TODO: This really ought to just be `by linear_combination h` + have := hA hx₂y₁ hx₁y₁ hx₁y₂ <| by -- TODO: This really ought to just be `by linear_combination h` rw [sub_add_sub_comm, add_comm, add_sub_add_comm, add_right_cancel_iff, sub_eq_sub_iff_add_eq_add, add_comm, hxy, add_comm] - exact hx₁x₂ $ by simpa using this.symm + exact hx₁x₂ <| by simpa using this.symm /-- **Roth's theorem** for `ℕ`. @@ -176,8 +176,8 @@ theorem roth_3ap_theorem_nat (ε : ℝ) (hε : 0 < ε) (hG : cornersTheoremBound omega rw [this] at hA have := Fin.isAddFreimanIso_Iio two_ne_zero (le_refl (2 * n)) - have := hA.of_image this.isAddFreimanHom Fin.val_injective.injOn $ Set.image_subset_iff.2 $ - hAn.trans fun x hx ↦ Fin.natCast_strictMono (by omega) $ by + have := hA.of_image this.isAddFreimanHom Fin.val_injective.injOn <| Set.image_subset_iff.2 <| + hAn.trans fun x hx ↦ Fin.natCast_strictMono (by omega) <| by simpa only [coe_range, Set.mem_Iio] using hx rw [← coe_image] at this refine roth_3ap_theorem (ε / 3) (by positivity) (by simp; omega) _ ?_ this @@ -188,7 +188,7 @@ theorem roth_3ap_theorem_nat (ε : ℝ) (hε : 0 < ε) (hG : cornersTheoremBound _ ≤ A.card := hAε _ = _ := by rw [card_image_of_injOn] - exact (CharP.natCast_injOn_Iio (Fin (2 * n).succ) (2 * n).succ).mono $ hAn.trans $ by + exact (CharP.natCast_injOn_Iio (Fin (2 * n).succ) (2 * n).succ).mono <| hAn.trans <| by simp; omega open Asymptotics Filter diff --git a/Mathlib/Combinatorics/Additive/Dissociation.lean b/Mathlib/Combinatorics/Additive/Dissociation.lean index 153c28f9d1b21..f22b05d75f55d 100644 --- a/Mathlib/Combinatorics/Additive/Dissociation.lean +++ b/Mathlib/Combinatorics/Additive/Dissociation.lean @@ -4,9 +4,9 @@ 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.Basic import Mathlib.Algebra.Group.Units.Equiv import Mathlib.Data.Fintype.Card -import Mathlib.Data.Set.Pointwise.Basic /-! # Dissociation and span @@ -39,7 +39,7 @@ def MulDissociated (s : Set α) : Prop := {t : Finset α | ↑t ⊆ s}.InjOn ( @[to_additive] lemma mulDissociated_iff_sum_eq_subsingleton : MulDissociated s ↔ ∀ a, {t : Finset α | ↑t ⊆ s ∧ ∏ x in t, x = a}.Subsingleton := - ⟨fun hs _ _t ht _u hu ↦ hs ht.1 hu.1 $ ht.2.trans hu.2.symm, + ⟨fun hs _ _t ht _u hu ↦ hs ht.1 hu.1 <| ht.2.trans hu.2.symm, fun hs _t ht _u hu htu ↦ hs _ ⟨ht, htu⟩ ⟨hu, rfl⟩⟩ @[to_additive] lemma MulDissociated.subset {t : Set α} (hst : s ⊆ t) (ht : MulDissociated t) : @@ -137,13 +137,13 @@ lemma exists_subset_mulSpan_card_le_of_forall_mulDissociated by_cases ha' : a ∈ s' · exact subset_mulSpan ha' obtain ⟨t, u, ht, hu, htu⟩ := not_mulDissociated_iff_exists_disjoint.1 fun h ↦ - hs'max _ (insert_subset_iff.2 ⟨ha, hs'.1⟩) h $ ssubset_insert ha' + hs'max _ (insert_subset_iff.2 ⟨ha, hs'.1⟩) h <| ssubset_insert ha' by_cases hat : a ∈ t · have : a = (∏ b in u, b) / ∏ b in t.erase a, b := by rw [prod_erase_eq_div hat, htu.2.2, div_div_self'] rw [this] exact prod_div_prod_mem_mulSpan - ((subset_insert_iff_of_not_mem $ disjoint_left.1 htu.1 hat).1 hu) (subset_insert_iff.1 ht) + ((subset_insert_iff_of_not_mem <| disjoint_left.1 htu.1 hat).1 hu) (subset_insert_iff.1 ht) rw [coe_subset, subset_insert_iff_of_not_mem hat] at ht by_cases hau : a ∈ u · have : a = (∏ b in t, b) / ∏ b in u.erase a, b := by diff --git a/Mathlib/Combinatorics/Additive/DoublingConst.lean b/Mathlib/Combinatorics/Additive/DoublingConst.lean new file mode 100644 index 0000000000000..f9f65e418d246 --- /dev/null +++ b/Mathlib/Combinatorics/Additive/DoublingConst.lean @@ -0,0 +1,215 @@ +/- +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.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 + +This file defines the doubling and difference constants of two finsets in a group. +-/ + +open Finset +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|`. + +The notation `σₘ[A, B]` is available in scope `Combinatorics.Additive`. -/ +@[to_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 + +/-- 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`. -/ +@[to_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 + +/-- 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 + +/-- The doubling constant `σₘ[A]` of a finset `A` in a group is `|A * A| / |A|`. -/ +scoped[Combinatorics.Additive] notation3:max "σₘ[" A "]" => Finset.mulConst A 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.addConst A B + +/-- The doubling constant `σ[A]` of a finset `A` in a group is `|A + A| / |A|`. -/ +scoped[Combinatorics.Additive] notation3:max "σ[" A "]" => Finset.addConst A A + +/-- The difference constant `σₘ[A, B]` of two finsets `A` and `B` in a group is `|A / B| / |A|`. -/ +scoped[Combinatorics.Additive] notation3:max "δₘ[" A ", " B "]" => Finset.divConst A B + +/-- The difference constant `σₘ[A]` of a finset `A` in a group is `|A / A| / |A|`. -/ +scoped[Combinatorics.Additive] notation3:max "δₘ[" A "]" => Finset.divConst A A + +/-- The difference constant `σ[A, B]` of two finsets `A` and `B` in a group is `|A - B| / |A|`. -/ +scoped[Combinatorics.Additive] notation3:max "δ[" A ", " B "]" => Finset.subConst A B + +/-- The difference constant `σ[A]` of a finset `A` in a group is `|A - A| / |A|`. -/ +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 + 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 + 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 + 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 + rw [mul_comm, divConst_mul_card] + +@[to_additive (attr := simp)] +lemma mulConst_empty_left (B : Finset G) : σₘ[∅, B] = 0 := by simp [mulConst] + +@[to_additive (attr := simp)] +lemma divConst_empty_left (B : Finset G) : δₘ[∅, B] = 0 := by simp [divConst] + +@[to_additive (attr := simp)] +lemma mulConst_empty_right (A : Finset G) : σₘ[A, ∅] = 0 := by simp [mulConst] + +@[to_additive (attr := simp)] +lemma divConst_empty_right (A : Finset G) : δₘ[A, ∅] = 0 := by simp [divConst] + +@[to_additive (attr := simp)] +lemma mulConst_inv_right (A B : Finset G) : σₘ[A, B⁻¹] = δₘ[A, B] := by + rw [mulConst, divConst, ← div_eq_mul_inv] + +@[to_additive (attr := simp)] +lemma divConst_inv_right (A B : Finset G) : δₘ[A, B⁻¹] = σₘ[A, B] := by + rw [mulConst, divConst, div_inv_eq_mul] + +section Fintype +variable [Fintype G] + +/-- Dense sets have small doubling. -/ +@[to_additive addConst_le_inv_dens "Dense sets have small doubling."] +lemma mulConst_le_inv_dens : σₘ[A, B] ≤ A.dens⁻¹ := by + rw [dens, inv_div, mulConst]; gcongr; exact card_le_univ _ + +/-- Dense sets have small difference constant. -/ +@[to_additive subConst_le_inv_dens "Dense sets have small difference constant."] +lemma divConst_le_inv_dens : δₘ[A, B] ≤ A.dens⁻¹ := by + rw [dens, inv_div, divConst]; gcongr; exact card_le_univ _ + +end Fintype + +variable {𝕜 : Type*} [Semifield 𝕜] [CharZero 𝕜] + +lemma cast_addConst (A B : Finset G') : (σ[A, B] : 𝕜) = (A + B).card / A.card := by + simp [addConst] + +lemma cast_subConst (A B : Finset G') : (δ[A, B] : 𝕜) = (A - B).card / A.card := by + simp [subConst] + +@[to_additive existing] +lemma cast_mulConst (A B : Finset G) : (σₘ[A, B] : 𝕜) = (A * B).card / A.card := 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_addConst_mul_card (A B : Finset G') : (σ[A, B] * A.card : 𝕜) = (A + B).card := by + norm_cast; exact addConst_mul_card _ _ + +lemma cast_subConst_mul_card (A B : Finset G') : (δ[A, B] * A.card : 𝕜) = (A - B).card := by + norm_cast; exact subConst_mul_card _ _ + +lemma card_mul_cast_addConst (A B : Finset G') : (A.card * σ[A, B] : 𝕜) = (A + B).card := by + norm_cast; exact card_mul_addConst _ _ + +lemma card_mul_cast_subConst (A B : Finset G') : (A.card * δ[A, B] : 𝕜) = (A - B).card := 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 + 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 + 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 + 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 + norm_cast; exact card_mul_divConst _ _ + +end Group + +open scoped Combinatorics.Additive + +section CommGroup +variable {G : Type*} [CommGroup G] [DecidableEq G] {A B : Finset G} {a : G} + +@[to_additive (attr := simp)] +lemma mulConst_inv_left (A B : Finset G) : σₘ[A⁻¹, B] = δₘ[A, B] := by + rw [mulConst, divConst, card_inv, ← card_inv, mul_inv_rev, inv_inv, inv_mul_eq_div] + +@[to_additive (attr := simp)] +lemma divConst_inv_left (A B : Finset G) : δₘ[A⁻¹, B] = σₘ[A, B] := by + rw [mulConst, divConst, card_inv, ← card_inv, inv_div, div_inv_eq_mul, mul_comm] + +/-- If `A` has small difference, then it has small doubling, with the constant squared. + +This is a consequence of the Ruzsa triangle inequality. -/ +@[to_additive +"If `A` has small difference, then it has small doubling, with the constant squared. + +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) + 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 .. + _ = _ := by rw [← divConst_mul_card]; ring + +/-- If `A` has small doubling, then it has small difference, with the constant squared. + +This is a consequence of the Ruzsa triangle inequality. -/ +@[to_additive +"If `A` has small doubling, then it has small difference, with the constant squared. + +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) + 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 .. + _ = _ := by rw [← mulConst_mul_card]; ring + +end CommGroup +end Finset 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 fdc2bce807bcc..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 @@ -132,7 +132,7 @@ variable {s t} @[to_additive] lemma mulEnergy_eq_sum_sq [Fintype α] (s t : Finset α) : Eₘ[s, t] = ∑ a, ((s ×ˢ t).filter fun (x, y) ↦ x * y = a).card ^ 2 := by rw [mulEnergy_eq_sum_sq'] - exact Fintype.sum_subset $ by aesop (add simp [filter_eq_empty_iff, mul_mem_mul]) + exact Fintype.sum_subset <| by aesop (add simp [filter_eq_empty_iff, mul_mem_mul]) @[to_additive card_sq_le_card_mul_addEnergy] lemma card_sq_le_card_mul_mulEnergy (s t u : Finset α) : @@ -164,7 +164,7 @@ variable [CommMonoid α] @[to_additive] lemma mulEnergy_comm (s t : Finset α) : Eₘ[s, t] = Eₘ[t, s] := by rw [mulEnergy, ← Finset.card_map (Equiv.prodComm _ _).toEmbedding, map_filter] - simp [-Finset.card_map, eq_comm, mulEnergy, mul_comm, map_eq_image, Function.comp] + simp [-Finset.card_map, eq_comm, mulEnergy, mul_comm, map_eq_image, Function.comp_def] end CommMonoid @@ -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 6359c2a1ca925..a3bad041f207e 100644 --- a/Mathlib/Combinatorics/Additive/ErdosGinzburgZiv.lean +++ b/Mathlib/Combinatorics/Additive/ErdosGinzburgZiv.lean @@ -67,14 +67,14 @@ private theorem ZMod.erdos_ginzburg_ziv_prime (a : ι → ZMod p) (hs : s.card = have hpN : p ∣ N := char_dvd_card_solutions_of_add_lt p (totalDegree_f₁_add_totalDegree_f₂.trans_eq hs') -- Hence, `2 ≤ p ≤ N` and we can make a common root `x ≠ 0`. - obtain ⟨x, hx⟩ := Fintype.exists_ne_of_one_lt_card ((Fact.out : p.Prime).one_lt.trans_le $ + 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⟩, ?_, ?_, ?_⟩ · 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] - refine Nat.eq_of_dvd_of_lt_two_mul (Finset.card_pos.2 ?_).ne' ?_ $ + refine Nat.eq_of_dvd_of_lt_two_mul (Finset.card_pos.2 ?_).ne' ?_ <| (Finset.card_filter_le _ _).trans_lt ?_ -- This number is nonzero because `x ≠ 0`. · rw [← Subtype.coe_ne_coe, Function.ne_iff] at hx @@ -135,11 +135,11 @@ theorem Int.erdos_ginzburg_ziv (a : ι → ℤ) (hs : 2 * n - 1 ≤ s.card) : -- `t ∈ ℬ` of `(∑ i ∈ t, a i) / n` is divisible by `m`. obtain ⟨ℬ, hℬ𝒜, hℬcard, hℬ⟩ := ihm (fun t ↦ (∑ i ∈ t, a i) / n) h𝒜card.ge -- We are done. - refine ⟨ℬ.biUnion fun x ↦ x, biUnion_subset.2 fun t ht ↦ (h𝒜 $ hℬ𝒜 ht).1, ?_, ?_⟩ - · rw [card_biUnion (h𝒜disj.mono hℬ𝒜), sum_const_nat fun t ht ↦ (h𝒜 $ hℬ𝒜 ht).2.1, hℬcard] + refine ⟨ℬ.biUnion fun x ↦ x, biUnion_subset.2 fun t ht ↦ (h𝒜 <| hℬ𝒜 ht).1, ?_, ?_⟩ + · rw [card_biUnion (h𝒜disj.mono hℬ𝒜), sum_const_nat fun t ht ↦ (h𝒜 <| hℬ𝒜 ht).2.1, hℬcard] rwa [sum_biUnion, natCast_mul, mul_comm, ← Int.dvd_div_iff_mul_dvd, Int.sum_div] - · exact fun t ht ↦ (h𝒜 $ hℬ𝒜 ht).2.2 - · exact dvd_sum fun t ht ↦ (h𝒜 $ hℬ𝒜 ht).2.2 + · exact fun t ht ↦ (h𝒜 <| hℬ𝒜 ht).2.2 + · exact dvd_sum fun t ht ↦ (h𝒜 <| hℬ𝒜 ht).2.2 · exact h𝒜disj.mono hℬ𝒜 -- Now, let's find those `2 * m - 1` sets. rintro k hk @@ -165,12 +165,12 @@ theorem Int.erdos_ginzburg_ziv (a : ι → ℤ) (hs : 2 * n - 1 ≤ s.card) : have : t₀ ∉ 𝒜 := by rintro h obtain rfl : n = 0 := by - simpa [← card_eq_zero, ht₀card] using sdiff_disjoint.mono ht₀ $ subset_biUnion_of_mem id h + simpa [← card_eq_zero, ht₀card] using sdiff_disjoint.mono ht₀ <| subset_biUnion_of_mem id h omega refine ⟨𝒜.cons t₀ this, by rw [card_cons, h𝒜card], ?_, ?_⟩ · simp only [cons_eq_insert, coe_insert, Set.pairwise_insert_of_symmetric symmetric_disjoint, mem_coe, ne_eq] - exact ⟨h𝒜disj, fun t ht _ ↦ sdiff_disjoint.mono ht₀ $ subset_biUnion_of_mem id ht⟩ + exact ⟨h𝒜disj, fun t ht _ ↦ sdiff_disjoint.mono ht₀ <| subset_biUnion_of_mem id ht⟩ · simp only [cons_eq_insert, mem_insert, forall_eq_or_imp, and_assoc] exact ⟨ht₀.trans sdiff_subset, ht₀card, ht₀sum, h𝒜⟩ diff --git a/Mathlib/Combinatorics/Additive/FreimanHom.lean b/Mathlib/Combinatorics/Additive/FreimanHom.lean index 3b9fd4e291330..01cf0ef4b01c3 100644 --- a/Mathlib/Combinatorics/Additive/FreimanHom.lean +++ b/Mathlib/Combinatorics/Additive/FreimanHom.lean @@ -1,13 +1,15 @@ /- 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.Algebra.BigOperators.Ring import Mathlib.Algebra.CharP.Defs +import Mathlib.Algebra.Group.Pointwise.Set.Basic +import Mathlib.Algebra.Group.Submonoid.Operations import Mathlib.Algebra.Order.BigOperators.Group.Multiset +import Mathlib.Algebra.Order.Ring.Nat import Mathlib.Data.ZMod.Defs -import Mathlib.Data.Set.Pointwise.Basic /-! # Freiman homomorphisms @@ -18,19 +20,29 @@ An `n`-Freiman homomorphism from `A` to `B` is a function `f : α → β` such t `f x₁ * ... * f xₙ = f y₁ * ... * f yₙ` for all `x₁, ..., xₙ, y₁, ..., yₙ ∈ A` such that `x₁ * ... * xₙ = y₁ * ... * yₙ`. In particular, any `MulHom` is a Freiman homomorphism. +Note a `0`- or `1`-Freiman homomorphism is simply a map, thus a `2`-Freiman homomorphism is the +first interesting case (and the most common). As `n` increases further, the property of being +an `n`-Freiman homomorphism between abelian groups becomes increasingly stronger. + An `n`-Freiman isomorphism from `A` to `B` is a function `f : α → β` bijective between `A` and `B` such that `f x₁ * ... * f xₙ = f y₁ * ... * f yₙ ↔ x₁ * ... * xₙ = y₁ * ... * yₙ` for all `x₁, ..., xₙ, y₁, ..., yₙ ∈ A`. In particular, any `MulEquiv` is a Freiman isomorphism. They are of interest in additive combinatorics. -## Main declaration +## Main declarations * `IsMulFreimanHom`: Predicate for a function to be a multiplicative Freiman homomorphism. * `IsAddFreimanHom`: Predicate for a function to be an additive Freiman homomorphism. * `IsMulFreimanIso`: Predicate for a function to be a multiplicative Freiman isomorphism. * `IsAddFreimanIso`: Predicate for a function to be an additive Freiman isomorphism. +## Main results + +* `isMulFreimanHom_two`: Characterisation of `2`-Freiman homomorphisms. +* `IsMulFreimanHom.mono`: If `m ≤ n` and `f` is an `n`-Freiman homomorphism, then it is also an + `m`-Freiman homomorphism. + ## Implementation notes In the context of combinatorics, we are interested in Freiman homomorphisms over sets which are not @@ -102,6 +114,20 @@ lemma IsMulFreimanIso.isMulFreimanHom (hf : IsMulFreimanIso n A B f) : IsMulFrei mapsTo := hf.bijOn.mapsTo map_prod_eq_map_prod _s _t hsA htA hs ht := (hf.map_prod_eq_map_prod hsA htA hs ht).2 +lemma IsMulFreimanHom.congr (hf₁ : IsMulFreimanHom n A B f₁) (h : EqOn f₁ f₂ A) : + IsMulFreimanHom n A B f₂ where + mapsTo := hf₁.mapsTo.congr h + map_prod_eq_map_prod s t hsA htA hs ht h' := by + rw [map_congr rfl fun x hx => (h (hsA hx)).symm, map_congr rfl fun x hx => (h (htA hx)).symm, + hf₁.map_prod_eq_map_prod hsA htA hs ht h'] + +lemma IsMulFreimanIso.congr (hf₁ : IsMulFreimanIso n A B f₁) (h : EqOn f₁ f₂ A) : + IsMulFreimanIso n A B f₂ where + bijOn := hf₁.bijOn.congr h + map_prod_eq_map_prod s t hsA htA hs ht := by + rw [map_congr rfl fun x hx => h.symm (hsA hx), map_congr rfl fun x hx => h.symm (htA hx), + hf₁.map_prod_eq_map_prod hsA htA hs ht] + @[to_additive] lemma IsMulFreimanHom.mul_eq_mul (hf : IsMulFreimanHom 2 A B f) {a b c d : α} (ha : a ∈ A) (hb : b ∈ A) (hc : c ∈ A) (hd : d ∈ A) (h : a * b = c * d) : @@ -116,13 +142,21 @@ lemma IsMulFreimanIso.mul_eq_mul (hf : IsMulFreimanIso 2 A B f) {a b c d : α} simp_rw [← prod_pair] refine hf.map_prod_eq_map_prod ?_ ?_ (card_pair _ _) (card_pair _ _) <;> simp [ha, hb, hc, hd] -/-- Characterisation of `2`-Freiman homs. -/ -@[to_additive "Characterisation of `2`-Freiman homs."] +/-- Characterisation of `2`-Freiman homomorphisms. -/ +@[to_additive "Characterisation of `2`-Freiman homomorphisms."] 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⟩ - mpr hf := ⟨hf.1, by aesop (add simp [Multiset.card_eq_two])⟩ + mpr hf := ⟨hf.1, by aesop (add simp card_eq_two)⟩ + +/-- Characterisation of `2`-Freiman homs. -/ +@[to_additive "Characterisation of `2`-Freiman isomorphisms."] +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⟩ + 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 mapsTo := hA @@ -171,6 +205,27 @@ lemma isMulFreimanHom_const {b : β} (hb : b ∈ B) : IsMulFreimanHom n A B fun mapsTo _ _ := hb map_prod_eq_map_prod s t _ _ hs ht _ := by simp only [map_const', hs, prod_replicate, ht] +@[to_additive (attr := simp)] +lemma isMulFreimanHom_zero_iff : IsMulFreimanHom 0 A B f ↔ MapsTo f A B := + ⟨fun h => h.mapsTo, fun h => ⟨h, by aesop⟩⟩ + +@[to_additive (attr := simp)] +lemma isMulFreimanIso_zero_iff : IsMulFreimanIso 0 A B f ↔ BijOn f A B := + ⟨fun h => h.bijOn, fun h => ⟨h, by aesop⟩⟩ + +@[to_additive (attr := simp) isAddFreimanHom_one_iff] +lemma isMulFreimanHom_one_iff : IsMulFreimanHom 1 A B f ↔ MapsTo f A B := + ⟨fun h => h.mapsTo, fun h => ⟨h, by aesop (add simp card_eq_one)⟩⟩ + +@[to_additive (attr := simp) isAddFreimanIso_one_iff] +lemma isMulFreimanIso_one_iff : IsMulFreimanIso 1 A B f ↔ BijOn f A B := + ⟨fun h => h.bijOn, fun h => ⟨h, by aesop (add simp [card_eq_one, BijOn])⟩⟩ + +@[to_additive (attr := simp)] +lemma isMulFreimanHom_empty : IsMulFreimanHom n (∅ : Set α) B f where + mapsTo := mapsTo_empty f B + map_prod_eq_map_prod s t := by aesop (add simp eq_zero_of_forall_not_mem) + @[to_additive (attr := simp)] lemma isMulFreimanIso_empty : IsMulFreimanIso n (∅ : Set α) (∅ : Set β) f where bijOn := bijOn_empty _ @@ -196,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 @@ -319,7 +379,7 @@ namespace Fin variable {k m n : ℕ} private lemma aux (hm : m ≠ 0) (hkmn : m * k ≤ n) : k < (n + 1) := - Nat.lt_succ_iff.2 $ le_trans (Nat.le_mul_of_pos_left _ hm.bot_lt) hkmn + Nat.lt_succ_iff.2 <| le_trans (Nat.le_mul_of_pos_left _ hm.bot_lt) hkmn /-- **No wrap-around principle**. @@ -335,7 +395,7 @@ lemma isAddFreimanIso_Iic (hm : m ≠ 0) (hkmn : m * k ≤ n) : have (u : Multiset (Fin (n + 1))) : Nat.castRingHom _ (u.map val).sum = u.sum := by simp rw [← this, ← this] have {u : Multiset (Fin (n + 1))} (huk : ∀ x ∈ u, x ≤ k) (hu : card u = m) : - (u.map val).sum < (n + 1) := Nat.lt_succ_iff.2 $ hkmn.trans' $ by + (u.map val).sum < (n + 1) := Nat.lt_succ_iff.2 <| hkmn.trans' <| by rw [← hu, ← card_map] refine sum_le_card_nsmul (u.map val) k ?_ simpa [le_iff_val_le_val, -val_fin_le, Nat.mod_eq_of_lt, aux hm hkmn] using huk diff --git a/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean b/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean index c959973f91a54..ae04f34d67a52 100644 --- a/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean +++ b/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean @@ -3,12 +3,12 @@ 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.GCongr -import Mathlib.Algebra.Order.Field.Basic -import Mathlib.Algebra.Order.Field.Rat /-! # The Plünnecke-Ruzsa inequality @@ -46,7 +46,7 @@ theorem ruzsa_triangle_inequality_div_div_div (A B C : Finset α) : · 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 ↦ ?_ · 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 hb hc), div_mul_div_cancel _ _ _⟩ · exact div_right_injective (Prod.ext_iff.1 h).1 · exact ((mem_bipartiteBelow _).1 hv).2 @@ -129,14 +129,14 @@ theorem ruzsa_triangle_inequality_mul_mul_mul (A B C : Finset α) : rw [mem_erase, mem_powerset, ← nonempty_iff_ne_empty] at hU refine cast_le.1 (?_ : (_ : ℚ≥0) ≤ _) push_cast - refine (le_div_iff <| cast_pos.2 hB.card_pos).1 ?_ + refine (le_div_iff₀ <| cast_pos.2 hB.card_pos).1 ?_ rw [mul_div_right_comm, mul_comm _ B] refine (Nat.cast_le.2 <| card_le_card_mul_left _ hU.1).trans ?_ refine le_trans ?_ (mul_le_mul (hUA _ hB') (cast_le.2 <| card_le_card <| mul_subset_mul_right hU.2) (zero_le _) (zero_le _)) rw [← mul_div_right_comm, ← mul_assoc] - refine (le_div_iff <| cast_pos.2 hU.1.card_pos).2 ?_ + refine (le_div_iff₀ <| cast_pos.2 hU.1.card_pos).2 ?_ exact mod_cast pluennecke_petridis_inequality_mul C (mul_aux hU.1 hU.2 hUA) /-- **Ruzsa's triangle inequality**. Mul-div-div version. -/ @@ -169,7 +169,7 @@ private lemma card_mul_pow_le (hAB : ∀ A' ⊆ A, (A * B).card * A'.card ≤ (A 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] + le_div_iff₀, ← cast_mul] swap · exact cast_pos.2 hA.card_pos refine (Nat.cast_le.2 <| pluennecke_petridis_inequality_mul _ hAB).trans ?_ diff --git a/Mathlib/Combinatorics/Additive/RuzsaCovering.lean b/Mathlib/Combinatorics/Additive/RuzsaCovering.lean index 06670fc204bb7..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 /-! @@ -65,8 +65,6 @@ lemma exists_subset_mul_div (hs : s.Finite) (ht' : t.Finite) (ht : t.Nonempty) : classical obtain ⟨u, hu, hsut⟩ := Finset.exists_subset_mul_div s ht refine ⟨u, ?_⟩ - -- `norm_cast` would find these automatically, but breaks `to_additive` when it does so - rw [← Finset.coe_mul, ← Finset.coe_mul, ← Finset.coe_div] norm_cast simp [*] diff --git a/Mathlib/Combinatorics/Colex.lean b/Mathlib/Combinatorics/Colex.lean index e4b1b34ce802f..54e26b8a2cc4c 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 α`. -/ @@ -197,7 +197,7 @@ lemma toColex_lt_singleton : toColex s < toColex {a} ↔ ∀ b ∈ s, b < a := b · refine h.2 <| eq_singleton_iff_unique_mem.2 ⟨hb, fun c hc ↦ (h.1 _ hc).2 hb⟩ · simp at h -/-- `{a} ≤ s` in colex iff `s` contains an element greated than or equal to `a`. -/ +/-- `{a} ≤ s` in colex iff `s` contains an element greater than or equal to `a`. -/ lemma singleton_le_toColex : (toColex {a} : Colex α) ≤ toColex s ↔ ∃ x ∈ s, a ≤ x := by simp [toColex_le_toColex]; by_cases a ∈ s <;> aesop @@ -345,15 +345,15 @@ lemma lt_iff_exists_filter_lt : 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 - have ⟨hmt, hms, hm⟩ : m ∈ t ∧ m ∉ s ∧ ∀ a ∈ s, a ∉ t → a < m := mem_u.1 $ max'_mem _ _ + have ⟨hmt, hms, hm⟩ : m ∈ t ∧ m ∉ s ∧ ∀ a ∈ s, a ∉ t → a < m := mem_u.1 <| max'_mem _ _ refine ⟨m, hmt, hms, fun a hma ↦ ⟨fun has ↦ not_imp_comm.1 (hm _ has) hma.asymm, fun hat ↦ ?_⟩⟩ by_contra has have hau : a ∈ u := mem_u.2 ⟨hat, has, fun b hbs hbt ↦ (hm _ hbs hbt).trans hma⟩ - exact hma.not_le $ le_max' _ _ hau + exact hma.not_le <| le_max' _ _ hau · rintro ⟨w, hwt, hws, hw⟩ refine ⟨w, hwt, hws, fun a has hat ↦ ?_⟩ by_contra! hwa - exact hat $ (hw $ hwa.lt_of_ne $ ne_of_mem_of_not_mem hwt hat).1 has + 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) : @@ -364,9 +364,9 @@ lemma erase_le_erase_min' (hst : toColex s ≤ toColex t) (hcard : s.card ≤ t. -- Case on whether `s = t` obtain rfl | h' := eq_or_ne s t -- If `s = t`, then `s \ {a} ≤ s \ {m}` because `m ≤ a` - · exact (erase_le_erase ha $ min'_mem _ _).2 $ min'_le _ _ $ ha + · exact (erase_le_erase ha <| min'_mem _ _).2 <| min'_le _ _ <| ha -- If `s ≠ t`, call `w` the colex witness. Case on whether `w < a` or `a < w` - replace hst := hst.lt_of_ne $ toColex_inj.not.2 h' + replace hst := hst.lt_of_ne <| toColex_inj.not.2 h' simp only [lt_iff_exists_filter_lt, mem_sdiff, filter_inj, and_assoc] at hst obtain ⟨w, hwt, hws, hw⟩ := hst obtain hwa | haw := (ne_of_mem_of_not_mem ha hws).symm.lt_or_lt @@ -379,14 +379,15 @@ lemma erase_le_erase_min' (hst : toColex s ≤ toColex t) (hcard : s.card ≤ t. obtain rfl | hbt := hbt · assumption · by_contra! hab - exact hbt $ (hw $ hwa.trans_le hab).1 $ mem_of_mem_erase hbs + exact hbt <| (hw <| hwa.trans_le hab).1 <| mem_of_mem_erase hbs -- If `a < w`, case on whether `m < w` or `m = w` obtain rfl | hmw : m = w ∨ m < w := (min'_le _ _ hwt).eq_or_lt -- If `m = w`, then `s \ {a} = t \ {m}` · have : erase t m ⊆ erase s a := by rintro b hb rw [mem_erase] at hb ⊢ - exact ⟨(haw.trans_le $ min'_le _ _ hb.2).ne', (hw $ hb.1.lt_of_le' $ min'_le _ _ hb.2).2 hb.2⟩ + exact ⟨(haw.trans_le <| min'_le _ _ hb.2).ne', + (hw <| hb.1.lt_of_le' <| min'_le _ _ hb.2).2 hb.2⟩ rw [eq_of_subset_of_card_le this] rw [card_erase_of_mem ha, card_erase_of_mem (min'_mem _ _)] exact tsub_le_tsub_right hcard _ @@ -398,7 +399,7 @@ lemma erase_le_erase_min' (hst : toColex s ≤ toColex t) (hcard : s.card ≤ t. obtain rfl | hbt := hbt · assumption · by_contra! hwb - exact hbt $ (hw $ hwb.lt_of_ne $ ne_of_mem_of_not_mem hwt hbt).1 $ mem_of_mem_erase hbs + exact hbt <| (hw <| hwb.lt_of_ne <| ne_of_mem_of_not_mem hwt hbt).1 <| mem_of_mem_erase hbs /-- Strictly monotone functions preserve the colex ordering. -/ lemma toColex_image_le_toColex_image (hf : StrictMono f) : diff --git a/Mathlib/Combinatorics/Configuration.lean b/Mathlib/Combinatorics/Configuration.lean index d680b794a0d30..a703f011ed4da 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 @@ -57,7 +56,7 @@ instance [h : Fintype P] : Fintype (Dual P) := -- Porting note (#11215): TODO: figure out if this is needed. set_option synthInstance.checkSynthOrder false in instance : Membership (Dual L) (Dual P) := - ⟨Function.swap (Membership.mem : P → L → Prop)⟩ + ⟨Function.swap (Membership.mem : L → P → Prop)⟩ /-- A configuration is nondegenerate if: 1) there does not exist a line that passes through all of the points, @@ -129,7 +128,7 @@ theorem Nondegenerate.exists_injective_of_card_le [Nondegenerate P L] [Fintype P by_cases hs₁ : s.card = 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 @@ -196,9 +195,8 @@ theorem HasLines.pointCount_le_lineCount [HasLines P L] {p : P} {l : L} (h : p exact Fintype.card_le_of_injective (fun p' => ⟨mkLine (this p'), (mkLine_ax (this p')).1⟩) fun p₁ p₂ hp => - Subtype.ext - ((eq_or_eq p₁.2 p₂.2 (mkLine_ax (this p₁)).2 - ((congr_arg _ (Subtype.ext_iff.mp hp)).mpr (mkLine_ax (this p₂)).2)).resolve_right + Subtype.ext ((eq_or_eq p₁.2 p₂.2 (mkLine_ax (this p₁)).2 + ((congr_arg (_ ∈ ·) (Subtype.ext_iff.mp hp)).mpr (mkLine_ax (this p₂)).2)).resolve_right fun h' => (congr_arg (¬p ∈ ·) h').mp h (mkLine_ax (this p₁)).1) theorem HasPoints.lineCount_le_pointCount [HasPoints P L] {p : P} {l : L} (h : p ∉ l) @@ -222,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 @@ -263,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 @@ -301,13 +299,12 @@ noncomputable def HasLines.hasPoints [HasLines P L] [Fintype P] [Fintype L] let f : { q : P // q ∈ l₂ } → { l : L // p ∈ l } := fun q => ⟨mkLine (this q), (mkLine_ax (this q)).1⟩ have hf : Function.Injective f := fun q₁ q₂ hq => - Subtype.ext - ((eq_or_eq q₁.2 q₂.2 (mkLine_ax (this q₁)).2 - ((congr_arg _ (Subtype.ext_iff.mp hq)).mpr (mkLine_ax (this q₂)).2)).resolve_right + Subtype.ext ((eq_or_eq q₁.2 q₂.2 (mkLine_ax (this q₁)).2 + ((congr_arg (_ ∈ ·) (Subtype.ext_iff.mp hq)).mpr (mkLine_ax (this q₂)).2)).resolve_right fun h => (congr_arg (¬p ∈ ·) h).mp hl₂ (mkLine_ax (this q₁)).1) have key' := ((Fintype.bijective_iff_injective_and_card f).mpr ⟨hf, key'⟩).2 obtain ⟨q, hq⟩ := key' ⟨l₁, hl₁⟩ - exact ⟨q, (congr_arg _ (Subtype.ext_iff.mp hq)).mp (mkLine_ax (this q)).2, q.2⟩ + exact ⟨q, (congr_arg (_ ∈ ·) (Subtype.ext_iff.mp hq)).mp (mkLine_ax (this q)).2, q.2⟩ { ‹HasLines P L› with mkPoint := fun {l₁ l₂} hl => Classical.choose (this l₁ l₂ hl) mkPoint_ax := fun {l₁ l₂} hl => Classical.choose_spec (this l₁ l₂ hl) } @@ -368,7 +365,7 @@ theorem lineCount_eq_lineCount [Finite P] [Finite L] (p q : P) : lineCount L p = or_not.elim (fun h₂ => ?_) fun h₂ => (HasLines.lineCount_eq_pointCount h h₂).trans hl₂ refine or_not.elim (fun h₃ => ?_) fun h₃ => (HasLines.lineCount_eq_pointCount h h₃).trans hl₃ rw [(eq_or_eq h₂ h₂₂ h₃ h₂₃).resolve_right fun h => - h₃₃ ((congr_arg (Membership.mem p₃) h).mp h₃₂)] + h₃₃ ((congr_arg (p₃ ∈ ·) h).mp h₃₂)] variable (P) {L} @@ -414,7 +411,7 @@ theorem one_lt_order [Finite P] [Finite L] : 1 < order P L := by rw [← add_lt_add_iff_right 1, ← pointCount_eq _ l₂, pointCount, Nat.card_eq_fintype_card, Fintype.two_lt_card_iff] simp_rw [Ne, Subtype.ext_iff] - have h := mkPoint_ax fun h => h₂₁ ((congr_arg _ h).mpr h₂₂) + have h := mkPoint_ax (P := P) (L := L) fun h => h₂₁ ((congr_arg (p₂ ∈ ·) h).mpr h₂₂) exact ⟨⟨mkPoint _, h.2⟩, ⟨p₂, h₂₂⟩, ⟨p₃, h₃₂⟩, ne_of_mem_of_not_mem h.1 h₂₁, ne_of_mem_of_not_mem h.1 h₃₁, ne_of_mem_of_not_mem h₂₃ h₃₃⟩ @@ -464,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/Finite.lean b/Mathlib/Combinatorics/Derangements/Finite.lean index 31ea036e767de..210773f9903ec 100644 --- a/Mathlib/Combinatorics/Derangements/Finite.lean +++ b/Mathlib/Combinatorics/Derangements/Finite.lean @@ -42,12 +42,14 @@ theorem card_derangements_invariant {α β : Type*} [Fintype α] [DecidableEq α theorem card_derangements_fin_add_two (n : ℕ) : card (derangements (Fin (n + 2))) = (n + 1) * card (derangements (Fin n)) + (n + 1) * card (derangements (Fin (n + 1))) := by - -- get some basic results about the size of fin (n+1) plus or minus an element + -- get some basic results about the size of Fin (n+1) plus or minus an element have h1 : ∀ a : Fin (n + 1), card ({a}ᶜ : Set (Fin (n + 1))) = card (Fin n) := by intro a - simp only [Fintype.card_fin, Finset.card_fin, Fintype.card_ofFinset, Finset.filter_ne' _ a, - Set.mem_compl_singleton_iff, Finset.card_erase_of_mem (Finset.mem_univ a), - add_tsub_cancel_right] + simp only + [card_ofFinset (s := Finset.filter (fun x => x ∈ ({a}ᶜ : Set (Fin (n + 1)))) Finset.univ), + Set.mem_compl_singleton_iff, Finset.filter_ne' _ a, + Finset.card_erase_of_mem (Finset.mem_univ a), Finset.card_fin, add_tsub_cancel_right, + card_fin] have h2 : card (Fin (n + 2)) = card (Option (Fin (n + 1))) := by simp only [card_fin, card_option] -- rewrite the LHS and substitute in our fintype-level equivalence simp only [card_derangements_invariant h2, diff --git a/Mathlib/Combinatorics/Digraph/Basic.lean b/Mathlib/Combinatorics/Digraph/Basic.lean new file mode 100644 index 0000000000000..b6c97992885be --- /dev/null +++ b/Mathlib/Combinatorics/Digraph/Basic.lean @@ -0,0 +1,239 @@ +/- +Copyright (c) 2024 Kyle Miller, Jack Cheverton. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kyle Miller, Jack Cheverton, Jeremy Tan +-/ +import Mathlib.Order.CompleteBooleanAlgebra +import Mathlib.Data.Fintype.Pi + +/-! +# Digraphs + +This module defines directed graphs on a vertex type `V`, +which is the same notion as a relation `V → V → Prop`. +While this might be too simple of a notion to deserve the grandeur of a new definition, +the intention here is to develop relations using the language of graph theory. + +Note that in this treatment, a digraph may have self loops. + +The type `Digraph V` is structurally equivalent to `Quiver.{0} V`, +but a difference between these is that `Quiver` is a class — +its purpose is to attach a quiver structure to a particular type `V`. +In contrast, for `Digraph V` we are interested in working with the entire lattice +of digraphs on `V`. + +## Main definitions + +* `Digraph` is a structure for relations. Unlike `SimpleGraph`, the relation does not need to be + symmetric or irreflexive. + +* `CompleteAtomicBooleanAlgebra` instance: Under the subgraph relation, `Digraph` forms a + `CompleteAtomicBooleanAlgebra`. In other words, this is the complete lattice of spanning subgraphs + of the complete graph. +-/ + +open Finset Function + +/-- +A digraph is a relation `Adj` on a vertex type `V`. +The relation describes which pairs of vertices are adjacent. + +In this treatment, a digraph may have self-loops. +-/ +@[ext] +structure Digraph (V : Type*) where + /-- The adjacency relation of a digraph. -/ + Adj : V → V → Prop + +/-- +Constructor for digraphs using a boolean function. +This is useful for creating a digraph with a decidable `Adj` relation, +and it's used in the construction of the `Fintype (Digraph V)` instance. +-/ +@[simps] +def Digraph.mk' {V : Type*} : (V → V → Bool) ↪ Digraph V where + toFun x := ⟨fun v w ↦ x v w⟩ + inj' adj adj' := by + simp_rw [mk.injEq] + intro h + funext v w + simpa only [eq_iff_iff, Bool.coe_iff_coe] using congr($h v w) + +instance {V : Type*} (adj : V → V → Bool) : DecidableRel (Digraph.mk' adj).Adj := + inferInstanceAs <| DecidableRel (fun v w ↦ adj v w) + +instance {V : Type*} [DecidableEq V] [Fintype V] : Fintype (Digraph V) := + Fintype.ofBijective Digraph.mk' <| by + classical + refine ⟨Embedding.injective _, ?_⟩ + intro G + use fun v w ↦ G.Adj v w + ext v w + simp + +namespace Digraph + +/-- +The complete digraph on a type `V` (denoted by `⊤`) +is the digraph whose vertices are all adjacent. +Note that every vertex is adjacent to itself in `⊤`. +-/ +protected def completeDigraph (V : Type*) : Digraph V where Adj := ⊤ + +/-- +The empty digraph on a type `V` (denoted by `⊥`) +is the digraph such that no pairs of vertices are adjacent. +Note that `⊥` is called the empty digraph because it has no edges. +-/ +protected def emptyDigraph (V : Type*) : Digraph V where Adj _ _ := False + +/-- +Two vertices are adjacent in the complete bipartite digraph on two vertex types +if and only if they are not from the same side. +Any bipartite digraph may be regarded as a subgraph of one of these. +-/ +@[simps] +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} + +theorem adj_injective : Injective (Adj : Digraph V → V → V → Prop) := fun _ _ ↦ Digraph.ext + +@[simp] theorem adj_inj {G H : Digraph V} : G.Adj = H.Adj ↔ G = H := Digraph.ext_iff.symm + +section Order + +/-- +The relation that one `Digraph` is a spanning subgraph of another. +Note that `Digraph.IsSubgraph G H` should be spelled `G ≤ H`. +-/ +protected def IsSubgraph (x y : Digraph V) : Prop := + ∀ ⦃v w : V⦄, x.Adj v w → y.Adj v w + +instance : LE (Digraph V) := ⟨Digraph.IsSubgraph⟩ + +@[simp] +theorem isSubgraph_eq_le : (Digraph.IsSubgraph : Digraph V → Digraph V → Prop) = (· ≤ ·) := rfl + +/-- The supremum of two digraphs `x ⊔ y` has edges where either `x` or `y` have edges. -/ +instance : Sup (Digraph V) where + sup x y := { Adj := x.Adj ⊔ y.Adj } + +@[simp] +theorem sup_adj (x y : Digraph V) (v w : V) : (x ⊔ y).Adj v w ↔ x.Adj v w ∨ y.Adj v w := Iff.rfl + +/-- The infimum of two digraphs `x ⊓ y` has edges where both `x` and `y` have edges. -/ +instance : Inf (Digraph V) where + inf x y := { Adj := x.Adj ⊓ y.Adj } + +@[simp] +theorem inf_adj (x y : Digraph V) (v w : V) : (x ⊓ y).Adj v w ↔ x.Adj v w ∧ y.Adj v w := Iff.rfl + +/-- We define `Gᶜ` to be the `Digraph V` such that no two adjacent vertices in `G` +are adjacent in the complement, and every nonadjacent pair of vertices is adjacent. -/ +instance hasCompl : HasCompl (Digraph V) where + compl G := { Adj := fun v w ↦ ¬G.Adj v w } + +@[simp] theorem compl_adj (G : Digraph V) (v w : V) : Gᶜ.Adj v w ↔ ¬G.Adj v w := Iff.rfl + +/-- The difference of two digraphs `x \ y` has the edges of `x` with the edges of `y` removed. -/ +instance sdiff : SDiff (Digraph V) where + sdiff x y := { Adj := x.Adj \ y.Adj } + +@[simp] +theorem sdiff_adj (x y : Digraph V) (v w : V) : (x \ y).Adj v w ↔ x.Adj v w ∧ ¬y.Adj v w := Iff.rfl + +instance supSet : SupSet (Digraph V) where + sSup s := { Adj := fun a b ↦ ∃ G ∈ s, Adj G a b } + +instance infSet : InfSet (Digraph V) where + sInf s := { Adj := fun a b ↦ (∀ ⦃G⦄, G ∈ s → Adj G a b) } + +@[simp] +theorem sSup_adj {s : Set (Digraph V)} : (sSup s).Adj a b ↔ ∃ G ∈ s, Adj G a b := Iff.rfl + +@[simp] +theorem sInf_adj {s : Set (Digraph V)} : (sInf s).Adj a b ↔ ∀ G ∈ s, Adj G a b := Iff.rfl + +@[simp] +theorem iSup_adj {f : ι → Digraph V} : (⨆ i, f i).Adj a b ↔ ∃ i, (f i).Adj a b := by simp [iSup] + +@[simp] +theorem iInf_adj {f : ι → Digraph V} : (⨅ i, f i).Adj a b ↔ (∀ i, (f i).Adj a b) := by simp [iInf] + +/-- For digraphs `G`, `H`, `G ≤ H` iff `∀ a b, G.Adj a b → H.Adj a b`. -/ +instance distribLattice : DistribLattice (Digraph V) := + { adj_injective.distribLattice Digraph.Adj (fun _ _ ↦ rfl) fun _ _ ↦ rfl with + le := fun G H ↦ ∀ ⦃a b⦄, G.Adj a b → H.Adj a b } + +instance completeAtomicBooleanAlgebra : CompleteAtomicBooleanAlgebra (Digraph V) := + { Digraph.distribLattice with + le := (· ≤ ·) + sup := (· ⊔ ·) + inf := (· ⊓ ·) + compl := HasCompl.compl + 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 + top_le_sup_compl := fun G v w _ ↦ by tauto + sSup := sSup + le_sSup := fun s G hG a b 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 + iInf_iSup_eq := fun f ↦ by ext; simp [Classical.skolem] } + +@[simp] theorem top_adj (v w : V) : (⊤ : Digraph V).Adj v w := trivial + +@[simp] theorem bot_adj (v w : V) : (⊥ : Digraph V).Adj v w ↔ False := Iff.rfl + +@[simp] theorem completeDigraph_eq_top (V : Type*) : Digraph.completeDigraph V = ⊤ := rfl + +@[simp] theorem emptyDigraph_eq_bot (V : Type*) : Digraph.emptyDigraph V = ⊥ := rfl + +@[simps] instance (V : Type*) : Inhabited (Digraph V) := ⟨⊥⟩ + +instance [IsEmpty V] : Unique (Digraph V) where + default := ⊥ + uniq G := by ext1; congr! + +instance [Nonempty V] : Nontrivial (Digraph V) := by + use ⊥, ⊤ + have v := Classical.arbitrary V + exact ne_of_apply_ne (·.Adj v v) (by simp) + +section Decidable + +variable (V) (H : Digraph V) [DecidableRel G.Adj] [DecidableRel H.Adj] + +instance Bot.adjDecidable : DecidableRel (⊥ : Digraph V).Adj := + inferInstanceAs <| DecidableRel fun _ _ ↦ False + +instance Sup.adjDecidable : DecidableRel (G ⊔ H).Adj := + inferInstanceAs <| DecidableRel fun v w ↦ G.Adj v w ∨ H.Adj v w + +instance Inf.adjDecidable : DecidableRel (G ⊓ H).Adj := + inferInstanceAs <| DecidableRel fun v w ↦ G.Adj v w ∧ H.Adj v w + +instance SDiff.adjDecidable : DecidableRel (G \ H).Adj := + inferInstanceAs <| DecidableRel fun v w ↦ G.Adj v w ∧ ¬H.Adj v w + +instance Top.adjDecidable : DecidableRel (⊤ : Digraph V).Adj := + inferInstanceAs <| DecidableRel fun _ _ ↦ True + +instance Compl.adjDecidable : DecidableRel (Gᶜ.Adj) := + inferInstanceAs <| DecidableRel fun v w ↦ ¬G.Adj v w + +end Decidable + +end Order + +end Digraph diff --git a/Mathlib/Combinatorics/Enumerative/Composition.lean b/Mathlib/Combinatorics/Enumerative/Composition.lean index 05f69e27409d1..917e4a7e41dbc 100644 --- a/Mathlib/Combinatorics/Enumerative/Composition.lean +++ b/Mathlib/Combinatorics/Enumerative/Composition.lean @@ -54,7 +54,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)`. @@ -112,7 +112,7 @@ structure CompositionAsSet (n : ℕ) where boundaries : Finset (Fin n.succ) /-- Proof that `0` is a member of `boundaries`-/ zero_mem : (0 : Fin n.succ) ∈ boundaries - /-- Last element of the composition-/ + /-- Last element of the composition -/ getLast_mem : Fin.last n ∈ boundaries instance {n : ℕ} : Inhabited (CompositionAsSet n) := @@ -168,6 +168,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 @@ -629,7 +635,7 @@ theorem getElem_splitWrtCompositionAux (l : List α) (ns : List ℕ) {i : ℕ} · rw [Nat.add_zero, List.take_zero, sum_nil] simp · simp only [splitWrtCompositionAux, getElem_cons_succ, IH, take, - sum_cons, Nat.add_eq, add_zero, splitAt_eq_take_drop, drop_take, drop_drop] + sum_cons, Nat.add_eq, add_zero, splitAt_eq, drop_take, drop_drop] rw [add_comm (sum _) n, Nat.add_sub_add_left] /-- The `i`-th sublist in the splitting of a list `l` along a composition `c`, is the slice of `l` @@ -759,7 +765,7 @@ def compositionAsSetEquiv (n : ℕ) : CompositionAsSet n ≃ Finset (Fin (n - 1) exact (zero_le i.val).trans_lt (i.2.trans_le (Nat.sub_le n 1)) simp only [add_comm, Fin.ext_iff, Fin.val_zero, Fin.val_last, exists_prop, Set.toFinset_setOf, Finset.mem_univ, forall_true_left, Finset.mem_filter, add_eq_zero, and_false, - add_left_inj, false_or, true_and] + add_left_inj, false_or, true_and, reduceCtorEq] erw [Set.mem_setOf_eq] simp only [Finset.mem_val] constructor diff --git a/Mathlib/Combinatorics/Enumerative/DoubleCounting.lean b/Mathlib/Combinatorics/Enumerative/DoubleCounting.lean index 064efd1a8362a..0264391a00385 100644 --- a/Mathlib/Combinatorics/Enumerative/DoubleCounting.lean +++ b/Mathlib/Combinatorics/Enumerative/DoubleCounting.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.BigOperators.Ring import Mathlib.Algebra.Order.BigOperators.Group.Finset -import Mathlib.Data.Set.Subsingleton /-! # Double countings @@ -30,7 +30,7 @@ and `t`. open Finset Function Relator -variable {α β : Type*} +variable {R α β : Type*} /-! ### Bipartite graph -/ @@ -39,7 +39,7 @@ 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`. -/ @@ -53,12 +53,12 @@ theorem bipartiteBelow_swap : t.bipartiteBelow (swap r) a = t.bipartiteAbove r a theorem bipartiteAbove_swap : s.bipartiteAbove (swap r) b = s.bipartiteBelow r b := rfl @[simp, norm_cast] -theorem coe_bipartiteBelow : (s.bipartiteBelow r b : Set α) = { a ∈ s | r a b } := coe_filter _ _ +theorem coe_bipartiteBelow : s.bipartiteBelow r b = ({a ∈ s | r a b} : Set α) := coe_filter _ _ @[simp, norm_cast] -theorem coe_bipartiteAbove : (t.bipartiteAbove r a : Set β) = { b ∈ t | r a b } := coe_filter _ _ +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 @@ -71,21 +71,98 @@ theorem sum_card_bipartiteAbove_eq_sum_card_bipartiteBelow [∀ a b, Decidable ( simp_rw [card_eq_sum_ones, bipartiteAbove, bipartiteBelow, sum_filter] exact sum_comm -/-- 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_mul_le_card_mul [∀ a b, Decidable (r a b)] +section OrderedSemiring +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 := + (hn : ∀ b ∈ t, (s.bipartiteBelow r b).card ≤ n) : s.card • m ≤ t.card • 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 + norm_cast; rw [sum_card_bipartiteAbove_eq_sum_card_bipartiteBelow] + _ ≤ _ := t.sum_le_card_nsmul _ _ hn + +/-- **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)] + (hn : ∀ b ∈ t, n ≤ (s.bipartiteBelow r b).card) + (hm : ∀ a ∈ s, (t.bipartiteAbove r a).card ≤ m) : t.card • n ≤ s.card • m := + card_nsmul_le_card_nsmul (swap r) hn hm + +end OrderedSemiring + +section StrictOrderedSemiring +variable [StrictOrderedSemiring R] (r : α → β → Prop) {s : Finset α} {t : Finset β} + (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 := calc - _ ≤ ∑ a ∈ s, (t.bipartiteAbove r a).card := s.card_nsmul_le_sum _ _ hm - _ = ∑ b ∈ t, (s.bipartiteBelow r b).card := - sum_card_bipartiteAbove_eq_sum_card_bipartiteBelow _ + _ = ∑ _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 + norm_cast; rw [sum_card_bipartiteAbove_eq_sum_card_bipartiteBelow] _ ≤ _ := t.sum_le_card_nsmul _ _ hn +/-- **Double counting** argument. + +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 := + 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 + norm_cast; rw [sum_card_bipartiteAbove_eq_sum_card_bipartiteBelow] + _ < ∑ _b ∈ t, n := sum_lt_sum_of_nonempty ht hn + _ = _ := sum_const _ + +/-- **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)] (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 := + card_nsmul_lt_card_nsmul_of_lt_of_le (swap r) ht hn hm + +/-- **Double counting** argument. + +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 := + card_nsmul_lt_card_nsmul_of_le_of_lt (swap r) hs hn hm + +end StrictOrderedSemiring + +/-- **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_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 := + 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 := - card_mul_le_card_mul (swap r) hn hm + 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) diff --git a/Mathlib/Combinatorics/Enumerative/DyckWord.lean b/Mathlib/Combinatorics/Enumerative/DyckWord.lean new file mode 100644 index 0000000000000..220e3d4c4f141 --- /dev/null +++ b/Mathlib/Combinatorics/Enumerative/DyckWord.lean @@ -0,0 +1,591 @@ +/- +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 + +/-! +# Dyck words + +A Dyck word is a sequence consisting of an equal number `n` of symbols of two types such that +for all prefixes one symbol occurs at least as many times as the other. +If the symbols are `(` and `)` the latter restriction is equivalent to balanced brackets; +if they are `U = (1, 1)` and `D = (1, -1)` the sequence is a lattice path from `(0, 0)` to `(0, 2n)` +and the restriction requires the path to never go below the x-axis. + +This file defines Dyck words and constructs their bijection with rooted binary trees, +one consequence being that the number of Dyck words with length `2 * n` is `catalan n`. + +## Main definitions + +* `DyckWord`: a list of `U`s and `D`s with as many `U`s as `D`s and with every prefix having +at least as many `U`s as `D`s. +* `DyckWord.semilength`: semilength (half the length) of a Dyck word. +* `DyckWord.firstReturn`: for a nonempty word, the index of the `D` matching the initial `U`. + +## Main results + +* `DyckWord.equivTree`: equivalence between Dyck words and rooted binary trees. + See the docstrings of `DyckWord.equivTreeToFun` and `DyckWord.equivTreeInvFun` for details. +* `DyckWord.equivTreesOfNumNodesEq`: equivalence between Dyck words of length `2 * n` and + rooted binary trees with `n` internal nodes. +* `DyckWord.card_dyckWord_semilength_eq_catalan`: + there are `catalan n` Dyck words of length `2 * n` or semilength `n`. + +## Implementation notes + +While any two-valued type could have been used for `DyckStep`, a new enumerated type is used here +to emphasise that the definition of a Dyck word does not depend on that underlying type. +-/ + +open List + +/-- A `DyckStep` is either `U` or `D`, corresponding to `(` and `)` respectively. -/ +inductive DyckStep + | U : DyckStep + | D : DyckStep + deriving Inhabited, DecidableEq + +/-- Named in analogy to `Bool.dichotomy`. -/ +lemma DyckStep.dichotomy (s : DyckStep) : s = U ∨ s = D := by cases s <;> tauto + +open DyckStep + +/-- A Dyck word is a list of `DyckStep`s with as many `U`s as `D`s and with every prefix having +at least as many `U`s as `D`s. -/ +@[ext] +structure DyckWord where + /-- The underlying list -/ + toList : List DyckStep + /-- There are as many `U`s as `D`s -/ + count_U_eq_count_D : toList.count U = toList.count D + /-- Each prefix has as least as many `U`s as `D`s -/ + count_D_le_count_U i : (toList.take i).count D ≤ (toList.take i).count U + deriving DecidableEq + +attribute [coe] DyckWord.toList +instance : Coe DyckWord (List DyckStep) := ⟨DyckWord.toList⟩ + +instance : Add DyckWord where + add p q := ⟨p ++ q, by + simp only [count_append, p.count_U_eq_count_D, q.count_U_eq_count_D], by + simp only [take_append_eq_append_take, count_append] + exact fun _ ↦ add_le_add (p.count_D_le_count_U _) (q.count_D_le_count_U _)⟩ + +instance : Zero DyckWord := ⟨[], by simp, by simp⟩ + +/-- Dyck words form an additive cancellative monoid under concatenation, +with the empty word as 0. -/ +instance : AddCancelMonoid DyckWord where + add_zero p := by ext1; exact append_nil _ + zero_add p := by ext1; rfl + add_assoc p q r := by ext1; apply append_assoc + nsmul := nsmulRec + add_left_cancel p q r h := by rw [DyckWord.ext_iff] at *; exact append_cancel_left h + add_right_cancel p q r h := by rw [DyckWord.ext_iff] at *; exact append_cancel_right h + +namespace DyckWord + +variable {p q : DyckWord} + +lemma toList_eq_nil : p.toList = [] ↔ p = 0 := by rw [DyckWord.ext_iff]; rfl +lemma toList_ne_nil : p.toList ≠ [] ↔ p ≠ 0 := toList_eq_nil.ne + +/-- The only Dyck word that is an additive unit is the empty word. -/ +instance : Unique (AddUnits DyckWord) where + uniq p := by + obtain ⟨a, b, h, -⟩ := p + obtain ⟨ha, hb⟩ := append_eq_nil.mp (toList_eq_nil.mpr h) + congr + · exact toList_eq_nil.mp ha + · exact toList_eq_nil.mp hb + +variable (h : p ≠ 0) + +/-- The first element of a nonempty Dyck word is `U`. -/ +lemma head_eq_U (p : DyckWord) (h) : p.toList.head h = U := by + rcases p with - | s; · tauto + rw [head_cons] + by_contra f + rename_i _ nonneg + simpa [s.dichotomy.resolve_left f] using nonneg 1 + +/-- The last element of a nonempty Dyck word is `D`. -/ +lemma getLast_eq_D (p : DyckWord) (h) : p.toList.getLast h = D := by + by_contra f; have s := p.count_U_eq_count_D + rw [← dropLast_append_getLast h, (dichotomy _).resolve_right f] at s + simp_rw [dropLast_eq_take, count_append, count_singleton', ite_true, reduceCtorEq, ite_false] at s + have := p.count_D_le_count_U (p.toList.length - 1); omega + +include h in +lemma cons_tail_dropLast_concat : U :: p.toList.dropLast.tail ++ [D] = p := by + have h' := toList_ne_nil.mpr h + have : p.toList.dropLast.take 1 = [p.toList.head h'] := by + rcases p with - | ⟨s, ⟨- | ⟨t, r⟩⟩⟩ + · tauto + · rename_i bal _ + cases s <;> simp at bal + · tauto + nth_rw 2 [← p.toList.dropLast_append_getLast h', ← p.toList.dropLast.take_append_drop 1] + rw [getLast_eq_D, drop_one, this, head_eq_U] + rfl + +variable (p) in +/-- Prefix of a Dyck word as a Dyck word, given that the count of `U`s and `D`s in it are equal. -/ +def take (i : ℕ) (hi : (p.toList.take i).count U = (p.toList.take i).count D) : DyckWord where + toList := p.toList.take i + count_U_eq_count_D := hi + count_D_le_count_U k := by rw [take_take]; exact p.count_D_le_count_U (min k i) + +variable (p) in +/-- Suffix of a Dyck word as a Dyck word, given that the count of `U`s and `D`s in the prefix +are equal. -/ +def drop (i : ℕ) (hi : (p.toList.take i).count U = (p.toList.take i).count D) : DyckWord where + toList := p.toList.drop i + count_U_eq_count_D := by + have := p.count_U_eq_count_D + rw [← take_append_drop i p.toList, count_append, count_append] at this + omega + count_D_le_count_U k := by + rw [show i = min i (i + k) by omega, ← take_take] at hi + rw [take_drop, ← add_le_add_iff_left (((p.toList.take (i + k)).take i).count U), + ← count_append, hi, ← count_append, take_append_drop] + exact p.count_D_le_count_U _ + +variable (p) in +/-- Nest `p` in one pair of brackets, i.e. `x` becomes `(x)`. -/ +def nest : DyckWord where + toList := [U] ++ p ++ [D] + count_U_eq_count_D := by simp [p.count_U_eq_count_D] + count_D_le_count_U i := by + simp only [take_append_eq_append_take, count_append] + rw [← add_rotate (count D _), ← add_rotate (count U _)] + apply add_le_add _ (p.count_D_le_count_U _) + rcases i.eq_zero_or_pos with hi | hi; · simp [hi] + rw [take_of_length_le (show [U].length ≤ i by rwa [length_singleton]), count_singleton'] + simp only [reduceCtorEq, ite_true, ite_false] + rw [add_comm] + exact add_le_add (zero_le _) ((count_le_length _ _).trans (by simp)) + +@[simp] lemma nest_ne_zero : p.nest ≠ 0 := by simp [← toList_ne_nil, nest] + +variable (p) in +/-- A property stating that `p` is nonempty and strictly positive in its interior, +i.e. is of the form `(x)` with `x` a Dyck word. -/ +def IsNested : Prop := + p ≠ 0 ∧ ∀ ⦃i⦄, 0 < i → i < p.toList.length → (p.toList.take i).count D < (p.toList.take i).count U + +protected lemma IsNested.nest : p.nest.IsNested := ⟨nest_ne_zero, fun i lb ub ↦ by + simp_rw [nest, length_append, length_singleton] at ub ⊢ + rw [take_append_of_le_length (by rw [singleton_append, length_cons]; omega), + take_append_eq_append_take, take_of_length_le (by rw [length_singleton]; omega), + length_singleton, singleton_append, count_cons_of_ne (by simp), count_cons_self, + Nat.lt_add_one_iff] + exact p.count_D_le_count_U _⟩ + +variable (p) in +/-- Denest `p`, i.e. `(x)` becomes `x`, given that `p.IsNested`. -/ +def denest (hn : p.IsNested) : DyckWord where + toList := p.toList.dropLast.tail + count_U_eq_count_D := by + have := p.count_U_eq_count_D + rw [← cons_tail_dropLast_concat hn.1, count_append, count_cons] at this + simpa using this + count_D_le_count_U i := by + replace h := toList_ne_nil.mpr hn.1 + have l1 : p.toList.take 1 = [p.toList.head h] := by rcases p with - | - <;> tauto + have l3 : p.toList.length - 1 = p.toList.length - 1 - 1 + 1 := by + rcases p with - | ⟨s, ⟨- | ⟨t, r⟩⟩⟩ + · tauto + · rename_i bal _ + cases s <;> simp at bal + · tauto + rw [← drop_one, take_drop, dropLast_eq_take, take_take] + have ub : min (1 + i) (p.toList.length - 1) < p.toList.length := + (min_le_right _ p.toList.length.pred).trans_lt (Nat.pred_lt ((length_pos.mpr h).ne')) + have lb : 0 < min (1 + i) (p.toList.length - 1) := by + rw [l3, add_comm, min_add_add_right]; omega + have eq := hn.2 lb ub + set j := min (1 + i) (p.toList.length - 1) + rw [← (p.toList.take j).take_append_drop 1, count_append, count_append, take_take, + min_eq_left (by omega), l1, head_eq_U] at eq + simp only [count_singleton', ite_true, ite_false] at eq + omega + +variable (p) in +lemma nest_denest (hn) : (p.denest hn).nest = p := by + simpa [DyckWord.ext_iff] using p.cons_tail_dropLast_concat hn.1 + +variable (p) in +lemma denest_nest : p.nest.denest .nest = p := by + simp_rw [nest, denest, DyckWord.ext_iff, dropLast_concat]; rfl + +section Semilength + +variable (p) in +/-- The semilength of a Dyck word is half of the number of `DyckStep`s in it, or equivalently +its number of `U`s. -/ +def semilength : ℕ := p.toList.count U + +@[simp] lemma semilength_zero : semilength 0 = 0 := rfl +@[simp] lemma semilength_add : (p + q).semilength = p.semilength + q.semilength := count_append .. +@[simp] lemma semilength_nest : p.nest.semilength = p.semilength + 1 := by simp [semilength, nest] + +lemma semilength_eq_count_D : p.semilength = p.toList.count D := by + rw [← count_U_eq_count_D]; rfl + +@[simp] +lemma two_mul_semilength_eq_length : 2 * p.semilength = p.toList.length := by + nth_rw 1 [two_mul, semilength, p.count_U_eq_count_D, semilength] + convert (p.toList.length_eq_countP_add_countP (· == D)).symm + rw [count]; congr!; rename_i s; cases s <;> tauto + +end Semilength + +section FirstReturn + +variable (p) in +/-- `p.firstReturn` is 0 if `p = 0` and the index of the `D` matching the initial `U` otherwise. -/ +def firstReturn : ℕ := + (range p.toList.length).findIdx fun i ↦ + (p.toList.take (i + 1)).count U = (p.toList.take (i + 1)).count D + +@[simp] lemma firstReturn_zero : firstReturn 0 = 0 := rfl + +include h in +lemma firstReturn_pos : 0 < p.firstReturn := by + by_contra! f + rw [Nat.le_zero, firstReturn, findIdx_eq] at f + #adaptation_note + /-- + If we don't swap, then the second goal is dropped after completing the first goal. + What's going on? + -/ + swap + · rw [length_range, length_pos] + exact toList_ne_nil.mpr h + · rw [getElem_range] at f + simp at f + rw [← p.cons_tail_dropLast_concat h] at f + simp at f + +include h in +lemma firstReturn_lt_length : p.firstReturn < p.toList.length := by + have lp := length_pos_of_ne_nil (toList_ne_nil.mpr h) + rw [← length_range p.toList.length] + apply findIdx_lt_length_of_exists + simp only [mem_range, decide_eq_true_eq] + use p.toList.length - 1 + exact ⟨by omega, by rw [Nat.sub_add_cancel lp, take_of_length_le (le_refl _), + p.count_U_eq_count_D]⟩ + +include h in +lemma count_take_firstReturn_add_one : + (p.toList.take (p.firstReturn + 1)).count U = (p.toList.take (p.firstReturn + 1)).count D := by + have := findIdx_getElem (w := (length_range p.toList.length).symm ▸ firstReturn_lt_length h) + simpa using this + +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_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] +lemma firstReturn_add : (p + q).firstReturn = if p = 0 then q.firstReturn else p.firstReturn := by + split_ifs with h; · simp [h] + have u : (p + q).toList = p.toList ++ q.toList := rfl + rw [firstReturn, findIdx_eq] + · simp_rw [u, decide_eq_true_eq, getElem_range] + have v := firstReturn_lt_length h + constructor + · rw [take_append_eq_append_take, show p.firstReturn + 1 - p.toList.length = 0 by omega, + take_zero, append_nil, count_take_firstReturn_add_one h] + · intro j hj + rw [take_append_eq_append_take, show j + 1 - p.toList.length = 0 by omega, + take_zero, append_nil] + 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) + +@[simp] +lemma firstReturn_nest : p.nest.firstReturn = p.toList.length + 1 := by + have u : p.nest.toList = U :: p.toList ++ [D] := rfl + rw [firstReturn, findIdx_eq] + · simp_rw [u, decide_eq_true_eq, getElem_range] + constructor + · rw [take_of_length_le (by simp), ← u, p.nest.count_U_eq_count_D] + · intro j hj + simp_rw [cons_append, take_succ_cons, count_cons, beq_self_eq_true, ite_true, + 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 _ + +variable (p) in +/-- The left part of the Dyck word decomposition, +inside the `U, D` pair that `firstReturn` refers to. `insidePart 0 = 0`. -/ +def insidePart : DyckWord := + if h : p = 0 then 0 else + (p.take (p.firstReturn + 1) (count_take_firstReturn_add_one h)).denest + ⟨by rw [← toList_ne_nil, take]; simpa using toList_ne_nil.mpr h, fun i lb ub ↦ by + simp only [take, length_take, lt_min_iff] at ub ⊢ + replace ub := ub.1 + rw [take_take, min_eq_left ub.le] + rw [show i = i - 1 + 1 by omega] at ub ⊢ + rw [Nat.add_lt_add_iff_right] at ub + exact count_D_lt_count_U_of_lt_firstReturn ub⟩ + +variable (p) in +/-- The right part of the Dyck word decomposition, +outside the `U, D` pair that `firstReturn` refers to. `outsidePart 0 = 0`. -/ +def outsidePart : DyckWord := + if h : p = 0 then 0 else p.drop (p.firstReturn + 1) (count_take_firstReturn_add_one h) + +@[simp] lemma insidePart_zero : insidePart 0 = 0 := by simp [insidePart] +@[simp] lemma outsidePart_zero : outsidePart 0 = 0 := by simp [outsidePart] + +include h in +@[simp] +lemma insidePart_add : (p + q).insidePart = p.insidePart := by + simp_rw [insidePart, firstReturn_add, add_eq_zero', h, false_and, dite_false, ite_false, + DyckWord.ext_iff, take] + congr 3 + exact take_append_of_le_length (firstReturn_lt_length h) + +include h in +@[simp] +lemma outsidePart_add : (p + q).outsidePart = p.outsidePart + q := by + simp_rw [outsidePart, firstReturn_add, add_eq_zero', h, false_and, dite_false, ite_false, + DyckWord.ext_iff, drop] + exact drop_append_of_le_length (firstReturn_lt_length h) + +@[simp] +lemma insidePart_nest : p.nest.insidePart = p := by + simp_rw [insidePart, nest_ne_zero, dite_false, firstReturn_nest] + convert p.denest_nest; rw [DyckWord.ext_iff]; apply take_of_length_le + simp_rw [nest, length_append, length_singleton]; omega + +@[simp] +lemma outsidePart_nest : p.nest.outsidePart = 0 := by + simp_rw [outsidePart, nest_ne_zero, dite_false, firstReturn_nest] + rw [DyckWord.ext_iff]; apply drop_of_length_le + simp_rw [nest, length_append, length_singleton]; omega + +include h in +@[simp] +theorem nest_insidePart_add_outsidePart : p.insidePart.nest + p.outsidePart = p := by + simp_rw [insidePart, outsidePart, h, dite_false, nest_denest, DyckWord.ext_iff] + apply take_append_drop + +include h in +lemma semilength_insidePart_add_semilength_outsidePart_add_one : + p.insidePart.semilength + p.outsidePart.semilength + 1 = p.semilength := by + rw [← congrArg semilength (nest_insidePart_add_outsidePart h), semilength_add, semilength_nest, + add_right_comm] + +include h in +theorem semilength_insidePart_lt : p.insidePart.semilength < p.semilength := by + have := semilength_insidePart_add_semilength_outsidePart_add_one h + omega + +include h in +theorem semilength_outsidePart_lt : p.outsidePart.semilength < p.semilength := by + have := semilength_insidePart_add_semilength_outsidePart_add_one h + omega + +end FirstReturn + +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 + +lemma le_add_self (p q : DyckWord) : q ≤ p + q := by + by_cases h : p = 0 + · simp [h] + · have := semilength_outsidePart_lt h + exact (le_add_self p.outsidePart q).trans + (Relation.ReflTransGen.single (Or.inr (outsidePart_add h).symm)) +termination_by p.semilength + +variable (p) in protected lemma zero_le : 0 ≤ p := add_zero p ▸ le_add_self p 0 + +lemma infix_of_le (h : p ≤ q) : p.toList <:+: q.toList := by + induction h with + | refl => exact infix_refl _ + | tail _pm mq ih => + rename_i m r + rcases eq_or_ne r 0 with rfl | hr + · rw [insidePart_zero, outsidePart_zero, or_self] at mq + rwa [mq] at ih + · have : [U] ++ r.insidePart ++ [D] ++ r.outsidePart = r := + DyckWord.ext_iff.mp (nest_insidePart_add_outsidePart hr) + rcases mq with hm | hm + · have : r.insidePart <:+: r.toList := by + use [U], [D] ++ r.outsidePart; rwa [← append_assoc] + exact ih.trans (hm ▸ this) + · have : r.outsidePart <:+: r.toList := by + use [U] ++ r.insidePart ++ [D], []; rwa [append_nil] + exact ih.trans (hm ▸ this) + +lemma le_of_suffix (h : p.toList <:+ q.toList) : p ≤ q := by + obtain ⟨r', h⟩ := h + have hc : (q.toList.take (q.toList.length - p.toList.length)).count U = + (q.toList.take (q.toList.length - p.toList.length)).count D := by + have hq := q.count_U_eq_count_D + rw [← h] at hq ⊢ + rw [count_append, count_append, p.count_U_eq_count_D, Nat.add_right_cancel_iff] at hq + simp [hq] + let r : DyckWord := q.take _ hc + have e : r' = r := by + simp_rw [r, take, ← h, length_append, add_tsub_cancel_right, take_left'] + rw [e] at h; replace h : r + p = q := DyckWord.ext h; rw [← h]; exact le_add_self .. + +/-- Partial order on Dyck words: `p ≤ q` if a (possibly empty) sequence of +`insidePart` and `outsidePart` operations can turn `q` into `p`. -/ +instance : PartialOrder DyckWord where + le_antisymm p q pq qp := by + have h₁ := infix_of_le pq + have h₂ := infix_of_le qp + exact DyckWord.ext <| h₁.eq_of_length <| h₁.length_le.antisymm h₂.length_le + +protected lemma pos_iff_ne_zero : 0 < p ↔ p ≠ 0 := by + rw [ne_comm, iff_comm, ne_iff_lt_iff_le] + exact DyckWord.zero_le p + +lemma monotone_semilength : Monotone semilength := fun p q pq ↦ by + induction pq with + | refl => rfl + | tail _ mq ih => + rename_i m r _ + rcases eq_or_ne r 0 with rfl | hr + · rw [insidePart_zero, outsidePart_zero, or_self] at mq + rwa [mq] at ih + · rcases mq with hm | hm + · exact ih.trans (hm ▸ semilength_insidePart_lt hr).le + · exact ih.trans (hm ▸ semilength_outsidePart_lt hr).le + +lemma strictMono_semilength : StrictMono semilength := fun p q pq ↦ by + obtain ⟨plq, pnq⟩ := lt_iff_le_and_ne.mp pq + apply lt_of_le_of_ne (monotone_semilength plq) + contrapose! pnq + replace pnq := congr(2 * $(pnq)) + simp_rw [two_mul_semilength_eq_length] at pnq + exact DyckWord.ext ((infix_of_le plq).eq_of_length pnq) + +end Order + +section Tree + +open Tree + +/-- Convert a Dyck word to a binary rooted tree. + +`f(0) = nil`. For a nonzero word find the `D` that matches the initial `U`, +which has index `p.firstReturn`, then let `x` be everything strictly between said `U` and `D`, +and `y` be everything strictly after said `D`. `p = x.nest + y` with `x, y` (possibly empty) +Dyck words. `f(p) = f(x) △ f(y)`, where △ (defined in `Mathlib.Data.Tree`) joins two subtrees +to a new root node. -/ +private def equivTreeToFun (p : DyckWord) : Tree Unit := + if h : p = 0 then nil else + have := semilength_insidePart_lt h + have := semilength_outsidePart_lt h + equivTreeToFun p.insidePart △ equivTreeToFun p.outsidePart +termination_by p.semilength + +/-- Convert a binary rooted tree to a Dyck word. + +`g(nil) = 0`. A nonempty tree with left subtree `l` and right subtree `r` +is sent to `g(l).nest + g(r)`. -/ +private def equivTreeInvFun : Tree Unit → DyckWord + | Tree.nil => 0 + | Tree.node _ l r => (equivTreeInvFun l).nest + equivTreeInvFun r + +@[nolint unusedHavesSuffices] +private lemma equivTree_left_inv (p) : equivTreeInvFun (equivTreeToFun p) = p := by + by_cases h : p = 0 + · simp [h, equivTreeToFun, equivTreeInvFun] + · rw [equivTreeToFun] + simp_rw [h, dite_false, equivTreeInvFun] + have := semilength_insidePart_lt h + have := semilength_outsidePart_lt h + rw [equivTree_left_inv p.insidePart, equivTree_left_inv p.outsidePart] + exact nest_insidePart_add_outsidePart h +termination_by p.semilength + +@[nolint unusedHavesSuffices] +private lemma equivTree_right_inv : ∀ t, equivTreeToFun (equivTreeInvFun t) = t + | Tree.nil => by simp [equivTreeInvFun, equivTreeToFun] + | Tree.node _ _ _ => by simp [equivTreeInvFun, equivTreeToFun, equivTree_right_inv] + +/-- Equivalence between Dyck words and rooted binary trees. -/ +def equivTree : DyckWord ≃ Tree Unit where + toFun := equivTreeToFun + invFun := equivTreeInvFun + left_inv := equivTree_left_inv + right_inv := equivTree_right_inv + +@[nolint unusedHavesSuffices] +lemma semilength_eq_numNodes_equivTree (p) : p.semilength = (equivTree p).numNodes := by + by_cases h : p = 0 + · simp [h, equivTree, equivTreeToFun] + · rw [equivTree, Equiv.coe_fn_mk, equivTreeToFun] + simp_rw [h, dite_false, numNodes] + have := semilength_insidePart_lt h + have := semilength_outsidePart_lt h + rw [← semilength_insidePart_add_semilength_outsidePart_add_one h, + semilength_eq_numNodes_equivTree p.insidePart, + semilength_eq_numNodes_equivTree p.outsidePart]; rfl +termination_by p.semilength + +/-- Equivalence between Dyck words of semilength `n` and rooted binary trees with +`n` internal nodes. -/ +def equivTreesOfNumNodesEq (n : ℕ) : + { p : DyckWord // p.semilength = n } ≃ treesOfNumNodesEq n where + toFun := fun ⟨p, _⟩ ↦ ⟨equivTree p, by + rwa [mem_treesOfNumNodesEq, ← semilength_eq_numNodes_equivTree]⟩ + invFun := fun ⟨tr, _⟩ ↦ ⟨equivTree.symm tr, by + rwa [semilength_eq_numNodes_equivTree, ← mem_treesOfNumNodesEq, Equiv.apply_symm_apply]⟩ + left_inv _ := by simp only [Equiv.symm_apply_apply] + right_inv _ := by simp only [Equiv.apply_symm_apply] + +instance {n : ℕ} : Fintype { p : DyckWord // p.semilength = n } := + Fintype.ofEquiv _ (equivTreesOfNumNodesEq n).symm + +/-- There are `catalan n` Dyck words of semilength `n` (or length `2 * n`). -/ +theorem card_dyckWord_semilength_eq_catalan (n : ℕ) : + Fintype.card { p : DyckWord // p.semilength = n } = catalan n := by + rw [← Fintype.ofEquiv_card (equivTreesOfNumNodesEq n), ← treesOfNumNodesEq_card_eq_catalan] + convert Fintype.card_coe _ + +end Tree + +end DyckWord + +namespace Mathlib.Meta.Positivity + +open Lean Meta Qq + +/-- Extension for the `positivity` tactic: `p.firstReturn` is positive if `p` is nonzero. -/ +@[positivity DyckWord.firstReturn _] +def evalDyckWordFirstReturn : PositivityExt where eval {u α} _zα _pα e := do + match u, α, e with + | 0, ~q(ℕ), ~q(DyckWord.firstReturn $a) => + let ra ← core q(inferInstance) q(inferInstance) a + assertInstancesCommute + match ra with + | .positive pa => pure (.positive q(DyckWord.firstReturn_pos ($pa).ne')) + | .nonzero pa => pure (.positive q(DyckWord.firstReturn_pos $pa)) + | _ => pure .none + | _, _, _ => throwError "not DyckWord.firstReturn" + +end Mathlib.Meta.Positivity diff --git a/Mathlib/Combinatorics/Enumerative/Partition.lean b/Mathlib/Combinatorics/Enumerative/Partition.lean index d88c1fba8060d..94bcb8771017a 100644 --- a/Mathlib/Combinatorics/Enumerative/Partition.lean +++ b/Mathlib/Combinatorics/Enumerative/Partition.lean @@ -50,7 +50,7 @@ namespace Nat structure Partition (n : ℕ) where /-- positive integers summing to `n`-/ parts : Multiset ℕ - /-- proof that the `parts` are positive-/ + /-- proof that the `parts` are positive -/ parts_pos : ∀ {i}, i ∈ parts → 0 < i /-- proof that the `parts` sum to `n`-/ parts_sum : parts.sum = n diff --git a/Mathlib/Combinatorics/HalesJewett.lean b/Mathlib/Combinatorics/HalesJewett.lean index babe5c7b82742..f02b849012141 100644 --- a/Mathlib/Combinatorics/HalesJewett.lean +++ b/Mathlib/Combinatorics/HalesJewett.lean @@ -4,12 +4,8 @@ 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 /-! # The Hales-Jewett theorem @@ -154,7 +150,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 180890300f1c4..52a8937ef3082 100644 --- a/Mathlib/Combinatorics/Hall/Basic.lean +++ b/Mathlib/Combinatorics/Hall/Basic.lean @@ -57,7 +57,7 @@ universe u v /-- The set of matchings for `t` when restricted to a `Finset` of `ι`. -/ def hallMatchingsOn {ι : Type u} {α : Type v} (t : ι → Finset α) (ι' : Finset ι) := - { f : ι' → α | Function.Injective f ∧ ∀ x, f x ∈ t x } + { f : ι' → α | Function.Injective f ∧ ∀ (x : {x // x ∈ ι'}), f x ∈ t x } /-- Given a matching on a finset, construct the restriction of that matching to a subset. -/ def hallMatchingsOn.restrict {ι : Type u} {α : Type v} (t : ι → Finset α) {ι' ι'' : Finset ι} diff --git a/Mathlib/Combinatorics/Hindman.lean b/Mathlib/Combinatorics/Hindman.lean index d509718bb8861..18555bba2e080 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 @@ -205,17 +206,17 @@ theorem exists_FP_of_finite_cover {M} [Semigroup M] [Nonempty M] (s : Set (Set M @[to_additive FS_iter_tail_sub_FS] theorem FP_drop_subset_FP {M} [Semigroup M] (a : Stream' M) (n : ℕ) : FP (a.drop n) ⊆ FP a := by - induction' n with n ih - · rfl - rw [Nat.add_comm, ← Stream'.drop_drop] - exact _root_.trans (FP.tail _) ih + induction n with + | zero => rfl + | succ n ih => + rw [Nat.add_comm, ← Stream'.drop_drop] + exact _root_.trans (FP.tail _) ih @[to_additive] theorem FP.singleton {M} [Semigroup M] (a : Stream' M) (i : ℕ) : a.get i ∈ FP a := by - induction' i with i ih generalizing a - · apply FP.head - · apply FP.tail - apply ih + induction i generalizing a with + | zero => exact FP.head _ + | succ i ih => exact FP.tail _ _ (ih _) @[to_additive] theorem FP.mul_two {M} [Semigroup M] (a : Stream' M) (i j : ℕ) (ij : i < j) : @@ -223,7 +224,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 +246,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/Quiver/Arborescence.lean b/Mathlib/Combinatorics/Quiver/Arborescence.lean index f535487f7fad2..44f2fe930821c 100644 --- a/Mathlib/Combinatorics/Quiver/Arborescence.lean +++ b/Mathlib/Combinatorics/Quiver/Arborescence.lean @@ -62,27 +62,32 @@ noncomputable def arborescenceMk {V : Type u} [Quiver V] (r : V) (height : V → uniquePath b := ⟨Classical.inhabited_of_nonempty (by rcases show ∃ n, height b < n from ⟨_, Nat.lt.base _⟩ with ⟨n, hn⟩ - induction' n with n ih generalizing b - · exact False.elim (Nat.not_lt_zero _ hn) + induction n generalizing b with + | zero => exact False.elim (Nat.not_lt_zero _ hn) + | succ n ih => rcases root_or_arrow b with (⟨⟨⟩⟩ | ⟨a, ⟨e⟩⟩) · exact ⟨Path.nil⟩ · rcases ih a (lt_of_lt_of_le (height_lt e) (Nat.lt_succ_iff.mp hn)) with ⟨p⟩ exact ⟨p.cons e⟩), by have height_le : ∀ {a b}, Path a b → height a ≤ height b := by intro a b p - induction' p with b c _ e ih - · rfl - · exact le_of_lt (lt_of_le_of_lt ih (height_lt e)) + induction p with + | nil => rfl + | cons _ e ih => exact le_of_lt (lt_of_le_of_lt ih (height_lt e)) suffices ∀ p q : Path r b, p = q by intro p apply this intro p q - induction' p with a c p e ih <;> cases' q with b _ q f - · rfl - · exact False.elim (lt_irrefl _ (lt_of_le_of_lt (height_le q) (height_lt f))) - · exact False.elim (lt_irrefl _ (lt_of_le_of_lt (height_le p) (height_lt e))) - · rcases unique_arrow e f with ⟨⟨⟩, ⟨⟩⟩ - rw [ih]⟩ + induction p with + | nil => + rcases q with _ | ⟨q, f⟩ + · rfl + · exact False.elim (lt_irrefl _ (lt_of_le_of_lt (height_le q) (height_lt f))) + | cons p e ih => + rcases q with _ | ⟨q, f⟩ + · exact False.elim (lt_irrefl _ (lt_of_le_of_lt (height_le p) (height_lt e))) + · rcases unique_arrow e f with ⟨⟨⟩, ⟨⟩⟩ + rw [ih]⟩ /-- `RootedConnected r` means that there is a path from `r` to any other vertex. -/ class RootedConnected {V : Type u} [Quiver V] (r : V) : Prop where diff --git a/Mathlib/Combinatorics/Quiver/Basic.lean b/Mathlib/Combinatorics/Quiver/Basic.lean index 32fe7fd00a050..f0f77f70aa4b7 100644 --- a/Mathlib/Combinatorics/Quiver/Basic.lean +++ b/Mathlib/Combinatorics/Quiver/Basic.lean @@ -1,10 +1,9 @@ /- 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 -import Mathlib.Tactic.Cases /-! # Quivers @@ -72,8 +71,8 @@ theorem ext {V : Type u} [Quiver.{v₁} V] {W : Type u₂} [Quiver.{v₂} W] {F (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 - cases' F with F_obj _ - cases' G with G_obj _ + obtain ⟨F_obj, _⟩ := F + obtain ⟨G_obj, _⟩ := G obtain rfl : F_obj = G_obj := by ext X apply h_obj diff --git a/Mathlib/Combinatorics/Quiver/Path.lean b/Mathlib/Combinatorics/Quiver/Path.lean index a57df538d7c60..d87402e7fb551 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 @@ -104,15 +105,19 @@ theorem length_comp (p : Path a b) : ∀ {c} (q : Path b c), (p.comp q).length = theorem comp_inj {p₁ p₂ : Path a b} {q₁ q₂ : Path b c} (hq : q₁.length = q₂.length) : p₁.comp q₁ = p₂.comp q₂ ↔ p₁ = p₂ ∧ q₁ = q₂ := by refine ⟨fun h => ?_, by rintro ⟨rfl, rfl⟩; rfl⟩ - induction' q₁ with d₁ e₁ q₁ f₁ ih <;> obtain _ | ⟨q₂, f₂⟩ := q₂ - · exact ⟨h, rfl⟩ - · cases hq - · cases hq - · simp only [comp_cons, cons.injEq] at h - obtain rfl := h.1 - obtain ⟨rfl, rfl⟩ := ih (Nat.succ.inj hq) h.2.1.eq - rw [h.2.2.eq] - exact ⟨rfl, rfl⟩ + induction q₁ with + | nil => + rcases q₂ with _ | ⟨q₂, f₂⟩ + · exact ⟨h, rfl⟩ + · cases hq + | cons q₁ f₁ ih => + rcases q₂ with _ | ⟨q₂, f₂⟩ + · cases hq + · simp only [comp_cons, cons.injEq] at h + obtain rfl := h.1 + obtain ⟨rfl, rfl⟩ := ih (Nat.succ.inj hq) h.2.1.eq + rw [h.2.2.eq] + exact ⟨rfl, rfl⟩ theorem comp_inj' {p₁ p₂ : Path a b} {q₁ q₂ : Path b c} (h : p₁.length = p₂.length) : p₁.comp q₁ = p₂.comp q₂ ↔ p₁ = p₂ ∧ q₁ = q₂ := 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/Quiver/SingleObj.lean b/Mathlib/Combinatorics/Quiver/SingleObj.lean index 21fb2f1c43094..0f8ecb66a9de8 100644 --- a/Mathlib/Combinatorics/Quiver/SingleObj.lean +++ b/Mathlib/Combinatorics/Quiver/SingleObj.lean @@ -111,14 +111,14 @@ def listToPath : List α → Path (star α) (star α) theorem listToPath_pathToList {x : SingleObj α} (p : Path (star α) x) : listToPath (pathToList p) = p.cast rfl ext := by - induction' p with y z p a ih - · rfl - · dsimp at *; rw [ih] + induction p with + | nil => rfl + | cons _ _ ih => dsimp at *; rw [ih] theorem pathToList_listToPath (l : List α) : pathToList (listToPath l) = l := by - induction' l with a l ih - · rfl - · change a :: pathToList (listToPath l) = a :: l; rw [ih] + induction l with + | nil => rfl + | cons a l ih => change a :: pathToList (listToPath l) = a :: l; rw [ih] /-- Paths in `SingleObj α` quiver correspond to lists of elements of type `α`. -/ def pathEquivList : Path (star α) (star α) ≃ List α := diff --git a/Mathlib/Combinatorics/Quiver/Symmetric.lean b/Mathlib/Combinatorics/Quiver/Symmetric.lean index 0cbc2f0156725..cf87c843a83f7 100644 --- a/Mathlib/Combinatorics/Quiver/Symmetric.lean +++ b/Mathlib/Combinatorics/Quiver/Symmetric.lean @@ -45,7 +45,7 @@ class HasReverse where def reverse {V} [Quiver.{v + 1} V] [HasReverse V] {a b : V} : (a ⟶ b) → (b ⟶ a) := HasReverse.reverse' -/-- A quiver `HasInvolutiveReverse` if reversing twice is the identity. -/ +/-- A quiver `HasInvolutiveReverse` if reversing twice is the identity. -/ class HasInvolutiveReverse extends HasReverse V where /-- `reverse` is involutive -/ inv' : ∀ {a b : V} (f : a ⟶ b), reverse (reverse f) = f @@ -132,16 +132,17 @@ theorem Path.reverse_toPath [HasReverse V] {a b : V} (f : a ⟶ b) : @[simp] theorem Path.reverse_comp [HasReverse V] {a b c : V} (p : Path a b) (q : Path b c) : (p.comp q).reverse = q.reverse.comp p.reverse := by - induction' q with _ _ _ _ h - · simp - · simp [h] + induction q with + | nil => simp + | cons _ _ h => simp [h] @[simp] theorem Path.reverse_reverse [h : HasInvolutiveReverse V] {a b : V} (p : Path a b) : p.reverse.reverse = p := by - induction' p with _ _ _ _ h - · simp - · rw [Path.reverse, Path.reverse_comp, h, Path.reverse_toPath, Quiver.reverse_reverse] + induction p with + | nil => simp + | cons _ _ h => + rw [Path.reverse, Path.reverse_comp, h, Path.reverse_toPath, Quiver.reverse_reverse] rfl end Paths diff --git a/Mathlib/Combinatorics/Schnirelmann.lean b/Mathlib/Combinatorics/Schnirelmann.lean index 016b6c772835e..266093dff23ab 100644 --- a/Mathlib/Combinatorics/Schnirelmann.lean +++ b/Mathlib/Combinatorics/Schnirelmann.lean @@ -68,7 +68,7 @@ lemma schnirelmannDensity_mul_le_card_filter {n : ℕ} : schnirelmannDensity A * n ≤ ((Ioc 0 n).filter (· ∈ A)).card := by rcases eq_or_ne n 0 with rfl | hn · simp - exact (le_div_iff (by positivity)).1 (schnirelmannDensity_le_div hn) + exact (le_div_iff₀ (by positivity)).1 (schnirelmannDensity_le_div hn) /-- To show the Schnirelmann density is upper bounded by `x`, it suffices to show @@ -196,7 +196,7 @@ lemma schnirelmannDensity_finset (A : Finset ℕ) : schnirelmannDensity A = 0 := let n : ℕ := ⌊A.card / ε⌋₊ + 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`. -/ @@ -243,9 +243,9 @@ lemma schnirelmannDensity_setOf_mod_eq_one {m : ℕ} (hm : m ≠ 1) : simp only [Nat.mul_add_mod', Nat.mod_eq_of_lt hm, add_pos_iff, or_true, and_true, true_and, ← Nat.le_sub_iff_add_le hn, zero_lt_one] exact Nat.mul_le_of_le_div _ _ _ hy' - rw [le_div_iff (Nat.cast_pos.2 hn), mul_comm, ← div_eq_mul_inv] + rw [le_div_iff₀ (Nat.cast_pos.2 hn), mul_comm, ← div_eq_mul_inv] apply (Nat.cast_le.2 (card_le_card this)).trans' - rw [card_image_of_injective, Nat.card_Icc, Nat.sub_zero, div_le_iff (Nat.cast_pos.2 hm'), + rw [card_image_of_injective, Nat.card_Icc, Nat.sub_zero, div_le_iff₀ (Nat.cast_pos.2 hm'), ← Nat.cast_mul, Nat.cast_le, add_one_mul (α := ℕ)] · have := @Nat.lt_div_mul_add n.pred m hm' rwa [← Nat.succ_le, Nat.succ_pred hn.ne'] at this @@ -259,7 +259,7 @@ lemma schnirelmannDensity_setOf_modeq_one {m : ℕ} : rw [← schnirelmannDensity_setOf_mod_eq_one hm] apply schnirelmannDensity_congr ext n - simp only [Set.mem_setOf_eq, Nat.ModEq, Nat.one_mod_of_ne_one hm] + simp only [Set.mem_setOf_eq, Nat.ModEq, Nat.one_mod_eq_one.mpr hm] lemma schnirelmannDensity_setOf_Odd : schnirelmannDensity (setOf Odd) = 2⁻¹ := by have h : setOf Odd = {n | n % 2 = 1} := Set.ext fun _ => Nat.odd_iff diff --git a/Mathlib/Combinatorics/SetFamily/AhlswedeZhang.lean b/Mathlib/Combinatorics/SetFamily/AhlswedeZhang.lean index d7ff51b86ec91..ea08e4e2baeef 100644 --- a/Mathlib/Combinatorics/SetFamily/AhlswedeZhang.lean +++ b/Mathlib/Combinatorics/SetFamily/AhlswedeZhang.lean @@ -87,9 +87,9 @@ private lemma Fintype.sum_div_mul_card_choose_card : have (n) (hn : n ∈ range (card α + 1)) : ((card α).choose n / ((card α - n) * (card α).choose n) : ℚ) = (card α - n : ℚ)⁻¹ := by rw [div_mul_cancel_right₀] - exact cast_ne_zero.2 (choose_pos $ mem_range_succ_iff.1 hn).ne' + exact cast_ne_zero.2 (choose_pos <| mem_range_succ_iff.1 hn).ne' simp only [sum_congr rfl this, mul_eq_mul_left_iff, cast_eq_zero] - convert Or.inl $ sum_range_reflect _ _ with a ha + convert Or.inl <| sum_range_reflect _ _ with a ha rw [add_tsub_cancel_right, cast_sub (mem_range_succ_iff.mp ha)] end @@ -124,7 +124,7 @@ lemma truncatedSup_of_mem (h : a ∈ lowerClosure s) : lemma truncatedSup_of_not_mem (h : a ∉ lowerClosure s) : truncatedSup s a = ⊤ := dif_neg h -@[simp] lemma truncatedSup_empty (a : α) : truncatedSup ∅ a = ⊤ := truncatedSup_of_not_mem $ by simp +@[simp] lemma truncatedSup_empty (a : α) : truncatedSup ∅ a = ⊤ := truncatedSup_of_not_mem (by simp) @[simp] lemma truncatedSup_singleton (b a : α) : truncatedSup {b} a = if a ≤ b then b else ⊤ := by simp [truncatedSup]; split_ifs <;> simp [Finset.filter_true_of_mem, *] @@ -133,7 +133,7 @@ lemma le_truncatedSup : a ≤ truncatedSup s a := by rw [truncatedSup] split_ifs with h · obtain ⟨ℬ, hb, h⟩ := h - exact h.trans $ le_sup' id $ mem_filter.2 ⟨hb, h⟩ + exact h.trans <| le_sup' id <| mem_filter.2 ⟨hb, h⟩ · exact le_top lemma map_truncatedSup [@DecidableRel β (· ≤ ·)] (e : α ≃o β) (s : Finset α) (a : α) : @@ -141,7 +141,7 @@ lemma map_truncatedSup [@DecidableRel β (· ≤ ·)] (e : α ≃o β) (s : Fins have : e a ∈ lowerClosure (s.map e.toEquiv.toEmbedding : Set β) ↔ a ∈ lowerClosure s := by simp simp_rw [truncatedSup, apply_dite e, map_finset_sup', map_top, this] congr with h - simp only [filter_map, Function.comp, Equiv.coe_toEmbedding, RelIso.coe_fn_toEquiv, + simp only [filter_map, Function.comp_def, Equiv.coe_toEmbedding, RelIso.coe_fn_toEquiv, OrderIso.le_iff_le, id] rw [sup'_map] -- TODO: Why can't `simp` use `Finset.sup'_map`? @@ -201,10 +201,10 @@ lemma truncatedInf_le : truncatedInf s a ≤ a := by unfold truncatedInf split_ifs with h · obtain ⟨b, hb, hba⟩ := h - exact hba.trans' $ inf'_le id $ mem_filter.2 ⟨hb, ‹_›⟩ + exact hba.trans' <| inf'_le id <| mem_filter.2 ⟨hb, ‹_›⟩ · exact bot_le -@[simp] lemma truncatedInf_empty (a : α) : truncatedInf ∅ a = ⊥ := truncatedInf_of_not_mem $ by simp +@[simp] lemma truncatedInf_empty (a : α) : truncatedInf ∅ a = ⊥ := truncatedInf_of_not_mem (by simp) @[simp] lemma truncatedInf_singleton (b a : α) : truncatedInf {b} a = if b ≤ a then b else ⊥ := by simp only [truncatedInf, coe_singleton, upperClosure_singleton, UpperSet.mem_Ici_iff, @@ -216,7 +216,7 @@ lemma map_truncatedInf (e : α ≃o β) (s : Finset α) (a : α) : have : e a ∈ upperClosure (s.map e.toEquiv.toEmbedding) ↔ a ∈ upperClosure s := by simp simp_rw [truncatedInf, apply_dite e, map_finset_inf', map_bot, this] congr with h - simp only [filter_map, Function.comp, Equiv.coe_toEmbedding, RelIso.coe_fn_toEquiv, + simp only [filter_map, Function.comp_def, Equiv.coe_toEmbedding, RelIso.coe_fn_toEquiv, OrderIso.le_iff_le, id, inf'_map] lemma truncatedInf_of_isAntichain (hs : IsAntichain (· ≤ ·) (s : Set α)) (ha : a ∈ s) : @@ -245,7 +245,7 @@ lemma truncatedInf_union_right (hs : a ∉ upperClosure s) (ht : a ∈ upperClos lemma truncatedInf_union_of_not_mem (hs : a ∉ upperClosure s) (ht : a ∉ upperClosure t) : truncatedInf (s ∪ t) a = ⊥ := - truncatedInf_of_not_mem $ by rw [coe_union, upperClosure_union]; exact fun h ↦ h.elim hs ht + truncatedInf_of_not_mem <| by rw [coe_union, upperClosure_union]; exact fun h ↦ h.elim hs ht end SemilatticeInf @@ -277,11 +277,11 @@ lemma truncatedInf_sups (hs : a ∈ upperClosure s) (ht : a ∈ upperClosure t) lemma truncatedSup_infs_of_not_mem (ha : a ∉ lowerClosure s ⊓ lowerClosure t) : truncatedSup (s ⊼ t) a = ⊤ := - truncatedSup_of_not_mem $ by rwa [coe_infs, lowerClosure_infs] + truncatedSup_of_not_mem <| by rwa [coe_infs, lowerClosure_infs] lemma truncatedInf_sups_of_not_mem (ha : a ∉ upperClosure s ⊔ upperClosure t) : truncatedInf (s ⊻ t) a = ⊥ := - truncatedInf_of_not_mem $ by rwa [coe_sups, upperClosure_sups] + truncatedInf_of_not_mem <| by rwa [coe_sups, upperClosure_sups] end DistribLattice @@ -301,8 +301,8 @@ 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 - by_cases h𝒜 : s ∈ lowerClosure (𝒜 : Set $ Finset α) <;> - by_cases hℬ : s ∈ lowerClosure (ℬ : Set $ Finset α) + by_cases h𝒜 : s ∈ lowerClosure (𝒜 : Set <| Finset α) <;> + by_cases hℬ : s ∈ lowerClosure (ℬ : Set <| Finset α) · rw [truncatedSup_union h𝒜 hℬ, truncatedSup_infs h𝒜 hℬ] exact card_union_add_card_inter _ _ · rw [truncatedSup_union_left h𝒜 hℬ, truncatedSup_of_not_mem hℬ, @@ -315,8 +315,8 @@ lemma card_truncatedSup_union_add_card_truncatedSup_infs (𝒜 ℬ : Finset (Fin 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 - by_cases h𝒜 : s ∈ upperClosure (𝒜 : Set $ Finset α) <;> - by_cases hℬ : s ∈ upperClosure (ℬ : Set $ Finset α) + by_cases h𝒜 : s ∈ upperClosure (𝒜 : Set <| Finset α) <;> + by_cases hℬ : s ∈ upperClosure (ℬ : Set <| Finset α) · rw [truncatedInf_union h𝒜 hℬ, truncatedInf_sups h𝒜 hℬ] exact card_inter_add_card_union _ _ · rw [truncatedInf_union_left h𝒜 hℬ, truncatedInf_of_not_mem hℬ, @@ -365,7 +365,7 @@ lemma IsAntichain.le_infSum (h𝒜 : IsAntichain (· ⊆ ·) (𝒜 : Set (Finset _ ≤ _ := 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₀] - have := (nonempty_iff_ne_empty.2 $ ne_of_mem_of_not_mem hs h𝒜₀).card_pos + have := (nonempty_iff_ne_empty.2 <| ne_of_mem_of_not_mem hs h𝒜₀).card_pos positivity variable [Nonempty α] diff --git a/Mathlib/Combinatorics/SetFamily/Compression/Down.lean b/Mathlib/Combinatorics/SetFamily/Compression/Down.lean index 222c68d63fd87..a93982a2764cf 100644 --- a/Mathlib/Combinatorics/SetFamily/Compression/Down.lean +++ b/Mathlib/Combinatorics/SetFamily/Compression/Down.lean @@ -35,7 +35,7 @@ compression, down-compression -/ -variable {α : Type*} [DecidableEq α] {𝒜 ℬ : Finset (Finset α)} {s : Finset α} {a : α} +variable {α : Type*} [DecidableEq α] {𝒜 : Finset (Finset α)} {s : Finset α} {a : α} namespace Finset diff --git a/Mathlib/Combinatorics/SetFamily/Compression/UV.lean b/Mathlib/Combinatorics/SetFamily/Compression/UV.lean index 5ebbd630b7265..8bfa4e268eb8a 100644 --- a/Mathlib/Combinatorics/SetFamily/Compression/UV.lean +++ b/Mathlib/Combinatorics/SetFamily/Compression/UV.lean @@ -327,7 +327,7 @@ theorem shadow_compression_subset_compression_shadow (u v : Finset α) exact ⟨Or.inl hat, hav⟩ · rw [← erase_sdiff_comm, sup_eq_union, erase_union_distrib, erase_eq_of_not_mem hau] intro s hs𝒜' hs𝒜 - -- This is gonna be useful a couple of times so let's name it. + -- This is going to be useful a couple of times so let's name it. have m : ∀ y, y ∉ s → insert y s ∉ 𝒜 := fun y h a => hs𝒜 (mem_shadow_iff_insert_mem.2 ⟨y, h, a⟩) obtain ⟨x, _, _⟩ := mem_shadow_iff_insert_mem.1 hs𝒜' have hus : u ⊆ insert x s := le_of_mem_compression_of_not_mem ‹_ ∈ 𝒜'› (m _ ‹x ∉ s›) diff --git a/Mathlib/Combinatorics/SetFamily/FourFunctions.lean b/Mathlib/Combinatorics/SetFamily/FourFunctions.lean index 2c7b78ec4d1b5..d3bd37943cd19 100644 --- a/Mathlib/Combinatorics/SetFamily/FourFunctions.lean +++ b/Mathlib/Combinatorics/SetFamily/FourFunctions.lean @@ -219,7 +219,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 diff --git a/Mathlib/Combinatorics/SetFamily/Kleitman.lean b/Mathlib/Combinatorics/SetFamily/Kleitman.lean index 7fe6c323c2871..e534f30f51b45 100644 --- a/Mathlib/Combinatorics/SetFamily/Kleitman.lean +++ b/Mathlib/Combinatorics/SetFamily/Kleitman.lean @@ -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 new file mode 100644 index 0000000000000..8b5ce0135fec7 --- /dev/null +++ b/Mathlib/Combinatorics/SetFamily/KruskalKatona.lean @@ -0,0 +1,294 @@ +/- +Copyright (c) 2020 Bhavik Mehta. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Bhavik Mehta, Yaël Dillies +-/ +import Mathlib.Combinatorics.Colex +import Mathlib.Combinatorics.SetFamily.Compression.UV + +/-! +# Kruskal-Katona theorem + +This file proves the Kruskal-Katona theorem. This is a sharp statement about how many sets of size +`k - 1` are covered by a family of sets of size `k`, given only its size. + +## Main declarations + +The key results proved here are: +* `Finset.kruskal_katona`: The basic Kruskal-Katona theorem. 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 shows that the minimum shadow size is + achieved by initial segments of colex. +* `Finset.iterated_kruskal_katona`: An iterated form of the Kruskal-Katona theorem, stating that the + minimum iterated shadow size is given by initial segments of colex. + +## TODO + +* Define the `k`-cascade representation of a natural and prove the corresponding version of + Kruskal-Katona. +* Abstract away from `Fin n` so that it also applies to `ℕ`. Probably `LocallyFiniteOrderBot` + will help here. +* Characterise the equality case. + +## References + +* http://b-mehta.github.io/maths-notes/iii/mich/combinatorics.pdf +* http://discretemath.imp.fu-berlin.de/DMII-2015-16/kruskal.pdf + +## Tags + +kruskal-katona, kruskal, katona, shadow, initial segments, intersecting +-/ + +-- TODO: There's currently a diamond. See https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/DecidableEq.20diamond.20on.20Fin +-- import Mathlib.Order.Fin.Basic +-- example (n : ℕ) : instDecidableEqFin n = instDecidableEq_mathlib := rfl +attribute [-instance] instDecidableEqFin + +open Nat +open scoped FinsetFamily + +namespace Finset +namespace Colex +variable {α : Type*} [LinearOrder α] {𝒜 𝒜₁ 𝒜₂ : Finset (Finset α)} {s t : Finset α} {r : ℕ} + +/-- This is important for iterating Kruskal-Katona: the shadow of an initial segment is also an +initial segment. -/ +lemma shadow_initSeg [Fintype α] (hs : s.Nonempty) : + ∂ (initSeg s) = initSeg (erase s <| min' s hs) := by + -- This is a pretty painful proof, with lots of cases. + ext t + simp only [mem_shadow_iff_insert_mem, mem_initSeg, exists_prop] + constructor + -- First show that if t ∪ a ≤ s, then t ≤ s - min s + · rintro ⟨a, ha, hst, hts⟩ + constructor + · rw [card_erase_of_mem (min'_mem _ _), hst, card_insert_of_not_mem ha, add_tsub_cancel_right] + · simpa [ha] using erase_le_erase_min' hts hst.ge (mem_insert_self _ _) + -- Now show that if t ≤ s - min s, there is j such that t ∪ j ≤ s + -- We choose j as the smallest thing not in t + simp_rw [le_iff_eq_or_lt, lt_iff_exists_filter_lt, mem_sdiff, filter_inj, and_assoc] + simp only [toColex_inj, ofColex_toColex, ne_eq, and_imp] + rintro cards' (rfl | ⟨k, hks, hkt, z⟩) + -- If t = s - min s, then use j = min s so t ∪ j = s + · refine ⟨min' s hs, not_mem_erase _ _, ?_⟩ + rw [insert_erase (min'_mem _ _)] + exact ⟨rfl, Or.inl rfl⟩ + set j := min' tᶜ ⟨k, mem_compl.2 hkt⟩ + -- 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 _ _)] + 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, + 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 + rcases lt_trichotomy k a with (lt | rfl | gt) + · apply mem_insert_of_mem + rw [z lt] + refine mem_erase_of_ne_of_mem (lt_of_le_of_lt ?_ lt).ne' ha + apply min'_le _ _ (mem_of_mem_erase ‹_›) + · rw [r₁]; apply mem_insert_self + · apply mem_insert_of_mem + rw [← r₁] at gt + by_contra + apply (min'_le tᶜ _ _).not_lt gt + rwa [mem_compl] + +/-- The shadow of an initial segment is also an initial segment. -/ +protected lemma IsInitSeg.shadow [Finite α] (h₁ : IsInitSeg 𝒜 r) : IsInitSeg (∂ 𝒜) (r - 1) := by + cases nonempty_fintype α + obtain rfl | hr := Nat.eq_zero_or_pos r + · have : 𝒜 ⊆ {∅} := fun s hs ↦ by rw [mem_singleton, ← Finset.card_eq_zero]; exact h₁.1 hs + have := shadow_monotone this + simp only [subset_empty, le_eq_subset, shadow_singleton_empty] at this + simp [this] + obtain rfl | h𝒜 := 𝒜.eq_empty_or_nonempty + · simp + obtain ⟨s, rfl, rfl⟩ := h₁.exists_initSeg h𝒜 + rw [shadow_initSeg (card_pos.1 hr), ← card_erase_of_mem (min'_mem _ _)] + exact isInitSeg_initSeg + +end Colex + +open Finset Colex Nat UV +open scoped BigOperators FinsetFamily + +variable {α : Type*} [LinearOrder α] {s U V : Finset α} {n : ℕ} + +namespace UV + +/-- Applying the compression makes the set smaller in colex. This is intuitive since a portion of +the set is being "shifted down" as `max U < max V`. -/ +lemma toColex_compress_lt_toColex {hU : U.Nonempty} {hV : V.Nonempty} (h : max' U hU < max' V hV) + (hA : compress U V s ≠ s) : toColex (compress U V s) < toColex s := by + rw [compress, ite_ne_right_iff] at hA + rw [compress, if_pos hA.1, lt_iff_exists_filter_lt] + simp_rw [mem_sdiff (s := s), filter_inj, and_assoc] + refine ⟨_, hA.1.2 <| max'_mem _ hV, not_mem_sdiff_of_mem_right <| max'_mem _ _, fun a ha ↦ ?_⟩ + have : a ∉ V := fun H ↦ ha.not_le (le_max' _ _ H) + have : a ∉ U := fun H ↦ ha.not_lt ((le_max' _ _ H).trans_lt h) + simp [‹a ∉ U›, ‹a ∉ V›] + +/-- 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 + +private instance UsefulCompression.instDecidableRel : @DecidableRel (Finset α) UsefulCompression := + 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 + 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) + · rw [← hU'] at same_size + have : erase U x = ∅ := by rw [← Finset.card_eq_zero, card_erase_of_mem Hx, ← hU'] + have : erase V (min' V hV) = ∅ := by + rw [← Finset.card_eq_zero, card_erase_of_mem (min'_mem _ _), ← same_size] + rw [‹erase U x = ∅›, ‹erase V (min' V hV) = ∅›] + exact isCompressed_self _ _ + refine h₂ ⟨UVd.mono (erase_subset ..) (erase_subset ..), ?_, ?_, ?_, ?_⟩ (card_erase_lt_of_mem Hx) + · rw [card_erase_of_mem (min'_mem _ _), card_erase_of_mem Hx, same_size] + · rwa [← card_pos, card_erase_of_mem Hx, tsub_pos_iff_lt] + · rwa [← Finset.card_pos, card_erase_of_mem (min'_mem _ _), ← same_size, tsub_pos_iff_lt] + · exact (Finset.max'_subset _ <| erase_subset _ _).trans_lt (max_lt.trans_le <| le_max' _ _ <| + mem_erase.2 ⟨(min'_lt_max'_of_card _ (by rwa [← same_size])).ne', max'_mem _ _⟩) + +/-- If we're compressed by all useful compressions, then we're an initial segment. This is the other +key Kruskal-Katona part. -/ +lemma isInitSeg_of_compressed {ℬ : Finset (Finset α)} {r : ℕ} (h₁ : (ℬ : Set (Finset α)).Sized r) + (h₂ : ∀ U V, UsefulCompression U V → IsCompressed U V ℬ) : IsInitSeg ℬ r := by + refine ⟨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 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 + have disj : Disjoint (B \ A) (A \ B) := disjoint_sdiff.mono_left sdiff_subset + have smaller : max' _ hV < max' _ hU := by + obtain hlt | heq | hgt := lt_trichotomy (max' _ hU) (max' _ hV) + · rw [← compress_sdiff_sdiff A B] at hAB hBA + cases hBA.not_lt <| toColex_compress_lt_toColex hlt hAB + · exact (disjoint_right.1 disj (max'_mem _ hU) <| heq.symm ▸ max'_mem _ _).elim + · assumption + refine hB ?_ + rw [← (h₂ _ _ ⟨disj, card_sdiff_comm hAB'.symm, hV, hU, smaller⟩).eq] + exact mem_compression.2 (Or.inr ⟨hB, A, hA, compress_sdiff_sdiff _ _⟩) + +attribute [-instance] Fintype.decidableForallFintype + +/-- This measures roughly how compressed the family is. + +Note that this does depend on the order of the ground set, unlike the Kruskal-Katona theorem itself +(although `kruskal_katona` currently is stated in an order-dependent manner). -/ +private def familyMeasure (𝒜 : Finset (Finset (Fin n))) : ℕ := ∑ A in 𝒜, ∑ a in A, 2 ^ (a : ℕ) + +/-- Applying a compression strictly decreases the measure. This helps show that "compress until we +can't any more" is a terminating process. -/ +private lemma familyMeasure_compression_lt_familyMeasure {U V : Finset (Fin n)} {hU : U.Nonempty} + {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 + 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 ∉ 𝒜) = 𝒜 := + filter_union_filter_neg_eq _ _ + have ne₂ : (𝒜.filter fun 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 + rw [familyMeasure, familyMeasure, sum_union compress_disjoint] + conv_rhs => rw [← uA] + rw [sum_union (disjoint_filter_filter_neg _ _ _), add_lt_add_iff_left, filter_image, + sum_image compress_injOn] + refine sum_lt_sum_of_nonempty ne₂ fun A hA ↦ ?_ + simp_rw [← sum_image Fin.val_injective.injOn] + rw [geomSum_lt_geomSum_iff_toColex_lt_toColex le_rfl, + toColex_image_lt_toColex_image Fin.val_strictMono] + exact toColex_compress_lt_toColex h <| q _ hA + +/-- The main Kruskal-Katona helper: use induction with our measure to keep compressing until +we can't any more, which gives a set family which is fully compressed and has the nice properties we +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 ∧ + (ℬ : 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 𝒜 + 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 ↦ ?_⟩ + rw [eq_empty_iff_forall_not_mem] at husable + 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 + rw [mem_filter] at hUV + have h₂ : ∀ U₁ V₁, UsefulCompression U₁ V₁ → U₁.card < U.card → 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₂ + 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') + exact ⟨t, q1.trans p1, (card_compression _ _ _).symm.trans q2, q3, q4⟩ +termination_by familyMeasure 𝒜 + +end UV + +-- Finally we can prove Kruskal-Katona. +section KK +variable {r k i : ℕ} {𝒜 𝒞 : Finset <| Finset <| Fin n} + +/-- The **Kruskal-Katona theorem**. + +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 + -- WLOG `|𝒜| = |𝒞|` + obtain ⟨𝒜', h𝒜, h𝒜𝒞⟩ := exists_subset_card_eq h𝒞𝒜 + -- By `kruskal_katona_helper`, we find a fully compressed family `ℬ` of the same size as `𝒜` + -- whose shadow is no bigger. + obtain ⟨ℬ, hℬ𝒜, h𝒜ℬ, hℬr, hℬ⟩ := UV.kruskal_katona_helper 𝒜' (h𝒜r.mono (by gcongr)) + -- 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𝒜𝒞 + 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 + induction' k with _k ih generalizing r 𝒜 𝒞 + · simpa + · refine ih h₁.shadow (kruskal_katona h₁ h₂ h₃) ?_ + convert h₃.shadow + +end KK +end Finset diff --git a/Mathlib/Combinatorics/SetFamily/LYM.lean b/Mathlib/Combinatorics/SetFamily/LYM.lean index b4677cec67585..6b5887d58e1ee 100644 --- a/Mathlib/Combinatorics/SetFamily/LYM.lean +++ b/Mathlib/Combinatorics/SetFamily/LYM.lean @@ -198,7 +198,7 @@ theorem sum_card_slice_div_choose_le_one [Fintype α] classical rw [← sum_flip] refine (le_card_falling_div_choose le_rfl h𝒜).trans ?_ - rw [div_le_iff] <;> norm_cast + rw [div_le_iff₀] <;> norm_cast · simpa only [Nat.sub_self, one_mul, Nat.choose_zero_right, falling] using Set.Sized.card_le (sized_falling 0 𝒜) · rw [tsub_self, choose_zero_right] diff --git a/Mathlib/Combinatorics/SetFamily/Shadow.lean b/Mathlib/Combinatorics/SetFamily/Shadow.lean index 4e2ec1fbdfd94..a3b293b819c4c 100644 --- a/Mathlib/Combinatorics/SetFamily/Shadow.lean +++ b/Mathlib/Combinatorics/SetFamily/Shadow.lean @@ -50,7 +50,7 @@ namespace Finset section Shadow -variable [DecidableEq α] {𝒜 : Finset (Finset α)} {s t : Finset α} {a : α} {k r : ℕ} +variable [DecidableEq α] {𝒜 ℬ : Finset (Finset α)} {s t : Finset α} {a : α} {k r : ℕ} /-- The shadow of a set family `𝒜` is all sets we can get by removing one element from any set in `𝒜`, and the (`k` times) iterated shadow (`shadow^[k]`) is all sets we can get by removing `k` @@ -75,12 +75,17 @@ 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 _ _ => sup_mono +@[gcongr] lemma shadow_mono (h𝒜ℬ : 𝒜 ⊆ ℬ) : ∂ 𝒜 ⊆ ∂ ℬ := shadow_monotone h𝒜ℬ + /-- `t` is in the shadow of `𝒜` iff there is a `s ∈ 𝒜` from which we can remove one element to get `t`. -/ lemma mem_shadow_iff : t ∈ ∂ 𝒜 ↔ ∃ s ∈ 𝒜, ∃ a ∈ s, erase s a = t := by diff --git a/Mathlib/Combinatorics/SetFamily/Shatter.lean b/Mathlib/Combinatorics/SetFamily/Shatter.lean index 6efd8f20ec42e..74f21f70fbc02 100644 --- a/Mathlib/Combinatorics/SetFamily/Shatter.lean +++ b/Mathlib/Combinatorics/SetFamily/Shatter.lean @@ -79,7 +79,7 @@ def shatterer (𝒜 : Finset (Finset α)) : Finset (Finset α) := (𝒜.biUnion 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 := @@ -181,6 +181,8 @@ 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 +@[gcongr] lemma vcDim_mono (h𝒜ℬ : 𝒜 ⊆ ℬ) : 𝒜.vcDim ≤ ℬ.vcDim := by unfold vcDim; gcongr + lemma Shatters.card_le_vcDim (hs : 𝒜.Shatters s) : s.card ≤ 𝒜.vcDim := le_sup <| mem_shatterer.2 hs /-- Down-compressing decreases the VC-dimension. -/ diff --git a/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean b/Mathlib/Combinatorics/SimpleGraph/Acyclic.lean index 6b8117d6925da..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 @@ -170,11 +170,12 @@ lemma IsTree.card_edgeFinset [Fintype V] [Fintype G.edgeSet] (hG : G.IsTree) : · exact (congrArg (·.fst) h) · have h1 : ((f a).firstDart <| not_nil_of_ne (by simpa using ha)).snd = b := congrArg (·.snd) h - have h3 := congrArg length (hf' _ (((f _).tail _).copy h1 rfl) ?_) - · rw [length_copy, ← add_left_inj 1, length_tail_add_one] at h3 + have h3 := congrArg length (hf' _ ((f _).tail.copy h1 rfl) ?_) + · rw [length_copy, ← add_left_inj 1, + length_tail_add_one (not_nil_of_ne (by simpa using ha))] at h3 omega · simp only [ne_eq, eq_mp_eq_cast, id_eq, isPath_copy] - exact (hf _).tail _ + exact (hf _).tail (not_nil_of_ne (by simpa using ha)) case surj => simp only [mem_edgeFinset, Finset.mem_compl, Finset.mem_singleton, Sym2.forall, mem_edgeSet] intros x y h @@ -188,7 +189,7 @@ lemma IsTree.card_edgeFinset [Fintype V] [Fintype G.edgeSet] (hG : G.IsTree) : length_cons, length_nil] at h' simp [Nat.le_zero, Nat.one_ne_zero] at h' rw [← hf' _ (.cons h.symm (f x)) ((cons_isPath_iff _ _).2 ⟨hf _, fun hy => ?contra⟩)] - · rfl + · simp only [firstDart_toProd, getVert_cons_succ, getVert_zero, Prod.swap_prod_mk] case contra => suffices (f x).takeUntil y hy = .cons h .nil by rw [← take_spec _ hy] at h' diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index fff296e425ccc..ed55cb02e74c6 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 @@ -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) := @@ -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 @@ -816,7 +819,7 @@ theorem deleteEdges_deleteEdges (s s' : Set (Sym2 V)) : lemma deleteEdges_le (s : Set (Sym2 V)) : G.deleteEdges s ≤ G := sdiff_le lemma deleteEdges_anti (h : s₁ ⊆ s₂) : G.deleteEdges s₂ ≤ G.deleteEdges s₁ := - sdiff_le_sdiff_left $ fromEdgeSet_mono h + sdiff_le_sdiff_left <| fromEdgeSet_mono h lemma deleteEdges_mono (h : G ≤ H) : G.deleteEdges s ≤ H.deleteEdges s := sdiff_le_sdiff_right h diff --git a/Mathlib/Combinatorics/SimpleGraph/Circulant.lean b/Mathlib/Combinatorics/SimpleGraph/Circulant.lean index 1b44d179c5ede..121f720ec7a12 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Circulant.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Circulant.lean @@ -3,8 +3,8 @@ 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.Basic import Mathlib.Combinatorics.SimpleGraph.Hasse -import Mathlib.Data.Set.Pointwise.Basic /-! # Definition of circulant graphs diff --git a/Mathlib/Combinatorics/SimpleGraph/Clique.lean b/Mathlib/Combinatorics/SimpleGraph/Clique.lean index 8de6f50777720..4023561674eb6 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 @@ -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, diff --git a/Mathlib/Combinatorics/SimpleGraph/Coloring.lean b/Mathlib/Combinatorics/SimpleGraph/Coloring.lean index 455f7edb1ac0e..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. @@ -370,8 +368,8 @@ lemma chromaticNumber_eq_iff_forall_surjective (hG : G.Colorable n) : rw [← hG.chromaticNumber_le.ge_iff_eq, le_chromaticNumber_iff_forall_surjective] theorem chromaticNumber_bot [Nonempty V] : (⊥ : SimpleGraph V).chromaticNumber = 1 := by - have : (⊥ : SimpleGraph V).Colorable 1 := ⟨.mk 0 $ by simp⟩ - exact this.chromaticNumber_le.antisymm $ ENat.one_le_iff_pos.2 $ chromaticNumber_pos this + have : (⊥ : SimpleGraph V).Colorable 1 := ⟨.mk 0 <| by simp⟩ + exact this.chromaticNumber_le.antisymm <| Order.one_le_iff_pos.2 <| chromaticNumber_pos this @[simp] theorem chromaticNumber_top [Fintype V] : (⊤ : SimpleGraph V).chromaticNumber = Fintype.card V := by diff --git a/Mathlib/Combinatorics/SimpleGraph/ConcreteColorings.lean b/Mathlib/Combinatorics/SimpleGraph/ConcreteColorings.lean index f82cadc1929e4..33ece69cf7414 100644 --- a/Mathlib/Combinatorics/SimpleGraph/ConcreteColorings.lean +++ b/Mathlib/Combinatorics/SimpleGraph/ConcreteColorings.lean @@ -62,13 +62,13 @@ theorem Coloring.even_length_iff_congr {α} {G : SimpleGraph α} theorem Coloring.odd_length_iff_not_congr {α} {G : SimpleGraph α} (c : G.Coloring Bool) {u v : α} (p : G.Walk u v) : Odd p.length ↔ (¬c u ↔ c v) := by - rw [Nat.odd_iff_not_even, c.even_length_iff_congr p] + rw [← Nat.not_even_iff_odd, c.even_length_iff_congr p] tauto theorem Walk.three_le_chromaticNumber_of_odd_loop {α} {G : SimpleGraph α} {u : α} (p : G.Walk u u) (hOdd : Odd p.length) : 3 ≤ G.chromaticNumber := Classical.by_contradiction <| by intro h - have h' : G.chromaticNumber ≤ 2 := ENat.le_of_lt_add_one <| not_le.mp h + have h' : G.chromaticNumber ≤ 2 := Order.le_of_lt_add_one <| not_le.mp h let c : G.Coloring (Fin 2) := (chromaticNumber_le_iff_colorable.mp h').some let c' : G.Coloring Bool := recolorOfEquiv G finTwoEquiv c have : ¬c' u ↔ c' u := (c'.odd_length_iff_not_congr p).mp hOdd diff --git a/Mathlib/Combinatorics/SimpleGraph/Connectivity/Subgraph.lean b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Subgraph.lean index e73b22eb31d5a..b19fdc540c1bb 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Connectivity/Subgraph.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Connectivity/Subgraph.lean @@ -189,9 +189,9 @@ theorem toSubgraph_adj_getVert {u v} (w : G.Walk u v) {i : ℕ} (hi : i < w.leng | nil => cases hi | cons hxy i' ih => cases i - · simp only [Walk.toSubgraph, Walk.getVert_zero, zero_add, cons_getVert_succ, Subgraph.sup_adj, + · simp only [Walk.toSubgraph, Walk.getVert_zero, zero_add, getVert_cons_succ, Subgraph.sup_adj, subgraphOfAdj_adj, true_or] - · simp only [Walk.toSubgraph, cons_getVert_succ, Subgraph.sup_adj, subgraphOfAdj_adj, Sym2.eq, + · simp only [Walk.toSubgraph, getVert_cons_succ, Subgraph.sup_adj, subgraphOfAdj_adj, Sym2.eq, Sym2.rel_iff', Prod.mk.injEq, Prod.swap_prod_mk] right exact ih (Nat.succ_lt_succ_iff.mp hi) @@ -211,7 +211,7 @@ theorem toSubgraph_adj_iff {u v u' v'} (w : G.Walk u v) : cases hadj with | inl hl => use 0 - simp only [Walk.getVert_zero, zero_add, cons_getVert_succ] + simp only [Walk.getVert_zero, zero_add, getVert_cons_succ] refine ⟨?_, by simp only [length_cons, Nat.zero_lt_succ]⟩ simp only [Sym2.eq, Sym2.rel_iff', Prod.mk.injEq, Prod.swap_prod_mk] cases hl with @@ -220,7 +220,7 @@ theorem toSubgraph_adj_iff {u v u' v'} (w : G.Walk u v) : | inr hr => obtain ⟨i, hi⟩ := (toSubgraph_adj_iff _).mp hr use i + 1 - simp only [cons_getVert_succ] + simp only [getVert_cons_succ] constructor · exact hi.1 · simp only [Walk.length_cons, add_lt_add_iff_right, Nat.add_lt_add_right hi.2 1] diff --git a/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkCounting.lean b/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkCounting.lean index bb84cf7219624..51818e2375813 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkCounting.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkCounting.lean @@ -41,7 +41,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 : ℕ) : @@ -58,8 +58,6 @@ theorem set_walk_length_succ_eq (u v : V) (n : ℕ) : · rintro ⟨w, huw, pwv, rfl, rfl, rfl⟩ rfl -variable [DecidableEq V] - /-- Walks of length two from `u` to `v` correspond bijectively to common neighbours of `u` and `v`. Note that `u` and `v` may be the same. -/ @[simps] @@ -73,7 +71,7 @@ def walkLengthTwoEquivCommonNeighbors (u v : V) : section LocallyFinite -variable [LocallyFinite G] +variable [DecidableEq V] [LocallyFinite G] /-- The `Finset` of length-`n` walks from `u` to `v`. This is used to give `{p : G.walk u v | p.length = n}` a `Fintype` instance, and it @@ -109,12 +107,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] @@ -134,16 +156,36 @@ theorem card_set_walk_length_eq (u v : V) (n : ℕ) : 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] + 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 ((G.finsetWalkLengthLT n u v).filter Walk.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 [Fintype V] [DecidableRel G.Adj] +variable [DecidableEq V] [Fintype V] [DecidableRel G.Adj] theorem reachable_iff_exists_finsetWalkLength_nonempty (u v : V) : G.Reachable u v ↔ ∃ n : Fin (Fintype.card V), (G.finsetWalkLength n u v).Nonempty := by @@ -151,7 +193,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⟩ @@ -168,12 +210,46 @@ instance : Decidable G.Connected := by rw [connected_iff, ← Finset.univ_nonempty_iff] infer_instance +open Finset in +instance Path.instFintype {u v : V} : Fintype (G.Path u v) where + elems := (univ (α := { p : G.Walk u v | p.IsPath ∧ p.length < Fintype.card V })).map + ⟨fun p ↦ { val := p.val, property := p.prop.left }, + 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) + c.recOn (fun w ↦ decidable_of_iff (G.Reachable v w) <| by simp) (fun _ _ _ _ ↦ Subsingleton.elim _ _) -lemma odd_card_iff_odd_components : Odd (Nat.card V) ↔ +variable {G} in +lemma disjiUnion_supp_toFinset_eq_supp_toFinset {G' : SimpleGraph V} (h : G ≤ G') + (c' : ConnectedComponent G') [Fintype c'.supp] + [DecidablePred fun c : G.ConnectedComponent ↦ c.supp ⊆ c'.supp] : + .disjiUnion {c : ConnectedComponent G | c.supp ⊆ c'.supp} (fun c ↦ c.supp.toFinset) + (fun x _ y _ hxy ↦ by simpa using pairwise_disjoint_supp_connectedComponent _ hxy) = + c'.supp.toFinset := + Finset.coe_injective <| by simpa using ConnectedComponent.biUnion_supp_eq_supp h _ + +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 + 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 + +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 + cases nonempty_fintype V rw [Nat.card_eq_fintype_card] simp only [← (set_fintype_card_eq_univ_iff _).mpr G.iUnion_connectedComponentSupp, ConnectedComponent.mem_supp_iff, Fintype.card_subtype_compl, @@ -184,8 +260,6 @@ lemma odd_card_iff_odd_components : Odd (Nat.card V) ↔ rw [Nat.card_eq_fintype_card, Fintype.card_ofFinset] exact (Finset.odd_sum_iff_odd_card_odd (fun x : G.ConnectedComponent ↦ Nat.card x.supp)) -end Finite - end WalkCounting end SimpleGraph diff --git a/Mathlib/Combinatorics/SimpleGraph/Dart.lean b/Mathlib/Combinatorics/SimpleGraph/Dart.lean index 34379dcf7bf71..8919e4cea77bf 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Dart.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Dart.lean @@ -39,6 +39,14 @@ theorem Dart.ext (d₁ d₂ : G.Dart) (h : d₁.toProd = d₂.toProd) : d₁ = d -- Porting note: deleted `Dart.fst` and `Dart.snd` since they are now invalid declaration names, -- even though there is not actually a `SimpleGraph.Dart.fst` or `SimpleGraph.Dart.snd`. +@[simp] +theorem Dart.fst_ne_snd (d : G.Dart) : d.fst ≠ d.snd := + fun h ↦ G.irrefl (h ▸ d.adj) + +@[simp] +theorem Dart.snd_ne_fst (d : G.Dart) : d.snd ≠ d.fst := + fun h ↦ G.irrefl (h ▸ d.adj) + theorem Dart.toProd_injective : Function.Injective (Dart.toProd : G.Dart → V × V) := Dart.ext diff --git a/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean b/Mathlib/Combinatorics/SimpleGraph/DegreeSum.lean index 5364ee41b6234..4b09938bdf173 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 @@ -51,7 +51,7 @@ 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 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⟩ @@ -121,8 +121,8 @@ 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] - rw [ZMod.eq_zero_iff_even, ZMod.eq_one_iff_odd, Nat.odd_iff_not_even, imp_self] + 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) @@ -131,7 +131,7 @@ theorem odd_card_odd_degree_vertices_ne [Fintype V] [DecidableEq V] [DecidableRe have hk : 0 < k := by have hh : (filter (fun v : V => Odd (G.degree v)) univ).Nonempty := 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,7 +144,7 @@ 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 @@ -154,7 +154,7 @@ theorem exists_ne_odd_degree_of_exists_odd_degree [Fintype V] [DecidableRel G.Ad 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 3da2261efc324..f71bb81713dbb 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Density.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Density.lean @@ -122,7 +122,7 @@ theorem edgeDensity_nonneg (s : Finset α) (t : Finset β) : 0 ≤ edgeDensity r 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 _ @@ -165,7 +165,7 @@ theorem mul_edgeDensity_le_edgeDensity (hs : s₂ ⊆ s₁) (ht : t₂ ⊆ t₁) (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] - rw [edgeDensity, edgeDensity, div_mul_div_comm, mul_comm, div_mul_div_cancel _ hst] + rw [edgeDensity, edgeDensity, div_mul_div_comm, mul_comm, div_mul_div_cancel₀ hst] gcongr exact interedges_mono hs ht @@ -175,10 +175,10 @@ theorem edgeDensity_sub_edgeDensity_le_one_sub_mul (hs : s₂ ⊆ s₁) (ht : t 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) : @@ -214,9 +214,9 @@ theorem abs_edgeDensity_sub_edgeDensity_le_two_mul_sub_sq (hs : s₂ ⊆ s₁) ( have h₁ := hs₂'.mono hs have h₂ := ht₂'.mono ht gcongr - · refine (le_div_iff ?_).2 hs₂ + · refine (le_div_iff₀ ?_).2 hs₂ exact mod_cast h₁.card_pos - · refine (le_div_iff ?_).2 ht₂ + · refine (le_div_iff₀ ?_).2 ht₂ exact mod_cast h₂.card_pos /-- If `s₂ ⊆ s₁`, `t₂ ⊆ t₁` and they take up all but a `δ`-proportion, then the difference in edge diff --git a/Mathlib/Combinatorics/SimpleGraph/Diam.lean b/Mathlib/Combinatorics/SimpleGraph/Diam.lean new file mode 100644 index 0000000000000..7e6b6d1920a5b --- /dev/null +++ b/Mathlib/Combinatorics/SimpleGraph/Diam.lean @@ -0,0 +1,200 @@ +/- +Copyright (c) 2024 Rida Hamadani. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rida Hamadani +-/ +import Mathlib.Combinatorics.SimpleGraph.Metric + +/-! +# Diameter of a simple graph + +This module defines the diameter of a simple graph, which measures the maximum distance between +vertices. + +## Main definitions + +- `SimpleGraph.ediam` is the graph extended diameter. + +- `SimpleGraph.diam` is the graph diameter. + +## Todo + +- Prove that `G.egirth ≤ 2 * G.ediam + 1` and `G.girth ≤ 2 * G.diam + 1` when the diameter is + non-zero. + +-/ + +namespace SimpleGraph +variable {α : Type*} {G G' : SimpleGraph α} + +section ediam + +/-- +The extended diameter is the greatest distance between any two vertices, with the value `⊤` in +case the distances are not bounded above, or the graph is not connected. +-/ +noncomputable def ediam (G : SimpleGraph α) : ℕ∞ := + ⨆ u, ⨆ v, G.edist u v + +lemma ediam_def : G.ediam = ⨆ p : α × α, G.edist p.1 p.2 := by + rw [ediam, iSup_prod] + +lemma edist_le_ediam {u v : α} : G.edist u v ≤ G.ediam := + le_iSup₂ (f := G.edist) u v + +lemma ediam_le_of_edist_le {k : ℕ∞} (h : ∀ u v, G.edist u v ≤ k ) : G.ediam ≤ k := + iSup₂_le h + +lemma ediam_le_iff {k : ℕ∞} : G.ediam ≤ k ↔ ∀ u v, G.edist u v ≤ k := + iSup₂_le_iff + +lemma ediam_eq_top : G.ediam = ⊤ ↔ ∀ b < ⊤, ∃ u v, b < G.edist u v := by + simp only [ediam, iSup_eq_top, lt_iSup_iff] + +lemma ediam_eq_zero_of_subsingleton [Subsingleton α] : G.ediam = 0 := by + rw [ediam_def, ENat.iSup_eq_zero] + simpa [edist_eq_zero_iff, Prod.forall] using subsingleton_iff.mp ‹_› + +lemma nontrivial_of_ediam_ne_zero (h : G.ediam ≠ 0) : Nontrivial α := by + contrapose! h + rw [not_nontrivial_iff_subsingleton] at h + exact ediam_eq_zero_of_subsingleton + +lemma ediam_ne_zero [Nontrivial α] : G.ediam ≠ 0 := by + obtain ⟨u, v, huv⟩ := exists_pair_ne ‹_› + contrapose! huv + simp only [ediam, nonpos_iff_eq_zero, ENat.iSup_eq_zero, edist_eq_zero_iff] at huv + exact huv u v + +lemma subsingleton_of_ediam_eq_zero (h : G.ediam = 0) : Subsingleton α := by + contrapose! h + apply not_subsingleton_iff_nontrivial.mp at h + exact ediam_ne_zero + +lemma ediam_ne_zero_iff_nontrivial : + G.ediam ≠ 0 ↔ Nontrivial α := + ⟨nontrivial_of_ediam_ne_zero, fun _ ↦ ediam_ne_zero⟩ + +@[simp] +lemma ediam_eq_zero_iff_subsingleton : + G.ediam = 0 ↔ Subsingleton α := + ⟨subsingleton_of_ediam_eq_zero, fun _ ↦ ediam_eq_zero_of_subsingleton⟩ + +lemma ediam_eq_top_of_not_connected [Nonempty α] (h : ¬G.Connected) : G.ediam = ⊤ := by + rw [connected_iff_exists_forall_reachable] at h + push_neg at h + obtain ⟨_, hw⟩ := h Classical.ofNonempty + rw [eq_top_iff, ← edist_eq_top_of_not_reachable hw] + exact edist_le_ediam + +lemma ediam_eq_top_of_not_preconnected (h : ¬G.Preconnected) : G.ediam = ⊤ := by + cases isEmpty_or_nonempty α + · exfalso + exact h <| IsEmpty.forall_iff.mpr trivial + · apply ediam_eq_top_of_not_connected + rw [connected_iff] + tauto + +lemma exists_edist_eq_ediam_of_ne_top [Nonempty α] (h : G.ediam ≠ ⊤) : + ∃ u v, G.edist u v = G.ediam := + ENat.exists_eq_iSup₂_of_lt_top h.lt_top + +-- Note: Neither `Finite α` nor `G.ediam ≠ ⊤` implies the other. +lemma exists_edist_eq_ediam_of_finite [Nonempty α] [Finite α] : + ∃ u v, G.edist u v = G.ediam := + Prod.exists'.mp <| ediam_def ▸ exists_eq_ciSup_of_finite + +@[gcongr] +lemma ediam_anti (h : G ≤ G') : G'.ediam ≤ G.ediam := + iSup₂_mono fun _ _ ↦ edist_anti h + +@[simp] +lemma ediam_bot [Nontrivial α] : (⊥ : SimpleGraph α).ediam = ⊤ := + ediam_eq_top_of_not_connected bot_not_connected + +@[simp] +lemma ediam_top [Nontrivial α] : (⊤ : SimpleGraph α).ediam = 1 := by + apply le_antisymm ?_ <| Order.one_le_iff_pos.mpr <| pos_iff_ne_zero.mpr ediam_ne_zero + apply ediam_def ▸ iSup_le_iff.mpr + intro p + by_cases h : (⊤ : SimpleGraph α).Adj p.1 p.2 + · apply le_of_eq <| edist_eq_one_iff_adj.mpr h + · simp_all + +@[simp] +lemma ediam_eq_one [Nontrivial α] : G.ediam = 1 ↔ G = ⊤ := by + refine ⟨fun h₁ ↦ ?_, fun h ↦ h ▸ ediam_top⟩ + ext u v + refine ⟨fun h ↦ h.ne, fun h₂ ↦ ?_⟩ + apply G.edist_pos_of_ne at h₂ + apply le_of_eq at h₁ + rw [ediam_def, iSup_le_iff] at h₁ + exact edist_eq_one_iff_adj.mp <| le_antisymm (h₁ (u, v)) <| Order.one_le_iff_pos.mpr h₂ + +end ediam + +section diam + +/-- +The diameter is the greatest distance between any two vertices, with the value `0` in +case the distances are not bounded above, or the graph is not connected. +-/ +noncomputable def diam (G : SimpleGraph α) := + G.ediam.toNat + +lemma diam_def : G.diam = (⨆ p : α × α, G.edist p.1 p.2).toNat := by + rw [diam, ediam_def] + +lemma dist_le_diam (h : G.ediam ≠ ⊤) {u v : α} : G.dist u v ≤ G.diam := + ENat.toNat_le_toNat edist_le_ediam h + +lemma nontrivial_of_diam_ne_zero (h : G.diam ≠ 0) : Nontrivial α := by + apply G.nontrivial_of_ediam_ne_zero + contrapose! h + simp [diam, h] + +lemma diam_eq_zero_of_not_connected (h : ¬G.Connected) : G.diam = 0 := by + cases isEmpty_or_nonempty α + · rw [diam, ediam, ciSup_of_empty, bot_eq_zero']; rfl + · rw [diam, ediam_eq_top_of_not_connected h, ENat.toNat_top] + +lemma diam_eq_zero_of_ediam_eq_top (h : G.ediam = ⊤) : G.diam = 0 := by + rw [diam, h, ENat.toNat_top] + +lemma ediam_ne_top_of_diam_ne_zero (h : G.diam ≠ 0) : G.ediam ≠ ⊤ := + mt diam_eq_zero_of_ediam_eq_top h + +lemma exists_dist_eq_diam [Nonempty α] : + ∃ u v, G.dist u v = G.diam := by + by_cases h : G.diam = 0 + · simp [h] + · obtain ⟨u, v, huv⟩ := exists_edist_eq_ediam_of_ne_top <| ediam_ne_top_of_diam_ne_zero h + use u, v + rw [diam, dist, congrArg ENat.toNat huv] + +@[gcongr] +lemma diam_anti_of_ediam_ne_top (h : G ≤ G') (hn : G.ediam ≠ ⊤) : G'.diam ≤ G.diam := + ENat.toNat_le_toNat (ediam_anti h) hn + +@[simp] +lemma diam_bot : (⊥ : SimpleGraph α).diam = 0 := by + rw [diam, ENat.toNat_eq_zero] + cases subsingleton_or_nontrivial α + · exact Or.inl ediam_eq_zero_of_subsingleton + · exact Or.inr ediam_bot + +@[simp] +lemma diam_top [Nontrivial α] : (⊤ : SimpleGraph α).diam = 1 := by + rw [diam, ediam_top, ENat.toNat_one] + +@[simp] +lemma diam_eq_zero : G.diam = 0 ↔ G.ediam = ⊤ ∨ Subsingleton α := by + rw [diam, ENat.toNat_eq_zero, or_comm, ediam_eq_zero_iff_subsingleton] + +@[simp] +lemma diam_eq_one [Nontrivial α] : G.diam = 1 ↔ G = ⊤ := by + rw [diam, ENat.toNat_eq_iff one_ne_zero, Nat.cast_one, ediam_eq_one] + +end diam + +end SimpleGraph diff --git a/Mathlib/Combinatorics/SimpleGraph/Ends/Defs.lean b/Mathlib/Combinatorics/SimpleGraph/Ends/Defs.lean index 0947929af9f98..085bfd8720ab2 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Ends/Defs.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Ends/Defs.lean @@ -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) : @@ -255,7 +255,9 @@ def componentComplFunctor : (Finset V)ᵒᵖ ⥤ Type u where obj K := G.ComponentCompl K.unop map f := ComponentCompl.hom (le_of_op_hom f) map_id _ := funext fun C => C.hom_refl - map_comp h h' := funext fun C => C.hom_trans (le_of_op_hom h) (le_of_op_hom h') + map_comp {_ Y Z} h h' := funext fun C => by + convert C.hom_trans (le_of_op_hom h) (le_of_op_hom _) + exact h' /-- The end of a graph, defined as the sections of the functor `component_compl_functor` . -/ protected def «end» := diff --git a/Mathlib/Combinatorics/SimpleGraph/Finite.lean b/Mathlib/Combinatorics/SimpleGraph/Finite.lean index ed7de03fd9d74..3ed8afcfac7a8 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Finite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Finite.lean @@ -92,6 +92,15 @@ 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] +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.card = Fintype.card G.edgeSet := Set.toFinset_card _ @@ -242,7 +251,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 (Membership.mem v) := by + G.incidenceFinset v = G.edgeFinset.filter (v ∈ ·) := by ext e induction e simp [mk'_mem_incidenceSet_iff] @@ -278,7 +287,7 @@ section Finite variable [Fintype V] instance neighborSetFintype [DecidableRel G.Adj] (v : V) : Fintype (G.neighborSet v) := - @Subtype.fintype _ _ + @Subtype.fintype _ (· ∈ G.neighborSet v) (by simp_rw [mem_neighborSet] infer_instance) @@ -408,7 +417,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 1f9b4d949285c..c5f35dfab6814 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Hamiltonian.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Hamiltonian.lean @@ -36,7 +36,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,7 +45,7 @@ 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⟩ @@ -59,15 +59,15 @@ lemma IsHamiltonian.support_toFinset (hp : p.IsHamiltonian) : p.support.toFinset /-- The length of a hamiltonian path is one less than the number of vertices of the graph. -/ lemma IsHamiltonian.length_eq (hp : p.IsHamiltonian) : p.length = Fintype.card α - 1 := - eq_tsub_of_add_eq $ by + eq_tsub_of_add_eq <| by rw [← length_support, ← List.sum_toFinset_count_eq_length, Finset.sum_congr rfl fun _ _ ↦ hp _, ← card_eq_sum_ones, hp.support_toFinset, card_univ] end /-- A hamiltonian cycle is a cycle that visits every vertex once. -/ -structure IsHamiltonianCycle (p : G.Walk a a) extends p.IsCycle : Prop := - isHamiltonian_tail : (p.tail toIsCycle.not_nil).IsHamiltonian +structure IsHamiltonianCycle (p : G.Walk a a) extends p.IsCycle : Prop where + isHamiltonian_tail : p.tail.IsHamiltonian variable {p : G.Walk a a} @@ -78,28 +78,29 @@ 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, + simp only [IsHamiltonian, support_tail, support_map, ne_eq, List.map_eq_nil_iff, support_ne_nil, not_false_eq_true, List.count_tail, List.head_map, beq_iff_eq, hf.surjective.forall, hf.injective, List.count_map_of_injective] intro x rcases p with (_ | ⟨y, p⟩) · cases hp.ne_nil rfl - simp only [support_cons, List.count_cons, beq_iff_eq, List.head_cons, hf.injective.eq_iff, - add_tsub_cancel_right] + simp only [map_cons, getVert_cons_succ, tail_cons_eq, support_copy,support_map] + rw [List.count_map_of_injective _ _ hf.injective, ← support_copy, ← tail_cons_eq] exact hp.isHamiltonian_tail _ lemma isHamiltonianCycle_isCycle_and_isHamiltonian_tail : - p.IsHamiltonianCycle ↔ ∃ h : p.IsCycle, (p.tail h.not_nil).IsHamiltonian := + p.IsHamiltonianCycle ↔ p.IsCycle ∧ p.tail.IsHamiltonian := ⟨fun ⟨h, h'⟩ ↦ ⟨h, h'⟩, fun ⟨h, h'⟩ ↦ ⟨h, h'⟩⟩ lemma isHamiltonianCycle_iff_isCycle_and_support_count_tail_eq_one : p.IsHamiltonianCycle ↔ p.IsCycle ∧ ∀ a, (support p).tail.count a = 1 := by - simp only [isHamiltonianCycle_isCycle_and_isHamiltonian_tail, IsHamiltonian, support_tail, - exists_prop] + simp (config := { contextual := true }) [isHamiltonianCycle_isCycle_and_isHamiltonian_tail, + IsHamiltonian, support_tail, IsCycle.not_nil, exists_prop] /-- A hamiltonian cycle visits every vertex. -/ lemma IsHamiltonianCycle.mem_support (hp : p.IsHamiltonianCycle) (b : α) : - b ∈ p.support := List.mem_of_mem_tail <| support_tail p _ ▸ hp.isHamiltonian_tail.mem_support _ + b ∈ p.support := + List.mem_of_mem_tail <| support_tail p hp.1.not_nil ▸ hp.isHamiltonian_tail.mem_support _ /-- The length of a hamiltonian cycle is the number of vertices. -/ lemma IsHamiltonianCycle.length_eq [Fintype α] (hp : p.IsHamiltonianCycle) : @@ -110,11 +111,11 @@ lemma IsHamiltonianCycle.length_eq [Fintype α] (hp : p.IsHamiltonianCycle) : lemma IsHamiltonianCycle.count_support_self (hp : p.IsHamiltonianCycle) : p.support.count a = 2 := by - rw [support_eq_cons, List.count_cons_self, ← support_tail, hp.isHamiltonian_tail] + rw [support_eq_cons, List.count_cons_self, ← support_tail _ hp.1.not_nil, hp.isHamiltonian_tail] lemma IsHamiltonianCycle.support_count_of_ne (hp : p.IsHamiltonianCycle) (h : a ≠ b) : p.support.count b = 1 := by - rw [← cons_support_tail p, List.count_cons_of_ne h.symm, hp.isHamiltonian_tail] + rw [← cons_support_tail p hp.1.not_nil, List.count_cons_of_ne h.symm, hp.isHamiltonian_tail] end Walk @@ -128,7 +129,7 @@ def IsHamiltonian (G : SimpleGraph α) : Prop := lemma IsHamiltonian.mono {H : SimpleGraph α} (hGH : G ≤ H) (hG : G.IsHamiltonian) : H.IsHamiltonian := - fun hα ↦ let ⟨_, p, hp⟩ := hG hα; ⟨_, p.map $ .ofLE hGH, hp.map _ bijective_id⟩ + fun hα ↦ let ⟨_, p, hp⟩ := hG hα; ⟨_, p.map <| .ofLE hGH, hp.map _ bijective_id⟩ lemma IsHamiltonian.connected (hG : G.IsHamiltonian) : G.Connected where preconnected a b := by @@ -138,7 +139,7 @@ lemma IsHamiltonian.connected (hG : G.IsHamiltonian) : G.Connected where obtain ⟨_, p, hp⟩ := hG Fintype.one_lt_card.ne' have a_mem := hp.mem_support a have b_mem := hp.mem_support b - exact ((p.takeUntil a a_mem).reverse.append $ p.takeUntil b b_mem).reachable - nonempty := not_isEmpty_iff.1 fun _ ↦ by simpa using hG $ by simp [@Fintype.card_eq_zero] + exact ((p.takeUntil a a_mem).reverse.append <| p.takeUntil b b_mem).reachable + nonempty := not_isEmpty_iff.1 fun _ ↦ by simpa using hG <| by simp [@Fintype.card_eq_zero] end SimpleGraph diff --git a/Mathlib/Combinatorics/SimpleGraph/Hasse.lean b/Mathlib/Combinatorics/SimpleGraph/Hasse.lean index dd320fc0cd417..5e6d344ea80ad 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Hasse.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Hasse.lean @@ -97,7 +97,7 @@ def pathGraph (n : ℕ) : SimpleGraph (Fin n) := theorem pathGraph_adj {n : ℕ} {u v : Fin n} : (pathGraph n).Adj u v ↔ u.val + 1 = v.val ∨ v.val + 1 = u.val := by simp only [pathGraph, hasse] - simp_rw [← Fin.coe_covBy_iff, Nat.covBy_iff_succ_eq] + simp_rw [← Fin.coe_covBy_iff, covBy_iff_add_one_eq] theorem pathGraph_preconnected (n : ℕ) : (pathGraph n).Preconnected := hasse_preconnected_of_succ _ @@ -107,6 +107,6 @@ theorem pathGraph_connected (n : ℕ) : (pathGraph (n + 1)).Connected := theorem pathGraph_two_eq_top : pathGraph 2 = ⊤ := by ext u v - fin_cases u <;> fin_cases v <;> simp [pathGraph, ← Fin.coe_covBy_iff, Nat.covBy_iff_succ_eq] + fin_cases u <;> fin_cases v <;> simp [pathGraph, ← Fin.coe_covBy_iff, covBy_iff_add_one_eq] end SimpleGraph diff --git a/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean b/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean index ec09c234563e3..8a8ce3e22216a 100644 --- a/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean +++ b/Mathlib/Combinatorics/SimpleGraph/IncMatrix.lean @@ -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 := diff --git a/Mathlib/Combinatorics/SimpleGraph/Init.lean b/Mathlib/Combinatorics/SimpleGraph/Init.lean index efd1b1d9dd8c3..349009999ed43 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Init.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Init.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jannis Limperg -/ +import Mathlib.Init import Aesop /-! diff --git a/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean b/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean index 570e89aa491e2..e609a7dee3f0e 100644 --- a/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean +++ b/Mathlib/Combinatorics/SimpleGraph/LapMatrix.lean @@ -113,9 +113,9 @@ theorem lapMatrix_toLinearMap₂'_apply'_eq_zero_iff_forall_reachable (x : V → rw [lapMatrix_toLinearMap₂'_apply'_eq_zero_iff_forall_adj] refine ⟨?_, fun h i j hA ↦ h i j hA.reachable⟩ intro h i j ⟨w⟩ - induction' w with w i j _ hA _ h' - · rfl - · exact (h i j hA).trans h' + induction w with + | nil => rfl + | cons hA _ h' => exact (h _ _ hA).trans h' theorem lapMatrix_toLin'_apply_eq_zero_iff_forall_reachable (x : V → ℝ) : Matrix.toLin' (G.lapMatrix ℝ) x = 0 ↔ ∀ i j : V, G.Reachable i j → x i = x j := by @@ -156,9 +156,10 @@ lemma linearIndependent_lapMatrix_ker_basis_aux : rw [Subtype.ext_iff] at h0 have h : ∑ c, g c • lapMatrix_ker_basis_aux G c = fun i ↦ g (connectedComponentMk G i) := by simp only [lapMatrix_ker_basis_aux, SetLike.mk_smul_mk, AddSubmonoid.coe_finset_sum] - conv_lhs => enter [2, c, j]; rw [Pi.smul_apply, smul_eq_mul, mul_ite, mul_one, mul_zero] + repeat rw [AddSubmonoid.coe_finset_sum] ext i - simp only [Finset.sum_apply, sum_ite_eq, mem_univ, ite_true] + simp only [Finset.sum_apply, Pi.smul_apply, smul_eq_mul, mul_ite, mul_one, mul_zero, sum_ite_eq, + mem_univ, ↓reduceIte] rw [h] at h0 intro c obtain ⟨i, h'⟩ : ∃ i : V, G.connectedComponentMk i = c := Quot.exists_rep c @@ -171,9 +172,10 @@ lemma top_le_span_range_lapMatrix_ker_basis_aux : use Quot.lift x.val (by rw [← lapMatrix_toLin'_apply_eq_zero_iff_forall_reachable G x, LinearMap.map_coe_ker]) ext j - simp only [lapMatrix_ker_basis_aux, AddSubmonoid.coe_finset_sum, Submodule.coe_toAddSubmonoid, - SetLike.val_smul, Finset.sum_apply, Pi.smul_apply, smul_eq_mul, mul_ite, mul_one, mul_zero, - sum_ite_eq, mem_univ, ite_true] + simp only [lapMatrix_ker_basis_aux] + rw [AddSubmonoid.coe_finset_sum] + simp only [SetLike.mk_smul_mk, Finset.sum_apply, Pi.smul_apply, smul_eq_mul, mul_ite, mul_one, + mul_zero, sum_ite_eq, mem_univ, ↓reduceIte] rfl /-- `lapMatrix_ker_basis G` is a basis of the nullspace indexed by its connected components, @@ -187,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/LineGraph.lean b/Mathlib/Combinatorics/SimpleGraph/LineGraph.lean new file mode 100644 index 0000000000000..a1c37b83a30f6 --- /dev/null +++ b/Mathlib/Combinatorics/SimpleGraph/LineGraph.lean @@ -0,0 +1,39 @@ +/- +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.Combinatorics.SimpleGraph.Basic + +/-! +# LineGraph + +## Main definitions + +* `SimpleGraph.lineGraph` is the line graph of a simple graph `G`, with vertices as the edges of `G` + and two vertices of the line graph adjacent if the corresponding edges share a vertex in `G`. + +## Tags + +line graph +-/ + +namespace SimpleGraph + +variable {V : Type*} {G : SimpleGraph V} + +/-- +The line graph of a simple graph `G` has its vertex set as the edges of `G`, and two vertices of +the line graph are adjacent if the corresponding edges share a vertex in `G`. +-/ +def lineGraph {V : Type*} (G : SimpleGraph V) : SimpleGraph G.edgeSet where + Adj e₁ e₂ := e₁ ≠ e₂ ∧ (e₁ ∩ e₂ : Set V).Nonempty + symm e₁ e₂ := by intro h; rwa [ne_comm, Set.inter_comm] + +lemma lineGraph_adj_iff_exists {e₁ e₂ : G.edgeSet} : + (G.lineGraph).Adj e₁ e₂ ↔ e₁ ≠ e₂ ∧ ∃ v, v ∈ (e₁ : Sym2 V) ∧ v ∈ (e₂ : Sym2 V) := by + simp [Set.Nonempty, lineGraph] + +@[simp] lemma lineGraph_bot : (⊥ : SimpleGraph V).lineGraph = ⊥ := by aesop (add simp lineGraph) + +end SimpleGraph diff --git a/Mathlib/Combinatorics/SimpleGraph/Matching.lean b/Mathlib/Combinatorics/SimpleGraph/Matching.lean index 70951275d32d1..862f0f20756a5 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Matching.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Matching.lean @@ -193,14 +193,21 @@ 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 - classical simpa using (hM.induce_connectedComponent_isMatching c).even_card - -lemma odd_matches_node_outside {u : Set V} {c : ConnectedComponent (Subgraph.deleteVerts ⊤ u).coe} + #adaptation_note + /-- + After lean4#5020, some instances that use the chain of coercions + `[SetLike X], X → Set α → Sort _` are + blocked by the discrimination tree. This can be fixed by redeclaring the instance for `X` + using the double coercion but the proper fix seems to avoid the double coercion. + -/ + 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 [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 @@ -216,8 +223,7 @@ 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.odd_iff_not_even.mp codd + apply Nat.not_even_iff_odd.2 codd haveI : Fintype ↑(Subgraph.induce M (Subtype.val '' supp c)).verts := Fintype.ofFinite _ classical have hMeven := Subgraph.IsMatching.even_card hMmatch @@ -246,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/Metric.lean b/Mathlib/Combinatorics/SimpleGraph/Metric.lean index 0e09bff03a186..2f95492e595b1 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Metric.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Metric.lean @@ -56,7 +56,7 @@ protected theorem Reachable.exists_walk_length_eq_edist (hr : G.Reachable u v) : ∃ p : G.Walk u v, p.length = G.edist u v := csInf_mem <| Set.range_nonempty_iff_nonempty.mpr hr -protected theorem Connected.exists_walk_length_eq_edist (hconn : G.Connected) (u v : V) : +protected theorem Connected.exists_walk_length_eq_edist (hconn : G.Connected) (u v : V) : ∃ p : G.Walk u v, p.length = G.edist u v := (hconn u v).exists_walk_length_eq_edist @@ -127,7 +127,7 @@ theorem edist_eq_one_iff_adj : G.edist u v = 1 ↔ G.Adj u v := by refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ · obtain ⟨w, hw⟩ := exists_walk_of_edist_ne_top <| by rw [h]; simp exact w.adj_of_length_eq_one <| Nat.cast_eq_one.mp <| h ▸ hw - · exact le_antisymm (edist_le h.toWalk) (ENat.one_le_iff_pos.mpr <| edist_pos_of_ne h.ne) + · exact le_antisymm (edist_le h.toWalk) (Order.one_le_iff_pos.mpr <| edist_pos_of_ne h.ne) lemma edist_bot_of_ne (h : u ≠ v) : (⊥ : SimpleGraph V).edist u v = ⊤ := by rwa [ne_eq, ← reachable_bot.not, ← edist_ne_top_iff_reachable.not, not_not] at h @@ -142,7 +142,8 @@ lemma edist_top [DecidableEq V] : (⊤ : SimpleGraph V).edist u v = (if u = v th by_cases h : u = v <;> simp [h] /-- Supergraphs have smaller or equal extended distances to their subgraphs. -/ -theorem edist_le_subgraph_edist {G' : SimpleGraph V} (h : G ≤ G') : +@[gcongr] +theorem edist_anti {G' : SimpleGraph V} (h : G ≤ G') : G'.edist u v ≤ G.edist u v := by by_cases hr : G.Reachable u v · obtain ⟨_, hw⟩ := hr.exists_walk_length_eq_edist @@ -267,7 +268,8 @@ lemma dist_top [DecidableEq V] : (⊤ : SimpleGraph V).dist u v = (if u = v then by_cases h : u = v <;> simp [h] /-- Supergraphs have smaller or equal distances to their subgraphs. -/ -theorem dist_le_subgraph_dist {G' : SimpleGraph V} (h : G ≤ G') (hr : G.Reachable u v) : +@[gcongr] +protected theorem Reachable.dist_anti {G' : SimpleGraph V} (h : G ≤ G') (hr : G.Reachable u v) : G'.dist u v ≤ G.dist u v := by obtain ⟨_, hw⟩ := hr.exists_walk_length_eq_dist rw [← hw, ← Walk.length_map (Hom.mapSpanningSubgraphs h)] diff --git a/Mathlib/Combinatorics/SimpleGraph/Path.lean b/Mathlib/Combinatorics/SimpleGraph/Path.lean index 1731440ff45a7..f40c73152000a 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Path.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Path.lean @@ -178,6 +178,19 @@ theorem IsTrail.count_edges_eq_one [DecidableEq V] {u v : V} {p : G.Walk u v} (h {e : Sym2 V} (he : e ∈ p.edges) : p.edges.count e = 1 := List.count_eq_one_of_mem h.edges_nodup he +theorem IsTrail.length_le_card_edgeFinset [Fintype G.edgeSet] {u v : V} + {w : G.Walk u v} (h : w.IsTrail) : w.length ≤ G.edgeFinset.card := by + classical + let edges := w.edges.toFinset + have : edges.card = w.length := length_edges _ ▸ List.toFinset_card_of_nodup h.edges_nodup + rw [← this] + have : edges ⊆ G.edgeFinset := by + intro e h + refine mem_edgeFinset.mpr ?_ + apply w.edges_subset_edgeSet + simpa [edges] using h + exact Finset.card_le_card this + theorem IsPath.nil {u : V} : (nil : G.Walk u u).IsPath := by constructor <;> simp theorem IsPath.of_cons {u v w : V} {h : G.Adj u v} {p : G.Walk v w} : @@ -236,7 +249,7 @@ theorem cons_isCycle_iff {u v : V} (p : G.Walk v u) (h : G.Adj u v) : have : p.support.Nodup → p.edges.Nodup := edges_nodup_of_support_nodup tauto -lemma IsPath.tail {p : G.Walk u v} (hp : p.IsPath) (hp' : ¬ p.Nil) : (p.tail hp').IsPath := by +lemma IsPath.tail {p : G.Walk u v} (hp : p.IsPath) (hp' : ¬ p.Nil) : p.tail.IsPath := by rw [Walk.isPath_def] at hp ⊢ rw [← cons_support_tail _ hp', List.nodup_cons] at hp exact hp.2 @@ -264,7 +277,8 @@ protected theorem IsTrail.takeUntil {u v w : V} {p : G.Walk v w} (hc : p.IsTrail protected theorem IsTrail.dropUntil {u v w : V} {p : G.Walk v w} (hc : p.IsTrail) (h : u ∈ p.support) : (p.dropUntil u h).IsTrail := - IsTrail.of_append_right (q := p.dropUntil u h) (by rwa [← take_spec _ h] at hc) + IsTrail.of_append_right (p := p.takeUntil u h) (q := p.dropUntil u h) + (by rwa [← take_spec _ h] at hc) protected theorem IsPath.takeUntil {u v w : V} {p : G.Walk v w} (hc : p.IsPath) (h : u ∈ p.support) : (p.takeUntil u h).IsPath := @@ -273,7 +287,8 @@ protected theorem IsPath.takeUntil {u v w : V} {p : G.Walk v w} (hc : p.IsPath) -- Porting note: p was previously accidentally an explicit argument protected theorem IsPath.dropUntil {u v w : V} {p : G.Walk v w} (hc : p.IsPath) (h : u ∈ p.support) : (p.dropUntil u h).IsPath := - IsPath.of_append_right (q := p.dropUntil u h) (by rwa [← take_spec _ h] at hc) + IsPath.of_append_right (p := p.takeUntil u h) (q := p.dropUntil u h) + (by rwa [← take_spec _ h] at hc) protected theorem IsTrail.rotate {u v : V} {c : G.Walk v v} (hc : c.IsTrail) (h : u ∈ c.support) : (c.rotate h).IsTrail := by @@ -570,12 +585,12 @@ theorem mapEmbedding_injective (f : G ↪g G') (u v : V) : end Path -/-! ### Transferring between graphs -/ +/-! ### Transferring between graphs -/ 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 @@ -794,6 +809,12 @@ namespace ConnectedComponent instance inhabited [Inhabited V] : Inhabited G.ConnectedComponent := ⟨G.connectedComponentMk default⟩ +instance isEmpty [IsEmpty V] : IsEmpty (ConnectedComponent G) := by + by_contra! hc + rw [@not_isEmpty_iff] at hc + obtain ⟨v, _⟩ := (Classical.inhabited_of_nonempty hc).default.exists_rep + exact IsEmpty.false v + @[elab_as_elim] protected theorem ind {β : G.ConnectedComponent → Prop} (h : ∀ v : V, β (G.connectedComponentMk v)) (c : G.ConnectedComponent) : β c := @@ -980,6 +1001,31 @@ lemma mem_coe_supp_of_adj {v w : V} {H : Subgraph G} {c : ConnectedComponent H.c rw [← (mem_supp_iff _ _).mp h.1] exact ⟨connectedComponentMk_eq_of_adj <| Subgraph.Adj.coe <| h.2 ▸ hadj.symm, rfl⟩ +lemma connectedComponentMk_supp_subset_supp {G'} {v : V} (h : G ≤ G') (c' : G'.ConnectedComponent) + (hc' : v ∈ c'.supp) : (G.connectedComponentMk v).supp ⊆ c'.supp := by + intro v' hv' + simp only [mem_supp_iff, ConnectedComponent.eq] at hv' ⊢ + rw [ConnectedComponent.sound (hv'.mono h)] + exact hc' + +lemma biUnion_supp_eq_supp {G G' : SimpleGraph V} (h : G ≤ G') (c' : ConnectedComponent G') : + ⋃ (c : ConnectedComponent G) (_ : c.supp ⊆ c'.supp), c.supp = c'.supp := by + ext v + simp_rw [Set.mem_iUnion] + refine ⟨fun ⟨_, ⟨hi, hi'⟩⟩ ↦ hi hi', ?_⟩ + intro hv + use G.connectedComponentMk v + use c'.connectedComponentMk_supp_subset_supp h hv + simp only [mem_supp_iff] + +lemma top_supp_eq_univ (c : ConnectedComponent (⊤ : SimpleGraph V)) : + c.supp = (Set.univ : Set V) := by + have ⟨w, hw⟩ := c.exists_rep + ext v + simp only [Set.mem_univ, iff_true, mem_supp_iff, ← hw] + apply SimpleGraph.ConnectedComponent.sound + exact (@SimpleGraph.top_connected V (Nonempty.intro v)).preconnected v w + end ConnectedComponent -- TODO: Extract as lemma about general equivalence relation @@ -1078,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 @@ -1097,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/Regularity/Bound.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean index e4ad3f317a965..5ee0f683c85af 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Bound.lean @@ -117,7 +117,7 @@ theorem eps_pos (hPε : 100 ≤ (4 : ℝ) ^ P.parts.card * ε ^ 5) : 0 < ε := 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 + (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] @@ -126,10 +126,10 @@ theorem hundred_le_m [Nonempty α] (hPα : P.parts.card * 16 ^ P.parts.card ≤ (hPε : 100 ≤ (4 : ℝ) ^ P.parts.card * ε ^ 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) _ + have h : 1 ≤ 4 ^ P.parts.card := 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] @@ -175,8 +175,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) @@ -219,17 +219,17 @@ theorem add_div_le_sum_sq_div_card (hst : s ⊆ t) (f : ι → 𝕜) (d : 𝕜) 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'] + 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' 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,` - -- ` mul_pow, div_le_iff (sq_pos_of_ne_zero htcard.ne'), sub_sq, sum_add_distrib, ← sum_mul,` + -- ` 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, - div_le_iff (sq_pos_of_ne_zero htcard.ne')] + 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] ring_nf; rfl diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean index 1086cfd9ef8b8..14c2df9eb7249 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Chunk.lean @@ -114,7 +114,7 @@ private theorem card_nonuniformWitness_sdiff_biUnion_star (hV : V ∈ P.parts) ( rw [sum_const] refine mul_le_mul_right' ?_ _ have t := card_filter_atomise_le_two_pow (s := U) hX - refine t.trans (pow_le_pow_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) @@ -123,7 +123,7 @@ private theorem one_sub_eps_mul_card_nonuniformWitness_le_card_star (hV : V ∈ (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 - rw [← div_div, div_le_iff'] + rw [← div_div, div_le_iff₀'] swap · sz_positivity refine le_of_mul_le_mul_left ?_ (pow_pos zero_lt_two P.parts.card) @@ -132,7 +132,7 @@ private theorem one_sub_eps_mul_card_nonuniformWitness_le_card_star (hV : V ∈ ((2 : ℝ) * 2) ^ P.parts.card * m / U.card := 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 _) + _ ≤ 1 := div_le_one_of_le₀ (pow_mul_m_le_card_part hP hU) (cast_nonneg _) _ ≤ ↑2 ^ P.parts.card * ε ^ 2 / 10 := by refine (one_le_sq_iff <| by positivity).1 ?_ rw [div_pow, mul_pow, pow_right_comm, ← pow_mul ε, @@ -156,7 +156,7 @@ private theorem one_sub_eps_mul_card_nonuniformWitness_le_card_star (hV : V ∈ refine sub_le_sub_left ?_ _ have : (2 : ℝ) ^ P.parts.card = ↑2 ^ (P.parts.card - 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] + rw [← mul_div_right_comm, this, mul_right_comm _ (2 : ℝ), mul_assoc, le_div_iff₀] · refine mul_le_mul_of_nonneg_left ?_ (by positivity) exact (G.le_card_nonuniformWitness hunif).trans (le_mul_of_one_le_left (cast_nonneg _) one_le_two) @@ -196,7 +196,7 @@ theorem card_biUnion_star_le_m_add_one_card_star_mul : 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 - rw [mul_div_assoc', div_le_iff coe_m_add_one_pos, mul_right_comm] + 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] exact card_nsmul_le_sum _ _ _ fun x hx => m_le_card_of_mem_chunk_parts <| h𝒜 hx @@ -205,7 +205,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 - rw [sup_eq_biUnion, mul_div_assoc', le_div_iff m_pos, mul_right_comm] + 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 refine card_biUnion_le_card_mul _ _ _ fun x hx => ?_ @@ -219,7 +219,7 @@ private theorem one_sub_le_m_div_m_add_one_sq [Nonempty α] rw [one_sub_div coe_m_add_one_pos.ne', add_sub_cancel_right] rw [this, sub_sq, one_pow, mul_one] refine le_trans ?_ (le_add_of_nonneg_right <| sq_nonneg _) - rw [sub_le_sub_iff_left, ← le_div_iff' (show (0 : ℝ) < 2 by norm_num), div_div, + rw [sub_le_sub_iff_left, ← le_div_iff₀' (show (0 : ℝ) < 2 by norm_num), div_div, one_div_le coe_m_add_one_pos, one_div_div] · refine le_trans ?_ (le_add_of_nonneg_right zero_le_one) norm_num @@ -238,9 +238,9 @@ private theorem m_add_one_div_m_le_one_add [Nonempty α] · positivity rw [add_sq, one_pow, add_assoc, add_le_add_iff_left, mul_one, ← le_sub_iff_add_le', div_eq_mul_one_div _ (49 : ℝ), mul_div_left_comm (2 : ℝ), ← mul_sub_left_distrib, div_pow, - div_le_iff (show (0 : ℝ) < ↑100 ^ 2 by norm_num), mul_assoc, sq] + 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) @@ -266,10 +266,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.card : ℝ), mul_comm (y.card : ℝ), 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 : ℝ) / _)] @@ -303,7 +303,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.card : ℝ), mul_comm (y.card : ℝ), 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ε₁) ?_) @@ -379,16 +379,16 @@ private theorem eps_le_card_star_div [Nonempty α] (hPα : P.parts.card * 16 ^ P (hPε : ↑100 ≤ ↑4 ^ P.parts.card * ε ^ 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α) + 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 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 <| + (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 rw [mul_assoc, mul_assoc, mul_div_left_comm] @@ -405,7 +405,7 @@ private theorem eps_le_card_star_div [Nonempty α] (hPα : P.parts.card * 16 ^ P 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', - div_le_iff hm] + div_le_iff₀ hm] linarith /-! diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Energy.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Energy.lean index c2dc97dd66768..2691d38a6f4b2 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Energy.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Energy.lean @@ -32,7 +32,7 @@ variable {α : Type*} [DecidableEq α] {s : Finset α} (P : Finpartition s) (G : namespace Finpartition /-- The energy of a partition, also known as index. Auxiliary quantity for Szemerédi's regularity -lemma. -/ +lemma. -/ def energy : ℚ := ((∑ uv ∈ P.parts.offDiag, G.edgeDensity uv.1 uv.2 ^ 2) : ℚ) / (P.parts.card : ℚ) ^ 2 @@ -40,7 +40,7 @@ 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 _ => diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Equitabilise.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Equitabilise.lean index d0c4c37b647fa..96d140587f9cc 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Equitabilise.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Equitabilise.lean @@ -45,8 +45,8 @@ theorem equitabilise_aux (hs : a * m + b * (m + 1) = s.card) : -- 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` diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean index e990c3f0fe8b3..4fe6e82a487fa 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Increment.lean @@ -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 @@ -166,7 +166,7 @@ theorem energy_increment (hP : P.IsEquipartition) (hP₇ : 7 ≤ P.parts.card) _ = (6/7 * P.parts.card ^ 2) * ε ^ 5 * (7 / 24) := by ring _ ≤ P.parts.offDiag.card * ε ^ 5 * (22 / 75) := by gcongr ?_ * _ * ?_ - · rw [← mul_div_right_comm, div_le_iff (by norm_num), offDiag_card] + · rw [← mul_div_right_comm, div_le_iff₀ (by norm_num), offDiag_card] norm_cast rw [tsub_mul] refine le_tsub_of_add_le_left ?_ diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Lemma.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Lemma.lean index 3c0421d65f4c2..bee7ea6b54e48 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Regularity/Lemma.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Regularity/Lemma.lean @@ -104,7 +104,7 @@ theorem szemeredi_regularity (hε : 0 < ε) (hl : l ≤ card α) : exact mul_le_mul_left' (pow_le_pow_left (by norm_num) (by norm_num) _) _ calc (1 : ℝ) = ε ^ 5 / ↑4 * (↑4 / ε ^ 5) := by - rw [mul_comm, div_mul_div_cancel 4 (pow_pos hε 5).ne']; norm_num + rw [mul_comm, div_mul_div_cancel₀ (pow_pos hε 5).ne']; norm_num _ < ε ^ 5 / 4 * (⌊4 / ε ^ 5⌋₊ + 1) := ((mul_lt_mul_left <| by positivity).2 (Nat.lt_floor_add_one _)) _ ≤ (P.energy G : ℝ) := by rwa [← Nat.cast_add_one] @@ -128,12 +128,12 @@ theorem szemeredi_regularity (hε : 0 < ε) (hl : l ≤ card α) : -- We gather a few numerical facts. have hεl' : 100 ≤ 4 ^ P.parts.card * ε ^ 5 := (hundred_lt_pow_initialBound_mul hε l).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 + 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ε _)] + rwa [le_div_iff₀' (pow_pos hε _)] have hsize : P.parts.card ≤ 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 α := diff --git a/Mathlib/Combinatorics/SimpleGraph/Regularity/Uniform.lean b/Mathlib/Combinatorics/SimpleGraph/Regularity/Uniform.lean index eaf8ae304e6c0..572c8e65f679c 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 @@ -86,7 +86,7 @@ lemma isUniform_one : G.IsUniform (1 : 𝕜) s t := by variable {G} lemma IsUniform.pos (hG : G.IsUniform ε s t) : 0 < ε := - not_le.1 fun hε ↦ (hε.trans $ abs_nonneg _).not_lt $ hG (empty_subset _) (empty_subset _) + not_le.1 fun hε ↦ (hε.trans <| abs_nonneg _).not_lt <| hG (empty_subset _) (empty_subset _) (by simpa using mul_nonpos_of_nonneg_of_nonpos (Nat.cast_nonneg _) hε) (by simpa using mul_nonpos_of_nonneg_of_nonpos (Nat.cast_nonneg _) hε) @@ -276,7 +276,7 @@ lemma IsEquipartition.card_interedges_sparsePairs_le' (hP : P.IsEquipartition) · 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 @@ -302,7 +302,7 @@ lemma IsEquipartition.card_interedges_sparsePairs_le (hP : P.IsEquipartition) (h private lemma aux {i j : ℕ} (hj : 0 < j) : j * (j - 1) * (i / j + 1) ^ 2 < (i + j) ^ 2 := by have : j * (j - 1) < j ^ 2 := by rw [sq]; exact Nat.mul_lt_mul_of_pos_left (Nat.sub_lt hj zero_lt_one) hj - apply (Nat.mul_lt_mul_of_pos_right this $ pow_pos Nat.succ_pos' _).trans_le + apply (Nat.mul_lt_mul_of_pos_right this <| pow_pos Nat.succ_pos' _).trans_le rw [← mul_pow] exact Nat.pow_le_pow_of_le_left (add_le_add_right (Nat.mul_div_le i j) _) _ @@ -329,15 +329,15 @@ lemma IsEquipartition.card_biUnion_offDiag_le (hε : 0 < ε) (hP : P.IsEquiparti 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)] + 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 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 ?_ + refine (mul_le_mul_of_nonneg_left this <| by positivity).trans ?_ suffices 1 ≤ ε/4 * P.parts.card 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.card : 𝕜)) using 1 <;> ring - rwa [← div_le_iff', one_div_div] + rwa [← div_le_iff₀', one_div_div] positivity lemma IsEquipartition.sum_nonUniforms_lt' (hA : A.Nonempty) (hε : 0 < ε) (hP : P.IsEquipartition) @@ -347,7 +347,7 @@ lemma IsEquipartition.sum_nonUniforms_lt' (hA : A.Nonempty) (hε : 0 < ε) (hP : _ ≤ (P.nonUniforms G ε).card • (↑(A.card / P.parts.card + 1) : 𝕜) ^ 2 := sum_le_card_nsmul _ _ _ ?_ _ = _ := nsmul_eq_mul _ _ - _ ≤ _ := mul_le_mul_of_nonneg_right hG $ by positivity + _ ≤ _ := mul_le_mul_of_nonneg_right hG <| by positivity _ < _ := ?_ · simp only [Prod.forall, Finpartition.mk_mem_nonUniforms, and_imp] rintro U V hU hV - - @@ -418,7 +418,7 @@ lemma unreduced_edges_subset : obtain rfl | hUV := eq_or_ne U V · exact Or.inr (Or.inl ⟨U, hU, hx, hy, G.ne_of_adj h⟩) by_cases h₂ : G.IsUniform (ε/8) U V - · exact Or.inr $ Or.inr ⟨U, V, hU, hV, hUV, h' _ hU _ hV hx hy hUV h₂, hx, hy, h⟩ + · exact Or.inr <| Or.inr ⟨U, V, hU, hV, hUV, h' _ hU _ hV hx hy hUV h₂, hx, hy, h⟩ · exact Or.inl ⟨U, V, hU, hV, hUV, h₂, hx, hy⟩ end SimpleGraph diff --git a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean index 68777353d2638..c0cc9e7d6ca21 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 @@ -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 4ce9dce76ebac..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 @@ -126,7 +126,7 @@ theorem IsEulerian.even_degree_iff {x u v : V} {p : G.Walk u v} (ht : p.IsEuleri rw [← Multiset.coe_countP, Multiset.countP_eq_card_filter, ← card_incidenceFinset_eq_degree] change Multiset.card _ = _ congr 1 - convert_to _ = (ht.isTrail.edgesFinset.filter (Membership.mem x)).val + convert_to _ = (ht.isTrail.edgesFinset.filter (x ∈ ·)).val have : Fintype G.edgeSet := fintypeEdgeSet ht rw [ht.edgesFinset_eq, G.incidenceFinset_eq_filter x] @@ -135,7 +135,7 @@ theorem IsEulerian.card_filter_odd_degree [Fintype V] [DecidableRel G.Adj] {u v (h : s = (Finset.univ : Finset V).filter fun v => Odd (G.degree v)) : s.card = 0 ∨ s.card = 2 := by subst s - simp only [Nat.odd_iff_not_even, Finset.card_eq_zero] + simp only [← Nat.not_even_iff_odd, Finset.card_eq_zero] simp only [ht.even_degree_iff, Ne, not_forall, not_and, Classical.not_not, exists_prop] obtain rfl | hn := eq_or_ne u v · left diff --git a/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean index 9eb128cce610b..96cd101472ef9 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Triangle/Basic.lean @@ -52,7 +52,7 @@ protected lemma LocallyLinear.edgeDisjointTriangles : G.LocallyLinear → G.Edge And.left nonrec lemma EdgeDisjointTriangles.mono (h : G ≤ H) (hH : H.EdgeDisjointTriangles) : - G.EdgeDisjointTriangles := hH.mono $ cliqueSet_mono h + G.EdgeDisjointTriangles := hH.mono <| cliqueSet_mono h @[simp] lemma edgeDisjointTriangles_bot : (⊥ : SimpleGraph α).EdgeDisjointTriangles := by simp [EdgeDisjointTriangles] @@ -133,10 +133,11 @@ 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).card ≤ 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 @@ -151,7 +152,7 @@ lemma EdgeDisjointTriangles.card_edgeFinset_le (hG : G.EdgeDisjointTriangles) : simp [insert_subset, *] · simpa only [card_le_one, mem_bipartiteBelow, and_imp, Set.Subsingleton, Set.mem_setOf_eq, mem_cliqueFinset_iff, mem_cliqueSet_iff] - using hG.mem_sym2_subsingleton (G.not_isDiag_of_mem_edgeSet $ mem_edgeFinset.1 he) + 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 @@ -165,7 +166,7 @@ lemma LocallyLinear.card_edgeFinset (hG : G.LocallyLinear) : rintro _ a b c hab hac hbc rfl calc _ ≤ ({s(a, b), s(a, c), s(b, c)} : Finset _).card := card_le_card ?_ - _ ≤ 3 := (card_insert_le _ _).trans (succ_le_succ $ (card_insert_le _ _).trans_eq $ by + _ ≤ 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, mem_edgeFinset, mem_singleton, and_imp, mem_edgeSet, Sym2.mem_iff, forall_eq_or_imp, @@ -213,7 +214,7 @@ private lemma farFromTriangleFree_of_disjoint_triangles_aux {tris : Finset (Fins by_contra! h refine hH t ?_ simp only [not_and, mem_sdiff, not_not, mem_edgeFinset, mem_edgeSet] at h - obtain ⟨x, y, z, xy, xz, yz, rfl⟩ := is3Clique_iff.1 (mem_cliqueFinset_iff.1 $ htris ht) + obtain ⟨x, y, z, xy, xz, yz, rfl⟩ := is3Clique_iff.1 (mem_cliqueFinset_iff.1 <| htris ht) rw [is3Clique_triple_iff] refine ⟨h _ _ ?_ ?_ xy.ne xy, h _ _ ?_ ?_ xz.ne xz, h _ _ ?_ ?_ yz.ne yz⟩ <;> simp choose fx fy hfx hfy hfne fmem using this @@ -237,9 +238,9 @@ lemma farFromTriangleFree_of_disjoint_triangles (tris : Finset (Finset α)) G.FarFromTriangleFree ε := by rw [farFromTriangleFree_iff] intros H _ hG hH - rw [← Nat.cast_sub (card_le_card $ edgeFinset_mono hG)] + rw [← Nat.cast_sub (card_le_card <| edgeFinset_mono hG)] exact tris_big.trans - (Nat.cast_le.2 $ farFromTriangleFree_of_disjoint_triangles_aux htris pd hG hH) + (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) : @@ -255,7 +256,7 @@ 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 simpa using hG.le_card_sub_card bot_le (cliqueFree_bot (le_succ _)) @@ -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 f0f5b628e442c..f1687fb68c6d4 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Triangle/Counting.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Triangle/Counting.lean @@ -29,13 +29,13 @@ 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 + s.filter fun x ↦ (t.filter <| G.Adj x).card < (G.edgeDensity s t - ε) * t.card 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 classical - refine (Nat.cast_le.2 $ (card_le_card $ subset_of_eq (Rel.interedges_eq_biUnion _)).trans + 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 : ℝ)] exact sum_le_card_nsmul _ _ _ fun x hx ↦ (mem_filter.1 hx).2.le @@ -44,14 +44,14 @@ private lemma edgeDensity_badVertices_le (hε : 0 ≤ ε) (dst : 2 * ε ≤ G.ed 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 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 _ _ _) + (dst.trans <| by exact_mod_cast edgeDensity_le_one _ _ _) by_contra! h have : |(G.edgeDensity (badVertices G ε s t) t - G.edgeDensity s t : ℝ)| < ε := hst (filter_subset _ _) Subset.rfl h.le (mul_le_of_le_one_right (Nat.cast_nonneg _) 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 (t.filter <| G.Adj x) (u.filter <| G.Adj x)).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, @@ -89,7 +89,7 @@ private lemma good_vertices_triangle_card [DecidableEq α] (dst : 2 * ε ≤ G.e 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 @@ -109,18 +109,18 @@ lemma triangle_counting' 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 _ - refine le_trans ?_ (Nat.cast_le.2 $ card_le_card this) + refine le_trans ?_ (Nat.cast_le.2 <| card_le_card this) rw [card_biUnion, Nat.cast_sum] - · apply le_trans _ (card_nsmul_le_sum X' _ _ $ G.good_vertices_triangle_card dst dsu dtu utu) + · 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 - exact Eq.trans_le (by ring) (mul_le_mul_of_nonneg_right hX' $ by positivity) + 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 _ _) rw [sub_mul, one_mul, card_sdiff i, Nat.cast_sub (card_le_card i), sub_le_sub_iff_left, mul_assoc, mul_comm ε, two_mul] - refine (Nat.cast_le.2 $ card_union_le _ _).trans ?_ + refine (Nat.cast_le.2 <| card_union_le _ _).trans ?_ rw [Nat.cast_add] exact add_le_add h₁ h₂ rintro a _ b _ t diff --git a/Mathlib/Combinatorics/SimpleGraph/Triangle/Removal.lean b/Mathlib/Combinatorics/SimpleGraph/Triangle/Removal.lean index 96c9a38f6795c..c5d8d7059920e 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Triangle/Removal.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Triangle/Removal.lean @@ -61,7 +61,7 @@ private lemma card_bound (hP₁ : P.IsEquipartition) (hP₃ : P.parts.card ≤ b calc _ ≤ card α / (2 * P.parts.card : ℝ) := by gcongr _ ≤ ↑(card α / P.parts.card) := - (div_le_iff' (by positivity)).2 $ mod_cast (aux ‹_› P.card_parts_le_card).le + (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 private lemma triangle_removal_aux (hε : 0 < ε) (hP₁ : P.IsEquipartition) diff --git a/Mathlib/Combinatorics/SimpleGraph/Triangle/Tripartite.lean b/Mathlib/Combinatorics/SimpleGraph/Triangle/Tripartite.lean index dac9907861a7d..6bcfe21447840 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Triangle/Tripartite.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Triangle/Tripartite.lean @@ -155,7 +155,7 @@ instance graph.instDecidableRelAdj : DecidableRel (graph t).Adj toFun x := {in₀ x.1, in₁ x.2.1, in₂ x.2.2} inj' := fun ⟨a, b, c⟩ ⟨a', b', c'⟩ ↦ by simpa only [Finset.Subset.antisymm_iff, Finset.subset_iff, mem_insert, mem_singleton, forall_eq_or_imp, forall_eq, Prod.mk.inj_iff, or_false, false_or, - in₀, in₁, in₂, Sum.inl.inj_iff, Sum.inr.inj_iff] using And.left + in₀, in₁, in₂, Sum.inl.inj_iff, Sum.inr.inj_iff, reduceCtorEq] using And.left lemma toTriangle_is3Clique (hx : x ∈ t) : (graph t).IsNClique 3 (toTriangle x) := by simp only [toTriangle_apply, is3Clique_triple_iff, in₀₁_iff, in₀₂_iff, in₁₂_iff] @@ -211,7 +211,7 @@ section Fintype variable [Fintype α] [Fintype β] [Fintype γ] lemma cliqueFinset_eq_image [NoAccidental t] : (graph t).cliqueFinset 3 = t.image toTriangle := - coe_injective $ by push_cast; exact cliqueSet_eq_image _ + coe_injective <| by push_cast; exact cliqueSet_eq_image _ lemma cliqueFinset_eq_map [NoAccidental t] : (graph t).cliqueFinset 3 = t.map toTriangle := by simp [cliqueFinset_eq_image, map_eq_image] @@ -224,7 +224,7 @@ lemma farFromTriangleFree [ExplicitDisjoint 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) - (map_toTriangle_disjoint t) $ by simpa [add_assoc] using ht + (map_toTriangle_disjoint t) <| by simpa [add_assoc] using ht end Fintype end DecidableEq diff --git a/Mathlib/Combinatorics/SimpleGraph/Turan.lean b/Mathlib/Combinatorics/SimpleGraph/Turan.lean index e83caeb3b7f52..45760dc0bd670 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Turan.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Turan.lean @@ -124,7 +124,7 @@ end Defs namespace IsTuranMaximal -variable {s t u : V} [DecidableEq V] +variable {s t u : V} /-- In a Turán-maximal graph, non-adjacent vertices have the same degree. -/ lemma degree_eq_of_not_adj (h : G.IsTuranMaximal r) (hn : ¬G.Adj s t) : @@ -186,7 +186,7 @@ instance : DecidableRel h.setoid.r := /-- The finpartition derived from `h.setoid`. -/ def finpartition [DecidableEq V] : Finpartition (univ : Finset V) := Finpartition.ofSetoid h.setoid -lemma not_adj_iff_part_eq : +lemma not_adj_iff_part_eq [DecidableEq V] : ¬G.Adj s t ↔ h.finpartition.part s = h.finpartition.part t := by change h.setoid.r s t ↔ _ rw [← Finpartition.mem_part_ofSetoid_iff_rel] @@ -194,7 +194,7 @@ lemma not_adj_iff_part_eq : change t ∈ fp.part s ↔ fp.part s = fp.part t rw [fp.mem_part_iff_part_eq_part (mem_univ t) (mem_univ s), eq_comm] -lemma degree_eq_card_sub_part_card : +lemma degree_eq_card_sub_part_card [DecidableEq V] : G.degree s = Fintype.card V - (h.finpartition.part s).card := calc _ = (univ.filter (G.Adj s)).card := by @@ -207,7 +207,7 @@ lemma degree_eq_card_sub_part_card : simp [setoid] /-- The parts of a Turán-maximal graph form an equipartition. -/ -theorem isEquipartition : h.finpartition.IsEquipartition := by +theorem isEquipartition [DecidableEq V] : h.finpartition.IsEquipartition := by set fp := h.finpartition by_contra hn rw [Finpartition.not_isEquipartition] at hn @@ -227,7 +227,7 @@ theorem isEquipartition : h.finpartition.IsEquipartition := by have : large.card ≤ Fintype.card V := by simpa using card_le_card large.subset_univ omega -lemma card_parts_le : h.finpartition.parts.card ≤ r := by +lemma card_parts_le [DecidableEq V] : h.finpartition.parts.card ≤ r := by by_contra! l obtain ⟨z, -, hz⟩ := h.finpartition.exists_subset_part_bijOn have ncf : ¬G.CliqueFree z.card := by @@ -240,7 +240,7 @@ lemma card_parts_le : 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 : h.finpartition.parts.card = min (Fintype.card V) r := by +theorem card_parts [DecidableEq V] : h.finpartition.parts.card = 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 @@ -280,8 +280,6 @@ theorem nonempty_iso_turanGraph : end IsTuranMaximal -variable [DecidableEq V] - /-- **Turán's theorem**, reverse direction. Any graph isomorphic to `turanGraph n r` is itself Turán-maximal if `0 < r`. -/ @@ -293,7 +291,7 @@ theorem isTuranMaximal_of_iso (f : G ≃g turanGraph n r) (hr : 0 < r) : G.IsTur fun H _ cf ↦ (f.symm.comp g).card_edgeFinset_eq ▸ j.2 H cf /-- Turán-maximality with `0 < r` transfers across graph isomorphisms. -/ -theorem IsTuranMaximal.iso {W : Type*} [DecidableEq W] [Fintype W] {H : SimpleGraph W} +theorem IsTuranMaximal.iso {W : Type*} [Fintype W] {H : SimpleGraph W} [DecidableRel H.Adj] (h : G.IsTuranMaximal r) (f : G ≃g H) (hr : 0 < r) : H.IsTuranMaximal r := isTuranMaximal_of_iso (h.nonempty_iso_turanGraph.some.comp f.symm) hr diff --git a/Mathlib/Combinatorics/SimpleGraph/Walk.lean b/Mathlib/Combinatorics/SimpleGraph/Walk.lean index 52c4b7eeca310..e2c574948f9c0 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Walk.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Walk.lean @@ -177,16 +177,19 @@ theorem adj_getVert_succ {u v} (w : G.Walk u v) {i : ℕ} (hi : i < w.length) : · simp [getVert, hxy] · exact ih (Nat.succ_lt_succ_iff.1 hi) +lemma getVert_cons_one {u v w} (q : G.Walk v w) (hadj : G.Adj u v) : + (q.cons hadj).getVert 1 = v := by + have : (q.cons hadj).getVert 1 = q.getVert 0 := rfl + simpa [getVert_zero] using this + @[simp] -lemma cons_getVert_succ {u v w n} (p : G.Walk v w) (h : G.Adj u v) : +lemma getVert_cons_succ {u v w n} (p : G.Walk v w) (h : G.Adj u v) : (p.cons h).getVert (n + 1) = p.getVert n := rfl -lemma cons_getVert {u v w n} (p : G.Walk v w) (h : G.Adj u v) (hn : n ≠ 0) : +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, cons_getVert_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) : @@ -196,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) @@ -494,9 +495,20 @@ theorem support_reverse {u v : V} (p : G.Walk u v) : p.reverse.support = p.suppo @[simp] theorem support_ne_nil {u v : V} (p : G.Walk u v) : p.support ≠ [] := by cases p <;> simp +@[simp] +theorem head_support {G : SimpleGraph V} {a b : V} (p : G.Walk a b) : + p.support.head (by simp) = a := by cases p <;> simp + +@[simp] +theorem getLast_support {G : SimpleGraph V} {a b : V} (p : G.Walk a b) : + p.support.getLast (by simp) = b := by + induction p + · simp + · simpa + 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 @@ -543,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 @@ -636,6 +648,20 @@ theorem map_fst_darts_append {u v : V} (p : G.Walk u v) : theorem map_fst_darts {u v : V} (p : G.Walk u v) : p.darts.map (·.fst) = p.support.dropLast := by simpa! using congr_arg List.dropLast (map_fst_darts_append p) +@[simp] +theorem head_darts_fst {G : SimpleGraph V} {a b : V} (p : G.Walk a b) (hp : p.darts ≠ []) : + (p.darts.head hp).fst = a := by + cases p + · contradiction + · simp + +@[simp] +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, p.getLast_support] + · simpa + @[simp] theorem edges_nil {u : V} : (nil : G.Walk u u).edges = [] := rfl @@ -713,6 +739,19 @@ theorem edges_nodup_of_support_nodup {u v : V} {p : G.Walk u v} (h : p.support.N simp only [edges_cons, support_cons, List.nodup_cons] at h ⊢ exact ⟨fun h' => h.1 (fst_mem_support_of_mem_edges p' h'), ih h.2⟩ +theorem edges_injective {u v : V} : Function.Injective (Walk.edges : G.Walk u v → List (Sym2 V)) + | .nil, .nil, _ => rfl + | .nil, .cons _ _, h => by simp at h + | .cons _ _, .nil, h => by simp at h + | .cons' u v c h₁ w₁, .cons' _ v' _ h₂ w₂, h => by + have h₃ : u ≠ v' := by rintro rfl; exact G.loopless _ h₂ + obtain ⟨rfl, h₃⟩ : v = v' ∧ w₁.edges = w₂.edges := by simpa [h₁, h₃] using h + obtain rfl := Walk.edges_injective h₃ + rfl + +theorem darts_injective {u v : V} : Function.Injective (Walk.darts : G.Walk u v → List G.Dart) := + edges_injective.of_comp + /-- Predicate for the empty walk. Solves the dependent type problem where `p = G.Walk.nil` typechecks @@ -741,6 +780,9 @@ lemma nil_iff_support_eq {p : G.Walk v w} : p.Nil ↔ p.support = [v] := by lemma nil_iff_length_eq {p : G.Walk v w} : p.Nil ↔ p.length = 0 := by cases p <;> simp +lemma not_nil_iff_lt_length {p : G.Walk v w} : ¬ p.Nil ↔ 0 < p.length := by + cases p <;> simp + lemma not_nil_iff {p : G.Walk v w} : ¬ p.Nil ↔ ∃ (u : V) (h : G.Adj v u) (q : G.Walk u w), p = cons h q := by cases p <;> simp [*] @@ -765,61 +807,77 @@ lemma notNilRec_cons {motive : {u w : V} → (p : G.Walk u w) → ¬ p.Nil → S motive (q.cons h) Walk.not_nil_cons) (h' : G.Adj u v) (q' : G.Walk v w) : @Walk.notNilRec _ _ _ _ _ cons _ _ = cons h' q' := by rfl -/-- The second vertex along a non-nil walk. -/ -def sndOfNotNil (p : G.Walk v w) (hp : ¬ p.Nil) : V := - p.notNilRec (@fun _ u _ _ _ => u) hp +@[simp] lemma adj_getVert_one {p : G.Walk v w} (hp : ¬ p.Nil) : + G.Adj v (p.getVert 1) := by + simpa using adj_getVert_succ p (by simpa [not_nil_iff_lt_length] using hp : 0 < p.length) -@[simp] lemma adj_sndOfNotNil {p : G.Walk v w} (hp : ¬ p.Nil) : - G.Adj v (p.sndOfNotNil hp) := - p.notNilRec (fun h _ => h) hp +/-- The walk obtained by removing the first `n` darts of a walk. -/ +def drop {u v : V} (p : G.Walk u v) (n : ℕ) : G.Walk (p.getVert n) v := + match p, n with + | .nil, _ => .nil + | p, 0 => p.copy (getVert_zero p).symm rfl + | .cons h q, (n + 1) => (q.drop n).copy (getVert_cons_succ _ h).symm rfl /-- The walk obtained by removing the first dart of a non-nil walk. -/ -def tail (p : G.Walk u v) (hp : ¬ p.Nil) : G.Walk (p.sndOfNotNil hp) v := - p.notNilRec (fun _ q => q) hp +def tail (p : G.Walk u v) : G.Walk (p.getVert 1) v := p.drop 1 + +@[simp] +lemma tail_cons_nil (h : G.Adj u v) : (Walk.cons h .nil).tail = .nil := by rfl + +lemma tail_cons_eq (h : G.Adj u v) (p : G.Walk v w) : + (p.cons h).tail = p.copy (getVert_zero p).symm rfl := by + match p with + | .nil => rfl + | .cons h q => rfl /-- The first dart of a walk. -/ @[simps] def firstDart (p : G.Walk v w) (hp : ¬ p.Nil) : G.Dart where fst := v - snd := p.sndOfNotNil hp - adj := p.adj_sndOfNotNil hp + snd := p.getVert 1 + adj := p.adj_getVert_one hp lemma edge_firstDart (p : G.Walk v w) (hp : ¬ p.Nil) : - (p.firstDart hp).edge = s(v, p.sndOfNotNil hp) := rfl + (p.firstDart hp).edge = s(v, p.getVert 1) := rfl variable {x y : V} -- TODO: rename to u, v, w instead? -@[simp] lemma cons_tail_eq (p : G.Walk x y) (hp : ¬ p.Nil) : - cons (p.adj_sndOfNotNil hp) (p.tail hp) = p := - p.notNilRec (fun _ _ => rfl) hp +lemma cons_tail_eq (p : G.Walk x y) (hp : ¬ p.Nil) : + cons (p.adj_getVert_one hp) p.tail = p := by + cases p with + | nil => simp only [nil_nil, not_true_eq_false] at hp + | cons h q => + simp only [getVert_cons_succ, tail_cons_eq, cons_copy, copy_rfl_rfl] @[simp] lemma cons_support_tail (p : G.Walk x y) (hp : ¬p.Nil) : - x :: (p.tail hp).support = p.support := by - rw [← support_cons, cons_tail_eq] + x :: p.tail.support = p.support := by + rw [← support_cons, cons_tail_eq _ hp] @[simp] lemma length_tail_add_one {p : G.Walk x y} (hp : ¬ p.Nil) : - (p.tail hp).length + 1 = p.length := by - rw [← length_cons, cons_tail_eq] + p.tail.length + 1 = p.length := by + rw [← length_cons, cons_tail_eq _ hp] @[simp] lemma nil_copy {x' y' : V} {p : G.Walk x y} (hx : x = x') (hy : y = y') : (p.copy hx hy).Nil = p.Nil := by subst_vars; rfl -@[simp] lemma support_tail (p : G.Walk v v) (hp) : - (p.tail hp).support = p.support.tail := by +@[simp] lemma support_tail (p : G.Walk v v) (hp : ¬ p.Nil) : + p.tail.support = p.support.tail := by rw [← cons_support_tail p hp, List.tail_cons] @[simp] lemma tail_cons {t u v} (p : G.Walk u v) (h : G.Adj t u) : - (p.cons h).tail not_nil_cons = p := by - unfold Walk.tail; simp only [notNilRec_cons] + (p.cons h).tail = p.copy (getVert_zero p).symm rfl := by + match p with + | .nil => rfl + | .cons h q => rfl -lemma tail_support_eq_support_tail (p : G.Walk u v) (hnp : ¬p.Nil) : - (p.tail hnp).support = p.support.tail := - p.notNilRec (by - intro u v w huv q - unfold Walk.tail - simp only [notNilRec_cons, Walk.support_cons, List.tail_cons]) hnp +lemma support_tail_of_not_nil (p : G.Walk u v) (hnp : ¬p.Nil) : + p.tail.support = p.support.tail := by + match p with + | .nil => simp only [nil_nil, not_true_eq_false] at hnp + | .cons h q => + simp only [tail_cons, getVert_cons_succ, support_copy, support_cons, List.tail_cons] /-! ### Walk decompositions -/ @@ -995,17 +1053,23 @@ theorem exists_boundary_dart {u v : V} (p : G.Walk u v) (S : Set V) (uS : u ∈ exact ⟨d, List.Mem.tail _ hd, hcd⟩ · exact ⟨⟨(x, y), a⟩, List.Mem.head _, uS, h⟩ -lemma getVert_tail {u v n} (p : G.Walk u v) (hnp: ¬ p.Nil) : - (p.tail hnp).getVert n = p.getVert (n + 1) := - p.notNilRec (fun _ _ ↦ by simp only [tail_cons, cons_getVert_succ]) hnp - -@[simp] -lemma cons_sndOfNotNil (q : G.Walk v w) (hadj : G.Adj u v) : - (q.cons hadj).sndOfNotNil not_nil_cons = v := by - unfold sndOfNotNil; simp only [notNilRec_cons] - -lemma getVert_one (p : G.Walk u v) (hnp : ¬ p.Nil) : p.getVert 1 = p.sndOfNotNil hnp := - p.notNilRec (fun _ _ ↦ by simp only [cons_getVert_succ, getVert_zero, cons_sndOfNotNil]) hnp +@[simp] lemma getVert_copy {u v w x : V} (p : G.Walk u v) (i : ℕ) (h : u = w) (h' : v = x) : + (p.copy h h').getVert i = p.getVert i := by + subst_vars + match p, i with + | .nil, _ => + rw [getVert_of_length_le _ (by simp only [length_nil, Nat.zero_le] : nil.length ≤ _)] + rw [getVert_of_length_le _ (by simp only [length_copy, length_nil, Nat.zero_le])] + | .cons hadj q, 0 => simp only [copy_rfl_rfl, getVert_zero] + | .cons hadj q, (n + 1) => simp only [copy_cons, getVert_cons_succ]; rfl + +@[simp] lemma getVert_tail {u v n} (p : G.Walk u v) (hnp: ¬ p.Nil) : + p.tail.getVert n = p.getVert (n + 1) := by + match p with + | .nil => rfl + | .cons h q => + simp only [getVert_cons_succ, tail_cons_eq, getVert_cons] + exact getVert_copy q n (getVert_zero q).symm rfl /-- Given a walk `w` and a node in the support, there exists a natural `n`, such that given node is the `n`-th node (zero-indexed) in the walk. In addition, `n` is at most the length of the path. @@ -1032,13 +1096,18 @@ theorem mem_support_iff_exists_getVert {u v w : V} {p : G.Walk v w} : rw [@nil_iff_length_eq] have : 1 ≤ p.length := by omega exact Nat.not_eq_zero_of_lt this - rw [← tail_support_eq_support_tail _ hnp] + rw [← support_tail_of_not_nil _ hnp] rw [mem_support_iff_exists_getVert] use n - 1 - simp only [Nat.sub_le_iff_le_add, length_tail_add_one, getVert_tail] - have : n - 1 + 1 = n := by omega + simp only [Nat.sub_le_iff_le_add] + rw [getVert_tail _ hnp, length_tail_add_one hnp] + have : (n - 1 + 1) = n:= by omega rwa [this] termination_by p.length +decreasing_by +· simp_wf + rw [@Nat.lt_iff_add_one_le] + rw [length_tail_add_one hnp] end Walk @@ -1126,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 @@ -1134,7 +1203,7 @@ theorem map_injective_of_injective {f : G →g G'} (hinj : Function.Injective f) abbrev mapLe {G G' : SimpleGraph V} (h : G ≤ G') {u v : V} (p : G.Walk u v) : G'.Walk u v := p.map (Hom.mapSpanningSubgraphs h) -/-! ### Transferring between graphs -/ +/-! ### Transferring between graphs -/ /-- The walk `p` transferred to lie in `H`, given that `H` contains its edges. -/ @[simp] diff --git a/Mathlib/Combinatorics/Young/YoungDiagram.lean b/Mathlib/Combinatorics/Young/YoungDiagram.lean index 79b3e2892c891..fad6a3949ea28 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] @@ -436,7 +436,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..211e594b14670 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 diff --git a/Mathlib/Computability/AkraBazzi/AkraBazzi.lean b/Mathlib/Computability/AkraBazzi/AkraBazzi.lean index d25df9001edd4..5f7d1c28e9623 100644 --- a/Mathlib/Computability/AkraBazzi/AkraBazzi.lean +++ b/Mathlib/Computability/AkraBazzi/AkraBazzi.lean @@ -266,7 +266,7 @@ lemma eventually_log_b_mul_pos : ∀ᶠ (n : ℕ) in atTop, ∀ i, 0 < log (b i exact h.eventually_gt_atTop 0 @[aesop safe apply] lemma T_pos (n : ℕ) : 0 < T n := by - induction n using Nat.strongInductionOn with + induction n using Nat.strongRecOn with | ind n h_ind => cases lt_or_le n R.n₀ with | inl hn => exact R.T_gt_zero' n hn -- n < R.n₀ @@ -399,7 +399,7 @@ lemma isLittleO_deriv_smoothingFn : deriv ε =o[atTop] fun x => x⁻¹ := calc rw [isLittleO_one_left_iff] exact Tendsto.comp tendsto_norm_atTop_atTop <| Tendsto.comp (tendsto_pow_atTop (by norm_num)) tendsto_log_atTop - · exact Filter.eventually_of_forall (fun x hx => by rw [mul_one] at hx; simp [hx]) + · exact Filter.Eventually.of_forall (fun x hx => by rw [mul_one] at hx; simp [hx]) _ = fun x => x⁻¹ := by simp lemma eventually_deriv_one_sub_smoothingFn : @@ -508,7 +508,7 @@ lemma isTheta_smoothingFn_sub_self (i : α) : Every Akra-Bazzi recurrence has an associated exponent, denoted by `p : ℝ`, such that `∑ a_i b_i^p = 1`. This section shows the existence and uniqueness of this exponent `p` for any `R : AkraBazziRecurrence`, and defines `R.asympBound` to be the asymptotic bound satisfied by `R`, -namely `n^p (1 + ∑_{u < n} g(u) / u^(p+1))`. -/ +namely `n^p (1 + ∑_{u < n} g(u) / u^(p+1))`. -/ @[continuity] lemma continuous_sumCoeffsExp : Continuous (fun (p : ℝ) => ∑ i, a i * (b i) ^ p) := by @@ -843,7 +843,7 @@ lemma isEquivalent_deriv_rpow_p_mul_one_sub_smoothingFn {p : ℝ} (hp : p ≠ 0) (fun z => z ^ (p-1) / (log z ^ 2)) =o[atTop] fun z => z ^ (p-1) / 1 := by simp_rw [div_eq_mul_inv] refine IsBigO.mul_isLittleO (isBigO_refl _ _) - (IsLittleO.inv_rev ?_ (by aesop (add safe eventually_of_forall))) + (IsLittleO.inv_rev ?_ (by aesop (add safe Eventually.of_forall))) rw [isLittleO_const_left] refine Or.inr <| Tendsto.comp tendsto_norm_atTop_atTop ?_ exact Tendsto.comp (g := fun z => z ^ 2) @@ -867,7 +867,7 @@ lemma isEquivalent_deriv_rpow_p_mul_one_add_smoothingFn {p : ℝ} (hp : p ≠ 0) (fun z => -(z ^ (p-1) / (log z ^ 2))) =o[atTop] fun z => z ^ (p-1) / 1 := by simp_rw [isLittleO_neg_left, div_eq_mul_inv] refine IsBigO.mul_isLittleO (isBigO_refl _ _) - (IsLittleO.inv_rev ?_ (by aesop (add safe eventually_of_forall))) + (IsLittleO.inv_rev ?_ (by aesop (add safe Eventually.of_forall))) rw [isLittleO_const_left] refine Or.inr <| Tendsto.comp tendsto_norm_atTop_atTop ?_ exact Tendsto.comp (g := fun z => z ^ 2) @@ -1053,7 +1053,7 @@ lemma rpow_p_mul_one_sub_smoothingFn_le : case bn_gt_one => calc 1 = b i * (b i)⁻¹ := by rw [mul_inv_cancel₀ (by positivity)] _ ≤ b i * ⌈(b i)⁻¹⌉₊ := by gcongr; exact Nat.le_ceil _ - _ < b i * n := by gcongr; rw [Nat.cast_lt]; exact hn + _ < b i * n := by gcongr case le => calc b i * n ≤ 1 * n := by have := R.b_lt_one i; gcongr _ = n := by rw [one_mul] positivity @@ -1149,7 +1149,7 @@ lemma rpow_p_mul_one_add_smoothingFn_ge : case bn_gt_one => calc 1 = b i * (b i)⁻¹ := by rw [mul_inv_cancel₀ (by positivity)] _ ≤ b i * ⌈(b i)⁻¹⌉₊ := by gcongr; exact Nat.le_ceil _ - _ < b i * n := by gcongr; rw [Nat.cast_lt]; exact hn + _ < b i * n := by gcongr case le => calc b i * n ≤ 1 * n := by have := R.b_lt_one i; gcongr _ = n := by rw [one_mul] positivity @@ -1220,7 +1220,7 @@ lemma T_isBigO_smoothingFn_mul_asympBound : rw [Finset.mem_Ico] at hn have htmp1 : 0 < 1 - ε n := h_smoothingFn_floor n hn.1 have htmp2 : 0 < asympBound g a b n := h_asympBound_floor n hn.1 - rw [← _root_.div_le_iff (by positivity)] + rw [← _root_.div_le_iff₀ (by positivity)] rw [← Finset.mem_Ico] at hn calc T n / ((1 - ε ↑n) * asympBound g a b n) ≤ (Finset.Ico (⌊b' * n₀⌋₊) n₀).sup' h_base_nonempty @@ -1231,7 +1231,7 @@ lemma T_isBigO_smoothingFn_mul_asympBound : have h_one_sub_smoothingFn_pos' : 0 < 1 - ε n := h_smoothing_pos n hn rw [Real.norm_of_nonneg (R.T_nonneg n), Real.norm_of_nonneg (by positivity)] -- We now prove all other cases by induction - induction n using Nat.strongInductionOn with + induction n using Nat.strongRecOn with | ind n h_ind => have b_mul_n₀_le_ri i : ⌊b' * ↑n₀⌋₊ ≤ r i n := by exact_mod_cast calc ⌊b' * (n₀ : ℝ)⌋₊ ≤ b' * n₀ := Nat.floor_le <| by positivity @@ -1369,7 +1369,7 @@ lemma smoothingFn_mul_asympBound_isBigO_T : rw [Finset.mem_Ico] at hn have htmp1 : 0 < 1 + ε n := h_smoothingFn_floor n hn.1 have htmp2 : 0 < asympBound g a b n := h_asympBound_floor n hn.1 - rw [← _root_.le_div_iff (by positivity)] + rw [← _root_.le_div_iff₀ (by positivity)] rw [← Finset.mem_Ico] at hn calc T n / ((1 + ε ↑n) * asympBound g a b n) ≥ (Finset.Ico (⌊b' * n₀⌋₊) n₀).inf' h_base_nonempty @@ -1380,7 +1380,7 @@ lemma smoothingFn_mul_asympBound_isBigO_T : have h_one_sub_smoothingFn_pos' : 0 < 1 + ε n := h_smoothing_pos n hn rw [Real.norm_of_nonneg (R.T_nonneg n), Real.norm_of_nonneg (by positivity)] -- We now prove all other cases by induction - induction n using Nat.strongInductionOn with + induction n using Nat.strongRecOn with | ind n h_ind => have b_mul_n₀_le_ri i : ⌊b' * ↑n₀⌋₊ ≤ r i n := by exact_mod_cast calc ⌊b' * ↑n₀⌋₊ ≤ b' * n₀ := Nat.floor_le <| by positivity diff --git a/Mathlib/Computability/AkraBazzi/GrowsPolynomially.lean b/Mathlib/Computability/AkraBazzi/GrowsPolynomially.lean index 8c7637a070683..f9b3f66acc2b8 100644 --- a/Mathlib/Computability/AkraBazzi/GrowsPolynomially.lean +++ b/Mathlib/Computability/AkraBazzi/GrowsPolynomially.lean @@ -96,7 +96,7 @@ lemma eventually_zero_of_frequently_zero (hf : GrowsPolynomially f) (hf' : ∃ intro m induction m with | zero => - simp only [Nat.zero_eq, CharP.cast_eq_zero, neg_zero, zero_sub, zpow_zero, one_mul] at * + simp only [CharP.cast_eq_zero, neg_zero, zero_sub, zpow_zero, one_mul] at * specialize hx x₀ (le_of_max_le_left hx₀_ge) simp only [hx₀, mul_zero, Set.Icc_self, Set.mem_singleton_iff] at hx refine fun z _ hz => hx _ ?_ @@ -130,17 +130,17 @@ lemma eventually_zero_of_frequently_zero (hf : GrowsPolynomially f) (hf' : ∃ exact this 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) _) + rw [← le_div_iff₀ x₀_pos] + 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] calc -logb 2 (x/x₀) ≤ ⌈-logb 2 (x/x₀)⌉₊ := Nat.le_ceil (-logb 2 (x / x₀)) _ ≤ _ := by rw [add_comm]; exact_mod_cast Nat.ceil_le_floor_add_one _ case ub => - rw [← div_le_iff x₀_pos] + 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/ContextFreeGrammar.lean b/Mathlib/Computability/ContextFreeGrammar.lean index 4ee8b65304fa8..74ef24c357923 100644 --- a/Mathlib/Computability/ContextFreeGrammar.lean +++ b/Mathlib/Computability/ContextFreeGrammar.lean @@ -53,10 +53,10 @@ inductive Rewrites (r : ContextFreeRule T N) : List (Symbol T N) → List (Symbo r.Rewrites (x :: s₁) (x :: s₂) lemma Rewrites.exists_parts {r : ContextFreeRule T N} {u v : List (Symbol T N)} - (hyp : r.Rewrites u v) : + (hr : r.Rewrites u v) : ∃ p q : List (Symbol T N), u = p ++ [Symbol.nonterminal r.input] ++ q ∧ v = p ++ r.output ++ q := by - induction hyp with + induction hr with | head s => use [], s simp @@ -181,7 +181,7 @@ lemma Derives.append_left {v w : List (Symbol T g.NT)} | refl => rfl | tail _ last ih => exact ih.trans_produces <| last.append_left p -/-- Add extra prefix to context-free deriving. -/ +/-- Add extra postfix to context-free deriving. -/ lemma Derives.append_right {v w : List (Symbol T g.NT)} (hvw : g.Derives v w) (p : List (Symbol T g.NT)) : g.Derives (v ++ p) (w ++ p) := by @@ -193,7 +193,10 @@ end ContextFreeGrammar /-- Context-free languages are defined by context-free grammars. -/ def Language.IsContextFree (L : Language T) : Prop := - ∃ g : ContextFreeGrammar.{uT} T, g.language = L + ∃ g : ContextFreeGrammar.{0} T, g.language = L + +proof_wanted Language.isContextFree_iff {L : Language T} : + L.IsContextFree ↔ ∃ g : ContextFreeGrammar.{uN} T, g.language = L section closure_reversal diff --git a/Mathlib/Computability/DFA.lean b/Mathlib/Computability/DFA.lean index 312e709b9fe77..48d4c11638987 100644 --- a/Mathlib/Computability/DFA.lean +++ b/Mathlib/Computability/DFA.lean @@ -28,11 +28,9 @@ Currently, there are two disjoint sets of simp lemmas: one for `DFA.eval`, and a - Should `mem_accepts` and `mem_acceptsFrom` be marked `@[simp]`? -/ - -open Computability - universe u v +open Computability /-- A DFA 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`). -/ @@ -247,3 +245,11 @@ theorem comap_reindex (f : α' → α) (g : σ ≃ σ') : end Maps end DFA + +/-- A regular language is a language that is defined by a DFA with finite states. -/ +def Language.IsRegular {T : Type u} (L : Language T) : Prop := + ∃ σ : Type, ∃ _ : Fintype σ, ∃ M : DFA T σ, M.accepts = L + +proof_wanted Language.isRegular_iff {T : Type u} {L : Language T} : + L.IsRegular ↔ ∃ σ : Type v, ∃ _ : Fintype σ, ∃ M : DFA T σ, M.accepts = L +-- probably needs `import Mathlib.Data.Countable.Small` diff --git a/Mathlib/Computability/Halting.lean b/Mathlib/Computability/Halting.lean index 9777467e4dbd1..a2de5176d359b 100644 --- a/Mathlib/Computability/Halting.lean +++ b/Mathlib/Computability/Halting.lean @@ -16,7 +16,6 @@ A universal partial recursive function, Rice's theorem, and the halting problem. * [Mario Carneiro, *Formalizing computability theory via partial recursive functions*][carneiro2019] -/ - open Mathlib (Vector) open Encodable Denumerable @@ -174,6 +173,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 @@ -215,7 +223,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 - ⟨by infer_instance, Computable.const _⟩ }⟩ + Computable.const _}⟩ /-- The Halting problem is recursively enumerable -/ theorem halting_problem_re (n) : RePred fun c => (eval c n).Dom := @@ -273,8 +281,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 e16b96d54f1eb..a8779cd1c9283 100644 --- a/Mathlib/Computability/Language.lean +++ b/Mathlib/Computability/Language.lean @@ -159,10 +159,10 @@ 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, isEmpty_iff_eq_nil] at hy + rw [mem_filter, Bool.not_eq_true', ← Bool.bool_iff_false, List.isEmpty_iff] at hy exact ⟨h y hy.1, hy.2⟩ · rintro ⟨S, hx, h⟩ exact ⟨S, hx, fun y hy ↦ (h y hy).1⟩ @@ -261,10 +261,11 @@ instance : KleeneAlgebra (Language α) := mul_kstar_le_self := fun l m h ↦ by rw [kstar_eq_iSup_pow, mul_iSup] refine iSup_le (fun n ↦ ?_) - induction' n with n ih - · simp - rw [pow_succ, ← mul_assoc m (l^n) l] - exact le_trans (le_mul_congr ih le_rfl) h } + induction n with + | zero => simp + | succ n ih => + rw [pow_succ, ← mul_assoc m (l^n) l] + exact le_trans (le_mul_congr ih le_rfl) h } /-- Language `l.reverse` is defined as the set of words from `l` backwards. -/ def reverse (l : Language α) : Language α := { w : List α | w.reverse ∈ l } diff --git a/Mathlib/Computability/PartrecCode.lean b/Mathlib/Computability/PartrecCode.lean index 0bb7463dbe554..74b64e82859ab 100644 --- a/Mathlib/Computability/PartrecCode.lean +++ b/Mathlib/Computability/PartrecCode.lean @@ -170,7 +170,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 := @@ -488,7 +488,7 @@ theorem eval_prec_succ (cf cg : Code) (a k : ℕ) : simp instance : Membership (ℕ →. ℕ) Code := - ⟨fun f c => eval c = f⟩ + ⟨fun c f => eval c = f⟩ @[simp] theorem eval_const : ∀ n m, eval (Code.const n) m = Part.some n @@ -900,7 +900,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 +937,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 +969,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 +1015,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 28f554c1f9089..350ee120e6376 100644 --- a/Mathlib/Computability/Primrec.lean +++ b/Mathlib/Computability/Primrec.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Mathlib.Algebra.Order.Ring.Nat -import Mathlib.Data.List.GetD import Mathlib.Logic.Equiv.List import Mathlib.Logic.Function.Iterate @@ -28,7 +27,6 @@ for this.) * [Mario Carneiro, *Formalizing computability theory via partial recursive functions*][carneiro2019] -/ - open Mathlib (Vector) open Denumerable Encodable Function @@ -277,7 +275,7 @@ end Primcodable namespace Primrec -variable {α : Type*} {σ : Type*} [Primcodable α] [Primcodable σ] +variable {α : Type*} [Primcodable α] open Nat.Primrec @@ -459,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 @@ -653,7 +651,7 @@ theorem dom_fintype [Finite α] (f : α → σ) : Primrec f := option_some_iff.1 <| by haveI := decidableEqOfEncodable α refine ((list_get?₁ (l.map f)).comp (list_indexOf₁ l)).of_eq fun a => ?_ - rw [List.get?_eq_getElem?, List.getElem?_map, List.getElem?_indexOf (m a), Option.map_some'] + rw [List.get?_eq_getElem?, List.getElem?_map, List.getElem?_indexOf (m a), Option.map_some'] -- Porting note: These are new lemmas -- I added it because it actually simplified the proofs @@ -768,10 +766,11 @@ private theorem list_foldl' {f : α → List β} {g : α → σ} {h : α → σ dsimp only [F] generalize f a = l generalize g a = x - induction' n with n IH generalizing l x - · rfl - simp only [iterate_succ, comp_apply] - cases' l with b l <;> simp [IH] + induction n generalizing l x with + | zero => rfl + | succ n IH => + simp only [iterate_succ, comp_apply] + cases' l with b l <;> simp [IH] private theorem list_cons' : (haveI := prim H; Primrec₂ (@List.cons β)) := letI := prim H @@ -925,9 +924,14 @@ theorem list_get? : Primrec₂ (@List.get? α) := induction' l with _ l IH <;> simp [*] · apply IH +theorem list_getElem? : Primrec₂ (fun (l : List α) (n : ℕ) => l[n]?) := by + convert list_get? + ext + simp + theorem list_getD (d : α) : Primrec₂ fun l n => List.getD l n d := by - simp only [List.getD_eq_getD_get?] - exact option_getD.comp₂ list_get? (const _) + simp only [List.getD_eq_getElem?_getD] + exact option_getD.comp₂ list_getElem? (const _) theorem list_getI [Inhabited α] : Primrec₂ (@List.getI α _) := list_getD _ @@ -993,15 +997,16 @@ theorem nat_strong_rec (f : α → ℕ → σ) {g : α → List σ → Option σ option_map (hg.comp (fst.comp fst) snd) (to₂ <| list_concat.comp (snd.comp fst) snd))).of_eq fun a n => by - induction' n with n IH; · rfl - simp [IH, H, List.range_succ] + induction n with + | zero => rfl + | succ n IH => simp [IH, H, List.range_succ] theorem listLookup [DecidableEq α] : Primrec₂ (List.lookup : α → List (α × β) → Option β) := (to₂ <| list_rec snd (const none) <| to₂ <| - cond (Primrec.beq.comp (fst.comp fst) (fst.comp $ fst.comp snd)) - (option_some.comp $ snd.comp $ fst.comp snd) - (snd.comp $ snd.comp snd)).of_eq + cond (Primrec.beq.comp (fst.comp fst) (fst.comp <| fst.comp snd)) + (option_some.comp <| snd.comp <| fst.comp snd) + (snd.comp <| snd.comp snd)).of_eq fun a ps => by induction' ps with p ps ih <;> simp [List.lookup, *] cases ha : a == p.1 <;> simp [ha] @@ -1014,7 +1019,7 @@ theorem nat_omega_rec' (f : β → σ) {m : β → ℕ} {l : β → List β} {g let mapGraph (M : List (β × σ)) (bs : List β) : List σ := bs.bind (Option.toList <| M.lookup ·) let bindList (b : β) : ℕ → List β := fun n ↦ n.rec [b] fun _ bs ↦ bs.bind l let graph (b : β) : ℕ → List (β × σ) := fun i ↦ i.rec [] fun i ih ↦ - (bindList b (m b - i)).filterMap fun b' ↦ (g b' $ mapGraph ih (l b')).map (b', ·) + (bindList b (m b - i)).filterMap fun b' ↦ (g b' <| mapGraph ih (l b')).map (b', ·) have mapGraph_primrec : Primrec₂ mapGraph := to₂ <| list_bind snd <| optionToList.comp₂ <| listLookup.comp₂ .right (fst.comp₂ .left) have bindList_primrec : Primrec₂ (bindList) := @@ -1026,9 +1031,9 @@ theorem nat_omega_rec' (f : β → σ) {m : β → ℕ} {l : β → List β} {g to₂ <| listFilterMap (bindList_primrec.comp (fst.comp fst) - (nat_sub.comp (hm.comp $ fst.comp fst) (fst.comp snd))) <| + (nat_sub.comp (hm.comp <| fst.comp fst) (fst.comp snd))) <| to₂ <| option_map - (hg.comp snd (mapGraph_primrec.comp (snd.comp $ snd.comp fst) (hl.comp snd))) + (hg.comp snd (mapGraph_primrec.comp (snd.comp <| snd.comp fst) (hl.comp snd))) (Primrec₂.pair.comp₂ (snd.comp₂ .left) .right) have : Primrec (fun b => ((graph b (m b + 1)).get? 0).map Prod.snd) := option_map (list_get?.comp (graph_primrec.comp Primrec.id (succ.comp hm)) (const 0)) @@ -1041,14 +1046,14 @@ theorem nat_omega_rec' (f : β → σ) {m : β → ℕ} {l : β → List β} {g induction' k with k ih <;> simp [bindList] intro a₂ a₁ ha₁ ha₂ have : k ≤ m b := - Nat.lt_succ.mp (by simpa using Nat.add_lt_of_lt_sub $ Nat.zero_lt_of_lt (ih a₁ ha₁)) + Nat.lt_succ.mp (by simpa using Nat.add_lt_of_lt_sub <| Nat.zero_lt_of_lt (ih a₁ ha₁)) have : m a₁ ≤ m b - k := Nat.lt_succ.mp (by rw [← Nat.succ_sub this]; simpa using ih a₁ ha₁) exact lt_of_lt_of_le (Ord a₁ a₂ ha₂) this List.eq_nil_iff_forall_not_mem.mpr (by intro b' ha'; by_contra; simpa using bindList_m_lt (m b + 1) b' ha') have mapGraph_graph {bs bs' : List β} (has : bs' ⊆ bs) : - mapGraph (bs.map $ fun x => (x, f x)) bs' = bs'.map f := by + mapGraph (bs.map <| fun x => (x, f x)) bs' = bs'.map f := by induction' bs' with b bs' ih <;> simp [mapGraph] · have : b ∈ bs ∧ bs' ⊆ bs := by simpa using has rcases this with ⟨ha, has'⟩ @@ -1083,8 +1088,7 @@ end Primrec namespace Primcodable -variable {α : Type*} {β : Type*} -variable [Primcodable α] [Primcodable β] +variable {α : Type*} [Primcodable α] open Primrec @@ -1134,8 +1138,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 @@ -1210,7 +1214,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) diff --git a/Mathlib/Computability/Reduce.lean b/Mathlib/Computability/Reduce.lean index 32ee465296600..131ccd8fadbc5 100644 --- a/Mathlib/Computability/Reduce.lean +++ b/Mathlib/Computability/Reduce.lean @@ -311,9 +311,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,9 +321,8 @@ 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) @@ -345,7 +342,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 +366,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 95abb4a8e3941..cbcdb86be9877 100644 --- a/Mathlib/Computability/RegularExpressions.lean +++ b/Mathlib/Computability/RegularExpressions.lean @@ -215,14 +215,15 @@ theorem char_rmatch_iff (a : α) (x : List α) : rmatch (char a) x ↔ x = [a] : · simp [List.singleton_inj]; tauto · rw [rmatch, rmatch, deriv] split_ifs with h - · simp only [deriv_one, zero_rmatch, cons.injEq, and_false] - · simp only [deriv_zero, zero_rmatch, cons.injEq, and_false] + · simp only [deriv_one, zero_rmatch, cons.injEq, and_false, reduceCtorEq] + · simp only [deriv_zero, zero_rmatch, cons.injEq, and_false, reduceCtorEq] theorem add_rmatch_iff (P Q : RegularExpression α) (x : List α) : (P + Q).rmatch x ↔ P.rmatch x ∨ Q.rmatch x := by - induction' x with _ _ ih generalizing P Q - · simp only [rmatch, matchEpsilon, Bool.or_eq_true_iff] - · repeat rw [rmatch] + induction x generalizing P Q with + | nil => simp only [rmatch, matchEpsilon, Bool.or_eq_true_iff] + | cons _ _ ih => + repeat rw [rmatch] rw [deriv_add] exact ih _ _ @@ -294,7 +295,7 @@ theorem star_rmatch_iff (P : RegularExpression α) : · intro t' ht' cases ht' with | head ht' => - simp only [ne_eq, not_false_iff, true_and, rmatch] + simp only [ne_eq, not_false_iff, true_and, rmatch, reduceCtorEq] exact ht | tail _ ht' => exact helem t' ht' · rintro ⟨S, hsum, helem⟩ @@ -305,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) diff --git a/Mathlib/Computability/TMToPartrec.lean b/Mathlib/Computability/TMToPartrec.lean index 3ae1f1aa58149..79a322e54c754 100644 --- a/Mathlib/Computability/TMToPartrec.lean +++ b/Mathlib/Computability/TMToPartrec.lean @@ -248,7 +248,7 @@ theorem exists_code.comp {m n} {f : Vector ℕ n →. ℕ} {g : Fin n → Vector · obtain ⟨cf, hf⟩ := hf exact ⟨cf.comp cg, fun v => by - simp [hg, hf, map_bind, seq_bind_eq, Function.comp] + simp [hg, hf, map_bind, seq_bind_eq, Function.comp_def] rfl⟩ clear hf f; induction' n with n IH · exact ⟨nil, fun v => by simp [Vector.mOfFn, Bind.bind]; rfl⟩ @@ -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] 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' => ?_ @@ -359,12 +359,13 @@ theorem exists_code {n} {f : Vector ℕ n →. ℕ} (hf : Nat.Partrec' f) : PFun.mem_fix_iff.2 (Or.inl (by simp [hf, hn])) generalize (n.succ :: v.1 : List ℕ) = w at this ⊢ clear hn - induction' n with n IH - · exact this - refine IH (fun {m} h' => hm (Nat.lt_succ_of_lt h')) - (PFun.mem_fix_iff.2 (Or.inr ⟨_, ?_, this⟩)) - simp only [hf, hm n.lt_succ_self, Part.bind_some, List.headI, eq_self_iff_true, if_false, - Part.mem_some_iff, and_self_iff, List.tail_cons] + induction n with + | zero => exact this + | succ n IH => + refine IH (fun {m} h' => hm (Nat.lt_succ_of_lt h')) + (PFun.mem_fix_iff.2 (Or.inr ⟨_, ?_, this⟩)) + simp only [hf, hm n.lt_succ_self, Part.bind_some, List.headI, eq_self_iff_true, if_false, + Part.mem_some_iff, and_self_iff, List.tail_cons] end Code @@ -510,10 +511,14 @@ def Cont.then : Cont → Cont → Cont | Cont.fix f k => fun k' => Cont.fix f (k.then k') theorem Cont.then_eval {k k' : Cont} {v} : (k.then k').eval v = k.eval v >>= k'.eval := by - induction' k with _ _ _ _ _ _ _ _ _ k_ih _ _ k_ih generalizing v <;> - simp only [Cont.eval, Cont.then, bind_assoc, pure_bind, *] - · simp only [← k_ih] - · split_ifs <;> [rfl; simp only [← k_ih, bind_assoc]] + induction k generalizing v with + | halt => simp only [Cont.eval, Cont.then, pure_bind] + | cons₁ => simp only [Cont.eval, bind_assoc, *] + | cons₂ => simp only [Cont.eval, *] + | comp _ _ k_ih => simp only [Cont.eval, bind_assoc, ← k_ih] + | fix _ _ k_ih => + simp only [Cont.eval, *] + split_ifs <;> [rfl; simp only [← k_ih, bind_assoc]] /-- The `then k` function is a "configuration homomorphism". Its operation on states is to append `k` to the continuation of a `Cfg.ret` state, and to run `k` on `v` if we are in the `Cfg.halt v` @@ -897,6 +902,7 @@ def natEnd : Γ' → Bool | Γ'.consₗ => true | Γ'.cons => true | _ => false +attribute [nolint simpNF] natEnd.eq_3 /-- Pop a value from the stack and place the result in local store. -/ @[simp] @@ -1232,7 +1238,7 @@ theorem move_ok {p k₁ k₂ q s L₁ o L₂} {S : K' → List Γ'} (h₁ : k₁ rfl simp only [splitAtPred, Option.elim, List.head?, List.tail_cons, Option.iget_some] at e ⊢ revert e; cases p a <;> intro e <;> - simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢ + simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and, reduceCtorEq] at e ⊢ simp only [e] rfl · refine TransGen.head rfl ?_ @@ -1287,7 +1293,7 @@ theorem clear_ok {p k q s L₁ o L₂} {S : K' → List Γ'} (e : splitAtPred p rfl simp only [splitAtPred, Option.elim, List.head?, List.tail_cons] at e ⊢ revert e; cases p a <;> intro e <;> - simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and] at e ⊢ + simp only [cond_false, cond_true, Prod.mk.injEq, true_and, false_and, reduceCtorEq] at e ⊢ rcases e with ⟨e₁, e₂⟩ rw [e₁, e₂] · refine TransGen.head rfl ?_ @@ -1404,7 +1410,7 @@ theorem succ_ok {q s n} {c d : List Γ'} : Reaches₁ (TM2.step tr) ⟨some q.succ, s, K'.elim (trPosNum a ++ [Γ'.cons]) l₁ c d⟩ ⟨some (unrev q), s', K'.elim (l₂' ++ [Γ'.cons]) l₁' c d⟩ by obtain ⟨l₁', l₂', s', e, h⟩ := this [] - simp? [List.reverseAux] at e says simp only [List.reverseAux] at e + simp? [List.reverseAux] at e says simp only [List.reverseAux, List.reverseAux_eq] at e refine h.trans ?_ convert unrev_ok using 2 simp [e, List.reverseAux_eq] @@ -1596,10 +1602,13 @@ def trStmts₁ : Λ' → Finset Λ' | Q@(Λ'.ret _) => {Q} theorem trStmts₁_trans {q q'} : q' ∈ trStmts₁ q → trStmts₁ q' ⊆ trStmts₁ q := by - induction' q with _ _ _ q q_ih _ _ q q_ih q q_ih _ _ q q_ih q q_ih q q_ih q₁ q₂ q₁_ih q₂_ih _ <;> + 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 (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] - repeat exact fun h => Finset.Subset.trans (q_ih h) (Finset.subset_insert _ _) + 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' simp only [Finset.mem_biUnion, Finset.mem_univ, true_and, Finset.mem_insert] @@ -1790,7 +1799,9 @@ theorem ret_supports {S k} (H₁ : contSupp k ⊆ S) : TM2.SupportsStmt S (tr ( theorem trStmts₁_supports {S q} (H₁ : (q : Λ').Supports S) (HS₁ : trStmts₁ q ⊆ S) : Supports (trStmts₁ q) S := by have W := fun {q} => trStmts₁_self q - induction' q with _ _ _ q q_ih _ _ q q_ih q q_ih _ _ q q_ih q q_ih q q_ih q₁ q₂ q₁_ih q₂_ih _ <;> + 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 => _ <;> simp [trStmts₁, -Finset.singleton_subset_iff] at HS₁ ⊢ any_goals cases' Finset.insert_subset_iff.1 HS₁ with h₁ h₂ @@ -1905,3 +1916,5 @@ end end PartrecToTM2 end Turing + +set_option linter.style.longFile 2100 diff --git a/Mathlib/Computability/TuringMachine.lean b/Mathlib/Computability/TuringMachine.lean index 70ae4513ecba5..0309fcce41a02 100644 --- a/Mathlib/Computability/TuringMachine.lean +++ b/Mathlib/Computability/TuringMachine.lean @@ -178,7 +178,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,7 +262,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, + rw [List.getI_eq_get _ h₂, List.get_eq_getElem, List.getElem_append_right h, List.getElem_replicate] @[simp] @@ -310,10 +309,10 @@ theorem ListBlank.nth_modifyNth {Γ} [Inhabited Γ] (f : Γ → Γ) (n i) (L : L (L.modifyNth f n).nth i = if i = n then f (L.nth i) else L.nth i := by induction' n with n IH generalizing i L · cases i <;> simp only [ListBlank.nth_zero, if_true, ListBlank.head_cons, ListBlank.modifyNth, - ListBlank.nth_succ, if_false, ListBlank.tail_cons, Nat.zero_eq] + ListBlank.nth_succ, if_false, ListBlank.tail_cons, reduceCtorEq] · cases i · rw [if_neg (Nat.succ_ne_zero _).symm] - simp only [ListBlank.nth_zero, ListBlank.head_cons, ListBlank.modifyNth, Nat.zero_eq] + simp only [ListBlank.nth_zero, ListBlank.head_cons, ListBlank.modifyNth] · simp only [IH, ListBlank.modifyNth, ListBlank.nth_succ, ListBlank.tail_cons, Nat.succ.injEq] /-- A pointed map of `Inhabited` types is a map that sends one default value to the other. -/ @@ -553,7 +552,7 @@ theorem Tape.nth_zero {Γ} [Inhabited Γ] (T : Tape Γ) : T.nth 0 = T.1 := theorem Tape.right₀_nth {Γ} [Inhabited Γ] (T : Tape Γ) (n : ℕ) : T.right₀.nth n = T.nth n := by cases n <;> simp only [Tape.nth, Tape.right₀, Int.ofNat_zero, ListBlank.nth_zero, - ListBlank.nth_succ, ListBlank.head_cons, ListBlank.tail_cons, Nat.zero_eq] + ListBlank.nth_succ, ListBlank.head_cons, ListBlank.tail_cons] @[simp] theorem Tape.mk'_nth_nat {Γ} [Inhabited Γ] (L R : ListBlank Γ) (n : ℕ) : @@ -626,7 +625,7 @@ theorem Tape.write_move_right_n {Γ} [Inhabited Γ] (f : Γ → Γ) (L R : ListB ((Tape.move Dir.right)^[n] (Tape.mk' L R)).write (f (R.nth n)) = (Tape.move Dir.right)^[n] (Tape.mk' L (R.modifyNth f n)) := by induction' n with n IH generalizing L R - · simp only [ListBlank.nth_zero, ListBlank.modifyNth, iterate_zero_apply, Nat.zero_eq] + · simp only [ListBlank.nth_zero, ListBlank.modifyNth, iterate_zero_apply] rw [← Tape.write_mk', ListBlank.cons_head_tail] simp only [ListBlank.head_cons, ListBlank.nth_succ, ListBlank.modifyNth, Tape.move_right_mk', ListBlank.tail_cons, iterate_succ_apply, IH] @@ -1383,7 +1382,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₂ @@ -1614,7 +1613,8 @@ theorem stepAux_write (q : Stmt'₁) (v : σ) (a b : Γ) (L R : ListBlank Γ) : induction' l₂ with a l₂ IH generalizing l₁ l₂' · cases List.length_eq_zero.1 e rfl - cases' l₂' with b l₂' <;> simp only [List.length_nil, List.length_cons, Nat.succ_inj'] at e + cases' l₂' with b l₂' <;> + simp only [List.length_nil, List.length_cons, Nat.succ_inj', reduceCtorEq] at e rw [List.reverseAux, ← IH (a :: l₁) l₂' e] simp only [stepAux, ListBlank.append, Tape.write_mk', Tape.move_right_mk', ListBlank.head_cons, ListBlank.tail_cons] @@ -1733,7 +1733,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 ↦ ?_⟩ @@ -2353,7 +2353,7 @@ theorem tr_respects_aux₂ [DecidableEq K] {k : K} {q : Stmt₂₁} {v : σ} {S · refine ⟨_, fun k' ↦ ?_, by erw [List.length_cons, Tape.move_right_n_head, Tape.mk'_nth_nat, addBottom_nth_succ_fst, - cond, iterate_succ', Function.comp, Tape.move_right_left, Tape.move_right_n_head, + cond_false, iterate_succ', Function.comp, Tape.move_right_left, Tape.move_right_n_head, 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, @@ -2487,7 +2487,6 @@ theorem trCfg_init (k) (L : List (Γ k)) : TrCfg (TM2.init k L) (TM1.init (trIni rw [ListBlank.nth_mk, List.getI_eq_iget_get?, List.map, List.reverse_nil] cases L.reverse.get? i <;> rfl · rw [trInit, TM1.init] - dsimp only congr <;> cases L.reverse <;> try rfl simp only [List.map_map, List.tail_cons, List.map] rfl @@ -2569,3 +2568,5 @@ end end TM2to1 end Turing + +set_option linter.style.longFile 2700 diff --git a/Mathlib/Condensed/Basic.lean b/Mathlib/Condensed/Basic.lean index fb904e7ecb227..8d384f0d7eb88 100644 --- a/Mathlib/Condensed/Basic.lean +++ b/Mathlib/Condensed/Basic.lean @@ -76,7 +76,7 @@ namespace CondensedSet -- Note: `simp` can prove this when stated for `Condensed C` for a concrete category `C`. -- However, it doesn't seem to see through the abbreviation `CondensedSet` @[simp] -lemma hom_naturality_apply {X Y : CondensedSet.{u}} (f : X ⟶ Y) {S T : CompHausᵒᵖ} (g : S ⟶ T) +lemma hom_naturality_apply {X Y : CondensedSet.{u}} (f : X ⟶ Y) {S T : CompHausᵒᵖ} (g : S ⟶ T) (x : X.val.obj S) : f.val.app T (X.val.map g x) = Y.val.map g (f.val.app S x) := NatTrans.naturality_apply f.val g x diff --git a/Mathlib/Condensed/CartesianClosed.lean b/Mathlib/Condensed/CartesianClosed.lean new file mode 100644 index 0000000000000..879b84fb4b87a --- /dev/null +++ b/Mathlib/Condensed/CartesianClosed.lean @@ -0,0 +1,20 @@ +/- +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.Limits +import Mathlib.CategoryTheory.Closed.Types +import Mathlib.CategoryTheory.Sites.CartesianClosed +/-! + +# Condensed sets form a cartesian closed category +-/ + +universe u + +noncomputable section + +open CategoryTheory + +instance : CartesianClosed (CondensedSet.{u}) := inferInstanceAs (CartesianClosed (Sheaf _ _)) diff --git a/Mathlib/Condensed/Discrete/Basic.lean b/Mathlib/Condensed/Discrete/Basic.lean index 5f2ed84dfda6a..d7964352317fa 100644 --- a/Mathlib/Condensed/Discrete/Basic.lean +++ b/Mathlib/Condensed/Discrete/Basic.lean @@ -12,13 +12,13 @@ import Mathlib.Condensed.Light.Basic # Discrete-underlying adjunction Given a category `C` with sheafification with respect to the coherent topology on compact Hausdorff -spaces, we define a functor `C ⥤ Condensed C` which associates to an object of `C` the +spaces, we define a functor `C ⥤ Condensed C` which associates to an object of `C` the corresponding "discrete" condensed object (see `Condensed.discrete`). -In `Condensed.discreteUnderlyingAdj` we prove that this functor is left adjoint to the forgetful +In `Condensed.discreteUnderlyingAdj` we prove that this functor is left adjoint to the forgetful functor from `Condensed C` to `C`. -We also give the variant `LightCondensed.discreteUnderlyingAdj` for light condensed objects. +We also give the variant `LightCondensed.discreteUnderlyingAdj` for light condensed objects. -/ universe u v w @@ -30,13 +30,13 @@ namespace Condensed variable (C : Type w) [Category.{u+1} C] [HasWeakSheafify (coherentTopology CompHaus.{u}) C] /-- -The discrete condensed object associated to an object of `C` is the constant sheaf at that object. +The discrete condensed object associated to an object of `C` is the constant sheaf at that object. -/ @[simps!] noncomputable def discrete : C ⥤ Condensed.{u} C := constantSheaf _ C /-- -The underlying object of a condensed object in `C` is the condensed object evaluated at a point. +The underlying object of a condensed object in `C` is the condensed object evaluated at a point. This can be viewed as a sort of forgetful functor from `Condensed C` to `C` -/ @[simps!] @@ -45,7 +45,7 @@ noncomputable def underlying : Condensed.{u} C ⥤ C := /-- Discreteness is left adjoint to the forgetful functor. When `C` is `Type*`, this is analogous to -`TopCat.adj₁ : TopCat.discrete ⊣ forget TopCat`.   +`TopCat.adj₁ : TopCat.discrete ⊣ forget TopCat`. -/ noncomputable def discreteUnderlyingAdj : discrete C ⊣ underlying C := constantSheafAdj _ _ CompHaus.isTerminalPUnit @@ -57,14 +57,14 @@ namespace LightCondensed variable (C : Type w) [Category.{u} C] [HasSheafify (coherentTopology LightProfinite.{u}) C] /-- -The discrete light condensed object associated to an object of `C` is the constant sheaf at that +The discrete light condensed object associated to an object of `C` is the constant sheaf at that object. -/ @[simps!] noncomputable def discrete : C ⥤ LightCondensed.{u} C := constantSheaf _ C /-- -The underlying object of a condensed object in `C` is the light condensed object evaluated at a +The underlying object of a condensed object in `C` is the light condensed object evaluated at a point. This can be viewed as a sort of forgetful functor from `LightCondensed C` to `C` -/ @[simps!] @@ -73,7 +73,7 @@ noncomputable def underlying : LightCondensed.{u} C ⥤ C := /-- Discreteness is left adjoint to the forgetful functor. When `C` is `Type*`, this is analogous to -`TopCat.adj₁ : TopCat.discrete ⊣ forget TopCat`.   +`TopCat.adj₁ : TopCat.discrete ⊣ forget TopCat`. -/ noncomputable def discreteUnderlyingAdj : discrete C ⊣ underlying C := constantSheafAdj _ _ CompHausLike.isTerminalPUnit diff --git a/Mathlib/Condensed/Discrete/LocallyConstant.lean b/Mathlib/Condensed/Discrete/LocallyConstant.lean new file mode 100644 index 0000000000000..ca028c4a70293 --- /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 S 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 x := LocallyConstant.const _ x + +/-- The unit of the adjunction is an iso. -/ +noncomputable def unitIso : 𝟭 (Type max u w) ≅ functor.{u, w} P hs ⋙ + (sheafSections _ _).obj ⟨CompHausLike.of P PUnit.{u+1}⟩ where + hom := unit P hs + inv := { app := fun X f ↦ f.toFun PUnit.unit } + +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/Equivalence.lean b/Mathlib/Condensed/Equivalence.lean index 579875bfae18a..abc50a1886387 100644 --- a/Mathlib/Condensed/Equivalence.lean +++ b/Mathlib/Condensed/Equivalence.lean @@ -20,7 +20,7 @@ Since Stonean spaces are the projective objects in `CompHaus`, which has enough and the notions of effective epimorphism, epimorphism and surjective continuous map are equivalent in `CompHaus` and `Stonean`, we can use the general setup in `Mathlib.CategoryTheory.Sites.Coherent.SheafComparison` to deduce the equivalence of categories. -We give the corresponding statements for `Profinite` as well. +We give the corresponding statements for `Profinite` as well. ## Main results @@ -61,7 +61,7 @@ instance : Stonean.toProfinite.ReflectsEffectiveEpis where ((Stonean.effectiveEpi_tfae f).out 0 2).mpr (((Profinite.effectiveEpi_tfae _).out 0 2).mp h) /-- -An effective presentation of an `X : Profinite` with respect to the inclusion functor from `Stonean` +An effective presentation of an `X : Profinite` with respect to the inclusion functor from `Stonean` -/ noncomputable def stoneanToProfiniteEffectivePresentation (X : Profinite) : Stonean.toProfinite.EffectivePresentation X where diff --git a/Mathlib/Condensed/Explicit.lean b/Mathlib/Condensed/Explicit.lean index 15e67c5ac1557..541c0747e15fc 100644 --- a/Mathlib/Condensed/Explicit.lean +++ b/Mathlib/Condensed/Explicit.lean @@ -19,9 +19,9 @@ We give the following three explicit descriptions of condensed objects: * `Condensed.ofSheafStonean`: A finite-product-preserving presheaf on `CompHaus`, satisfying `EqualizerCondition`. -The property `EqualizerCondition` is defined in `Mathlib/CategoryTheory/Sites/RegularSheaves.lean` +The property `EqualizerCondition` is defined in `Mathlib/CategoryTheory/Sites/RegularSheaves.lean` and it says that for any effective epi `X ⟶ B` (in this case that is equivalent to being a -continuous surjection), the presheaf `F` exhibits `F(B)` as the equalizer of the two maps +continuous surjection), the presheaf `F` exhibits `F(B)` as the equalizer of the two maps `F(X) ⇉ F(X ×_B X)` We also give variants for condensed objects in concrete categories whose forgetful functor @@ -150,17 +150,17 @@ end Condensed namespace CondensedSet -/-- A `CondensedSet` version of `Condensed.ofSheafStonean`. -/ +/-- A `CondensedSet` version of `Condensed.ofSheafStonean`. -/ noncomputable abbrev ofSheafStonean (F : Stonean.{u}ᵒᵖ ⥤ Type (u+1)) [PreservesFiniteProducts F] : CondensedSet := Condensed.ofSheafStonean F -/-- A `CondensedSet` version of `Condensed.ofSheafProfinite`. -/ +/-- A `CondensedSet` version of `Condensed.ofSheafProfinite`. -/ noncomputable abbrev ofSheafProfinite (F : Profinite.{u}ᵒᵖ ⥤ Type (u+1)) [PreservesFiniteProducts F] (hF : EqualizerCondition F) : CondensedSet := Condensed.ofSheafProfinite F hF -/-- A `CondensedSet` version of `Condensed.ofSheafCompHaus`. -/ +/-- A `CondensedSet` version of `Condensed.ofSheafCompHaus`. -/ noncomputable abbrev ofSheafCompHaus (F : CompHaus.{u}ᵒᵖ ⥤ Type (u+1)) [PreservesFiniteProducts F] (hF : EqualizerCondition F) : CondensedSet := Condensed.ofSheafCompHaus F hF @@ -171,19 +171,19 @@ namespace CondensedMod variable (R : Type (u+1)) [Ring R] -/-- A `CondensedMod` version of `Condensed.ofSheafStonean`. -/ +/-- A `CondensedMod` version of `Condensed.ofSheafStonean`. -/ noncomputable abbrev ofSheafStonean (F : Stonean.{u}ᵒᵖ ⥤ ModuleCat.{u+1} R) [PreservesFiniteProducts F] : CondensedMod R := haveI : HasLimitsOfSize.{u, u+1} (ModuleCat R) := hasLimitsOfSizeShrink.{u, u+1, u+1, u+1} _ Condensed.ofSheafStonean F -/-- A `CondensedMod` version of `Condensed.ofSheafProfinite`. -/ +/-- A `CondensedMod` version of `Condensed.ofSheafProfinite`. -/ noncomputable abbrev ofSheafProfinite (F : Profinite.{u}ᵒᵖ ⥤ ModuleCat.{u+1} R) [PreservesFiniteProducts F] (hF : EqualizerCondition F) : CondensedMod R := haveI : HasLimitsOfSize.{u, u+1} (ModuleCat R) := hasLimitsOfSizeShrink.{u, u+1, u+1, u+1} _ Condensed.ofSheafProfinite F hF -/-- A `CondensedMod` version of `Condensed.ofSheafCompHaus`. -/ +/-- A `CondensedMod` version of `Condensed.ofSheafCompHaus`. -/ noncomputable abbrev ofSheafCompHaus (F : CompHaus.{u}ᵒᵖ ⥤ ModuleCat.{u+1} R) [PreservesFiniteProducts F] (hF : EqualizerCondition F) : CondensedMod R := Condensed.ofSheafCompHaus F hF diff --git a/Mathlib/Condensed/Functors.lean b/Mathlib/Condensed/Functors.lean index 73869ef6f22b8..c83e320059c0d 100644 --- a/Mathlib/Condensed/Functors.lean +++ b/Mathlib/Condensed/Functors.lean @@ -17,16 +17,16 @@ sets. ## Main definitions -* `compHausToCondensed : CompHaus.{u} ⥤ CondensedSet.{u}` is essentially the yoneda presheaf - functor. We also define `profiniteToCondensed` and `stoneanToCondensed`. +* `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 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 + mapping a compact Hausdorff space `S` to `LocallyConstant S X`, along with the isomorphism with the functor that goes through `TopCat.{u+1}`. -/ @@ -49,7 +49,7 @@ end Universes section Topology -/-- The functor from `CompHaus` to `Condensed.{u} (Type u)` given by the Yoneda sheaf. -/ +/-- The functor from `CompHaus` to `Condensed.{u} (Type u)` given by the Yoneda sheaf. -/ def compHausToCondensed' : CompHaus.{u} ⥤ Condensed.{u} (Type u) := (coherentTopology.subcanonical CompHaus).yoneda diff --git a/Mathlib/Condensed/Light/Basic.lean b/Mathlib/Condensed/Light/Basic.lean index e4336e0a3ea2d..f5156d707ed0f 100644 --- a/Mathlib/Condensed/Light/Basic.lean +++ b/Mathlib/Condensed/Light/Basic.lean @@ -60,7 +60,7 @@ namespace LightCondSet -- Note: `simp` can prove this when stated for `LightCondensed C` for a concrete category `C`. -- However, it doesn't seem to see through the abbreviation `LightCondSet` @[simp] -lemma hom_naturality_apply {X Y : LightCondSet.{u}} (f : X ⟶ Y) {S T : LightProfiniteᵒᵖ} +lemma hom_naturality_apply {X Y : LightCondSet.{u}} (f : X ⟶ Y) {S T : LightProfiniteᵒᵖ} (g : S ⟶ T) (x : X.val.obj S) : f.val.app T (X.val.map g x) = Y.val.map g (f.val.app S x) := NatTrans.naturality_apply f.val g x diff --git a/Mathlib/Condensed/Light/CartesianClosed.lean b/Mathlib/Condensed/Light/CartesianClosed.lean new file mode 100644 index 0000000000000..99af9b717d59a --- /dev/null +++ b/Mathlib/Condensed/Light/CartesianClosed.lean @@ -0,0 +1,22 @@ +/- +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.Light.Limits +import Mathlib.CategoryTheory.Closed.Types +import Mathlib.CategoryTheory.Sites.CartesianClosed +/-! + +# Light condensed sets form a cartesian closed category +-/ + +universe u + +noncomputable section + +open CategoryTheory + +variable {C : Type u} [SmallCategory C] + +instance : CartesianClosed (LightCondSet.{u}) := inferInstanceAs (CartesianClosed (Sheaf _ _)) diff --git a/Mathlib/Condensed/Light/Explicit.lean b/Mathlib/Condensed/Light/Explicit.lean index 8967577b1c7d4..837d7f33f7fab 100644 --- a/Mathlib/Condensed/Light/Explicit.lean +++ b/Mathlib/Condensed/Light/Explicit.lean @@ -14,9 +14,9 @@ We give explicit description of light condensed sets: * `LightCondensed.ofSheafLightProfinite`: A finite-product-preserving presheaf on `LightProfinite`, satisfying `EqualizerCondition`. -The property `EqualizerCondition` is defined in `Mathlib/CategoryTheory/Sites/RegularExtensive.lean` +The property `EqualizerCondition` is defined in `Mathlib/CategoryTheory/Sites/RegularExtensive.lean` and it says that for any effective epi `X ⟶ B` (in this case that is equivalent to being a -continuous surjection), the presheaf `F` exhibits `F(B)` as the equalizer of the two maps +continuous surjection), the presheaf `F` exhibits `F(B)` as the equalizer of the two maps `F(X) ⇉ F(X ×_B X)` We also give variants for light condensed objects in concrete categories whose forgetful functor @@ -71,7 +71,7 @@ end LightCondensed namespace LightCondSet -/-- A `LightCondSet` version of `LightCondensed.ofSheafLightProfinite`. -/ +/-- A `LightCondSet` version of `LightCondensed.ofSheafLightProfinite`. -/ noncomputable abbrev ofSheafLightProfinite (F : LightProfinite.{u}ᵒᵖ ⥤ Type u) [PreservesFiniteProducts F] (hF : EqualizerCondition F) : LightCondSet := LightCondensed.ofSheafLightProfinite F hF @@ -82,7 +82,7 @@ namespace LightCondMod variable (R : Type u) [Ring R] -/-- A `LightCondAb` version of `LightCondensed.ofSheafLightProfinite`. -/ +/-- A `LightCondAb` version of `LightCondensed.ofSheafLightProfinite`. -/ noncomputable abbrev ofSheafLightProfinite (F : LightProfinite.{u}ᵒᵖ ⥤ ModuleCat.{u} R) [PreservesFiniteProducts F] (hF : EqualizerCondition F) : LightCondMod.{u} R := LightCondensed.ofSheafLightProfinite F hF @@ -91,7 +91,7 @@ end LightCondMod namespace LightCondAb -/-- A `LightCondAb` version of `LightCondensed.ofSheafLightProfinite`. -/ +/-- A `LightCondAb` version of `LightCondensed.ofSheafLightProfinite`. -/ noncomputable abbrev ofSheafLightProfinite (F : LightProfiniteᵒᵖ ⥤ ModuleCat ℤ) [PreservesFiniteProducts F] (hF : EqualizerCondition F) : LightCondAb := LightCondMod.ofSheafLightProfinite ℤ F hF diff --git a/Mathlib/Condensed/Light/Functors.lean b/Mathlib/Condensed/Light/Functors.lean index 191499d9bb0d8..7d58dbe10bb93 100644 --- a/Mathlib/Condensed/Light/Functors.lean +++ b/Mathlib/Condensed/Light/Functors.lean @@ -14,13 +14,13 @@ sets. ## Main definitions -* `lightProfiniteToLightCondSet : LightProfinite.{u} ⥤ LightCondSet.{u}`  +* `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 + mapping a light profinite space `S` to `LocallyConstant S X`, along with the isomorphism with the functor that goes through `TopCat.{u+1}`. -/ @@ -29,7 +29,7 @@ universe u v open CategoryTheory Limits -/-- The functor from `LightProfinite.{u}` to `LightCondSet.{u}` given by the Yoneda sheaf. -/ +/-- The functor from `LightProfinite.{u}` to `LightCondSet.{u}` given by the Yoneda sheaf. -/ def lightProfiniteToLightCondSet : LightProfinite.{u} ⥤ LightCondSet.{u} := (coherentTopology.subcanonical LightProfinite).yoneda diff --git a/Mathlib/Condensed/Light/Limits.lean b/Mathlib/Condensed/Light/Limits.lean new file mode 100644 index 0000000000000..c1509f55c090b --- /dev/null +++ b/Mathlib/Condensed/Light/Limits.lean @@ -0,0 +1,30 @@ +/- +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.Light.Module +/-! + +# Limits in categories of light condensed objects + +This file adds some instances for limits in light condensed sets and modules. +-/ + +universe u + +open CategoryTheory Limits + +instance : HasLimitsOfSize.{u, u} LightCondSet.{u} := by + change HasLimitsOfSize (Sheaf _ _) + infer_instance + +instance : HasFiniteLimits LightCondSet.{u} := hasFiniteLimits_of_hasLimitsOfSize _ + +variable (R : Type u) [Ring R] + +instance : HasLimitsOfSize.{u, u} (LightCondMod.{u} R) := by + change HasLimitsOfSize (Sheaf _ _) + infer_instance + +instance : HasFiniteLimits (LightCondMod.{u} R) := hasFiniteLimits_of_hasLimitsOfSize _ diff --git a/Mathlib/Condensed/Light/Module.lean b/Mathlib/Condensed/Light/Module.lean index d75eee03e1156..e4ba98cbb8812 100644 --- a/Mathlib/Condensed/Light/Module.lean +++ b/Mathlib/Condensed/Light/Module.lean @@ -68,7 +68,7 @@ namespace LightCondMod -- Note: `simp` can prove this when stated for `LightCondensed C` for a concrete category `C`. -- However, it doesn't seem to see through the abbreviation `LightCondMod` @[simp] -lemma hom_naturality_apply {X Y : LightCondMod.{u} R} (f : X ⟶ Y) {S T : LightProfiniteᵒᵖ} +lemma hom_naturality_apply {X Y : LightCondMod.{u} R} (f : X ⟶ Y) {S T : LightProfiniteᵒᵖ} (g : S ⟶ T) (x : X.val.obj S) : f.val.app T (X.val.map g x) = Y.val.map g (f.val.app S x) := NatTrans.naturality_apply f.val g x diff --git a/Mathlib/Condensed/Light/TopCatAdjunction.lean b/Mathlib/Condensed/Light/TopCatAdjunction.lean index fbdac8cf24455..5b6ffa2fd3fa4 100644 --- a/Mathlib/Condensed/Light/TopCatAdjunction.lean +++ b/Mathlib/Condensed/Light/TopCatAdjunction.lean @@ -39,14 +39,14 @@ private def coinducingCoprod : X.val.obj ⟨LightProfinite.of PUnit⟩ := fun ⟨⟨S, i⟩, s⟩ ↦ X.val.map (S.const s).op i -/-- Let `X` be a light condensed set. We define a topology on `X(*)` as the quotient topology of +/-- 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)`. In other words, the topology coinduced by the map `LightCondSet.coinducingCoprod` above. -/ local instance underlyingTopologicalSpace : TopologicalSpace (X.val.obj ⟨LightProfinite.of PUnit⟩) := TopologicalSpace.coinduced (coinducingCoprod X) inferInstance -/-- The object part of the functor `LightCondSet ⥤ TopCat`  -/ +/-- The object part of the functor `LightCondSet ⥤ TopCat` -/ def toTopCat : TopCat.{u} := TopCat.of (X.val.obj ⟨LightProfinite.of PUnit⟩) lemma continuous_coinducingCoprod {S : LightProfinite.{u}} (x : X.val.obj ⟨S⟩) : @@ -58,7 +58,7 @@ lemma continuous_coinducingCoprod {S : LightProfinite.{u}} (x : X.val.obj ⟨S variable {X} {Y : LightCondSet} (f : X ⟶ Y) -/-- The map part of the functor `LightCondSet ⥤ TopCat`  -/ +/-- The map part of the functor `LightCondSet ⥤ TopCat` -/ @[simps] def toTopCatMap : X.toTopCat ⟶ Y.toTopCat where toFun := f.val.app ⟨LightProfinite.of PUnit⟩ @@ -73,7 +73,7 @@ def toTopCatMap : X.toTopCat ⟶ Y.toTopCat where rw [this] exact continuous_coinducingCoprod _ _ -/-- The functor `LightCondSet ⥤ TopCat`  -/ +/-- The functor `LightCondSet ⥤ TopCat` -/ @[simps] def _root_.lightCondSetToTopCat : LightCondSet.{u} ⥤ TopCat.{u} where obj X := X.toTopCat @@ -87,7 +87,7 @@ def topCatAdjunctionCounit (X : TopCat.{u}) : X.toLightCondSet.toTopCat ⟶ X wh continuity /-- The counit of the adjunction `lightCondSetToTopCat ⊣ topCatToLightCondSet` is always bijective, -but not an isomorphism in general (the inverse isn't continuous unless `X` is sequential). +but not an isomorphism in general (the inverse isn't continuous unless `X` is sequential). -/ def topCatAdjunctionCounitEquiv (X : TopCat.{u}) : X.toLightCondSet.toTopCat ≃ X where toFun := topCatAdjunctionCounit X @@ -112,19 +112,19 @@ def topCatAdjunctionUnit (X : LightCondSet.{u}) : X ⟶ X.toTopCat.toLightCondSe apply continuous_coinduced_rng } naturality := fun _ _ _ ↦ by ext - simp only [types_comp_apply, ContinuousMap.coe_mk, TopCat.toLightCondSet_val_map, - ContinuousMap.comp_apply, ← FunctorToTypes.map_comp_apply] + simp only [TopCat.toSheafCompHausLike_val_obj, CompHausLike.compHausLikeToTop_obj, + Opposite.op_unop, types_comp_apply, TopCat.toSheafCompHausLike_val_map, + ← FunctorToTypes.map_comp_apply] 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/Light/TopComparison.lean b/Mathlib/Condensed/Light/TopComparison.lean index 6fca286eaff84..bebf7bfe42841 100644 --- a/Mathlib/Condensed/Light/TopComparison.lean +++ b/Mathlib/Condensed/Light/TopComparison.lean @@ -3,7 +3,7 @@ Copyright (c) 2023 Dagur Asgeirsson. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Dagur Asgeirsson -/ -import Mathlib.Condensed.Light.Explicit +import Mathlib.Condensed.Light.Basic import Mathlib.Condensed.TopComparison /-! @@ -14,26 +14,19 @@ We define the functor `topCatToLightCondSet : TopCat.{u} ⥤ LightCondSet.{u}`. -/ -universe w w' v u +universe u -open CategoryTheory Opposite Limits regularTopology ContinuousMap +open CategoryTheory /-- Associate to a `u`-small topological space the corresponding light condensed set, given by `yonedaPresheaf`. -/ -@[simps! val_obj val_map] -noncomputable def TopCat.toLightCondSet (X : TopCat.{u}) : LightCondSet.{u} := - @LightCondSet.ofSheafLightProfinite (yonedaPresheaf LightProfinite.toTopCat.{u} X) _ (by - apply equalizerCondition_yonedaPresheaf LightProfinite.toTopCat.{u} X - intro Z B π he - rw [LightProfinite.effectiveEpi_iff_surjective] at he - apply QuotientMap.of_surjective_continuous he π.continuous) +noncomputable abbrev TopCat.toLightCondSet (X : TopCat.{u}) : LightCondSet.{u} := + toSheafCompHausLike.{u} _ X (fun _ _ _ ↦ (LightProfinite.effectiveEpi_iff_surjective _).mp) /-- -`TopCat.toLightCondSet` yields a functor from `TopCat.{u}` to `LightCondSet.{u}`. +`TopCat.toLightCondSet` yields a functor from `TopCat.{u}` to `LightCondSet.{u}`. -/ -@[simps] -noncomputable def topCatToLightCondSet : TopCat.{u} ⥤ LightCondSet.{u} where - obj X := X.toLightCondSet - map f := ⟨⟨fun _ g ↦ f.comp g, by aesop⟩⟩ +noncomputable abbrev topCatToLightCondSet : TopCat.{u} ⥤ LightCondSet.{u} := + topCatToSheafCompHausLike.{u} _ (fun _ _ _ ↦ (LightProfinite.effectiveEpi_iff_surjective _).mp) diff --git a/Mathlib/Condensed/Module.lean b/Mathlib/Condensed/Module.lean index c9e76f9b22338..24a5079139cfa 100644 --- a/Mathlib/Condensed/Module.lean +++ b/Mathlib/Condensed/Module.lean @@ -74,7 +74,7 @@ namespace CondensedMod -- Note: `simp` can prove this when stated for `Condensed C` for a concrete category `C`. -- However, it doesn't seem to see through the abbreviation `CondensedMod` @[simp] -lemma hom_naturality_apply {X Y : CondensedMod.{u} R} (f : X ⟶ Y) {S T : CompHausᵒᵖ} (g : S ⟶ T) +lemma hom_naturality_apply {X Y : CondensedMod.{u} R} (f : X ⟶ Y) {S T : CompHausᵒᵖ} (g : S ⟶ T) (x : X.val.obj S) : f.val.app T (X.val.map g x) = Y.val.map g (f.val.app S x) := NatTrans.naturality_apply f.val g x diff --git a/Mathlib/Condensed/TopCatAdjunction.lean b/Mathlib/Condensed/TopCatAdjunction.lean index c4f72257d9754..732a1448149d9 100644 --- a/Mathlib/Condensed/TopCatAdjunction.lean +++ b/Mathlib/Condensed/TopCatAdjunction.lean @@ -34,13 +34,13 @@ 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 -/-- Let `X` be a condensed set. We define a topology on `X(*)` as the quotient topology of +/-- 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)`. In other words, the topology coinduced by the map `CondensedSet.coinducingCoprod` above. -/ local instance : TopologicalSpace (X.val.obj ⟨CompHaus.of PUnit⟩) := TopologicalSpace.coinduced (coinducingCoprod X) inferInstance -/-- The object part of the functor `CondensedSet ⥤ TopCat`  -/ +/-- The object part of the functor `CondensedSet ⥤ TopCat` -/ def CondensedSet.toTopCat : TopCat.{u+1} := TopCat.of (X.val.obj ⟨CompHaus.of PUnit⟩) namespace CondensedSet @@ -54,7 +54,7 @@ lemma continuous_coinducingCoprod {S : CompHaus.{u}} (x : X.val.obj ⟨S⟩) : variable {X} {Y : CondensedSet} (f : X ⟶ Y) -/-- The map part of the functor `CondensedSet ⥤ TopCat`  -/ +/-- The map part of the functor `CondensedSet ⥤ TopCat` -/ @[simps] def toTopCatMap : X.toTopCat ⟶ Y.toTopCat where toFun := f.val.app ⟨CompHaus.of PUnit⟩ @@ -71,7 +71,7 @@ def toTopCatMap : X.toTopCat ⟶ Y.toTopCat where end CondensedSet -/-- The functor `CondensedSet ⥤ TopCat`  -/ +/-- The functor `CondensedSet ⥤ TopCat` -/ @[simps] def condensedSetToTopCat : CondensedSet.{u} ⥤ TopCat.{u+1} where obj X := X.toTopCat @@ -88,7 +88,7 @@ def topCatAdjunctionCounit (X : TopCat.{u+1}) : X.toCondensedSet.toTopCat ⟶ X continuity /-- The counit of the adjunction `condensedSetToTopCat ⊣ topCatToCondensedSet` is always bijective, -but not an isomorphism in general (the inverse isn't continuous unless `X` is compactly generated). +but not an isomorphism in general (the inverse isn't continuous unless `X` is compactly generated). -/ def topCatAdjunctionCounitEquiv (X : TopCat.{u+1}) : X.toCondensedSet.toTopCat ≃ X where toFun := topCatAdjunctionCounit X @@ -113,20 +113,19 @@ def topCatAdjunctionUnit (X : CondensedSet.{u}) : X ⟶ X.toTopCat.toCondensedSe apply continuous_coinduced_rng } naturality := fun _ _ _ ↦ by ext - simp only [TopCat.toCondensedSet_val_obj, CompHausLike.compHausLikeToTop_obj, - Opposite.op_unop, types_comp_apply, TopCat.toCondensedSet_val_map, + simp only [TopCat.toSheafCompHausLike_val_obj, CompHausLike.compHausLikeToTop_obj, + Opposite.op_unop, types_comp_apply, TopCat.toSheafCompHausLike_val_map, ← FunctorToTypes.map_comp_apply] 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 56eeda95ac14a..bcb10b87c8ea9 100644 --- a/Mathlib/Condensed/TopComparison.lean +++ b/Mathlib/Condensed/TopComparison.lean @@ -4,14 +4,15 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Dagur Asgeirsson -/ import Mathlib.CategoryTheory.Limits.Preserves.Opposites +import Mathlib.CategoryTheory.Sites.Coherent.SheafComparison +import Mathlib.Condensed.Basic import Mathlib.Topology.Category.TopCat.Yoneda -import Mathlib.Condensed.Explicit /-! # The functor from topological spaces to condensed sets -This file builds on the API from the file `TopCat.Yoneda`. If the forgetful functor to `TopCat` has +This file builds on the API from the file `TopCat.Yoneda`. If the forgetful functor to `TopCat` has nice properties, like preserving pullbacks and finite coproducts, then this Yoneda presheaf satisfies the sheaf condition for the regular and extensive topologies respectively. @@ -24,11 +25,13 @@ universe w w' v u open CategoryTheory Opposite Limits regularTopology ContinuousMap +attribute [local instance] ConcreteCategory.instFunLike + 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 `QuotientMap.lift` in the proof of `equalizerCondition_yonedaPresheaf`. -/ theorem factorsThrough_of_pullbackCondition {Z B : C} {π : Z ⟶ B} [HasPullback π π] @@ -47,13 +50,13 @@ 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' /-- If `G` preserves the relevant pullbacks and every effective epi in `C` is a quotient map (which is -the case when `C` is `CompHaus` or `Profinite`), then `yonedaPresheaf` satisfies the equalizer +the case when `C` is `CompHaus` or `Profinite`), then `yonedaPresheaf` satisfies the equalizer condition which is required to be a sheaf for the regular topology. -/ theorem equalizerCondition_yonedaPresheaf @@ -80,42 +83,60 @@ theorem equalizerCondition_yonedaPresheaf exact DFunLike.ext'_iff.mp ((hq Z B π).lift_comp a (factorsThrough_of_pullbackCondition G X ha)) /-- -If `G` preserves finite coproducts (which is the case when `C` is `CompHaus`, `Profinite` or +If `G` preserves finite coproducts (which is the case when `C` is `CompHaus`, `Profinite` or `Stonean`), then `yonedaPresheaf` preserves finite products, which is required to be a sheaf for the extensive topology. -/ noncomputable instance [PreservesFiniteCoproducts G] : - PreservesFiniteProducts (yonedaPresheaf G X) := by - change PreservesFiniteProducts (G.op ⋙ yonedaPresheaf' X) - have h' : PreservesFiniteProducts (yonedaPresheaf' X) := inferInstance - have h : PreservesFiniteProducts G.op := - { preserves := fun J _ => by - apply (config := { allowSynthFailures := true }) preservesLimitsOfShapeOp - exact preservesColimitsOfShapeOfEquiv (Discrete.opposite J).symm _ } - constructor - intro J _ - have := h.1 J - have := h'.1 J - exact compPreservesLimitsOfShape _ _ + PreservesFiniteProducts (yonedaPresheaf G X) := + have := preservesFiniteProductsOp G + ⟨fun _ ↦ compPreservesLimitsOfShape G.op (yonedaPresheaf' X)⟩ + +section + +variable (P : TopCat.{u} → Prop) (X : TopCat.{max u w}) + [CompHausLike.HasExplicitFiniteCoproducts.{0} P] [CompHausLike.HasExplicitPullbacks.{u} P] + (hs : ∀ ⦃X Y : CompHausLike P⦄ (f : X ⟶ Y), EffectiveEpi f → Function.Surjective f) /-- -Associate to a `(u+1)`-small topological space the corresponding condensed set, given by -`yonedaPresheaf`. +The sheaf on `CompHausLike P` of continuous maps to a topological space. -/ @[simps! val_obj val_map] -noncomputable def TopCat.toCondensedSet (X : TopCat.{u+1}) : CondensedSet.{u} := - @CondensedSet.ofSheafCompHaus (yonedaPresheaf.{u, u+1, u, u+1} compHausToTop.{u} X) _ (by +def TopCat.toSheafCompHausLike : + have := CompHausLike.preregular hs + Sheaf (coherentTopology (CompHausLike.{u} P)) (Type (max u w)) where + val := yonedaPresheaf.{u, max u w} (CompHausLike.compHausLikeToTop.{u} P) X + cond := by + have := CompHausLike.preregular hs + rw [Presheaf.isSheaf_iff_preservesFiniteProducts_and_equalizerCondition] + refine ⟨⟨inferInstance⟩, ?_⟩ apply (config := { allowSynthFailures := true }) equalizerCondition_yonedaPresheaf - compHausToTop.{u} X + (CompHausLike.compHausLikeToTop.{u} P) X intro Z B π he - rw [((CompHaus.effectiveEpi_tfae π).out 0 2 :)] at he - apply QuotientMap.of_surjective_continuous he π.continuous ) - + apply QuotientMap.of_surjective_continuous (hs _ he) π.continuous /-- -`TopCat.toCondensedSet` yields a functor from `TopCat.{u+1}` to `CondensedSet.{u}`. +`TopCat.toSheafCompHausLike` yields a functor from `TopCat.{max u w}` to +`Sheaf (coherentTopology (CompHausLike.{u} P)) (Type (max u w))`. -/ @[simps] -noncomputable def topCatToCondensedSet : TopCat.{u+1} ⥤ CondensedSet.{u} where - obj X := X.toCondensedSet +noncomputable def topCatToSheafCompHausLike : + have := CompHausLike.preregular hs + TopCat.{max u w} ⥤ Sheaf (coherentTopology (CompHausLike.{u} P)) (Type (max u w)) where + obj X := X.toSheafCompHausLike P hs map f := ⟨⟨fun _ g ↦ f.comp g, by aesop⟩⟩ + +end + +/-- +Associate to a `(u+1)`-small topological space the corresponding condensed set, given by +`yonedaPresheaf`. +-/ +noncomputable abbrev TopCat.toCondensedSet (X : TopCat.{u+1}) : CondensedSet.{u} := + toSheafCompHausLike.{u+1} _ X (fun _ _ _ ↦ ((CompHaus.effectiveEpi_tfae _).out 0 2).mp) + +/-- +`TopCat.toCondensedSet` yields a functor from `TopCat.{u+1}` to `CondensedSet.{u}`. +-/ +noncomputable abbrev topCatToCondensedSet : TopCat.{u+1} ⥤ CondensedSet.{u} := + topCatToSheafCompHausLike.{u+1} _ (fun _ _ _ ↦ ((CompHaus.effectiveEpi_tfae _).out 0 2).mp) diff --git a/Mathlib/Control/Applicative.lean b/Mathlib/Control/Applicative.lean index 50670dad3673d..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] @@ -82,11 +83,11 @@ theorem map_pure (f : α → β) (x : α) : (f <$> pure x : Comp F G β) = pure Comp.ext <| by simp theorem seq_pure (f : Comp F G (α → β)) (x : α) : f <*> pure x = (fun g : α → β => g x) <$> f := - Comp.ext <| by simp [(· ∘ ·), functor_norm] + Comp.ext <| by simp [comp_def, functor_norm] theorem seq_assoc (x : Comp F G α) (f : Comp F G (α → β)) (g : Comp F G (β → γ)) : g <*> (f <*> x) = @Function.comp α β γ <$> g <*> f <*> x := - Comp.ext <| by simp [(· ∘ ·), functor_norm] + Comp.ext <| by simp [comp_def, functor_norm] theorem pure_seq_eq_map (f : α → β) (x : Comp F G α) : pure f <*> x = f <$> x := Comp.ext <| by simp [Applicative.pure_seq_eq_map', functor_norm] @@ -119,7 +120,7 @@ instance {f : Type u → Type w} {g : Type v → Type u} [Applicative f] [Applic commutative_prod _ _ := by simp! [map, Seq.seq] rw [commutative_map] - simp only [mk, flip, seq_map_assoc, Function.comp, map_map] + simp only [mk, flip, seq_map_assoc, Function.comp_def, map_map] congr funext x y rw [commutative_map] diff --git a/Mathlib/Control/Basic.lean b/Mathlib/Control/Basic.lean index 8796014b34cc6..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 @@ -54,6 +49,7 @@ theorem seq_map_assoc (x : F (α → β)) (f : γ → α) (y : F γ) : simp only [← pure_seq] simp only [seq_assoc, Function.comp, seq_pure, ← comp_map] simp [pure_seq] + rfl @[functor_norm] theorem map_seq (f : β → γ) (x : F (α → β)) (y : F α) : @@ -66,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 @@ -213,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 := @@ -224,3 +214,4 @@ theorem CommApplicative.commutative_map {m : Type u → Type v} [h : Applicative _ = (fun b a => f a b) <$> b <*> a := by rw [@CommApplicative.commutative_prod m h] simp [seq_map_assoc, map_seq, seq_assoc, seq_pure, map_map, (· ∘ ·)] + rfl diff --git a/Mathlib/Control/Bitraversable/Instances.lean b/Mathlib/Control/Bitraversable/Instances.lean index ad3106d4f11c4..0627c13d3bbac 100644 --- a/Mathlib/Control/Bitraversable/Instances.lean +++ b/Mathlib/Control/Bitraversable/Instances.lean @@ -93,7 +93,7 @@ instance (priority := 10) Bitraversable.isLawfulTraversable [LawfulBitraversable constructor <;> intros <;> simp [traverse, comp_tsnd, functor_norm] · simp [tsnd_eq_snd_id, (· <$> ·), id.mk] - · simp [tsnd, binaturality, Function.comp, functor_norm] + · simp [tsnd, binaturality, Function.comp_def, functor_norm] end diff --git a/Mathlib/Control/Bitraversable/Lemmas.lean b/Mathlib/Control/Bitraversable/Lemmas.lean index 085f0781b4305..a13f3aa61a6b2 100644 --- a/Mathlib/Control/Bitraversable/Lemmas.lean +++ b/Mathlib/Control/Bitraversable/Lemmas.lean @@ -66,27 +66,27 @@ theorem id_tsnd : ∀ {α β} (x : t α β), tsnd (F := Id) pure x = pure x := theorem comp_tfst {α₀ α₁ α₂ β} (f : α₀ → F α₁) (f' : α₁ → G α₂) (x : t α₀ β) : Comp.mk (tfst f' <$> tfst f x) = tfst (Comp.mk ∘ map f' ∘ f) x := by rw [← comp_bitraverse] - simp only [Function.comp, tfst, map_pure, Pure.pure] + simp only [Function.comp_def, tfst, map_pure, Pure.pure] @[higher_order tfst_comp_tsnd] theorem tfst_tsnd {α₀ α₁ β₀ β₁} (f : α₀ → F α₁) (f' : β₀ → G β₁) (x : t α₀ β₀) : Comp.mk (tfst f <$> tsnd f' x) = bitraverse (Comp.mk ∘ pure ∘ f) (Comp.mk ∘ map pure ∘ f') x := by rw [← comp_bitraverse] - simp only [Function.comp, map_pure] + simp only [Function.comp_def, map_pure] @[higher_order tsnd_comp_tfst] theorem tsnd_tfst {α₀ α₁ β₀ β₁} (f : α₀ → F α₁) (f' : β₀ → G β₁) (x : t α₀ β₀) : Comp.mk (tsnd f' <$> tfst f x) = bitraverse (Comp.mk ∘ map pure ∘ f) (Comp.mk ∘ pure ∘ f') x := by rw [← comp_bitraverse] - simp only [Function.comp, map_pure] + simp only [Function.comp_def, map_pure] @[higher_order tsnd_comp_tsnd] theorem comp_tsnd {α β₀ β₁ β₂} (g : β₀ → F β₁) (g' : β₁ → G β₂) (x : t α β₀) : Comp.mk (tsnd g' <$> tsnd g x) = tsnd (Comp.mk ∘ map g' ∘ g) x := by rw [← comp_bitraverse] - simp only [Function.comp, map_pure] + simp only [Function.comp_def, map_pure] rfl open Bifunctor diff --git a/Mathlib/Control/Combinators.lean b/Mathlib/Control/Combinators.lean index f414787695265..b0aaad216354b 100644 --- a/Mathlib/Control/Combinators.lean +++ b/Mathlib/Control/Combinators.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Leonardo de Moura -/ +import Mathlib.Init /-! # Monad combinators, as in Haskell's Control.Monad. -/ diff --git a/Mathlib/Control/EquivFunctor.lean b/Mathlib/Control/EquivFunctor.lean index 05e6050b3e91e..ecbf36b36a8a5 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 diff --git a/Mathlib/Control/EquivFunctor/Instances.lean b/Mathlib/Control/EquivFunctor/Instances.lean index 87b89a8ea37f9..13987af2679b9 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 diff --git a/Mathlib/Control/Fold.lean b/Mathlib/Control/Fold.lean index 5d51cf1544185..71a4d437faaa3 100644 --- a/Mathlib/Control/Fold.lean +++ b/Mathlib/Control/Fold.lean @@ -315,7 +315,8 @@ theorem toList_spec (xs : t α) : toList xs = FreeMonoid.toList (foldMap FreeMon Function.comp_apply] theorem foldMap_map [Monoid γ] (f : α → β) (g : β → γ) (xs : t α) : - foldMap g (f <$> xs) = foldMap (g ∘ f) xs := by simp only [foldMap, traverse_map, Function.comp] + foldMap g (f <$> xs) = foldMap (g ∘ f) xs := by + simp only [foldMap, traverse_map, Function.comp_def] theorem foldl_toList (f : α → β → α) (xs : t β) (x : α) : foldl f x xs = List.foldl f x (toList xs) := by @@ -331,18 +332,19 @@ theorem foldr_toList (f : α → β → β) (xs : t α) (x : β) : theorem toList_map (f : α → β) (xs : t α) : toList (f <$> xs) = f <$> toList xs := by simp only [toList_spec, Free.map_eq_map, foldMap_hom, foldMap_map, FreeMonoid.ofList_toList, - FreeMonoid.map_of, (· ∘ ·)] + FreeMonoid.map_of, Function.comp_def] @[simp] theorem foldl_map (g : β → γ) (f : α → γ → α) (a : α) (l : t β) : foldl f a (g <$> l) = foldl (fun x y => f x (g y)) a l := by #adaptation_note /-- nightly-2024-03-16: simp was simp only [foldl, foldMap_map, (· ∘ ·), flip] -/ - simp only [foldl, foldMap_map, (· ∘ ·), Function.flip_def] + simp only [foldl, foldMap_map, Function.comp_def, Function.flip_def] @[simp] theorem foldr_map (g : β → γ) (f : γ → α → α) (a : α) (l : t β) : - foldr f a (g <$> l) = foldr (f ∘ g) a l := by simp only [foldr, foldMap_map, (· ∘ ·), flip] + foldr f a (g <$> l) = foldr (f ∘ g) a l := by + simp only [foldr, foldMap_map, Function.comp_def, flip] @[simp] theorem toList_eq_self {xs : List α} : toList xs = xs := by @@ -357,9 +359,9 @@ theorem length_toList {xs : t α} : length xs = List.length (toList xs) := by generalize toList xs = ys rw [← Nat.add_zero ys.length] generalize 0 = n - induction' ys with _ _ ih generalizing n - · simp - · simp_arith [ih] + induction ys generalizing n with + | nil => simp + | cons _ _ ih => simp_arith [ih] variable {m : Type u → Type u} [Monad m] [LawfulMonad m] @@ -382,11 +384,12 @@ theorem foldlm_map (g : β → γ) (f : α → γ → m α) (a : α) (l : t β) foldlm f a (g <$> l) = foldlm (fun x y => f x (g y)) a l := by #adaptation_note /-- nightly-2024-03-16: simp was simp only [foldlm, foldMap_map, (· ∘ ·), flip] -/ - simp only [foldlm, foldMap_map, (· ∘ ·), Function.flip_def] + simp only [foldlm, foldMap_map, Function.comp_def, Function.flip_def] @[simp] theorem foldrm_map (g : β → γ) (f : γ → α → m α) (a : α) (l : t β) : - foldrm f a (g <$> l) = foldrm (f ∘ g) a l := by simp only [foldrm, foldMap_map, (· ∘ ·), flip] + foldrm f a (g <$> l) = foldrm (f ∘ g) a l := by + simp only [foldrm, foldMap_map, Function.comp_def, flip] end Equalities diff --git a/Mathlib/Control/Functor.lean b/Mathlib/Control/Functor.lean index 8aad2ceefbc06..305a88d2cc83f 100644 --- a/Mathlib/Control/Functor.lean +++ b/Mathlib/Control/Functor.lean @@ -3,8 +3,8 @@ 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.Init.Set +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 b2d82ecaeea4d..993d066487aa9 100644 --- a/Mathlib/Control/Functor/Multivariate.lean +++ b/Mathlib/Control/Functor/Multivariate.lean @@ -213,7 +213,7 @@ theorem LiftR_RelLast_iff (x y : F (α ::: β)) : -- Porting note: proof was -- rw [MvFunctor.map_map, MvFunctor.map_map, (· ⊚ ·), (· ⊚ ·)] -- congr <;> ext i ⟨x, _⟩ <;> cases i <;> rfl - suffices (fun i t => t.val.fst) = ((fun i x => (MvFunctor.f' rr n α i x).val.fst)) + suffices (fun i t => t.val.fst) = ((fun i x => (MvFunctor.f' rr n α i x).val.fst)) ∧ (fun i t => t.val.snd) = ((fun i x => (MvFunctor.f' rr n α i x).val.snd)) by rw [this.1, this.2] constructor <;> ext i ⟨x, _⟩ <;> cases i <;> rfl 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 82375eb1c0037..f22207cffe5c1 100644 --- a/Mathlib/Control/LawfulFix.lean +++ b/Mathlib/Control/LawfulFix.lean @@ -35,11 +35,12 @@ halting problem. Instead, this requirement is limited to only functions that are sense of `ω`-complete partial orders, which excludes the example because it is not monotone (making the input argument less defined can make `f` more defined). -/ class LawfulFix (α : Type*) [OmegaCompletePartialOrder α] extends Fix α where - fix_eq : ∀ {f : α →o α}, Continuous f → Fix.fix f = f (Fix.fix f) + fix_eq : ∀ {f : α → α}, ωScottContinuous f → Fix.fix f = f (Fix.fix f) +@[deprecated LawfulFix.fix_eq (since := "2024-08-26")] theorem LawfulFix.fix_eq' {α} [OmegaCompletePartialOrder α] [LawfulFix α] {f : α → α} - (hf : Continuous' f) : Fix.fix f = f (Fix.fix f) := - LawfulFix.fix_eq (hf.to_bundled _) + (hf : ωScottContinuous f) : Fix.fix f = f (Fix.fix f) := + LawfulFix.fix_eq hf namespace Part @@ -79,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₀ @@ -107,7 +108,7 @@ def approxChain : Chain ((a : _) → Part <| β a) := ⟨approx f, approx_mono f⟩ theorem le_f_of_mem_approx {x} : x ∈ approxChain f → x ≤ f x := by - simp only [(· ∈ ·), forall_exists_index] + simp only [Membership.mem, forall_exists_index] rintro i rfl apply approx_mono' @@ -157,8 +158,30 @@ theorem fix_le {X : (a : _) → Part <| β a} (hX : f X ≤ X) : Part.fix f ≤ · apply f.monotone i_ih · apply hX +variable {g : ((a : _) → Part <| β a) → (a : _) → Part <| β a} + +theorem fix_eq_ωSup_of_ωScottContinuous (hc : ωScottContinuous g) : Part.fix g = + ωSup (approxChain (⟨g,hc.monotone⟩ : ((a : _) → Part <| β a) →o (a : _) → Part <| β a)) := by + rw [← fix_eq_ωSup] + rfl + +theorem fix_eq_of_ωScottContinuous (hc : ωScottContinuous g) : + Part.fix g = g (Part.fix g) := by + rw [fix_eq_ωSup_of_ωScottContinuous hc, hc.map_ωSup] + apply le_antisymm + · apply ωSup_le_ωSup_of_le _ + intro i + exists i + intro x + apply le_f_of_mem_approx _ ⟨i, rfl⟩ + · apply ωSup_le_ωSup_of_le _ + intro i + exists i.succ + variable {f} +set_option linter.deprecated false in +@[deprecated fix_eq_of_ωScottContinuous (since := "2024-08-26")] theorem fix_eq (hc : Continuous f) : Part.fix f = f (Part.fix f) := by rw [fix_eq_ωSup f, hc] apply le_antisymm @@ -182,6 +205,14 @@ def toUnitMono (f : Part α →o Part α) : (Unit → Part α) →o Unit → Par toFun x u := f (x u) monotone' x y (h : x ≤ y) u := f.monotone <| h u +theorem ωScottContinuous_toUnitMono (f : Part α → Part α) (hc : ωScottContinuous f) : + ωScottContinuous (toUnitMono ⟨f,hc.monotone⟩) := .of_map_ωSup_of_orderHom fun _ => by + ext ⟨⟩ : 1 + dsimp [OmegaCompletePartialOrder.ωSup] + erw [hc.map_ωSup, Chain.map_comp]; rfl + +set_option linter.deprecated false in +@[deprecated ωScottContinuous_toUnitMono (since := "2024-08-26")] theorem to_unit_cont (f : Part α →o Part α) (hc : Continuous f) : Continuous (toUnitMono f) | _ => by ext ⟨⟩ : 1 @@ -189,8 +220,8 @@ theorem to_unit_cont (f : Part α →o Part α) (hc : Continuous f) : Continuous erw [hc, Chain.map_comp]; rfl instance lawfulFix : LawfulFix (Part α) := - ⟨fun {f : Part α →o Part α} hc ↦ show Part.fix (toUnitMono f) () = _ by - rw [Part.fix_eq (to_unit_cont f hc)]; rfl⟩ + ⟨fun {f : Part α → Part α} hc ↦ show Part.fix (toUnitMono ⟨f,hc.monotone⟩) () = _ by + rw [Part.fix_eq_of_ωScottContinuous (ωScottContinuous_toUnitMono f hc)]; rfl⟩ end Part @@ -199,7 +230,7 @@ open Sigma namespace Pi instance lawfulFix {β} : LawfulFix (α → Part β) := - ⟨fun {_f} ↦ Part.fix_eq⟩ + ⟨fun {_f} ↦ Part.fix_eq_of_ωScottContinuous⟩ variable {γ : ∀ a : α, β a → Type*} @@ -225,12 +256,32 @@ variable [(x y : _) → OmegaCompletePartialOrder <| γ x y] open OmegaCompletePartialOrder.Chain +theorem ωScottContinuous_curry : + ωScottContinuous (monotoneCurry α β γ) := + ωScottContinuous.of_map_ωSup_of_orderHom fun c ↦ by + ext x y + dsimp [curry, ωSup] + rw [map_comp, map_comp] + rfl + +set_option linter.deprecated false in +@[deprecated ωScottContinuous_curry (since := "2024-08-26")] theorem continuous_curry : Continuous <| monotoneCurry α β γ := fun c ↦ by ext x y dsimp [curry, ωSup] rw [map_comp, map_comp] rfl +theorem ωScottContinuous_uncurry : + ωScottContinuous (monotoneUncurry α β γ) := + .of_map_ωSup_of_orderHom fun c ↦ by + ext ⟨x, y⟩ + dsimp [uncurry, ωSup] + rw [map_comp, map_comp] + rfl + +set_option linter.deprecated false in +@[deprecated ωScottContinuous_uncurry (since := "2024-08-26")] theorem continuous_uncurry : Continuous <| monotoneUncurry α β γ := fun c ↦ by ext ⟨x, y⟩ dsimp [uncurry, ωSup] @@ -248,9 +299,18 @@ variable [∀ x y, OmegaCompletePartialOrder <| γ x y] section Curry -variable {f : ((x : _) → (y : β x) → γ x y) →o (x : _) → (y : β x) → γ x y} +variable {f : (∀ a b, γ a b) → ∀ a b, γ a b} + +theorem uncurry_curry_ωScottContinuous (hc : ωScottContinuous f) : + ωScottContinuous <| (monotoneUncurry α β γ).comp <| + (⟨f,hc.monotone⟩ : ((x : _) → (y : β x) → γ x y) →o (x : _) → (y : β x) → γ x y).comp <| + monotoneCurry α β γ := + (ωScottContinuous_uncurry _ _ _).comp (hc.comp (ωScottContinuous_curry _ _ _)) -theorem uncurry_curry_continuous (hc : Continuous f) : +set_option linter.deprecated false in +@[deprecated uncurry_curry_ωScottContinuous (since := "2024-08-26")] +theorem uncurry_curry_continuous {f : ((x : _) → (y : β x) → γ x y) →o (x : _) → (y : β x) → γ x y} + (hc : Continuous f) : Continuous <| (monotoneUncurry α β γ).comp <| f.comp <| monotoneCurry α β γ := continuous_comp _ _ (continuous_comp _ _ (continuous_curry _ _ _) hc) (continuous_uncurry _ _ _) @@ -260,7 +320,7 @@ instance lawfulFix' [LawfulFix <| (x : Sigma β) → γ x.1 x.2] : LawfulFix ((x y : _) → γ x y) where fix_eq {_f} hc := by dsimp [fix] - conv_lhs => erw [LawfulFix.fix_eq (uncurry_curry_continuous hc)] + conv_lhs => erw [LawfulFix.fix_eq (uncurry_curry_ωScottContinuous hc)] rfl end Pi 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 05198d61db646..c83ecbaba193b 100644 --- a/Mathlib/Control/Random.lean +++ b/Mathlib/Control/Random.lean @@ -28,18 +28,18 @@ 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) -/-- A monad to generate random objects using the generator type `g`. -/ +/-- A monad to generate random objects using the generator type `g`. -/ abbrev RandG (g : Type) := RandGT g Id /-- A monad transformer to generate random objects using the generator type `StdGen`. `RandT m α` should be thought of a random value in `m α`. -/ abbrev RandT := RandGT StdGen -/-- A monad to generate random objects using the generator type `StdGen`. -/ +/-- A monad to generate random objects using the generator type `StdGen`. -/ abbrev Rand := RandG StdGen instance [MonadLift m n] : MonadLiftT (RandGT g m) (RandGT g n) where diff --git a/Mathlib/Control/Traversable/Basic.lean b/Mathlib/Control/Traversable/Basic.lean index 6c338a28da53e..eff2d5afd7056 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 @@ -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. -/ @@ -221,7 +221,7 @@ satisfy a naturality condition with respect to applicative transformations. -/ class LawfulTraversable (t : Type u → Type u) [Traversable t] extends LawfulFunctor t : Prop where - /-- `traverse` plays well with `pure` of the identity monad-/ + /-- `traverse` plays well with `pure` of the identity monad -/ id_traverse : ∀ {α} (x : t α), traverse (pure : α → Id α) x = x /-- `traverse` plays well with composition of applicative functors. -/ comp_traverse : @@ -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 6b7276bafe9a7..db32b26b14bb2 100644 --- a/Mathlib/Control/Traversable/Equiv.lean +++ b/Mathlib/Control/Traversable/Equiv.lean @@ -43,7 +43,7 @@ protected def map {α β : Type u} (f : α → β) (x : t' α) : t' β := eqv β <| map f ((eqv α).symm x) /-- The function `Equiv.map` transfers the functoriality of `t` to -`t'` using the equivalences `eqv`. -/ +`t'` using the equivalences `eqv`. -/ protected def functor : Functor t' where map := Equiv.map eqv variable [LawfulFunctor t] @@ -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..7b98b4bf635c3 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 @@ -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 a18277cf38b2e..2482e0095fe06 100644 --- a/Mathlib/Control/ULift.lean +++ b/Mathlib/Control/ULift.lean @@ -1,9 +1,10 @@ /- -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 /-! # Monadic instances for `ULift` and `PLift` @@ -77,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/Data/Analysis/Topology.lean b/Mathlib/Data/Analysis/Topology.lean index f8db5f20dd999..6da9c694593d9 100644 --- a/Mathlib/Data/Analysis/Topology.lean +++ b/Mathlib/Data/Analysis/Topology.lean @@ -208,7 +208,7 @@ end Ctop.Realizer /-- A `LocallyFinite.Realizer F f` is a realization that `f` is locally finite, namely it is a choice of open sets from the basis of `F` such that they intersect only finitely many of the values -of `f`. -/ +of `f`. -/ structure LocallyFinite.Realizer [TopologicalSpace α] (F : Ctop.Realizer α) (f : β → Set α) where bas : ∀ a, { s // a ∈ F.F s } sets : ∀ x : α, Fintype { i | (f i ∩ F.F (bas x)).Nonempty } @@ -237,7 +237,7 @@ instance [TopologicalSpace α] [Finite β] (F : Ctop.Realizer α) (f : β → Se (locallyFinite_iff_exists_realizer _).1 <| locallyFinite_of_finite _ /-- A `Compact.Realizer s` is a realization that `s` is compact, namely it is a -choice of finite open covers for each set family covering `s`. -/ +choice of finite open covers for each set family covering `s`. -/ def Compact.Realizer [TopologicalSpace α] (s : Set α) := ∀ {f : Filter α} (F : f.Realizer) (x : F.σ), f ≠ ⊥ → F.F x ⊆ s → { a // a ∈ s ∧ 𝓝 a ⊓ f ≠ ⊥ } diff --git a/Mathlib/Data/Array/Defs.lean b/Mathlib/Data/Array/Defs.lean index f3d25eac2c584..2e86c181ba220 100644 --- a/Mathlib/Data/Array/Defs.lean +++ b/Mathlib/Data/Array/Defs.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Arthur Paulino, Floris van Doorn -/ +import Mathlib.Init /-! ## Definitions on Arrays @@ -31,3 +32,5 @@ where cyclicPermuteAux : Array α → List Nat → α → Nat → Array α /-- Permute the array using a list of cycles. -/ def permute! [Inhabited α] (a : Array α) (ls : List (List Nat)) : Array α := ls.foldl (init := a) (·.cyclicPermute! ·) + +end Array diff --git a/Mathlib/Data/Array/ExtractLemmas.lean b/Mathlib/Data/Array/ExtractLemmas.lean index 53aadf1b86929..b27b5245af41d 100644 --- a/Mathlib/Data/Array/ExtractLemmas.lean +++ b/Mathlib/Data/Array/ExtractLemmas.lean @@ -3,6 +3,7 @@ Copyright (c) 2024 Jiecheng Zhao. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jiecheng Zhao -/ +import Mathlib.Init /-! # Lemmas about `Array.extract` @@ -26,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 @@ -34,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 @@ -49,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/Bool/AllAny.lean b/Mathlib/Data/Bool/AllAny.lean index 2e419d830a5b4..49c4ca9337f53 100644 --- a/Mathlib/Data/Bool/AllAny.lean +++ b/Mathlib/Data/Bool/AllAny.lean @@ -3,7 +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.Data.List.Basic +import Batteries.Tactic.Alias +import Mathlib.Tactic.TypeStar /-! # Boolean quantifiers @@ -17,26 +18,16 @@ variable {α : Type*} {p : α → Prop} [DecidablePred p] {l : List α} {a : α} namespace List --- Porting note: in Batteries - -theorem all_iff_forall {p : α → Bool} : all l p ↔ ∀ a ∈ l, p a := by - induction' l with a l ih - · exact iff_of_true rfl (forall_mem_nil _) - simp only [all_cons, Bool.and_eq_true_iff, ih, forall_mem_cons] +@[deprecated (since := "2024-08-10")] alias all_iff_forall := all_eq_true theorem all_iff_forall_prop : (all l fun a => p a) ↔ ∀ a ∈ l, p a := by - simp only [all_iff_forall, decide_eq_true_iff] - --- Porting note: in Batteries + simp -theorem any_iff_exists {p : α → Bool} : any l p ↔ ∃ a ∈ l, p a := by - induction' l with a l ih - · exact iff_of_false Bool.false_ne_true (not_exists_mem_nil _) - simp only [any_cons, Bool.or_eq_true_iff, ih, exists_mem_cons_iff] +@[deprecated (since := "2024-08-10")] alias any_iff_exists := any_eq_true -theorem any_iff_exists_prop : (any l fun a => p a) ↔ ∃ a ∈ l, p a := by simp [any_iff_exists] +theorem any_iff_exists_prop : (any l fun a => p a) ↔ ∃ a ∈ l, p a := by simp theorem any_of_mem {p : α → Bool} (h₁ : a ∈ l) (h₂ : p a) : any l p := - any_iff_exists.2 ⟨_, h₁, h₂⟩ + any_eq_true.2 ⟨_, h₁, h₂⟩ end List diff --git a/Mathlib/Data/Bool/Basic.lean b/Mathlib/Data/Bool/Basic.lean index da700043cf44d..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 @@ -120,21 +119,6 @@ alias of_decide_iff := decide_eq_true_iff theorem dichotomy (b : Bool) : b = false ∨ b = true := by cases b <;> simp -theorem forall_bool' {p : Bool → Prop} (b : Bool) : (∀ x, p x) ↔ p b ∧ p !b := - ⟨fun h ↦ ⟨h _, h _⟩, fun ⟨h₁, h₂⟩ x ↦ by cases b <;> cases x <;> assumption⟩ - -@[simp] -theorem forall_bool {p : Bool → Prop} : (∀ b, p b) ↔ p false ∧ p true := - forall_bool' false - -theorem exists_bool' {p : Bool → Prop} (b : Bool) : (∃ x, p x) ↔ p b ∨ p !b := - ⟨fun ⟨x, hx⟩ ↦ by cases x <;> cases b <;> first | exact .inl ‹_› | exact .inr ‹_›, - fun h ↦ by cases h <;> exact ⟨_, ‹_›⟩⟩ - -@[simp] -theorem exists_bool {p : Bool → Prop} : (∃ b, p b) ↔ p false ∨ p true := - exists_bool' false - theorem not_ne_id : not ≠ id := fun h ↦ false_ne_true <| congrFun h true @[deprecated (since := "2024-06-07")] alias eq_true_of_ne_false := eq_true_of_ne_false @@ -181,7 +165,7 @@ attribute [simp] xor_assoc theorem xor_iff_ne : ∀ {x y : Bool}, xor x y = true ↔ x ≠ y := by decide -/-! ### De Morgan's laws for booleans-/ +/-! ### De Morgan's laws for booleans -/ instance linearOrder : LinearOrder Bool where le_refl := by decide @@ -221,8 +205,8 @@ def ofNat (n : Nat) : Bool := @[simp] lemma toNat_beq_zero (b : Bool) : (b.toNat == 0) = !b := by cases b <;> rfl @[simp] lemma toNat_bne_zero (b : Bool) : (b.toNat != 0) = b := by simp [bne] -@[simp] lemma toNat_beq_one (b : Bool) : (b.toNat == 1) = b := by cases b <;> rfl -@[simp] lemma toNat_bne_one (b : Bool) : (b.toNat != 1) = !b := by simp [bne] +@[simp] lemma toNat_beq_one (b : Bool) : (b.toNat == 1) = b := by cases b <;> rfl +@[simp] lemma toNat_bne_one (b : Bool) : (b.toNat != 1) = !b := by simp [bne] theorem ofNat_le_ofNat {n m : Nat} (h : n ≤ m) : ofNat n ≤ ofNat m := by simp only [ofNat, ne_eq, _root_.decide_not] @@ -243,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/ByteArray.lean b/Mathlib/Data/ByteArray.lean index 8f5407658504d..c199be41b3f7c 100644 --- a/Mathlib/Data/ByteArray.lean +++ b/Mathlib/Data/ByteArray.lean @@ -3,16 +3,23 @@ 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.Data.ByteSubarray -- Only needed for the deprecation. +import Mathlib.Init /-! # Main result Introduce main properties of `Up` (well-ordered relation for "upwards" induction on `ℕ`) and of `ByteArray` + +This entire file has been deprecated on 2024-08-19 in favour of `ByteSubarray` in Batteries. -/ +set_option linter.deprecated false + namespace Nat /-- A well-ordered relation for "upwards" induction on the natural numbers up to some bound `ub`. -/ +@[deprecated (since := "2024-08-19")] def Up (ub a i : Nat) := i < a ∧ i < ub theorem Up.next {ub i} (h : i < ub) : Up ub (i+1) i := ⟨Nat.lt_succ_self _, h⟩ @@ -21,11 +28,13 @@ theorem Up.WF (ub) : WellFounded (Up ub) := Subrelation.wf (h₂ := (measure (ub - ·)).wf) fun ⟨ia, iu⟩ ↦ Nat.sub_lt_sub_left iu ia /-- A well-ordered relation for "upwards" induction on the natural numbers up to some bound `ub`. -/ +@[deprecated (since := "2024-08-19")] def upRel (ub : Nat) : WellFoundedRelation Nat := ⟨Up ub, Up.WF ub⟩ end Nat /-- A terminal byte slice, a suffix of a byte array. -/ +@[deprecated (since := "2024-08-19")] structure ByteSliceT := (arr : ByteArray) (off : Nat) namespace ByteSliceT @@ -42,6 +51,7 @@ end ByteSliceT def ByteArray.toSliceT (arr : ByteArray) : ByteSliceT := ⟨arr, 0⟩ /-- A byte slice, given by a backing byte array, and an offset and length. -/ +@[deprecated Batteries.ByteSubarray (since := "2024-08-19")] structure ByteSlice := (arr : ByteArray) (off len : Nat) namespace ByteSlice @@ -56,6 +66,7 @@ def toArray : ByteSlice → ByteArray universe u v /-- The inner loop of the `forIn` implementation for byte slices. -/ +@[deprecated (since := "2024-08-19")] def forIn.loop {m : Type u → Type v} {β : Type u} [Monad m] (f : UInt8 → β → m (ForInStep β)) (arr : ByteArray) (off _end : Nat) (i : Nat) (b : β) : m β := if h : i < _end then do @@ -63,8 +74,8 @@ def forIn.loop {m : Type u → Type v} {β : Type u} [Monad m] (f : UInt8 → β | ForInStep.done b => pure b | ForInStep.yield b => have := Nat.Up.next h; loop f arr off _end (i+1) b else pure b -termination_by _end - i +@[deprecated (since := "2024-08-19")] instance {m : Type u → Type v} : ForIn m ByteSlice UInt8 := ⟨fun ⟨arr, off, len⟩ b f ↦ forIn.loop f arr off (off + len) off b⟩ @@ -77,19 +88,6 @@ def ByteSliceT.toSlice : ByteSliceT → ByteSlice /-- Convert a byte array into a byte slice. -/ def ByteArray.toSlice (arr : ByteArray) : ByteSlice := ⟨arr, 0, arr.size⟩ -/-- Convert a string of assumed-ASCII characters into a byte array. -(If any characters are non-ASCII they will be reduced modulo 256.) -/ -def String.toAsciiByteArray (s : String) : ByteArray := - let rec loop (p : Pos) (out : ByteArray) : ByteArray := - if h : s.atEnd p then out else - let c := s.get p - have : utf8ByteSize s - (next s p).byteIdx < utf8ByteSize s - p.byteIdx := - Nat.sub_lt_sub_left (Nat.lt_of_not_le <| mt decide_eq_true h) - (Nat.lt_add_of_pos_right (Char.utf8Size_pos _)) - loop (s.next p) (out.push c.toUInt8) - termination_by utf8ByteSize s - p.byteIdx - loop 0 ByteArray.empty - /-- Convert a byte slice into a string. This does not handle non-ASCII characters correctly: every byte will become a unicode character with codepoint < 256. -/ def ByteSlice.toString (bs : ByteSlice) : String := Id.run do diff --git a/Mathlib/Data/Complex/Abs.lean b/Mathlib/Data/Complex/Abs.lean index 3fdd10b7dd853..8ca8f1fbe0ea6 100644 --- a/Mathlib/Data/Complex/Abs.lean +++ b/Mathlib/Data/Complex/Abs.lean @@ -202,12 +202,12 @@ theorem abs_le_sqrt_two_mul_max (z : ℂ) : Complex.abs z ≤ Real.sqrt 2 * max theorem abs_re_div_abs_le_one (z : ℂ) : |z.re / Complex.abs z| ≤ 1 := if hz : z = 0 then by simp [hz, zero_le_one] else by simp_rw [_root_.abs_div, abs_abs, - div_le_iff (AbsoluteValue.pos Complex.abs hz), one_mul, abs_re_le_abs] + div_le_iff₀ (AbsoluteValue.pos Complex.abs hz), one_mul, abs_re_le_abs] theorem abs_im_div_abs_le_one (z : ℂ) : |z.im / Complex.abs z| ≤ 1 := if hz : z = 0 then by simp [hz, zero_le_one] else by simp_rw [_root_.abs_div, abs_abs, - div_le_iff (AbsoluteValue.pos Complex.abs hz), one_mul, abs_im_le_abs] + div_le_iff₀ (AbsoluteValue.pos Complex.abs hz), one_mul, abs_im_le_abs] @[simp, norm_cast] lemma abs_intCast (n : ℤ) : abs n = |↑n| := by rw [← ofReal_intCast, abs_ofReal] @@ -232,7 +232,7 @@ theorem isCauSeq_re (f : CauSeq ℂ Complex.abs) : IsCauSeq abs' fun n => (f n). theorem isCauSeq_im (f : CauSeq ℂ Complex.abs) : IsCauSeq abs' fun n => (f n).im := fun ε ε0 => (f.cauchy ε0).imp fun i H j ij ↦ by - simpa only [← ofReal_sub, abs_ofReal, sub_re] using (abs_im_le_abs _).trans_lt $ H _ ij + simpa only [← ofReal_sub, abs_ofReal, sub_re] using (abs_im_le_abs _).trans_lt <| H _ ij /-- The real part of a complex Cauchy sequence, as a real Cauchy sequence. -/ noncomputable def cauSeqRe (f : CauSeq ℂ Complex.abs) : CauSeq ℝ abs' := diff --git a/Mathlib/Data/Complex/Basic.lean b/Mathlib/Data/Complex/Basic.lean index 6483469eea3bc..bb39cc9638ee7 100644 --- a/Mathlib/Data/Complex/Basic.lean +++ b/Mathlib/Data/Complex/Basic.lean @@ -329,8 +329,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] @@ -442,6 +441,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 @@ -628,6 +636,28 @@ def ofReal : ℝ →+* ℂ where theorem ofReal_eq_coe (r : ℝ) : ofReal r = r := rfl +variable {α : Type*} + +@[simp] lemma ofReal_comp_add (f g : α → ℝ) : ofReal' ∘ (f + g) = ofReal' ∘ f + ofReal' ∘ g := + map_comp_add ofReal .. + +@[simp] lemma ofReal_comp_sub (f g : α → ℝ) : ofReal' ∘ (f - g) = ofReal' ∘ f - ofReal' ∘ g := + map_comp_sub ofReal .. + +@[simp] lemma ofReal_comp_neg (f : α → ℝ) : ofReal' ∘ (-f) = -(ofReal' ∘ f) := map_comp_neg ofReal _ + +lemma ofReal_comp_nsmul (n : ℕ) (f : α → ℝ) : ofReal' ∘ (n • f) = n • (ofReal' ∘ f) := + map_comp_nsmul ofReal .. + +lemma ofReal_comp_zsmul (n : ℤ) (f : α → ℝ) : ofReal' ∘ (n • f) = n • (ofReal' ∘ f) := + map_comp_zsmul ofReal .. + +@[simp] lemma ofReal_comp_mul (f g : α → ℝ) : ofReal' ∘ (f * g) = ofReal' ∘ f * ofReal' ∘ g := + map_comp_mul ofReal .. + +@[simp] lemma ofReal_comp_pow (f : α → ℝ) (n : ℕ) : ofReal' ∘ (f ^ n) = (ofReal' ∘ f) ^ n := + map_comp_pow ofReal .. + @[simp] theorem I_sq : I ^ 2 = -1 := by rw [sq, I_mul_I] diff --git a/Mathlib/Data/Complex/BigOperators.lean b/Mathlib/Data/Complex/BigOperators.lean index 43c85d7750bfa..df65eec1fe310 100644 --- a/Mathlib/Data/Complex/BigOperators.lean +++ b/Mathlib/Data/Complex/BigOperators.lean @@ -3,14 +3,16 @@ 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 α) @@ -23,12 +25,45 @@ theorem ofReal_prod (f : α → ℝ) : ((∏ i ∈ s, f i : ℝ) : ℂ) = ∏ i theorem ofReal_sum (f : α → ℝ) : ((∑ i ∈ s, f i : ℝ) : ℂ) = ∑ i ∈ s, (f i : ℂ) := map_sum ofReal _ _ +@[simp, norm_cast] +lemma ofReal_expect (f : α → ℝ) : (𝔼 i ∈ s, f i : ℝ) = 𝔼 i ∈ s, (f i : ℂ) := + map_expect ofReal .. + +@[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/Exponential.lean b/Mathlib/Data/Complex/Exponential.lean index 9e9f187d59df4..e3fd8a0bac2f2 100644 --- a/Mathlib/Data/Complex/Exponential.lean +++ b/Mathlib/Data/Complex/Exponential.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes, Abhimanyu Pallavi Sudhir -/ import Mathlib.Algebra.Order.CauSeq.BigOperators -import Mathlib.Algebra.Star.Order +import Mathlib.Algebra.Order.Star.Basic import Mathlib.Data.Complex.Abs import Mathlib.Data.Complex.BigOperators import Mathlib.Data.Nat.Choose.Sum @@ -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 @@ -186,6 +186,7 @@ theorem exp_add : exp (x + y) = exp x * exp y := by -- Porting note (#11445): new definition /-- the exponential function as a monoid hom from `Multiplicative ℂ` to `ℂ` -/ +@[simps] noncomputable def expMonoidHom : MonoidHom (Multiplicative ℂ) ℂ := { toFun := fun z => exp (Multiplicative.toAdd z), map_one' := by simp, @@ -210,7 +211,7 @@ theorem exp_nat_mul (x : ℂ) : ∀ n : ℕ, exp (n * x) = exp x ^ n @[simp] theorem exp_ne_zero : exp x ≠ 0 := fun h => - zero_ne_one <| by rw [← exp_zero, ← add_neg_cancel x, exp_add, h]; simp + zero_ne_one (α := ℂ) <| by rw [← exp_zero, ← add_neg_cancel x, exp_add, h]; simp theorem exp_neg : exp (-x) = (exp x)⁻¹ := by rw [← mul_right_inj' (exp_ne_zero x), ← exp_add]; simp [mul_inv_cancel₀ (exp_ne_zero x)] @@ -689,6 +690,7 @@ nonrec theorem exp_add : exp (x + y) = exp x * exp y := by simp [exp_add, exp] -- Porting note (#11445): new definition /-- the exponential function as a monoid hom from `Multiplicative ℝ` to `ℝ` -/ +@[simps] noncomputable def expMonoidHom : MonoidHom (Multiplicative ℝ) ℝ := { toFun := fun x => exp (Multiplicative.toAdd x), map_one' := by simp, @@ -1108,7 +1110,7 @@ theorem exp_bound {x : ℂ} (hx : abs x ≤ 1) {n : ℕ} (hn : 0 < n) : simp_rw [map_mul, map_pow, map_div₀, abs_natCast] gcongr rw [abv_pow abs] - exact pow_le_one _ (abs.nonneg _) hx + exact pow_le_one₀ (abs.nonneg _) hx _ = abs x ^ n * ∑ m ∈ (range j).filter fun k => n ≤ k, (1 / m.factorial : ℝ) := by simp [abs_mul, abv_pow abs, abs_div, ← mul_sum] _ ≤ abs x ^ n * (n.succ * (n.factorial * n : ℝ)⁻¹) := by @@ -1332,9 +1334,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 @@ -1357,7 +1359,7 @@ theorem sin_pos_of_pos_of_le_one {x : ℝ} (hx0 : 0 < x) (hx : x ≤ 1) : 0 < si sub_le_comm.1 (abs_sub_le_iff.1 (sin_bound (by rwa [_root_.abs_of_nonneg (le_of_lt hx0)]))).2 theorem sin_pos_of_pos_of_le_two {x : ℝ} (hx0 : 0 < x) (hx : x ≤ 2) : 0 < sin x := - have : x / 2 ≤ 1 := (div_le_iff (by norm_num)).mpr (by simpa) + have : x / 2 ≤ 1 := (div_le_iff₀ (by norm_num)).mpr (by simpa) calc 0 < 2 * sin (x / 2) * cos (x / 2) := mul_pos (mul_pos (by norm_num) (sin_pos_of_pos_of_le_one (half_pos hx0) this)) @@ -1393,10 +1395,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 @@ -1410,7 +1413,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 6bcc28c3ae79b..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 @@ -45,13 +44,13 @@ instance (priority := 100) FiniteDimensional.complexToReal (E : Type*) [AddCommG theorem rank_real_of_complex (E : Type*) [AddCommGroup E] [Module ℂ E] : Module.rank ℝ E = 2 * Module.rank ℂ E := - Cardinal.lift_inj.1 <| by + Cardinal.lift_inj.{_,0}.1 <| by rw [← lift_rank_mul_lift_rank ℝ ℂ E, Complex.rank_real_complex'] 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 d79c2f4a80d70..e8fc5c5c392dc 100644 --- a/Mathlib/Data/Complex/Module.lean +++ b/Mathlib/Data/Complex/Module.lean @@ -291,7 +291,7 @@ def liftAux (I' : A) (hf : I' * I' = -1) : ℂ →ₐ[ℝ] A := congr 1 -- equate "real" and "imaginary" parts · let inst : SMulCommClass ℝ A A := by infer_instance -- Porting note: added - rw [smul_mul_smul, hf, smul_neg, ← Algebra.algebraMap_eq_smul_one, ← sub_eq_add_neg, ← + rw [smul_mul_smul_comm, hf, smul_neg, ← Algebra.algebraMap_eq_smul_one, ← sub_eq_add_neg, ← RingHom.map_mul, ← RingHom.map_sub] · rw [Algebra.smul_def, Algebra.smul_def, Algebra.smul_def, ← Algebra.right_comm _ x₂, ← mul_assoc, ← add_mul, ← RingHom.map_mul, ← RingHom.map_mul, ← RingHom.map_add] @@ -498,8 +498,8 @@ lemma imaginaryPart_ofReal (r : ℝ) : ℑ (r : ℂ) = 0 := by ext1; simp [imaginaryPart_apply_coe, conj_ofReal] lemma Complex.coe_realPart (z : ℂ) : (ℜ z : ℂ) = z.re := calc - (ℜ z : ℂ) = _ := by congrm (ℜ $((re_add_im z).symm)) - _ = z.re := by + (ℜ z : ℂ) = (↑(ℜ (↑z.re + ↑z.im * I))) := by congrm (ℜ $((re_add_im z).symm)) + _ = z.re := by rw [map_add, AddSubmonoid.coe_add, mul_comm, ← smul_eq_mul, realPart_I_smul] simp [conj_ofReal, ← two_mul] diff --git a/Mathlib/Data/Complex/Order.lean b/Mathlib/Data/Complex/Order.lean index f43e1f5666884..a9bc019f2b0bf 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 diff --git a/Mathlib/Data/Countable/Basic.lean b/Mathlib/Data/Countable/Basic.lean index c3c3559c29934..89694dd120b07 100644 --- a/Mathlib/Data/Countable/Basic.lean +++ b/Mathlib/Data/Countable/Basic.lean @@ -65,12 +65,19 @@ instance Sum.uncountable_inl [Uncountable α] : Uncountable (α ⊕ β) := instance Sum.uncountable_inr [Uncountable β] : Uncountable (α ⊕ β) := inr_injective.uncountable -instance [Countable α] : Countable (Option α) := - Countable.of_equiv _ (Equiv.optionEquivSumPUnit.{_, 0} α).symm +instance Option.instCountable [Countable α] : Countable (Option α) := + Countable.of_equiv _ (Equiv.optionEquivSumPUnit.{0, _} α).symm + +instance WithTop.instCountable [Countable α] : Countable (WithTop α) := Option.instCountable +instance WithBot.instCountable [Countable α] : Countable (WithBot α) := Option.instCountable +instance ENat.instCountable : Countable ℕ∞ := Option.instCountable instance Option.instUncountable [Uncountable α] : Uncountable (Option α) := Injective.uncountable fun _ _ ↦ Option.some_inj.1 +instance WithTop.instUncountable [Uncountable α] : Uncountable (WithTop α) := Option.instUncountable +instance WithBot.instUncountable [Uncountable α] : Uncountable (WithBot α) := Option.instUncountable + instance [Countable α] [Countable β] : Countable (α × β) := by rcases exists_injective_nat α with ⟨f, hf⟩ rcases exists_injective_nat β with ⟨g, hg⟩ @@ -123,7 +130,7 @@ instance [Finite α] [∀ a, Countable (π a)] : Countable (∀ a, π a) := by induction' n with n ihn · change Countable (Fin 0 → ℕ); infer_instance · haveI := ihn - exact Countable.of_equiv (ℕ × (Fin n → ℕ)) (Equiv.piFinSucc _ _).symm + exact Countable.of_equiv (ℕ × (Fin n → ℕ)) (Fin.consEquiv fun _ ↦ ℕ) rcases Finite.exists_equiv_fin α with ⟨n, ⟨e⟩⟩ have f := fun a => (nonempty_embedding_nat (π a)).some exact ((Embedding.piCongrRight f).trans (Equiv.piCongrLeft' _ e).toEmbedding).countable 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 2a240cc29359d..11111a2e35ca6 100644 --- a/Mathlib/Data/DFinsupp/Basic.lean +++ b/Mathlib/Data/DFinsupp/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: Johannes Hölzl, Kenny Lau -/ +import Mathlib.Algebra.BigOperators.GroupWithZero.Action import Mathlib.Algebra.BigOperators.GroupWithZero.Finset import Mathlib.Algebra.Group.Action.Prod import Mathlib.Algebra.Group.Submonoid.Membership @@ -11,7 +12,6 @@ import Mathlib.Algebra.Module.LinearMap.Defs import Mathlib.Data.Finset.Preimage import Mathlib.Data.Fintype.Quotient import Mathlib.Data.Set.Finite -import Mathlib.GroupTheory.GroupAction.BigOperators import Mathlib.Order.ConditionallyCompleteLattice.Basic /-! @@ -1300,7 +1300,7 @@ instance distribMulAction₂ [Monoid γ] [∀ i j, AddMonoid (δ i j)] variable [DecidableEq ι] -/-- The natural map between `Π₀ (i : Σ i, α i), δ i.1 i.2` and `Π₀ i (j : α i), δ i j`. -/ +/-- The natural map between `Π₀ (i : Σ i, α i), δ i.1 i.2` and `Π₀ i (j : α i), δ i j`. -/ def sigmaCurry [∀ i j, Zero (δ i j)] (f : Π₀ (i : Σ _, _), δ i.1 i.2) : Π₀ (i) (j), δ i j where toFun := fun i ↦ @@ -2093,3 +2093,5 @@ instance DFinsupp.infinite_of_right {ι : Sort _} {π : ι → Sort _} [∀ i, I DFinsupp.infinite_of_exists_right (Classical.arbitrary ι) end FiniteInfinite + +set_option linter.style.longFile 2200 diff --git a/Mathlib/Data/DFinsupp/Interval.lean b/Mathlib/Data/DFinsupp/Interval.lean index 460f8e07408e8..8588c90c87525 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 diff --git a/Mathlib/Data/DFinsupp/Lex.lean b/Mathlib/Data/DFinsupp/Lex.lean index 46b0543f7f7bc..b0c8d8ea0b694 100644 --- a/Mathlib/Data/DFinsupp/Lex.lean +++ b/Mathlib/Data/DFinsupp/Lex.lean @@ -60,10 +60,9 @@ theorem lex_lt_of_lt [∀ i, PartialOrder (α i)] (r) [IsStrictOrder ι r] {x y variable [LinearOrder ι] instance Lex.isStrictOrder [∀ i, PartialOrder (α i)] : - IsStrictOrder (Lex (Π₀ i, α i)) (· < ·) := - let i : IsStrictOrder (Lex (∀ i, α i)) (· < ·) := Pi.Lex.isStrictOrder - { irrefl := toLex.surjective.forall.2 fun _ ↦ @irrefl _ _ i.toIsIrrefl _ - trans := toLex.surjective.forall₃.2 fun _ _ _ ↦ @trans _ _ i.toIsTrans _ _ _ } + IsStrictOrder (Lex (Π₀ i, α i)) (· < ·) where + irrefl _ := lt_irrefl (α := Lex (∀ i, α i)) _ + trans _ _ _ := lt_trans (α := Lex (∀ i, α i)) /-- The partial order on `DFinsupp`s obtained by the lexicographic ordering. See `DFinsupp.Lex.linearOrder` for a proof that this partial order is in fact linear. -/ diff --git a/Mathlib/Data/DFinsupp/Notation.lean b/Mathlib/Data/DFinsupp/Notation.lean index 7da5e6203d43a..f4782385250a8 100644 --- a/Mathlib/Data/DFinsupp/Notation.lean +++ b/Mathlib/Data/DFinsupp/Notation.lean @@ -19,9 +19,7 @@ is correct. namespace DFinsupp -open Lean -open Lean.Parser -open Lean.Parser.Term +open Lean Parser Term attribute [term_parser] Finsupp.stxSingle₀ Finsupp.stxUpdate₀ diff --git a/Mathlib/Data/DFinsupp/Order.lean b/Mathlib/Data/DFinsupp/Order.lean index db1c8bc2bdd5f..ebb4970f7a3ce 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 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/Defs.lean b/Mathlib/Data/DList/Defs.lean index 30de15869b4ca..408fa448595bd 100644 --- a/Mathlib/Data/DList/Defs.lean +++ b/Mathlib/Data/DList/Defs.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura -/ import Batteries.Data.DList -import Mathlib.Tactic.Cases /-! # Difference list @@ -39,7 +38,7 @@ 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 - cases' l with app inv + obtain ⟨app, inv⟩ := l simp only [ofList, toList, mk.injEq] funext x rw [(inv x)] @@ -48,14 +47,13 @@ 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₂ := - show toList (DList.append l₁ l₂) = toList l₁ ++ toList l₂ by - cases' l₁ with _ l₁_invariant; cases' l₂; simp; rw [l₁_invariant] +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 - cases' l with _ l_invariant; simp; rw [l_invariant] + obtain ⟨_, l_invariant⟩ := l; simp; rw [l_invariant] end Batteries.DList diff --git a/Mathlib/Data/ENNReal/Basic.lean b/Mathlib/Data/ENNReal/Basic.lean index 4acf0165b1904..11fe99146aa06 100644 --- a/Mathlib/Data/ENNReal/Basic.lean +++ b/Mathlib/Data/ENNReal/Basic.lean @@ -186,8 +186,7 @@ protected def toReal (a : ℝ≥0∞) : Real := a.toNNReal /-- `ofReal x` returns `x` if it is nonnegative, `0` otherwise. -/ protected noncomputable def ofReal (r : Real) : ℝ≥0∞ := r.toNNReal -@[simp, norm_cast] -theorem toNNReal_coe : (r : ℝ≥0∞).toNNReal = r := rfl +@[simp, norm_cast] lemma toNNReal_coe (r : ℝ≥0) : (r : ℝ≥0∞).toNNReal = r := rfl @[simp] theorem coe_toNNReal : ∀ {a : ℝ≥0∞}, a ≠ ∞ → ↑a.toNNReal = a @@ -215,6 +214,8 @@ theorem ofReal_eq_coe_nnreal {x : ℝ} (h : 0 ≤ x) : ENNReal.ofReal x = ofNNReal ⟨x, h⟩ := (coe_nnreal_eq ⟨x, h⟩).symm +theorem ofNNReal_toNNReal (x : ℝ) : (Real.toNNReal x : ℝ≥0∞) = ENNReal.ofReal x := rfl + @[simp] theorem ofReal_coe_nnreal : ENNReal.ofReal p = p := (coe_nnreal_eq p).symm @[simp, norm_cast] theorem coe_zero : ↑(0 : ℝ≥0) = (0 : ℝ≥0∞) := rfl @@ -402,7 +403,7 @@ def neTopEquivNNReal : { a | a ≠ ∞ } ≃ ℝ≥0 where toFun x := ENNReal.toNNReal x invFun x := ⟨x, coe_ne_top⟩ left_inv := fun x => Subtype.eq <| coe_toNNReal x.2 - right_inv _ := toNNReal_coe + right_inv := toNNReal_coe theorem cinfi_ne_top [InfSet α] (f : ℝ≥0∞ → α) : ⨅ x : { x // x ≠ ∞ }, f x = ⨅ x : ℝ≥0, f x := Eq.symm <| neTopEquivNNReal.symm.surjective.iInf_congr _ fun _ => rfl @@ -471,6 +472,7 @@ theorem coe_natCast (n : ℕ) : ((n : ℝ≥0) : ℝ≥0∞) = n := rfl ofReal_natCast n @[simp] 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] theorem top_ne_natCast (n : ℕ) : ∞ ≠ n := WithTop.top_ne_natCast n @@ -709,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 f32953b91a158..19655b9e5fb17 100644 --- a/Mathlib/Data/ENNReal/Inv.lean +++ b/Mathlib/Data/ENNReal/Inv.lean @@ -97,6 +97,15 @@ protected theorem div_mul_cancel (h0 : a ≠ 0) (hI : a ≠ ∞) : b / a * a = b protected theorem mul_div_cancel' (h0 : a ≠ 0) (hI : a ≠ ∞) : a * (b / a) = b := by rw [mul_comm, ENNReal.div_mul_cancel h0 hI] +protected theorem mul_eq_left (ha : a ≠ 0) (h'a : a ≠ ∞) : a * b = a ↔ b = 1 := by + refine ⟨fun h ↦ ?_, fun h ↦ by rw [h, mul_one]⟩ + have : a * b * a⁻¹ = a * a⁻¹ := by rw [h] + rwa [mul_assoc, mul_comm b, ← mul_assoc, ENNReal.mul_inv_cancel ha h'a, one_mul] at this + +protected theorem mul_eq_right (ha : a ≠ 0) (h'a : a ≠ ∞) : b * a = a ↔ b = 1 := by + rw [mul_comm] + exact ENNReal.mul_eq_left ha h'a + -- Porting note: `simp only [div_eq_mul_inv, mul_comm, mul_assoc]` doesn't work in the following two protected theorem mul_comm_div : a / b * c = a * (c / b) := by simp only [div_eq_mul_inv, mul_right_comm, ← mul_assoc] @@ -119,7 +128,7 @@ theorem inv_lt_top {x : ℝ≥0∞} : x⁻¹ < ∞ ↔ 0 < x := by simp only [lt_top_iff_ne_top, inv_ne_top, pos_iff_ne_zero] theorem div_lt_top {x y : ℝ≥0∞} (h1 : x ≠ ∞) (h2 : y ≠ 0) : x / y < ∞ := - mul_lt_top h1 (inv_ne_top.mpr h2) + mul_lt_top h1.lt_top (inv_ne_top.mpr h2).lt_top @[simp] protected theorem inv_eq_zero : a⁻¹ = 0 ↔ a = ∞ := @@ -429,9 +438,7 @@ 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 @@ -458,7 +465,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 x => 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] } @@ -567,13 +574,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 @@ -594,5 +601,250 @@ 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 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]⟩ + 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/Operations.lean b/Mathlib/Data/ENNReal/Operations.lean index 9f5df7b047487..473c3d6c65d78 100644 --- a/Mathlib/Data/ENNReal/Operations.lean +++ b/Mathlib/Data/ENNReal/Operations.lean @@ -5,6 +5,7 @@ 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 /-! @@ -186,9 +187,8 @@ theorem top_pow {n : ℕ} (n_pos : 0 < n) : (∞ : ℝ≥0∞) ^ n = ∞ := With 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 - -theorem mul_ne_top : a ≠ ∞ → b ≠ ∞ → a * b ≠ ∞ := by simpa only [lt_top_iff_ne_top] using mul_lt_top +theorem mul_lt_top : a < ∞ → b < ∞ → a * b < ∞ := WithTop.mul_lt_top +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 < ∞ := lt_top_iff_ne_top.2 fun ha => h <| mul_eq_top.2 (Or.inr ⟨ha, hb⟩) @@ -202,7 +202,7 @@ theorem mul_lt_top_iff {a b : ℝ≥0∞} : a * b < ∞ ↔ a < ∞ ∧ b < ∞ rw [← or_assoc, or_iff_not_imp_right, or_iff_not_imp_right] intro hb ha exact ⟨lt_top_of_mul_ne_top_left h.ne hb, lt_top_of_mul_ne_top_right h.ne ha⟩ - · rintro (⟨ha, hb⟩ | rfl | rfl) <;> [exact mul_lt_top ha.ne hb.ne; simp; simp] + · rintro (⟨ha, hb⟩ | rfl | rfl) <;> [exact mul_lt_top ha hb; simp; simp] theorem mul_self_lt_top_iff {a : ℝ≥0∞} : a * a < ⊤ ↔ a < ⊤ := by rw [ENNReal.mul_lt_top_iff, and_self, or_self, or_iff_left_iff_imp] @@ -256,6 +256,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,11 +295,13 @@ 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 @@ -314,15 +317,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 +363,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 @@ -399,27 +424,28 @@ section Sum open Finset -variable {α : Type*} +variable {α : Type*} {s : Finset α} {f : α → ℝ≥0∞} + +/-- A product of finite numbers is still finite. -/ +lemma prod_ne_top (h : ∀ a ∈ s, f a ≠ ∞) : ∏ a ∈ s, f a ≠ ∞ := WithTop.prod_ne_top h + +/-- A product of finite numbers is still finite. -/ +lemma prod_lt_top (h : ∀ a ∈ s, f a < ∞) : ∏ a ∈ s, f a < ∞ := WithTop.prod_lt_top h -/-- A product of finite numbers is still finite -/ -theorem prod_lt_top {s : Finset α} {f : α → ℝ≥0∞} (h : ∀ a ∈ s, f a ≠ ∞) : ∏ a ∈ s, f a < ∞ := - WithTop.prod_lt_top h +/-- A sum is infinite iff one of the summands is infinite. -/ +@[simp] lemma sum_eq_top : ∑ x ∈ s, f x = ∞ ↔ ∃ a ∈ s, f a = ∞ := WithTop.sum_eq_top -/-- A sum of finite numbers is still finite -/ -theorem sum_lt_top {s : Finset α} {f : α → ℝ≥0∞} (h : ∀ a ∈ s, f a ≠ ∞) : ∑ a ∈ s, f a < ∞ := - WithTop.sum_lt_top h +/-- A sum is finite iff all summands are finite. -/ +lemma sum_ne_top : ∑ a ∈ s, f a ≠ ∞ ↔ ∀ a ∈ s, f a ≠ ∞ := WithTop.sum_ne_top -/-- A sum of finite numbers is still finite -/ -theorem sum_lt_top_iff {s : Finset α} {f : α → ℝ≥0∞} : ∑ a ∈ s, f a < ∞ ↔ ∀ a ∈ s, f a < ∞ := - WithTop.sum_lt_top_iff +/-- A sum is finite iff all summands are finite. -/ +@[simp] lemma sum_lt_top : ∑ a ∈ s, f a < ∞ ↔ ∀ a ∈ s, f a < ∞ := WithTop.sum_lt_top -/-- A sum of numbers is infinite iff one of them is infinite -/ -theorem sum_eq_top_iff {s : Finset α} {f : α → ℝ≥0∞} : ∑ x ∈ s, f x = ∞ ↔ ∃ a ∈ s, f a = ∞ := - WithTop.sum_eq_top_iff +@[deprecated (since := "2024-08-25")] alias sum_lt_top_iff := sum_lt_top theorem lt_top_of_sum_ne_top {s : Finset α} {f : α → ℝ≥0∞} (h : ∑ x ∈ s, f x ≠ ∞) {a : α} (ha : a ∈ s) : f a < ∞ := - sum_lt_top_iff.1 h.lt_top a ha + sum_lt_top.1 h.lt_top a ha /-- Seeing `ℝ≥0∞` as `ℝ≥0` does not change their sum, unless one of the `ℝ≥0∞` is infinity -/ @@ -428,7 +454,7 @@ theorem toNNReal_sum {s : Finset α} {f : α → ℝ≥0∞} (hf : ∀ a ∈ s, rw [← coe_inj, coe_toNNReal, coe_finset_sum, sum_congr rfl] · intro x hx exact (coe_toNNReal (hf x hx)).symm - · exact (sum_lt_top hf).ne + · exact sum_ne_top.2 hf /-- seeing `ℝ≥0∞` as `Real` does not change their sum, unless one of the `ℝ≥0∞` is infinity -/ theorem toReal_sum {s : Finset α} {f : α → ℝ≥0∞} (hf : ∀ a ∈ s, f a ≠ ∞) : @@ -523,6 +549,15 @@ theorem smul_top {R} [Zero R] [SMulWithZero R ℝ≥0∞] [IsScalarTower R ℝ -- Porting note: need the primed version of `one_ne_zero` now simp_rw [smul_eq_zero, or_iff_left (one_ne_zero' ℝ≥0∞)] +lemma nnreal_smul_lt_top {x : ℝ≥0} {y : ℝ≥0∞} (hy : y < ⊤) : x • y < ⊤ := mul_lt_top (by simp) hy +lemma nnreal_smul_ne_top {x : ℝ≥0} {y : ℝ≥0∞} (hy : y ≠ ⊤) : x • y ≠ ⊤ := mul_ne_top (by simp) hy + +lemma nnreal_smul_ne_top_iff {x : ℝ≥0} {y : ℝ≥0∞} (hx : x ≠ 0) : x • y ≠ ⊤ ↔ y ≠ ⊤ := + ⟨by rintro h rfl; simp [smul_top, hx] at h, nnreal_smul_ne_top⟩ + +lemma nnreal_smul_lt_top_iff {x : ℝ≥0} {y : ℝ≥0∞} (hx : x ≠ 0) : x • y < ⊤ ↔ y < ⊤ := by + rw [lt_top_iff_ne_top, lt_top_iff_ne_top, nnreal_smul_ne_top_iff hx] + end Actions end ENNReal diff --git a/Mathlib/Data/ENNReal/Real.lean b/Mathlib/Data/ENNReal/Real.lean index d1cdba2b5cfd8..e9cc940e48612 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 @@ -360,7 +360,7 @@ theorem smul_toNNReal (a : ℝ≥0) (b : ℝ≥0∞) : (a • b).toNNReal = a * /-- `ENNReal.toNNReal` as a `MonoidHom`. -/ def toNNRealHom : ℝ≥0∞ →* ℝ≥0 where toFun := ENNReal.toNNReal - map_one' := toNNReal_coe + map_one' := toNNReal_coe _ map_mul' _ _ := toNNReal_mul @[simp] @@ -441,18 +441,18 @@ theorem toReal_pos_iff_ne_top (p : ℝ≥0∞) [Fact (1 ≤ p)] : 0 < p.toReal this rfl, fun h => zero_lt_one.trans_le (p.dichotomy.resolve_left h)⟩ -theorem toNNReal_inv (a : ℝ≥0∞) : a⁻¹.toNNReal = a.toNNReal⁻¹ := by +@[simp] theorem toNNReal_inv (a : ℝ≥0∞) : a⁻¹.toNNReal = a.toNNReal⁻¹ := by induction' a with a; · simp rcases eq_or_ne a 0 with (rfl | ha); · simp rw [← coe_inv ha, toNNReal_coe, toNNReal_coe] -theorem toNNReal_div (a b : ℝ≥0∞) : (a / b).toNNReal = a.toNNReal / b.toNNReal := by +@[simp] theorem toNNReal_div (a b : ℝ≥0∞) : (a / b).toNNReal = a.toNNReal / b.toNNReal := by rw [div_eq_mul_inv, toNNReal_mul, toNNReal_inv, div_eq_mul_inv] -theorem toReal_inv (a : ℝ≥0∞) : a⁻¹.toReal = a.toReal⁻¹ := by +@[simp] theorem toReal_inv (a : ℝ≥0∞) : a⁻¹.toReal = a.toReal⁻¹ := by simp only [ENNReal.toReal, toNNReal_inv, NNReal.coe_inv] -theorem toReal_div (a b : ℝ≥0∞) : (a / b).toReal = a.toReal / b.toReal := by +@[simp] theorem toReal_div (a b : ℝ≥0∞) : (a / b).toReal = a.toReal / b.toReal := by rw [div_eq_mul_inv, toReal_mul, toReal_inv, div_eq_mul_inv] theorem ofReal_prod_of_nonneg {α : Type*} {s : Finset α} {f : α → ℝ} (hf : ∀ i, i ∈ s → 0 ≤ f i) : @@ -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 _ _) @@ -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 e641b878298b9..3486a11a1cef2 100644 --- a/Mathlib/Data/ENat/Basic.lean +++ b/Mathlib/Data/ENat/Basic.lean @@ -24,22 +24,16 @@ and `Nat.cast` coercion. If you need to apply a lemma about `WithTop`, you may e and forth using `ENat.some_eq_coe`, or restate the lemma for `ENat`. -/ -/-- Extended natural numbers `ℕ∞ = WithTop ℕ`. -/ -def ENat : Type := - WithTop ℕ -deriving Zero, +deriving instance Zero, CanonicallyOrderedCommSemiring, Nontrivial, + LinearOrder, Bot, CanonicallyLinearOrderedAddCommMonoid, Sub, + LinearOrderedAddCommMonoidWithTop, WellFoundedRelation + for ENat -- AddCommMonoidWithOne, - CanonicallyOrderedCommSemiring, Nontrivial, - LinearOrder, Bot, Top, CanonicallyLinearOrderedAddCommMonoid, Sub, - LinearOrderedAddCommMonoidWithTop, WellFoundedRelation, Inhabited -- OrderBot, OrderTop, OrderedSub, SuccOrder, WellFoundedLt, CharZero -- Porting Note: In `Data.Nat.ENatPart` proofs timed out when having -- the `deriving AddCommMonoidWithOne`, and it seems to work without. -/-- Extended natural numbers `ℕ∞ = WithTop ℕ`. -/ -notation "ℕ∞" => ENat - namespace ENat -- Porting note: instances that derive failed to find @@ -57,6 +51,9 @@ variable {m n : ℕ∞} `ℕ → ℕ∞` 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 := @@ -107,34 +104,25 @@ lemma toNatHom_apply (n : ℕ) : toNatHom n = toNat n := rfl theorem toNat_coe (n : ℕ) : toNat n = n := rfl --- See note [no_index around OfNat.ofNat] @[simp] -theorem toNat_ofNat (n : ℕ) [n.AtLeastTwo] : toNat (no_index (OfNat.ofNat n)) = n := +theorem toNat_zero : toNat 0 = 0 := rfl @[simp] -theorem toNat_top : toNat ⊤ = 0 := +theorem toNat_one : toNat 1 = 1 := rfl -@[simp] theorem toNat_eq_zero : toNat n = 0 ↔ n = 0 ∨ n = ⊤ := WithTop.untop'_eq_self_iff - --- Porting note (#11445): new definition copied from `WithTop` -/-- Recursor for `ENat` using the preferred forms `⊤` and `↑a`. -/ -@[elab_as_elim, induction_eliminator, cases_eliminator] -def recTopCoe {C : ℕ∞ → Sort*} (top : C ⊤) (coe : ∀ a : ℕ, C a) : ∀ n : ℕ∞, C n - | none => top - | Option.some a => coe a - +-- See note [no_index around OfNat.ofNat] @[simp] -theorem recTopCoe_top {C : ℕ∞ → Sort*} (d : C ⊤) (f : ∀ a : ℕ, C a) : - @recTopCoe C d f ⊤ = d := +theorem toNat_ofNat (n : ℕ) [n.AtLeastTwo] : toNat (no_index (OfNat.ofNat n)) = n := rfl @[simp] -theorem recTopCoe_coe {C : ℕ∞ → Sort*} (d : C ⊤) (f : ∀ a : ℕ, C a) (x : ℕ) : - @recTopCoe C d f ↑x = f x := +theorem toNat_top : toNat ⊤ = 0 := rfl +@[simp] theorem toNat_eq_zero : toNat n = 0 ↔ n = 0 ∨ n = ⊤ := WithTop.untop'_eq_self_iff + @[simp] theorem recTopCoe_zero {C : ℕ∞ → Sort*} (d : C ⊤) (f : ∀ a : ℕ, C a) : @recTopCoe C d f 0 = f 0 := rfl @@ -225,28 +213,32 @@ lemma toNat_le_toNat {m n : ℕ∞} (h : m ≤ n) (hn : n ≠ ⊤) : toNat m ≤ toNat_le_of_le_coe <| h.trans_eq (coe_toNat hn).symm @[simp] -theorem succ_def (m : ℕ∞) : Order.succ m = m + 1 := by cases m <;> rfl +theorem succ_def (m : ℕ∞) : Order.succ m = m + 1 := + Order.succ_eq_add_one m +@[deprecated Order.add_one_le_of_lt (since := "2024-09-04")] theorem add_one_le_of_lt (h : m < n) : m + 1 ≤ n := - m.succ_def ▸ Order.succ_le_of_lt h + Order.add_one_le_of_lt h theorem add_one_le_iff (hm : m ≠ ⊤) : m + 1 ≤ n ↔ m < n := - m.succ_def ▸ (Order.succ_le_iff_of_not_isMax <| by rwa [isMax_iff_eq_top]) + Order.add_one_le_iff_of_not_isMax (not_isMax_iff_ne_top.mpr hm) +@[deprecated Order.one_le_iff_pos (since := "2024-09-04")] theorem one_le_iff_pos : 1 ≤ n ↔ 0 < n := - add_one_le_iff WithTop.zero_ne_top + Order.one_le_iff_pos theorem one_le_iff_ne_zero : 1 ≤ n ↔ n ≠ 0 := - one_le_iff_pos.trans pos_iff_ne_zero + Order.one_le_iff_pos.trans pos_iff_ne_zero lemma lt_one_iff_eq_zero : n < 1 ↔ n = 0 := not_le.symm.trans one_le_iff_ne_zero.not_left +@[deprecated Order.le_of_lt_add_one (since := "2024-09-04")] theorem le_of_lt_add_one (h : m < n + 1) : m ≤ n := - Order.le_of_lt_succ <| n.succ_def.symm ▸ h + Order.le_of_lt_add_one h theorem lt_add_one_iff (hm : n ≠ ⊤) : m < n + 1 ↔ m ≤ n := - n.succ_def ▸ Order.lt_succ_iff_of_not_isMax (not_isMax_iff_ne_top.mpr hm) + Order.lt_add_one_iff_of_not_isMax (not_isMax_iff_ne_top.mpr hm) theorem le_coe_iff {n : ℕ∞} {k : ℕ} : n ≤ ↑k ↔ ∃ (n₀ : ℕ), n = n₀ ∧ n₀ ≤ k := WithTop.le_coe_iff @@ -267,4 +259,26 @@ 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)⟩ + end ENat diff --git a/Mathlib/Data/ENat/Lattice.lean b/Mathlib/Data/ENat/Lattice.lean index 869003b893a3e..25c112487f8a7 100644 --- a/Mathlib/Data/ENat/Lattice.lean +++ b/Mathlib/Data/ENat/Lattice.lean @@ -100,4 +100,13 @@ lemma finite_of_sSup_lt_top (h : sSup s < ⊤) : s.Finite := by lemma sSup_mem_of_Nonempty_of_lt_top [Nonempty s] (hs' : sSup s < ⊤) : sSup s ∈ s := Nonempty.csSup_mem nonempty_of_nonempty_subtype (finite_of_sSup_lt_top hs') +lemma exists_eq_iSup_of_lt_top [Nonempty ι] (h : ⨆ i, f i < ⊤) : + ∃ i, f i = ⨆ i, f i := + sSup_mem_of_Nonempty_of_lt_top h + +lemma exists_eq_iSup₂_of_lt_top {ι₁ ι₂ : Type*} {f : ι₁ → ι₂ → ℕ∞} [Nonempty ι₁] [Nonempty ι₂] + (h : ⨆ i, ⨆ j, f i j < ⊤) : ∃ i j, f i j = ⨆ i, ⨆ j, f i j := by + rw [iSup_prod'] at h ⊢ + exact Prod.exists'.mp (exists_eq_iSup_of_lt_top h) + end ENat diff --git a/Mathlib/Data/FP/Basic.lean b/Mathlib/Data/FP/Basic.lean index 8ba466a35a5cb..c854edb12daef 100644 --- a/Mathlib/Data/FP/Basic.lean +++ b/Mathlib/Data/FP/Basic.lean @@ -86,7 +86,7 @@ theorem Float.Zero.valid : ValidFinite emin 0 := rw [mul_comm] assumption le_trans C.precMax (Nat.le_mul_of_pos_left _ two_pos), - by (rw [max_eq_right]; simp [sub_eq_add_neg])⟩ + by (rw [max_eq_right]; simp [sub_eq_add_neg, Int.ofNat_zero_le])⟩ @[nolint docBlame] def Float.zero (s : Bool) : Float := diff --git a/Mathlib/Data/Fin/Basic.lean b/Mathlib/Data/Fin/Basic.lean index 937ec7c6da20d..edc71f8ff4d06 100644 --- a/Mathlib/Data/Fin/Basic.lean +++ b/Mathlib/Data/Fin/Basic.lean @@ -5,10 +5,11 @@ Authors: Robert Y. Lewis, Keeley Hoek -/ import Mathlib.Algebra.NeZero import Mathlib.Data.Nat.Defs -import Mathlib.Init.Data.Nat.Lemmas +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 @@ -78,6 +79,11 @@ def finZeroElim {α : Fin 0 → Sort*} (x : Fin 0) : α x := namespace Fin +@[deprecated (since := "2024-02-15")] alias eq_of_veq := eq_of_val_eq +@[deprecated (since := "2024-02-15")] alias veq_of_eq := val_eq_of_eq +@[deprecated (since := "2024-08-13")] alias ne_of_vne := ne_of_val_ne +@[deprecated (since := "2024-08-13")] alias vne_of_ne := val_ne_of_ne + instance {n : ℕ} : CanLift ℕ (Fin n) Fin.val (· < n) where prf k hk := ⟨⟨k, hk⟩, rfl⟩ @@ -107,10 +113,10 @@ protected lemma lt_of_lt_of_le : a < b → b ≤ c → a < c := Nat.lt_of_lt_of_ protected lemma le_rfl : a ≤ a := Nat.le_refl _ protected lemma lt_iff_le_and_ne : a < b ↔ a ≤ b ∧ a ≠ b := by rw [← val_ne_iff]; exact Nat.lt_iff_le_and_ne -protected lemma lt_or_lt_of_ne (h : a ≠ b) : a < b ∨ b < a := Nat.lt_or_lt_of_ne $ val_ne_iff.2 h +protected lemma lt_or_lt_of_ne (h : a ≠ b) : a < b ∨ b < a := Nat.lt_or_lt_of_ne <| val_ne_iff.2 h protected lemma lt_or_le (a b : Fin n) : a < b ∨ b ≤ a := Nat.lt_or_ge _ _ protected lemma le_or_lt (a b : Fin n) : a ≤ b ∨ b < a := (b.lt_or_le a).symm -protected lemma le_of_eq (hab : a = b) : a ≤ b := Nat.le_of_eq $ congr_arg val hab +protected lemma le_of_eq (hab : a = b) : a ≤ b := Nat.le_of_eq <| congr_arg val hab protected lemma ge_of_eq (hab : a = b) : b ≤ a := Fin.le_of_eq hab.symm protected lemma eq_or_lt_of_le : a ≤ b → a = b ∨ a < b := by rw [Fin.ext_iff]; exact Nat.eq_or_lt_of_le @@ -123,10 +129,10 @@ lemma lt_last_iff_ne_last {a : Fin (n + 1)} : a < last n ↔ a ≠ last n := by simp [Fin.lt_iff_le_and_ne, le_last] lemma ne_zero_of_lt {a b : Fin (n + 1)} (hab : a < b) : b ≠ 0 := - Fin.ne_of_gt $ Fin.lt_of_le_of_lt a.zero_le hab + Fin.ne_of_gt <| Fin.lt_of_le_of_lt a.zero_le hab lemma ne_last_of_lt {a b : Fin (n + 1)} (hab : a < b) : a ≠ last n := - Fin.ne_of_lt $ Fin.lt_of_lt_of_le hab b.le_last + Fin.ne_of_lt <| Fin.lt_of_lt_of_le hab b.le_last /-- Equivalence between `Fin n` and `{ i // i < n }`. -/ @[simps apply symm_apply] @@ -177,6 +183,8 @@ protected theorem heq_fun₂_iff {α : Sort*} {k l k' l' : ℕ} (h : k = l) (h' subst h' simp [Function.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 @@ -184,14 +192,13 @@ protected theorem heq_ext_iff {k l : ℕ} (h : k = l) {i : Fin k} {j : Fin l} : end coe + section Order /-! ### order -/ - - theorem le_iff_val_le_val {a b : Fin n} : a ≤ b ↔ (a : ℕ) ≤ b := Iff.rfl @@ -268,6 +275,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 @@ -322,6 +335,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 /-! @@ -341,8 +406,7 @@ instance nontrivial {n : ℕ} : Nontrivial (Fin (n + 2)) where theorem nontrivial_iff_two_le : Nontrivial (Fin n) ↔ 2 ≤ n := by rcases n with (_ | _ | n) <;> - simp [← Nat.one_eq_succ_zero, Fin.nontrivial, not_nontrivial, Nat.succ_le_iff] --- Porting note: here and in the next lemma, had to use `← Nat.one_eq_succ_zero`. + simp [Fin.nontrivial, not_nontrivial, Nat.succ_le_iff] section Monoid @@ -350,16 +414,6 @@ section Monoid 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 @@ -370,8 +424,8 @@ theorem default_eq_zero (n : ℕ) [NeZero n] : (default : Fin n) = 0 := 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 +@[simp] lemma ofNat'_zero [NeZero n] : (Fin.ofNat' n 0) = 0 := rfl +@[simp] lemma ofNat'_one [NeZero n] : (Fin.ofNat' n 1) = 1 := rfl end from_ad_hoc @@ -401,12 +455,12 @@ alias val_nat_cast := val_natCast -- Porting note: is this the right name for things involving `Nat.cast`? /-- Converting an in-range number to `Fin (n + 1)` produces a result -whose value is the original number. -/ +whose value is the original number. -/ theorem val_cast_of_lt {n : ℕ} [NeZero n] {a : ℕ} (h : a < n) : (a : Fin n).val = a := Nat.mod_eq_of_lt h /-- If `n` is non-zero, converting the value of a `Fin n` to `Fin n` results -in the same value. -/ +in the same value. -/ @[simp] theorem cast_val_eq_self {n : ℕ} [NeZero n] (a : Fin n) : (a.val : Fin n) = a := Fin.ext <| val_cast_of_lt a.isLt @@ -414,7 +468,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 @@ -451,13 +506,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 @@ -513,10 +561,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] @@ -532,7 +576,7 @@ lemma castAdd_injective (m n : ℕ) : Injective (@Fin.castAdd m n) := castLE_inj lemma castSucc_injective (n : ℕ) : Injective (@Fin.castSucc n) := castAdd_injective _ _ -/-- `Fin.castLE` as an `Embedding`, `castLEEmb h i` embeds `i` into a larger `Fin` type. -/ +/-- `Fin.castLE` as an `Embedding`, `castLEEmb h i` embeds `i` into a larger `Fin` type. -/ @[simps! apply] def castLEEmb (h : n ≤ m) : Fin n ↪ Fin m where toFun := castLE h @@ -636,13 +680,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} @@ -710,7 +755,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 @@ -756,8 +801,6 @@ section Pred ### pred -/ - - theorem pred_one' [NeZero n] (h := (zero_ne_one' (n := n)).symm) : Fin.pred (1 : Fin (n + 1)) h = 0 := by simp_rw [Fin.ext_iff, coe_pred, val_one', val_zero', Nat.sub_eq_zero_iff_le, Nat.mod_le] @@ -775,7 +818,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) : @@ -976,7 +1019,7 @@ lemma succAbove_castSucc_of_le (p i : Fin n) (h : p ≤ i) : succAbove p.castSuc succAbove_castSucc_of_le _ _ Fin.le_rfl lemma succAbove_pred_of_lt (p i : Fin (n + 1)) (h : p < i) - (hi := Fin.ne_of_gt $ Fin.lt_of_le_of_lt p.zero_le h) : succAbove p (i.pred hi) = i := by + (hi := Fin.ne_of_gt <| Fin.lt_of_le_of_lt p.zero_le h) : succAbove p (i.pred hi) = i := by rw [succAbove_of_lt_succ _ _ (succ_pred _ _ ▸ h), succ_pred] lemma succAbove_pred_of_le (p i : Fin (n + 1)) (h : i ≤ p) (hi : i ≠ 0) : @@ -986,7 +1029,7 @@ lemma succAbove_pred_of_le (p i : Fin (n + 1)) (h : i ≤ p) (hi : i ≠ 0) : succAbove p (p.pred h) = (p.pred h).castSucc := succAbove_pred_of_le _ _ Fin.le_rfl h lemma succAbove_castPred_of_lt (p i : Fin (n + 1)) (h : i < p) - (hi := Fin.ne_of_lt $ Nat.lt_of_lt_of_le h p.le_last) : succAbove p (i.castPred hi) = i := by + (hi := Fin.ne_of_lt <| Nat.lt_of_lt_of_le h p.le_last) : succAbove p (i.castPred hi) = i := by rw [succAbove_of_castSucc_lt _ _ (castSucc_castPred _ _ ▸ h), castSucc_castPred] lemma succAbove_castPred_of_le (p i : Fin (n + 1)) (h : p ≤ i) (hi : i ≠ last n) : @@ -1025,9 +1068,9 @@ lemma succAbove_right_injective : Injective p.succAbove := by split_ifs at hij with hi hj hj · exact castSucc_injective _ hij · rw [hij] at hi - cases hj $ Nat.lt_trans j.castSucc_lt_succ hi + cases hj <| Nat.lt_trans j.castSucc_lt_succ hi · rw [← hij] at hj - cases hi $ Nat.lt_trans i.castSucc_lt_succ hj + cases hi <| Nat.lt_trans i.castSucc_lt_succ hj · exact succ_injective _ hij /-- Given a fixed pivot `p : Fin (n + 1)`, `p.succAbove` is injective. -/ @@ -1086,7 +1129,7 @@ lemma succAbove_lt_iff_castSucc_lt (p : Fin (n + 1)) (i : Fin n) : cases' castSucc_lt_or_lt_succ p i with H H · rwa [iff_true_right H, succAbove_of_castSucc_lt _ _ H] · rw [castSucc_lt_iff_succ_le, iff_false_right (Fin.not_le.2 H), succAbove_of_lt_succ _ _ H] - exact Fin.not_lt.2 $ Fin.le_of_lt H + exact Fin.not_lt.2 <| Fin.le_of_lt H lemma succAbove_lt_iff_succ_le (p : Fin (n + 1)) (i : Fin n) : p.succAbove i < p ↔ succ i ≤ p := by @@ -1098,7 +1141,7 @@ lemma lt_succAbove_iff_le_castSucc (p : Fin (n + 1)) (i : Fin n) : p < p.succAbove i ↔ p ≤ castSucc i := by cases' castSucc_lt_or_lt_succ p i with H H · rw [iff_false_right (Fin.not_le.2 H), succAbove_of_castSucc_lt _ _ H] - exact Fin.not_lt.2 $ Fin.le_of_lt H + exact Fin.not_lt.2 <| Fin.le_of_lt H · rwa [succAbove_of_lt_succ _ _ H, iff_true_left H, le_castSucc_iff] lemma lt_succAbove_iff_lt_castSucc (p : Fin (n + 1)) (i : Fin n) : @@ -1111,12 +1154,12 @@ lemma succAbove_pos [NeZero n] (p : Fin (n + 1)) (i : Fin n) (h : 0 < i) : 0 < p · simp [succAbove_of_le_castSucc _ _ (Fin.not_lt.1 H)] lemma castPred_succAbove (x : Fin n) (y : Fin (n + 1)) (h : castSucc x < y) - (h' := Fin.ne_last_of_lt $ (succAbove_lt_iff_castSucc_lt ..).2 h) : + (h' := Fin.ne_last_of_lt <| (succAbove_lt_iff_castSucc_lt ..).2 h) : (y.succAbove x).castPred h' = x := by rw [castPred_eq_iff_eq_castSucc, succAbove_of_castSucc_lt _ _ h] lemma pred_succAbove (x : Fin n) (y : Fin (n + 1)) (h : y ≤ castSucc x) - (h' := Fin.ne_zero_of_lt $ (lt_succAbove_iff_le_castSucc ..).2 h) : + (h' := Fin.ne_zero_of_lt <| (lt_succAbove_iff_le_castSucc ..).2 h) : (y.succAbove x).pred h' = x := by simp only [succAbove_of_le_castSucc _ _ h, pred_succ] lemma exists_succAbove_eq {x y : Fin (n + 1)} (h : x ≠ y) : ∃ z, y.succAbove z = x := by @@ -1205,11 +1248,11 @@ section PredAbove def predAbove (p : Fin n) (i : Fin (n + 1)) : Fin n := if h : castSucc p < i then pred i (Fin.ne_zero_of_lt h) - else castPred i (Fin.ne_of_lt $ Fin.lt_of_le_of_lt (Fin.not_lt.1 h) (castSucc_lt_last _)) + else castPred i (Fin.ne_of_lt <| Fin.lt_of_le_of_lt (Fin.not_lt.1 h) (castSucc_lt_last _)) lemma predAbove_of_le_castSucc (p : Fin n) (i : Fin (n + 1)) (h : i ≤ castSucc p) - (hi := Fin.ne_of_lt $ Fin.lt_of_le_of_lt h $ castSucc_lt_last _) : - p.predAbove i = i.castPred hi := dif_neg $ Fin.not_lt.2 h + (hi := Fin.ne_of_lt <| Fin.lt_of_le_of_lt h <| castSucc_lt_last _) : + p.predAbove i = i.castPred hi := dif_neg <| Fin.not_lt.2 h lemma predAbove_of_lt_succ (p : Fin n) (i : Fin (n + 1)) (h : i < succ p) (hi := Fin.ne_last_of_lt h) : p.predAbove i = i.castPred hi := @@ -1219,7 +1262,7 @@ lemma predAbove_of_castSucc_lt (p : Fin n) (i : Fin (n + 1)) (h : castSucc p < i (hi := Fin.ne_zero_of_lt h) : p.predAbove i = i.pred hi := dif_pos h lemma predAbove_of_succ_le (p : Fin n) (i : Fin (n + 1)) (h : succ p ≤ i) - (hi := Fin.ne_of_gt $ Fin.lt_of_lt_of_le (succ_pos _) h) : + (hi := Fin.ne_of_gt <| Fin.lt_of_lt_of_le (succ_pos _) h) : p.predAbove i = i.pred hi := predAbove_of_castSucc_lt _ _ (castSucc_lt_iff_succ_le.mpr h) lemma predAbove_succ_of_lt (p i : Fin n) (h : i < p) (hi := succ_ne_last_of_lt h) : @@ -1247,7 +1290,7 @@ lemma predAbove_pred_of_lt (p i : Fin (n + 1)) (h : i < p) (hp := Fin.ne_zero_of rw [predAbove_of_lt_succ _ _ (succ_pred _ _ ▸ h)] lemma predAbove_pred_of_le (p i : Fin (n + 1)) (h : p ≤ i) (hp : p ≠ 0) - (hi := Fin.ne_of_gt $ Fin.lt_of_lt_of_le (Fin.pos_iff_ne_zero.2 hp) h) : + (hi := Fin.ne_of_gt <| Fin.lt_of_lt_of_le (Fin.pos_iff_ne_zero.2 hp) h) : (pred p hp).predAbove i = pred i hi := by rw [predAbove_of_succ_le _ _ (succ_pred _ _ ▸ h)] lemma predAbove_pred_self (p : Fin (n + 1)) (hp : p ≠ 0) : (pred p hp).predAbove p = pred p hp := @@ -1258,7 +1301,7 @@ lemma predAbove_castPred_of_lt (p i : Fin (n + 1)) (h : p < i) (hp := Fin.ne_las rw [predAbove_of_castSucc_lt _ _ (castSucc_castPred _ _ ▸ h)] lemma predAbove_castPred_of_le (p i : Fin (n + 1)) (h : i ≤ p) (hp : p ≠ last n) - (hi := Fin.ne_of_lt $ Fin.lt_of_le_of_lt h $ Fin.lt_last_iff_ne_last.2 hp) : + (hi := Fin.ne_of_lt <| Fin.lt_of_le_of_lt h <| Fin.lt_last_iff_ne_last.2 hp) : (castPred p hp).predAbove i = castPred i hi := by rw [predAbove_of_le_castSucc _ _ (castSucc_castPred _ _ ▸ h)] @@ -1332,7 +1375,7 @@ then back to `Fin n` by subtracting one from anything above `p` is the identity. lemma predAbove_succAbove (p : Fin n) (i : Fin n) : p.predAbove ((castSucc p).succAbove i) = i := by obtain h | h := p.le_or_lt i · rw [succAbove_castSucc_of_le _ _ h, predAbove_succ_of_le _ _ h] - · rw [succAbove_castSucc_of_lt _ _ h, predAbove_castSucc_of_le _ _ $ Fin.le_of_lt h] + · rw [succAbove_castSucc_of_lt _ _ h, predAbove_castSucc_of_le _ _ <| Fin.le_of_lt h] /-- `succ` commutes with `predAbove`. -/ @[simp] lemma succ_predAbove_succ (a : Fin n) (b : Fin (n + 1)) : @@ -1428,11 +1471,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] 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 +1488,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_eq, 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 +1499,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_eq, 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,14 +1548,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 0bb5943fae65c..c89677f2b5dae 100644 --- a/Mathlib/Data/Fin/Tuple/Basic.lean +++ b/Mathlib/Data/Fin/Tuple/Basic.lean @@ -5,7 +5,6 @@ Authors: Floris van Doorn, Yury Kudryashov, Sébastien Gouëzel, Chris Hughes -/ import Mathlib.Data.Fin.Basic import Mathlib.Data.Nat.Find -import Batteries.Data.Fin.Lemmas /-! # Operation on tuples @@ -94,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 @@ -118,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 @@ -193,7 +192,7 @@ 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 @@ -255,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 @@ -265,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] @@ -282,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] @@ -317,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 @@ -330,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] @@ -349,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 @@ -361,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] @@ -383,7 +390,7 @@ 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 @@ -391,31 +398,33 @@ 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 @@ -426,7 +435,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 @@ -435,11 +444,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 @@ -457,14 +466,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 @@ -486,21 +495,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 @@ -511,13 +520,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 _ _) @@ -543,7 +552,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' @@ -588,14 +597,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 @@ -613,7 +622,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 @@ -622,7 +631,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 @@ -634,21 +643,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 @@ -662,7 +671,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⟩ @@ -676,7 +685,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] @@ -696,7 +705,7 @@ 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 @@ -707,7 +716,7 @@ 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. -/ @@ -724,9 +733,37 @@ def succAboveCases {α : Fin (n + 1) → Sort u} (i : Fin (n + 1)) (x : α i) else @Eq.recOn _ _ (fun x _ ↦ α x) _ (succAbove_pred_of_lt _ _ <| (Fin.lt_or_lt_of_ne hj).resolve_left hlt) (p _) -theorem forall_iff_succAbove {p : Fin (n + 1) → Prop} (i : Fin (n + 1)) : - (∀ j, p j) ↔ p i ∧ ∀ j, p (i.succAbove j) := - ⟨fun h ↦ ⟨h _, fun _ ↦ h _⟩, fun h ↦ succAboveCases i h.1 h.2⟩ +-- This is a duplicate of `Fin.exists_fin_succ` in Core. We should upstream the name change. +alias forall_iff_succ := forall_fin_succ + +-- This is a duplicate of `Fin.exists_fin_succ` in Core. We should upstream the name change. +alias exists_iff_succ := exists_fin_succ + +lemma forall_iff_castSucc {P : Fin (n + 1) → Prop} : + (∀ i, P i) ↔ P (last n) ∧ ∀ i, P (castSucc i) := + ⟨fun h ↦ ⟨h _, fun _ ↦ h _⟩, fun h ↦ lastCases h.1 h.2⟩ + +lemma exists_iff_castSucc {P : Fin (n + 1) → Prop} : + (∃ i, P i) ↔ P (last n) ∨ ∃ i, P (castSucc i) where + mp := by + rintro ⟨i, hi⟩ + induction' i using lastCases + · exact .inl hi + · exact .inr ⟨_, hi⟩ + mpr := by rintro (h | ⟨i, hi⟩) <;> exact ⟨_, ‹_›⟩ + +theorem forall_iff_succAbove {P : Fin (n + 1) → Prop} (p : Fin (n + 1)) : + (∀ i, P i) ↔ P p ∧ ∀ i, P (p.succAbove i) := + ⟨fun h ↦ ⟨h _, fun _ ↦ h _⟩, fun h ↦ succAboveCases p h.1 h.2⟩ + +lemma exists_iff_succAbove {P : Fin (n + 1) → Prop} (p : Fin (n + 1)) : + (∃ i, P i) ↔ P p ∨ ∃ i, P (p.succAbove i) where + mp := by + rintro ⟨i, hi⟩ + induction' i using p.succAboveCases + · exact .inl hi + · exact .inr ⟨_, hi⟩ + mpr := by rintro (h | ⟨i, hi⟩) <;> exact ⟨_, ‹_›⟩ /-- Remove the `p`-th entry of a tuple. -/ def removeNth (p : Fin (n + 1)) (f : ∀ i, α i) : ∀ i, α (p.succAbove i) := fun i ↦ f (p.succAbove i) @@ -751,13 +788,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)) : @@ -827,7 +864,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 @@ -861,8 +898,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 @@ -872,7 +910,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 @@ -888,7 +926,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) @@ -1002,7 +1040,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/Curry.lean b/Mathlib/Data/Fin/Tuple/Curry.lean index 1b752e325ecb5..65e49ebf5c77c 100644 --- a/Mathlib/Data/Fin/Tuple/Curry.lean +++ b/Mathlib/Data/Fin/Tuple/Curry.lean @@ -73,7 +73,7 @@ variable {n : ℕ} {p : Fin n → Type u} {τ : Type u} theorem curry_uncurry (f : Function.FromTypes p τ) : curry (uncurry f) = f := by induction n with | zero => rfl - | succ n ih => exact funext (ih $ f ·) + | succ n ih => exact funext (ih <| f ·) @[simp] theorem uncurry_curry (f : ((i : Fin n) → p i) → τ) : diff --git a/Mathlib/Data/Fin/Tuple/Finset.lean b/Mathlib/Data/Fin/Tuple/Finset.lean index 5a102d77f270b..d376279817e25 100644 --- a/Mathlib/Data/Fin/Tuple/Finset.lean +++ b/Mathlib/Data/Fin/Tuple/Finset.lean @@ -3,34 +3,87 @@ 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_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_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 ↔ init x ∈ piFinset (init s) ∧ x (last n) ∈ s (last n) := by - simp only [mem_piFinset, forall_fin_succ', init] +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 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] +@[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 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 ∈ piFinset s ∧ xₙ ∈ sₙ := by - simp_rw [mem_piFinset_succ', init_snoc, snoc_last] +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_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] : + ((piFinset S).filter fun r ↦ P <| tail r).map (consEquiv α).symm.toEmbedding = + S 0 ×ˢ (piFinset fun x ↦ S <| succ x).filter P := by + unfold tail; ext; simp [Fin.forall_iff_succ, and_assoc] + +lemma map_snocEquiv_filter_piFinset (P : (∀ i, α (castSucc i)) → Prop) [DecidablePred P] : + ((piFinset S).filter fun r ↦ P <| init r).map (snocEquiv α).symm.toEmbedding = + S (last _) ×ˢ (piFinset <| init S).filter P := by + unfold init; ext; simp [Fin.forall_iff_castSucc, and_assoc] + +lemma map_insertNthEquiv_filter_piFinset (P : (∀ i, α (p.succAbove i)) → Prop) [DecidablePred P] : + ((piFinset S).filter fun r ↦ P <| p.removeNth r).map (p.insertNthEquiv α).symm.toEmbedding = + S p ×ˢ (piFinset <| p.removeNth S).filter P := by + unfold removeNth; ext; simp [Fin.forall_iff_succAbove p, and_assoc] + +lemma card_consEquiv_filter_piFinset (P : (∀ i, α (succ i)) → Prop) [DecidablePred P] : + ((piFinset S).filter fun r ↦ P <| tail r).card = + (S 0).card * ((piFinset fun x ↦ S <| succ x).filter P).card := by + rw [← card_product, ← map_consEquiv_filter_piFinset, card_map] + +lemma card_snocEquiv_filter_piFinset (P : (∀ i, α (castSucc i)) → Prop) [DecidablePred P] : + ((piFinset S).filter fun r ↦ P <| init r).card = + (S (last _)).card * ((piFinset <| init S).filter P).card := by + rw [← card_product, ← map_snocEquiv_filter_piFinset, card_map] + +lemma card_insertNthEquiv_filter_piFinset (P : (∀ i, α (p.succAbove i)) → Prop) [DecidablePred P] : + ((piFinset S).filter fun r ↦ P <| p.removeNth r).card = + (S p).card * ((piFinset <| p.removeNth S).filter P).card := by + 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 a2b9e02f3bc43..7f311baa1744c 100644 --- a/Mathlib/Data/Fin/Tuple/NatAntidiagonal.lean +++ b/Mathlib/Data/Fin/Tuple/NatAntidiagonal.lean @@ -120,10 +120,10 @@ theorem antidiagonalTuple_zero_right : ∀ k, antidiagonalTuple k 0 = [0] @[simp] theorem antidiagonalTuple_one (n : ℕ) : antidiagonalTuple 1 n = [![n]] := by simp_rw [antidiagonalTuple, antidiagonal, List.range_succ, List.map_append, List.map_singleton, - tsub_self, List.bind_append, List.bind_singleton, List.bind_map] + 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/Sort.lean b/Mathlib/Data/Fin/Tuple/Sort.lean index d53751d03f1f5..6dfe8a11de7e8 100644 --- a/Mathlib/Data/Fin/Tuple/Sort.lean +++ b/Mathlib/Data/Fin/Tuple/Sort.lean @@ -178,7 +178,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/VecNotation.lean b/Mathlib/Data/Fin/VecNotation.lean index 56651d1ba5421..d3b561640f0ae 100644 --- a/Mathlib/Data/Fin/VecNotation.lean +++ b/Mathlib/Data/Fin/VecNotation.lean @@ -171,7 +171,7 @@ theorem range_cons_cons_empty (x y : α) (u : Fin 0 → α) : @[simp] theorem vecCons_const (a : α) : (vecCons a fun _ : Fin n => a) = fun _ => a := - funext <| Fin.forall_fin_succ.2 ⟨rfl, cons_val_succ _ _⟩ + funext <| Fin.forall_iff_succ.2 ⟨rfl, cons_val_succ _ _⟩ theorem vec_single_eq_const (a : α) : ![a] = fun _ => a := let _ : Unique (Fin 1) := inferInstance @@ -208,8 +208,7 @@ theorem cons_val_fin_one (x : α) (u : Fin 0 → α) : ∀ (i : Fin 1), vecCons theorem cons_fin_one (x : α) (u : Fin 0 → α) : vecCons x u = fun _ => x := funext (cons_val_fin_one x u) -open Lean in -open Qq in +open Lean Qq in protected instance _root_.PiFin.toExpr [ToLevel.{u}] [ToExpr α] (n : ℕ) : ToExpr (Fin n → α) := have lu := toLevel.{u} have eα : Q(Type $lu) := toTypeExpr α @@ -317,7 +316,7 @@ theorem vecAlt1_vecAppend (v : Fin (n + 1) → α) : cases n with | zero => cases' i with i hi - simp only [Nat.zero_eq, Nat.zero_add, Nat.lt_one_iff] at hi; subst i; rfl + simp only [Nat.zero_add, Nat.lt_one_iff] at hi; subst i; rfl | succ n => split_ifs with h <;> congr · simp [Nat.mod_eq_of_lt, h] diff --git a/Mathlib/Data/FinEnum.lean b/Mathlib/Data/FinEnum.lean index 82688911d453d..c2d94fcfa23ad 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) @@ -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/Card.lean b/Mathlib/Data/Finite/Card.lean index e13bf96384a2c..c16b94bbcd01b 100644 --- a/Mathlib/Data/Finite/Card.lean +++ b/Mathlib/Data/Finite/Card.lean @@ -206,4 +206,8 @@ theorem equiv_image_eq_iff_subset (e : α ≃ α) (hs : s.Finite) : e '' s = s end Finite +theorem eq_top_of_card_le_of_finite [Finite α] {s : Set α} (h : Nat.card α ≤ Nat.card s) : s = ⊤ := + Set.Finite.eq_of_subset_of_card_le univ.toFinite (subset_univ s) <| + Nat.card_congr (Equiv.Set.univ α) ▸ h + end Set diff --git a/Mathlib/Data/Finmap.lean b/Mathlib/Data/Finmap.lean index fb4a761948449..c4d3fe1b9820d 100644 --- a/Mathlib/Data/Finmap.lean +++ b/Mathlib/Data/Finmap.lean @@ -17,7 +17,7 @@ open List variable {α : Type u} {β : α → Type v} -/-! ### Multisets of sigma types-/ +/-! ### Multisets of sigma types -/ namespace Multiset @@ -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,7 +107,6 @@ 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₂) : γ := @@ -151,7 +149,7 @@ theorem ext_iff' {s t : Finmap β} : s.entries = t.entries ↔ s = t := /-- The predicate `a ∈ s` means that `s` has a value associated to the key `a`. -/ instance : Membership α (Finmap β) := - ⟨fun a s => a ∈ s.entries.keys⟩ + ⟨fun s a => a ∈ s.entries.keys⟩ theorem mem_def {a : α} {s : Finmap β} : a ∈ s ↔ a ∈ s.entries.keys := Iff.rfl @@ -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 := diff --git a/Mathlib/Data/Finset/Attr.lean b/Mathlib/Data/Finset/Attr.lean index d122deb225f9a..43bc734336e24 100644 --- a/Mathlib/Data/Finset/Attr.lean +++ b/Mathlib/Data/Finset/Attr.lean @@ -3,6 +3,7 @@ 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.Init import Aesop import Qq diff --git a/Mathlib/Data/Finset/Basic.lean b/Mathlib/Data/Finset/Basic.lean index c010b93b78035..e86ab424aa5fb 100644 --- a/Mathlib/Data/Finset/Basic.lean +++ b/Mathlib/Data/Finset/Basic.lean @@ -105,8 +105,9 @@ In Lean, we use lattice notation to talk about things involving unions and inter ### Equivalences between finsets -* The `Mathlib/Data/Equiv.lean` files describe a general type of equivalence, so look in there for - any lemmas. There is some API for rewriting sums and products from `s` to `t` given that `s ≃ t`. +* The `Mathlib/Logic/Equiv/Defs.lean` files describe a general type of equivalence, so look in there + for any lemmas. There is some API for rewriting sums and products from `s` to `t` given that + `s ≃ t`. TODO: examples ## Tags @@ -122,7 +123,9 @@ assert_not_exists Multiset.powerset assert_not_exists CompleteLattice -open Multiset Subtype Nat Function +assert_not_exists OrderedCommMonoid + +open Multiset Subtype Function universe u @@ -161,7 +164,7 @@ instance decidableEq [DecidableEq α] : DecidableEq (Finset α) instance : Membership α (Finset α) := - ⟨fun a s => a ∈ s.1⟩ + ⟨fun s a => a ∈ s.1⟩ theorem mem_def {a : α} {s : Finset α} : a ∈ s ↔ a ∈ s.1 := Iff.rfl @@ -212,17 +215,13 @@ instance decidableMem' [DecidableEq α] (a : α) (s : Finset α) : Decidable (a /-! ### extensionality -/ - -theorem ext_iff {s₁ s₂ : Finset α} : s₁ = s₂ ↔ ∀ a, a ∈ s₁ ↔ a ∈ s₂ := - val_inj.symm.trans <| s₁.nodup.ext s₂.nodup - @[ext] -theorem ext {s₁ s₂ : Finset α} : (∀ a, a ∈ s₁ ↔ a ∈ s₂) → s₁ = s₂ := - ext_iff.2 +theorem ext {s₁ s₂ : Finset α} (h : ∀ a, a ∈ s₁ ↔ a ∈ s₂) : s₁ = s₂ := + (val_inj.symm.trans <| s₁.nodup.ext s₂.nodup).mpr h @[simp, norm_cast] theorem coe_inj {s₁ s₂ : Finset α} : (s₁ : Set α) = s₂ ↔ s₁ = s₂ := - Set.ext_iff.trans ext_iff.symm + Set.ext_iff.trans Finset.ext_iff.symm theorem coe_injective {α} : Injective ((↑) : Finset α → Set α) := fun _s _t => coe_inj.1 @@ -774,9 +773,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 @@ -804,6 +807,11 @@ 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 + end Cons /-! ### disjoint -/ @@ -1039,7 +1047,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.subst <| mem_insert_self _ _) ha, congr_arg (insert · s)⟩ + ⟨fun h => eq_of_not_mem_of_mem_insert (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 @@ -1099,7 +1107,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 @@ -1428,7 +1436,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₁) : @@ -1443,6 +1451,10 @@ theorem singleton_inter_of_not_mem {a : α} {s : Finset α} (H : a ∉ s) : {a} eq_empty_of_forall_not_mem <| by simp only [mem_inter, mem_singleton]; rintro x ⟨rfl, h⟩; exact H h +lemma singleton_inter {a : α} {s : Finset α} : + {a} ∩ s = if a ∈ s then {a} else ∅ := by + split_ifs with h <;> simp [h] + @[simp] theorem inter_singleton_of_mem {a : α} {s : Finset α} (h : a ∈ s) : s ∩ {a} = {a} := by rw [inter_comm, singleton_inter_of_mem h] @@ -1451,6 +1463,10 @@ theorem inter_singleton_of_mem {a : α} {s : Finset α} (h : a ∈ s) : s ∩ {a theorem inter_singleton_of_not_mem {a : α} {s : Finset α} (h : a ∉ s) : s ∩ {a} = ∅ := by rw [inter_comm, singleton_inter_of_not_mem h] +lemma inter_singleton {a : α} {s : Finset α} : + s ∩ {a} = if a ∈ s then {a} else ∅ := by + split_ifs with h <;> simp [h] + @[mono, gcongr] theorem inter_subset_inter {x y s t : Finset α} (h : x ⊆ y) (h' : s ⊆ t) : x ∩ s ⊆ y ∩ t := by intro a a_in @@ -1472,7 +1488,7 @@ 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 _ _ @@ -1592,7 +1608,7 @@ theorem erase_empty (a : α) : erase ∅ a = ∅ := rfl protected lemma Nontrivial.erase_nonempty (hs : s.Nontrivial) : (s.erase a).Nonempty := - (hs.exists_ne a).imp $ by aesop + (hs.exists_ne a).imp <| by aesop @[simp] lemma erase_nonempty (ha : a ∈ s) : (s.erase a).Nonempty ↔ s.Nontrivial := by simp only [Finset.Nonempty, mem_erase, and_comm (b := _ ∈ _)] @@ -1630,7 +1646,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] @@ -1647,7 +1663,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 @@ -1745,7 +1761,7 @@ variable [DecidableEq α] {s t u v : Finset α} {a b : α} /-- `s \ t` is the set consisting of the elements of `s` that are not in `t`. -/ instance : SDiff (Finset α) := - ⟨fun s₁ s₂ => ⟨s₁.1 - s₂.1, nodup_of_le tsub_le_self s₁.2⟩⟩ + ⟨fun s₁ s₂ => ⟨s₁.1 - s₂.1, nodup_of_le (Multiset.sub_le_self ..) s₁.2⟩⟩ @[simp] theorem sdiff_val (s₁ s₂ : Finset α) : (s₁ \ s₂).val = s₁.val - s₂.val := @@ -1762,14 +1778,14 @@ theorem inter_sdiff_self (s₁ s₂ : Finset α) : s₁ ∩ (s₂ \ s₁) = ∅ instance : GeneralizedBooleanAlgebra (Finset α) := { sup_inf_sdiff := fun x y => by - simp only [ext_iff, mem_union, mem_sdiff, inf_eq_inter, sup_eq_union, mem_inter, + 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 [ext_iff, inter_sdiff_self, inter_empty, inter_assoc, false_iff_iff, inf_eq_inter, - not_mem_empty, bot_eq_empty, not_false_iff, implies_true] } + 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] @@ -1905,7 +1921,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] @@ -1961,9 +1977,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 @@ -2027,6 +2043,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 @@ -2082,10 +2100,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] @@ -2146,6 +2165,67 @@ as a `Finset α` (when a `DecidablePred (· ∈ t)` instance is available). -/ def filter (s : Finset α) : Finset α := ⟨_, s.2.filter p⟩ +end Finset.Filter + +namespace Mathlib.Meta +open Lean Elab Term Meta Batteries.ExtendedBinder + +/-- Return `true` if `expectedType?` is `some (Finset ?α)`, throws `throwUnsupportedSyntax` if it is +`some (Set ?α)`, and returns `false` otherwise. -/ +def knownToBeFinsetNotSet (expectedType? : Option Expr) : TermElabM Bool := + -- As we want to reason about the expected type, we would like to wait for it to be available. + -- However this means that if we fall back on `elabSetBuilder` we will have postponed. + -- This is undesirable as we want set builder notation to quickly elaborate to a `Set` when no + -- expected type is available. + -- tryPostponeIfNoneOrMVar expectedType? + match expectedType? with + | some expectedType => + match_expr expectedType with + -- If the expected type is known to be `Finset ?α`, return `true`. + | Finset _ => pure true + -- If the expected type is known to be `Set ?α`, give up. + | Set _ => throwUnsupportedSyntax + -- If the expected type is known to not be `Finset ?α` or `Set ?α`, return `false`. + | _ => pure false + -- If the expected type is not known, return `false`. + | none => pure false + +/-- Elaborate set builder notation for `Finset`. + +`{x ∈ s | p x}` is elaborated as `Finset.filter (fun x ↦ p x) s` if either the expected type is +`Finset ?α` or the expected type is not `Set ?α` and `s` has expected type `Finset ?α`. + +See also +* `Data.Set.Defs` for the `Set` builder notation elaborator that this elaborator partly overrides. +* `Data.Fintype.Basic` for the `Finset` builder notation elaborator handling syntax of the form + `{x | p x}`, `{x : α | p x}`, `{x ∉ s | p x}`, `{x ≠ a | p x}`. +* `Order.LocallyFinite.Basic` for the `Finset` builder notation elaborator handling syntax of the + form `{x ≤ a | p x}`, `{x ≥ a | p x}`, `{x < a | p x}`, `{x > a | p x}`. + +TODO: Write a delaborator +-/ +@[term_elab setBuilder] +def elabFinsetBuilderSep : TermElab + | `({ $x:ident ∈ $s:term | $p }), expectedType? => do + -- If the expected type is known to be `Set ?α`, give up. If it is not known to be `Set ?α` or + -- `Finset ?α`, check the expected type of `s`. + unless ← knownToBeFinsetNotSet expectedType? do + let ty ← try whnfR (← inferType (← elabTerm s none)) catch _ => throwUnsupportedSyntax + -- If the expected type of `s` is not known to be `Finset ?α`, give up. + match_expr ty with + | Finset _ => pure () + | _ => throwUnsupportedSyntax + -- Finally, we can elaborate the syntax as a finset. + -- TODO: Seems a bit wasteful to have computed the expected type but still use `expectedType?`. + elabTerm (← `(Finset.filter (fun $x:ident ↦ $p) $s)) expectedType? + | _, _ => throwUnsupportedSyntax + +end Mathlib.Meta + +namespace Finset +section Filter +variable (p q : α → Prop) [DecidablePred p] [DecidablePred q] {s t : Finset α} + @[simp] theorem filter_val (s : Finset α) : (filter p s).1 = s.1.filter p := rfl @@ -2242,7 +2322,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) : @@ -2271,6 +2351,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 _ _ _ @@ -2284,15 +2366,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 α] @@ -2325,7 +2402,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] @@ -2345,9 +2422,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 @@ -2395,7 +2469,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 @@ -2416,10 +2490,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 @@ -2430,9 +2500,13 @@ theorem filter_union_filter_neg_eq [∀ x, Decidable (¬p x)] (s : Finset α) : end -lemma filter_inj : s.filter p = t.filter p ↔ ∀ ⦃a⦄, p a → (a ∈ s ↔ a ∈ t) := by simp [ext_iff] +variable {p q} + +lemma filter_inj : s.filter p = t.filter p ↔ ∀ ⦃a⦄, p a → (a ∈ s ↔ a ∈ t) := by + simp [Finset.ext_iff] -lemma filter_inj' : s.filter p = s.filter q ↔ ∀ ⦃a⦄, a ∈ s → (p a ↔ q a) := by simp [ext_iff] +lemma filter_inj' : s.filter p = s.filter q ↔ ∀ ⦃a⦄, a ∈ s → (p a ↔ q a) := by + simp [Finset.ext_iff] end Filter @@ -2441,6 +2515,8 @@ end Filter section Range +open Nat + variable {n m l : ℕ} /-- `range n` is the set of natural numbers less than `n`. -/ @@ -2498,15 +2574,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 @@ -2519,13 +2599,17 @@ theorem range_filter_eq {n m : ℕ} : (range n).filter (· = m) = if m < n then lemma range_nontrivial {n : ℕ} (hn : 1 < n) : (Finset.range n).Nontrivial := by rw [Finset.Nontrivial, Finset.coe_range] - exact ⟨0, Nat.zero_lt_one.trans hn, 1, hn, zero_ne_one⟩ + 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 s _ ⟨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 @@ -2642,10 +2726,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] @@ -2775,10 +2862,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 @@ -2827,6 +2917,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] @@ -2976,6 +3071,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 @@ -3000,3 +3097,5 @@ def proveFinsetNonempty {u : Level} {α : Q(Type u)} (s : Q(Finset $α)) : Lean.getExprMVarAssignment? mvar end Mathlib.Meta + +set_option linter.style.longFile 3200 diff --git a/Mathlib/Data/Finset/Card.lean b/Mathlib/Data/Finset/Card.lean index 36650f6030a8e..6cd9aef810c64 100644 --- a/Mathlib/Data/Finset/Card.lean +++ b/Mathlib/Data/Finset/Card.lean @@ -296,7 +296,7 @@ theorem card_eq_of_bijective (f : ∀ i, i < n → α) (hf : ∀ a ∈ s, ∃ i, 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' @@ -426,7 +426,7 @@ lemma surj_on_of_inj_on_of_card_le (f : ∀ a ∈ s, β) (hf : ∀ a ha, f a ha intro ⟨_, _⟩ ⟨_, _⟩ h exact Subtype.eq <| hinj _ _ _ _ h obtain rfl : image (fun a : { a // a ∈ s } => f a a.prop) s.attach = t := - eq_of_subset_of_card_le (image_subset_iff.2 $ by simpa) (by simp [hst, h]) + eq_of_subset_of_card_le (image_subset_iff.2 <| by simpa) (by simp [hst, h]) simp only [mem_image, mem_attach, true_and, Subtype.exists, forall_exists_index] exact fun b a ha hb ↦ ⟨a, ha, hb.symm⟩ @@ -683,6 +683,11 @@ 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.card = n + 1 ↔ ∃ a t, ∃ (h : a ∉ t), cons a t h = s ∧ t.card = 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 α] @@ -826,6 +831,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 c486e085f6987..002513c40e808 100644 --- a/Mathlib/Data/Finset/Density.lean +++ b/Mathlib/Data/Finset/Density.lean @@ -4,8 +4,9 @@ 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 /-! # Density of a finite set @@ -82,10 +83,10 @@ protected alias ⟨_, Nonempty.dens_pos⟩ := dens_pos protected alias ⟨_, Nonempty.dens_ne_zero⟩ := dens_ne_zero lemma dens_le_dens (h : s ⊆ t) : dens s ≤ dens t := - div_le_div_of_nonneg_right (mod_cast card_mono h) $ by positivity + div_le_div_of_nonneg_right (mod_cast card_mono h) <| by positivity lemma dens_lt_dens (h : s ⊂ t) : dens s < dens t := - div_lt_div_of_pos_right (mod_cast card_strictMono h) $ by + div_lt_div_of_pos_right (mod_cast card_strictMono h) <| by cases isEmpty_or_nonempty α · simp [Subsingleton.elim s t, ssubset_irrfl] at h · exact mod_cast Fintype.card_pos @@ -102,6 +103,36 @@ lemma dens_map_le [Fintype β] (f : α ↪ β) : dens (s.map f) ≤ dens s := by · exact mod_cast Fintype.card_pos · exact Fintype.card_le_of_injective _ f.2 +@[simp] lemma dens_map_equiv [Fintype β] (e : α ≃ β) : (s.map e.toEmbedding).dens = s.dens := by + simp [dens, Fintype.card_congr e] + +lemma dens_image [Fintype β] [DecidableEq β] {f : α → β} (hf : Bijective f) (s : Finset α) : + (s.image f).dens = s.dens := by + simpa [map_eq_image, -dens_map_equiv] using dens_map_equiv (.ofBijective f hf) + +@[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 + +@[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 𝕜] + +@[simp] lemma natCast_card_mul_nnratCast_dens (s : Finset α) : + (Fintype.card α * s.dens : 𝕜) = s.card := mod_cast s.card_mul_dens + +@[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] + +end Semifield + section Nonempty variable [Nonempty α] @@ -114,6 +145,11 @@ lemma dens_ne_one : dens s ≠ 1 ↔ s ≠ univ := dens_eq_one.not end Nonempty +@[simp] lemma dens_le_one : s.dens ≤ 1 := by + cases isEmpty_or_nonempty α + · simp [Subsingleton.elim s ∅] + · simpa using dens_le_dens s.subset_univ + section Lattice variable [DecidableEq α] @@ -134,7 +170,7 @@ lemma dens_sdiff_add_dens (s t : Finset α) : dens (s \ t) + dens t = (s ∪ t). rw [← dens_union_of_disjoint sdiff_disjoint, sdiff_union_self_eq_union] lemma dens_sdiff_comm (h : card s = card t) : dens (s \ t) = dens (t \ s) := - add_left_injective (dens t) $ by + add_left_injective (dens t) <| by simp_rw [dens_sdiff_add_dens, union_comm s, ← dens_sdiff_add_dens, dens, h] @[simp] 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..3d7111a8e4605 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 diff --git a/Mathlib/Data/Finset/Fold.lean b/Mathlib/Data/Finset/Fold.lean index 06a0145f30d7f..39befbf6c8239 100644 --- a/Mathlib/Data/Finset/Fold.lean +++ b/Mathlib/Data/Finset/Fold.lean @@ -4,16 +4,15 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Mathlib.Algebra.Order.Monoid.Unbundled.MinMax +import Mathlib.Algebra.Order.Monoid.Unbundled.WithTop import Mathlib.Data.Finset.Image import Mathlib.Data.Multiset.Fold -import Mathlib.Algebra.Order.Monoid.Unbundled.WithTop /-! # The fold operation for a commutative associative operation over a finset. -/ --- TODO: --- assert_not_exists OrderedCommMonoid +assert_not_exists OrderedCommMonoid assert_not_exists MonoidWithZero namespace Finset diff --git a/Mathlib/Data/Finset/Functor.lean b/Mathlib/Data/Finset/Functor.lean index 2ae78966a4cd7..1359446c44d7e 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 @@ -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/Image.lean b/Mathlib/Data/Finset/Image.lean index e0e8779501a94..88939058da20c 100644 --- a/Mathlib/Data/Finset/Image.lean +++ b/Mathlib/Data/Finset/Image.lean @@ -129,7 +129,7 @@ theorem map_map (f : α ↪ β) (g : β ↪ γ) (s : Finset α) : (s.map f).map theorem map_comm {β'} {f : β ↪ γ} {g : α ↪ β} {f' : α ↪ β'} {g' : β' ↪ γ} (h_comm : ∀ a, f (g a) = g' (f' a)) : (s.map g).map f = (s.map f').map g' := by - simp_rw [map_map, Embedding.trans, Function.comp, h_comm] + simp_rw [map_map, Embedding.trans, Function.comp_def, h_comm] theorem _root_.Function.Semiconj.finset_map {f : α ↪ β} {ga : α ↪ α} {gb : β ↪ β} (h : Function.Semiconj f ga gb) : Function.Semiconj (map f) (map ga) (map gb) := fun _ => @@ -186,7 +186,7 @@ theorem filter_map {p : β → Prop} [DecidablePred p] : lemma map_filter' (p : α → Prop) [DecidablePred p] (f : α ↪ β) (s : Finset α) [DecidablePred (∃ a, p a ∧ f a = ·)] : (s.filter p).map f = (s.map f).filter fun b => ∃ a, p a ∧ f a = b := by - simp [(· ∘ ·), filter_map, f.injective.eq_iff] + simp [Function.comp_def, filter_map, f.injective.eq_iff] lemma filter_attach' [DecidableEq α] (s : Finset α) (p : s → Prop) [DecidablePred p] : s.attach.filter p = @@ -201,7 +201,7 @@ lemma filter_attach (p : α → Prop) [DecidablePred p] (s : Finset α) : theorem map_filter {f : α ≃ β} {p : α → Prop} [DecidablePred p] : (s.filter p).map f.toEmbedding = (s.map f.toEmbedding).filter (p ∘ f.symm) := by - simp only [filter_map, Function.comp, Equiv.toEmbedding_apply, Equiv.symm_apply_apply] + simp only [filter_map, Function.comp_def, Equiv.toEmbedding_apply, Equiv.symm_apply_apply] @[simp] theorem disjoint_map {s t : Finset α} (f : α ↪ β) : @@ -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] @@ -255,7 +256,7 @@ theorem map_nontrivial : (s.map f).Nontrivial ↔ s.Nontrivial := theorem attach_map_val {s : Finset α} : s.attach.map (Embedding.subtype _) = s := eq_of_veq <| by rw [map_val, attach_val]; exact Multiset.attach_map_val _ -theorem disjoint_range_addLeftEmbedding (a : ℕ) (s : Finset ℕ): +theorem disjoint_range_addLeftEmbedding (a : ℕ) (s : Finset ℕ) : Disjoint (range a) (map (addLeftEmbedding a) s) := by simp_rw [disjoint_left, mem_map, mem_range, addLeftEmbedding_apply] rintro _ h ⟨l, -, rfl⟩ @@ -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 @@ -392,7 +384,7 @@ theorem image_image [DecidableEq γ] {g : β → γ} : (s.image f).image g = s.i theorem image_comm {β'} [DecidableEq β'] [DecidableEq γ] {f : β → γ} {g : α → β} {f' : α → β'} {g' : β' → γ} (h_comm : ∀ a, f (g a) = g' (f' a)) : - (s.image g).image f = (s.image f').image g' := by simp_rw [image_image, comp, h_comm] + (s.image g).image f = (s.image f').image g' := by simp_rw [image_image, comp_def, h_comm] theorem _root_.Function.Semiconj.finset_image [DecidableEq α] {f : α → β} {ga : α → α} {gb : β → β} (h : Function.Semiconj f ga gb) : Function.Semiconj (image f) (image ga) (image gb) := fun _ => @@ -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₂ @@ -633,7 +633,7 @@ theorem mem_subtype {p : α → Prop} [DecidablePred p] {s : Finset α} : | ⟨a, ha⟩ => by simp [Finset.subtype, ha] theorem subtype_eq_empty {p : α → Prop} [DecidablePred p] {s : Finset α} : - s.subtype p = ∅ ↔ ∀ x, p x → x ∉ s := by simp [ext_iff, Subtype.forall, Subtype.coe_mk] + s.subtype p = ∅ ↔ ∀ x, p x → x ∉ s := by simp [Finset.ext_iff, Subtype.forall, Subtype.coe_mk] @[mono] theorem subtype_mono {p : α → Prop} [DecidablePred p] : Monotone (Finset.subtype p) := @@ -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 16acc98aceb59..b41a111701bda 100644 --- a/Mathlib/Data/Finset/Lattice.lean +++ b/Mathlib/Data/Finset/Lattice.lean @@ -5,21 +5,25 @@ 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. -/ --- TODO: --- assert_not_exists OrderedCommMonoid +assert_not_exists OrderedCommMonoid assert_not_exists MonoidWithZero open Function Multiset OrderDual @@ -205,9 +209,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 @@ -221,7 +222,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 @@ -521,7 +522,7 @@ theorem inf_sup {κ : ι → Type*} (s : Finset ι) (t : ∀ i, Finset (κ i)) ( -- Porting note: `simpa` doesn't support placeholders in proof terms have := h (fun j hj => if hji : j = i then cast (congr_arg κ hji.symm) a else g _ <| mem_of_mem_insert_of_ne hj hji) (fun j hj => ?_) - · simpa only [cast_eq, dif_pos, Function.comp, Subtype.coe_mk, dif_neg, aux] using this + · simpa only [cast_eq, dif_pos, Function.comp_def, Subtype.coe_mk, dif_neg, aux] using this rw [mem_insert] at hj obtain (rfl | hj) := hj · simpa @@ -705,7 +706,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] @@ -812,8 +813,9 @@ theorem _root_.map_finset_sup' [SemilatticeSup β] [FunLike F α β] [SupHomClas f (s.sup' hs g) = s.sup' hs (f ∘ g) := by refine hs.cons_induction ?_ ?_ <;> intros <;> simp [*] -lemma nsmul_sup' {α'} [LinearOrderedAddCommMonoid β] {s : Finset α'} - (hs : s.Nonempty) (f : α' → β) (n : ℕ) : +lemma nsmul_sup' {α β : Type*} [AddMonoid β] [LinearOrder β] + [CovariantClass β β (· + ·) (· ≤ ·)] [CovariantClass β β (swap (· + ·)) (· ≤ ·)] + {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 } (map_finset_sup' ns hs _).symm @@ -873,7 +875,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] @@ -963,8 +965,9 @@ theorem _root_.map_finset_inf' [SemilatticeInf β] [FunLike F α β] [InfHomClas f (s.inf' hs g) = s.inf' hs (f ∘ g) := by refine hs.cons_induction ?_ ?_ <;> intros <;> simp [*] -lemma nsmul_inf' {α'} [LinearOrderedAddCommMonoid β] {s : Finset α'} - (hs : s.Nonempty) (f : α' → β) (n : ℕ) : +lemma nsmul_inf' {α β : Type*} [AddMonoid β] [LinearOrder β] + [CovariantClass β β (· + ·) (· ≤ ·)] [CovariantClass β β (swap (· + ·)) (· ≤ ·)] + {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 } (map_finset_inf' ns hs _).symm @@ -1154,529 +1157,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 @@ -1725,228 +1205,3 @@ theorem sup_singleton' [DecidableEq α] (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 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 6d9a95ba9eb9e..534b98c618c6b 100644 --- a/Mathlib/Data/Finset/MulAntidiagonal.lean +++ b/Mathlib/Data/Finset/MulAntidiagonal.lean @@ -3,7 +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, Yaël Dillies -/ -import Mathlib.Data.Set.Pointwise.Basic +import Mathlib.Algebra.Group.Pointwise.Set.Basic +import Mathlib.Algebra.Order.Monoid.Defs import Mathlib.Data.Set.MulAntidiagonal /-! # Multiplication antidiagonal as a `Finset`. diff --git a/Mathlib/Data/Finset/NAry.lean b/Mathlib/Data/Finset/NAry.lean index 74ad2d6a47ad7..4db70840b348d 100644 --- a/Mathlib/Data/Finset/NAry.lean +++ b/Mathlib/Data/Finset/NAry.lean @@ -94,11 +94,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⟩ @@ -453,9 +454,9 @@ theorem card_dvd_card_image₂_left (hf : ∀ b ∈ t, Injective fun a => f a b) /-- 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 +464,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 diff --git a/Mathlib/Data/Finset/NatAntidiagonal.lean b/Mathlib/Data/Finset/NatAntidiagonal.lean index 012eccf69ede9..c5cb7f832ea29 100644 --- a/Mathlib/Data/Finset/NatAntidiagonal.lean +++ b/Mathlib/Data/Finset/NatAntidiagonal.lean @@ -151,7 +151,7 @@ theorem antidiagonal.snd_lt {n : ℕ} {kl : ℕ × ℕ} (hlk : kl ∈ antidiagon def antidiagonalEquivFin (n : ℕ) : antidiagonal n ≃ Fin (n + 1) where toFun := fun ⟨⟨i, j⟩, h⟩ ↦ ⟨i, antidiagonal.fst_lt h⟩ invFun := fun ⟨i, h⟩ ↦ ⟨⟨i, n - i⟩, by - rw [mem_antidiagonal, add_comm, tsub_add_cancel_iff_le] + 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 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 16af175533226..6074576260a47 100644 --- a/Mathlib/Data/Finset/NoncommProd.lean +++ b/Mathlib/Data/Finset/NoncommProd.lean @@ -39,16 +39,16 @@ 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 : β) : noncommFoldr f (l : Multiset α) comm b = l.foldr f b := by - simp only [noncommFoldr, coe_foldr, coe_attach, List.attach, List.attachWith, Function.comp] + simp only [noncommFoldr, coe_foldr, coe_attach, List.attach, List.attachWith, Function.comp_def] rw [← List.foldr_map] simp [List.map_pmap] @@ -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 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 d040789ab2d0d..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 @@ -65,7 +66,7 @@ maps provided that it is true on `fun _ ↦ ∅` and for any function `g : ∀ i `i : ι`, and `x ∉ g i`, `p g` implies `p (update g i (insert x (g i)))`. See also `Finset.induction_on_pi_max` and `Finset.induction_on_pi_min` for specialized versions -that require `∀ i, LinearOrder (α i)`. -/ +that require `∀ i, LinearOrder (α i)`. -/ theorem induction_on_pi {p : (∀ i, Finset (α i)) → Prop} (f : ∀ i, Finset (α i)) (h0 : p fun _ ↦ ∅) (step : ∀ (g : ∀ i, Finset (α i)) (i : ι), ∀ x ∉ g i, p g → p (update g i (insert x (g i)))) : p f := diff --git a/Mathlib/Data/Finset/Powerset.lean b/Mathlib/Data/Finset/Powerset.lean index 7fca063a429b2..6e8275f105d31 100644 --- a/Mathlib/Data/Finset/Powerset.lean +++ b/Mathlib/Data/Finset/Powerset.lean @@ -112,12 +112,12 @@ instance decidableForallOfDecidableSubsets {s : Finset α} {p : ∀ t ⊆ s, Pro /-- For predicate `p` decidable on subsets, it is decidable whether `p` holds for any subset. -/ instance decidableExistsOfDecidableSubsets' {s : Finset α} {p : Finset α → Prop} [∀ t, Decidable (p t)] : Decidable (∃ t ⊆ s, p t) := - decidable_of_iff (∃ (t : _) (_h : t ⊆ s), p t) $ by simp + decidable_of_iff (∃ (t : _) (_h : t ⊆ s), p t) <| by simp /-- For predicate `p` decidable on subsets, it is decidable whether `p` holds for every subset. -/ instance decidableForallOfDecidableSubsets' {s : Finset α} {p : Finset α → Prop} [∀ t, Decidable (p t)] : Decidable (∀ t ⊆ s, p t) := - decidable_of_iff (∀ (t : _) (_h : t ⊆ s), p t) $ by simp + decidable_of_iff (∀ (t : _) (_h : t ⊆ s), p t) <| by simp end Powerset @@ -195,7 +195,7 @@ theorem powersetCard_zero (s : Finset α) : s.powersetCard 0 = {∅} := by exact ⟨empty_subset s, rfl⟩⟩ lemma powersetCard_empty_subsingleton (n : ℕ) : - (powersetCard n (∅ : Finset α) : Set $ Finset α).Subsingleton := by + (powersetCard n (∅ : Finset α) : Set <| Finset α).Subsingleton := by simp [Set.Subsingleton, subset_empty] @[simp] @@ -209,9 +209,9 @@ theorem powersetCard_one (s : Finset α) : @[simp] lemma powersetCard_eq_empty : powersetCard n s = ∅ ↔ s.card < n := by - refine ⟨?_, fun h ↦ card_eq_zero.1 $ by rw [card_powersetCard, Nat.choose_eq_zero_of_lt h]⟩ + refine ⟨?_, fun h ↦ card_eq_zero.1 <| by rw [card_powersetCard, Nat.choose_eq_zero_of_lt h]⟩ contrapose! - exact fun h ↦ nonempty_iff_ne_empty.1 $ (exists_subset_card_eq h).imp $ by simp + exact fun h ↦ nonempty_iff_ne_empty.1 <| (exists_subset_card_eq h).imp <| by simp @[simp] lemma powersetCard_card_add (s : Finset α) (hn : 0 < n) : s.powersetCard (s.card + n) = ∅ := by simpa @@ -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 d5c3ba82dd978..657acee065919 100644 --- a/Mathlib/Data/Finset/Preimage.lean +++ b/Mathlib/Data/Finset/Preimage.lean @@ -21,7 +21,7 @@ namespace Finset section Preimage -/-- Preimage of `s : Finset β` under a map `f` injective on `f ⁻¹' s` as a `Finset`. -/ +/-- Preimage of `s : Finset β` under a map `f` injective on `f ⁻¹' s` as a `Finset`. -/ noncomputable def preimage (s : Finset β) (f : α → β) (hf : Set.InjOn f (f ⁻¹' ↑s)) : Finset α := (s.finite_toSet.preimage hf).toFinset @@ -80,6 +80,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 @@ -96,7 +100,7 @@ theorem preimage_subset {f : α ↪ β} {s : Finset β} {t : Finset α} (hs : s 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 +118,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/Sort.lean b/Mathlib/Data/Finset/Sort.lean index 418f537711a77..361e4f3721a7f 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 @@ -117,13 +137,13 @@ theorem sorted_last_eq_max' {s : Finset α} {h : (s.sort (· ≤ ·)).length - 1 < (s.sort (· ≤ ·)).length} : (s.sort (· ≤ ·))[(s.sort (· ≤ ·)).length - 1] = s.max' (by rw [length_sort] at h; exact card_pos.1 (lt_of_le_of_lt bot_le h)) := - sorted_last_eq_max'_aux _ _ _ + sorted_last_eq_max'_aux _ h _ theorem max'_eq_sorted_last {s : Finset α} {h : s.Nonempty} : s.max' h = (s.sort (· ≤ ·))[(s.sort (· ≤ ·)).length - 1]' (by simpa using Nat.sub_lt (card_pos.mpr h) Nat.zero_lt_one) := - (sorted_last_eq_max'_aux _ _ _).symm + (sorted_last_eq_max'_aux _ (by simpa using Nat.sub_lt (card_pos.mpr h) Nat.zero_lt_one) _).symm /-- Given a finset `s` of cardinality `k` in a linear order `α`, the map `orderIsoOfFin s h` is the increasing bijection between `Fin k` and `s` as an `OrderIso`. Here, `h` is a proof that @@ -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 @@ -241,3 +261,21 @@ theorem sort_univ (n : ℕ) : Finset.univ.sort (fun x y : Fin n => x ≤ y) = Li (List.pairwise_le_finRange n) end Fin + +/-- Given a `Fintype` `α` of cardinality `k`, the map `orderIsoFinOfCardEq s h` is the increasing +bijection between `Fin k` and `α` as an `OrderIso`. Here, `h` is a proof that the cardinality of `α` +is `k`. We use this instead of an iso `Fin (Fintype.card α) ≃o α` to avoid casting issues in further +uses of this function. -/ +def Fintype.orderIsoFinOfCardEq + (α : Type*) [LinearOrder α] [Fintype α] {k : ℕ} (h : Fintype.card α = k) : + Fin k ≃o α := + (Finset.univ.orderIsoOfFin h).trans + ((OrderIso.setCongr _ _ Finset.coe_univ).trans OrderIso.Set.univ) + +/-- Any finite linear order order-embeds into any infinite linear order. -/ +lemma nonempty_orderEmbedding_of_finite_infinite + (α : Type*) [LinearOrder α] [hα : Finite α] + (β : Type*) [LinearOrder β] [hβ : Infinite β] : Nonempty (α ↪o β) := by + haveI := Fintype.ofFinite α + obtain ⟨s, hs⟩ := Infinite.exists_subset_card_eq β (Fintype.card α) + exact ⟨((Fintype.orderIsoFinOfCardEq α rfl).symm.toOrderEmbedding).trans (s.orderEmbOfFin hs)⟩ diff --git a/Mathlib/Data/Finset/Sum.lean b/Mathlib/Data/Finset/Sum.lean index b07e704317ad9..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 `β`. -/ @@ -68,7 +70,7 @@ theorem inr_mem_disjSum : inr b ∈ s.disjSum t ↔ b ∈ t := Multiset.inr_mem_disjSum @[simp] -theorem disjSum_eq_empty : s.disjSum t = ∅ ↔ s = ∅ ∧ t = ∅ := by simp [ext_iff] +theorem disjSum_eq_empty : s.disjSum t = ∅ ↔ s = ∅ ∧ t = ∅ := by simp [Finset.ext_iff] theorem disjSum_mono (hs : s₁ ⊆ s₂) (ht : t₁ ⊆ t₂) : s₁.disjSum t₁ ⊆ s₂.disjSum t₂ := val_le_iff.1 <| Multiset.disjSum_mono (val_le_iff.2 hs) (val_le_iff.2 ht) @@ -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..5188385616bb7 100644 --- a/Mathlib/Data/Finset/Sups.lean +++ b/Mathlib/Data/Finset/Sups.lean @@ -99,10 +99,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 +146,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 @@ -245,10 +246,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 +293,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 @@ -480,6 +482,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 +494,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] @@ -551,9 +557,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 +582,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) @@ -625,10 +632,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..3df81fb5d2be1 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 = @@ -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/Basic.lean b/Mathlib/Data/Finsupp/Basic.lean index 30a1877ed23d9..a9e39269baa78 100644 --- a/Mathlib/Data/Finsupp/Basic.lean +++ b/Mathlib/Data/Finsupp/Basic.lean @@ -1,9 +1,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, Scott Morrison +Authors: Johannes Hölzl, Kim Morrison -/ import Mathlib.Algebra.BigOperators.Finsupp +import Mathlib.Algebra.Group.Action.Basic import Mathlib.Algebra.Module.Basic import Mathlib.Algebra.Regular.SMul import Mathlib.Data.Rat.BigOperators @@ -84,7 +85,8 @@ theorem not_mem_graph_snd_zero (a : α) (f : α →₀ M) : (a, (0 : M)) ∉ f.g @[simp] theorem image_fst_graph [DecidableEq α] (f : α →₀ M) : f.graph.image Prod.fst = f.support := by - classical simp only [graph, map_eq_image, image_image, Embedding.coeFn_mk, (· ∘ ·), image_id'] + classical + simp only [graph, map_eq_image, image_image, Embedding.coeFn_mk, Function.comp_def, image_id'] theorem graph_injective (α M) [Zero M] : Injective (@graph α M _) := by intro f g h @@ -620,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) @@ -1701,3 +1703,5 @@ theorem sigmaFinsuppAddEquivPiFinsupp_apply {α : Type*} {ιs : η → Type*} [A end Sigma end Finsupp + +set_option linter.style.longFile 1900 diff --git a/Mathlib/Data/Finsupp/Defs.lean b/Mathlib/Data/Finsupp/Defs.lean index c58fab65e2979..17844597d0e12 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 @@ -23,7 +23,7 @@ Functions with finite support are used (at least) in the following parts of the * the linear combination of a family of vectors `v i` with coefficients `f i` (as used, e.g., to define linearly independent family `LinearIndependent`) is defined as a map - `Finsupp.total : (ι → M) → (ι →₀ R) →ₗ[R] M`. + `Finsupp.linearCombination : (ι → M) → (ι →₀ R) →ₗ[R] M`. Some other constructions are naturally equivalent to `α →₀ M` with some `α` and `M` but are defined in a different way in the library: @@ -365,15 +365,18 @@ theorem unique_single_eq_iff [Unique α] {b' : M} : single a b = single a' b' rw [Finsupp.unique_ext_iff, Unique.eq_default a, Unique.eq_default a', single_eq_same, single_eq_same] -lemma apply_single [AddCommMonoid N] [AddCommMonoid P] - {F : Type*} [FunLike F N P] [AddMonoidHomClass F N P] (e : F) - (a : α) (n : N) (b : α) : +lemma apply_single' [Zero N] [Zero P] (e : N → P) (he : e 0 = 0) (a : α) (n : N) (b : α) : e ((single a n) b) = single a (e n) b := by classical simp only [single_apply] split_ifs · rfl - · exact map_zero e + · exact he + +lemma apply_single [Zero N] [Zero P] {F : Type*} [FunLike F N P] [ZeroHomClass F N P] + (e : F) (a : α) (n : N) (b : α) : + e ((single a n) b) = single a (e n) b := + apply_single' e (map_zero e) a n b theorem support_eq_singleton {f : α →₀ M} {a : α} : f.support = {a} ↔ f a ≠ 0 ∧ f = single a (f a) := @@ -711,6 +714,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 @@ -727,6 +734,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` -/ @@ -753,7 +768,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] @@ -907,6 +922,20 @@ theorem support_add_eq [DecidableEq α] {g₁ g₂ : α →₀ M} (h : Disjoint theorem single_add (a : α) (b₁ b₂ : M) : single a (b₁ + b₂) = single a b₁ + single a b₂ := (zipWith_single_single _ _ _ _ _).symm +theorem support_single_add {a : α} {b : M} {f : α →₀ M} (ha : a ∉ f.support) (hb : b ≠ 0) : + support (single a b + f) = cons a f.support ha := by + classical + have H := support_single_ne_zero a hb + rw [support_add_eq, H, cons_eq_insert, insert_eq] + rwa [H, disjoint_singleton_left] + +theorem support_add_single {a : α} {b : M} {f : α →₀ M} (ha : a ∉ f.support) (hb : b ≠ 0) : + support (f + single a b) = cons a f.support ha := by + classical + have H := support_single_ne_zero a hb + rw [support_add_eq, H, union_comm, cons_eq_insert, insert_eq] + rwa [H, disjoint_singleton_right] + instance instAddZeroClass : AddZeroClass (α →₀ M) := DFunLike.coe_injective.addZeroClass _ coe_zero coe_add @@ -1031,6 +1060,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/Lex.lean b/Mathlib/Data/Finsupp/Lex.lean index 887891452be35..9174fd421d429 100644 --- a/Mathlib/Data/Finsupp/Lex.lean +++ b/Mathlib/Data/Finsupp/Lex.lean @@ -55,10 +55,9 @@ theorem lex_lt_of_lt [PartialOrder N] (r) [IsStrictOrder α r] {x y : α →₀ DFinsupp.lex_lt_of_lt r (id hlt : x.toDFinsupp < y.toDFinsupp) instance Lex.isStrictOrder [LinearOrder α] [PartialOrder N] : - IsStrictOrder (Lex (α →₀ N)) (· < ·) := - let i : IsStrictOrder (Lex (α → N)) (· < ·) := Pi.Lex.isStrictOrder - { irrefl := toLex.surjective.forall.2 fun _ ↦ @irrefl _ _ i.toIsIrrefl _ - trans := toLex.surjective.forall₃.2 fun _ _ _ ↦ @trans _ _ i.toIsTrans _ _ _ } + IsStrictOrder (Lex (α →₀ N)) (· < ·) where + irrefl _ := lt_irrefl (α := Lex (α → N)) _ + trans _ _ _ := lt_trans (α := Lex (α → N)) variable [LinearOrder α] diff --git a/Mathlib/Data/Finsupp/Notation.lean b/Mathlib/Data/Finsupp/Notation.lean index ef547e495b37b..2091f9b3cb8d1 100644 --- a/Mathlib/Data/Finsupp/Notation.lean +++ b/Mathlib/Data/Finsupp/Notation.lean @@ -15,9 +15,7 @@ This file provides `fun₀ | 3 => a | 7 => b` notation for `Finsupp`, which desu namespace Finsupp -open Lean -open Lean.Parser -open Lean.Parser.Term +open Lean Parser Term -- A variant of `Lean.Parser.Term.matchAlts` with less line wrapping. @[nolint docBlame] -- we do not want any doc hover on this notation. diff --git a/Mathlib/Data/Finsupp/Order.lean b/Mathlib/Data/Finsupp/Order.lean index c77303cc05d77..2d4dbe742d79c 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,7 +69,7 @@ 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 @@ -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,11 +148,24 @@ 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 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/ToDFinsupp.lean b/Mathlib/Data/Finsupp/ToDFinsupp.lean index 53292b96ad67d..a66af26255602 100644 --- a/Mathlib/Data/Finsupp/ToDFinsupp.lean +++ b/Mathlib/Data/Finsupp/ToDFinsupp.lean @@ -8,7 +8,7 @@ import Mathlib.Data.DFinsupp.Basic import Mathlib.Data.Finsupp.Basic /-! -# Conversion between `Finsupp` and homogenous `DFinsupp` +# Conversion between `Finsupp` and homogeneous `DFinsupp` This module provides conversions between `Finsupp` and `DFinsupp`. It is in its own file since neither `Finsupp` or `DFinsupp` depend on each other. @@ -65,7 +65,7 @@ variable {ι : Type*} {R : Type*} {M : Type*} section Defs -/-- Interpret a `Finsupp` as a homogenous `DFinsupp`. -/ +/-- Interpret a `Finsupp` as a homogeneous `DFinsupp`. -/ def Finsupp.toDFinsupp [Zero M] (f : ι →₀ M) : Π₀ _ : ι, M where toFun := f support' := @@ -93,7 +93,7 @@ theorem toDFinsupp_support (f : ι →₀ M) : f.toDFinsupp.support = f.support ext simp -/-- Interpret a homogenous `DFinsupp` as a `Finsupp`. +/-- Interpret a homogeneous `DFinsupp` as a `Finsupp`. Note that the elaborator has a lot of trouble with this definition - it is often necessary to write `(DFinsupp.toFinsupp f : ι →₀ M)` instead of `f.toFinsupp`, as for some unknown reason diff --git a/Mathlib/Data/Finsupp/Weight.lean b/Mathlib/Data/Finsupp/Weight.lean index 8c24117e1132d..ed767ee615ac8 100644 --- a/Mathlib/Data/Finsupp/Weight.lean +++ b/Mathlib/Data/Finsupp/Weight.lean @@ -24,7 +24,7 @@ We fix a type `σ` and an `AddCommMonoid M`, as well as a function `w : σ → M - `Finsupp.weight` of a finitely supported function `f : σ →₀ ℕ` with respect to `w`: it is the sum `∑ (f i) • (w i)`. -It is an `AddMonoidHom` map defined using `Finsupp.total`. +It is an `AddMonoidHom` map defined using `Finsupp.linearCombination`. - `Finsupp.le_weight`says that `f s ≤ f.weight w` when `M = ℕ`` @@ -72,7 +72,7 @@ variable [AddCommMonoid M] /-- The `weight` of the finitely supported function `f : σ →₀ ℕ` with respect to `w : σ → M` is the sum `∑(f i)•(w i)`. -/ noncomputable def weight : (σ →₀ ℕ) →+ M := - (Finsupp.total σ M ℕ w).toAddMonoidHom + (Finsupp.linearCombination ℕ w).toAddMonoidHom @[deprecated weight (since := "2024-07-20")] alias _root_.MvPolynomial.weightedDegree := weight @@ -145,7 +145,7 @@ variable {M : Type*} [CanonicallyOrderedAddCommMonoid M] (w : σ → M) theorem le_weight_of_ne_zero' {s : σ} {f : σ →₀ ℕ} (hs : f s ≠ 0) : w s ≤ weight w f := - le_weight_of_ne_zero w (fun _ ↦ zero_le _) hs + le_weight_of_ne_zero (fun _ ↦ zero_le _) hs /-- If `M` is a `CanonicallyOrderedAddCommMonoid`, then `weight f` is zero iff `f=0. -/ theorem weight_eq_zero_iff_eq_zero @@ -157,7 +157,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 08d7bacc8a516..0ff3b973f0141 100644 --- a/Mathlib/Data/Fintype/Basic.lean +++ b/Mathlib/Data/Fintype/Basic.lean @@ -75,7 +75,7 @@ theorem mem_univ (x : α) : x ∈ (univ : Finset α) := theorem mem_univ_val : ∀ x, x ∈ (univ : Finset α).1 := mem_univ -theorem eq_univ_iff_forall : s = univ ↔ ∀ x, x ∈ s := by simp [ext_iff] +theorem eq_univ_iff_forall : s = univ ↔ ∀ x, x ∈ s := by simp [Finset.ext_iff] theorem eq_univ_of_forall : (∀ x, x ∈ s) → s = univ := eq_univ_iff_forall.2 @@ -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 ‹_› @@ -141,12 +141,71 @@ theorem codisjoint_left : Codisjoint s t ↔ ∀ ⦃a⦄, a ∉ s → a ∈ t := theorem codisjoint_right : Codisjoint s t ↔ ∀ ⦃a⦄, a ∉ t → a ∈ s := Codisjoint_comm.trans codisjoint_left -section BooleanAlgebra +instance booleanAlgebra [DecidableEq α] : BooleanAlgebra (Finset α) := + GeneralizedBooleanAlgebra.toBooleanAlgebra -variable [DecidableEq α] {a : α} +end Finset -instance booleanAlgebra : BooleanAlgebra (Finset α) := - GeneralizedBooleanAlgebra.toBooleanAlgebra +namespace Mathlib.Meta +open Lean Elab Term Meta Batteries.ExtendedBinder + +/-- Elaborate set builder notation for `Finset`. + +* `{x | p x}` is elaborated as `Finset.filter (fun x ↦ p x) Finset.univ` if the expected type is + `Finset ?α`. +* `{x : α | p x}` is elaborated as `Finset.filter (fun x : α ↦ p x) Finset.univ` if the expected + type is `Finset ?α`. +* `{x ∉ s | p x}` is elaborated as `Finset.filter (fun x ↦ p x) sᶜ` if either the expected type is + `Finset ?α` or the expected type is not `Set ?α` and `s` has expected type `Finset ?α`. +* `{x ≠ a | p x}` is elaborated as `Finset.filter (fun x ↦ p x) {a}ᶜ` if the expected type is + `Finset ?α`. + +See also +* `Data.Set.Defs` for the `Set` builder notation elaborator that this elaborator partly overrides. +* `Data.Finset.Basic` for the `Finset` builder notation elaborator partly overriding this one for + syntax of the form `{x ∈ s | p x}`. +* `Data.Fintype.Basic` for the `Finset` builder notation elaborator handling syntax of the form + `{x | p x}`, `{x : α | p x}`, `{x ∉ s | p x}`, `{x ≠ a | p x}`. +* `Order.LocallyFinite.Basic` for the `Finset` builder notation elaborator handling syntax of the + form `{x ≤ a | p x}`, `{x ≥ a | p x}`, `{x < a | p x}`, `{x > a | p x}`. + +TODO: Write a delaborator +-/ +@[term_elab setBuilder] +def elabFinsetBuilderSetOf : TermElab + | `({ $x:ident | $p }), expectedType? => do + -- If the expected type is not known to be `Finset ?α`, give up. + unless ← knownToBeFinsetNotSet expectedType? do throwUnsupportedSyntax + elabTerm (← `(Finset.filter (fun $x:ident ↦ $p) Finset.univ)) expectedType? + | `({ $x:ident : $t | $p }), expectedType? => do + -- If the expected type is not known to be `Finset ?α`, give up. + unless ← knownToBeFinsetNotSet expectedType? do throwUnsupportedSyntax + elabTerm (← `(Finset.filter (fun $x:ident : $t ↦ $p) Finset.univ)) expectedType? + | `({ $x:ident ∉ $s:term | $p }), expectedType? => do + -- If the expected type is known to be `Set ?α`, give up. If it is not known to be `Set ?α` or + -- `Finset ?α`, check the expected type of `s`. + unless ← knownToBeFinsetNotSet expectedType? do + let ty ← try whnfR (← inferType (← elabTerm s none)) catch _ => throwUnsupportedSyntax + -- If the expected type of `s` is not known to be `Finset ?α`, give up. + match_expr ty with + | Finset _ => pure () + | _ => throwUnsupportedSyntax + -- Finally, we can elaborate the syntax as a finset. + -- TODO: Seems a bit wasteful to have computed the expected type but still use `expectedType?`. + elabTerm (← `(Finset.filter (fun $x:ident ↦ $p) $sᶜ)) expectedType? + | `({ $x:ident ≠ $a | $p }), expectedType? => do + -- If the expected type is not known to be `Finset ?α`, give up. + unless ← knownToBeFinsetNotSet expectedType? do throwUnsupportedSyntax + elabTerm (← `(Finset.filter (fun $x:ident ↦ $p) (singleton $a)ᶜ)) expectedType? + | _, _ => throwUnsupportedSyntax + +end Mathlib.Meta + +namespace Finset +variable [Fintype α] {s t : Finset α} + +section BooleanAlgebra +variable [DecidableEq α] {a : α} theorem sdiff_eq_inter_compl (s t : Finset α) : s \ t = s ∩ tᶜ := sdiff_eq @@ -211,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)] @@ -288,7 +347,7 @@ namespace Finset variable {s t : Finset α} @[simp] lemma subtype_eq_univ {p : α → Prop} [DecidablePred p] [Fintype {a // p a}] : - s.subtype p = univ ↔ ∀ ⦃a⦄, p a → a ∈ s := by simp [ext_iff] + s.subtype p = univ ↔ ∀ ⦃a⦄, p a → a ∈ s := by simp [Finset.ext_iff] @[simp] lemma subtype_univ [Fintype α] (p : α → Prop) [DecidablePred p] [Fintype {a // p a}] : univ.subtype p = univ := by simp @@ -433,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 @@ -509,7 +568,7 @@ def ofEquiv (α : Type*) [Fintype α] (f : α ≃ β) : Fintype β := def ofSubsingleton (a : α) [Subsingleton α] : Fintype α := ⟨{a}, fun _ => Finset.mem_singleton.2 (Subsingleton.elim _ _)⟩ --- In principle, this could be a `simp` theorem but it applies to any occurence of `univ` and +-- In principle, this could be a `simp` theorem but it applies to any occurrence of `univ` and -- required unification of the (possibly very complex) `Fintype` instances. theorem univ_ofSubsingleton (a : α) [Subsingleton α] : @univ _ (ofSubsingleton a) = {a} := rfl @@ -533,7 +592,7 @@ namespace Set variable {s t : Set α} -/-- Construct a finset enumerating a set `s`, given a `Fintype` instance. -/ +/-- Construct a finset enumerating a set `s`, given a `Fintype` instance. -/ def toFinset (s : Set α) [Fintype s] : Finset α := (@Finset.univ s _).map <| Function.Embedding.subtype _ @@ -562,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]⟩ @@ -661,7 +723,7 @@ theorem toFinset_eq_univ [Fintype α] [Fintype s] : s.toFinset = Finset.univ ↔ @[simp] theorem toFinset_setOf [Fintype α] (p : α → Prop) [DecidablePred p] [Fintype { x | p x }] : - { x | p x }.toFinset = Finset.univ.filter p := by + Set.toFinset {x | p x} = Finset.univ.filter p := by ext simp diff --git a/Mathlib/Data/Fintype/BigOperators.lean b/Mathlib/Data/Fintype/BigOperators.lean index 02838b7dad046..b772a62fd0956 100644 --- a/Mathlib/Data/Fintype/BigOperators.lean +++ b/Mathlib/Data/Fintype/BigOperators.lean @@ -148,7 +148,7 @@ lemma card_filter_piFinset_eq_of_mem [∀ i, DecidableEq (α i)] 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) := - (card_filter_piFinset_eq_of_mem _ _ hx).trans $ by + (card_filter_piFinset_eq_of_mem _ _ hx).trans <| by rw [prod_const s.card, card_erase_of_mem (mem_univ _), card_univ] lemma card_filter_piFinset_eq [∀ i, DecidableEq (α i)] (s : ∀ i, Finset (α i)) (i : ι) (a : α i) : @@ -161,13 +161,13 @@ lemma card_filter_piFinset_eq [∀ i, DecidableEq (α i)] (s : ∀ i, Finset (α 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 := - (card_filter_piFinset_eq _ _ _).trans $ by + (card_filter_piFinset_eq _ _ _).trans <| by rw [prod_const s.card, card_erase_of_mem (mem_univ _), card_univ] end Fintype end Pi --- TODO: this is a basic thereom about `Fintype.card`, +-- TODO: this is a basic theorem about `Fintype.card`, -- and ideally could be moved to `Mathlib.Data.Fintype.Card`. theorem Fintype.card_fun [DecidableEq α] [Fintype α] [Fintype β] : Fintype.card (α → β) = Fintype.card β ^ Fintype.card α := by @@ -224,26 +224,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 4c50104e54305..45c0a90562ef5 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*} @@ -77,7 +75,7 @@ See `Fintype.truncFinBijection` for a version without `[DecidableEq α]`. def truncEquivFin (α) [DecidableEq α] [Fintype α] : Trunc (α ≃ Fin (card α)) := by unfold card Finset.card exact - Quot.recOnSubsingleton' + Quot.recOnSubsingleton (motive := fun s : Multiset α => (∀ x : α, x ∈ s) → s.Nodup → Trunc (α ≃ Fin (Multiset.card s))) univ.val @@ -106,7 +104,7 @@ given `[DecidableEq α]`. def truncFinBijection (α) [Fintype α] : Trunc { f : Fin (card α) → α // Bijective f } := by unfold card Finset.card refine - Quot.recOnSubsingleton' + Quot.recOnSubsingleton (motive := fun s : Multiset α => (∀ x : α, x ∈ s) → s.Nodup → Trunc {f : Fin (Multiset.card s) → α // Bijective f}) univ.val @@ -295,6 +293,10 @@ 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 @@ -542,7 +544,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) @@ -815,7 +817,7 @@ theorem wellFounded_of_trans_of_irrefl (r : α → α → Prop) [IsTrans α r] [ fun x y hxy => 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⟩⟩⟩ diff --git a/Mathlib/Data/Fintype/Fin.lean b/Mathlib/Data/Fintype/Fin.lean index bdd198e51a477..9c66b04ae7c46 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,20 @@ 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]) + if p 0 then (univ.filter (p ∘ Fin.succ)).card + 1 else (univ.filter (p ∘ Fin.succ)).card := by + rw [Fin.univ_succ, filter_cons, apply_ite Finset.card, card_cons, filter_map, card_map]; rfl + +theorem card_filter_univ_succ' (p : Fin (n + 1) → Prop) [DecidablePred p] : + (univ.filter p).card = ite (p 0) 1 0 + (univ.filter (p ∘ Fin.succ)).card := by + 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 induction' v with n x xs hxs · simp - · simp_rw [card_filter_univ_succ', Vector.get_cons_zero, Vector.toList_cons, Function.comp, + · 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] 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/Order.lean b/Mathlib/Data/Fintype/Order.lean index daef09e27fc55..6fa3b6c7e32fd 100644 --- a/Mathlib/Data/Fintype/Order.lean +++ b/Mathlib/Data/Fintype/Order.lean @@ -156,15 +156,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 -/ @@ -188,7 +210,7 @@ variable {α : Type*} {r : α → α → Prop} [IsTrans α r] {β γ : Type*} [N theorem Directed.finite_set_le (D : Directed r f) {s : Set γ} (hs : s.Finite) : ∃ z, ∀ i ∈ s, r (f i) (f z) := by - convert D.finset_le hs.toFinset; rw [Set.Finite.mem_toFinset] + convert D.finset_le hs.toFinset using 3; rw [Set.Finite.mem_toFinset] theorem Directed.finite_le (D : Directed r f) (g : β → γ) : ∃ z, ∀ i, r (f (g i)) (f z) := by classical @@ -211,12 +233,14 @@ theorem Set.Finite.exists_ge [IsDirected α (· ≥ ·)] {s : Set α} (hs : s.Fi ∃ M, ∀ i ∈ s, M ≤ i := directed_id.finite_set_le (r := (· ≥ ·)) hs +@[simp] theorem Finite.bddAbove_range [IsDirected α (· ≤ ·)] (f : β → α) : BddAbove (Set.range f) := by obtain ⟨M, hM⟩ := Finite.exists_le f refine ⟨M, fun a ha => ?_⟩ obtain ⟨b, rfl⟩ := ha exact hM b +@[simp] theorem Finite.bddBelow_range [IsDirected α (· ≥ ·)] (f : β → α) : BddBelow (Set.range f) := by obtain ⟨M, hM⟩ := Finite.exists_ge f refine ⟨M, fun a ha => ?_⟩ diff --git a/Mathlib/Data/Fintype/Perm.lean b/Mathlib/Data/Fintype/Perm.lean index 4e2bc19dc273d..47dbd625b6d70 100644 --- a/Mathlib/Data/Fintype/Perm.lean +++ b/Mathlib/Data/Fintype/Perm.lean @@ -36,7 +36,7 @@ theorem length_permsOfList : ∀ l : List α, length (permsOfList l) = l.length | [] => rfl | a :: l => by rw [length_cons, Nat.factorial_succ] - simp only [permsOfList, length_append, length_permsOfList, length_bind, comp, + simp only [permsOfList, length_append, length_permsOfList, length_bind, comp_def, length_map, map_const', sum_replicate, smul_eq_mul, succ_mul] ring @@ -46,7 +46,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)) diff --git a/Mathlib/Data/Fintype/Pi.lean b/Mathlib/Data/Fintype/Pi.lean index a216886258a7e..99a88bda7004a 100644 --- a/Mathlib/Data/Fintype/Pi.lean +++ b/Mathlib/Data/Fintype/Pi.lean @@ -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 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..1675f05ea0a49 100644 --- a/Mathlib/Data/Fintype/Quotient.lean +++ b/Mathlib/Data/Fintype/Quotient.lean @@ -63,7 +63,7 @@ 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) diff --git a/Mathlib/Data/Fintype/Sigma.lean b/Mathlib/Data/Fintype/Sigma.lean index de9ae773d01eb..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 @@ -30,6 +30,7 @@ lemma Set.biUnion_finsetSigma_univ' (s : Finset ι) (f : Π i, κ i → Set α) lemma Set.biInter_finsetSigma_univ (s : Finset ι) (f : Sigma κ → Set α) : ⋂ ij ∈ s.sigma fun _ ↦ Finset.univ, f ij = ⋂ i ∈ s, ⋂ j, f ⟨i, j⟩ := by aesop +attribute [local simp] Sigma.forall in lemma Set.biInter_finsetSigma_univ' (s : Finset ι) (f : Π i, κ i → Set α) : ⋂ i ∈ s, ⋂ j, f i j = ⋂ ij ∈ s.sigma fun _ ↦ Finset.univ, f ij.1 ij.2 := by aesop diff --git a/Mathlib/Data/FunLike/Basic.lean b/Mathlib/Data/FunLike/Basic.lean index f23481b549544..3a04435a85ca6 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] 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/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 index 8f45148a5452b..70c7b26e8b80d 100644 --- a/Mathlib/Data/Int/Align.lean +++ b/Mathlib/Data/Int/Align.lean @@ -4,6 +4,7 @@ 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 646ee6284ae3e..664c817a6e578 100644 --- a/Mathlib/Data/Int/Bitwise.lean +++ b/Mathlib/Data/Int/Bitwise.lean @@ -24,7 +24,7 @@ def div2 : ℤ → ℤ | (n : ℕ) => n.div2 | -[n +1] => negSucc n.div2 -/-- `bodd n` returns `true` if `n` is odd-/ +/-- `bodd n` returns `true` if `n` is odd -/ def bodd : ℤ → Bool | (n : ℕ) => n.bodd | -[n +1] => not (n.bodd) @@ -81,7 +81,7 @@ def ldiff : ℤ → ℤ → ℤ | -[m +1], -[n +1] => Nat.ldiff n m -- Porting note: I don't know why `Nat.xor'` got the prime, but I'm matching this change here -/-- `xor` computes the bitwise `xor` of two natural numbers-/ +/-- `xor` computes the bitwise `xor` of two natural numbers -/ protected def xor : ℤ → ℤ → ℤ | (m : ℕ), (n : ℕ) => (m ^^^ n) | (m : ℕ), -[n +1] => -[(m ^^^ n) +1] diff --git a/Mathlib/Data/Int/CardIntervalMod.lean b/Mathlib/Data/Int/CardIntervalMod.lean index 8b80171fc546a..b5725e3f43eb6 100644 --- a/Mathlib/Data/Int/CardIntervalMod.lean +++ b/Mathlib/Data/Int/CardIntervalMod.lean @@ -43,14 +43,14 @@ 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 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 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 @@ -125,7 +125,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 +139,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/Defs.lean b/Mathlib/Data/Int/Defs.lean index 313c5e9be0e6e..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 @@ -234,7 +234,7 @@ where conv => rhs; exact b.add_zero.symm rw [Int.add_lt_add_iff_left]; apply negSucc_lt_zero -variable (b) {z b b H0 Hs Hp} +variable {z b H0 Hs Hp} lemma inductionOn'_self : b.inductionOn' b H0 Hs Hp = H0 := cast_eq_iff_heq.mpr <| .symm <| by rw [b.sub_self, ← cast_eq_iff_heq]; rfl @@ -333,9 +333,9 @@ lemma natAbs_add_of_nonpos {a b : Int} (ha : a ≤ 0) (hb : b ≤ 0) : lemma natAbs_surjective : natAbs.Surjective := fun n => ⟨n, natAbs_ofNat n⟩ lemma natAbs_pow (n : ℤ) (k : ℕ) : Int.natAbs (n ^ k) = Int.natAbs n ^ k := by - induction' k with k ih - · rfl - · rw [Int.pow_succ, natAbs_mul, Nat.pow_succ, ih, Nat.mul_comm] + induction k with + | zero => rfl + | succ k ih => rw [Int.pow_succ, natAbs_mul, Nat.pow_succ, ih, Nat.mul_comm] lemma pow_right_injective (h : 1 < a.natAbs) : ((a ^ ·) : ℕ → ℤ).Injective := by refine (?_ : (natAbs ∘ (a ^ · : ℕ → ℤ)).Injective).of_comp @@ -562,13 +562,12 @@ lemma lt_of_toNat_lt {a b : ℤ} (h : toNat a < toNat b) : a < b := (toNat_lt_toNat <| lt_toNat.1 <| Nat.lt_of_le_of_lt (Nat.zero_le _) h).1 h @[simp] lemma toNat_pred_coe_of_pos {i : ℤ} (h : 0 < i) : ((i.toNat - 1 : ℕ) : ℤ) = i - 1 := by - simp [h, Int.le_of_lt h, push_cast] + simp only [lt_toNat, Nat.cast_ofNat_Int, h, natCast_pred_of_pos, Int.le_of_lt h, toNat_of_nonneg] @[simp] lemma toNat_eq_zero : ∀ {n : ℤ}, n.toNat = 0 ↔ n ≤ 0 | (n : ℕ) => by simp | -[n+1] => by simpa [toNat] using Int.le_of_lt (negSucc_lt_zero n) -@[simp] theorem toNat_sub_of_le {a b : ℤ} (h : b ≤ a) : (toNat (a - b) : ℤ) = a - b := Int.toNat_of_nonneg (Int.sub_nonneg_of_le h) @@ -604,3 +603,5 @@ attribute [simp] natCast_pow @[deprecated (since := "2024-04-02")] alias sign_coe_nat_of_nonzero := sign_natCast_of_ne_zero @[deprecated (since := "2024-04-02")] alias toNat_coe_nat := toNat_natCast @[deprecated (since := "2024-04-02")] alias toNat_coe_nat_add_one := toNat_natCast_add_one + +end Int diff --git a/Mathlib/Data/Int/DivMod.lean b/Mathlib/Data/Int/DivMod.lean new file mode 100644 index 0000000000000..e2d8db47293a8 --- /dev/null +++ b/Mathlib/Data/Int/DivMod.lean @@ -0,0 +1,20 @@ +/- +Copyright (c) 2024 Lean FRO. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kim Morrison +-/ + +/-! +# 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 diff --git a/Mathlib/Data/Int/GCD.lean b/Mathlib/Data/Int/GCD.lean index 108bf803cbc6f..6c4e2b4ad9ed9 100644 --- a/Mathlib/Data/Int/GCD.lean +++ b/Mathlib/Data/Int/GCD.lean @@ -5,9 +5,9 @@ Authors: Sangwoo Jo (aka Jason), Guy Leroy, Johannes Hölzl, Mario Carneiro -/ import Mathlib.Algebra.Group.Int import Mathlib.Algebra.GroupWithZero.Semiconj -import Mathlib.Order.Bounds.Basic import Mathlib.Algebra.Group.Commute.Units import Mathlib.Data.Nat.GCD.Basic +import Mathlib.Order.Bounds.Basic /-! # Extended GCD and divisibility over ℤ @@ -322,7 +322,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 9788ca3705b51..ce53928746469 100644 --- a/Mathlib/Data/Int/Interval.lean +++ b/Mathlib/Data/Int/Interval.lean @@ -112,9 +112,7 @@ theorem card_Ioo : (Ioo a b).card = (b - a - 1).toNat := (card_map _).trans <| c @[simp] theorem card_uIcc : (uIcc a b).card = (b - a).natAbs + 1 := (card_map _).trans <| - Int.ofNat.inj <| by - -- Porting note (#11215): TODO: Restore `Int.ofNat.inj` and remove the `change` - change ((↑) : ℕ → ℤ) _ = ((↑) : ℕ → ℤ) _ + (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] @@ -184,7 +182,7 @@ theorem image_Ico_emod (n a : ℤ) (h : 0 ≤ a) : (Ico n (n + a)).image (· % a · exact hn.symm.le.trans (add_le_add_right hi _) · rw [add_comm n a] refine add_lt_add_of_lt_of_le hia.right (le_trans ?_ hn.le) - simp only [zero_le, le_add_iff_nonneg_left] + simp only [Nat.zero_le, le_add_iff_nonneg_left] exact Int.emod_nonneg n (ne_of_gt ha) · rw [Int.add_mul_emod_self_left, Int.emod_eq_of_lt hia.left hia.right] diff --git a/Mathlib/Data/Int/Lemmas.lean b/Mathlib/Data/Int/Lemmas.lean index 9300c6b89865c..61ccb22c02adb 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 /-! diff --git a/Mathlib/Data/Int/Log.lean b/Mathlib/Data/Int/Log.lean index adc07b2f77f74..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 _ @@ -122,21 +121,30 @@ theorem log_zero_right (b : ℕ) : log b (0 : R) = 0 := theorem log_one_right (b : ℕ) : log b (1 : R) = 0 := by rw [log_of_one_le_right _ le_rfl, Nat.floor_one, Nat.log_one_right, Int.ofNat_zero] +@[simp] +theorem log_zero_left (r : R) : log 0 r = 0 := by + simp only [log, Nat.log_zero_left, Nat.cast_zero, Nat.clog_zero_left, neg_zero, ite_self] + +@[simp] +theorem log_one_left (r : R) : log 1 r = 0 := by + by_cases hr : 1 ≤ r + · simp_all only [log, ↓reduceIte, Nat.log_one_left, Nat.cast_zero] + · simp only [log, Nat.log_one_left, Nat.cast_zero, Nat.clog_one_left, neg_zero, ite_self] + -- 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₁) @@ -150,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} @@ -193,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] @@ -225,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 := @@ -243,6 +251,16 @@ theorem clog_zero_right (b : ℕ) : clog b (0 : R) = 0 := theorem clog_one_right (b : ℕ) : clog b (1 : R) = 0 := by rw [clog_of_one_le_right _ le_rfl, Nat.ceil_one, Nat.clog_one_right, Int.ofNat_zero] +@[simp] +theorem clog_zero_left (r : R) : clog 0 r = 0 := by + by_cases hr : 1 ≤ r + · simp only [clog, Nat.clog_zero_left, Nat.cast_zero, Nat.log_zero_left, neg_zero, ite_self] + · simp only [clog, hr, ite_cond_eq_false, Nat.log_zero_left, Nat.cast_zero, neg_zero] + +@[simp] +theorem clog_one_left (r : R) : clog 1 r = 0 := by + simp only [clog, Nat.log_one_left, Nat.cast_zero, Nat.clog_one_left, neg_zero, ite_self] + -- Porting note: needed to replace b ^ z with (b : R) ^ z in the below theorem clog_zpow {b : ℕ} (hb : 1 < b) (z : ℤ) : clog b ((b : R) ^ z : R) = z := by rw [← neg_log_inv_eq_clog, ← zpow_neg, log_zpow hb, neg_neg] @@ -251,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/Notation.lean b/Mathlib/Data/Int/Notation.lean index 7db60724ac2a7..57ac150fcbfe1 100644 --- a/Mathlib/Data/Int/Notation.lean +++ b/Mathlib/Data/Int/Notation.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad -/ +import Mathlib.Init /-! # Notation `ℤ` for the integers. -/ diff --git a/Mathlib/Data/Int/Order/Basic.lean b/Mathlib/Data/Int/Order/Basic.lean new file mode 100644 index 0000000000000..4fcb9a0a8f8f8 --- /dev/null +++ b/Mathlib/Data/Int/Order/Basic.lean @@ -0,0 +1,69 @@ +/- +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.Data.Int.Notation +import Mathlib.Data.Nat.Notation +import Mathlib.Order.Defs + +/-! +# The order relation on the integers +-/ + +open Nat + +namespace Int + +export private decNonneg from Init.Data.Int.Basic + +theorem le.elim {a b : ℤ} (h : a ≤ b) {P : Prop} (h' : ∀ n : ℕ, a + ↑n = b → P) : P := + Exists.elim (le.dest h) h' + +alias ⟨le_of_ofNat_le_ofNat, ofNat_le_ofNat_of_le⟩ := ofNat_le + +theorem lt.elim {a b : ℤ} (h : a < b) {P : Prop} (h' : ∀ n : ℕ, a + ↑(Nat.succ n) = b → P) : P := + Exists.elim (lt.dest h) h' + +alias ⟨lt_of_ofNat_lt_ofNat, ofNat_lt_ofNat_of_lt⟩ := ofNat_lt + +instance instLinearOrder : LinearOrder ℤ where + le := (·≤·) + le_refl := Int.le_refl + le_trans := @Int.le_trans + le_antisymm := @Int.le_antisymm + lt := (·<·) + lt_iff_le_not_le := @Int.lt_iff_le_not_le + le_total := Int.le_total + decidableEq := by infer_instance + decidableLE := by infer_instance + decidableLT := by infer_instance + +@[deprecated (since := "2024-07-27")] alias mul_neg_eq_neg_mul_symm := Int.mul_neg +@[deprecated (since := "2024-07-27")] alias neg_mul_eq_neg_mul_symm := Int.neg_mul + +protected theorem eq_zero_or_eq_zero_of_mul_eq_zero {a b : ℤ} (h : a * b = 0) : a = 0 ∨ b = 0 := + Int.mul_eq_zero.mp h + +theorem nonneg_or_nonpos_of_mul_nonneg {a b : ℤ} : 0 ≤ a * b → 0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0 := by + intro h + by_cases ha : 0 ≤ a <;> by_cases hb : 0 ≤ b + · exact .inl ⟨ha, hb⟩ + · refine .inr ⟨?_, le_of_not_le hb⟩ + obtain _ | _ := Int.mul_eq_zero.mp <| + Int.le_antisymm (Int.mul_nonpos_of_nonneg_of_nonpos ha <| le_of_not_le hb) h + all_goals omega + · refine .inr ⟨le_of_not_le ha, ?_⟩ + obtain _ | _ := Int.mul_eq_zero.mp <| + Int.le_antisymm (Int.mul_nonpos_of_nonpos_of_nonneg (le_of_not_le ha) hb) h + all_goals omega + · exact .inr ⟨le_of_not_ge ha, le_of_not_ge hb⟩ + +theorem mul_nonneg_of_nonneg_or_nonpos {a b : ℤ} : 0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0 → 0 ≤ a * b + | .inl ⟨ha, hb⟩ => Int.mul_nonneg ha hb + | .inr ⟨ha, hb⟩ => Int.mul_nonneg_of_nonpos_of_nonpos ha hb + +protected theorem mul_nonneg_iff {a b : ℤ} : 0 ≤ a * b ↔ 0 ≤ a ∧ 0 ≤ b ∨ a ≤ 0 ∧ b ≤ 0 := + ⟨nonneg_or_nonpos_of_mul_nonneg, mul_nonneg_of_nonneg_or_nonpos⟩ +end Int diff --git a/Mathlib/Data/Int/Order/Lemmas.lean b/Mathlib/Data/Int/Order/Lemmas.lean index e7bc9e148fc42..d664a5b284aca 100644 --- a/Mathlib/Data/Int/Order/Lemmas.lean +++ b/Mathlib/Data/Int/Order/Lemmas.lean @@ -34,15 +34,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/Sqrt.lean b/Mathlib/Data/Int/Sqrt.lean index 8a9136358543f..1c6db061ba8f7 100644 --- a/Mathlib/Data/Int/Sqrt.lean +++ b/Mathlib/Data/Int/Sqrt.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau -/ import Mathlib.Data.Int.Defs -import Mathlib.Data.Nat.Defs +import Mathlib.Data.Nat.Sqrt import Mathlib.Tactic.Common /-! diff --git a/Mathlib/Data/Int/Star.lean b/Mathlib/Data/Int/Star.lean index c654adbb78ad6..b4e7290794d36 100644 --- a/Mathlib/Data/Int/Star.lean +++ b/Mathlib/Data/Int/Star.lean @@ -3,10 +3,11 @@ 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.Star.Order import Mathlib.Algebra.Order.Group.Abs import Mathlib.Algebra.Order.Monoid.Submonoid import Mathlib.Algebra.Order.Ring.Basic +import Mathlib.Algebra.Order.Ring.Int +import Mathlib.Algebra.Order.Star.Basic /-! # Star ordered ring structure on `ℤ` @@ -23,13 +24,13 @@ namespace Int refine le_antisymm (closure_le.2 <| range_subset_iff.2 hn.pow_nonneg) fun x hx ↦ ?_ have : x = x.natAbs • 1 ^ n := by simpa [eq_comm (a := x)] using hx rw [this] - exact nsmul_mem (subset_closure $ mem_range_self _) _ + exact nsmul_mem (subset_closure <| mem_range_self _) _ @[simp] lemma addSubmonoid_closure_range_mul_self : closure (range fun x : ℤ ↦ x * x) = nonneg _ := by simpa only [sq] using addSubmonoid_closure_range_pow even_two instance instStarOrderedRing : StarOrderedRing ℤ where - le_iff a b := by simp [le_iff_exists_nonneg_add a b] + le_iff a b := by simp [eq_comm, le_iff_exists_nonneg_add (a := a)] end Int diff --git a/Mathlib/Data/Int/SuccPred.lean b/Mathlib/Data/Int/SuccPred.lean index b7ca8527c1e1b..51f82b5b2556a 100644 --- a/Mathlib/Data/Int/SuccPred.lean +++ b/Mathlib/Data/Int/SuccPred.lean @@ -21,13 +21,16 @@ namespace Int @[instance] abbrev instSuccOrder : SuccOrder ℤ := { SuccOrder.ofSuccLeIff succ fun {_ _} => Iff.rfl with succ := succ } +instance instSuccAddOrder : SuccAddOrder ℤ := ⟨fun _ => rfl⟩ + -- so that Lean reads `Int.pred` through `PredOrder.pred` @[instance] abbrev instPredOrder : PredOrder ℤ where pred := pred pred_le _ := (sub_one_lt_of_le le_rfl).le min_of_le_pred ha := ((sub_one_lt_of_le le_rfl).not_le ha).elim le_pred_of_lt {_ _} := le_sub_one_of_lt - le_of_pred_lt {_ _} := le_of_sub_one_lt + +instance instPredSubOrder : PredSubOrder ℤ := ⟨fun _ => rfl⟩ @[simp] theorem succ_eq_succ : Order.succ = succ := @@ -37,46 +40,44 @@ theorem succ_eq_succ : Order.succ = succ := theorem pred_eq_pred : Order.pred = pred := rfl +@[deprecated Order.one_le_iff_pos (since := "2024-09-04")] theorem pos_iff_one_le {a : ℤ} : 0 < a ↔ 1 ≤ a := Order.succ_le_iff.symm -theorem succ_iterate (a : ℤ) : ∀ n, succ^[n] a = a + n - | 0 => (add_zero a).symm - | n + 1 => by - rw [Function.iterate_succ', Int.ofNat_succ, ← add_assoc] - exact congr_arg _ (succ_iterate a n) +@[deprecated Order.succ_iterate (since := "2024-09-04")] +protected theorem succ_iterate (a : ℤ) : ∀ n, succ^[n] a = a + n := + Order.succ_iterate a -theorem pred_iterate (a : ℤ) : ∀ n, pred^[n] a = a - n - | 0 => (sub_zero a).symm - | n + 1 => by - rw [Function.iterate_succ', Int.ofNat_succ, ← sub_sub] - exact congr_arg _ (pred_iterate a n) +@[deprecated Order.pred_iterate (since := "2024-09-04")] +protected theorem pred_iterate (a : ℤ) : ∀ n, pred^[n] a = a - n := + Order.pred_iterate a instance : IsSuccArchimedean ℤ := ⟨fun {a b} h => - ⟨(b - a).toNat, by - rw [succ_eq_succ, succ_iterate, toNat_sub_of_le h, ← add_sub_assoc, add_sub_cancel_left]⟩⟩ + ⟨(b - a).toNat, by rw [succ_iterate, toNat_sub_of_le h, ← add_sub_assoc, add_sub_cancel_left]⟩⟩ instance : IsPredArchimedean ℤ := ⟨fun {a b} h => - ⟨(b - a).toNat, by rw [pred_eq_pred, pred_iterate, toNat_sub_of_le h, sub_sub_cancel]⟩⟩ + ⟨(b - a).toNat, by rw [pred_iterate, toNat_sub_of_le h, sub_sub_cancel]⟩⟩ /-! ### Covering relation -/ +@[deprecated Order.covBy_iff_add_one_eq (since := "2024-09-04")] protected theorem covBy_iff_succ_eq {m n : ℤ} : m ⋖ n ↔ m + 1 = n := succ_eq_iff_covBy.symm -@[simp] -theorem sub_one_covBy (z : ℤ) : z - 1 ⋖ z := by rw [Int.covBy_iff_succ_eq, sub_add_cancel] +@[deprecated Order.sub_one_covBy (since := "2024-09-04")] +theorem sub_one_covBy (z : ℤ) : z - 1 ⋖ z := + Order.sub_one_covBy z -@[simp] +@[deprecated Order.covBy_add_one (since := "2024-09-04")] theorem covBy_add_one (z : ℤ) : z ⋖ z + 1 := - Int.covBy_iff_succ_eq.mpr rfl + Order.covBy_add_one z @[simp, norm_cast] theorem natCast_covBy {a b : ℕ} : (a : ℤ) ⋖ b ↔ a ⋖ b := by - rw [Nat.covBy_iff_succ_eq, Int.covBy_iff_succ_eq] + rw [Order.covBy_iff_add_one_eq, Order.covBy_iff_add_one_eq] exact Int.natCast_inj end Int diff --git a/Mathlib/Data/Int/WithZero.lean b/Mathlib/Data/Int/WithZero.lean new file mode 100644 index 0000000000000..ec6f9a4c79ab0 --- /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.Basic + +/-! +# 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/LazyList/Basic.lean b/Mathlib/Data/LazyList/Basic.lean index ad67f3d3f60aa..7a9b820336505 100644 --- a/Mathlib/Data/LazyList/Basic.lean +++ b/Mathlib/Data/LazyList/Basic.lean @@ -47,25 +47,29 @@ instance : Traversable LazyList where @[deprecated (since := "2024-07-22")] instance : LawfulTraversable LazyList := by apply Equiv.isLawfulTraversable' listEquivLazyList <;> intros <;> ext <;> rename_i f xs - · induction' xs using LazyList.rec with _ _ _ _ ih - · simp only [Functor.map, LazyList.traverse, pure, Equiv.map, listEquivLazyList, + · induction xs using LazyList.rec with + | nil => + simp only [Functor.map, LazyList.traverse, pure, Equiv.map, listEquivLazyList, Equiv.coe_fn_symm_mk, toList, Equiv.coe_fn_mk, ofList] - · simpa only [Equiv.map, Functor.map, listEquivLazyList, Equiv.coe_fn_symm_mk, Equiv.coe_fn_mk, + | cons => + simpa only [Equiv.map, Functor.map, listEquivLazyList, Equiv.coe_fn_symm_mk, Equiv.coe_fn_mk, LazyList.traverse, Seq.seq, toList, ofList, cons.injEq, true_and] - · ext; apply ih + | mk _ ih => ext; apply ih · simp only [Equiv.map, listEquivLazyList, Equiv.coe_fn_symm_mk, Equiv.coe_fn_mk, comp, Functor.mapConst] - induction' xs using LazyList.rec with _ _ _ _ ih - · simp only [LazyList.traverse, pure, Functor.map, toList, ofList] - · simpa only [toList, ofList, LazyList.traverse, Seq.seq, Functor.map, cons.injEq, true_and] - · congr; apply ih + induction xs using LazyList.rec with + | nil => simp only [LazyList.traverse, pure, Functor.map, toList, ofList] + | cons => + simpa only [toList, ofList, LazyList.traverse, Seq.seq, Functor.map, cons.injEq, true_and] + | mk _ ih => congr; apply ih · simp only [traverse, Equiv.traverse, listEquivLazyList, Equiv.coe_fn_mk, Equiv.coe_fn_symm_mk] - induction' xs using LazyList.rec with _ tl ih _ ih - · simp only [LazyList.traverse, toList, List.traverse, map_pure, ofList] - · replace ih : tl.get.traverse f = ofList <$> tl.get.toList.traverse f := ih + induction xs using LazyList.rec with + | nil => simp only [LazyList.traverse, toList, List.traverse, map_pure, ofList] + | cons _ tl ih => + replace ih : tl.get.traverse f = ofList <$> tl.get.toList.traverse f := ih simp [traverse.eq_2, ih, Functor.map_map, seq_map_assoc, toList, List.traverse, map_seq, - Function.comp, Thunk.pure, ofList] - · apply ih + Function.comp_def, Thunk.pure, ofList] + | mk _ ih => apply ih @[deprecated (since := "2024-07-22"), simp] theorem bind_singleton {α} (x : LazyList α) : x.bind singleton = x := by @@ -91,10 +95,10 @@ instance : LawfulMonad LazyList := LawfulMonad.mk' apply append_nil) (bind_assoc := by intro _ _ _ xs _ _ - induction' xs using LazyList.rec with _ _ _ _ ih - · simp only [bind, LazyList.bind] - · simp only [bind, LazyList.bind, append_bind]; congr - · congr; funext; apply ih) + induction xs using LazyList.rec with + | nil => simp only [bind, LazyList.bind] + | cons => simp only [bind, LazyList.bind, append_bind]; congr + | mk _ ih => congr; funext; apply ih) (bind_pure_comp := by intro _ _ f xs simp only [bind, Functor.map, pure, singleton] diff --git a/Mathlib/Data/List/AList.lean b/Mathlib/Data/List/AList.lean index 1498c2afd3a09..cb4442a55a060 100644 --- a/Mathlib/Data/List/AList.lean +++ b/Mathlib/Data/List/AList.lean @@ -78,7 +78,7 @@ theorem keys_nodup (s : AList β) : s.keys.Nodup := /-- The predicate `a ∈ s` means that `s` has a value associated to the key `a`. -/ instance : Membership α (AList β) := - ⟨fun a s => a ∈ s.keys⟩ + ⟨fun s a => a ∈ s.keys⟩ theorem mem_keys {a : α} {s : AList β} : a ∈ s ↔ a ∈ s.keys := Iff.rfl diff --git a/Mathlib/Data/List/Basic.lean b/Mathlib/Data/List/Basic.lean index 22a70729a558d..267f3bbefd34e 100644 --- a/Mathlib/Data/List/Basic.lean +++ b/Mathlib/Data/List/Basic.lean @@ -3,16 +3,15 @@ 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.Init.Data.List.Basic -import Mathlib.Init.Data.List.Instances -import Mathlib.Init.Data.List.Lemmas +import Mathlib.Data.List.Monad +import Mathlib.Logic.OpClass import Mathlib.Logic.Unique import Mathlib.Order.Basic import Mathlib.Tactic.Common -import Batteries.Data.List.Perm /-! # Basic properties of lists @@ -33,6 +32,10 @@ universe u v w variable {ι : Type*} {α : Type u} {β : Type v} {γ : Type w} {l₁ l₂ : List α} +/-- `≤` implies not `>` for lists. -/ +@[deprecated (since := "2024-07-27")] +theorem le_eq_not_gt [LT α] : ∀ l₁ l₂ : List α, (l₁ ≤ l₂) = ¬l₂ < l₁ := fun _ _ => rfl + -- Porting note: Delete this attribute -- attribute [inline] List.head! @@ -55,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 @@ -90,12 +90,6 @@ theorem _root_.Function.Involutive.exists_mem_and_apply_eq_iff {f : α → α} theorem mem_map_of_involutive {f : α → α} (hf : Involutive f) {a : α} {l : List α} : a ∈ map f l ↔ f a ∈ l := by rw [mem_map, hf.exists_mem_and_apply_eq_iff] -attribute [simp] List.mem_join - -attribute [simp] List.mem_bind - --- Porting note: bExists in Lean3, And in Lean4 - /-! ### length -/ alias ⟨_, length_pos_of_ne_nil⟩ := length_pos @@ -132,13 +126,10 @@ theorem length_eq_three {l : List α} : l.length = 3 ↔ ∃ a b c, l = [a, b, c /-! ### set-theoretic notation of lists -/ --- ADHOC Porting note: instance from Lean3 core instance instSingletonList : Singleton α (List α) := ⟨fun x => [x]⟩ --- ADHOC Porting note: instance from Lean3 core instance [DecidableEq α] : Insert α (List α) := ⟨List.insert⟩ --- ADHOC Porting note: instance from Lean3 core instance [DecidableEq α] : LawfulSingleton α (List α) := { insert_emptyc_eq := fun x => show (if x ∈ ([] : List α) then [] else [x]) = [x] from if_neg (not_mem_nil _) } @@ -185,9 +176,6 @@ theorem exists_mem_cons_iff (p : α → Prop) (a : α) (l : List α) : /-! ### list subset -/ -instance : IsTrans (List α) Subset where - trans := fun _ _ _ => List.Subset.trans - theorem cons_subset_of_subset_of_mem {a : α} {l m : List α} (ainm : a ∈ m) (lsubm : l ⊆ m) : a::l ⊆ m := cons_subset.2 ⟨ainm, lsubm⟩ @@ -196,10 +184,6 @@ theorem append_subset_of_subset_of_subset {l₁ l₂ l : List α} (l₁subl : l l₁ ++ l₂ ⊆ l := fun _ h ↦ (mem_append.1 h).elim (@l₁subl _) (@l₂subl _) --- Porting note: in Batteries - -alias ⟨eq_nil_of_subset_nil, _⟩ := subset_nil - theorem map_subset_iff {l₁ l₂ : List α} (f : α → β) (h : Injective f) : map f l₁ ⊆ map f l₂ ↔ l₁ ⊆ l₂ := by refine ⟨?_, map_subset f⟩; intro h2 x hx @@ -211,28 +195,10 @@ 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 --- Porting note: in Batteries - -@[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 -@[simp] theorem append_left_eq_self {x y : List α} : x ++ y = y ↔ x = [] := by - rw [← append_left_inj (s₁ := x), nil_append] - -@[simp] theorem self_eq_append_left {x y : List α} : y = x ++ y ↔ x = [] := by - rw [eq_comm, append_left_eq_self] - -@[simp] theorem append_right_eq_self {x y : List α} : x ++ y = x ↔ y = [] := by - rw [← append_right_inj (t₁ := y), append_nil] - -@[simp] theorem self_eq_append_right {x y : List α} : x = x ++ y ↔ y = [] := by - rw [eq_comm, append_right_eq_self] - theorem append_right_injective (s : List α) : Injective fun t ↦ s ++ t := fun _ _ ↦ append_cancel_left @@ -255,13 +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] theorem tail_replicate (a : α) (n) : - tail (replicate n a) = replicate (n - 1) a := by cases n <;> rfl + 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 := @@ -292,9 +255,6 @@ theorem bind_eq_bind {α β} (f : α → List β) (l : List α) : l >>= f = l.bi /-! ### reverse -/ --- Porting note: Do we need this? -attribute [local simp] reverseAux - theorem reverse_cons' (a : α) (l : List α) : reverse (a :: l) = concat (reverse l) a := by simp only [reverse_cons, concat_eq_append] @@ -320,10 +280,6 @@ theorem reverse_surjective : Surjective (@reverse α) := theorem reverse_bijective : Bijective (@reverse α) := reverse_involutive.bijective -@[simp] -theorem reverse_inj {l₁ l₂ : List α} : reverse l₁ = reverse l₂ ↔ l₁ = l₂ := - reverse_injective.eq_iff - theorem concat_eq_reverse_cons (a : α) (l : List α) : concat l a = reverse (a :: reverse l) := by simp only [concat_eq_append, reverse_cons, reverse_reverse] @@ -333,12 +289,7 @@ theorem map_reverseAux (f : α → β) (l₁ l₂ : List α) : /-! ### empty -/ --- Porting note: this does not work as desired --- attribute [simp] List.isEmpty - -theorem isEmpty_iff_eq_nil {l : List α} : l.isEmpty ↔ l = [] := by cases l <;> simp [isEmpty] - -/-! ### dropLast -/ +@[deprecated (since := "2024-08-15")] alias isEmpty_iff_eq_nil := isEmpty_iff /-! ### getLast -/ @@ -351,11 +302,9 @@ theorem getLast_append_singleton {a : α} (l : List α) : -- Porting note: name should be fixed upstream theorem getLast_append' (l₁ l₂ : List α) (h : l₂ ≠ []) : getLast (l₁ ++ l₂) (append_ne_nil_of_right_ne_nil l₁ h) = getLast l₂ h := by - induction' l₁ with _ _ ih - · simp - · simp only [cons_append] - rw [List.getLast_cons] - exact ih + induction l₁ with + | nil => simp + | cons _ _ ih => simp only [cons_append]; rw [List.getLast_cons]; exact ih theorem getLast_concat' {a : α} (l : List α) : getLast (concat l a) (concat_ne_nil a l) = a := by simp @@ -403,25 +352,10 @@ lemma getLast_filter {p : α → Bool} : /-! ### getLast? -/ --- Porting note: Moved earlier in file, for use in subsequent lemmas. -@[simp] -theorem getLast?_cons_cons (a b : α) (l : List α) : - getLast? (a :: b :: l) = getLast? (b :: l) := rfl - -@[simp] -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 => @@ -442,10 +376,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 @@ -488,6 +418,10 @@ theorem head!_nil [Inhabited α] : ([] : List α).head! = default := rfl @[simp] theorem head_cons_tail (x : List α) (h : x ≠ []) : x.head h :: x.tail = x := by cases x <;> simp at h ⊢ +theorem head_eq_getElem_zero {l : List α} (hl : l ≠ []) : + l.head hl = l[0]'(length_pos.2 hl) := + (getElem_zero _).symm + theorem head!_eq_head? [Inhabited α] (l : List α) : head! l = (head? l).iget := by cases l <;> rfl theorem surjective_head! [Inhabited α] : Surjective (@head! α _) := fun x => ⟨[x], rfl⟩ @@ -505,9 +439,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] @@ -550,47 +481,34 @@ theorem head!_mem_self [Inhabited α] {l : List α} (h : l ≠ nil) : l.head! have h' := mem_cons_self l.head! l.tail rwa [cons_head!_tail h] at h' -theorem tail_append_of_ne_nil (l l' : List α) (h : l ≠ []) : (l ++ l').tail = l.tail ++ l' := by - cases l - · contradiction - · simp - theorem get_eq_get? (l : List α) (i : Fin l.length) : l.get i = (l.get? i).get (by simp [getElem?_eq_getElem]) := by - simp [getElem_eq_iff] + simp -section deprecated -set_option linter.deprecated false -- TODO(Mario): make replacements for theorems in this section +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⟩⟩ -/-- nth element of a list `l` given `n < l.length`. -/ -@[deprecated get (since := "2023-01-05")] -def nthLe (l : List α) (n) (h : n < l.length) : α := get l ⟨n, h⟩ +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 α] -@[simp] theorem nthLe_tail (l : List α) (i) (h : i < l.tail.length) +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 + +theorem get_tail (l : List α) (i) (h : i < l.tail.length) (h' : i + 1 < l.length := (by simp only [length_tail] at h; omega)) : - l.tail.nthLe i h = l.nthLe (i + 1) h' := by + l.tail.get ⟨i, h⟩ = l.get ⟨i + 1, h'⟩ := by cases l <;> [cases h; rfl] -theorem nthLe_cons_aux {l : List α} {a : α} {n} (hn : n ≠ 0) (h : n < (a :: l).length) : - n - 1 < l.length := by - contrapose! h - rw [length_cons] - omega - -theorem nthLe_cons {l : List α} {a : α} {n} (hl) : - (a :: l).nthLe n hl = if hn : n = 0 then a else l.nthLe (n - 1) (nthLe_cons_aux hn hl) := by - split_ifs with h - · simp [nthLe, h] - cases l - · rw [length_singleton, Nat.lt_succ_iff] at hl - omega - cases n - · contradiction - rfl - -end deprecated +@[deprecated (since := "2024-08-22")] +theorem get_cons {l : List α} {a : α} {n} (hl) : + (a :: l).get ⟨n, hl⟩ = if hn : n = 0 then a else + l.get ⟨n - 1, by contrapose! hl; rw [length_cons]; omega⟩ := + getElem_cons hl -@[simp 1100] theorem modifyHead_modifyHead (l : List α) (f g : α → α) : (l.modifyHead f).modifyHead g = l.modifyHead (g ∘ f) := by cases l <;> simp @@ -719,27 +637,11 @@ lemma cons_sublist_cons' {a b : α} : a :: l₁ <+ b :: l₂ ↔ a :: l₁ <+ l theorem sublist_cons_of_sublist (a : α) (h : l₁ <+ l₂) : l₁ <+ a :: l₂ := h.cons _ -theorem tail_sublist : ∀ l : List α, tail l <+ l - | [] => .slnil - | a::l => sublist_cons_self a l - -@[gcongr] protected theorem Sublist.tail : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → tail l₁ <+ tail l₂ - | _, _, slnil => .slnil - | _, _, Sublist.cons _ h => (tail_sublist _).trans h - | _, _, Sublist.cons₂ _ h => h - -theorem Sublist.of_cons_cons {l₁ l₂ : List α} {a b : α} (h : a :: l₁ <+ b :: l₂) : l₁ <+ l₂ := - h.tail - @[deprecated (since := "2024-04-07")] theorem sublist_of_cons_sublist_cons {a} (h : a :: l₁ <+ a :: l₂) : l₁ <+ l₂ := h.of_cons_cons -attribute [simp] cons_sublist_cons @[deprecated (since := "2024-04-07")] alias cons_sublist_cons_iff := cons_sublist_cons -theorem eq_nil_of_sublist_nil {l : List α} (s : l <+ []) : l = [] := - eq_nil_of_subset_nil <| s.subset - -- Porting note: this lemma seems to have been renamed on the occasion of its move to Batteries alias sublist_nil_iff_eq_nil := sublist_nil @@ -800,7 +702,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' @@ -816,7 +718,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 @@ -842,31 +744,14 @@ end IndexOf section deprecated set_option linter.deprecated false -@[deprecated get_of_mem (since := "2023-01-05")] -theorem nthLe_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n h, nthLe l n h = a := - let ⟨i, h⟩ := get_of_mem h; ⟨i.1, i.2, h⟩ - -@[deprecated get?_eq_get (since := "2023-01-05")] -theorem nthLe_get? {l : List α} {n} (h) : get? l n = some (nthLe l n h) := get?_eq_get _ - @[simp] theorem getElem?_length (l : List α) : l[l.length]? = none := getElem?_len_le le_rfl @[deprecated getElem?_length (since := "2024-06-12")] theorem get?_length (l : List α) : l.get? l.length = none := get?_len_le le_rfl -@[deprecated get_mem (since := "2023-01-05")] -theorem nthLe_mem (l : List α) (n h) : nthLe l n h ∈ l := get_mem .. - -@[deprecated mem_iff_get (since := "2023-01-05")] -theorem mem_iff_nthLe {a} {l : List α} : a ∈ l ↔ ∃ n h, nthLe l n h = a := - mem_iff_get.trans ⟨fun ⟨⟨n, h⟩, e⟩ => ⟨n, h, e⟩, fun ⟨n, h, e⟩ => ⟨⟨n, h⟩, e⟩⟩ - @[deprecated (since := "2024-05-03")] alias get?_injective := get?_inj -@[deprecated get_map (since := "2023-01-05")] -theorem nthLe_map (f : α → β) {l n} (H1 H2) : nthLe (map f l) n H1 = f (nthLe l n H2) := get_map .. - /-- A version of `getElem_map` that can be used for rewriting. -/ theorem getElem_map_rev (f : α → β) {l} {n : Nat} {h : n < l.length} : f l[n] = (map f l)[n]'((l.length_map f).symm ▸ h) := Eq.symm (getElem_map _) @@ -876,32 +761,10 @@ theorem getElem_map_rev (f : α → β) {l} {n : Nat} {h : n < l.length} : theorem get_map_rev (f : α → β) {l n} : f (get l n) = get (map f l) ⟨n.1, (l.length_map f).symm ▸ n.2⟩ := Eq.symm (get_map _) -/-- A version of `nthLe_map` that can be used for rewriting. -/ -@[deprecated get_map_rev (since := "2023-01-05")] -theorem nthLe_map_rev (f : α → β) {l n} (H) : - f (nthLe l n H) = nthLe (map f l) n ((l.length_map f).symm ▸ H) := - (nthLe_map f _ _).symm - -@[simp, deprecated get_map (since := "2023-01-05")] -theorem nthLe_map' (f : α → β) {l n} (H) : - nthLe (map f l) n H = f (nthLe l n (l.length_map f ▸ H)) := nthLe_map f _ _ - -@[simp, deprecated get_singleton (since := "2023-01-05")] -theorem nthLe_singleton (a : α) {n : ℕ} (hn : n < 1) : nthLe [a] n hn = a := get_singleton .. - -@[deprecated get_append_right' (since := "2023-01-05")] -theorem nthLe_append_right {l₁ l₂ : List α} {n : ℕ} (h₁ : l₁.length ≤ n) (h₂) : - (l₁ ++ l₂).nthLe n h₂ = l₂.nthLe (n - l₁.length) (get_append_right_aux h₁ h₂) := - get_append_right' h₁ h₂ - theorem get_length_sub_one {l : List α} (h : l.length - 1 < l.length) : l.get ⟨l.length - 1, h⟩ = l.getLast (by rintro rfl; exact Nat.lt_irrefl 0 h) := (getLast_eq_get l _).symm -@[deprecated get_cons_length (since := "2023-01-05")] -theorem nthLe_cons_length : ∀ (x : α) (xs : List α) (n : ℕ) (h : n = xs.length), - (x :: xs).nthLe n (by simp [h]) = (x :: xs).getLast (cons_ne_nil x xs) := get_cons_length - theorem take_one_drop_eq_of_lt_length {l : List α} {n : ℕ} (h : n < l.length) : (l.drop n).take 1 = [l.get ⟨n, h⟩] := by rw [drop_eq_get_cons h, take, take] @@ -929,11 +792,6 @@ theorem ext_get?_iff' {l₁ l₂ : List α} : l₁ = l₂ ↔ ∀ n < max l₁.length l₂.length, l₁.get? n = l₂.get? n := ⟨by rintro rfl _ _; rfl, ext_get?'⟩ -@[deprecated ext_get (since := "2023-01-05")] -theorem ext_nthLe {l₁ l₂ : List α} (hl : length l₁ = length l₂) - (h : ∀ n h₁ h₂, nthLe l₁ n h₁ = nthLe l₂ n h₂) : l₁ = l₂ := - ext_get hl h - @[simp] theorem getElem_indexOf [DecidableEq α] {a : α} : ∀ {l : List α} (h : indexOf a l < l.length), l[indexOf a l] = a @@ -955,14 +813,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 @@ -972,53 +822,21 @@ 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⟩ -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 - -@[simp] theorem getElem_reverse (l : List α) (i : Nat) (h1 h2) : - (reverse l)[length l - 1 - i]'h1 = l[i]'h2 := - getElem_reverse_aux₂ _ _ _ _ _ - -@[deprecated getElem_reverse_aux₂ (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 [getElem_reverse_aux₂, h1, h2] - @[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₂ _ _ _ _ _ - -@[simp, deprecated get_reverse (since := "2023-01-05")] -theorem nthLe_reverse (l : List α) (i : Nat) (h1 h2) : - nthLe (reverse l) (length l - 1 - i) h1 = nthLe l i h2 := - get_reverse .. + 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 nthLe_reverse' (l : List α) (n : ℕ) (hn : n < l.reverse.length) (hn') : - l.reverse.nthLe n hn = l.nthLe (l.length - 1 - n) hn' := by +theorem get_reverse' (l : List α) (n) (hn') : + l.reverse.get n = l.get ⟨l.length - 1 - n, hn'⟩ := by rw [eq_comm] - convert nthLe_reverse l.reverse n (by simpa) hn using 1 + convert get_reverse l.reverse n (by simpa) n.2 using 1 simp -theorem get_reverse' (l : List α) (n) (hn') : - l.reverse.get n = l.get ⟨l.length - 1 - n, hn'⟩ := nthLe_reverse' .. - --- FIXME: prove it the other way around -attribute [deprecated get_reverse' (since := "2023-01-05")] nthLe_reverse' - -theorem eq_cons_of_length_one {l : List α} (h : l.length = 1) : - l = [l.nthLe 0 (by omega)] := by +theorem eq_cons_of_length_one {l : List α} (h : l.length = 1) : l = [l.get ⟨0, by omega⟩] := by refine ext_get (by convert h) fun n h₁ h₂ => ?_ simp only [get_singleton] congr @@ -1054,18 +872,6 @@ theorem modifyNth_eq_set (f : α → α) : | n + 1, b :: l => (congr_arg (cons b) (modifyNth_eq_set f n l)).trans <| by cases h : l[n]? <;> simp [h] -theorem length_modifyNthTail (f : List α → List α) (H : ∀ l, length (f l) = length l) : - ∀ n l, length (modifyNthTail f n l) = length l - | 0, _ => H _ - | _ + 1, [] => rfl - | _ + 1, _ :: _ => @congr_arg _ _ _ _ (· + 1) (length_modifyNthTail _ H _ _) - --- Porting note: Duplicate of `modify_get?_length` --- (but with a substantially better name?) --- @[simp] -theorem length_modifyNth (f : α → α) : ∀ n l, length (modifyNth f n l) = length l := - modify_get?_length f - @[simp] theorem getElem_set_of_ne {l : List α} {i j : ℕ} (h : i ≠ j) (a : α) (hj : j < (l.set i a).length) : @@ -1081,6 +887,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 := @@ -1103,9 +914,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`. @@ -1201,13 +1009,6 @@ theorem zipWith_flip (f : α → β → γ) : ∀ as bs, zipWith (flip f) bs as /-! ### take, drop -/ -theorem take_cons (n) (a : α) (l : List α) : take (succ n) (a :: l) = a :: take n l := - rfl - -@[simp] -theorem drop_tail (l : List α) (n : ℕ) : l.tail.drop n = l.drop (n + 1) := by - rw [← drop_drop, drop_one] - theorem cons_getElem_drop_succ {l : List α} {n : Nat} {h : n < l.length} : l[n] :: l.drop (n + 1) = l.drop n := (drop_eq_getElem_cons h).symm @@ -1312,11 +1113,10 @@ theorem foldr_fixed {b : β} : ∀ l : List α, foldr (fun _ b => b) b l = b := -- Porting note (#10618): simp can prove this -- @[simp] theorem foldr_eta : ∀ l : List α, foldr cons [] l = l := by - simp only [foldr_self_append, append_nil, forall_const] + simp only [foldr_cons_eq_append, append_nil, forall_const] -@[simp] theorem reverse_foldl {l : List α} : reverse (foldl (fun t h => h :: t) [] l) = l := by - rw [← foldr_reverse]; simp only [foldr_self_append, append_nil, reverse_reverse] + rw [← foldr_reverse]; simp only [foldr_cons_eq_append, append_nil, reverse_reverse] theorem foldl_hom₂ (l : List ι) (f : α → β → γ) (op₁ : α → ι → α) (op₂ : β → ι → β) (op₃ : γ → ι → γ) (a : α) (b : β) (h : ∀ a b i, f (op₁ a i) (op₂ b i) = op₃ (f a b) i) : @@ -1340,52 +1140,6 @@ theorem injective_foldl_comp {l : List (α → α)} {f : α → α} apply Function.Injective.comp hf apply hl _ (List.mem_cons_self _ _) -/-- Induction principle for values produced by a `foldr`: if a property holds -for the seed element `b : β` and for all incremental `op : α → β → β` -performed on the elements `(a : α) ∈ l`. The principle is given for -a `Sort`-valued predicate, i.e., it can also be used to construct data. -/ -def foldrRecOn {C : β → Sort*} (l : List α) (op : α → β → β) (b : β) (hb : C b) - (hl : ∀ b, C b → ∀ a ∈ l, C (op a b)) : C (foldr op b l) := by - induction l with - | nil => exact hb - | cons hd tl IH => - refine hl _ ?_ hd (mem_cons_self hd tl) - refine IH ?_ - intro y hy x hx - exact hl y hy x (mem_cons_of_mem hd hx) - -/-- Induction principle for values produced by a `foldl`: if a property holds -for the seed element `b : β` and for all incremental `op : β → α → β` -performed on the elements `(a : α) ∈ l`. The principle is given for -a `Sort`-valued predicate, i.e., it can also be used to construct data. -/ -def foldlRecOn {C : β → Sort*} (l : List α) (op : β → α → β) (b : β) (hb : C b) - (hl : ∀ b, C b → ∀ a ∈ l, C (op b a)) : C (foldl op b l) := by - induction l generalizing b with - | nil => exact hb - | cons hd tl IH => - refine IH _ ?_ ?_ - · exact hl b hb hd (mem_cons_self hd tl) - · intro y hy x hx - exact hl y hy x (mem_cons_of_mem hd hx) - -@[simp] -theorem foldrRecOn_nil {C : β → Sort*} (op : α → β → β) (b) (hb : C b) (hl) : - foldrRecOn [] op b hb hl = hb := - rfl - -@[simp] -theorem foldrRecOn_cons {C : β → Sort*} (x : α) (l : List α) (op : α → β → β) (b) (hb : C b) - (hl : ∀ b, C b → ∀ a ∈ x :: l, C (op a b)) : - foldrRecOn (x :: l) op b hb hl = - hl _ (foldrRecOn l op b hb fun b hb a ha => hl b hb a (mem_cons_of_mem _ ha)) x - (mem_cons_self _ _) := - rfl - -@[simp] -theorem foldlRecOn_nil {C : β → Sort*} (op : β → α → β) (b) (hb : C b) (hl) : - foldlRecOn [] op b hb hl = hb := - rfl - /-- Consider two lists `l₁` and `l₂` with designated elements `a₁` and `a₂` somewhere in them: `l₁ = x₁ ++ [a₁] ++ z₁` and `l₂ = x₂ ++ [a₂] ++ z₂`. Assume the designated element `a₂` is present in neither `x₁` nor `z₁`. @@ -1395,7 +1149,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⟩ @@ -1439,11 +1193,6 @@ theorem getElem_scanl_zero {h : 0 < (scanl f b l).length} : (scanl f b l)[0] = b theorem get_zero_scanl {h : 0 < (scanl f b l).length} : (scanl f b l).get ⟨0, h⟩ = b := by simp [getElem_scanl_zero] -set_option linter.deprecated false in -@[simp, deprecated get_zero_scanl (since := "2023-01-05")] -theorem nthLe_zero_scanl {h : 0 < (scanl f b l).length} : (scanl f b l).nthLe 0 h = b := - get_zero_scanl - theorem get?_succ_scanl {i : ℕ} : (scanl f b l).get? (i + 1) = ((scanl f b l).get? i).bind fun x => (l.get? i).map fun y => f x y := by induction' l with hd tl hl generalizing b i @@ -1455,33 +1204,30 @@ theorem get?_succ_scanl {i : ℕ} : (scanl f b l).get? (i + 1) = · simp · simp only [hl, get?] -set_option linter.deprecated false in -theorem nthLe_succ_scanl {i : ℕ} {h : i + 1 < (scanl f b l).length} : - (scanl f b l).nthLe (i + 1) h = - f ((scanl f b l).nthLe i (Nat.lt_of_succ_lt h)) - (l.nthLe i (Nat.lt_of_succ_lt_succ (lt_of_lt_of_le h (le_of_eq (length_scanl b l))))) := by +theorem getElem_succ_scanl {i : ℕ} (h : i + 1 < (scanl f b l).length) : + (scanl f b l)[i + 1] = + f ((scanl f b l)[i]'(Nat.lt_of_succ_lt h)) + (l[i]'(Nat.lt_of_succ_lt_succ (h.trans_eq (length_scanl b l)))) := by induction i generalizing b l with | zero => cases l · simp only [length, zero_eq, lt_self_iff_false] at h - · simp [scanl_cons, singleton_append, nthLe_zero_scanl, nthLe_cons] + · simp | succ i hi => cases l · simp only [length] at h exact absurd h (by omega) · simp_rw [scanl_cons] - rw [nthLe_append_right] + rw [getElem_append_right] · simp only [length, Nat.zero_add 1, succ_add_sub_one, hi]; rfl · simp only [length_singleton]; omega +@[deprecated getElem_succ_scanl (since := "2024-08-22")] theorem get_succ_scanl {i : ℕ} {h : i + 1 < (scanl f b l).length} : (scanl f b l).get ⟨i + 1, h⟩ = f ((scanl f b l).get ⟨i, Nat.lt_of_succ_lt h⟩) (l.get ⟨i, Nat.lt_of_succ_lt_succ (lt_of_lt_of_le h (le_of_eq (length_scanl b l)))⟩) := - nthLe_succ_scanl - --- FIXME: we should do the proof the other way around -attribute [deprecated get_succ_scanl (since := "2023-01-05")] nthLe_succ_scanl + getElem_succ_scanl h end Scanl @@ -1503,25 +1249,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 | 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 | 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 @@ -1563,13 +1311,6 @@ 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 @@ -1622,49 +1363,11 @@ theorem intersperse_cons_cons (a b c : α) (tl : List α) : section SplitAtOn -/- Porting note: the new version of `splitOnP` uses a `Bool`-valued predicate instead of a - `Prop`-valued one. All downstream definitions have been updated to match. -/ +variable (p : α → Bool) (xs : List α) (ls : List (List α)) -variable (p : α → Bool) (xs ys : List α) (ls : List (List α)) (f : List α → List α) +attribute [simp] splitAt_eq -/- Porting note: this had to be rewritten because of the new implementation of `splitAt`. It's - long in large part because `splitAt.go` (`splitAt`'s auxiliary function) works differently - in the case where n ≥ length l, requiring two separate cases (and two separate inductions). Still, - this can hopefully be golfed. -/ - -@[simp] -theorem splitAt_eq_take_drop (n : ℕ) (l : List α) : splitAt n l = (take n l, drop n l) := by - by_cases h : n < l.length <;> rw [splitAt, go_eq_take_drop] - · rw [if_pos h]; rfl - · rw [if_neg h, take_of_length_le <| le_of_not_lt h, drop_eq_nil_of_le <| le_of_not_lt h] -where - go_eq_take_drop (n : ℕ) (l xs : List α) (acc : Array α) : splitAt.go l xs n acc = - if n < xs.length then (acc.toList ++ take n xs, drop n xs) else (l, []) := by - split_ifs with h - · induction n generalizing xs acc with - | zero => - rw [splitAt.go, take, drop, append_nil] - · intros h₁; rw [h₁] at h; contradiction - · intros; contradiction - | succ _ ih => - cases xs with - | nil => contradiction - | cons hd tl => - rw [length] at h - rw [splitAt.go, take, drop, append_cons, Array.toList_eq, ← Array.push_data, - ← Array.toList_eq] - exact ih _ _ <| (by omega) - · induction n generalizing xs acc with - | zero => - replace h : xs.length = 0 := by omega - rw [eq_nil_of_length_eq_zero h, splitAt.go] - | succ _ ih => - cases xs with - | nil => rw [splitAt.go] - | cons hd tl => - rw [length] at h - rw [splitAt.go] - exact ih _ _ <| not_imp_not.mpr (Nat.add_lt_add_right · 1) h +@[deprecated (since := "2024-08-17")] alias splitAt_eq_take_drop := splitAt_eq @[simp] theorem splitOn_nil [DecidableEq α] (a : α) : [].splitOn a = [[]] := @@ -1674,10 +1377,6 @@ theorem splitOn_nil [DecidableEq α] (a : α) : [].splitOn a = [[]] := theorem splitOnP_nil : [].splitOnP p = [[]] := rfl -/- Porting note: `split_on_p_aux` and `split_on_p_aux'` were used to prove facts about - `split_on_p`. `splitOnP` has a different structure, and we need different facts about - `splitOnP.go`. Theorems involving `split_on_p_aux` have been omitted where possible. -/ - theorem splitOnP.go_ne_nil (xs acc : List α) : splitOnP.go p xs acc ≠ [] := by induction xs generalizing acc <;> simp [go]; split <;> simp [*] @@ -1780,7 +1479,6 @@ theorem splitOn_intercalate [DecidableEq α] (x : α) (hx : ∀ l ∈ ls, x ∉ end SplitAtOn -/- Porting note: new; here tentatively -/ /-! ### modifyLast -/ section ModifyLast @@ -1795,18 +1493,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 @@ -1837,33 +1536,10 @@ theorem sizeOf_lt_sizeOf_of_mem [SizeOf α] {x : α} {l : List α} (hx : x ∈ l @[deprecated attach_map_coe (since := "2024-07-29")] alias attach_map_coe' := attach_map_coe @[deprecated attach_map_val (since := "2024-07-29")] alias attach_map_val' := attach_map_val -set_option linter.deprecated false in -@[deprecated get_pmap (since := "2023-01-05")] -theorem nthLe_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h : ∀ a ∈ l, p a) {n : ℕ} - (hn : n < (pmap f l h).length) : - nthLe (pmap f l h) n hn = - f (nthLe l n (@length_pmap _ _ p f l h ▸ hn)) - (h _ (get_mem l n (@length_pmap _ _ p f l h ▸ hn))) := - get_pmap .. - /-! ### find -/ section find? -variable {p : α → Bool} {l : List α} {a : α} - --- @[simp] --- Later porting note (at time of this lemma moving to Batteries): --- removing attribute `nolint simpNF` -attribute [simp 1100] find?_cons_of_pos - --- @[simp] --- Later porting note (at time of this lemma moving to Batteries): --- removing attribute `nolint simpNF` -attribute [simp 1100] find?_cons_of_neg - -attribute [simp] find?_eq_none - @[deprecated (since := "2024-05-05")] alias find?_mem := mem_of_find?_eq_some end find? @@ -1878,11 +1554,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] @@ -1892,13 +1570,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 @@ -2041,25 +1719,25 @@ theorem monotone_filter_right (l : List α) ⦃p q : α → Bool⦄ lemma map_filter' {f : α → β} (hf : Injective f) (l : List α) [DecidablePred fun b => ∃ a, p a ∧ f a = b] : (l.filter p).map f = (l.map f).filter fun b => ∃ a, p a ∧ f a = b := by - simp [(· ∘ ·), filter_map, hf.eq_iff] + simp [comp_def, filter_map, hf.eq_iff] 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 classical refine map_injective_iff.2 Subtype.coe_injective ?_ - simp [(· ∘ ·), map_filter' _ Subtype.coe_injective] + simp [comp_def, map_filter' _ Subtype.coe_injective] -- 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) := map_injective_iff.2 Subtype.coe_injective <| by - simp_rw [map_map, (· ∘ ·), Subtype.map, id, ← Function.comp_apply (g := Subtype.val), + 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 α) : @@ -2080,19 +1758,19 @@ theorem span.loop_eq_take_drop : theorem span_eq_take_drop (l : List α) : span p l = (takeWhile p l, dropWhile p l) := by simpa using span.loop_eq_take_drop p l [] --- TODO update to use `get` instead of `nthLe` -set_option linter.deprecated false in -theorem dropWhile_nthLe_zero_not (l : List α) (hl : 0 < (l.dropWhile p).length) : - ¬p ((l.dropWhile p).nthLe 0 hl) := by +theorem dropWhile_get_zero_not (l : List α) (hl : 0 < (l.dropWhile p).length) : + ¬p ((l.dropWhile p).get ⟨0, hl⟩) := by induction' l with hd tl IH · cases hl · simp only [dropWhile] by_cases hp : p hd - · simp [hp, IH] - · simp [hp, nthLe_cons] --- Porting note: How did the Lean 3 proof work, --- without mentioning nthLe_cons? --- Same question for takeWhile_eq_nil_iff below + · simp_all only [get_eq_getElem] + apply IH + simp_all only [dropWhile_cons_of_pos] + · simp [hp] + +@[deprecated (since := "2024-08-19")] alias nthLe_cons := getElem_cons +@[deprecated (since := "2024-08-19")] alias dropWhile_nthLe_zero_not := dropWhile_get_zero_not variable {p} {l : List α} @@ -2100,23 +1778,21 @@ variable {p} {l : List α} theorem dropWhile_eq_nil_iff : dropWhile p l = [] ↔ ∀ x ∈ l, p x := by induction' l with x xs IH · simp [dropWhile] - · by_cases hp : p x <;> simp [hp, dropWhile, IH] + · by_cases hp : p x <;> simp [hp, IH] @[simp] theorem takeWhile_eq_self_iff : takeWhile p l = l ↔ ∀ x ∈ l, p x := by induction' l with x xs IH · simp - · by_cases hp : p x <;> simp [hp, takeWhile_cons, IH] + · by_cases hp : p x <;> simp [hp, IH] --- TODO update to use `get` instead of `nthLe` -set_option linter.deprecated false in @[simp] -theorem takeWhile_eq_nil_iff : takeWhile p l = [] ↔ ∀ hl : 0 < l.length, ¬p (l.nthLe 0 hl) := by +theorem takeWhile_eq_nil_iff : takeWhile p l = [] ↔ ∀ hl : 0 < l.length, ¬p (l.get ⟨0, hl⟩) := by induction' l with x xs IH · simp only [takeWhile_nil, Bool.not_eq_true, true_iff] intro h simp at h - · by_cases hp : p x <;> simp [hp, takeWhile_cons, IH, nthLe_cons] + · by_cases hp : p x <;> simp [hp, IH] theorem mem_takeWhile_imp {x : α} (hx : x ∈ takeWhile p l) : p x := by induction l with simp [takeWhile] at hx @@ -2183,7 +1859,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' @@ -2470,13 +2146,6 @@ theorem zipRight_eq_zipRight' : zipRight as bs = (zipRight' as bs).fst := by end ZipRight -/-! ### toChunks -/ - --- Porting note: --- The definition of `toChunks` has changed substantially from Lean 3. --- The theorems about `toChunks` are not used anywhere in mathlib, anyways. --- TODO: Prove these theorems for the new definitions. - /-! ### Forall -/ section Forall @@ -2485,7 +2154,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 @@ -2510,16 +2179,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 (α × β)) : @@ -2586,11 +2247,36 @@ 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 + simp_rw [List.disjoint_left, p.mem_iff] + +theorem Perm.disjoint_right {l₁ l₂ l : List α} (p : List.Perm l₁ l₂) : + Disjoint l l₁ ↔ Disjoint l l₂ := by + simp_rw [List.disjoint_right, p.mem_iff] + +@[simp] +theorem disjoint_reverse_left {l₁ l₂ : List α} : Disjoint l₁.reverse l₂ ↔ Disjoint l₁ l₂ := + reverse_perm _ |>.disjoint_left + +@[simp] +theorem disjoint_reverse_right {l₁ l₂ : List α} : Disjoint l₁ l₂.reverse ↔ Disjoint l₁ l₂ := + reverse_perm _ |>.disjoint_right + 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 @@ -2603,3 +2289,5 @@ lemma lookup_graph (f : α → β) {a : α} {as : List α} (h : a ∈ as) : end lookup end List + +set_option linter.style.longFile 2700 diff --git a/Mathlib/Data/List/Chain.lean b/Mathlib/Data/List/Chain.lean index e8e436dc37099..965aee596b838 100644 --- a/Mathlib/Data/List/Chain.lean +++ b/Mathlib/Data/List/Chain.lean @@ -6,7 +6,6 @@ Authors: Mario Carneiro, Kenny Lau, Yury Kudryashov import Mathlib.Logic.Relation import Mathlib.Data.List.Forall2 import Mathlib.Data.List.Lex -import Mathlib.Data.List.Infix /-! # Relation chain @@ -18,8 +17,7 @@ A graph-specialized version is in development and will hopefully be added under sometime soon. -/ --- Make sure we haven't imported `Data.Nat.Order.Basic` -assert_not_exists OrderedSub +assert_not_imported Mathlib.Algebra.Order.Group.Nat universe u v @@ -38,18 +36,21 @@ theorem Chain.iff {S : α → α → Prop} (H : ∀ a b, R a b ↔ S a b) {a : theorem Chain.iff_mem {a : α} {l : List α} : Chain R a l ↔ Chain (fun x y => x ∈ a :: l ∧ y ∈ l ∧ R x y) a l := ⟨fun p => by - induction' p with _ a b l r _ IH <;> 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⟩], + induction p with + | nil => exact nil + | @cons _ _ _ r _ IH => + 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⟩ 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 α} : @@ -98,7 +99,7 @@ protected theorem Chain.pairwise [IsTrans α R] : | 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) := @@ -137,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] @@ -231,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₂) @@ -265,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) := @@ -319,31 +332,53 @@ theorem exists_chain_of_relationReflTransGen (h : Relation.ReflTransGen r a b) : refine ⟨d :: l, Chain.cons e hl₁, ?_⟩ rwa [getLast_cons_cons] +/-- Given a chain from `a` to `b`, and a predicate true at `a`, if `r x y → p x → p y` then +the predicate is true everywhere in the chain. +That is, we can propagate the predicate down the chain. +-/ +theorem Chain.induction (p : α → Prop) (l : List α) (h : Chain r a l) + (carries : ∀ ⦃x y : α⦄, r x y → p x → p y) (initial : p a) : ∀ i ∈ l, p i := by + induction h with + | nil => simp + | @cons a b t hab _ h_ind => + simp only [mem_cons, forall_eq_or_imp] + exact ⟨carries hab initial, h_ind (carries hab initial)⟩ + +/-- A version of `List.Chain.induction` for `List.Chain'` +-/ +theorem Chain'.induction (p : α → Prop) (l : List α) (h : Chain' r l) + (carries : ∀ ⦃x y : α⦄, r x y → p x → p y) (initial : (lne : l ≠ []) → p (l.head lne)) : + ∀ i ∈ l, p i := by + unfold Chain' at h + split at h + · simp + · simp_all only [ne_eq, not_false_eq_true, head_cons, true_implies, mem_cons, forall_eq_or_imp, + true_and, reduceCtorEq] + exact h.induction p _ carries initial + /-- Given a chain from `a` to `b`, and a predicate true at `b`, if `r x y → p y → p x` then the predicate is true everywhere in the chain and at `a`. That is, we can propagate the predicate up the chain. -/ -theorem Chain.induction (p : α → Prop) (l : List α) (h : Chain r a l) +theorem Chain.backwards_induction (p : α → Prop) (l : List α) (h : Chain r a l) (hb : getLast (a :: l) (cons_ne_nil _ _) = b) (carries : ∀ ⦃x y : α⦄, r x y → p y → p x) (final : p b) : ∀ i ∈ a :: l, p i := by - induction' l with _ _ l_ih generalizing a - · cases hb - simpa using final - · rw [chain_cons] at h - simp only [mem_cons] - rintro _ (rfl | H) - · apply carries h.1 (l_ih h.2 hb _ (mem_cons.2 (Or.inl rfl))) - · apply l_ih h.2 hb _ (mem_cons.2 H) + have : Chain' (flip (flip r)) (a :: l) := by simpa [Chain'] + replace this := chain'_reverse.mpr this + simp_rw (config := {singlePass := true}) [← List.mem_reverse] + apply this.induction _ _ (fun _ _ h ↦ carries h) + simpa only [ne_eq, reverse_eq_nil_iff, not_false_eq_true, head_reverse, forall_true_left, hb, + reduceCtorEq] /-- Given a chain from `a` to `b`, and a predicate true at `b`, if `r x y → p y → p x` then the predicate is true at `a`. That is, we can propagate the predicate all the way up the chain. -/ @[elab_as_elim] -theorem Chain.induction_head (p : α → Prop) (l : List α) (h : Chain r a l) +theorem Chain.backwards_induction_head (p : α → Prop) (l : List α) (h : Chain r a l) (hb : getLast (a :: l) (cons_ne_nil _ _) = b) (carries : ∀ ⦃x y : α⦄, r x y → p y → p x) (final : p b) : p a := - (Chain.induction p l h hb carries final) _ (mem_cons_self _ _) + (Chain.backwards_induction p l h hb carries final) _ (mem_cons_self _ _) /-- If there is an `r`-chain starting from `a` and ending at `b`, then `a` and `b` are related by the @@ -351,7 +386,7 @@ reflexive transitive closure of `r`. The converse of `exists_chain_of_relationRe -/ theorem relationReflTransGen_of_exists_chain (l : List α) (hl₁ : Chain r a l) (hl₂ : getLast (a :: l) (cons_ne_nil _ _) = b) : Relation.ReflTransGen r a b := - Chain.induction_head _ l hl₁ hl₂ (fun _ _ => Relation.ReflTransGen.head) + Chain.backwards_induction_head _ l hl₁ hl₂ (fun _ _ => Relation.ReflTransGen.head) Relation.ReflTransGen.refl theorem Chain'.cons_of_le [LinearOrder α] {a : α} {as m : List α} @@ -363,7 +398,7 @@ theorem Chain'.cons_of_le [LinearOrder α] {a : α} {as m : List α} apply hm.cons cases as with | nil => - simp only [le_iff_lt_or_eq, or_false] at hmas + simp only [le_iff_lt_or_eq, reduceCtorEq, or_false] at hmas exact (List.Lex.not_nil_right (·<·) _ hmas).elim | cons a' as => rw [List.chain'_cons] at ha @@ -377,6 +412,36 @@ theorem Chain'.cons_of_le [LinearOrder α] {a : α} {as m : List α} exact (List.lt_iff_lex_lt _ _).mp (List.lt.head _ _ hh) · simp_all only [List.cons.injEq, le_refl] +lemma Chain'.chain {α : Type*} {R : α → α → Prop} {l : List α} {v : α} + (hl : l.Chain' R) (hv : (lne : l ≠ []) → R v (l.head lne)) : l.Chain R v := by + rw [List.chain_iff_get] + constructor + · intro h + rw [List.get_mk_zero] + apply hv + · exact List.chain'_iff_get.mp hl + +lemma Chain'.iterate_eq_of_apply_eq {α : Type*} {f : α → α} {l : List α} + (hl : l.Chain' (fun x y ↦ f x = y)) (i : ℕ) (hi : i < l.length) : + f^[i] l[0] = l[i] := by + induction' i with i h + · rfl + · rw [Function.iterate_succ', Function.comp_apply, h (by omega)] + rw [List.chain'_iff_get] at hl + 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 1e128c3d42e2b..89475cec9fe1e 100644 --- a/Mathlib/Data/List/Count.lean +++ b/Mathlib/Data/List/Count.lean @@ -3,7 +3,8 @@ 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 @@ -19,7 +20,7 @@ assert_not_exists Ring open Nat -variable {α : Type*} {l : List α} +variable {α : Type*} namespace List @@ -30,15 +31,9 @@ section Count @[simp] theorem count_map_of_injective {β} [DecidableEq α] [DecidableEq β] (l : List α) (f : α → β) (hf : Function.Injective f) (x : α) : count (f x) (map f l) = count x l := by - simp only [count, countP_map, (· ∘ ·), 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] + simp only [count, countP_map] + unfold Function.comp + simp only [hf.beq_eq] end Count diff --git a/Mathlib/Data/List/Cycle.lean b/Mathlib/Data/List/Cycle.lean index d16894eab2b25..9c8cbaa143209 100644 --- a/Mathlib/Data/List/Cycle.lean +++ b/Mathlib/Data/List/Cycle.lean @@ -165,7 +165,7 @@ theorem next_getLast_cons (h : x ∈ l) (y : α) (h : x ∈ y :: l) (hy : x ≠ intro H obtain ⟨⟨_ | k, hk⟩, hk'⟩ := get_of_mem H · rw [← Option.some_inj] at hk' - rw [← get?_eq_get, dropLast_eq_take, get?_eq_getElem?, getElem?_take, getElem?_cons_zero, + rw [← get?_eq_get, dropLast_eq_take, get?_eq_getElem?, getElem?_take_of_lt, getElem?_cons_zero, Option.some_inj] at hk' · exact hy (Eq.symm hk') rw [length_cons] @@ -178,7 +178,7 @@ theorem next_getLast_cons (h : x ∈ l) (y : α) (h : x ∈ y :: l) (hy : x ≠ refine Fin.val_eq_of_eq <| @hl ⟨k, Nat.lt_of_succ_lt <| by simpa using hk⟩ ⟨tl.length, by simp⟩ ?_ rw [← Option.some_inj] at hk' - rw [← get?_eq_get, dropLast_eq_take, get?_eq_getElem?, getElem?_take, getElem?_cons_succ, + rw [← get?_eq_get, dropLast_eq_take, get?_eq_getElem?, getElem?_take_of_lt, getElem?_cons_succ, getElem?_eq_getElem, Option.some_inj] at hk' · rw [get_eq_getElem, hk'] simp only [getLast_eq_getElem, length_cons, Nat.succ_eq_add_one, Nat.succ_sub_succ_eq_sub, @@ -233,13 +233,14 @@ theorem prev_mem (h : x ∈ l) : l.prev x h ∈ l := by · exact mem_cons_self _ _ · exact mem_cons_of_mem _ (hl _ _) -theorem next_get : ∀ (l : List α) (_h : Nodup l) (i : Fin l.length), - next l (l.get i) (get_mem _ _ _) = l.get ⟨(i + 1) % l.length, - Nat.mod_lt _ (i.1.zero_le.trans_lt i.2)⟩ +theorem next_get (l : List α) (h : Nodup l) (i : Fin l.length) : + next l (l.get i) (get_mem _ _ _) = + l.get ⟨(i + 1) % l.length, Nat.mod_lt _ (i.1.zero_le.trans_lt i.2)⟩ := + match l, h, i with | [], _, i => by simpa using i.2 | [_], _, _ => by simp | x::y::l, _h, ⟨0, h0⟩ => by - have h₁ : get (x :: y :: l) { val := 0, isLt := h0 } = x := by simp + have h₁ : get (x :: y :: l) ⟨0, h0⟩ = x := by simp rw [next_cons_cons_eq' _ _ _ _ _ h₁] simp | x::y::l, hn, ⟨i+1, hi⟩ => by @@ -273,108 +274,96 @@ theorem next_get : ∀ (l : List α) (_h : Nodup l) (i : Fin l.length), simp at this; simp [this] at hi' · rw [get_cons_succ]; exact get_mem _ _ _ -set_option linter.deprecated false in -@[deprecated next_get (since := "2023-01-27")] -theorem next_nthLe (l : List α) (h : Nodup l) (n : ℕ) (hn : n < l.length) : - next l (l.nthLe n hn) (nthLe_mem _ _ _) = - l.nthLe ((n + 1) % l.length) (Nat.mod_lt _ (n.zero_le.trans_lt hn)) := - next_get l h ⟨n, hn⟩ - -set_option linter.deprecated false in -theorem prev_nthLe (l : List α) (h : Nodup l) (n : ℕ) (hn : n < l.length) : - prev l (l.nthLe n hn) (nthLe_mem _ _ _) = - l.nthLe ((n + (l.length - 1)) % l.length) (Nat.mod_lt _ (n.zero_le.trans_lt hn)) := by - cases' l with x l - · simp at hn - induction' l with y l hl generalizing n x - · simp - · rcases n with (_ | _ | n) - · simp [Nat.add_succ_sub_one, add_zero, List.prev_cons_cons_eq, Nat.zero_eq, List.length, - List.nthLe, Nat.succ_add_sub_one, zero_add, getLast_eq_get, - Nat.mod_eq_of_lt (Nat.succ_lt_succ l.length.lt_succ_self)] - · simp only [mem_cons, nodup_cons] at h - push_neg at h - simp only [List.prev_cons_cons_of_ne _ _ _ _ h.left.left.symm, Nat.zero_eq, List.length, - List.nthLe, add_comm, eq_self_iff_true, Nat.succ_add_sub_one, Nat.mod_self, zero_add, - List.get] - · rw [prev_ne_cons_cons] - · convert hl n.succ y h.of_cons (Nat.le_of_succ_le_succ hn) using 1 - have : ∀ k hk, (y :: l).nthLe k hk = (x :: y :: l).nthLe (k + 1) (Nat.succ_lt_succ hk) := by - simp [List.nthLe] - rw [this] - congr - simp only [Nat.add_succ_sub_one, add_zero, length] - simp only [length, Nat.succ_lt_succ_iff] at hn - set k := l.length - rw [Nat.succ_add, ← Nat.add_succ, Nat.add_mod_right, Nat.succ_add, ← Nat.add_succ _ k, - Nat.add_mod_right, Nat.mod_eq_of_lt, Nat.mod_eq_of_lt] - · exact Nat.lt_succ_of_lt hn - · exact Nat.succ_lt_succ (Nat.lt_succ_of_lt hn) - · intro H - suffices n.succ.succ = 0 by simpa - rw [nodup_iff_nthLe_inj] at h - refine h _ _ hn Nat.succ_pos' ?_ - simpa using H - · intro H - suffices n.succ.succ = 1 by simpa - rw [nodup_iff_nthLe_inj] at h - refine h _ _ hn (Nat.succ_lt_succ Nat.succ_pos') ?_ - simpa using H - -set_option linter.deprecated false in +-- Unused variable linter incorrectly reports that `h` is unused here. +set_option linter.unusedVariables false in +theorem prev_get (l : List α) (h : Nodup l) (i : Fin l.length) : + prev l (l.get i) (get_mem _ _ _) = + l.get ⟨(i + (l.length - 1)) % l.length, Nat.mod_lt _ i.pos⟩ := + match l with + | [] => by simpa using i.2 + | x::l => by + obtain ⟨n, hn⟩ := i + induction l generalizing n x with + | nil => simp + | cons y l hl => + rcases n with (_ | _ | n) + · simp [getLast_eq_getElem] + · simp only [mem_cons, nodup_cons] at h + push_neg at h + simp only [List.prev_cons_cons_of_ne _ _ _ _ h.left.left.symm, List.length, + List.get, add_comm, Nat.succ_add_sub_one, Nat.mod_self, zero_add] + · rw [prev_ne_cons_cons] + · convert hl y h.of_cons n.succ (Nat.le_of_succ_le_succ hn) using 1 + have : ∀ k hk, (y :: l).get ⟨k, hk⟩ = (x :: y :: l).get ⟨k + 1, Nat.succ_lt_succ hk⟩ := by + simp [List.get] + rw [this] + congr + simp only [Nat.add_succ_sub_one, add_zero, length] + simp only [length, Nat.succ_lt_succ_iff] at hn + set k := l.length + rw [Nat.succ_add, ← Nat.add_succ, Nat.add_mod_right, Nat.succ_add, ← Nat.add_succ _ k, + Nat.add_mod_right, Nat.mod_eq_of_lt, Nat.mod_eq_of_lt] + · exact Nat.lt_succ_of_lt hn + · exact Nat.succ_lt_succ (Nat.lt_succ_of_lt hn) + · intro H + suffices n.succ.succ = 0 by simpa + suffices Fin.mk _ hn = ⟨0, by omega⟩ by rwa [Fin.mk.inj_iff] at this + rw [nodup_iff_injective_get] at h + apply h; rw [← H]; simp + · intro H + suffices n.succ.succ = 1 by simpa + suffices Fin.mk _ hn = ⟨1, by omega⟩ by rwa [Fin.mk.inj_iff] at this + rw [nodup_iff_injective_get] at h + apply h; rw [← H]; simp + theorem pmap_next_eq_rotate_one (h : Nodup l) : (l.pmap l.next fun _ h => h) = l.rotate 1 := by - apply List.ext_nthLe + apply List.ext_get · simp · intros - rw [nthLe_pmap, nthLe_rotate, next_nthLe _ h] + rw [get_pmap, get_rotate, next_get _ h] -set_option linter.deprecated false in theorem pmap_prev_eq_rotate_length_sub_one (h : Nodup l) : (l.pmap l.prev fun _ h => h) = l.rotate (l.length - 1) := by - apply List.ext_nthLe + apply List.ext_get · simp · intro n hn hn' - rw [nthLe_rotate, nthLe_pmap, prev_nthLe _ h] + rw [get_rotate, get_pmap, prev_get _ h] -set_option linter.deprecated false in theorem prev_next (l : List α) (h : Nodup l) (x : α) (hx : x ∈ l) : prev l (next l x hx) (next_mem _ _ _) = x := by - obtain ⟨n, hn, rfl⟩ := nthLe_of_mem hx - simp only [next_nthLe, prev_nthLe, h, Nat.mod_add_mod] + 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] simp only [length_cons, Nat.succ_sub_succ_eq_sub, Nat.sub_zero, Nat.succ_eq_add_one, this] -set_option linter.deprecated false in theorem next_prev (l : List α) (h : Nodup l) (x : α) (hx : x ∈ l) : next l (prev l x hx) (prev_mem _ _ _) = x := by - obtain ⟨n, hn, rfl⟩ := nthLe_of_mem hx - simp only [next_nthLe, prev_nthLe, h, Nat.mod_add_mod] + 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] simp [this] -set_option linter.deprecated false in theorem prev_reverse_eq_next (l : List α) (h : Nodup l) (x : α) (hx : x ∈ l) : prev l.reverse x (mem_reverse.mpr hx) = next l x hx := by - obtain ⟨k, hk, rfl⟩ := nthLe_of_mem hx + obtain ⟨k, hk, rfl⟩ := getElem_of_mem hx have lpos : 0 < l.length := k.zero_le.trans_lt hk have key : l.length - 1 - k < l.length := by omega - rw [← nthLe_pmap l.next (fun _ h => h) (by simpa using hk)] - simp_rw [← nthLe_reverse l k (key.trans_le (by simp)), pmap_next_eq_rotate_one _ h] - rw [← nthLe_pmap l.reverse.prev fun _ h => h] + rw [← getElem_pmap l.next (fun _ h => h) (by simpa using hk)] + simp_rw [getElem_eq_getElem_reverse (l := l), pmap_next_eq_rotate_one _ h] + rw [← getElem_pmap l.reverse.prev fun _ h => h] · simp_rw [pmap_prev_eq_rotate_length_sub_one _ (nodup_reverse.mpr h), rotate_reverse, length_reverse, Nat.mod_eq_of_lt (Nat.sub_lt lpos Nat.succ_pos'), Nat.sub_sub_self (Nat.succ_le_of_lt lpos)] - rw [← nthLe_reverse] + rw [getElem_eq_getElem_reverse] · simp [Nat.sub_sub_self (Nat.le_sub_one_of_lt hk)] - · simpa using (Nat.sub_le _ _).trans_lt (Nat.sub_lt lpos Nat.succ_pos') · simpa theorem next_reverse_eq_prev (l : List α) (h : Nodup l) (x : α) (hx : x ∈ l) : @@ -466,7 +455,7 @@ theorem induction_on {C : Cycle α → Prop} (s : Cycle α) (H0 : C nil) assumption' /-- For `x : α`, `s : Cycle α`, `x ∈ s` indicates that `x` occurs at least once in `s`. -/ -def Mem (a : α) (s : Cycle α) : Prop := +def Mem (s : Cycle α) (a : α) : Prop := Quot.liftOn s (fun l => a ∈ l) fun _ _ e => propext <| e.mem_iff instance : Membership α (Cycle α) := @@ -539,7 +528,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. -/ @@ -554,7 +543,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 @@ -678,10 +667,10 @@ def decidableNontrivialCoe : ∀ l : List α, Decidable (Nontrivial (l : Cycle else isTrue ⟨x, y, h, by simp, by simp⟩ instance {s : Cycle α} : Decidable (Nontrivial s) := - Quot.recOnSubsingleton' s decidableNontrivialCoe + Quot.recOnSubsingleton s decidableNontrivialCoe instance {s : Cycle α} : Decidable (Nodup s) := - Quot.recOnSubsingleton' s List.nodupDecidable + Quot.recOnSubsingleton s List.nodupDecidable instance fintypeNodupCycle [Fintype α] : Fintype { s : Cycle α // s.Nodup } := Fintype.ofSurjective (fun l : { l : List α // l.Nodup } => ⟨l.val, by simpa using l.prop⟩) @@ -806,7 +795,7 @@ nonrec def Chain (r : α → α → Prop) (c : Cycle α) : Prop := · dsimp only cases' hab with n hn induction' n with d hd generalizing a b l m - · simp only [Nat.zero_eq, rotate_zero, cons.injEq] at hn + · simp only [rotate_zero, cons.injEq] at hn rw [hn.1, hn.2] · cases' l with c s · simp only [rotate_cons_succ, nil_append, rotate_singleton, cons.injEq] at hn @@ -891,7 +880,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 d75adc40ad06c..55576850f682a 100644 --- a/Mathlib/Data/List/Dedup.lean +++ b/Mathlib/Data/List/Dedup.lean @@ -5,6 +5,7 @@ Authors: Mario Carneiro -/ import Mathlib.Data.List.Nodup import Mathlib.Data.List.Lattice +import Batteries.Data.List.Pairwise /-! # Erasure of duplicates in a list @@ -81,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 @@ -95,7 +96,7 @@ theorem dedup_eq_nil (l : List α) : l.dedup = [] ↔ l = [] := by induction' l with a l hl · exact Iff.rfl · by_cases h : a ∈ l - · simp only [List.dedup_cons_of_mem h, hl, List.ne_nil_of_mem h] + · simp only [List.dedup_cons_of_mem h, hl, List.ne_nil_of_mem h, reduceCtorEq] · simp only [List.dedup_cons_of_not_mem h, List.cons_ne_nil] protected theorem Nodup.dedup {l : List α} (h : l.Nodup) : l.dedup = l := diff --git a/Mathlib/Data/List/Defs.lean b/Mathlib/Data/List/Defs.lean index cc5d8513bf39b..f0aad1fcd0f00 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 @@ -29,15 +30,30 @@ variable {α β γ δ ε ζ : Type*} instance [DecidableEq α] : SDiff (List α) := ⟨List.diff⟩ --- mathlib3 `array` is not ported. --- Porting note: see --- https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/List.2Ehead/near/313204716 --- for the fooI naming convention. /-- "Inhabited" `get` function: returns `default` instead of `none` in the case that the index is out of bounds. -/ def getI [Inhabited α] (l : List α) (n : Nat) : α := getD l n default +/-- The head of a list, or the default element of the type is the list is `nil`. -/ +def headI [Inhabited α] : List α → α + | [] => default + | (a :: _) => a + +@[simp] theorem headI_nil [Inhabited α] : ([] : List α).headI = default := rfl +@[simp] theorem headI_cons [Inhabited α] {h : α} {t : List α} : (h :: t).headI = h := rfl + +/-- The last element of a list, with the default if list empty -/ +def getLastI [Inhabited α] : List α → α + | [] => default + | [a] => a + | [_, b] => b + | _ :: _ :: l => getLastI l + +/-- List with a single given element. -/ +@[inline, deprecated List.pure (since := "2024-03-24")] +protected def ret {α : Type u} (a : α) : List α := [a] + /-- "Inhabited" `take` function: Take `n` elements from a list `l`. If `l` has less than `n` elements, append `n - length l` elements `default`. -/ def takeI [Inhabited α] (n : Nat) (l : List α) : List α := @@ -431,4 +447,64 @@ theorem iterate_eq_iterateTR : @iterate = @iterateTR := by funext α f a n exact Eq.symm <| iterateTR_loop_eq f a n [] +section MapAccumr + +/-- Runs a function over a list returning the intermediate results and a final result. -/ +def mapAccumr (f : α → γ → γ × β) : List α → γ → γ × List β + | [], c => (c, []) + | y :: yr, c => + let r := mapAccumr f yr c + let z := f y r.1 + (z.1, z.2 :: r.2) + +/-- Length of the list obtained by `mapAccumr`. -/ +@[simp] +theorem length_mapAccumr : + ∀ (f : α → γ → γ × β) (x : List α) (s : γ), length (mapAccumr f x s).2 = length x + | f, _ :: x, s => congr_arg succ (length_mapAccumr f x s) + | _, [], _ => rfl + +/-- Runs a function over two lists returning the intermediate results and a final result. -/ +def mapAccumr₂ (f : α → β → γ → γ × δ) : List α → List β → γ → γ × List δ + | [], _, c => (c, []) + | _, [], c => (c, []) + | x :: xr, y :: yr, c => + let r := mapAccumr₂ f xr yr c + let q := f x y r.1 + (q.1, q.2 :: r.2) + +/-- Length of a list obtained using `mapAccumr₂`. -/ +@[simp] +theorem length_mapAccumr₂ : + ∀ (f : α → β → γ → γ × δ) (x y c), length (mapAccumr₂ f x y c).2 = min (length x) (length y) + | f, _ :: x, _ :: y, c => + calc + succ (length (mapAccumr₂ f x y c).2) = succ (min (length x) (length y)) := + congr_arg succ (length_mapAccumr₂ f x y c) + _ = min (succ (length x)) (succ (length y)) := Eq.symm (succ_min_succ (length x) (length y)) + | _, _ :: _, [], _ => rfl + | _, [], _ :: _, _ => rfl + | _, [], [], _ => rfl + +end MapAccumr + +section Deprecated + +@[deprecated List.mem_cons (since := "2024-08-10")] +theorem mem_cons_eq (a y : α) (l : List α) : (a ∈ y :: l) = (a = y ∨ a ∈ l) := + propext List.mem_cons + +alias ⟨eq_or_mem_of_mem_cons, _⟩ := mem_cons + +@[deprecated List.not_mem_nil (since := "2024-08-10")] +theorem not_exists_mem_nil (p : α → Prop) : ¬∃ x ∈ @nil α, p x := + fun ⟨_, hx, _⟩ => List.not_mem_nil _ hx + +@[deprecated (since := "2024-03-23")] alias not_bex_nil := not_exists_mem_nil +@[deprecated (since := "2024-03-23")] alias bex_cons := exists_mem_cons + +@[deprecated (since := "2024-08-10")] alias length_le_of_sublist := Sublist.length_le + +end Deprecated + end List diff --git a/Mathlib/Data/List/DropRight.lean b/Mathlib/Data/List/DropRight.lean index 6a591c57257f2..10638f80de52e 100644 --- a/Mathlib/Data/List/DropRight.lean +++ b/Mathlib/Data/List/DropRight.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Yakov Pechersky. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yakov Pechersky -/ -import Mathlib.Data.List.Infix +import Mathlib.Data.List.Basic /-! # Dropping or taking from lists on the right @@ -155,7 +155,7 @@ variable (p) (l) theorem dropWhile_idempotent : dropWhile p (dropWhile p l) = dropWhile p l := by simp only [dropWhile_eq_self_iff] - exact fun h => dropWhile_nthLe_zero_not p l h + exact fun h => dropWhile_get_zero_not p l h theorem rdropWhile_idempotent : rdropWhile p (rdropWhile p l) = rdropWhile p l := rdropWhile_eq_self_iff.mpr (rdropWhile_last_not _ _) @@ -198,7 +198,7 @@ theorem rtakeWhile_eq_nil_iff : rtakeWhile p l = [] ↔ ∀ hl : l ≠ [], ¬p ( · simp only [rtakeWhile, takeWhile, reverse_nil, true_iff] intro f; contradiction · simp only [rtakeWhile, reverse_append, takeWhile, ne_eq, not_false_eq_true, - getLast_append_of_ne_nil, getLast_singleton] + getLast_append_of_ne_nil, getLast_singleton, reduceCtorEq] refine ⟨fun h => ?_ , fun h => ?_⟩ · split at h <;> simp_all · simp [h] diff --git a/Mathlib/Data/List/Duplicate.lean b/Mathlib/Data/List/Duplicate.lean index 0a020d73eafca..9023118d20cb8 100644 --- a/Mathlib/Data/List/Duplicate.lean +++ b/Mathlib/Data/List/Duplicate.lean @@ -39,9 +39,9 @@ theorem Duplicate.duplicate_cons (h : x ∈+ l) (y : α) : x ∈+ y :: l := Duplicate.cons_duplicate h theorem Duplicate.mem (h : x ∈+ l) : x ∈ l := by - induction' h with l' _ y l' _ hm - · exact mem_cons_self _ _ - · exact mem_cons_of_mem _ hm + induction h with + | cons_mem => exact mem_cons_self _ _ + | cons_duplicate _ hm => exact mem_cons_of_mem _ hm theorem Duplicate.mem_cons_self (h : x ∈+ x :: l) : x ∈ l := by cases' h with _ h _ _ h 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 4b79e8b7234fa..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 @@ -90,7 +90,7 @@ instance estimator' : constructor · simp only [List.minimum_of_length_pos_le_iff] exact suffixLevenshtein_minimum_le_levenshtein_append _ _ _ - · exact List.length_le_of_sublist (List.sublist_append_right _ _) + · exact (List.sublist_append_right _ _).length_le improve_spec e := by dsimp [EstimatorData.improve] match e.pre_rev, e.split, e.bound_eq, e.distances_eq with diff --git a/Mathlib/Data/List/Enum.lean b/Mathlib/Data/List/Enum.lean index e7bd524eb313e..a574ea756a233 100644 --- a/Mathlib/Data/List/Enum.lean +++ b/Mathlib/Data/List/Enum.lean @@ -3,54 +3,80 @@ 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 + +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 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) : get? (enumFrom n l) m = (get? l m).map fun a => (n + m, a) := by simp @[deprecated (since := "2024-04-06")] alias enumFrom_get? := get?_enumFrom +@[deprecated getElem?_enum (since := "2024-08-15")] theorem get?_enum (l : List α) (n) : get? (enum l) n = (get? l n).map fun a => (n, a) := by simp @[deprecated (since := "2024-04-06")] alias enum_get? := get?_enum +@[deprecated getElem_enumFrom (since := "2024-08-15")] theorem get_enumFrom (l : List α) (n) (i : Fin (l.enumFrom n).length) : (l.enumFrom n).get i = (n + i, l.get (i.cast enumFrom_length)) := by simp +@[deprecated getElem_enum (since := "2024-08-15")] theorem get_enum (l : List α) (i : Fin l.enum.length) : l.enum.get i = (i.1, l.get (i.cast enum_length)) := by simp +@[deprecated mk_add_mem_enumFrom_iff_getElem? (since := "2024-08-12")] theorem mk_add_mem_enumFrom_iff_get? {n i : ℕ} {x : α} {l : List α} : (n + i, x) ∈ enumFrom n l ↔ l.get? i = x := by simp [mem_iff_get?] +@[deprecated mk_mem_enumFrom_iff_le_and_getElem?_sub (since := "2024-08-12")] theorem mk_mem_enumFrom_iff_le_and_get?_sub {n i : ℕ} {x : α} {l : List α} : (i, x) ∈ enumFrom n l ↔ n ≤ i ∧ l.get? (i - n) = x := by - if h : n ≤ i then - rcases Nat.exists_eq_add_of_le h with ⟨i, rfl⟩ - simp [mk_add_mem_enumFrom_iff_get?, Nat.add_sub_cancel_left] - else - have : ∀ k, n + k ≠ i := by rintro k rfl; simp at h - simp [h, mem_iff_get?, this] + simp [mk_mem_enumFrom_iff_le_and_getElem?_sub] +@[deprecated mk_mem_enum_iff_getElem? (since := "2024-08-15")] theorem mk_mem_enum_iff_get? {i : ℕ} {x : α} {l : List α} : (i, x) ∈ enum l ↔ l.get? i = x := by - simp [enum, mk_mem_enumFrom_iff_le_and_get?_sub] + simp [enum, mk_mem_enumFrom_iff_le_and_getElem?_sub] +set_option linter.deprecated false in +@[deprecated mem_enum_iff_getElem? (since := "2024-08-15")] 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 3ca008028c7c7..62d8122999597 100644 --- a/Mathlib/Data/List/FinRange.lean +++ b/Mathlib/Data/List/FinRange.lean @@ -1,10 +1,11 @@ /- 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 +import Batteries.Data.List.Perm /-! # Lists of elements of `Fin n` @@ -29,7 +30,7 @@ theorem finRange_succ_eq_map (n : ℕ) : finRange n.succ = 0 :: (finRange n).map apply map_injective_iff.mpr Fin.val_injective rw [map_cons, map_coe_finRange, range_succ_eq_map, Fin.val_zero, ← map_coe_finRange, map_map, map_map] - simp only [Function.comp, Fin.val_succ] + simp only [Function.comp_def, Fin.val_succ] theorem finRange_succ (n : ℕ) : finRange n.succ = (finRange n |>.map Fin.castSucc |>.concat (.last _)) := by @@ -41,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 @@ -71,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 132891a19defd..20808976c60ab 100644 --- a/Mathlib/Data/List/Forall2.lean +++ b/Mathlib/Data/List/Forall2.lean @@ -84,15 +84,18 @@ theorem forall₂_cons_right_iff {b l u} : match u, h with | _, ⟨_, _, h₁, h₂, rfl⟩ => Forall₂.cons h₁ h₂ +#adaptation_note +/-- +After nightly-2024-09-06 we can remove the `_root_` prefixes below. +-/ theorem forall₂_and_left {p : α → Prop} : ∀ l u, Forall₂ (fun a b => p a ∧ R a b) l u ↔ (∀ a ∈ l, p a) ∧ Forall₂ R l u | [], u => by - simp only [forall₂_nil_left_iff, forall_prop_of_false (not_mem_nil _), imp_true_iff, - true_and_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, + simp only [forall₂_and_left l, forall₂_cons_left_iff, forall_mem_cons, _root_.and_assoc, @and_comm _ (p a), @and_left_comm _ (p a), exists_and_left] - simp only [and_comm, and_assoc, and_left_comm, ← exists_and_right] + simp only [_root_.and_comm, _root_.and_assoc, and_left_comm, ← exists_and_right] @[simp] theorem forall₂_map_left_iff {f : γ → α} : @@ -136,10 +139,6 @@ theorem Forall₂.get : | _, _, Forall₂.cons ha _, 0, _, _ => ha | _, _, Forall₂.cons _ hl, succ _, _, _ => hl.get _ _ -set_option linter.deprecated false in -@[deprecated (since := "2024-05-05")] theorem Forall₂.nthLe {x y} (h : Forall₂ R x y) ⦃i : ℕ⦄ - (hx : i < x.length) (hy : i < y.length) : R (x.nthLe i hx) (y.nthLe i hy) := h.get hx hy - theorem forall₂_of_length_eq_of_get : ∀ {x : List α} {y : List β}, x.length = y.length → (∀ i h₁ h₂, R (x.get ⟨i, h₁⟩) (y.get ⟨i, h₂⟩)) → Forall₂ R x y @@ -149,20 +148,10 @@ theorem forall₂_of_length_eq_of_get : (forall₂_of_length_eq_of_get (succ.inj hl) fun i h₁ h₂ => h i.succ (succ_lt_succ h₁) (succ_lt_succ h₂)) -set_option linter.deprecated false in -@[deprecated (since := "2024-05-05")] theorem forall₂_of_length_eq_of_nthLe {x y} - (H : x.length = y.length) (H' : ∀ i h₁ h₂, R (x.nthLe i h₁) (y.nthLe i h₂)) : - Forall₂ R x y := forall₂_of_length_eq_of_get H H' - theorem forall₂_iff_get {l₁ : List α} {l₂ : List β} : Forall₂ R l₁ l₂ ↔ l₁.length = l₂.length ∧ ∀ i h₁ h₂, R (l₁.get ⟨i, h₁⟩) (l₂.get ⟨i, h₂⟩) := ⟨fun h => ⟨h.length_eq, h.get⟩, fun h => forall₂_of_length_eq_of_get h.1 h.2⟩ -set_option linter.deprecated false in -@[deprecated (since := "2024-05-05")] theorem forall₂_iff_nthLe {l₁ : List α} {l₂ : List β} : - Forall₂ R l₁ l₂ ↔ l₁.length = l₂.length ∧ ∀ i h₁ h₂, R (l₁.nthLe i h₁) (l₂.nthLe i h₂) := - forall₂_iff_get - theorem forall₂_zip : ∀ {l₁ l₂}, Forall₂ R l₁ l₂ → ∀ {a b}, (a, b) ∈ zip l₁ l₂ → R a b | _, _, Forall₂.cons h₁ h₂, x, y, hx => by rw [zip, zipWith, mem_cons] at hx @@ -258,7 +247,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₂] @@ -282,19 +271,25 @@ inductive SublistForall₂ (R : α → β → Prop) : List α → List β → Pr theorem sublistForall₂_iff {l₁ : List α} {l₂ : List β} : SublistForall₂ R l₁ l₂ ↔ ∃ l, Forall₂ R l₁ l ∧ l <+ l₂ := by constructor <;> intro h - · induction' h with _ a b l1 l2 rab _ ih b l1 l2 _ ih - · exact ⟨nil, Forall₂.nil, nil_sublist _⟩ - · obtain ⟨l, hl1, hl2⟩ := ih + · induction h with + | nil => exact ⟨nil, Forall₂.nil, nil_sublist _⟩ + | @cons a b l1 l2 rab _ ih => + obtain ⟨l, hl1, hl2⟩ := ih exact ⟨b :: l, Forall₂.cons rab hl1, hl2.cons_cons b⟩ - · obtain ⟨l, hl1, hl2⟩ := ih + | cons_right _ ih => + obtain ⟨l, hl1, hl2⟩ := ih exact ⟨l, hl1, hl2.trans (Sublist.cons _ (Sublist.refl _))⟩ · obtain ⟨l, hl1, hl2⟩ := h revert l₁ - induction' hl2 with _ _ _ _ ih _ _ _ _ ih <;> intro l₁ hl1 - · rw [forall₂_nil_right_iff.1 hl1] + induction hl2 with + | slnil => + intro l₁ hl1 + rw [forall₂_nil_right_iff.1 hl1] exact SublistForall₂.nil - · exact SublistForall₂.cons_right (ih hl1) - · cases' hl1 with _ _ _ _ hr hl _ + | cons _ _ ih => intro l₁ hl1; exact SublistForall₂.cons_right (ih hl1) + | cons₂ _ _ ih => + intro l₁ hl1 + cases' hl1 with _ _ _ _ hr hl _ exact SublistForall₂.cons hr (ih hl) instance SublistForall₂.is_refl [IsRefl α Rₐ] : IsRefl (List α) (SublistForall₂ Rₐ) := @@ -303,11 +298,13 @@ instance SublistForall₂.is_refl [IsRefl α Rₐ] : IsRefl (List α) (SublistFo instance SublistForall₂.is_trans [IsTrans α Rₐ] : IsTrans (List α) (SublistForall₂ Rₐ) := ⟨fun a b c => by revert a b - induction' c with _ _ ih - · rintro _ _ h1 h2 + induction c with + | nil => + rintro _ _ h1 h2 cases h2 exact h1 - · rintro a b h1 h2 + | cons _ _ ih => + rintro a b h1 h2 cases' h2 with _ _ _ _ _ hbc tbc _ _ y1 btc · cases h1 exact SublistForall₂.nil @@ -324,4 +321,22 @@ theorem Sublist.sublistForall₂ {l₁ l₂ : List α} (h : l₁ <+ l₂) [IsRef theorem tail_sublistForall₂_self [IsRefl α Rₐ] (l : List α) : SublistForall₂ Rₐ l.tail l := l.tail_sublist.sublistForall₂ +@[simp] +theorem sublistForall₂_map_left_iff {f : γ → α} {l₁ : List γ} {l₂ : List β} : + SublistForall₂ R (map f l₁) l₂ ↔ SublistForall₂ (fun c b => R (f c) b) l₁ l₂ := by + simp [sublistForall₂_iff] + +@[simp] +theorem sublistForall₂_map_right_iff {f : γ → β} {l₁ : List α} {l₂ : List γ} : + SublistForall₂ R l₁ (map f l₂) ↔ SublistForall₂ (fun a c => R a (f c)) l₁ l₂ := by + simp only [sublistForall₂_iff] + constructor + · rintro ⟨l1, h1, h2⟩ + obtain ⟨l', hl1, rfl⟩ := sublist_map_iff.mp h2 + use l' + simpa [hl1] using h1 + · rintro ⟨l1, h1, h2⟩ + use l1.map f + simp [h1, h2.map] + end List diff --git a/Mathlib/Data/List/GetD.lean b/Mathlib/Data/List/GetD.lean index 9b888110c53b9..e16ce04be7e33 100644 --- a/Mathlib/Data/List/GetD.lean +++ b/Mathlib/Data/List/GetD.lean @@ -6,7 +6,6 @@ Mario Carneiro -/ import Mathlib.Data.List.Defs import Mathlib.Data.Option.Basic -import Mathlib.Init.Data.List.Basic import Mathlib.Util.AssertExists /-! # getD and getI @@ -14,11 +13,9 @@ import Mathlib.Util.AssertExists This file provides theorems for working with the `getD` and `getI` functions. These are used to access an element of a list by numerical index, with a default value as a fallback when the index is out of range. - -/ --- Make sure we haven't imported `Data.Nat.Order.Basic` -assert_not_exists OrderedSub +assert_not_imported Mathlib.Algebra.Order.Group.Nat namespace List @@ -75,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] @@ -113,11 +107,11 @@ theorem getI_cons_succ : getI (x :: xs) (n + 1) = getI xs n := rfl theorem getI_eq_getElem {n : ℕ} (hn : n < l.length) : l.getI n = l[n] := - getD_eq_getElem .. + getD_eq_getElem l default hn @[deprecated getI_eq_getElem (since := "2024-08-02")] theorem getI_eq_get {n : ℕ} (hn : n < l.length) : l.getI n = l.get ⟨n, hn⟩ := - getD_eq_getElem .. + getD_eq_getElem l default hn theorem getI_eq_default {n : ℕ} (hn : l.length ≤ n) : l.getI n = default := getD_eq_default _ _ hn @@ -138,3 +132,5 @@ theorem getI_eq_iget_get? (n : ℕ) : l.getI n = (l.get? n).iget := by theorem getI_zero_eq_headI : l.getI 0 = l.headI := by cases l <;> rfl end getI + +end List diff --git a/Mathlib/Data/List/Indexes.lean b/Mathlib/Data/List/Indexes.lean index 6da70619cfb4b..7e53018e89d4b 100644 --- a/Mathlib/Data/List/Indexes.lean +++ b/Mathlib/Data/List/Indexes.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jannis Limperg -/ import Mathlib.Data.List.OfFn -import Mathlib.Data.List.Range import Mathlib.Data.List.Zip /-! @@ -25,34 +24,11 @@ variable {α : Type u} {β : Type v} section MapIdx --- Porting note: Add back old definition because it's easier for writing proofs. - -/-- Lean3 `map_with_index` helper function -/ -protected def oldMapIdxCore (f : ℕ → α → β) : ℕ → List α → List β - | _, [] => [] - | k, a :: as => f k a :: List.oldMapIdxCore f (k + 1) as - -/-- Given a function `f : ℕ → α → β` and `as : List α`, `as = [a₀, a₁, ...]`, returns the list -`[f 0 a₀, f 1 a₁, ...]`. -/ -protected def oldMapIdx (f : ℕ → α → β) (as : List α) : List β := - List.oldMapIdxCore f 0 as - @[simp] theorem mapIdx_nil {α β} (f : ℕ → α → β) : mapIdx f [] = [] := rfl -protected theorem oldMapIdxCore_eq (l : List α) (f : ℕ → α → β) (n : ℕ) : - l.oldMapIdxCore f n = l.oldMapIdx fun i a ↦ f (i + n) a := by - induction' l with hd tl hl generalizing f n - · rfl - · rw [List.oldMapIdx] - simp only [List.oldMapIdxCore, hl, Nat.add_left_comm, Nat.add_comm, Nat.add_zero] --- Porting note: convert new definition to old definition. --- A few new theorems are added to achieve this --- 1. Prove that `oldMapIdxCore f (l ++ [e]) = oldMapIdxCore f l ++ [f l.length e]` --- 2. Prove that `oldMapIdx f (l ++ [e]) = oldMapIdx f l ++ [f l.length e]` --- 3. Prove list induction using `∀ l e, p [] → (p l → p (l ++ [e])) → p l` theorem list_reverse_induction (p : List α → Prop) (base : p []) (ind : ∀ (l : List α) (e : α), p l → p (l ++ [e])) : (∀ (l : List α), p l) := by let q := fun l ↦ p (reverse l) @@ -65,39 +41,6 @@ theorem list_reverse_induction (p : List α → Prop) (base : p []) · apply pq; simp only [reverse_nil, base] · apply pq; simp only [reverse_cons]; apply ind; apply qp; rw [reverse_reverse]; exact ih -protected theorem oldMapIdxCore_append : ∀ (f : ℕ → α → β) (n : ℕ) (l₁ l₂ : List α), - List.oldMapIdxCore f n (l₁ ++ l₂) = - List.oldMapIdxCore f n l₁ ++ List.oldMapIdxCore f (n + l₁.length) l₂ := by - intros f n l₁ l₂ - generalize e : (l₁ ++ l₂).length = len - revert n l₁ l₂ - induction' len with len ih <;> intros n l₁ l₂ h - · have l₁_nil : l₁ = [] := by - cases l₁ - · rfl - · contradiction - have l₂_nil : l₂ = [] := by - cases l₂ - · rfl - · rw [List.length_append] at h; contradiction - simp only [l₁_nil, l₂_nil]; rfl - · cases' l₁ with head tail - · rfl - · simp only [List.oldMapIdxCore, List.append_eq, length_cons, cons_append,cons.injEq, true_and] - suffices n + Nat.succ (length tail) = n + 1 + tail.length by - rw [this] - apply ih (n + 1) _ _ _ - simp only [cons_append, length_cons, length_append, Nat.succ.injEq] at h - simp only [length_append, h] - rw [Nat.add_assoc]; simp only [Nat.add_comm] - -protected theorem oldMapIdx_append : ∀ (f : ℕ → α → β) (l : List α) (e : α), - List.oldMapIdx f (l ++ [e]) = List.oldMapIdx f l ++ [f l.length e] := by - intros f l e - unfold List.oldMapIdx - rw [List.oldMapIdxCore_append f 0 l [e]] - simp only [Nat.zero_add]; rfl - theorem mapIdxGo_append : ∀ (f : ℕ → α → β) (l₁ l₂ : List α) (arr : Array β), mapIdx.go f (l₁ ++ l₂) arr = mapIdx.go f l₂ (List.toArray (mapIdx.go f l₁ arr)) := by intros f l₁ l₂ arr @@ -112,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 @@ -124,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] @@ -134,15 +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] - -protected theorem new_def_eq_old_def : - ∀ (f : ℕ → α → β) (l : List α), l.mapIdx f = List.oldMapIdx f l := by - intro f - apply list_reverse_induction - · rfl - · intro l e h - rw [List.oldMapIdx_append, mapIdx_append_one, h] + Array.push_toList, Array.toList_toArray] @[local simp] theorem map_enumFrom_eq_zipWith : ∀ (l : List α) (n : ℕ) (f : ℕ → α → β), @@ -168,13 +103,47 @@ theorem map_enumFrom_eq_zipWith : ∀ (l : List α) (n : ℕ) (f : ℕ → α simp only [comp, Nat.add_assoc, Nat.add_comm, Nat.add_succ] simp only [length_cons, Nat.succ.injEq] at e; exact e +theorem length_mapIdx_go (f : ℕ → α → β) : ∀ (l : List α) (arr : Array β), + (mapIdx.go f l arr).length = l.length + arr.size + | [], _ => by simp [mapIdx.go] + | a :: l, _ => by + simp only [mapIdx.go, length_cons] + rw [length_mapIdx_go] + simp + omega + +@[simp] theorem length_mapIdx (l : List α) (f : ℕ → α → β) : (l.mapIdx f).length = l.length := by + simp [mapIdx, length_mapIdx_go] + +theorem getElem?_mapIdx_go (f : ℕ → α → β) : ∀ (l : List α) (arr : Array β) (i : ℕ), + (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 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_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 + · have : i - arr.size = i - (arr.size + 1) + 1 := by omega + simp_all + +@[simp] theorem getElem?_mapIdx (l : List α) (f : ℕ → α → β) (i : ℕ) : + (l.mapIdx f)[i]? = Option.map (f i) l[i]? := by + simp [mapIdx, getElem?_mapIdx_go] + theorem mapIdx_eq_enum_map (l : List α) (f : ℕ → α → β) : l.mapIdx f = l.enum.map (Function.uncurry f) := by - rw [List.new_def_eq_old_def] - induction' l with hd tl hl generalizing f - · rfl - · rw [List.oldMapIdx, List.oldMapIdxCore, List.oldMapIdxCore_eq, hl] - simp [map, enum_eq_zip_range, map_uncurry_zip_eq_zipWith] + ext1 i + simp only [getElem?_mapIdx, Option.map, getElem?_map, getElem?_enum] + split <;> simp @[simp] theorem mapIdx_cons (l : List α) (f : ℕ → α → β) (a : α) : @@ -188,29 +157,96 @@ theorem mapIdx_append (K L : List α) (f : ℕ → α → β) : · rfl · simp [IH fun i ↦ f (i + 1), Nat.add_assoc] -@[simp] -theorem length_mapIdx (l : List α) (f : ℕ → α → β) : (l.mapIdx f).length = l.length := by - induction' l with hd tl IH generalizing f - · rfl - · simp [IH] - @[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] -set_option linter.deprecated false in -@[simp, deprecated (since := "2023-02-11")] -theorem nthLe_mapIdx (l : List α) (f : ℕ → α → β) (i : ℕ) (h : i < l.length) +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) : - (l.mapIdx f).nthLe i h' = f i (l.nthLe i h) := by + (l.mapIdx f).get ⟨i, h'⟩ = f i (l.get ⟨i, h⟩) := by simp [mapIdx_eq_enum_map, enum_eq_zip_range] +@[deprecated (since := "2024-08-19")] alias nthLe_mapIdx := get_mapIdx + theorem mapIdx_eq_ofFn (l : List α) (f : ℕ → α → β) : l.mapIdx f = ofFn fun i : Fin l.length ↦ f (i : ℕ) (l.get i) := by induction l generalizing f with | nil => simp | cons _ _ IH => simp [IH] +section deprecated + +/-- Lean3 `map_with_index` helper function -/ +@[deprecated (since := "2024-08-15")] +protected def oldMapIdxCore (f : ℕ → α → β) : ℕ → List α → List β + | _, [] => [] + | k, a :: as => f k a :: List.oldMapIdxCore f (k + 1) as + +set_option linter.deprecated false in +/-- Given a function `f : ℕ → α → β` and `as : List α`, `as = [a₀, a₁, ...]`, returns the list +`[f 0 a₀, f 1 a₁, ...]`. -/ +@[deprecated (since := "2024-08-15")] +protected def oldMapIdx (f : ℕ → α → β) (as : List α) : List β := + List.oldMapIdxCore f 0 as + +set_option linter.deprecated false in +@[deprecated (since := "2024-08-15")] +protected theorem oldMapIdxCore_eq (l : List α) (f : ℕ → α → β) (n : ℕ) : + l.oldMapIdxCore f n = l.oldMapIdx fun i a ↦ f (i + n) a := by + induction' l with hd tl hl generalizing f n + · rfl + · rw [List.oldMapIdx] + simp only [List.oldMapIdxCore, hl, Nat.add_left_comm, Nat.add_comm, Nat.add_zero] + +set_option linter.deprecated false in +@[deprecated (since := "2024-08-15")] +protected theorem oldMapIdxCore_append : ∀ (f : ℕ → α → β) (n : ℕ) (l₁ l₂ : List α), + List.oldMapIdxCore f n (l₁ ++ l₂) = + List.oldMapIdxCore f n l₁ ++ List.oldMapIdxCore f (n + l₁.length) l₂ := by + intros f n l₁ l₂ + generalize e : (l₁ ++ l₂).length = len + revert n l₁ l₂ + induction' len with len ih <;> intros n l₁ l₂ h + · have l₁_nil : l₁ = [] := by + cases l₁ + · rfl + · contradiction + have l₂_nil : l₂ = [] := by + cases l₂ + · rfl + · rw [List.length_append] at h; contradiction + simp only [l₁_nil, l₂_nil]; rfl + · cases' l₁ with head tail + · rfl + · simp only [List.oldMapIdxCore, List.append_eq, length_cons, cons_append,cons.injEq, true_and] + suffices n + Nat.succ (length tail) = n + 1 + tail.length by + rw [this] + apply ih (n + 1) _ _ _ + simp only [cons_append, length_cons, length_append, Nat.succ.injEq] at h + simp only [length_append, h] + rw [Nat.add_assoc]; simp only [Nat.add_comm] + +set_option linter.deprecated false in +@[deprecated (since := "2024-08-15")] +protected theorem oldMapIdx_append : ∀ (f : ℕ → α → β) (l : List α) (e : α), + List.oldMapIdx f (l ++ [e]) = List.oldMapIdx f l ++ [f l.length e] := by + intros f l e + unfold List.oldMapIdx + rw [List.oldMapIdxCore_append f 0 l [e]] + simp only [Nat.zero_add]; rfl + +set_option linter.deprecated false in +@[deprecated (since := "2024-08-15")] +protected theorem new_def_eq_old_def : + ∀ (f : ℕ → α → β) (l : List α), l.mapIdx f = List.oldMapIdx f l := by + intro f + apply list_reverse_induction + · rfl + · intro l e h + rw [List.oldMapIdx_append, mapIdx_append_one, h] + +end deprecated + end MapIdx section FoldrIdx @@ -247,73 +283,6 @@ theorem findIdxs_eq_map_indexesValues (p : α → Prop) [DecidablePred p] (as : map_filter_eq_foldr, findIdxs, uncurry, foldrIdx_eq_foldr_enum, decide_eq_true_eq, comp_apply, Bool.cond_decide] -section FindIdx -- TODO: upstream to Batteries - -theorem findIdx_eq_length {p : α → Bool} {xs : List α} : - xs.findIdx p = xs.length ↔ ∀ x ∈ xs, ¬p x := by - induction xs with - | nil => simp_all - | cons x xs ih => - rw [findIdx_cons, length_cons] - constructor <;> intro h - · have : ¬p x := by contrapose h; simp_all - simp_all - · simp_rw [h x (mem_cons_self x xs), cond_false, Nat.succ.injEq, ih] - exact fun y hy ↦ h y <| mem_cons.mpr (Or.inr hy) - -theorem findIdx_le_length (p : α → Bool) {xs : List α} : xs.findIdx p ≤ xs.length := by - by_cases e : ∃ x ∈ xs, p x - · exact (findIdx_lt_length_of_exists e).le - · push_neg at e; exact (findIdx_eq_length.mpr e).le - -theorem findIdx_lt_length {p : α → Bool} {xs : List α} : - xs.findIdx p < xs.length ↔ ∃ x ∈ xs, p x := by - rw [← not_iff_not, not_lt] - have := @le_antisymm_iff _ _ (xs.findIdx p) xs.length - simp only [findIdx_le_length, true_and] at this - rw [← this, findIdx_eq_length, not_exists] - simp only [Bool.not_eq_true, not_and] - -/-- `p` does not hold for elements with indices less than `xs.findIdx p`. -/ -theorem not_of_lt_findIdx {p : α → Bool} {xs : List α} {i : ℕ} (h : i < xs.findIdx p) : - ¬p (xs.get ⟨i, h.trans_le (findIdx_le_length p)⟩) := by - revert i - induction xs with - | nil => intro i h; rw [findIdx_nil] at h; omega - | cons x xs ih => - intro i h - have ho := h - rw [findIdx_cons] at h - have npx : ¬p x := by by_contra y; rw [y, cond_true] at h; omega - simp_rw [npx, cond_false] at h - cases' i.eq_zero_or_pos with e e - · simpa only [e, Fin.zero_eta, get_cons_zero] - · have ipm := Nat.succ_pred_eq_of_pos e - have ilt := ho.trans_le (findIdx_le_length p) - rw [(Fin.mk_eq_mk (h' := ipm ▸ ilt)).mpr ipm.symm, get_cons_succ] - rw [← ipm, Nat.succ_lt_succ_iff] at h - exact ih h - -theorem le_findIdx_of_not {p : α → Bool} {xs : List α} {i : ℕ} (h : i < xs.length) - (h2 : ∀ j (hji : j < i), ¬p (xs.get ⟨j, hji.trans h⟩)) : i ≤ xs.findIdx p := by - by_contra! f - exact absurd (@findIdx_get _ p xs (f.trans h)) (h2 (xs.findIdx p) f) - -theorem lt_findIdx_of_not {p : α → Bool} {xs : List α} {i : ℕ} (h : i < xs.length) - (h2 : ∀ j (hji : j ≤ i), ¬p (xs.get ⟨j, hji.trans_lt h⟩)) : i < xs.findIdx p := by - by_contra! f - exact absurd (@findIdx_get _ p xs (f.trans_lt h)) (h2 (xs.findIdx p) f) - -theorem findIdx_eq {p : α → Bool} {xs : List α} {i : ℕ} (h : i < xs.length) : - xs.findIdx p = i ↔ p (xs.get ⟨i, h⟩) ∧ ∀ j (hji : j < i), ¬p (xs.get ⟨j, hji.trans h⟩) := by - refine ⟨fun f ↦ ⟨f ▸ (@findIdx_get _ p xs (f ▸ h)), fun _ hji ↦ not_of_lt_findIdx (f ▸ hji)⟩, - fun ⟨h1, h2⟩ ↦ ?_⟩ - apply Nat.le_antisymm _ (le_findIdx_of_not h h2) - contrapose! h1 - exact not_of_lt_findIdx h1 - -end FindIdx - section FoldlIdx -- Porting note: Changed argument order of `foldlIdxSpec` to align better with `foldlIdx`. @@ -388,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 8d4e9784ae69e..b7bf8b65b8356 100644 --- a/Mathlib/Data/List/Infix.lean +++ b/Mathlib/Data/List/Infix.lean @@ -25,55 +25,31 @@ All those (except `insert`) are defined in `Mathlib.Data.List.Defs`. * `l₁ <:+: l₂`: `l₁` is an infix of `l₂`. -/ -open Nat - -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 -/ - section Fix -theorem prefix_rfl : l <+: l := - prefix_refl _ - -theorem suffix_rfl : l <:+ l := - suffix_refl _ - -theorem infix_rfl : l <:+: l := - infix_refl _ - -theorem prefix_concat (a : α) (l) : l <+: concat l a := by simp - -theorem prefix_concat_iff {l₁ l₂ : List α} {a : α} : - l₁ <+: l₂ ++ [a] ↔ l₁ = l₂ ++ [a] ∨ l₁ <+: l₂ := by - simpa only [← reverse_concat', reverse_inj, reverse_suffix] using - suffix_cons_iff (l₁ := l₁.reverse) (l₂ := l₂.reverse) - -protected alias ⟨_, isSuffix.reverse⟩ := reverse_prefix - -protected alias ⟨_, isPrefix.reverse⟩ := reverse_suffix - -protected alias ⟨_, isInfix.reverse⟩ := reverse_infix - -alias ⟨eq_nil_of_infix_nil, _⟩ := infix_nil - -alias ⟨eq_nil_of_prefix_nil, _⟩ := prefix_nil - -alias ⟨eq_nil_of_suffix_nil, _⟩ := suffix_nil +@[deprecated IsSuffix.reverse (since := "2024-08-12")] alias isSuffix.reverse := IsSuffix.reverse +@[deprecated IsPrefix.reverse (since := "2024-08-12")] alias isPrefix.reverse := IsPrefix.reverse +@[deprecated IsInfix.reverse (since := "2024-08-12")] alias isInfix.reverse := IsInfix.reverse +@[deprecated IsInfix.eq_of_length (since := "2024-08-12")] theorem eq_of_infix_of_length_eq (h : l₁ <:+: l₂) : l₁.length = l₂.length → l₁ = l₂ := - h.sublist.eq_of_length + h.eq_of_length +@[deprecated IsPrefix.eq_of_length (since := "2024-08-12")] theorem eq_of_prefix_of_length_eq (h : l₁ <+: l₂) : l₁.length = l₂.length → l₁ = l₂ := - h.sublist.eq_of_length + h.eq_of_length +@[deprecated IsSuffix.eq_of_length (since := "2024-08-12")] theorem eq_of_suffix_of_length_eq (h : l₁ <:+ l₂) : l₁.length = l₂.length → l₁ = l₂ := - h.sublist.eq_of_length + h.eq_of_length lemma dropSlice_sublist (n m : ℕ) (l : List α) : l.dropSlice n m <+ l := calc @@ -87,67 +63,13 @@ 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 -theorem takeWhile_prefix (p : α → Bool) : l.takeWhile p <+: l := - ⟨l.dropWhile p, takeWhile_append_dropWhile p l⟩ - -theorem dropWhile_suffix (p : α → Bool) : l.dropWhile p <:+ l := - ⟨l.takeWhile p, takeWhile_append_dropWhile p l⟩ - -theorem dropLast_prefix : ∀ l : List α, l.dropLast <+: l - | [] => ⟨nil, by rw [dropLast, List.append_nil]⟩ - | a :: l => ⟨_, dropLast_append_getLast (cons_ne_nil a l)⟩ - -theorem tail_suffix (l : List α) : tail l <:+ l := by rw [← drop_one]; apply drop_suffix - -theorem dropLast_sublist (l : List α) : l.dropLast <+ l := - (dropLast_prefix l).sublist - -@[gcongr] -theorem drop_sublist_drop_left (l : List α) {m n : ℕ} (h : m ≤ n) : drop n l <+ drop m l := by - rw [← Nat.sub_add_cancel h, ← drop_drop] - apply drop_sublist - -theorem dropLast_subset (l : List α) : l.dropLast ⊆ l := - (dropLast_sublist l).subset - 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 - -@[gcongr] -protected theorem Sublist.drop : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → ∀ n, l₁.drop n <+ l₂.drop n - | _, _, h, 0 => h - | _, _, h, n + 1 => by rw [← drop_tail, ← drop_tail]; exact h.tail.drop n - -theorem prefix_iff_eq_append : l₁ <+: l₂ ↔ l₁ ++ drop (length l₁) l₂ = l₂ := - ⟨by rintro ⟨r, rfl⟩; rw [drop_left], fun e => ⟨_, e⟩⟩ - -theorem suffix_iff_eq_append : l₁ <:+ l₂ ↔ take (length l₂ - length l₁) l₂ ++ l₁ = l₂ := - ⟨by rintro ⟨r, rfl⟩; simp only [length_append, Nat.add_sub_cancel_right, take_left], fun e => - ⟨_, e⟩⟩ - -theorem prefix_iff_eq_take : l₁ <+: l₂ ↔ l₁ = take (length l₁) l₂ := - ⟨fun h => append_cancel_right <| (prefix_iff_eq_append.1 h).trans (take_append_drop _ _).symm, - fun e => e.symm ▸ take_prefix _ _⟩ - -theorem prefix_take_iff {x y : List α} {n : ℕ} : x <+: y.take n ↔ x <+: y ∧ x.length ≤ n := by - constructor - · intro h - constructor - · exact List.IsPrefix.trans h <| List.take_prefix n y - · replace h := h.length_le - rw [length_take, Nat.le_min] at h - exact h.left - · intro ⟨hp, hl⟩ - have hl' := hp.length_le - rw [List.prefix_iff_eq_take] at * - rw [hp, List.take_take] - simp [min_eq_left, hl, hl'] +attribute [gcongr] Sublist.drop theorem concat_get_prefix {x y : List α} (h : x <+: y) (hl : x.length < y.length) : x ++ [y.get ⟨x.length, hl⟩] <+: y := by @@ -156,79 +78,17 @@ 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 -theorem suffix_iff_eq_drop : l₁ <:+ l₂ ↔ l₁ = drop (length l₂ - length l₁) l₂ := - ⟨fun h => append_cancel_left <| (suffix_iff_eq_append.1 h).trans (take_append_drop _ _).symm, - fun e => e.symm ▸ drop_suffix _ _⟩ - -instance decidablePrefix [DecidableEq α] : ∀ l₁ l₂ : List α, Decidable (l₁ <+: l₂) - | [], l₂ => isTrue ⟨l₂, rfl⟩ - | a :: l₁, [] => isFalse fun ⟨t, te⟩ => List.noConfusion te - | a :: l₁, b :: l₂ => - if h : a = b then - @decidable_of_decidable_of_iff _ _ (decidablePrefix l₁ l₂) (by rw [← h, prefix_cons_inj]) - else - isFalse fun ⟨t, te⟩ => h <| by injection te - --- Alternatively, use mem_tails -instance decidableSuffix [DecidableEq α] : ∀ l₁ l₂ : List α, Decidable (l₁ <:+ l₂) - | [], l₂ => isTrue ⟨l₂, append_nil _⟩ - | a :: l₁, [] => isFalse <| mt (Sublist.length_le ∘ IsSuffix.sublist) (by simp) - | l₁, b :: l₂ => - @decidable_of_decidable_of_iff _ _ - (@instDecidableOr _ _ _ (l₁.decidableSuffix l₂)) - suffix_cons_iff.symm - 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₂ => - @decidable_of_decidable_of_iff _ _ - (@instDecidableOr _ _ (l₁.decidablePrefix (b :: l₂)) (l₁.decidableInfix l₂)) + letI := l₁.decidableInfix l₂ + @decidable_of_decidable_of_iff (l₁ <+: b :: l₂ ∨ l₁ <:+: l₂) _ _ infix_cons_iff.symm -theorem prefix_take_le_iff {L : List (List (Option α))} (hm : m < L.length) : - L.take m <+: L.take n ↔ m ≤ n := by - simp only [prefix_iff_eq_take, length_take] - induction m generalizing L n with - | zero => simp [min_eq_left, eq_self_iff_true, Nat.zero_le, take] - | succ m IH => - cases L with - | nil => simp_all - | cons l ls => - cases n with - | zero => - simp - | succ n => - simp only [length_cons, succ_eq_add_one, Nat.add_lt_add_iff_right] at hm - simp [← @IH n ls hm, Nat.min_eq_left, Nat.le_of_lt hm] - +@[deprecated cons_prefix_cons (since := "2024-08-14")] theorem cons_prefix_iff : a :: l₁ <+: b :: l₂ ↔ a = b ∧ l₁ <+: l₂ := by - constructor - · rintro ⟨L, hL⟩ - simp only [cons_append] at hL - injection hL with hLLeft hLRight - exact ⟨hLLeft, ⟨L, hLRight⟩⟩ - · rintro ⟨rfl, h⟩ - rwa [prefix_cons_inj] - -protected theorem IsPrefix.map (h : l₁ <+: l₂) (f : α → β) : l₁.map f <+: l₂.map f := by - induction' l₁ with hd tl hl generalizing l₂ - · simp only [nil_prefix, map_nil] - · cases' l₂ with hd₂ tl₂ - · simpa only using eq_nil_of_prefix_nil h - · rw [cons_prefix_iff] at h - simp only [List.map_cons, h, prefix_cons_inj, hl, map] - -protected theorem IsPrefix.filterMap (h : l₁ <+: l₂) (f : α → Option β) : - l₁.filterMap f <+: l₂.filterMap f := by - induction' l₁ with hd₁ tl₁ hl generalizing l₂ - · simp only [nil_prefix, filterMap_nil] - · cases' l₂ with hd₂ tl₂ - · simpa only using eq_nil_of_prefix_nil h - · rw [cons_prefix_iff] at h - rw [← @singleton_append _ hd₁ _, ← @singleton_append _ hd₂ _, filterMap_append, - filterMap_append, h.left, prefix_append_right_inj] - exact hl h.right + simp @[deprecated (since := "2024-03-26")] alias IsPrefix.filter_map := IsPrefix.filterMap @@ -237,19 +97,19 @@ protected theorem IsPrefix.reduceOption {l₁ l₂ : List (Option α)} (h : l₁ h.filterMap id instance : IsPartialOrder (List α) (· <+: ·) where - refl := prefix_refl + refl _ := prefix_rfl trans _ _ _ := IsPrefix.trans - antisymm _ _ h₁ h₂ := eq_of_prefix_of_length_eq h₁ <| h₁.length_le.antisymm h₂.length_le + antisymm _ _ h₁ h₂ := h₁.eq_of_length <| h₁.length_le.antisymm h₂.length_le instance : IsPartialOrder (List α) (· <:+ ·) where - refl := suffix_refl + refl _ := suffix_rfl trans _ _ _ := IsSuffix.trans - antisymm _ _ h₁ h₂ := eq_of_suffix_of_length_eq h₁ <| h₁.length_le.antisymm h₂.length_le + antisymm _ _ h₁ h₂ := h₁.eq_of_length <| h₁.length_le.antisymm h₂.length_le instance : IsPartialOrder (List α) (· <:+: ·) where - refl := infix_refl + refl _ := infix_rfl trans _ _ _ := IsInfix.trans - antisymm _ _ h₁ h₂ := eq_of_infix_of_length_eq h₁ <| h₁.length_le.antisymm h₂.length_le + antisymm _ _ h₁ h₂ := h₁.eq_of_length <| h₁.length_le.antisymm h₂.length_le end Fix @@ -259,7 +119,7 @@ section InitsTails theorem mem_inits : ∀ s t : List α, s ∈ inits t ↔ s <+: t | s, [] => suffices s = nil ↔ s <+: nil by simpa only [inits, mem_singleton] - ⟨fun h => h.symm ▸ prefix_refl [], eq_nil_of_prefix_nil⟩ + ⟨fun h => h.symm ▸ prefix_rfl, eq_nil_of_prefix_nil⟩ | s, a :: t => suffices (s = nil ∨ ∃ l ∈ inits t, a :: l = s) ↔ s <+: a :: t by simpa ⟨fun o => @@ -297,11 +157,21 @@ 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 [· ∘ ·] - | a :: s, t => by simp [inits_append s t, · ∘ ·] + | [], a :: t => by simp + | a :: s, t => by simp [inits_append s t, Function.comp_def] @[simp] theorem tails_append : @@ -370,20 +240,6 @@ theorem getElem_inits (l : List α) (n : Nat) (h : n < length (inits l)) : theorem get_inits (l : List α) (n : Fin (length (inits l))) : (inits l).get n = l.take n := by simp -section deprecated -set_option linter.deprecated false - -@[simp, deprecated get_tails (since := "2024-04-16")] -theorem nth_le_tails (l : List α) (n : ℕ) (hn : n < length (tails l)) : - nthLe (tails l) n hn = l.drop n := - get_tails l _ - -@[simp, deprecated get_inits (since := "2024-04-16")] -theorem nth_le_inits (l : List α) (n : ℕ) (hn : n < length (inits l)) : - nthLe (inits l) n hn = l.take n := - get_inits l _ -end deprecated - end InitsTails /-! ### insert -/ @@ -414,24 +270,13 @@ theorem subset_insert (a : α) (l : List α) : l ⊆ l.insert a := end Insert -theorem mem_of_mem_suffix (hx : a ∈ l₁) (hl : l₁ <:+ l₂) : a ∈ l₂ := - hl.subset hx - -theorem IsPrefix.ne_nil {x y : List α} (h : x <+: y) (hx : x ≠ []) : y ≠ [] := by - rintro rfl; exact hx <| List.prefix_nil.mp h - -theorem IsPrefix.getElem {x y : List α} (h : x <+: y) {n} (hn : n < x.length) : - x[n] = y[n]'(hn.trans_le h.length_le) := by - obtain ⟨_, rfl⟩ := h - exact (List.getElem_append n hn).symm +@[deprecated (since := "2024-08-15")] alias mem_of_mem_suffix := IsSuffix.mem +@[deprecated IsPrefix.getElem (since := "2024-08-15")] theorem IsPrefix.get_eq {x y : List α} (h : x <+: y) {n} (hn : n < x.length) : x.get ⟨n, hn⟩ = y.get ⟨n, hn.trans_le h.length_le⟩ := by simp only [get_eq_getElem, IsPrefix.getElem h hn] -theorem IsPrefix.head_eq {x y : List α} (h : x <+: y) (hx : x ≠ []) : - x.head hx = y.head (h.ne_nil hx) := by - cases x <;> cases y <;> simp only [head_cons, ne_eq, not_true_eq_false] at hx ⊢ - all_goals (obtain ⟨_, h⟩ := h; injection h) +@[deprecated (since := "2024-08-15")] alias IsPrefix.head_eq := IsPrefix.head end List diff --git a/Mathlib/Data/List/InsertNth.lean b/Mathlib/Data/List/InsertNth.lean index 33044a0a6908c..00cef198f31e7 100644 --- a/Mathlib/Data/List/InsertNth.lean +++ b/Mathlib/Data/List/InsertNth.lean @@ -19,9 +19,9 @@ open Nat hiding one_pos namespace List -universe u v w +universe u -variable {ι : Type*} {α : Type u} {β : Type v} {γ : Type w} {l₁ l₂ : List α} +variable {α : Type u} section InsertNth @@ -83,13 +83,17 @@ theorem insertNth_comm (a b : α) : simp only [insertNth_succ_cons, cons.injEq, true_and] exact insertNth_comm a b i j l (Nat.le_of_succ_le_succ h₀) (Nat.le_of_succ_le_succ h₁) +#adaptation_note +/-- +After nightly-2024-09-06 we can remove the `_root_` prefixes below. +-/ theorem mem_insertNth {a b : α} : ∀ {n : ℕ} {l : List α} (_ : n ≤ l.length), a ∈ l.insertNth n b ↔ a = b ∨ a ∈ l | 0, as, _ => by simp | n + 1, [], h => (Nat.not_succ_le_zero _ h).elim | n + 1, a' :: as, h => by rw [List.insertNth_succ_cons, mem_cons, mem_insertNth (Nat.le_of_succ_le_succ h), - ← or_assoc, @or_comm (a = a'), or_assoc, mem_cons] + ← _root_.or_assoc, @or_comm (a = a'), _root_.or_assoc, mem_cons] theorem insertNth_of_length_lt (l : List α) (x : α) (n : ℕ) (h : l.length < n) : insertNth n x l = l := by @@ -139,12 +143,6 @@ theorem get_insertNth_of_lt (l : List α) (x : α) (n k : ℕ) (hn : k < n) (hk (insertNth n x l).get ⟨k, hk'⟩ = l.get ⟨k, hk⟩ := by simp_all [getElem_insertNth_of_lt] -set_option linter.deprecated false in -@[deprecated get_insertNth_of_lt (since := "2023-01-05")] -theorem nthLe_insertNth_of_lt : ∀ (l : List α) (x : α) (n k : ℕ), k < n → ∀ (hk : k < l.length) - (hk' : k < (insertNth n x l).length := hk.trans_le (length_le_length_insertNth _ _ _)), - (insertNth n x l).nthLe k hk' = l.nthLe k hk := @get_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])) : @@ -163,12 +161,6 @@ theorem get_insertNth_self (l : List α) (x : α) (n : ℕ) (hn : n ≤ l.length (insertNth n x l).get ⟨n, hn'⟩ = x := by simp [hn, hn'] -set_option linter.deprecated false in -@[simp, deprecated get_insertNth_self (since := "2023-01-05")] -theorem nthLe_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).nthLe n hn' = x := get_insertNth_self _ _ _ 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])) : @@ -185,14 +177,6 @@ theorem get_insertNth_add_succ (l : List α) (x : α) (n k : ℕ) (hk' : n + k < (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.deprecated false in -@[deprecated get_insertNth_add_succ (since := "2023-01-05")] -theorem nthLe_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).nthLe (n + k + 1) hk = nthLe l (n + k) hk' := - @get_insertNth_add_succ _ - set_option linter.unnecessarySimpa false in theorem insertNth_injective (n : ℕ) (x : α) : Function.Injective (insertNth n x) := by induction' n with n IH diff --git a/Mathlib/Data/List/Intervals.lean b/Mathlib/Data/List/Intervals.lean index cefbcfd118662..870f434107df2 100644 --- a/Mathlib/Data/List/Intervals.lean +++ b/Mathlib/Data/List/Intervals.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.Data.List.Lattice import Mathlib.Data.Bool.Basic -import Mathlib.Init.Data.Nat.Lemmas import Mathlib.Order.Lattice + /-! # Intervals in ℕ @@ -42,15 +42,15 @@ theorem zero_bot (n : ℕ) : Ico 0 n = range n := by rw [Ico, Nat.sub_zero, rang @[simp] theorem length (n m : ℕ) : length (Ico n m) = m - n := by dsimp [Ico] - simp [length_range', autoParam] + simp [length_range'] theorem pairwise_lt (n m : ℕ) : Pairwise (· < ·) (Ico n m) := by dsimp [Ico] - simp [pairwise_lt_range', autoParam] + simp [pairwise_lt_range'] theorem nodup (n m : ℕ) : Nodup (Ico n m) := by dsimp [Ico] - simp [nodup_range', autoParam] + simp [nodup_range'] @[simp] theorem mem {n m l : ℕ} : l ∈ Ico n m ↔ n ≤ l ∧ l < m := by @@ -116,9 +116,7 @@ theorem eq_cons {n m : ℕ} (h : n < m) : Ico n m = n :: Ico (n + 1) m := by @[simp] theorem pred_singleton {m : ℕ} (h : 0 < m) : Ico (m - 1) m = [m - 1] := by - dsimp [Ico] - rw [Nat.sub_sub_self (succ_le_of_lt h)] - simp [← Nat.one_eq_succ_zero] + simp [Ico, Nat.sub_sub_self (succ_le_of_lt h)] theorem chain'_succ (n m : ℕ) : Chain' (fun a b => b = succ a) (Ico n m) := by by_cases h : n < m @@ -137,7 +135,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 @@ -163,7 +161,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/Iterate.lean b/Mathlib/Data/List/Iterate.lean index dc981a78f8e38..5fe809d67beed 100644 --- a/Mathlib/Data/List/Iterate.lean +++ b/Mathlib/Data/List/Iterate.lean @@ -31,15 +31,17 @@ theorem getElem?_iterate (f : α → α) (a : α) : | n + 1, 0 , _ => by simp | n + 1, i + 1, h => by simp [getElem?_iterate f (f a) n i (by simpa using h)] +@[deprecated getElem?_iterate (since := "2024-08-23")] theorem get?_iterate (f : α → α) (a : α) (n i : ℕ) (h : i < n) : get? (iterate f a n) i = f^[i] a := by - simp only [get?_eq_getElem?, length_iterate, h, Option.some.injEq, getElem?_iterate] + simp only [get?_eq_getElem?, getElem?_iterate, h] @[simp] theorem getElem_iterate (f : α → α) (a : α) (n : ℕ) (i : Nat) (h : i < (iterate f a n).length) : - (iterate f a n)[i] = f^[↑i] a := - (get?_eq_some.1 <| get?_iterate f a n i (by simpa using h)).2 + (iterate f a n)[i] = f^[i] a := + getElem_eq_iff.2 <| getElem?_iterate _ _ _ _ <| by rwa [length_iterate] at h +@[deprecated getElem_iterate (since := "2024-08-23")] theorem get_iterate (f : α → α) (a : α) (n : ℕ) (i : Fin (iterate f a n).length) : get (iterate f a n) i = f^[↑i] a := by simp @@ -52,7 +54,7 @@ theorem mem_iterate {f : α → α} {a : α} {n : ℕ} {b : α} : @[simp] theorem range_map_iterate (n : ℕ) (f : α → α) (a : α) : (List.range n).map (f^[·] a) = List.iterate f a n := by - apply List.ext_get <;> simp + apply List.ext_getElem <;> simp theorem iterate_add (f : α → α) (a : α) (m n : ℕ) : iterate f a (m + n) = iterate f a m ++ iterate f (f^[m] a) n := by diff --git a/Mathlib/Data/List/Join.lean b/Mathlib/Data/List/Join.lean index c8ecd55aad8c5..69f2b6f90ab34 100644 --- a/Mathlib/Data/List/Join.lean +++ b/Mathlib/Data/List/Join.lean @@ -19,31 +19,8 @@ variable {α β : Type*} namespace List --- Porting note (#10618): simp can prove this --- @[simp] -theorem join_singleton (l : List α) : [l].join = l := by rw [join, join, append_nil] - -@[deprecated join_eq_nil_iff (since := "2024-07-10")] -theorem join_eq_nil : ∀ {L : List (List α)}, join L = [] ↔ ∀ l ∈ L, l = [] := join_eq_nil_iff - - -@[simp] -theorem join_filter_not_isEmpty : - ∀ {L : List (List α)}, join (L.filter fun l => !l.isEmpty) = L.join - | [] => rfl - | [] :: L => by - simp [join_filter_not_isEmpty (L := L), isEmpty_iff_eq_nil] - | (a :: l) :: L => by - simp [join_filter_not_isEmpty (L := L)] - @[deprecated (since := "2024-02-25")] alias join_filter_isEmpty_eq_false := join_filter_not_isEmpty -@[simp] -theorem join_filter_ne_nil [DecidablePred fun l : List α => l ≠ []] {L : List (List α)} : - join (L.filter fun l => l ≠ []) = L.join := by - simp only [ne_eq, ← isEmpty_iff_eq_nil, Bool.not_eq_true, Bool.decide_eq_false, - join_filter_not_isEmpty] - /-- See `List.length_join` for the corresponding statement using `List.sum`. -/ lemma length_join' (L : List (List α)) : length (join L) = Nat.sum (map length L) := by induction L <;> [rfl; simp only [*, join, map, Nat.sum_cons, length_append]] @@ -70,11 +47,6 @@ lemma countP_bind' (p : β → Bool) (l : List α) (f : α → List β) : lemma count_bind' [BEq β] (l : List α) (f : α → List β) (x : β) : count x (l.bind f) = Nat.sum (map (count x ∘ f) l) := countP_bind' _ _ _ -@[simp] -theorem bind_eq_nil {l : List α} {f : α → List β} : List.bind l f = [] ↔ ∀ x ∈ l, f x = [] := - join_eq_nil_iff.trans <| by - simp only [mem_map, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂] - /-- In a join, taking the first elements up to an index which is the sum of the lengths of the first `i` sublists, is the same as taking the join of the first `i` sublists. @@ -110,22 +82,6 @@ theorem drop_take_succ_eq_cons_get (L : List α) (i : Fin L.length) : (L.take (i + 1)).drop i = [get L i] := by simp [drop_take_succ_eq_cons_getElem] -set_option linter.deprecated false in -/-- Taking only the first `i+1` elements in a list, and then dropping the first `i` ones, one is -left with a list of length `1` made of the `i`-th element of the original list. -/ -@[deprecated drop_take_succ_eq_cons_get (since := "2023-01-10")] -theorem drop_take_succ_eq_cons_nthLe (L : List α) {i : ℕ} (hi : i < L.length) : - (L.take (i + 1)).drop i = [nthLe L i hi] := by - induction' L with head tail generalizing i - · simp only [length] at hi - exact (Nat.not_succ_le_zero i hi).elim - cases' i with i hi - · simp - rfl - have : i < tail.length := by simpa using hi - simp [*] - rfl - /-- In a join of sublists, taking the slice between the indices `A` and `B - 1` gives back the original sublist of index `i` if `A` is the sum of the lengths of sublists of index `< i`, and `B` is the sum of the lengths of sublists of index `≤ i`. @@ -145,18 +101,6 @@ theorem drop_take_succ_join_eq_get' (L : List (List α)) (i : Fin L.length) : get L i := by simp [drop_take_succ_join_eq_getElem'] -/-- Two lists of sublists are equal iff their joins coincide, as well as the lengths of the -sublists. -/ -theorem eq_iff_join_eq (L L' : List (List α)) : - L = L' ↔ L.join = L'.join ∧ map length L = map length L' := by - refine ⟨fun H => by simp [H], ?_⟩ - rintro ⟨join_eq, length_eq⟩ - apply ext_getElem - · have : length (map length L) = length (map length L') := by rw [length_eq] - simpa using this - · intro n h₁ h₂ - rw [← drop_take_succ_join_eq_getElem', ← drop_take_succ_join_eq_getElem', join_eq, length_eq] - theorem join_drop_length_sub_one {L : List (List α)} (h : L ≠ []) : (L.drop (L.length - 1)).join = L.getLast h := by induction L using List.reverseRecOn @@ -167,25 +111,10 @@ theorem join_drop_length_sub_one {L : List (List α)} (h : L ≠ []) : `(x ++ l₁) ++ (x ++ l₂) ++ ... ++ (x ++ lₙ) ++ x` where `L = [l₁, l₂, ..., lₙ]`. -/ theorem append_join_map_append (L : List (List α)) (x : List α) : x ++ (L.map (· ++ x)).join = (L.map (x ++ ·)).join ++ x := by - induction' L with _ _ ih - · rw [map_nil, join, append_nil, map_nil, join, nil_append] - · rw [map_cons, join, map_cons, join, append_assoc, ih, append_assoc, append_assoc] - - -/-- Any member of `L : List (List α))` is a sublist of `L.join` -/ -lemma sublist_join (L : List (List α)) {s : List α} (hs : s ∈ L) : - s.Sublist L.join := by induction L with - | nil => - exfalso - exact not_mem_nil s hs - | cons t m ht => - cases mem_cons.mp hs with - | inl h => - rw [h] - simp only [join_cons, sublist_append_left] - | inr h => - simp only [join_cons] - exact sublist_append_of_sublist_right (ht h) + | nil => rw [map_nil, join, append_nil, map_nil, join, nil_append] + | cons _ _ ih => rw [map_cons, join, map_cons, join, append_assoc, ih, append_assoc, append_assoc] + +@[deprecated (since := "2024-08-15")] alias sublist_join := sublist_join_of_mem end List diff --git a/Mathlib/Data/List/Lattice.lean b/Mathlib/Data/List/Lattice.lean index 181f14ce99536..5a0ae92ccc6c0 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` -/ @@ -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 d01b10c18df2b..b055f1b187222 100644 --- a/Mathlib/Data/List/Lemmas.lean +++ b/Mathlib/Data/List/Lemmas.lean @@ -5,7 +5,6 @@ Authors: Yakov Pechersky, Yury Kudryashov -/ import Mathlib.Data.Set.Image import Mathlib.Data.List.InsertNth -import Mathlib.Init.Data.List.Lemmas /-! # Some lemmas about lists involving sets @@ -18,13 +17,26 @@ variable {α β γ : Type*} namespace List +@[deprecated (since := "2024-08-20")] alias getElem_reverse' := getElem_reverse + +theorem tail_reverse_eq_reverse_dropLast (l : List α) : + l.reverse.tail = l.dropLast.reverse := by + ext i v; by_cases hi : i < l.length - 1 + · simp only [← drop_one] + rw [getElem?_eq_getElem (by simpa), getElem?_eq_getElem (by simpa), + ← getElem_drop' _, getElem_reverse, getElem_reverse, getElem_dropLast] + · simp [show l.length - 1 - (1 + i) = l.length - 1 - 1 - i by omega] + all_goals ((try simp); omega) + · rw [getElem?_eq_none, getElem?_eq_none] + all_goals (simp; omega) + +@[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 induction' l with hd tl IH · intro n hn m hm _ - simp only [Set.mem_singleton_iff, Set.setOf_eq_eq_singleton, - length] at hn hm - simp_all [hn, hm] + simp_all [Set.mem_singleton_iff, Set.setOf_eq_eq_singleton, length] · intro n hn m hm h simp only [length, Set.mem_setOf_eq] at hn hm simp only [mem_cons, not_or] at hx @@ -32,7 +44,7 @@ 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, insertNth_succ_cons] at h rw [Nat.succ_inj'] refine IH hx.right ?_ ?_ (by injection h) · simpa [Nat.succ_le_succ_iff] using hn diff --git a/Mathlib/Data/List/Lex.lean b/Mathlib/Data/List/Lex.lean index fad422e7a7b85..9431966564a45 100644 --- a/Mathlib/Data/List/Lex.lean +++ b/Mathlib/Data/List/Lex.lean @@ -99,6 +99,7 @@ instance isAsymm (r : α → α → Prop) [IsAsymm α r] : IsAsymm (List α) (Le | _, _, Lex.cons _, Lex.rel h₂ => asymm h₂ h₂ | _, _, Lex.cons h₁, Lex.cons h₂ => aux _ _ h₁ h₂ +@[deprecated (since := "2024-07-30")] instance isStrictTotalOrder (r : α → α → Prop) [IsStrictTotalOrder α r] : IsStrictTotalOrder (List α) (Lex r) := { isStrictWeakOrder_of_isOrderConnected with } diff --git a/Mathlib/Data/List/MinMax.lean b/Mathlib/Data/List/MinMax.lean index c20935506c371..52a8f59fb7167 100644 --- a/Mathlib/Data/List/MinMax.lean +++ b/Mathlib/Data/List/MinMax.lean @@ -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/Init/Data/List/Instances.lean b/Mathlib/Data/List/Monad.lean similarity index 59% rename from Mathlib/Init/Data/List/Instances.lean rename to Mathlib/Data/List/Monad.lean index f4ae241d5a94a..04d1477cbd14d 100644 --- a/Mathlib/Init/Data/List/Instances.lean +++ b/Mathlib/Data/List/Monad.lean @@ -4,22 +4,16 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura -/ +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.) - -We intend to move all the content of these files out into the main `Mathlib` directory structure. -Contributions assisting with this are appreciated. - -# Decidable and Monad instances for `List` not (yet) in `Batteries` +# 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..3d11150f01d9e 100644 --- a/Mathlib/Data/List/NatAntidiagonal.lean +++ b/Mathlib/Data/List/NatAntidiagonal.lean @@ -59,7 +59,7 @@ 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, + simp only [antidiagonal, range_succ_eq_map, map_cons, Nat.add_succ_sub_one, Nat.add_zero, id, eq_self_iff_true, Nat.sub_zero, map_map, Prod.map_mk] apply congr rfl (congr rfl _) ext; simp diff --git a/Mathlib/Data/List/Nodup.lean b/Mathlib/Data/List/Nodup.lean index 5bfb47206bb95..f04247b8a0193 100644 --- a/Mathlib/Data/List/Nodup.lean +++ b/Mathlib/Data/List/Nodup.lean @@ -5,7 +5,6 @@ Authors: Mario Carneiro, Kenny Lau -/ import Mathlib.Data.List.Forall2 import Mathlib.Data.Set.Pairwise.Basic -import Mathlib.Init.Data.Fin.Basic /-! # Lists with no duplicates @@ -17,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 @@ -78,14 +77,6 @@ theorem nodup_iff_injective_get {l : List α} : change _ ↔ Injective (fun i => l.get i) simp -set_option linter.deprecated false in -@[deprecated nodup_iff_injective_get (since := "2023-01-10")] -theorem nodup_iff_nthLe_inj {l : List α} : - Nodup l ↔ ∀ i j h₁ h₂, nthLe l i h₁ = nthLe l j h₂ → i = j := - nodup_iff_injective_get.trans - ⟨fun hinj _ _ _ _ h => congr_arg Fin.val (hinj h), - fun hinj i j h => Fin.eq_of_veq (hinj i j i.2 j.2 h)⟩ - theorem Nodup.get_inj_iff {l : List α} (h : Nodup l) {i j : Fin l.length} : l.get i = l.get j ↔ i = j := (nodup_iff_injective_get.1 h).eq_iff @@ -96,19 +87,13 @@ theorem Nodup.getElem_inj_iff {l : List α} (h : Nodup l) have := @Nodup.get_inj_iff _ _ h ⟨i, hi⟩ ⟨j, hj⟩ simpa -set_option linter.deprecated false in -@[deprecated Nodup.get_inj_iff (since := "2023-01-10")] -theorem Nodup.nthLe_inj_iff {l : List α} (h : Nodup l) {i j : ℕ} (hi : i < l.length) - (hj : j < l.length) : l.nthLe i hi = l.nthLe j hj ↔ i = j := - ⟨nodup_iff_nthLe_inj.mp h _ _ _ _, by simp (config := { contextual := true })⟩ - theorem nodup_iff_getElem?_ne_getElem? {l : List α} : l.Nodup ↔ ∀ i j : ℕ, i < j → j < l.length → l[i]? ≠ l[j]? := by rw [Nodup, pairwise_iff_getElem] constructor · intro h i j hij hj rw [getElem?_eq_getElem (lt_trans hij hj), getElem?_eq_getElem hj, Ne, Option.some_inj] - exact h _ _ _ _ hij + exact h _ _ (by omega) hj hij · intro h i j hi hj hij rw [Ne, ← Option.some_inj, ← getElem?_eq_getElem, ← getElem?_eq_getElem] exact h i j hij hj @@ -155,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 @@ -239,7 +224,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 := @@ -259,8 +244,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 @@ -277,8 +262,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'] @@ -319,13 +304,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] @@ -373,7 +357,7 @@ theorem Nodup.pairwise_coe [IsSymm α r] (hl : l.Nodup) : rw [List.nodup_cons] at hl have : ∀ b ∈ l, ¬a = b → r a b ↔ r a b := fun b hb => imp_iff_right (ne_of_mem_of_not_mem hb hl.1).symm - simp [Set.setOf_or, Set.pairwise_insert_of_symmetric (@symm_of _ r _), ih hl.2, and_comm, + simp [Set.setOf_or, Set.pairwise_insert_of_symmetric fun _ _ ↦ symm_of r, ih hl.2, and_comm, forall₂_congr this] theorem Nodup.take_eq_filter_mem [DecidableEq α] : @@ -381,7 +365,7 @@ theorem Nodup.take_eq_filter_mem [DecidableEq α] : | [], n, _ => by simp | b::l, 0, _ => by simp | b::l, n+1, hl => by - rw [take_cons, Nodup.take_eq_filter_mem (Nodup.of_cons hl), List.filter_cons_of_pos (by simp)] + rw [take_succ_cons, Nodup.take_eq_filter_mem (Nodup.of_cons hl), filter_cons_of_pos (by simp)] congr 1 refine List.filter_congr ?_ intro x hx diff --git a/Mathlib/Data/List/NodupEquivFin.lean b/Mathlib/Data/List/NodupEquivFin.lean index 36b450b8c49a8..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 @@ -137,12 +137,14 @@ theorem sublist_iff_exists_orderEmbedding_get?_eq {l l' : List α} : l <+ l' ↔ ∃ f : ℕ ↪o ℕ, ∀ ix : ℕ, l.get? ix = l'.get? (f ix) := by constructor · intro H - induction' H with xs ys y _H IH xs ys x _H IH - · simp - · obtain ⟨f, hf⟩ := IH + induction H with + | slnil => simp + | cons _ _ IH => + obtain ⟨f, hf⟩ := IH refine ⟨f.trans (OrderEmbedding.ofStrictMono (· + 1) fun _ => by simp), ?_⟩ simpa using hf - · obtain ⟨f, hf⟩ := IH + | cons₂ _ _ IH => + obtain ⟨f, hf⟩ := IH refine ⟨OrderEmbedding.ofMapLEIff (fun ix : ℕ => if ix = 0 then 0 else (f ix.pred).succ) ?_, ?_⟩ · rintro ⟨_ | a⟩ ⟨_ | b⟩ <;> simp [Nat.succ_le_succ_iff] @@ -221,19 +223,6 @@ theorem duplicate_iff_exists_distinct_get {l : List α} {x : α} : · simpa using h · simpa using h' -set_option linter.deprecated false in -/-- An element `x : α` of `l : List α` is a duplicate iff it can be found -at two distinct indices `n m : ℕ` inside the list `l`. --/ -@[deprecated duplicate_iff_exists_distinct_get (since := "2023-01-19")] -theorem duplicate_iff_exists_distinct_nthLe {l : List α} {x : α} : - l.Duplicate x ↔ - ∃ (n : ℕ) (hn : n < l.length) (m : ℕ) (hm : m < l.length) (_ : n < m), - x = l.nthLe n hn ∧ x = l.nthLe m hm := - duplicate_iff_exists_distinct_get.trans - ⟨fun ⟨n, m, h⟩ => ⟨n.1, n.2, m.1, m.2, h⟩, - fun ⟨n, hn, m, hm, h⟩ => ⟨⟨n, hn⟩, ⟨m, hm⟩, h⟩⟩ - end Sublist end List diff --git a/Mathlib/Data/List/OfFn.lean b/Mathlib/Data/List/OfFn.lean index 99f86c4e1dc1c..9aa74790b948b 100644 --- a/Mathlib/Data/List/OfFn.lean +++ b/Mathlib/Data/List/OfFn.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 -/ +import Batteries.Data.List.OfFn +import Batteries.Data.List.Pairwise import Mathlib.Data.Fin.Tuple.Basic -import Mathlib.Data.List.Basic /-! # Lists from functions @@ -16,7 +17,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,60 +32,13 @@ 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 -set_option linter.deprecated false in -@[deprecated get_ofFn (since := "2023-01-17")] -theorem nthLe_ofFn {n} (f : Fin n → α) (i : Fin n) : - nthLe (ofFn f) i ((length_ofFn f).symm ▸ i.2) = f i := by - simp [nthLe] - -set_option linter.deprecated false in -@[simp, deprecated get_ofFn (since := "2023-01-17")] -theorem nthLe_ofFn' {n} (f : Fin n → α) {i : ℕ} (h : i < (ofFn f).length) : - nthLe (ofFn f) i h = f ⟨i, length_ofFn f ▸ h⟩ := - nthLe_ofFn f ⟨i, length_ofFn f ▸ h⟩ - @[simp] theorem map_ofFn {β : Type*} {n : ℕ} (f : Fin n → α) (g : α → β) : map g (ofFn f) = ofFn (g ∘ f) := @@ -129,7 +82,7 @@ theorem ofFn_succ' {n} (f : Fin (succ n) → α) : @[simp] theorem ofFn_eq_nil_iff {n : ℕ} {f : Fin n → α} : ofFn f = [] ↔ n = 0 := by - cases n <;> simp only [ofFn_zero, ofFn_succ, eq_self_iff_true, Nat.succ_ne_zero] + cases n <;> simp only [ofFn_zero, ofFn_succ, eq_self_iff_true, Nat.succ_ne_zero, reduceCtorEq] theorem last_ofFn {n : ℕ} (f : Fin n → α) (h : ofFn f ≠ []) (hn : n - 1 < n := Nat.pred_lt <| ofFn_eq_nil_iff.not.mp h) : @@ -201,11 +154,6 @@ theorem ofFn_getElem_eq_map {β : Type*} (l : List α) (f : α → β) : theorem ofFn_get_eq_map {β : Type*} (l : List α) (f : α → β) : ofFn (f <| l.get ·) = l.map f := by simp -set_option linter.deprecated false in -@[deprecated ofFn_get (since := "2023-01-17")] -theorem ofFn_nthLe : ∀ l : List α, (ofFn fun i => nthLe l i i.2) = l := - ofFn_get - -- not registered as a simp lemma, as otherwise it fires before `forall_mem_ofFn_iff` which -- is much more useful theorem mem_ofFn {n} (f : Fin n → α) (a : α) : a ∈ ofFn f ↔ a ∈ Set.range f := by diff --git a/Mathlib/Data/List/Pairwise.lean b/Mathlib/Data/List/Pairwise.lean index 9f117438fd350..507a0a3195b58 100644 --- a/Mathlib/Data/List/Pairwise.lean +++ b/Mathlib/Data/List/Pairwise.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.List.Pairwise import Mathlib.Logic.Pairwise import Mathlib.Logic.Relation -import Mathlib.Data.List.Basic /-! # Pairwise relations on a list @@ -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 @@ -57,30 +57,6 @@ theorem Pairwise.set_pairwise (hl : Pairwise R l) (hr : Symmetric R) : { x | x simp only [map, pairwise_cons, mem_map, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂, pairwise_map] -theorem pairwise_pmap {p : β → Prop} {f : ∀ b, p b → α} {l : List β} (h : ∀ x ∈ l, p x) : - Pairwise R (l.pmap f h) ↔ - Pairwise (fun b₁ b₂ => ∀ (h₁ : p b₁) (h₂ : p b₂), R (f b₁ h₁) (f b₂ h₂)) l := by - induction' l with a l ihl - · simp - obtain ⟨_, hl⟩ : p a ∧ ∀ b, b ∈ l → p b := by simpa using h - simp only [ihl hl, pairwise_cons, exists₂_imp, pmap, and_congr_left_iff, mem_pmap] - refine fun _ => ⟨fun H b hb _ hpb => H _ _ hb rfl, ?_⟩ - rintro H _ b hb rfl - exact H b hb _ _ - -theorem Pairwise.pmap {l : List α} (hl : Pairwise R l) {p : α → Prop} {f : ∀ a, p a → β} - (h : ∀ x ∈ l, p x) {S : β → β → Prop} - (hS : ∀ ⦃x⦄ (hx : p x) ⦃y⦄ (hy : p y), R x y → S (f x hx) (f y hy)) : - Pairwise S (l.pmap f h) := by - refine (pairwise_pmap h).2 (Pairwise.imp_of_mem ?_ hl) - intros; apply hS; assumption - -theorem pairwise_of_forall_mem_list {l : List α} {r : α → α → Prop} (h : ∀ a ∈ l, ∀ b ∈ l, r a b) : - l.Pairwise r := by - rw [pairwise_iff_forall_sublist] - intro a b hab - apply h <;> (apply hab.subset; simp) - theorem pairwise_of_reflexive_of_forall_ne {l : List α} {r : α → α → Prop} (hr : Reflexive r) (h : ∀ a ∈ l, ∀ b ∈ l, a ≠ b → r a b) : l.Pairwise r := by rw [pairwise_iff_forall_sublist] @@ -91,19 +67,8 @@ theorem pairwise_of_reflexive_of_forall_ne {l : List α} {r : α → α → Prop apply h <;> try (apply hab.subset; simp) exact heq -set_option linter.deprecated false in -@[deprecated pairwise_iff_get (since := "2023-01-10")] -theorem pairwise_iff_nthLe {R} {l : List α} : Pairwise R l ↔ - ∀ (i j) (h₁ : j < length l) (h₂ : i < j), R (nthLe l i (lt_trans h₂ h₁)) (nthLe l j h₁) := - pairwise_iff_get.trans - ⟨fun h i j _ h₂ => h ⟨i, _⟩ ⟨j, _⟩ h₂, - fun h i j hij => h i j _ hij⟩ - /-! ### Pairwise filtering -/ - -variable [DecidableRel R] - alias ⟨_, Pairwise.pwFilter⟩ := pwFilter_eq_self -- Porting note: commented out diff --git a/Mathlib/Data/List/Perm.lean b/Mathlib/Data/List/Perm.lean index f804a9590f642..52ea464bb6804 100644 --- a/Mathlib/Data/List/Perm.lean +++ b/Mathlib/Data/List/Perm.lean @@ -10,6 +10,7 @@ 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 @@ -144,17 +145,17 @@ lemma count_eq_count_filter_add [DecidableEq α] (P : α → Prop) [DecidablePre 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₂) : +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 + 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₂) : +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] + | swap' _ _ _ r => simp only [foldr_cons]; rw [lcomm.left_comm, r b] | trans _ _ r₁ r₂ => exact Eq.trans (r₁ b) (r₂ b) section @@ -165,8 +166,13 @@ 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) _ +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 @@ -216,16 +222,18 @@ variable [DecidableEq α] theorem Perm.bagInter_right {l₁ l₂ : List α} (t : List α) (h : l₁ ~ l₂) : l₁.bagInter t ~ l₂.bagInter t := by - induction' h with x _ _ _ _ x y _ _ _ _ _ _ ih_1 ih_2 generalizing t; · simp - · by_cases x ∈ t <;> simp [*, Perm.cons] - · by_cases h : x = y + 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] - · exact (ih_1 _).trans (ih_2 _) + | 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 @@ -263,7 +271,7 @@ theorem Perm.inter_append {l t₁ t₂ : List α} (h : Disjoint t₁ 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, + · 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₂) @@ -335,10 +343,9 @@ theorem Perm.drop_inter [DecidableEq α] {xs ys : List α} (n : ℕ) (h : xs ~ y 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₁ : n' ≤ xs.length := Nat.sub_le .. - have h₂ : xs.drop n = (xs.reverse.take n').reverse := by - rw [take_reverse h₁, h₀, reverse_reverse] - rw [h₂] + 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' @@ -453,14 +460,16 @@ theorem perm_permutations'Aux_comm (a b : α) (l : List α) : exact perm_append_comm.append (ih.map _) theorem Perm.permutations' {s t : List α} (p : s ~ t) : permutations' s ~ permutations' t := by - induction' p with a s t _ IH a b l s t u _ _ IH₁ IH₂; · simp - · exact IH.bind_right _ - · dsimp + 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 - · exact IH₁.trans IH₂ + | 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 _⟩ @@ -513,13 +522,6 @@ theorem get_permutations'Aux (s : List α) (x : α) (n : ℕ) (permutations'Aux x s).get ⟨n, hn⟩ = s.insertNth n x := by simp [getElem_permutations'Aux] -set_option linter.deprecated false in -@[deprecated get_permutations'Aux (since := "2024-04-23")] -theorem nthLe_permutations'Aux (s : List α) (x : α) (n : ℕ) - (hn : n < length (permutations'Aux x s)) : - (permutations'Aux x s).nthLe n hn = s.insertNth n x := - get_permutations'Aux s x n hn - 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 @@ -564,37 +566,34 @@ theorem nodup_permutations'Aux_of_not_mem (s : List α) (x : α) (hx : x ∉ s) · exact IH hx.right · simp -set_option linter.deprecated false in theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations'Aux x s) ↔ x ∉ s := by - refine ⟨fun h => ?_, nodup_permutations'Aux_of_not_mem _ _⟩ - intro H - obtain ⟨k, hk, hk'⟩ := nthLe_of_mem H - rw [nodup_iff_nthLe_inj] at h - refine k.succ_ne_self.symm $ h k (k + 1) ?_ ?_ ?_ - · simpa [Nat.lt_succ_iff] using hk.le - · simpa using hk - rw [nthLe_permutations'Aux, nthLe_permutations'Aux] + 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_nthLe hl fun n hn hn' => ?_ + refine ext_get hl fun n hn hn' => ?_ rcases lt_trichotomy n k with (H | rfl | H) - · rw [nthLe_insertNth_of_lt _ _ _ _ H (H.trans hk), - nthLe_insertNth_of_lt _ _ _ _ (H.trans (Nat.lt_succ_self _))] - · rw [nthLe_insertNth_self _ _ _ hk.le, nthLe_insertNth_of_lt _ _ _ _ (Nat.lt_succ_self _) hk, - hk'] + · 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 [nthLe_insertNth_self _ _ _ (Nat.succ_le_of_lt hk)] + · rw [get_insertNth_self _ _ _ (Nat.succ_le_of_lt hk)] convert hk' using 1 - exact nthLe_insertNth_add_succ _ _ _ 0 _ + 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 [nthLe_insertNth_add_succ] - · convert nthLe_insertNth_add_succ s x k m.succ (by simpa using hn) using 2 + rw [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 -set_option linter.deprecated false in 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 @@ -614,24 +613,23 @@ theorem nodup_permutations (s : List α) (hs : Nodup s) : Nodup s.permutations : 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 [← nthLe, nthLe_permutations'Aux] at hn' hm' + rw [get_permutations'Aux] at hn' hm' have hx : - nthLe (insertNth n x as) m (by rwa [length_insertNth _ _ hn, Nat.lt_succ_iff, hl]) = x := by + (insertNth n x as)[m]'(by rwa [length_insertNth _ _ hn, Nat.lt_succ_iff, hl]) = x := by simp [hn', ← hm', hm] have hx' : - nthLe (insertNth m x bs) n (by rwa [length_insertNth _ _ hm, Nat.lt_succ_iff, ← hl]) = - x := by + (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', nthLe_insertNth_of_lt _ _ _ _ ht (ht.trans_le hm)] - exact nthLe_mem _ _ _ + 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, nthLe_insertNth_of_lt _ _ _ _ ht (ht.trans_le hn)] - exact nthLe_mem _ _ _ + 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 diff --git a/Mathlib/Data/List/Permutation.lean b/Mathlib/Data/List/Permutation.lean index 873cf8aacfaee..dfa4674956933 100644 --- a/Mathlib/Data/List/Permutation.lean +++ b/Mathlib/Data/List/Permutation.lean @@ -182,7 +182,7 @@ theorem mem_foldr_permutationsAux2 {t : α} {ts : List α} {r L : List (List α) theorem length_foldr_permutationsAux2 (t : α) (ts : List α) (r L : List (List α)) : length (foldr (fun y r => (permutationsAux2 t ts r y id).2) r L) = Nat.sum (map length L) + length r := by - simp [foldr_permutationsAux2, (· ∘ ·), length_permutationsAux2, length_bind'] + simp [foldr_permutationsAux2, Function.comp_def, length_permutationsAux2, length_bind'] theorem length_foldr_permutationsAux2' (t : α) (ts : List α) (r L : List (List α)) (n) (H : ∀ l ∈ L, length l = n) : diff --git a/Mathlib/Data/List/Pi.lean b/Mathlib/Data/List/Pi.lean index 25244772bc6f4..629d8a1e4f855 100644 --- a/Mathlib/Data/List/Pi.lean +++ b/Mathlib/Data/List/Pi.lean @@ -24,12 +24,12 @@ def nil (α : ι → Sort*) : (∀ i ∈ ([] : List ι), α i) := variable {i : ι} {l : List ι} -/-- Given `f` a function whose domain is `i :: l`, get its value at `i`. -/ +/-- Given `f` a function whose domain is `i :: l`, get its value at `i`. -/ def head (f : ∀ j ∈ i :: l, α j) : α i := f i (mem_cons_self _ _) /-- Given `f` a function whose domain is `i :: l`, produce a function whose domain -is restricted to `l`. -/ +is restricted to `l`. -/ def tail (f : ∀ j ∈ i :: l, α j) : ∀ j ∈ l, α j := fun j hj ↦ f j (mem_cons_of_mem _ hj) diff --git a/Mathlib/Data/List/Prime.lean b/Mathlib/Data/List/Prime.lean index e5812cb86b262..45c8f957e4d93 100644 --- a/Mathlib/Data/List/Prime.lean +++ b/Mathlib/Data/List/Prime.lean @@ -43,7 +43,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 +54,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/ProdSigma.lean b/Mathlib/Data/List/ProdSigma.lean index 254509b226ec3..5b55bac8afedb 100644 --- a/Mathlib/Data/List/ProdSigma.lean +++ b/Mathlib/Data/List/ProdSigma.lean @@ -5,7 +5,6 @@ Authors: Leonardo de Moura, Mario Carneiro -/ import Mathlib.Data.List.Basic import Mathlib.Data.Sigma.Basic -import Batteries.Data.Nat.Lemmas /-! # Lists in product and sigma types diff --git a/Mathlib/Data/List/Range.lean b/Mathlib/Data/List/Range.lean index 64aec7b5b00f9..63ca906ece471 100644 --- a/Mathlib/Data/List/Range.lean +++ b/Mathlib/Data/List/Range.lean @@ -1,12 +1,10 @@ /- 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 -import Mathlib.Data.List.Pairwise -import Batteries.Data.Nat.Lemmas /-! # Ranges of naturals as lists @@ -27,14 +25,8 @@ namespace List variable {α : Type u} -set_option linter.deprecated false in -@[simp] -theorem nthLe_range' {n m step} (i) (H : i < (range' n m step).length) : - nthLe (range' n m step) i H = n + step * i := get_range' i H - -set_option linter.deprecated false in -theorem nthLe_range'_1 {n m} (i) (H : i < (range' n m).length) : - nthLe (range' n m) i H = n + i := by simp +theorem getElem_range'_1 {n m} (i) (H : i < (range' n m).length) : + (range' n m)[i] = n + i := by simp theorem chain'_range_succ (r : ℕ → ℕ → Prop) (n : ℕ) : Chain' r (range n.succ) ↔ ∀ m < n, r m m.succ := by @@ -42,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 : ℕ) : @@ -67,7 +58,7 @@ theorem mem_finRange {n : ℕ} (a : Fin n) : a ∈ finRange n := rfl⟩ theorem nodup_finRange (n : ℕ) : (finRange n).Nodup := - (Pairwise.pmap (nodup_range n) _) fun _ _ _ _ => @Fin.ne_of_vne _ ⟨_, _⟩ ⟨_, _⟩ + (Pairwise.pmap (nodup_range n) _) fun _ _ _ _ => @Fin.ne_of_val_ne _ ⟨_, _⟩ ⟨_, _⟩ @[simp] theorem length_finRange (n : ℕ) : (finRange n).length = n := by @@ -83,31 +74,25 @@ theorem pairwise_lt_finRange (n : ℕ) : Pairwise (· < ·) (finRange n) := theorem pairwise_le_finRange (n : ℕ) : Pairwise (· ≤ ·) (finRange n) := (List.pairwise_le_range n).pmap (by simp) (by simp) -set_option linter.deprecated false in -@[simp] -theorem nthLe_range {n} (i) (H : i < (range n).length) : nthLe (range n) i H = i := - get_range i H - @[simp] theorem getElem_finRange {n : ℕ} {i : ℕ} (h) : (finRange n)[i] = ⟨i, length_finRange n ▸ h⟩ := by - simp only [finRange, getElem_range, getElem_pmap] + simp [finRange, getElem_range, getElem_pmap] -- Porting note (#10756): new theorem theorem get_finRange {n : ℕ} {i : ℕ} (h) : (finRange n).get ⟨i, h⟩ = ⟨i, length_finRange n ▸ h⟩ := by simp +@[deprecated (since := "2024-08-19")] alias nthLe_range' := get_range' +@[deprecated (since := "2024-08-19")] alias nthLe_range'_1 := getElem_range'_1 +@[deprecated (since := "2024-08-19")] alias nthLe_range := get_range +@[deprecated (since := "2024-08-19")] alias nthLe_finRange := get_finRange + @[simp] theorem finRange_map_get (l : List α) : (finRange l.length).map l.get = l := List.ext_get (by simp) (by simp) -set_option linter.deprecated false in -@[simp] -theorem nthLe_finRange {n : ℕ} {i : ℕ} (h) : - (finRange n).nthLe i h = ⟨i, length_finRange n ▸ h⟩ := - get_finRange h - @[simp] theorem indexOf_finRange {k : ℕ} (i : Fin k) : (finRange k).indexOf i = i := by have : (finRange k).indexOf i < (finRange k).length := indexOf_lt_length.mpr (by simp) have h₁ : (finRange k).get ⟨(finRange k).indexOf i, this⟩ = i := indexOf_get this @@ -169,7 +154,7 @@ lemma mem_mem_ranges_iff_lt_natSum (l : List ℕ) {n : ℕ} : /-- The members of `l.ranges` have no duplicate -/ theorem ranges_nodup {l s : List ℕ} (hs : s ∈ ranges l) : s.Nodup := - (List.pairwise_join.mp $ by rw [ranges_join']; exact nodup_range _).1 s hs + (List.pairwise_join.mp <| by rw [ranges_join']; exact nodup_range _).1 s hs end Ranges 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 854cb1f9533fe..8b6479898785b 100644 --- a/Mathlib/Data/List/Rotate.lean +++ b/Mathlib/Data/List/Rotate.lean @@ -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 : ℕ} : @@ -168,7 +168,6 @@ theorem rotate_eq_nil_iff {l : List α} {n : ℕ} : l.rotate n = [] ↔ l = [] : · simp · simp [rotate_cons_succ, hn] -@[simp] theorem nil_eq_rotate_iff {l : List α} {n : ℕ} : [] = l.rotate n ↔ [] = l := by rw [eq_comm, rotate_eq_nil_iff, eq_comm] @@ -195,11 +194,11 @@ theorem getElem?_rotate {l : List α} {n m : ℕ} (hml : m < l.length) : (l.rotate n)[m]? = l[(m + n) % l.length]? := by rw [rotate_eq_drop_append_take_mod] rcases lt_or_le m (l.drop (n % l.length)).length with hm | hm - · rw [getElem?_append hm, getElem?_drop, ← add_mod_mod] + · rw [getElem?_append_left hm, getElem?_drop, ← add_mod_mod] rw [length_drop, Nat.lt_sub_iff_add_lt] at hm rw [mod_eq_of_lt hm, Nat.add_comm] · have hlt : n % length l < length l := mod_lt _ (m.zero_le.trans_lt hml) - rw [getElem?_append_right hm, getElem?_take, length_drop] + rw [getElem?_append_right hm, getElem?_take_of_lt, length_drop] · congr 1 rw [length_drop] at hm have hm' := Nat.sub_le_iff_le_add'.1 hm @@ -225,28 +224,18 @@ theorem get?_rotate {l : List α} {n m : ℕ} (hml : m < l.length) : -- Porting note (#10756): new lemma theorem get_rotate (l : List α) (n : ℕ) (k : Fin (l.rotate n).length) : - (l.rotate n).get k = - l.get ⟨(k + n) % l.length, mod_lt _ (length_rotate l n ▸ k.1.zero_le.trans_lt k.2)⟩ := by + (l.rotate n).get k = l.get ⟨(k + n) % l.length, mod_lt _ (length_rotate l n ▸ k.pos)⟩ := by simp [getElem_rotate] theorem head?_rotate {l : List α} {n : ℕ} (h : n < l.length) : head? (l.rotate n) = l[n]? := by rw [← get?_zero, get?_rotate (n.zero_le.trans_lt h), Nat.zero_add, Nat.mod_eq_of_lt h, get?_eq_getElem?] --- Porting note: moved down from its original location below `get_rotate` so that the --- non-deprecated lemma does not use the deprecated version -set_option linter.deprecated false in -@[deprecated get_rotate (since := "2023-01-13")] -theorem nthLe_rotate (l : List α) (n k : ℕ) (hk : k < (l.rotate n).length) : - (l.rotate n).nthLe k hk = - l.nthLe ((k + n) % l.length) (mod_lt _ (length_rotate l n ▸ k.zero_le.trans_lt hk)) := - get_rotate l n ⟨k, hk⟩ - -set_option linter.deprecated false in -theorem nthLe_rotate_one (l : List α) (k : ℕ) (hk : k < (l.rotate 1).length) : - (l.rotate 1).nthLe k hk = - l.nthLe ((k + 1) % l.length) (mod_lt _ (length_rotate l 1 ▸ k.zero_le.trans_lt hk)) := - nthLe_rotate l 1 k hk +theorem get_rotate_one (l : List α) (k : Fin (l.rotate 1).length) : + (l.rotate 1).get k = l.get ⟨(k + 1) % l.length, mod_lt _ (length_rotate l 1 ▸ k.pos)⟩ := + get_rotate l 1 k + +@[deprecated (since := "2024-08-19")] alias nthLe_rotate_one := get_rotate_one /-- A version of `List.get_rotate` that represents `List.get l` in terms of `List.get (List.rotate l n)`, not vice versa. Can be used instead of rewriting `List.get_rotate` @@ -260,15 +249,6 @@ theorem get_eq_get_rotate (l : List α) (n : ℕ) (k : Fin l.length) : rw [← add_mod_mod, Nat.add_right_comm, Nat.sub_add_cancel, add_mod_left, mod_eq_of_lt] exacts [k.2, (mod_lt _ (k.1.zero_le.trans_lt k.2)).le] -set_option linter.deprecated false in -/-- A variant of `List.nthLe_rotate` useful for rewrites from right to left. -/ -@[deprecated get_eq_get_rotate (since := "2023-03-26")] -theorem nthLe_rotate' (l : List α) (n k : ℕ) (hk : k < l.length) : - (l.rotate n).nthLe ((l.length - n % l.length + k) % l.length) - ((Nat.mod_lt _ (k.zero_le.trans_lt hk)).trans_le (length_rotate _ _).ge) = - l.nthLe k hk := - (get_eq_get_rotate l n ⟨k, hk⟩).symm - theorem rotate_eq_self_iff_eq_replicate [hα : Nonempty α] : ∀ {l : List α}, (∀ n, l.rotate n = l) ↔ ∃ a, l = replicate l.length a | [] => by simp @@ -374,7 +354,8 @@ def IsRotated : Prop := ∃ n, l.rotate n = l' @[inherit_doc List.IsRotated] -infixr:1000 " ~r " => IsRotated +-- This matches the precedence of the infix `~` for `List.Perm`, and of other relation infixes +infixr:50 " ~r " => IsRotated variable {l l'} @@ -477,6 +458,24 @@ theorem IsRotated.map {β : Type*} {l₁ l₂ : List α} (h : l₁ ~r l₂) (f : rw [map_rotate] use n +theorem IsRotated.cons_getLast_dropLast + (L : List α) (hL : L ≠ []) : L.getLast hL :: L.dropLast ~r L := by + induction L using List.reverseRecOn with + | nil => simp at hL + | append_singleton a L _ => + simp only [getLast_append, dropLast_concat] + apply IsRotated.symm + apply isRotated_concat + +theorem IsRotated.dropLast_tail {α} + {L : List α} (hL : L ≠ []) (hL' : L.head hL = L.getLast hL) : L.dropLast ~r L.tail := + match L with + | [] => by simp + | [_] => by simp + | a :: b :: L => by + 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`. The `cyclicPermutations` of a nonempty list `l` will always contain `List.length l` elements. This implies that under certain conditions, there are duplicates in `List.cyclicPermutations l`. @@ -611,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 4419034921ee1..ba2c572fe9480 100644 --- a/Mathlib/Data/List/Sigma.lean +++ b/Mathlib/Data/List/Sigma.lean @@ -26,11 +26,11 @@ If `α : Type*` and `β : α → Type*`, then we regard `s : Sigma β` as having - `List.kextract` returns a value with a given key and the rest of the values. -/ -universe u v +universe u u' v v' namespace List -variable {α : Type u} {β : α → Type v} {l l₁ l₂ : List (Sigma β)} +variable {α : Type u} {α' : Type u'} {β : α → Type v} {β' : α' → Type v'} {l l₁ l₂ : List (Sigma β)} /-! ### `keys` -/ @@ -123,7 +123,7 @@ theorem nodupKeys_join {L : List (List (Sigma β))} : rw [nodupKeys_iff_pairwise, pairwise_join, pairwise_map] refine and_congr (forall₂_congr fun l _ => by simp [nodupKeys_iff_pairwise]) ?_ apply iff_of_eq; congr with (l₁ l₂) - simp [keys, disjoint_iff_ne] + simp [keys, disjoint_iff_ne, Sigma.forall] theorem nodup_enum_map_fst (l : List α) : (l.enum.map Prod.fst).Nodup := by simp [List.nodup_range] @@ -131,7 +131,7 @@ theorem mem_ext {l₀ l₁ : List (Sigma β)} (nd₀ : l₀.Nodup) (nd₁ : l₁ (h : ∀ x, x ∈ l₀ ↔ x ∈ l₁) : l₀ ~ l₁ := (perm_ext_iff_of_nodup nd₀ nd₁).2 h -variable [DecidableEq α] +variable [DecidableEq α] [DecidableEq α'] /-! ### `dlookup` -/ @@ -204,6 +204,25 @@ theorem lookup_ext {l₀ l₁ : List (Sigma β)} (nd₀ : l₀.NodupKeys) (nd₁ mem_ext nd₀.nodup nd₁.nodup fun ⟨a, b⟩ => by rw [← mem_dlookup_iff, ← mem_dlookup_iff, h] <;> assumption +theorem dlookup_map (l : List (Sigma β)) + {f : α → α'} (hf : Function.Injective f) (g : ∀ a, β a → β' (f a)) (a : α) : + (l.map fun x => ⟨f x.1, g _ x.2⟩).dlookup (f a) = (l.dlookup a).map (g a) := by + induction' l with b l IH + · rw [map_nil, dlookup_nil, dlookup_nil, Option.map_none'] + · rw [map_cons] + obtain rfl | h := eq_or_ne a b.1 + · rw [dlookup_cons_eq, dlookup_cons_eq, Option.map_some'] + · rw [dlookup_cons_ne _ _ h, dlookup_cons_ne _ _ (fun he => h <| hf he), IH] + +theorem dlookup_map₁ {β : Type v} (l : List (Σ _ : α, β)) + {f : α → α'} (hf : Function.Injective f) (a : α) : + (l.map fun x => ⟨f x.1, x.2⟩ : List (Σ _ : α', β)).dlookup (f a) = l.dlookup a := by + rw [dlookup_map (β' := fun _ => β) l hf (fun _ x => x) a, Option.map_id'] + +theorem dlookup_map₂ {γ δ : α → Type*} {l : List (Σ a, γ a)} {f : ∀ a, γ a → δ a} (a : α) : + (l.map fun x => ⟨x.1, f _ x.2⟩ : List (Σ a, δ a)).dlookup a = (l.dlookup a).map (f a) := + dlookup_map l Function.injective_id _ _ + /-! ### `lookupAll` -/ @@ -231,7 +250,7 @@ theorem lookupAll_eq_nil {a : α} : by_cases h : a = a' · subst a' simp only [lookupAll_cons_eq, mem_cons, Sigma.mk.inj_iff, heq_eq_eq, true_and, not_or, - false_iff, not_forall, not_and, not_not] + false_iff, not_forall, not_and, not_not, reduceCtorEq] use b simp · simp [h, lookupAll_eq_nil] @@ -282,6 +301,16 @@ theorem perm_lookupAll (a : α) {l₁ l₂ : List (Sigma β)} (nd₁ : l₁.Nodu (p : l₁ ~ l₂) : lookupAll a l₁ = lookupAll a l₂ := by simp [lookupAll_eq_dlookup, nd₁, nd₂, perm_dlookup a nd₁ nd₂ p] +theorem dlookup_append (l₁ l₂ : List (Sigma β)) (a : α) : + (l₁ ++ l₂).dlookup a = (l₁.dlookup a).or (l₂.dlookup a) := by + induction l₁ with + | nil => rfl + | cons x l₁ IH => + rw [cons_append] + obtain rfl | hb := Decidable.eq_or_ne a x.1 + · rw [dlookup_cons_eq, dlookup_cons_eq, Option.or] + · rw [dlookup_cons_ne _ _ hb, dlookup_cons_ne _ _ hb, IH] + /-! ### `kreplace` -/ @@ -350,7 +379,9 @@ theorem kerase_cons_ne {a} {s : Sigma β} {l : List (Sigma β)} (h : a ≠ s.1) @[simp] theorem kerase_of_not_mem_keys {a} {l : List (Sigma β)} (h : a ∉ l.keys) : kerase a l = l := by - induction' l with _ _ ih <;> [rfl; (simp [not_or] at h; simp [h.1, ih h.2])] + induction l with + | nil => rfl + | cons _ _ ih => simp [not_or] at h; simp [h.1, ih h.2] theorem kerase_sublist (a : α) (l : List (Sigma β)) : kerase a l <+ l := eraseP_sublist _ @@ -388,7 +419,7 @@ theorem mem_keys_kerase_of_ne {a₁ a₂} {l : List (Sigma β)} (h : a₁ ≠ a else by simp [q, p] theorem keys_kerase {a} {l : List (Sigma β)} : (kerase a l).keys = l.keys.erase a := by - rw [keys, kerase, erase_eq_eraseP, eraseP_map, Function.comp] + rw [keys, kerase, erase_eq_eraseP, eraseP_map, Function.comp_def] simp only [beq_eq_decide] congr funext diff --git a/Mathlib/Data/List/Sort.lean b/Mathlib/Data/List/Sort.lean index 7866907505fca..be93169d29b88 100644 --- a/Mathlib/Data/List/Sort.lean +++ b/Mathlib/Data/List/Sort.lean @@ -5,8 +5,8 @@ Authors: Jeremy Avigad -/ import Mathlib.Data.List.OfFn import Mathlib.Data.List.Nodup -import Mathlib.Data.List.Infix import Mathlib.Order.Fin.Basic +import Batteries.Data.List.Perm /-! # Sorting algorithms on lists @@ -14,13 +14,31 @@ import Mathlib.Order.Fin.Basic 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. +`List.insertionSort` and `List.mergeSort'`, and prove their 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 +universe u v namespace List @@ -31,7 +49,7 @@ namespace List section Sorted -variable {α : Type u} {r : α → α → Prop} {a : α} {l : List α} +variable {α : Type u} {β : Type v} {r : α → α → Prop} {s : β → β → 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) -/ @@ -105,8 +123,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] @@ -123,27 +141,15 @@ theorem Sorted.rel_get_of_lt {l : List α} (h : l.Sorted r) {a b : Fin l.length} r (l.get a) (l.get b) := List.pairwise_iff_get.1 h _ _ hab -set_option linter.deprecated false in -@[deprecated Sorted.rel_get_of_lt (since := "2024-05-08")] -theorem Sorted.rel_nthLe_of_lt {l : List α} (h : l.Sorted r) {a b : ℕ} (ha : a < l.length) - (hb : b < l.length) (hab : a < b) : r (l.nthLe a ha) (l.nthLe b hb) := - List.pairwise_iff_get.1 h ⟨a, ha⟩ ⟨b, hb⟩ hab - theorem Sorted.rel_get_of_le [IsRefl α r] {l : List α} (h : l.Sorted r) {a b : Fin l.length} (hab : a ≤ b) : r (l.get a) (l.get b) := by obtain rfl | hlt := Fin.eq_or_lt_of_le hab; exacts [refl _, h.rel_get_of_lt hlt] -set_option linter.deprecated false in -@[deprecated Sorted.rel_get_of_le (since := "2024-05-08")] -theorem Sorted.rel_nthLe_of_le [IsRefl α r] {l : List α} (h : l.Sorted r) {a b : ℕ} - (ha : a < l.length) (hb : b < l.length) (hab : a ≤ b) : r (l.nthLe a ha) (l.nthLe b hb) := - h.rel_get_of_le hab - theorem Sorted.rel_of_mem_take_of_mem_drop {l : List α} (h : List.Sorted r l) {k : ℕ} {x y : α} (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) @@ -167,10 +173,6 @@ strictly monotone. -/ @[simp] theorem sorted_le_ofFn_iff : (ofFn f).Sorted (· ≤ ·) ↔ Monotone f := sorted_ofFn_iff.trans monotone_iff_forall_lt.symm -/-- A tuple is monotone if and only if the list obtained from it is sorted. -/ -@[deprecated sorted_le_ofFn_iff (since := "2023-01-10")] -theorem monotone_iff_ofFn_sorted : Monotone f ↔ (ofFn f).Sorted (· ≤ ·) := sorted_le_ofFn_iff.symm - /-- The list obtained from a monotone tuple is sorted. -/ alias ⟨_, _root_.Monotone.ofFn_sorted⟩ := sorted_le_ofFn_iff @@ -178,9 +180,11 @@ end Monotone section sort -variable {α : Type u} (r : α → α → Prop) [DecidableRel r] +variable {α : Type u} {β : Type v} (r : α → α → Prop) (s : β → β → Prop) +variable [DecidableRel r] [DecidableRel s] local infixl:50 " ≼ " => r +local infixl:50 " ≼ " => s /-! ### Insertion sort -/ @@ -194,6 +198,10 @@ 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 α @@ -236,6 +244,18 @@ theorem mem_orderedInsert {a b : α} {l : List α} : · simp [orderedInsert] · rw [mem_cons, mem_cons, mem_orderedInsert, or_left_comm] +theorem map_orderedInsert (f : α → β) (l : List α) (x : α) + (hl₁ : ∀ a ∈ l, a ≼ x ↔ f a ≼ f x) (hl₂ : ∀ a ∈ l, x ≼ a ↔ f x ≼ f a) : + (l.orderedInsert r x).map f = (l.map f).orderedInsert s (f x) := by + induction l with + | nil => simp + | cons x xs ih => + rw [List.forall_mem_cons] at hl₁ hl₂ + simp only [List.map, List.orderedInsert, ← hl₁.1, ← hl₂.1] + split_ifs + · rw [List.map, List.map] + · rw [List.map, ih (fun _ ha => hl₁.2 _ ha) (fun _ ha => hl₂.2 _ ha)] + section Correctness open Perm @@ -257,6 +277,36 @@ theorem perm_insertionSort : ∀ l : List α, insertionSort r l ~ l | b :: l => by simpa [insertionSort] using (perm_orderedInsert _ _ _).trans ((perm_insertionSort l).cons b) +@[simp] +theorem mem_insertionSort {l : List α} {x : α} : x ∈ l.insertionSort r ↔ x ∈ l := + (perm_insertionSort r l).mem_iff + +@[simp] +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 + | nil => simp + | cons x xs ih => + simp_rw [List.forall_mem_cons, forall_and] at hl + simp_rw [List.map, List.insertionSort] + rw [List.map_orderedInsert _ s, ih hl.2.2] + · simpa only [mem_insertionSort] using hl.2.1 + · simpa only [mem_insertionSort] using hl.1.2 + variable {r} /-- If `l` is already `List.Sorted` with respect to `r`, then `insertionSort` does not change @@ -310,6 +360,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] @@ -339,6 +423,59 @@ theorem sorted_insertionSort : ∀ l, Sorted r (insertionSort r l) end TotalAndTransitive +/-- +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 + +variable [IsAntisymm α r] [IsTotal α r] [IsTrans α r] + +/-- +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 ..) + +/-- +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 + end Correctness end InsertionSort @@ -363,6 +500,17 @@ def split : List α → List α × List α 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] +@[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] + +@[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⟩ @@ -393,7 +541,7 @@ theorem perm_split : ∀ {l l₁ l₂ : List α}, split l = (l₁, 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 α +def mergeSort' : List α → List α | [] => [] | [a] => [a] | a :: b :: l => by @@ -401,43 +549,47 @@ def mergeSort : List α → List α 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) + exact merge (mergeSort' ls.1) (mergeSort' ls.2) (r · ·) termination_by l => length l @[nolint unusedHavesSuffices] -- Porting note: false positive -theorem mergeSort_cons_cons {a b} {l l₁ l₂ : List α} (h : split (a :: b :: l) = (l₁, l₂)) : - mergeSort r (a :: b :: l) = merge (r · ·) (mergeSort r l₁) (mergeSort r l₂) := by - simp only [mergeSort, h] +theorem mergeSort'_cons_cons {a b} {l l₁ l₂ : List α} (h : split (a :: b :: l) = (l₁, l₂)) : + mergeSort' r (a :: b :: l) = merge (mergeSort' r l₁) (mergeSort' r l₂) (r · ·) := by + simp only [mergeSort', h] section Correctness -theorem perm_mergeSort : ∀ l : List α, mergeSort r l ~ l - | [] => by simp [mergeSort] - | [a] => by simp [mergeSort] +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] + rw [mergeSort'_cons_cons r e] apply (perm_merge (r · ·) _ _).trans exact - ((perm_mergeSort l₁).append (perm_mergeSort l₂)).trans (perm_split e).symm + ((perm_mergeSort' l₁).append (perm_mergeSort' l₂)).trans (perm_split e).symm termination_by l => length l @[simp] -theorem length_mergeSort (l : List α) : (mergeSort r l).length = l.length := - (perm_mergeSort r _).length_eq +theorem mem_mergeSort' {l : List α} {x : α} : x ∈ l.mergeSort' r ↔ x ∈ l := + (perm_mergeSort' r l).mem_iff + +@[simp] +theorem length_mergeSort' (l : List α) : (mergeSort' r l).length = l.length := + (perm_mergeSort' r _).length_eq section TotalAndTransitive variable {r} [IsTotal α r] [IsTrans α r] -theorem Sorted.merge : ∀ {l l' : List α}, Sorted r l → Sorted r l' → Sorted r (merge (r · ·) l l') +theorem Sorted.merge : ∀ {l l' : List α}, Sorted r l → Sorted r l' → Sorted r (merge l l' (r · ·) ) | [], [], _, _ => by simp | [], b :: l', _, h₂ => by simpa using h₂ | a :: l, [], h₁, _ => by simpa using h₁ | a :: l, b :: l', h₁, h₂ => by by_cases h : a ≼ b - · suffices ∀ b' ∈ List.merge (r · ·) l (b :: l'), r a b' by + · suffices ∀ b' ∈ List.merge l (b :: l') (r · ·) , r a b' by simpa [h, h₁.of_cons.merge h₂] intro b' bm rcases show b' = b ∨ b' ∈ l ∨ b' ∈ l' by @@ -447,7 +599,7 @@ theorem Sorted.merge : ∀ {l l' : List α}, Sorted r l → Sorted r l' → Sort assumption · exact rel_of_sorted_cons h₁ _ bl · exact _root_.trans h (rel_of_sorted_cons h₂ _ bl') - · suffices ∀ b' ∈ List.merge (r · ·) (a :: l) l', r b b' by + · suffices ∀ b' ∈ List.merge (a :: l) l' (r · ·) , r b b' by simpa [h, h₁.merge h₂.of_cons] intro b' bm have ba : b ≼ a := (total_of r _ _).resolve_left h @@ -460,33 +612,54 @@ theorem Sorted.merge : ∀ {l l' : List α}, Sorted r l → Sorted r l' → Sort variable (r) -theorem sorted_mergeSort : ∀ l : List α, Sorted r (mergeSort r l) - | [] => by simp [mergeSort] - | [a] => by simp [mergeSort] +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₂) + 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_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) +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) end TotalAndTransitive end Correctness @[simp] -theorem mergeSort_nil : [].mergeSort r = [] := by rw [List.mergeSort] +theorem mergeSort'_nil : [].mergeSort' r = [] := by rw [List.mergeSort'] @[simp] -theorem mergeSort_singleton (a : α) : [a].mergeSort r = [a] := by rw [List.mergeSort] +theorem mergeSort'_singleton (a : α) : [a].mergeSort' r = [a] := by rw [List.mergeSort'] + +theorem map_mergeSort' (f : α → β) (l : List α) (hl : ∀ a ∈ l, ∀ b ∈ l, a ≼ b ↔ f a ≼ f b) : + (l.mergeSort' r).map f = (l.map f).mergeSort' s := + match l with + | [] => by simp + | [x] => by simp + | a :: b :: l => by + simp_rw [← mem_split_iff (l := a :: b :: l), or_imp, forall_and] at hl + set l₁ := (split (a :: b :: l)).1 + set l₂ := (split (a :: b :: l)).2 + have e : split (a :: b :: l) = (l₁, l₂) := rfl + have fe : split (f a :: f b :: l.map f) = (l₁.map f, l₂.map f) := by + rw [← map, ← map, map_split, e] + have := length_split_fst_le l + have := length_split_snd_le l + simp_rw [List.map] + rw [List.mergeSort'_cons_cons _ e, List.mergeSort'_cons_cons _ fe, + map_merge, map_mergeSort' _ l₁ hl.1.1, map_mergeSort' _ l₂ hl.2.2] + simp_rw [mem_mergeSort', decide_eq_decide] + exact hl.1.2 + termination_by length l end MergeSort @@ -494,5 +667,5 @@ 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] +--#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 7df5ef9099e10..3d8300bd2d98a 100644 --- a/Mathlib/Data/List/Sublists.lean +++ b/Mathlib/Data/List/Sublists.lean @@ -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 @@ -138,7 +136,7 @@ theorem sublists_append (l₁ l₂ : List α) : | nil => simp | cons a l₁ ih => rw [foldr_cons, ih] - simp [List.bind, join_join, Function.comp] + simp [List.bind, join_join, Function.comp_def] theorem sublists_cons (a : α) (l : List α) : sublists (a :: l) = sublists l >>= (fun x => [x, a :: x]) := @@ -155,13 +153,13 @@ theorem sublists_concat (l : List α) (a : α) : theorem sublists_reverse (l : List α) : sublists (reverse l) = map reverse (sublists' l) := by induction' l with hd tl ih <;> [rfl; simp only [reverse_cons, sublists_append, sublists'_cons, map_append, ih, sublists_singleton, - map_eq_map, bind_eq_bind, map_map, bind_cons, append_nil, bind_nil, (· ∘ ·)]] + map_eq_map, bind_eq_bind, map_map, bind_cons, append_nil, bind_nil, Function.comp_def]] theorem sublists_eq_sublists' (l : List α) : sublists l = map reverse (sublists' (reverse l)) := by rw [← sublists_reverse, reverse_reverse] theorem sublists'_reverse (l : List α) : sublists' (reverse l) = map reverse (sublists l) := by - simp only [sublists_eq_sublists', map_map, map_id'' reverse_reverse, Function.comp] + simp only [sublists_eq_sublists', map_map, map_id'' reverse_reverse, Function.comp_def] theorem sublists'_eq_sublists (l : List α) : sublists' l = map reverse (sublists (reverse l)) := by rw [← sublists'_reverse, reverse_reverse] 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/ToFinsupp.lean b/Mathlib/Data/List/ToFinsupp.lean index b8fbb880f704e..5d55f1ae03af6 100644 --- a/Mathlib/Data/List/ToFinsupp.lean +++ b/Mathlib/Data/List/ToFinsupp.lean @@ -62,10 +62,10 @@ theorem toFinsupp_support : rfl theorem toFinsupp_apply_lt (hn : n < l.length) : l.toFinsupp n = l[n] := - getD_eq_getElem _ _ _ + getD_eq_getElem _ _ hn theorem toFinsupp_apply_fin (n : Fin l.length) : l.toFinsupp n = l[n] := - getD_eq_getElem _ _ _ + getD_eq_getElem _ _ n.isLt theorem toFinsupp_apply_le (hn : l.length ≤ n) : l.toFinsupp n = 0 := getD_eq_default _ _ hn diff --git a/Mathlib/Data/List/Zip.lean b/Mathlib/Data/List/Zip.lean index b67d88264a517..cb8b7daa47501 100644 --- a/Mathlib/Data/List/Zip.lean +++ b/Mathlib/Data/List/Zip.lean @@ -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] @@ -144,27 +144,12 @@ theorem get_zipWith {f : α → β → γ} {l : List α} {l' : List β} {i : Fin (l'.get ⟨i, lt_length_right_of_zipWith i.isLt⟩) := by simp -set_option linter.deprecated false in -@[simp, deprecated get_zipWith (since := "2024-05-09")] -theorem nthLe_zipWith {f : α → β → γ} {l : List α} {l' : List β} {i : ℕ} - {h : i < (zipWith f l l').length} : - (zipWith f l l').nthLe i h = - f (l.nthLe i (lt_length_left_of_zipWith h)) (l'.nthLe i (lt_length_right_of_zipWith h)) := - get_zipWith (i := ⟨i, h⟩) - @[deprecated getElem_zip (since := "2024-06-12")] theorem get_zip {l : List α} {l' : List β} {i : Fin (zip l l').length} : (zip l l').get i = (l.get ⟨i, lt_length_left_of_zip i.isLt⟩, l'.get ⟨i, lt_length_right_of_zip i.isLt⟩) := by simp -set_option linter.deprecated false in -@[simp, deprecated get_zip (since := "2024-05-09")] -theorem nthLe_zip {l : List α} {l' : List β} {i : ℕ} {h : i < (zip l l').length} : - (zip l l').nthLe i h = - (l.nthLe i (lt_length_left_of_zip h), l'.nthLe i (lt_length_right_of_zip h)) := - nthLe_zipWith - theorem mem_zip_inits_tails {l : List α} {init tail : List α} : (init, tail) ∈ zip l.inits l.tails ↔ init ++ tail = l := by induction' l with hd tl ih generalizing init tail <;> simp_rw [tails, inits, zip_cons_cons] diff --git a/Mathlib/Data/MLList/BestFirst.lean b/Mathlib/Data/MLList/BestFirst.lean index 38b1922f6cf69..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 @@ -40,7 +40,7 @@ If someone would like to generalize appropriately that would be great. We want to maintain a priority queue of `MLList m β`, each indexed by some `a : α` with a priority. (One could simplify matters here by simply flattening this out to a priority queue of pairs `α × β`, with the priority determined by the `α` factor. -However the lazyness of `MLList` is essential to performance here: +However the laziness of `MLList` is essential to performance here: we will extract elements from these lists one at a time, and only when they at the head of the queue. If another item arrives at the head of the queue, @@ -87,9 +87,7 @@ structure BestFirstNode {α : Sort*} {ω : Type*} (prio : α → Thunk ω) (ε : (We will assume we have `[∀ a : α, Estimator (prio a) (ε a)]`.) -/ estimator : ε key -set_option autoImplicit true - -variable {α : Type} {prio : α → Thunk ω} {ε : α → Type} [LinearOrder ω] +variable {ω α : Type} {prio : α → Thunk ω} {ε : α → Type} [LinearOrder ω] [∀ a, Estimator (prio a) (ε a)] [I : ∀ a : α, WellFoundedGT (range (bound (prio a) : ε a → ω))] {m : Type → Type} [Monad m] {β : Type} diff --git a/Mathlib/Data/MLList/Dedup.lean b/Mathlib/Data/MLList/Dedup.lean index f4579cb51a78d..736453f47d9f1 100644 --- a/Mathlib/Data/MLList/Dedup.lean +++ b/Mathlib/Data/MLList/Dedup.lean @@ -1,15 +1,22 @@ /- -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 import Batteries.Data.HashMap.Basic /-! # Lazy deduplication of lazy lists + +## Deprecation + +This material has been moved out of Mathlib to https://github.com/semorrison/lean-monadic-list. -/ +set_option linter.deprecated false + open Batteries namespace MLList @@ -18,6 +25,7 @@ variable {α β : Type} {m : Type → Type} [Monad m] [BEq β] [Hashable β] /-- Lazily deduplicate a lazy list, using a stored `HashMap`. -/ -- We choose `HashMap` here instead of `RBSet` as the initial application is `Expr`. +@[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] def dedupBy (L : MLList m α) (f : α → m β) : MLList m α := ((L.liftM : MLList (StateT (HashMap β Unit) m) α) >>= fun a => do let b ← f a @@ -27,7 +35,7 @@ def dedupBy (L : MLList m α) (f : α → m β) : MLList m α := |>.runState' ∅ /-- Lazily deduplicate a lazy list, using a stored `HashMap`. -/ -def dedup (L : MLList m β) : MLList m β := - L.dedupBy (fun b => pure b) +@[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] +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 0e0b0e96a5e2b..cc407b0ef5c2d 100644 --- a/Mathlib/Data/MLList/DepthFirst.lean +++ b/Mathlib/Data/MLList/DepthFirst.lean @@ -1,11 +1,11 @@ /- -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.HashSet import Batteries.Data.MLList.Basic import Mathlib.Control.Combinators +import Std.Data.HashSet.Basic /-! # Depth first search @@ -17,8 +17,14 @@ or a lazy list `α → MLList MetaM α`. This is useful in meta code for searching for solutions in the presence of alternatives. It can be nice to represent the choices via a lazy list, so the later choices don't need to be evaluated while we do depth first search on earlier choices. + +## Deprecation + +This material has been moved out of Mathlib to https://github.com/semorrison/lean-monadic-list. -/ +set_option linter.deprecated false + universe u variable {α : Type u} {m : Type u → Type u} @@ -28,6 +34,7 @@ variable [Monad m] [Alternative m] /-- A generalisation of `depthFirst`, which allows the generation function to know the current depth, and to count the depth starting from a specified value. -/ +@[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] partial def depthFirst' (f : Nat → α → m α) (n : Nat) (a : α) : m α := pure a <|> joinM ((f n a) <&> (depthFirst' f (n+1))) @@ -43,6 +50,7 @@ The option `maxDepth` limits the search depth. Note that if the graph is not a tree then elements will be visited multiple times. (See `depthFirstRemovingDuplicates`) -/ +@[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] def depthFirst (f : α → m α) (a : α) (maxDepth : Option Nat := none) : m α := match maxDepth with | some d => depthFirst' (fun n a => if n ≤ d then f a else failure) 0 a @@ -66,15 +74,16 @@ avoiding duplication up to equality or isomorphism, use Brendan McKay's method of "generation by canonical construction path". -/ -- TODO can you make this work in `List` and `MLList m` simultaneously, by being tricky with monads? +@[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] def depthFirstRemovingDuplicates {α : Type u} [BEq α] [Hashable α] (f : α → MLList m α) (a : α) (maxDepth : Option Nat := none) : MLList m α := -let f' : α → MLList (StateT.{u} (HashSet α) m) α := fun a => +let f' : α → MLList (StateT.{u} (Std.HashSet α) m) α := fun a => (f a).liftM >>= fun b => do let s ← get if s.contains b then failure set <| s.insert b pure b -(depthFirst f' a maxDepth).runState' (HashSet.empty.insert a) +(depthFirst f' a maxDepth).runState' (Std.HashSet.empty.insert a) /-- Variant of `depthFirst`, @@ -82,6 +91,7 @@ using an internal `HashSet` to record and avoid already visited nodes. This version describes the graph using `α → List α`, and returns the list of nodes visited in order. -/ +@[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] def depthFirstRemovingDuplicates' [BEq α] [Hashable α] (f : α → List α) (a : α) (maxDepth : Option Nat := none) : List α := depthFirstRemovingDuplicates diff --git a/Mathlib/Data/MLList/IO.lean b/Mathlib/Data/MLList/IO.lean index 38b8d9242d245..caec83d6d5838 100644 --- a/Mathlib/Data/MLList/IO.lean +++ b/Mathlib/Data/MLList/IO.lean @@ -1,19 +1,26 @@ /- -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 /-! # Reading from handles, files, and processes as lazy lists. + +## Deprecation + +This material has been moved out of Mathlib to https://github.com/semorrison/lean-monadic-list. -/ open System IO.FS +set_option linter.deprecated false namespace MLList /-- Read lines of text from a handle, as a lazy list in `IO`. -/ +@[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] def linesFromHandle (h : Handle) : MLList IO String := MLList.iterate (do let line ← h.getLine @@ -30,6 +37,7 @@ def linesFromHandle (h : Handle) : MLList IO String := |>.takeWhile (·.isSome) |>.map (fun o => o.getD "") /-- Read lines of text from a file, as a lazy list in `IO`. -/ +@[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] def lines (f : FilePath) : MLList IO String := .squash fun _ => do return linesFromHandle (← Handle.mk f Mode.read) @@ -38,6 +46,7 @@ open IO.Process in Run a command with given input on `stdio`, returning `stdout` as a lazy list in `IO`. -/ +@[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] def runCmd (cmd : String) (args : Array String) (input : String := "") : MLList IO String := do let child ← spawn { cmd := cmd, args := args, stdin := .piped, stdout := .piped, stderr := .piped } @@ -49,3 +58,5 @@ where put stdin.putStr input stdin.flush return child + +end MLList diff --git a/Mathlib/Data/MLList/Split.lean b/Mathlib/Data/MLList/Split.lean index 84dc19b7dbc81..2705ad27826e6 100644 --- a/Mathlib/Data/MLList/Split.lean +++ b/Mathlib/Data/MLList/Split.lean @@ -1,15 +1,21 @@ /- -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 /-! # Functions for splitting monadic lazy lists. + +## Deprecation + +This material has been moved out of Mathlib to https://github.com/semorrison/lean-monadic-list. -/ +set_option linter.deprecated false + namespace MLList universe u @@ -20,6 +26,7 @@ Extract the prefix of a lazy list consisting of elements up to and including the first element satisfying a monadic predicate. Return (in the monad) the prefix as a `List`, along with the remaining elements as a `MLList`. -/ +@[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] partial def getUpToFirstM (L : MLList m α) (p : α → m (ULift Bool)) : m (List α × MLList m α) := do match ← L.uncons with | none => return ([], nil) @@ -34,6 +41,7 @@ Extract the prefix of a lazy list consisting of elements up to and including the first element satisfying a predicate. Return (in the monad) the prefix as a `List`, along with the remaining elements as a `MLList`. -/ +@[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] def getUpToFirst (L : MLList m α) (p : α → Bool) : m (List α × MLList m α) := L.getUpToFirstM fun a => pure (.up (p a)) @@ -45,6 +53,7 @@ Return (in the monad) the prefix as a `List`, along with the remaining elements (Note that the first element *not* satisfying the predicate will be generated, and pushed back on to the remaining lazy list.) -/ +@[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] partial def splitWhileM (L : MLList m α) (p : α → m (ULift Bool)) : m (List α × MLList m α) := do match ← L.uncons with @@ -63,6 +72,7 @@ Return (in the monad) the prefix as a `List`, along with the remaining elements (Note that the first element *not* satisfying the predicate will be generated, and pushed back on to the remaining lazy list.) -/ +@[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] def splitWhile (L : MLList m α) (p : α → Bool) : m (List α × MLList m α) := L.splitWhileM fun a => pure (.up (p a)) @@ -72,6 +82,7 @@ a monadic function. Return a lazy lists of pairs, consisting of a value under that function, and a maximal list of elements having that value. -/ +@[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] partial def groupByM [DecidableEq β] (L : MLList m α) (f : α → m β) : MLList m (β × List α) := L.cases (fun _ => nil) fun a t => squash fun _ => do let b ← f a @@ -83,6 +94,7 @@ Splits a lazy list into contiguous sublists of elements with the same value unde Return a lazy lists of pairs, consisting of a value under that function, and a maximal list of elements having that value. -/ +@[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] def groupBy [DecidableEq β] (L : MLList m α) (f : α → β) : MLList m (β × List α) := L.groupByM fun a => pure (f a) @@ -93,6 +105,7 @@ def groupBy [DecidableEq β] (L : MLList m α) (f : α → β) : MLList m (β × Split a lazy list into contiguous sublists, starting a new sublist each time a monadic predicate changes from `false` to `true`. -/ +@[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] partial def splitAtBecomesTrueM (L : MLList m α) (p : α → m (ULift Bool)) : MLList m (List α) := aux (L.groupByM p) where aux (M : MLList m (ULift.{u} Bool × List α)) : MLList m (List α) := @@ -106,5 +119,8 @@ where aux (M : MLList m (ULift.{u} Bool × List α)) : MLList m (List α) := Split a lazy list into contiguous sublists, starting a new sublist each time a predicate changes from `false` to `true`. -/ +@[deprecated "See deprecation note in module documentation." (since := "2024-08-22")] def splitAtBecomesTrue (L : MLList m α) (p : α → Bool) : MLList m (List α) := L.splitAtBecomesTrueM fun a => pure (.up (p a)) + +end MLList diff --git a/Mathlib/Data/Matrix/Basic.lean b/Mathlib/Data/Matrix/Basic.lean index 3d645f33d8402..63bc543ba910b 100644 --- a/Mathlib/Data/Matrix/Basic.lean +++ b/Mathlib/Data/Matrix/Basic.lean @@ -5,6 +5,7 @@ Authors: Ellen Arlt, Blair Shi, Sean Leather, Mario Carneiro, Johan Commelin, Lu -/ import Mathlib.Algebra.Algebra.Opposite import Mathlib.Algebra.Algebra.Pi +import Mathlib.Algebra.BigOperators.GroupWithZero.Action import Mathlib.Algebra.BigOperators.Pi import Mathlib.Algebra.BigOperators.Ring import Mathlib.Algebra.BigOperators.RingEquiv @@ -13,7 +14,6 @@ import Mathlib.Algebra.Star.BigOperators import Mathlib.Algebra.Star.Module import Mathlib.Algebra.Star.Pi import Mathlib.Data.Fintype.BigOperators -import Mathlib.GroupTheory.GroupAction.BigOperators /-! # Matrices @@ -492,6 +492,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 α] @@ -733,7 +738,7 @@ theorem dotProduct_comp_equiv_symm (e : n ≃ m) : u ⬝ᵥ x ∘ e.symm = u ∘ @[simp] theorem comp_equiv_dotProduct_comp_equiv (e : m ≃ n) : x ∘ e ⬝ᵥ y ∘ e = x ⬝ᵥ y := by -- Porting note: was `simp only` with all three lemmas - rw [← dotProduct_comp_equiv_symm]; simp only [Function.comp, Equiv.apply_symm_apply] + rw [← dotProduct_comp_equiv_symm]; simp only [Function.comp_def, Equiv.apply_symm_apply] end NonUnitalNonAssocSemiring @@ -2093,7 +2098,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] @@ -2161,7 +2165,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 @@ -2526,10 +2529,12 @@ theorem map_dotProduct [NonAssocSemiring R] [NonAssocSemiring S] (f : R →+* S) theorem map_vecMul [NonAssocSemiring R] [NonAssocSemiring S] (f : R →+* S) (M : Matrix n m R) (v : n → R) (i : m) : f ((v ᵥ* M) i) = ((f ∘ v) ᵥ* M.map f) i := by - simp only [Matrix.vecMul, Matrix.map_apply, RingHom.map_dotProduct, Function.comp] + simp only [Matrix.vecMul, Matrix.map_apply, RingHom.map_dotProduct, Function.comp_def] theorem map_mulVec [NonAssocSemiring R] [NonAssocSemiring S] (f : R →+* S) (M : Matrix m n R) (v : n → R) (i : m) : f ((M *ᵥ v) i) = (M.map f *ᵥ (f ∘ v)) i := by - simp only [Matrix.mulVec, Matrix.map_apply, RingHom.map_dotProduct, Function.comp] + simp only [Matrix.mulVec, Matrix.map_apply, RingHom.map_dotProduct, Function.comp_def] end RingHom + +set_option linter.style.longFile 2700 diff --git a/Mathlib/Data/Matrix/Basis.lean b/Mathlib/Data/Matrix/Basis.lean index 1204f7bb9f157..01c7a8cf445b6 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 diff --git a/Mathlib/Data/Matrix/ColumnRowPartitioned.lean b/Mathlib/Data/Matrix/ColumnRowPartitioned.lean index d8f1117d5f756..1fef44043ba64 100644 --- a/Mathlib/Data/Matrix/ColumnRowPartitioned.lean +++ b/Mathlib/Data/Matrix/ColumnRowPartitioned.lean @@ -74,11 +74,11 @@ lemma toRows₂_apply (A : Matrix (m₁ ⊕ m₂) n R) (i : m₂) (j : n) : (toRows₂ A) i j = A (Sum.inr i) j := rfl @[simp] -lemma toRows₁_fromRows (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) : +lemma toRows₁_fromRows (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) : toRows₁ (fromRows A₁ A₂) = A₁ := rfl @[simp] -lemma toRows₂_fromRows (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) : +lemma toRows₂_fromRows (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) : toRows₂ (fromRows A₁ A₂) = A₂ := rfl @[simp] @@ -124,14 +124,14 @@ lemma fromRows_ext_iff (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) (B₁ : (B₂ : Matrix m₂ n R) : fromRows A₁ A₂ = fromRows B₁ B₂ ↔ A₁ = B₁ ∧ A₂ = B₂ := fromRows_inj.eq_iff -/-- A column partioned matrix when transposed gives a row partioned matrix with columns of the -initial matrix tranposed to become rows. -/ +/-- A column partitioned matrix when transposed gives a row partitioned matrix with columns of the +initial matrix transposed to become rows. -/ lemma transpose_fromColumns (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) : transpose (fromColumns A₁ A₂) = fromRows (transpose A₁) (transpose A₂) := by ext (i | i) j <;> simp -/-- A row partioned matrix when transposed gives a column partioned matrix with rows of the initial -matrix tranposed to become columns. -/ +/-- A row partitioned matrix when transposed gives a column partitioned matrix with rows of the +initial matrix transposed to become columns. -/ lemma transpose_fromRows (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) : transpose (fromRows A₁ A₂) = fromColumns (transpose A₁) (transpose A₂) := by ext i (j | j) <;> simp @@ -212,29 +212,31 @@ lemma fromRows_zero : fromRows (0 : Matrix m₁ n R) (0 : Matrix m₂ n R) = 0 : lemma fromColumns_zero : fromColumns (0 : Matrix m n₁ R) (0 : Matrix m n₂ R) = 0 := by ext _ (_ | _) <;> simp -/-- A row partitioned matrix multiplied by a column partioned matrix gives a 2 by 2 block matrix -/ +/-- A row partitioned matrix multiplied by a column partitioned matrix gives a 2 by 2 block +matrix. -/ lemma fromRows_mul_fromColumns [Fintype n] (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) (B₁ : Matrix n n₁ R) (B₂ : Matrix n n₂ R) : (fromRows A₁ A₂) * (fromColumns B₁ B₂) = fromBlocks (A₁ * B₁) (A₁ * B₂) (A₂ * B₁) (A₂ * B₂) := by ext (_ | _) (_ | _) <;> simp -/-- A column partitioned matrix mulitplied by a row partitioned matrix gives the sum of the "outer" -products of the block matrices -/ +/-- A column partitioned matrix multiplied by a row partitioned matrix gives the sum of the "outer" +products of the block matrices. -/ lemma fromColumns_mul_fromRows [Fintype n₁] [Fintype n₂] (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) (B₁ : Matrix n₁ n R) (B₂ : Matrix n₂ n R) : fromColumns A₁ A₂ * fromRows B₁ B₂ = (A₁ * B₁ + A₂ * B₂) := by ext simp [mul_apply] -/-- A column partitioned matrix multipiled by a block matrix results in a column partioned matrix -/ +/-- A column partitioned matrix multipiled by a block matrix results in a column partitioned +matrix. -/ lemma fromColumns_mul_fromBlocks [Fintype m₁] [Fintype m₂] (A₁ : Matrix m m₁ R) (A₂ : Matrix m m₂ R) (B₁₁ : Matrix m₁ n₁ R) (B₁₂ : Matrix m₁ n₂ R) (B₂₁ : Matrix m₂ n₁ R) (B₂₂ : Matrix m₂ n₂ R) : (fromColumns A₁ A₂) * fromBlocks B₁₁ B₁₂ B₂₁ B₂₂ = fromColumns (A₁ * B₁₁ + A₂ * B₂₁) (A₁ * B₁₂ + A₂ * B₂₂) := by ext _ (_ | _) <;> simp [mul_apply] -/-- A block matrix mulitplied by a row partitioned matrix gives a row partitioned matrix -/ +/-- A block matrix multiplied by a row partitioned matrix gives a row partitioned matrix. -/ lemma fromBlocks_mul_fromRows [Fintype n₁] [Fintype n₂] (A₁ : Matrix n₁ n R) (A₂ : Matrix n₂ n R) (B₁₁ : Matrix m₁ n₁ R) (B₁₂ : Matrix m₁ n₂ R) (B₂₁ : Matrix m₂ n₁ R) (B₂₂ : Matrix m₂ n₂ R) : fromBlocks B₁₁ B₁₂ B₂₁ B₂₂ * (fromRows A₁ A₂) = @@ -256,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. -/ @@ -282,14 +275,14 @@ end CommRing section Star variable [Star R] -/-- A column partioned matrix in a Star ring when conjugate transposed gives a row partitioned +/-- A column partitioned matrix in a Star ring when conjugate transposed gives a row partitioned matrix with the columns of the initial matrix conjugate transposed to become rows. -/ lemma conjTranspose_fromColumns_eq_fromRows_conjTranspose (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) : conjTranspose (fromColumns A₁ A₂) = fromRows (conjTranspose A₁) (conjTranspose A₂) := by ext (_ | _) _ <;> simp -/-- A row partioned matrix in a Star ring when conjugate transposed gives a column partitioned +/-- A row partitioned matrix in a Star ring when conjugate transposed gives a column partitioned matrix with the rows of the initial matrix conjugate transposed to become columns. -/ lemma conjTranspose_fromRows_eq_fromColumns_conjTranspose (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) : conjTranspose (fromRows A₁ A₂) = diff --git a/Mathlib/Data/Matrix/Composition.lean b/Mathlib/Data/Matrix/Composition.lean index ae65a787e8669..1970544baa99b 100644 --- a/Mathlib/Data/Matrix/Composition.lean +++ b/Mathlib/Data/Matrix/Composition.lean @@ -24,7 +24,7 @@ Semiring, and Algebra over a CommSemiring K. namespace Matrix -variable (I J K L R : Type*) +variable (I J K L R : Type*) /-- I by J matrix where each entry is a K by L matrix is equivalent to I × K by J × L matrix -/ @@ -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..2b482b6e0ee61 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 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/Invertible.lean b/Mathlib/Data/Matrix/Invertible.lean index c0923041fcdb8..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 @@ -31,22 +32,31 @@ namespace Matrix section Semiring variable [Semiring α] -/-- A copy of `invOf_mul_self_assoc` for rectangular matrices. -/ -protected theorem invOf_mul_self_assoc (A : Matrix n n α) (B : Matrix n m α) [Invertible A] : +/-- A copy of `invOf_mul_cancel_left` for rectangular matrices. -/ +protected theorem invOf_mul_cancel_left (A : Matrix n n α) (B : Matrix n m α) [Invertible A] : ⅟ A * (A * B) = B := by rw [← Matrix.mul_assoc, invOf_mul_self, Matrix.one_mul] -/-- A copy of `mul_invOf_self_assoc` for rectangular matrices. -/ -protected theorem mul_invOf_self_assoc (A : Matrix n n α) (B : Matrix n m α) [Invertible A] : +/-- A copy of `mul_invOf_cancel_left` for rectangular matrices. -/ +protected theorem mul_invOf_cancel_left (A : Matrix n n α) (B : Matrix n m α) [Invertible A] : A * (⅟ A * B) = B := by rw [← Matrix.mul_assoc, mul_invOf_self, Matrix.one_mul] -/-- A copy of `mul_invOf_mul_self_cancel` for rectangular matrices. -/ -protected theorem mul_invOf_mul_self_cancel (A : Matrix m n α) (B : Matrix n n α) [Invertible B] : +/-- A copy of `invOf_mul_cancel_right` for rectangular matrices. -/ +protected theorem invOf_mul_cancel_right (A : Matrix m n α) (B : Matrix n n α) [Invertible B] : A * ⅟ B * B = A := by rw [Matrix.mul_assoc, invOf_mul_self, Matrix.mul_one] -/-- A copy of `mul_mul_invOf_self_cancel` for rectangular matrices. -/ -protected theorem mul_mul_invOf_self_cancel (A : Matrix m n α) (B : Matrix n n α) [Invertible B] : +/-- A copy of `mul_invOf_cancel_right` for rectangular matrices. -/ +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")] +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 α) @@ -101,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 f2afadf172ca1..61bfd0d4ab97b 100644 --- a/Mathlib/Data/Matrix/Kronecker.lean +++ b/Mathlib/Data/Matrix/Kronecker.lean @@ -217,8 +217,8 @@ theorem det_kroneckerMapBilinear [CommSemiring R] [Fintype m] [Fintype n] [Decid det (kroneckerMapBilinear f A B) = det (kroneckerMapBilinear f A 1 * kroneckerMapBilinear f 1 B) := by rw [← kroneckerMapBilinear_mul_mul f h_comm, Matrix.mul_one, Matrix.one_mul] - _ = det (blockDiagonal fun _ => A.map fun a => f a 1) * - det (blockDiagonal fun _ => B.map fun b => f 1 b) := by + _ = det (blockDiagonal fun (_ : n) => A.map fun a => f a 1) * + det (blockDiagonal fun (_ : m) => B.map fun b => f 1 b) := by rw [det_mul, ← diagonal_one, ← diagonal_one, kroneckerMapBilinear_apply_apply, kroneckerMap_diagonal_right _ fun _ => _, kroneckerMapBilinear_apply_apply, kroneckerMap_diagonal_left _ fun _ => _, det_reindex_self] diff --git a/Mathlib/Data/Matrix/Notation.lean b/Mathlib/Data/Matrix/Notation.lean index cabbdb210c83a..34515d69bf4ca 100644 --- a/Mathlib/Data/Matrix/Notation.lean +++ b/Mathlib/Data/Matrix/Notation.lean @@ -46,8 +46,8 @@ variable {α : Type u} {o n m : ℕ} {m' : Type uₘ} {n' : Type uₙ} {o' : Typ open Matrix section toExpr -open Lean -open Qq + +open Lean Qq /-- Matrices can be reflected whenever their entries can. We insert a `Matrix.of` to prevent immediate decay to a function. -/ 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/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 22af93d6f230f..5f098b5a7e053 100644 --- a/Mathlib/Data/Matroid/Basic.lean +++ b/Mathlib/Data/Matroid/Basic.lean @@ -169,7 +169,7 @@ def Matroid.ExchangeProperty {α : Type _} (P : Set α → Prop) : Prop := ∀ X Y, P X → P Y → ∀ a ∈ X \ Y, ∃ b ∈ Y \ X, P (insert b (X \ {a})) /-- A set `X` has the maximal subset property for a predicate `P` if every subset of `X` satisfying - `P` is contained in a maximal subset of `X` satisfying `P`. -/ + `P` is contained in a maximal subset of `X` satisfying `P`. -/ def Matroid.ExistsMaximalSubsetProperty {α : Type _} (P : Set α → Prop) (X : Set α) : Prop := ∀ I, P I → I ⊆ X → ∃ J, I ⊆ J ∧ Maximal (fun K ↦ P K ∧ K ⊆ X) J @@ -186,7 +186,7 @@ def Matroid.ExistsMaximalSubsetProperty {α : Type _} (P : Set α → Prop) (X : @[ext] structure Matroid (α : Type _) where /-- `M` has a ground set `E`. -/ (E : Set α) - /-- `M` has a predicate `Base` definining its bases. -/ + /-- `M` has a predicate `Base` defining its bases. -/ (Base : Set α → Prop) /-- `M` has a predicate `Indep` defining its independent sets. -/ (Indep : Set α → Prop) @@ -713,7 +713,7 @@ def Basis (M : Matroid α) (I X : Set α) : Prop := Maximal (fun A ↦ M.Indep A ∧ A ⊆ X) I ∧ X ⊆ M.E /-- A `Basis'` is a basis without the requirement that `X ⊆ M.E`. This is convenient for some - API building, especially when working with rank and closure. -/ + API building, especially when working with rank and closure. -/ def Basis' (M : Matroid α) (I X : Set α) : Prop := Maximal (fun A ↦ M.Indep A ∧ A ⊆ X) I diff --git a/Mathlib/Data/Matroid/Closure.lean b/Mathlib/Data/Matroid/Closure.lean index 555e6ec09d4dd..10fddef9acbd1 100644 --- a/Mathlib/Data/Matroid/Closure.lean +++ b/Mathlib/Data/Matroid/Closure.lean @@ -50,7 +50,7 @@ Its disadvantage is that the statement `X ⊆ M.closure X` is only true provided Choice (2) has the reverse property: we would have `X ⊆ M.closure X` for all `X`, but the condition `M.closure X ⊆ M.E` requires `X ⊆ M.E` to hold. -It has a couple of other advantages too: is is actually the closure function of a matroid on `α` +It has a couple of other advantages too: it is actually the closure function of a matroid on `α` with ground set `univ` (specifically, the direct sum of `M` and a free matroid on `M.Eᶜ`), and because of this, it is an example of a `ClosureOperator` on `α`, which in turn gives access to nice existing API for both `ClosureOperator` and `GaloisInsertion`. diff --git a/Mathlib/Data/Matroid/Init.lean b/Mathlib/Data/Matroid/Init.lean index d888905b6f315..0ba1866f02d1e 100644 --- a/Mathlib/Data/Matroid/Init.lean +++ b/Mathlib/Data/Matroid/Init.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Peter Nelson. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Peter Nelson -/ +import Mathlib.Init import Aesop /-! diff --git a/Mathlib/Data/Matroid/Map.lean b/Mathlib/Data/Matroid/Map.lean index b231376efdada..bf22fe80c5b92 100644 --- a/Mathlib/Data/Matroid/Map.lean +++ b/Mathlib/Data/Matroid/Map.lean @@ -501,7 +501,7 @@ end map section mapSetEquiv /-- Map `M : Matroid α` to a `Matroid β` with ground set `E` using an equivalence `M.E ≃ E`. -Defined using `Matroid.ofExistsMatroid` for better defeq. -/ +Defined using `Matroid.ofExistsMatroid` for better defeq. -/ def mapSetEquiv (M : Matroid α) {E : Set β} (e : M.E ≃ E) : Matroid β := Matroid.ofExistsMatroid E (fun I ↦ (M.Indep ↑(e.symm '' (E ↓∩ I)) ∧ I ⊆ E)) ⟨M.mapSetEmbedding (e.toEmbedding.trans <| Function.Embedding.subtype _), by diff --git a/Mathlib/Data/Matroid/Restrict.lean b/Mathlib/Data/Matroid/Restrict.lean index 46d88f70b7cf7..013d3c6c68740 100644 --- a/Mathlib/Data/Matroid/Restrict.lean +++ b/Mathlib/Data/Matroid/Restrict.lean @@ -36,7 +36,7 @@ It also proves some `Basis` analogues of `Base` lemmas that, while they could be ## Implementation Notes Since `R` and `M.E` are both terms in `Set α`, to define the restriction `M ↾ R`, -we need to either insist that `R ⊆ M.E`, or to say what happens when `R` contains the junk +we need to either insist that `R ⊆ M.E`, or to say what happens when `R` contains the junk outside `M.E`. It turns out that `R ⊆ M.E` is just an unnecessary hypothesis; if we say the restriction @@ -115,7 +115,7 @@ section restrict /-- 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`, - but it is convenient not to require this. The elements of `R \ M.E` become 'loops'. -/ + but it is convenient not to require this. The elements of `R \ M.E` become 'loops'. -/ def restrict (M : Matroid α) (R : Set α) : Matroid α := (M.restrictIndepMatroid R).matroid /-- `M ↾ R` means `M.restrict R`. -/ diff --git a/Mathlib/Data/Multiset/Antidiagonal.lean b/Mathlib/Data/Multiset/Antidiagonal.lean index f74172f629ecb..df02ceb0f2f41 100644 --- a/Mathlib/Data/Multiset/Antidiagonal.lean +++ b/Mathlib/Data/Multiset/Antidiagonal.lean @@ -12,6 +12,7 @@ The antidiagonal of a multiset `s` consists of all pairs `(t₁, t₂)` such that `t₁ + t₂ = s`. These pairs are counted with multiplicities. -/ +assert_not_exists OrderedCommMonoid assert_not_exists Ring universe u @@ -80,7 +81,7 @@ theorem antidiagonal_cons (a : α) (s) : 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, zero_tsub, map_singleton] + · 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, id, sub_cons, erase_cons_head] rw [add_comm] diff --git a/Mathlib/Data/Multiset/Basic.lean b/Mathlib/Data/Multiset/Basic.lean index 523808b4def1c..0c4fb024e449e 100644 --- a/Mathlib/Data/Multiset/Basic.lean +++ b/Mathlib/Data/Multiset/Basic.lean @@ -4,10 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Mathlib.Algebra.Group.Nat -import Mathlib.Algebra.Order.Sub.Canonical +import Mathlib.Algebra.Order.Sub.Unbundled.Basic import Mathlib.Data.List.Perm import Mathlib.Data.Set.List -import Mathlib.Init.Quot import Mathlib.Order.Hom.Basic /-! @@ -17,6 +16,9 @@ These are implemented as the quotient of a list by permutations. We define the global infix notation `::ₘ` for `Multiset.cons`. -/ +-- No bundled ordered algebra should be required +assert_not_exists OrderedCommMonoid + universe v open List Subtype Nat Function @@ -24,7 +26,7 @@ open List Subtype Nat Function variable {α : Type*} {β : Type v} {γ : Type*} /-- `Multiset α` is the quotient of `List α` by list permutation. The result - is a type of finite sets with duplicates allowed. -/ + is a type of finite sets with duplicates allowed. -/ def Multiset.{u} (α : Type u) : Type u := Quotient (List.isSetoid α) @@ -110,7 +112,7 @@ theorem coe_eq_zero (l : List α) : (l : Multiset α) = 0 ↔ l = [] := Iff.trans coe_eq_coe perm_nil theorem coe_eq_zero_iff_isEmpty (l : List α) : (l : Multiset α) = 0 ↔ l.isEmpty := - Iff.trans (coe_eq_zero l) isEmpty_iff_eq_nil.symm + Iff.trans (coe_eq_zero l) isEmpty_iff.symm /-! ### `Multiset.cons` -/ @@ -146,7 +148,7 @@ theorem cons_inj_right (a : α) : ∀ {s t : Multiset α}, a ::ₘ s = a ::ₘ t @[elab_as_elim] protected theorem induction {p : Multiset α → Prop} (empty : p 0) (cons : ∀ (a : α) (s : Multiset α), p s → p (a ::ₘ s)) : ∀ s, p s := by - rintro ⟨l⟩; induction' l with _ _ ih <;> [exact empty; exact cons _ _ ih] + rintro ⟨l⟩; induction l with | nil => exact empty | cons _ _ ih => exact cons _ _ ih @[elab_as_elim] protected theorem induction_on {p : Multiset α → Prop} (s : Multiset α) (empty : p 0) @@ -201,7 +203,7 @@ end Rec section Mem /-- `a ∈ s` means that `a` has nonzero multiplicity in `s`. -/ -def Mem (a : α) (s : Multiset α) : Prop := +def Mem (s : Multiset α) (a : α) : Prop := Quot.liftOn s (fun l => a ∈ l) fun l₁ l₂ (e : l₁ ~ l₂) => propext <| e.mem_iff instance : Membership α (Multiset α) := @@ -212,7 +214,7 @@ theorem mem_coe {a : α} {l : List α} : a ∈ (l : Multiset α) ↔ a ∈ l := Iff.rfl instance decidableMem [DecidableEq α] (a : α) (s : Multiset α) : Decidable (a ∈ s) := - Quot.recOnSubsingleton' s fun l ↦ inferInstanceAs (Decidable (a ∈ l)) + Quot.recOnSubsingleton s fun l ↦ inferInstanceAs (Decidable (a ∈ l)) @[simp] theorem mem_cons {a b : α} {s : Multiset α} : a ∈ b ::ₘ s ↔ a = b ∨ a ∈ s := @@ -304,7 +306,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] @@ -526,6 +528,11 @@ 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 _ _) @@ -585,22 +592,24 @@ instance : CovariantClass (Multiset α) (Multiset α) (· + ·) (· ≤ ·) := instance : ContravariantClass (Multiset α) (Multiset α) (· + ·) (· ≤ ·) := ⟨fun _s _t _u => add_le_add_iff_left'.1⟩ -instance : OrderedCancelAddCommMonoid (Multiset α) where - zero := 0 - add := (· + ·) +instance instAddCommMonoid : AddCancelCommMonoid (Multiset α) where add_comm := fun s t => Quotient.inductionOn₂ s t fun l₁ l₂ => 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 add_zero := fun s => Quotient.inductionOn s fun l => congr_arg _ <| append_nil l - add_le_add_left := fun s₁ s₂ => add_le_add_left - le_of_add_le_add_left := fun s₁ s₂ s₃ => le_of_add_le_add_left + 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) nsmul := nsmulRec theorem le_add_right (s t : Multiset α) : s ≤ s + t := by simpa using add_le_add_left (zero_le t) s 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 => @@ -608,13 +617,6 @@ theorem le_iff_exists_add {s t : Multiset α} : s ≤ t ↔ ∃ u, t = s + u := ⟨l, Quot.sound p⟩, fun ⟨_u, e⟩ => e.symm ▸ le_add_right _ _⟩ -instance : CanonicallyOrderedAddCommMonoid (Multiset α) where - __ := inferInstanceAs (OrderBot (Multiset α)) - le_self_add := le_add_right - exists_add_of_le h := leInductionOn h fun s => - let ⟨l, p⟩ := s.exists_perm_append - ⟨l, Quot.sound p⟩ - @[simp] theorem cons_add (a : α) (s t : Multiset α) : a ::ₘ s + t = a ::ₘ (s + t) := by rw [← singleton_add, ← singleton_add, add_assoc] @@ -968,6 +970,8 @@ 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⟩ + theorem erase_le_erase {s t : Multiset α} (a : α) (h : s ≤ t) : s.erase a ≤ t.erase a := leInductionOn h fun h => (h.erase _).subperm @@ -1196,92 +1200,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 -/ @@ -1289,7 +1305,7 @@ theorem foldl_induction (f : α → α → α) (H : RightCommutative f) (x : α) /-- Lift of the list `pmap` operation. Map a partial function `f` over a multiset `s` whose elements are all in the domain of `f`. -/ nonrec def pmap {p : α → Prop} (f : ∀ a, p a → β) (s : Multiset α) : (∀ a ∈ s, p a) → Multiset β := - Quot.recOn' s (fun l H => ↑(pmap f l H)) fun l₁ l₂ (pp : l₁ ~ l₂) => + Quot.recOn s (fun l H => ↑(pmap f l H)) fun l₁ l₂ (pp : l₁ ~ l₂) => funext fun H₂ : ∀ a ∈ l₂, p a => have H₁ : ∀ a ∈ l₁, p a := fun a h => H₂ a (pp.subset h) have : ∀ {s₂ e H}, @Eq.ndrec (Multiset α) l₁ (fun s => (∀ a ∈ s, p a) → Multiset β) @@ -1334,8 +1350,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 := @@ -1380,7 +1395,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 @@ -1446,6 +1461,9 @@ protected theorem sub_zero (s : Multiset α) : s - 0 = s := theorem sub_cons (a : α) (s t : Multiset α) : s - a ::ₘ t = s.erase a - t := Quotient.inductionOn₂ s t fun _l₁ _l₂ => congr_arg _ <| diff_cons _ _ _ +protected theorem zero_sub (t : Multiset α) : 0 - t = 0 := + Multiset.induction_on t rfl fun a s ih => by simp [ih] + /-- This is a special case of `tsub_le_iff_right`, which should be used instead of this. This is needed to prove `OrderedSub (Multiset α)`. -/ protected theorem sub_le_iff_le_add : s - t ≤ u ↔ s ≤ u + t := by @@ -1453,22 +1471,31 @@ protected theorem sub_le_iff_le_add : s - t ≤ u ↔ s ≤ u + t := by exact @(Multiset.induction_on t (by simp [Multiset.sub_zero]) fun a t IH s => by simp [IH, erase_le_iff_le_cons]) +protected theorem sub_le_self (s t : Multiset α) : s - t ≤ s := by + rw [Multiset.sub_le_iff_le_add] + exact le_add_right _ _ + instance : OrderedSub (Multiset α) := ⟨fun _n _m _k => Multiset.sub_le_iff_le_add⟩ +instance : ExistsAddOfLE (Multiset α) where + exists_add_of_le h := leInductionOn h fun s => + let ⟨l, p⟩ := s.exists_perm_append + ⟨l, Quot.sound p⟩ + 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 @[simp] theorem card_sub {s t : Multiset α} (h : t ≤ s) : card (s - t) = card s - card t := - Nat.eq_sub_of_add_eq $ by rw [← card_add, tsub_add_cancel_of_le h] + Nat.eq_sub_of_add_eq <| by rw [← card_add, tsub_add_cancel_of_le h] /-! ### Union -/ @@ -1500,9 +1527,10 @@ theorem union_le_union_right (h : s ≤ t) (u) : s ∪ u ≤ t ∪ u := theorem union_le (h₁ : s ≤ u) (h₂ : t ≤ u) : s ∪ t ≤ u := by rw [← eq_union_left h₂]; exact union_le_union_right h₁ t + @[simp] theorem mem_union : a ∈ s ∪ t ↔ a ∈ s ∨ a ∈ t := - ⟨fun h => (mem_add.1 h).imp_left (mem_of_le tsub_le_self), + ⟨fun h => (mem_add.1 h).imp_left (mem_of_le <| Multiset.sub_le_self _ _), (Or.elim · (mem_of_le <| le_union_left _ _) (mem_of_le <| le_union_right _ _))⟩ @[simp] @@ -1512,7 +1540,7 @@ theorem map_union [DecidableEq β] {f : α → β} (finj : Function.Injective f) congr_arg ofList (by rw [List.map_append f, List.map_diff finj]) @[simp] theorem zero_union : 0 ∪ s = s := by - simp [union_def] + simp [union_def, Multiset.zero_sub] @[simp] theorem union_zero : s ∪ 0 = s := by simp [union_def] @@ -1554,7 +1582,7 @@ theorem inter_le_right (s : Multiset α) : ∀ t, s ∩ t ≤ t := theorem le_inter (h₁ : s ≤ t) (h₂ : s ≤ u) : s ≤ t ∩ u := by revert s u; refine @(Multiset.induction_on t ?_ fun a t IH => ?_) <;> intros s u h₁ h₂ - · simpa only [zero_inter, nonpos_iff_eq_zero] using h₁ + · simpa only [zero_inter] using h₁ by_cases h : a ∈ u · rw [cons_inter_of_pos _ h, ← erase_le_iff_le_cons] exact IH (erase_le_iff_le_cons.2 h₁) (erase_le_erase _ h₂) @@ -1733,13 +1761,12 @@ theorem mem_filter_of_mem {a : α} {l} (m : a ∈ l) (h : p a) : a ∈ filter p theorem filter_eq_self {s} : filter p s = s ↔ ∀ a ∈ s, p a := Quot.inductionOn s fun _l => - Iff.trans ⟨fun h => (filter_sublist _).eq_of_length (@congr_arg _ _ _ _ card h), + Iff.trans ⟨fun h => (filter_sublist _).eq_of_length (congr_arg card h), congr_arg ofList⟩ <| by simp theorem filter_eq_nil {s} : filter p s = 0 ↔ ∀ a ∈ s, ¬p a := Quot.inductionOn s fun _l => - Iff.trans ⟨fun h => eq_nil_of_length_eq_zero (@congr_arg _ _ _ _ card h), congr_arg ofList⟩ <| - by simpa using List.filter_eq_nil (p := (p ·)) + Iff.trans ⟨fun h => eq_nil_of_length_eq_zero (congr_arg card h), congr_arg ofList⟩ (by simp) theorem le_filter {s t} : s ≤ filter p t ↔ s ≤ t ∧ ∀ a ∈ s, p a := ⟨fun h => ⟨le_trans h (filter_le _ _), fun _a m => of_mem_filter (mem_of_le h m)⟩, fun ⟨h, al⟩ => @@ -1828,7 +1855,7 @@ theorem filter_map (f : β → α) (s : Multiset β) : filter p (map f s) = map lemma map_filter' {f : α → β} (hf : Injective f) (s : Multiset α) [DecidablePred fun b => ∃ a, p a ∧ f a = b] : (s.filter p).map f = (s.map f).filter fun b => ∃ a, p a ∧ f a = b := by - simp [(· ∘ ·), filter_map, hf.eq_iff] + simp [comp_def, filter_map, hf.eq_iff] lemma card_filter_le_iff (s : Multiset α) (P : α → Prop) [DecidablePred P] (n : ℕ) : card (s.filter P) ≤ n ↔ ∀ s' ≤ s, n < card s' → ∃ a ∈ s', ¬ P a := by @@ -1994,11 +2021,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 @@ -2027,7 +2054,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] @@ -2140,8 +2167,8 @@ theorem count_replicate_self (a : α) (n : ℕ) : count a (replicate n a) = n := theorem count_replicate (a b : α) (n : ℕ) : count a (replicate n b) = if b = a then n else 0 := by convert List.count_replicate a b n - rw [← coe_count, coe_replicate] - simp + · rw [← coe_count, coe_replicate] + · simp @[simp] theorem count_erase_self (a : α) (s : Multiset α) : count a (erase s a) = count a s - 1 := @@ -2206,7 +2233,7 @@ theorem ext' {s t : Multiset α} : (∀ a, count a s = count a t) → s = t := ext.2 lemma count_injective : Injective fun (s : Multiset α) a ↦ s.count a := - fun _s _t hst ↦ ext' $ congr_fun hst + fun _s _t hst ↦ ext' <| congr_fun hst @[simp] theorem coe_inter (s t : List α) : (s ∩ t : Multiset α) = (s.bagInter t : List α) := by ext; simp @@ -2327,6 +2354,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 -/ @@ -2711,13 +2756,12 @@ end Choose variable (α) -set_option linter.deprecated false in /-- The equivalence between lists and multisets of a subsingleton type. -/ def subsingletonEquiv [Subsingleton α] : List α ≃ Multiset α where toFun := ofList invFun := (Quot.lift id) fun (a b : List α) (h : a ~ b) => - (List.ext_nthLe h.length_eq) fun _ _ _ => Subsingleton.elim _ _ + (List.ext_get h.length_eq) fun _ _ _ => Subsingleton.elim _ _ left_inv _ := rfl right_inv m := Quot.inductionOn m fun _ => rfl @@ -2728,7 +2772,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 5dbf593b2a902..3fe645c8e220e 100644 --- a/Mathlib/Data/Multiset/Bind.lean +++ b/Mathlib/Data/Multiset/Bind.lean @@ -191,7 +191,7 @@ theorem le_bind {α β : Type*} {f : α → Multiset β} (S : Multiset α) {x : f x ≤ S.bind f := by classical refine le_iff_count.2 fun a ↦ ?_ - obtain ⟨m', hm'⟩ := exists_cons_of_mem $ mem_map_of_mem (fun b ↦ count a (f b)) hx + obtain ⟨m', hm'⟩ := exists_cons_of_mem <| mem_map_of_mem (fun b ↦ count a (f b)) hx rw [count_bind, hm', sum_cons] exact Nat.le_add_right _ _ diff --git a/Mathlib/Data/Multiset/Fintype.lean b/Mathlib/Data/Multiset/Fintype.lean index 9f48dea81db32..369c39be15028 100644 --- a/Mathlib/Data/Multiset/Fintype.lean +++ b/Mathlib/Data/Multiset/Fintype.lean @@ -130,7 +130,7 @@ namespace Multiset have : card (s.1.filter fun x ↦ a = x.1) ≤ card (s.1.filter fun x ↦ a = x.1) - 1 := by simpa [Finset.card, eq_comm] using Finset.card_mono h omega - exact Nat.le_of_pred_lt (han.trans_lt $ by simpa using hsm hn) + exact Nat.le_of_pred_lt (han.trans_lt <| by simpa using hsm hn) end Multiset @@ -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 05b29adb37aa7..81575f5f445c4 100644 --- a/Mathlib/Data/Multiset/Functor.lean +++ b/Mathlib/Data/Multiset/Functor.lean @@ -55,7 +55,7 @@ def traverse : Multiset α' → F (Multiset β') := by congr funext a b l simpa [flip] using Perm.swap a b l - simp [(· ∘ ·), this, functor_norm, Coe.coe] + simp [Function.comp_def, this, functor_norm, Coe.coe] | trans => simp [*] instance : Monad Multiset := @@ -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, 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/Lattice.lean b/Mathlib/Data/Multiset/Lattice.lean index ebc72e3ce307b..194cae4b5a776 100644 --- a/Mathlib/Data/Multiset/Lattice.lean +++ b/Mathlib/Data/Multiset/Lattice.lean @@ -79,9 +79,9 @@ theorem nodup_sup_iff {α : Type*} [DecidableEq α] {m : Multiset (Multiset α)} m.sup.Nodup ↔ ∀ a : Multiset α, a ∈ m → a.Nodup := by -- Porting note: this was originally `apply m.induction_on`, which failed due to -- `failed to elaborate eliminator, expected type is not available` - induction' m using Multiset.induction_on with _ _ h - · simp - · simp [h] + induction m using Multiset.induction_on with + | empty => simp + | cons _ _ h => simp [h] end Sup diff --git a/Mathlib/Data/Multiset/Nodup.lean b/Mathlib/Data/Multiset/Nodup.lean index 7e24031fb1f8c..2ea7505ae7caa 100644 --- a/Mathlib/Data/Multiset/Nodup.lean +++ b/Mathlib/Data/Multiset/Nodup.lean @@ -192,7 +192,7 @@ theorem range_le {m n : ℕ} : range m ≤ range n ↔ m ≤ n := theorem mem_sub_of_nodup [DecidableEq α] {a : α} {s t : Multiset α} (d : Nodup s) : a ∈ s - t ↔ a ∈ s ∧ a ∉ t := ⟨fun h => - ⟨mem_of_le tsub_le_self h, fun h' => by + ⟨mem_of_le (Multiset.sub_le_self ..) h, fun h' => by refine count_eq_zero.1 ?_ h rw [count_sub a s t, Nat.sub_eq_zero_iff_le] exact le_trans (nodup_iff_count_le_one.1 d _) (count_pos.2 h')⟩, diff --git a/Mathlib/Data/Multiset/OrderedMonoid.lean b/Mathlib/Data/Multiset/OrderedMonoid.lean new file mode 100644 index 0000000000000..bf40bc0b213eb --- /dev/null +++ b/Mathlib/Data/Multiset/OrderedMonoid.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: Mario Carneiro +-/ +import Mathlib.Data.Multiset.Basic +import Mathlib.Algebra.Order.Monoid.Canonical.Defs + +/-! +# Multisets as ordered monoids + +The `OrderedCancelAddCommMonoid` and `CanonicallyOrderedAddCommMonoid` instances on `Multiset α` + +-/ + +variable {α : Type*} + +namespace Multiset + +open List + +instance : OrderedCancelAddCommMonoid (Multiset α) where + add_le_add_left := fun _ _ => add_le_add_left + le_of_add_le_add_left := fun _ _ _ => le_of_add_le_add_left + +instance : CanonicallyOrderedAddCommMonoid (Multiset α) where + __ := inferInstanceAs (OrderBot (Multiset α)) + le_self_add := le_add_right + exists_add_of_le h := exists_add_of_le h + +end Multiset diff --git a/Mathlib/Data/Multiset/Powerset.lean b/Mathlib/Data/Multiset/Powerset.lean index e344eddc1b02f..924f768a2ffbb 100644 --- a/Mathlib/Data/Multiset/Powerset.lean +++ b/Mathlib/Data/Multiset/Powerset.lean @@ -50,16 +50,18 @@ theorem powersetAux'_cons (a : α) (l : List α) : simp [powersetAux'] theorem powerset_aux'_perm {l₁ l₂ : List α} (p : l₁ ~ l₂) : powersetAux' l₁ ~ powersetAux' l₂ := by - induction' p with a l₁ l₂ p IH a b l l₁ l₂ l₃ _ _ IH₁ IH₂ - · simp - · simp only [powersetAux'_cons] + induction p with + | nil => simp + | cons _ _ IH => + simp only [powersetAux'_cons] exact IH.append (IH.map _) - · simp only [powersetAux'_cons, map_append, List.map_map, append_assoc] + | swap a b => + simp only [powersetAux'_cons, map_append, List.map_map, append_assoc] apply Perm.append_left rw [← append_assoc, ← append_assoc, (by funext s; simp [cons_swap] : cons b ∘ cons a = cons a ∘ cons b)] exact perm_append_comm.append_right _ - · exact IH₁.trans IH₂ + | trans _ _ IH₁ IH₂ => exact IH₁.trans IH₂ theorem powersetAux_perm {l₁ l₂ : List α} (p : l₁ ~ l₂) : powersetAux l₁ ~ powersetAux l₂ := powersetAux_perm_powersetAux'.trans <| @@ -179,11 +181,13 @@ theorem powersetCardAux_perm {n} {l₁ l₂ : List α} (p : l₁ ~ l₂) : powersetCardAux n l₁ ~ powersetCardAux n l₂ := by induction' n with n IHn generalizing l₁ l₂ · simp - induction' p with a l₁ l₂ p IH a b l l₁ l₂ l₃ _ _ IH₁ IH₂ - · rfl - · simp only [powersetCardAux_cons] + induction p with + | nil => rfl + | cons _ p IH => + simp only [powersetCardAux_cons] exact IH.append ((IHn p).map _) - · simp only [powersetCardAux_cons, append_assoc] + | swap a b => + simp only [powersetCardAux_cons, append_assoc] apply Perm.append_left cases n · simp [Perm.swap] @@ -191,7 +195,7 @@ theorem powersetCardAux_perm {n} {l₁ l₂ : List α} (p : l₁ ~ l₂) : rw [← append_assoc, ← append_assoc, (by funext s; simp [cons_swap] : cons b ∘ cons a = cons a ∘ cons b)] exact perm_append_comm.append_right _ - · exact IH₁.trans IH₂ + | trans _ _ IH₁ IH₂ => exact IH₁.trans IH₂ /-- `powersetCard n s` is the multiset of all submultisets of `s` of length `n`. -/ def powersetCard (n : ℕ) (s : Multiset α) : Multiset (Multiset α) := @@ -219,7 +223,7 @@ theorem powersetCard_cons (n : ℕ) (a : α) (s) : theorem powersetCard_one (s : Multiset α) : powersetCard 1 s = s.map singleton := Quotient.inductionOn s fun l ↦ by - simp [powersetCard_coe, sublistsLen_one, map_reverse, Function.comp] + simp [powersetCard_coe, sublistsLen_one, map_reverse, Function.comp_def] @[simp] theorem mem_powersetCard {n : ℕ} {s t : Multiset α} : s ∈ powersetCard n t ↔ s ≤ t ∧ card s = n := diff --git a/Mathlib/Data/Multiset/Sections.lean b/Mathlib/Data/Multiset/Sections.lean index 8a09ff3a33675..4cc916de7c550 100644 --- a/Mathlib/Data/Multiset/Sections.lean +++ b/Mathlib/Data/Multiset/Sections.lean @@ -42,7 +42,7 @@ theorem coe_sections : | a :: l => by simp only [List.map_cons, List.sections] rw [← cons_coe, sections_cons, bind_map_comm, coe_sections l] - simp [List.sections, (· ∘ ·), List.bind] + simp [List.sections, Function.comp_def, List.bind] @[simp] theorem sections_add (s t : Multiset (Multiset α)) : diff --git a/Mathlib/Data/Multiset/Sort.lean b/Mathlib/Data/Multiset/Sort.lean index c3a6dabdb273b..997af93b548c0 100644 --- a/Mathlib/Data/Multiset/Sort.lean +++ b/Mathlib/Data/Multiset/Sort.lean @@ -15,45 +15,57 @@ namespace Multiset open List -variable {α : Type*} +variable {α β : Type*} section sort variable (r : α → α → Prop) [DecidableRel r] [IsTrans α r] [IsAntisymm α r] [IsTotal α r] +variable (r' : β → β → Prop) [DecidableRel r'] [IsTrans β r'] [IsAntisymm β r'] [IsTotal β r'] /-- `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 ((perm_mergeSort' _ _).trans <| h.trans (perm_mergeSort' _ _).symm) + (sorted_mergeSort' r _) (sorted_mergeSort' r _) @[simp] -theorem coe_sort (l : List α) : sort r l = mergeSort r l := +theorem coe_sort (l : List α) : sort r l = mergeSort' r l := 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 => sorted_mergeSort' r _ @[simp] theorem sort_eq (s : Multiset α) : ↑(sort r s) = s := - Quot.inductionOn s fun _ => Quot.sound <| perm_mergeSort _ _ + Quot.inductionOn s fun _ => Quot.sound <| perm_mergeSort' _ _ @[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 r @[simp] theorem sort_singleton (a : α) : sort r {a} = [a] := - List.mergeSort_singleton r a + List.mergeSort'_singleton r 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' _ _ _ _ + +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 end sort diff --git a/Mathlib/Data/NNRat/Defs.lean b/Mathlib/Data/NNRat/Defs.lean index db2875604c859..e41ecbe750139 100644 --- a/Mathlib/Data/NNRat/Defs.lean +++ b/Mathlib/Data/NNRat/Defs.lean @@ -3,9 +3,10 @@ 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.Nonneg.Ring -import Mathlib.Algebra.Order.Ring.Rat -import Mathlib.Data.Nat.Cast.Order.Ring +import Mathlib.Algebra.Order.Group.Unbundled.Int +import Mathlib.Algebra.Order.Ring.Unbundled.Nonneg +import Mathlib.Algebra.Order.Ring.Unbundled.Rat +import Mathlib.Algebra.Ring.Rat /-! # Nonnegative rationals @@ -30,16 +31,34 @@ Whenever you state a lemma about the coercion `ℚ≥0 → ℚ`, check that Lean `Subtype.val`. Else your lemma will never apply. -/ +assert_not_exists OrderedCommMonoid + +library_note "specialised high priority simp lemma" /-- +It sometimes happens that a `@[simp]` lemma declared early in the library can be proved by `simp` +using later, more general simp lemmas. In that case, the following reasons might be arguments for +the early lemma to be tagged `@[simp high]` (rather than `@[simp, nolint simpNF]` or +un``@[simp]``ed): +1. There is a significant portion of the library which needs the early lemma to be available via + `simp` and which doesn't have access to the more general lemmas. +2. The more general lemmas have more complicated typeclass assumptions, causing rewrites with them + to be slower. +-/ + open Function -deriving instance CanonicallyOrderedCommSemiring for NNRat -deriving instance CanonicallyLinearOrderedAddCommMonoid for NNRat +instance Rat.instZeroLEOneClass : ZeroLEOneClass ℚ where + zero_le_one := rfl + +instance Rat.instPosMulMono : PosMulMono ℚ where + elim := fun r p q h => by + simp only [mul_comm] + simpa [sub_mul, sub_nonneg] using Rat.mul_nonneg (sub_nonneg.2 h) r.2 + +deriving instance CommSemiring for NNRat +deriving instance LinearOrder for NNRat deriving instance Sub for NNRat deriving instance Inhabited for NNRat --- TODO: `deriving instance OrderedSub for NNRat` doesn't work yet, so we add the instance manually -instance NNRat.instOrderedSub : OrderedSub ℚ≥0 := Nonneg.orderedSub - namespace NNRat variable {α : Type*} {p q : ℚ≥0} @@ -56,7 +75,8 @@ theorem ext : (p : ℚ) = (q : ℚ) → p = q := protected theorem coe_injective : Injective ((↑) : ℚ≥0 → ℚ) := Subtype.coe_injective -@[simp, norm_cast] +-- See note [specialised high priority simp lemma] +@[simp high, norm_cast] theorem coe_inj : (p : ℚ) = q ↔ p = q := Subtype.coe_inj @@ -109,7 +129,8 @@ theorem coe_mul (p q : ℚ≥0) : ((p * q : ℚ≥0) : ℚ) = p * q := theorem coe_sub (h : q ≤ p) : ((p - q : ℚ≥0) : ℚ) = p - q := max_eq_left <| le_sub_comm.2 <| by rwa [sub_zero] -@[simp] +-- See note [specialised high priority simp lemma] +@[simp high] theorem coe_eq_zero : (q : ℚ) = 0 ↔ q = 0 := by norm_cast theorem coe_ne_zero : (q : ℚ) ≠ 0 ↔ q ≠ 0 := @@ -140,7 +161,7 @@ theorem toNNRat_coe (q : ℚ≥0) : toNNRat q = q := @[simp] theorem toNNRat_coe_nat (n : ℕ) : toNNRat n = n := - ext <| by simp only [Nat.cast_nonneg, Rat.coe_toNNRat]; rfl + ext <| by simp only [Nat.cast_nonneg', Rat.coe_toNNRat]; rfl /-- `toNNRat` and `(↑) : ℚ≥0 → ℚ` form a Galois insertion. -/ protected def gi : GaloisInsertion toNNRat (↑) := @@ -158,7 +179,7 @@ def coeHom : ℚ≥0 →+* ℚ where -- See note [no_index around OfNat.ofNat] @[simp] -theorem mk_natCast (n : ℕ) : @Eq ℚ≥0 (⟨(n : ℚ), n.cast_nonneg⟩ : ℚ≥0) n := +theorem mk_natCast (n : ℕ) : @Eq ℚ≥0 (⟨(n : ℚ), Nat.cast_nonneg' n⟩ : ℚ≥0) n := rfl @[deprecated (since := "2024-04-05")] alias mk_coe_nat := mk_natCast @@ -197,6 +218,11 @@ theorem sub_def (p q : ℚ≥0) : p - q = toNNRat (p - q) := theorem abs_coe (q : ℚ≥0) : |(q : ℚ)| = q := abs_of_nonneg q.2 +-- See note [specialised high priority simp lemma] +@[simp high] +theorem nonpos_iff_eq_zero (q : ℚ≥0) : q ≤ 0 ↔ q = 0 := + ⟨fun h => le_antisymm h q.2, fun h => h.symm ▸ q.2⟩ + end NNRat open NNRat @@ -283,14 +309,15 @@ namespace NNRat variable {p q : ℚ≥0} @[norm_cast] lemma num_coe (q : ℚ≥0) : (q : ℚ).num = q.num := by - simp [num, abs_of_nonneg, Rat.num_nonneg, q.2] + simp only [num, Int.natCast_natAbs, Rat.num_nonneg, coe_nonneg, abs_of_nonneg] theorem natAbs_num_coe : (q : ℚ).num.natAbs = q.num := rfl @[norm_cast] lemma den_coe : (q : ℚ).den = q.den := rfl @[simp] lemma num_ne_zero : q.num ≠ 0 ↔ q ≠ 0 := by simp [num] -@[simp] lemma num_pos : 0 < q.num ↔ 0 < q := by simp [pos_iff_ne_zero] +@[simp] lemma num_pos : 0 < q.num ↔ 0 < q := by + simpa [num, -nonpos_iff_eq_zero] using nonpos_iff_eq_zero _ |>.not.symm @[simp] lemma den_pos (q : ℚ≥0) : 0 < q.den := Rat.den_pos _ @[simp] lemma den_ne_zero (q : ℚ≥0) : q.den ≠ 0 := Rat.den_ne_zero _ @@ -315,14 +342,15 @@ theorem ext_num_den_iff : p = q ↔ p.num = q.num ∧ p.den = q.den := /-- Form the quotient `n / d` where `n d : ℕ`. See also `Rat.divInt` and `mkRat`. -/ -def divNat (n d : ℕ) : ℚ≥0 := ⟨.divInt n d, Rat.divInt_nonneg n.cast_nonneg d.cast_nonneg⟩ +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 : ℕ} @[simp, norm_cast] lemma coe_divNat (n d : ℕ) : (divNat n d : ℚ) = .divInt n d := rfl lemma mk_divInt (n d : ℕ) : - ⟨.divInt n d, Rat.divInt_nonneg n.cast_nonneg d.cast_nonneg⟩ = divNat n d := rfl + ⟨.divInt n d, Rat.divInt_nonneg (Int.ofNat_zero_le n) (Int.ofNat_zero_le d)⟩ = divNat n d := rfl lemma divNat_inj (h₁ : d₁ ≠ 0) (h₂ : d₂ ≠ 0) : divNat n₁ d₁ = divNat n₂ d₂ ↔ n₁ * d₂ = n₂ * d₁ := by rw [← coe_inj]; simp [Rat.mkRat_eq_iff, h₁, h₂]; norm_cast @@ -330,7 +358,7 @@ lemma divNat_inj (h₁ : d₁ ≠ 0) (h₂ : d₂ ≠ 0) : divNat n₁ d₁ = di @[simp] lemma divNat_zero (n : ℕ) : divNat n 0 = 0 := by simp [divNat]; rfl @[simp] lemma num_divNat_den (q : ℚ≥0) : divNat q.num q.den = q := - ext $ by rw [← (q : ℚ).mkRat_num_den']; simp [num_coe, den_coe] + ext <| by rw [← (q : ℚ).mkRat_num_den']; simp [num_coe, den_coe] lemma natCast_eq_divNat (n : ℕ) : (n : ℚ≥0) = divNat n 1 := (num_divNat_den _).symm diff --git a/Mathlib/Data/NNRat/Lemmas.lean b/Mathlib/Data/NNRat/Lemmas.lean index fcd82064c57c7..4e1ee467939eb 100644 --- a/Mathlib/Data/NNRat/Lemmas.lean +++ b/Mathlib/Data/NNRat/Lemmas.lean @@ -43,7 +43,7 @@ variable {p q : ℚ} lemma toNNRat_inv (q : ℚ) : toNNRat q⁻¹ = (toNNRat q)⁻¹ := by obtain hq | hq := le_total q 0 - · rw [toNNRat_eq_zero.mpr hq, inv_zero, toNNRat_eq_zero.mpr (inv_nonpos (α := ℚ) |>.mpr hq)] + · rw [toNNRat_eq_zero.mpr hq, inv_zero, toNNRat_eq_zero.mpr (inv_nonpos.mpr hq)] · nth_rw 1 [← Rat.coe_toNNRat q hq] rw [← coe_inv, toNNRat_coe] @@ -51,7 +51,7 @@ lemma toNNRat_div (hp : 0 ≤ p) : toNNRat (p / q) = toNNRat p / toNNRat q := by rw [div_eq_mul_inv, div_eq_mul_inv, ← toNNRat_inv, ← toNNRat_mul hp] lemma toNNRat_div' (hq : 0 ≤ q) : toNNRat (p / q) = toNNRat p / toNNRat q := by - rw [div_eq_inv_mul, div_eq_inv_mul, toNNRat_mul (inv_nonneg (α := ℚ) |>.2 hq), toNNRat_inv] + rw [div_eq_inv_mul, div_eq_inv_mul, toNNRat_mul (inv_nonneg.2 hq), toNNRat_inv] end Rat diff --git a/Mathlib/Data/NNRat/Order.lean b/Mathlib/Data/NNRat/Order.lean new file mode 100644 index 0000000000000..4b09aedfa4560 --- /dev/null +++ b/Mathlib/Data/NNRat/Order.lean @@ -0,0 +1,19 @@ +/- +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.Data.NNRat.Defs +import Mathlib.Algebra.Order.Ring.Rat +import Mathlib.Algebra.Order.Nonneg.Ring + +/-! +# Bundled ordered algebra structures on `ℚ≥0` + +-/ + +deriving instance CanonicallyOrderedCommSemiring for NNRat +deriving instance CanonicallyLinearOrderedAddCommMonoid for NNRat + +-- TODO: `deriving instance OrderedSub for NNRat` doesn't work yet, so we add the instance manually +instance NNRat.instOrderedSub : OrderedSub ℚ≥0 := Nonneg.orderedSub diff --git a/Mathlib/Data/NNReal/Basic.lean b/Mathlib/Data/NNReal/Basic.lean index 86a021f070b0d..bf80f11181f55 100644 --- a/Mathlib/Data/NNReal/Basic.lean +++ b/Mathlib/Data/NNReal/Basic.lean @@ -3,16 +3,13 @@ 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.Algebra.Ring.Regular import Mathlib.Data.Real.Pointwise import Mathlib.Order.ConditionallyCompleteLattice.Group -import Mathlib.Tactic.Bound.Attribute -import Mathlib.Tactic.GCongr.Core -import Mathlib.Algebra.Ring.Regular /-! # Nonnegative real numbers @@ -55,6 +52,7 @@ This file defines `ℝ≥0` as a localized notation for `NNReal`. assert_not_exists Star open Function +open scoped BigOperators -- to ensure these instances are computable /-- Nonnegative real numbers. -/ @@ -70,7 +68,8 @@ scoped notation "ℝ≥0" => NNReal noncomputable instance : FloorSemiring ℝ≥0 := Nonneg.floorSemiring instance instDenselyOrdered : DenselyOrdered ℝ≥0 := Nonneg.instDenselyOrdered instance : OrderBot ℝ≥0 := inferInstance -instance : Archimedean ℝ≥0 := Nonneg.archimedean +instance : Archimedean ℝ≥0 := Nonneg.instArchimedean +instance : MulArchimedean ℝ≥0 := Nonneg.instMulArchimedean noncomputable instance : Sub ℝ≥0 := Nonneg.sub noncomputable instance : OrderedSub ℝ≥0 := Nonneg.orderedSub @@ -94,7 +93,7 @@ instance canLift : CanLift ℝ ℝ≥0 toReal fun r => 0 ≤ r := Subtype.eq theorem ne_iff {x y : ℝ≥0} : (x : ℝ) ≠ (y : ℝ) ↔ x ≠ y := - NNReal.eq_iff.symm.not + not_congr <| NNReal.eq_iff.symm protected theorem «forall» {p : ℝ≥0 → Prop} : (∀ x : ℝ≥0, p x) ↔ ∀ (x : ℝ) (hx : 0 ≤ x), p ⟨x, hx⟩ := @@ -154,6 +153,9 @@ protected theorem coe_injective : Injective ((↑) : ℝ≥0 → ℝ) := Subtype @[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 @@ -274,28 +276,32 @@ 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 -@[norm_cast] -theorem coe_sum {α} {s : Finset α} {f : α → ℝ≥0} : ↑(∑ a ∈ s, f a) = ∑ a ∈ s, (f a : ℝ) := +variable {ι : Type*} {s : Finset ι} {f : ι → ℝ} + +@[simp, norm_cast] +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)] -@[norm_cast] -theorem coe_prod {α} {s : Finset α} {f : α → ℝ≥0} : ↑(∏ a ∈ s, f a) = ∏ a ∈ s, (f a : ℝ) := +@[simp, norm_cast] +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)] --- Porting note (#11215): TODO: `simp`? `norm_cast`? -theorem coe_nsmul (r : ℝ≥0) (n : ℕ) : ↑(n • r) = n • (r : ℝ) := rfl +@[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 := @@ -428,7 +434,7 @@ theorem orderIsoIccZeroCoe_symm_apply_coe (a : ℝ≥0) (b : Set.Iic a) : -- 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 _ _ ⟨x, h⟩ s } := + (↑) '' 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 := @@ -811,45 +817,49 @@ theorem le_inv_iff_mul_le {r p : ℝ≥0} (h : p ≠ 0) : r ≤ p⁻¹ ↔ r * p 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] -theorem mul_le_iff_le_inv {a b r : ℝ≥0} (hr : r ≠ 0) : r * a ≤ b ↔ a ≤ r⁻¹ * b := by - have : 0 < r := lt_of_le_of_ne (zero_le r) hr.symm - rw [← mul_le_mul_left (inv_pos.mpr this), ← mul_assoc, inv_mul_cancel₀ hr, one_mul] +@[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₀ hr + le_div_iff₀ (pos_iff_ne_zero.2 hr) -theorem div_le_iff {a b r : ℝ≥0} (hr : r ≠ 0) : a / r ≤ b ↔ a ≤ b * r := - div_le_iff₀ 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) -nonrec theorem div_le_iff' {a b r : ℝ≥0} (hr : r ≠ 0) : a / r ≤ b ↔ a ≤ r * b := - @div_le_iff' ℝ _ a r b <| 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 h0).2 h + 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 -nonrec theorem le_div_iff {a b r : ℝ≥0} (hr : r ≠ 0) : a ≤ b / r ↔ a * r ≤ b := - @le_div_iff ℝ _ a b r <| pos_iff_ne_zero.2 hr +@[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 -nonrec theorem le_div_iff' {a b r : ℝ≥0} (hr : r ≠ 0) : a ≤ b / r ↔ r * a ≤ b := - @le_div_iff' ℝ _ a b r <| pos_iff_ne_zero.2 hr +@[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 -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 hr) +@[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 -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' hr) +@[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 -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 hr) +@[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 -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' hr) +@[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 fun hr => False.elim <| by simp [hr] at h).1 h + (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 := @@ -874,8 +884,7 @@ 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) + 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 @@ -892,13 +901,13 @@ theorem _root_.Real.toNNReal_div' {x y : ℝ} (hy : 0 ≤ y) : 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] + rw [← one_div, div_lt_iff₀ hx.bot_lt, one_mul] -theorem zpow_pos {x : ℝ≥0} (hx : x ≠ 0) (n : ℤ) : 0 < x ^ n := - zpow_pos_of_pos hx.bot_lt _ +@[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_lt_inv_of_lt hx.bot_lt h + inv_strictAnti₀ hx.bot_lt h end Inv @@ -928,10 +937,15 @@ theorem iSup_empty [IsEmpty ι] (f : ι → ℝ≥0) : ⨆ i, f i = 0 := ciSup_o 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 + exact Real.iInf_const_zero theorem iInf_mul (f : ι → ℝ≥0) (a : ℝ≥0) : iInf f * a = ⨅ i, f i * a := by rw [← coe_inj, NNReal.coe_mul, coe_iInf, coe_iInf] diff --git a/Mathlib/Data/Nat/BitIndices.lean b/Mathlib/Data/Nat/BitIndices.lean index 2b9034e73c7b8..79bd2eb583ef4 100644 --- a/Mathlib/Data/Nat/BitIndices.lean +++ b/Mathlib/Data/Nat/BitIndices.lean @@ -7,8 +7,8 @@ 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.Star.Order /-! # Bit Indices @@ -35,9 +35,9 @@ 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)) := diff --git a/Mathlib/Data/Nat/Bits.lean b/Mathlib/Data/Nat/Bits.lean index 117d9a800575e..753381e7318d1 100644 --- a/Mathlib/Data/Nat/Bits.lean +++ b/Mathlib/Data/Nat/Bits.lean @@ -6,7 +6,7 @@ Authors: Praneeth Kolichala import Mathlib.Algebra.Group.Basic import Mathlib.Algebra.Group.Nat import Mathlib.Data.Nat.Defs -import Mathlib.Init.Data.List.Basic +import Mathlib.Data.List.Defs import Mathlib.Tactic.Convert import Mathlib.Tactic.GeneralizeProofs import Mathlib.Tactic.Says @@ -25,7 +25,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 @@ -43,12 +43,12 @@ def boddDiv2 : ℕ → Bool × ℕ /-- `div2 n = ⌊n/2⌋` the greatest integer smaller than `n/2`-/ def div2 (n : ℕ) : ℕ := (boddDiv2 n).2 -/-- `bodd n` returns `true` if `n` is odd-/ +/-- `bodd n` returns `true` if `n` is odd -/ 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 @@ -66,9 +66,10 @@ lemma bodd_add (m n : ℕ) : bodd (m + n) = bxor (bodd m) (bodd n) := by @[simp] lemma bodd_mul (m n : ℕ) : bodd (m * n) = (bodd m && bodd n) := by - induction' n with n IH - · simp - · simp only [mul_succ, bodd_add, IH, bodd_succ] + induction n with + | zero => simp + | succ n IH => + 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 @@ -83,16 +84,16 @@ lemma mod_two_of_bodd (n : ℕ) : n % 2 = cond (bodd n) 1 0 := by intro b cases b <;> rfl rw [← this] - cases' mod_two_eq_zero_or_one n with h h <;> rw [h] <;> rfl + rcases mod_two_eq_zero_or_one n with h | h <;> rw [h] <;> rfl @[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 @@ -131,7 +132,7 @@ lemma bit_zero : bit false 0 = 0 := /-- `shiftLeft' b m n` performs a left shift of `m` `n` times and adds the bit `b` as the least significant bit each time. - Returns the corresponding natural number-/ + Returns the corresponding natural number -/ def shiftLeft' (b : Bool) (m : ℕ) : ℕ → ℕ | 0 => m | n + 1 => bit b (shiftLeft' b m n) @@ -194,6 +195,12 @@ lemma binaryRec_zero {C : Nat → Sort u} (z : C 0) (f : ∀ b n, C n → C (bit rw [binaryRec] rfl +@[simp] +lemma binaryRec_one {C : Nat → Sort u} (z : C 0) (f : ∀ b n, C n → C (bit b n)) : + binaryRec z f 1 = f true 0 z := by + rw [binaryRec] + simp + /-! bitwise ops -/ lemma bodd_bit (b n) : bodd (bit b n) = b := by @@ -290,7 +297,7 @@ theorem bit_ne_zero (b) {n} (h : n ≠ 0) : bit b n ≠ 0 := by @[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] + eq_of_heq <| (eqRec_heq _ _).trans <| by rw [bodd_bit, div2_bit] @[simp] theorem bitCasesOn_bit0 {C : ℕ → Sort u} (H : ∀ b n, C (bit b n)) (n : ℕ) : @@ -339,7 +346,7 @@ theorem binaryRec_eq' {C : ℕ → Sort*} {z : C 0} {f : ∀ b n, C n → C (bit 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] at h + simp only [imp_false, or_false, eq_self_iff_true, not_true, reduceCtorEq] at h exact h.symm · dsimp only [] generalize_proofs e @@ -390,17 +397,20 @@ 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] -- := by norm_num theorem bodd_eq_bits_head (n : ℕ) : n.bodd = n.bits.headI := by - induction' n using Nat.binaryRec' with b n h _; · simp - simp [bodd_bit, bits_append_bit _ _ h] + induction n using Nat.binaryRec' with + | z => simp + | f _ _ h _ => simp [bodd_bit, bits_append_bit _ _ h] theorem div2_bits_eq_tail (n : ℕ) : n.div2.bits = n.bits.tail := by - induction' n using Nat.binaryRec' with b n h _; · simp - simp [div2_bit, bits_append_bit _ _ h] + induction n using Nat.binaryRec' with + | z => simp + | f _ _ h _ => simp [div2_bit, bits_append_bit _ _ h] end Nat diff --git a/Mathlib/Data/Nat/Bitwise.lean b/Mathlib/Data/Nat/Bitwise.lean index 0d5dc3611afd5..98bc466c54c8d 100644 --- a/Mathlib/Data/Nat/Bitwise.lean +++ b/Mathlib/Data/Nat/Bitwise.lean @@ -9,6 +9,7 @@ import Mathlib.Algebra.Ring.Nat import Mathlib.Order.Basic import Mathlib.Tactic.AdaptationNote import Mathlib.Tactic.Common +import Mathlib.Algebra.NeZero /-! # Bitwise operations on natural numbers @@ -246,34 +247,11 @@ theorem lt_of_testBit {n m : ℕ} (i : ℕ) (hn : testBit n i = false) (hm : tes _ ≤ 2 * m := mul_le_mul_left 2 this · exact Nat.succ_lt_succ this' -@[simp] -theorem testBit_two_pow_self (n : ℕ) : testBit (2 ^ n) n = true := by - rw [testBit, shiftRight_eq_div_pow, Nat.div_self (Nat.pow_pos Nat.zero_lt_two)] - simp - -theorem testBit_two_pow_of_ne {n m : ℕ} (hm : n ≠ m) : testBit (2 ^ n) m = false := by - rw [testBit, shiftRight_eq_div_pow] - cases' hm.lt_or_lt with hm hm - · rw [Nat.div_eq_of_lt] - · simp - · exact Nat.pow_lt_pow_right Nat.one_lt_two hm - · rw [Nat.pow_div hm.le Nat.two_pos, ← Nat.sub_add_cancel (succ_le_of_lt <| Nat.sub_pos_of_lt hm)] - -- Porting note: XXX why does this make it work? - rw [(rfl : succ 0 = 1)] - simp [pow_succ, and_one_is_mod, mul_mod_left] - -theorem testBit_two_pow (n m : ℕ) : testBit (2 ^ n) m = (n = m) := by - by_cases h : n = m - · cases h - simp - · rw [testBit_two_pow_of_ne h] - simp [h] - theorem bitwise_swap {f : Bool → Bool → Bool} : bitwise (Function.swap f) = Function.swap (bitwise f) := by funext m n simp only [Function.swap] - induction' m using Nat.strongInductionOn with m ih generalizing n + induction' m using Nat.strongRecOn with m ih generalizing n cases' m with m <;> cases' n with n <;> try rw [bitwise_zero_left, bitwise_zero_right] @@ -295,9 +273,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 @@ -309,13 +284,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| ( @@ -328,22 +296,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] @@ -362,45 +324,44 @@ 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] - -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 + 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] @[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/Basic.lean b/Mathlib/Data/Nat/Cast/Basic.lean index 8e33f0b37f992..82a0796b55644 100644 --- a/Mathlib/Data/Nat/Cast/Basic.lean +++ b/Mathlib/Data/Nat/Cast/Basic.lean @@ -130,7 +130,7 @@ theorem map_ofNat' {A} [AddMonoidWithOne A] [FunLike F A B] [AddMonoidHomClass F { toFun := fun n ↦ n • (1 : A) map_zero' := zero_nsmul _ map_add' := add_nsmul _ } - exact eq_natCast' f $ by simp [f] + exact eq_natCast' f <| by simp [f] end AddMonoidHomClass diff --git a/Mathlib/Data/Nat/Cast/Commute.lean b/Mathlib/Data/Nat/Cast/Commute.lean index 4d8306384d75f..9d1e9bc89094b 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 diff --git a/Mathlib/Data/Nat/Cast/Defs.lean b/Mathlib/Data/Nat/Cast/Defs.lean index 0a184083269a5..937ea2f0f088c 100644 --- a/Mathlib/Data/Nat/Cast/Defs.lean +++ b/Mathlib/Data/Nat/Cast/Defs.lean @@ -83,7 +83,7 @@ class AddMonoidWithOne (R : Type*) extends NatCast R, AddMonoid R, One R where /-- The canonical map `ℕ → R` is a homomorphism. -/ natCast_succ : ∀ n, natCast (n + 1) = natCast n + 1 := by intros; rfl -/-- An `AddCommMonoidWithOne` is an `AddMonoidWithOne` satisfying `a + b = b + a`. -/ +/-- An `AddCommMonoidWithOne` is an `AddMonoidWithOne` satisfying `a + b = b + a`. -/ class AddCommMonoidWithOne (R : Type*) extends AddMonoidWithOne R, AddCommMonoid R library_note "coercion into rings" @@ -149,8 +149,7 @@ protected def binCast [Zero R] [One R] [Add R] : ℕ → R @[simp] theorem binCast_eq [AddMonoidWithOne R] (n : ℕ) : (Nat.binCast n : R) = ((n : ℕ) : R) := by - apply Nat.strongInductionOn n - intros k hk + induction n using Nat.strongRecOn with | ind k hk => ?_ cases k with | zero => rw [Nat.binCast, Nat.cast_zero] | succ k => diff --git a/Mathlib/Data/Nat/Cast/Field.lean b/Mathlib/Data/Nat/Cast/Field.lean index 3fe4913e4f2ef..d532397a177fd 100644 --- a/Mathlib/Data/Nat/Cast/Field.lean +++ b/Mathlib/Data/Nat/Cast/Field.lean @@ -37,6 +37,6 @@ theorem cast_div_div_div_cancel_right [DivisionSemiring α] [CharZero α] {m n d (↑(m / d) : α) / (↑(n / d) : α) = (m : α) / n := by rcases eq_or_ne d 0 with (rfl | hd); · simp [Nat.zero_dvd.1 hm] replace hd : (d : α) ≠ 0 := by norm_cast - rw [cast_div hm, cast_div hn, div_div_div_cancel_right _ hd] <;> exact hd + rw [cast_div hm, cast_div hn, div_div_div_cancel_right₀ hd] <;> exact hd end Nat 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 489bdfacffcc2..0bd91bdef4a52 100644 --- a/Mathlib/Data/Nat/Cast/Order/Basic.lean +++ b/Mathlib/Data/Nat/Cast/Order/Basic.lean @@ -69,6 +69,9 @@ variable [CharZero α] {m n : ℕ} theorem strictMono_cast : StrictMono (Nat.cast : ℕ → α) := mono_cast.strictMono_of_injective cast_injective +@[gcongr] +lemma _root_.GCongr.natCast_lt_natCast {a b : ℕ} (h : a < b) : (a : α) < b := strictMono_cast h + /-- `Nat.cast : ℕ → α` as an `OrderEmbedding` -/ @[simps! (config := .asFn)] def castOrderEmbedding : ℕ ↪o α := diff --git a/Mathlib/Data/Nat/Cast/Order/Field.lean b/Mathlib/Data/Nat/Cast/Order/Field.lean index 0ae2a744f0146..bf5cfd6d2e238 100644 --- a/Mathlib/Data/Nat/Cast/Order/Field.lean +++ b/Mathlib/Data/Nat/Cast/Order/Field.lean @@ -22,13 +22,13 @@ 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 cases n · rw [cast_zero, div_zero, Nat.div_zero, cast_zero] - rw [le_div_iff, ← Nat.cast_mul, @Nat.cast_le] + rw [le_div_iff₀, ← Nat.cast_mul, @Nat.cast_le] · exact Nat.div_mul_le_self m _ · exact Nat.cast_pos.2 (Nat.succ_pos _) 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 dd13795e37b76..08947b2993cb9 100644 --- a/Mathlib/Data/Nat/Choose/Basic.lean +++ b/Mathlib/Data/Nat/Choose/Basic.lean @@ -60,6 +60,21 @@ 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 _ @@ -362,10 +377,8 @@ 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] - termination_by a b => a + b - decreasing_by all_goals assumption end Nat diff --git a/Mathlib/Data/Nat/Choose/Bounds.lean b/Mathlib/Data/Nat/Choose/Bounds.lean index 2f82b251e6fa9..d4b21ddf606d9 100644 --- a/Mathlib/Data/Nat/Choose/Bounds.lean +++ b/Mathlib/Data/Nat/Choose/Bounds.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Yaël Dillies. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies, Eric Rodriguez -/ -import Mathlib.Algebra.Order.Field.Basic +import Mathlib.Algebra.Order.Field.Defs import Mathlib.Data.Nat.Cast.Order.Basic import Mathlib.Data.Nat.Choose.Basic @@ -15,7 +15,7 @@ bounds `n^r/r^r ≤ n.choose r ≤ e^r n^r/r^r` in the future. ## Main declarations -* `Nat.choose_le_pow`: `n.choose r ≤ n^r / r!` +* `Nat.choose_le_pow_div`: `n.choose r ≤ n^r / r!` * `Nat.pow_le_choose`: `(n + 1 - r)^r / r! ≤ n.choose r`. Beware of the fishy ℕ-subtraction. -/ @@ -26,16 +26,25 @@ variable {α : Type*} [LinearOrderedSemifield α] namespace Nat -theorem choose_le_pow (r n : ℕ) : (n.choose r : α) ≤ (n ^ r : α) / r ! := by - rw [le_div_iff'] +theorem choose_le_pow_div (r n : ℕ) : (n.choose r : α) ≤ (n ^ r : α) / r ! := by + rw [le_div_iff₀'] · norm_cast rw [← Nat.descFactorial_eq_factorial_mul_choose] exact n.descFactorial_le_pow r exact mod_cast r.factorial_pos +lemma choose_le_descFactorial (n k : ℕ) : n.choose k ≤ n.descFactorial k := by + rw [choose_eq_descFactorial_div_factorial] + exact Nat.div_le_self _ _ + +/-- This lemma was changed on 2024/08/29, the old statement is available +in `Nat.choose_le_pow_div`. -/ +lemma choose_le_pow (n k : ℕ) : n.choose k ≤ n ^ k := + (choose_le_descFactorial n k).trans (descFactorial_le_pow n k) + -- horrific casting is due to ℕ-subtraction theorem pow_le_choose (r n : ℕ) : ((n + 1 - r : ℕ) ^ r : α) / r ! ≤ n.choose r := by - rw [div_le_iff'] + rw [div_le_iff₀'] · norm_cast rw [← Nat.descFactorial_eq_factorial_mul_choose] exact n.pow_sub_le_descFactorial r diff --git a/Mathlib/Data/Nat/Choose/Factorization.lean b/Mathlib/Data/Nat/Choose/Factorization.lean index 71966a049eb3a..258c4eb897817 100644 --- a/Mathlib/Data/Nat/Choose/Factorization.lean +++ b/Mathlib/Data/Nat/Choose/Factorization.lean @@ -78,7 +78,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 c896d134554d5..ed55883414890 100644 --- a/Mathlib/Data/Nat/Choose/Lucas.lean +++ b/Mathlib/Data/Nat/Choose/Lucas.lean @@ -47,7 +47,7 @@ theorem choose_modEq_choose_mod_mul_choose_div : rw [Prod.mk.injEq] constructor <;> intro h · simp only [mem_product, mem_range] at hx - have h' : x₁ < p := lt_of_lt_of_le hx.left $ mod_lt _ Fin.size_pos' + have h' : x₁ < p := lt_of_lt_of_le hx.left <| mod_lt _ Fin.size_pos' rw [h, add_mul_mod_self_left, add_mul_div_left _ _ Fin.size_pos', eq_comm (b := x₂)] exact ⟨mod_eq_of_lt h', self_eq_add_left.mpr (div_eq_of_lt h')⟩ · rw [← h.left, ← h.right, mod_add_div] diff --git a/Mathlib/Data/Nat/Choose/Multinomial.lean b/Mathlib/Data/Nat/Choose/Multinomial.lean index f41552ee482ec..62485e17c0efa 100644 --- a/Mathlib/Data/Nat/Choose/Multinomial.lean +++ b/Mathlib/Data/Nat/Choose/Multinomial.lean @@ -73,9 +73,9 @@ lemma multinomial_insert [DecidableEq α] (ha : a ∉ s) (f : α → ℕ) : @[simp] theorem multinomial_insert_one [DecidableEq α] (h : a ∉ s) (h₁ : f a = 1) : multinomial (insert a s) f = (s.sum f).succ * multinomial s f := by - simp only [multinomial, one_mul, factorial] + simp only [multinomial] rw [Finset.sum_insert h, Finset.prod_insert h, h₁, add_comm, ← succ_eq_add_one, factorial_succ] - simp only [factorial_one, one_mul, Function.comp_apply, factorial, mul_one, ← one_eq_succ_zero] + simp only [factorial, succ_eq_add_one, zero_add, mul_one, one_mul] rw [Nat.mul_div_assoc _ (prod_factorial_dvd_factorial_sum _ _)] theorem multinomial_congr {f g : α → ℕ} (h : ∀ a ∈ s, f a = g a) : diff --git a/Mathlib/Data/Nat/Choose/Sum.lean b/Mathlib/Data/Nat/Choose/Sum.lean index ac70377042b48..d15893af1129d 100644 --- a/Mathlib/Data/Nat/Choose/Sum.lean +++ b/Mathlib/Data/Nat/Choose/Sum.lean @@ -17,13 +17,9 @@ import Mathlib.Tactic.Ring This file includes variants of the binomial theorem and other results on sums of binomial coefficients. Theorems whose proofs depend on such sums may also go in this file for import reasons. - -/ - -open Nat - -open Finset +open Nat Finset variable {R : Type*} @@ -33,32 +29,33 @@ variable [Semiring R] {x y : R} /-- A version of the **binomial theorem** for commuting elements in noncommutative semirings. -/ theorem add_pow (h : Commute x y) (n : ℕ) : - (x + y) ^ n = ∑ m ∈ range (n + 1), x ^ m * y ^ (n - m) * choose n m := by - let t : ℕ → ℕ → R := fun n m ↦ x ^ m * y ^ (n - m) * choose n m + (x + y) ^ n = ∑ m ∈ range (n + 1), x ^ m * y ^ (n - m) * n.choose m := by + let t : ℕ → ℕ → R := fun n m ↦ x ^ m * y ^ (n - m) * n.choose m change (x + y) ^ n = ∑ m ∈ range (n + 1), t n m have h_first : ∀ n, t n 0 = y ^ n := fun n ↦ by - simp only [t, choose_zero_right, _root_.pow_zero, Nat.cast_one, mul_one, one_mul, tsub_zero] + simp only [t, choose_zero_right, pow_zero, cast_one, mul_one, one_mul, tsub_zero] have h_last : ∀ n, t n n.succ = 0 := fun n ↦ by simp only [t, choose_succ_self, cast_zero, mul_zero] have h_middle : - ∀ n i : ℕ, i ∈ range n.succ → (t n.succ (Nat.succ i)) = - x * t n i + y * t n i.succ := by + ∀ n i : ℕ, i ∈ range n.succ → (t n.succ i.succ) = x * t n i + y * t n i.succ := by intro n i h_mem - have h_le : i ≤ n := Nat.le_of_lt_succ (mem_range.mp h_mem) + have h_le : i ≤ n := le_of_lt_succ (mem_range.mp h_mem) dsimp only [t] - rw [choose_succ_succ, Nat.cast_add, mul_add] + rw [choose_succ_succ, cast_add, mul_add] congr 1 · rw [pow_succ' x, succ_sub_succ, mul_assoc, mul_assoc, mul_assoc] · rw [← mul_assoc y, ← mul_assoc y, (h.symm.pow_right i.succ).eq] by_cases h_eq : i = n - · rw [h_eq, choose_succ_self, Nat.cast_zero, mul_zero, mul_zero] + · rw [h_eq, choose_succ_self, cast_zero, mul_zero, mul_zero] · rw [succ_sub (lt_of_le_of_ne h_le h_eq)] rw [pow_succ' y, mul_assoc, mul_assoc, mul_assoc, mul_assoc] - induction' n with n ih - · rw [_root_.pow_zero, sum_range_succ, range_zero, sum_empty, zero_add] + induction n with + | zero => + rw [pow_zero, sum_range_succ, range_zero, sum_empty, zero_add] dsimp only [t] - rw [_root_.pow_zero, _root_.pow_zero, choose_self, Nat.cast_one, mul_one, mul_one] - · rw [sum_range_succ', h_first, sum_congr rfl (h_middle n), sum_add_distrib, add_assoc, + rw [pow_zero, pow_zero, choose_self, cast_one, mul_one, mul_one] + | succ n ih => + rw [sum_range_succ', h_first, sum_congr rfl (h_middle n), sum_add_distrib, add_assoc, pow_succ' (x + y), ih, add_mul, mul_sum, mul_sum] congr 1 rw [sum_range_succ', sum_range_succ, h_first, h_last, mul_zero, add_zero, _root_.pow_succ'] @@ -66,81 +63,107 @@ theorem add_pow (h : Commute x y) (n : ℕ) : /-- A version of `Commute.add_pow` that avoids ℕ-subtraction by summing over the antidiagonal and also with the binomial coefficient applied via scalar action of ℕ. -/ theorem add_pow' (h : Commute x y) (n : ℕ) : - (x + y) ^ n = ∑ m ∈ antidiagonal n, choose n m.fst • (x ^ m.fst * y ^ m.snd) := by - simp_rw [Finset.Nat.sum_antidiagonal_eq_sum_range_succ fun m p ↦ choose n m • (x ^ m * y ^ p), - _root_.nsmul_eq_mul, cast_comm, h.add_pow] + (x + y) ^ n = ∑ m ∈ antidiagonal n, n.choose m.1 • (x ^ m.1 * y ^ m.2) := by + simp_rw [Nat.sum_antidiagonal_eq_sum_range_succ fun m p ↦ n.choose m • (x ^ m * y ^ p), + nsmul_eq_mul, cast_comm, h.add_pow] end Commute /-- The **binomial theorem** -/ theorem add_pow [CommSemiring R] (x y : R) (n : ℕ) : - (x + y) ^ n = ∑ m ∈ range (n + 1), x ^ m * y ^ (n - m) * choose n m := + (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 -/ -theorem sum_range_choose (n : ℕ) : (∑ m ∈ range (n + 1), choose n m) = 2 ^ n := by +theorem sum_range_choose (n : ℕ) : (∑ m ∈ range (n + 1), n.choose m) = 2 ^ n := by have := (add_pow 1 1 n).symm simpa [one_add_one_eq_two] using this -theorem sum_range_choose_halfway (m : Nat) : (∑ i ∈ range (m + 1), choose (2 * m + 1) i) = 4 ^ m := - have : (∑ i ∈ range (m + 1), choose (2 * m + 1) (2 * m + 1 - i)) = - ∑ i ∈ range (m + 1), choose (2 * m + 1) i := +theorem sum_range_choose_halfway (m : ℕ) : (∑ i ∈ range (m + 1), (2 * m + 1).choose i) = 4 ^ m := + have : (∑ i ∈ range (m + 1), (2 * m + 1).choose (2 * m + 1 - i)) = + ∑ i ∈ range (m + 1), (2 * m + 1).choose i := sum_congr rfl fun i hi ↦ choose_symm <| by linarith [mem_range.1 hi] mul_right_injective₀ two_ne_zero <| calc - (2 * ∑ i ∈ range (m + 1), choose (2 * m + 1) i) = - (∑ i ∈ range (m + 1), choose (2 * m + 1) i) + - ∑ i ∈ range (m + 1), choose (2 * m + 1) (2 * m + 1 - i) := by rw [two_mul, this] - _ = (∑ i ∈ range (m + 1), choose (2 * m + 1) i) + - ∑ i ∈ Ico (m + 1) (2 * m + 2), choose (2 * m + 1) i := by - { rw [range_eq_Ico, sum_Ico_reflect] - · congr - have A : m + 1 ≤ 2 * m + 1 := by omega - rw [add_comm, add_tsub_assoc_of_le A, ← add_comm] - congr - rw [tsub_eq_iff_eq_add_of_le A] - ring - · omega } - _ = ∑ i ∈ range (2 * m + 2), choose (2 * m + 1) i := sum_range_add_sum_Ico _ (by omega) + (2 * ∑ i ∈ range (m + 1), (2 * m + 1).choose i) = + (∑ i ∈ range (m + 1), (2 * m + 1).choose i) + + ∑ i ∈ range (m + 1), (2 * m + 1).choose (2 * m + 1 - i) := by rw [two_mul, this] + _ = (∑ i ∈ range (m + 1), (2 * m + 1).choose i) + + ∑ i ∈ Ico (m + 1) (2 * m + 2), (2 * m + 1).choose i := by + rw [range_eq_Ico, sum_Ico_reflect _ _ (by omega)] + congr + have A : m + 1 ≤ 2 * m + 1 := by omega + rw [add_comm, add_tsub_assoc_of_le A, ← add_comm] + congr + rw [tsub_eq_iff_eq_add_of_le A] + ring + _ = ∑ i ∈ range (2 * m + 2), (2 * m + 1).choose i := sum_range_add_sum_Ico _ (by omega) _ = 2 ^ (2 * m + 1) := sum_range_choose (2 * m + 1) - _ = 2 * 4 ^ m := by rw [Nat.pow_succ, pow_mul, mul_comm]; rfl + _ = 2 * 4 ^ m := by rw [pow_succ, pow_mul, mul_comm]; rfl -theorem choose_middle_le_pow (n : ℕ) : choose (2 * n + 1) n ≤ 4 ^ n := by - have t : choose (2 * n + 1) n ≤ ∑ i ∈ range (n + 1), choose (2 * n + 1) i := +theorem choose_middle_le_pow (n : ℕ) : (2 * n + 1).choose n ≤ 4 ^ n := by + have t : (2 * n + 1).choose n ≤ ∑ i ∈ range (n + 1), (2 * n + 1).choose i := single_le_sum (fun x _ ↦ by omega) (self_mem_range_succ n) simpa [sum_range_choose_halfway n] using t theorem four_pow_le_two_mul_add_one_mul_central_binom (n : ℕ) : - 4 ^ n ≤ (2 * n + 1) * choose (2 * n) n := + 4 ^ n ≤ (2 * n + 1) * (2 * n).choose n := calc 4 ^ n = (1 + 1) ^ (2 * n) := by norm_num [pow_mul] - _ = ∑ m ∈ range (2 * n + 1), choose (2 * n) m := by set_option simprocs false in simp [add_pow] - _ ≤ ∑ m ∈ range (2 * n + 1), choose (2 * n) (2 * n / 2) := by gcongr; apply choose_le_middle + _ = ∑ 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 _ = (2 * n + 1) * choose (2 * n) n := by simp -/-- **Zhu Shijie's identity** aka hockey-stick identity. -/ +/-- **Zhu Shijie's identity** aka hockey-stick identity, version with `Icc`. -/ theorem sum_Icc_choose (n k : ℕ) : ∑ m ∈ Icc k n, m.choose k = (n + 1).choose (k + 1) := by - cases' le_or_gt k n with h h - · induction' n, h using le_induction with n _ ih; · simp - rw [← Ico_insert_right (by omega), sum_insert (by simp), - show Ico k (n + 1) = Icc k n by rfl, ih, choose_succ_succ' (n + 1)] + rcases lt_or_le n k with h | h · rw [choose_eq_zero_of_lt (by omega), Icc_eq_empty_of_lt h, sum_empty] + · induction n, h using le_induction with + | base => simp + | succ n _ ih => + rw [← Ico_insert_right (by omega), sum_insert (by simp), + show Ico k (n + 1) = Icc k n by rfl, ih, choose_succ_succ' (n + 1)] + +/-- **Zhu Shijie's identity** aka hockey-stick identity, version with `range`. +Summing `(i + k).choose k` for `i ∈ [0, n]` gives `(n + k + 1).choose (k + 1)`. + +Combinatorial interpretation: `(i + k).choose k` is the number of decompositions of `[0, i)` in +`k + 1` (possibly empty) intervals (this follows from a stars and bars description). In particular, +`(n + k + 1).choose (k + 1)` corresponds to decomposing `[0, n)` into `k + 2` intervals. +By putting away the last interval (of some length `n - i`), +we have to decompose the remaining interval `[0, i)` into `k + 1` intervals, hence the sum. -/ +lemma sum_range_add_choose (n k : ℕ) : + ∑ i ∈ Finset.range (n + 1), (i + k).choose k = (n + k + 1).choose (k + 1) := by + rw [← sum_Icc_choose, range_eq_Ico] + convert (sum_map _ (addRightEmbedding k) (·.choose k)).symm using 2 + rw [map_add_right_Ico, zero_add, add_right_comm, Nat.Ico_succ_right] end Nat theorem Int.alternating_sum_range_choose {n : ℕ} : - (∑ m ∈ range (n + 1), ((-1) ^ m * ↑(choose n m) : ℤ)) = if n = 0 then 1 else 0 := by + (∑ m ∈ range (n + 1), ((-1) ^ m * n.choose m : ℤ)) = if n = 0 then 1 else 0 := by cases n with | zero => simp | succ n => have h := add_pow (-1 : ℤ) 1 n.succ simp only [one_pow, mul_one, neg_add_cancel] at h - rw [← h, zero_pow n.succ_ne_zero, if_neg (Nat.succ_ne_zero n)] + rw [← h, zero_pow n.succ_ne_zero, if_neg n.succ_ne_zero] theorem Int.alternating_sum_range_choose_of_ne {n : ℕ} (h0 : n ≠ 0) : - (∑ m ∈ range (n + 1), ((-1) ^ m * ↑(choose n m) : ℤ)) = 0 := by + (∑ m ∈ range (n + 1), ((-1) ^ m * n.choose m : ℤ)) = 0 := by rw [Int.alternating_sum_range_choose, if_neg h0] namespace Finset @@ -166,11 +189,10 @@ theorem sum_powerset_neg_one_pow_card {α : Type*} [DecidableEq α] {x : Finset theorem sum_powerset_neg_one_pow_card_of_nonempty {α : Type*} {x : Finset α} (h0 : x.Nonempty) : (∑ m ∈ x.powerset, (-1 : ℤ) ^ m.card) = 0 := by classical - rw [sum_powerset_neg_one_pow_card, if_neg] - rw [← Ne, ← nonempty_iff_ne_empty] - apply h0 + 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 : ℕ) : @@ -179,10 +201,9 @@ theorem prod_pow_choose_succ {M : Type*} [CommMonoid M] (f : ℕ → ℕ → M) ∏ i ∈ range (n + 1), f (i + 1) (n - i) ^ n.choose i := by have A : (∏ i ∈ range (n + 1), f (i + 1) (n - i) ^ (n.choose (i + 1))) * f 0 (n + 1) = ∏ i ∈ range (n + 1), f i (n + 1 - i) ^ (n.choose i) := by - rw [prod_range_succ, prod_range_succ'] - simp + rw [prod_range_succ, prod_range_succ']; simp rw [prod_range_succ'] - simpa [Nat.choose_succ_succ, pow_add, prod_mul_distrib, A, mul_assoc] using mul_comm _ _ + simpa [choose_succ_succ, pow_add, prod_mul_distrib, A, mul_assoc] using mul_comm _ _ @[to_additive sum_antidiagonal_choose_succ_nsmul] theorem prod_antidiagonal_pow_choose_succ {M : Type*} [CommMonoid M] (f : ℕ → ℕ → M) (n : ℕ) : @@ -195,9 +216,8 @@ theorem prod_antidiagonal_pow_choose_succ {M : Type*} [CommMonoid M] (f : ℕ · refine prod_congr rfl fun i hi ↦ ?_ rw [tsub_add_eq_add_tsub (this _ hi)] · refine prod_congr rfl fun i hi ↦ ?_ - rw [Nat.choose_symm (this _ hi)] + rw [choose_symm (this _ hi)] --- Porting note: moved from `Mathlib.Analysis.Calculus.ContDiff` /-- The sum of `(n+1).choose i * f i (n+1-i)` can be split into two sums at rank `n`, respectively of `n.choose i * f i (n+1-i)` and `n.choose i * f (i+1) (n-i)`. -/ theorem sum_choose_succ_mul (f : ℕ → ℕ → R) (n : ℕ) : @@ -215,8 +235,7 @@ theorem sum_antidiagonal_choose_succ_mul (f : ℕ → ℕ → R) (n : ℕ) : simpa only [nsmul_eq_mul] using sum_antidiagonal_choose_succ_nsmul f n theorem sum_antidiagonal_choose_add (d n : ℕ) : - (Finset.sum (antidiagonal n) fun ij => (d + ij.2).choose d) = - (d + n).choose d + (d + n).choose (succ d) := by + (∑ ij ∈ antidiagonal n, (d + ij.2).choose d) = (d + n).choose d + (d + n).choose (d + 1) := by induction n with | zero => simp | succ n hn => simpa [Nat.sum_antidiagonal_succ] using hn diff --git a/Mathlib/Data/Nat/Count.lean b/Mathlib/Data/Nat/Count.lean index c3e60e57f4397..cb2e2160ea3aa 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 diff --git a/Mathlib/Data/Nat/Defs.lean b/Mathlib/Data/Nat/Defs.lean index 4670f85b6aeb7..3bff75138a170 100644 --- a/Mathlib/Data/Nat/Defs.lean +++ b/Mathlib/Data/Nat/Defs.lean @@ -5,11 +5,9 @@ Authors: Floris van Doorn, Leonardo de Moura, Jeremy Avigad, Mario Carneiro -/ import Mathlib.Logic.Function.Basic import Mathlib.Logic.Nontrivial.Defs -import Mathlib.Tactic.Cases -import Mathlib.Tactic.GCongr.Core +import Mathlib.Tactic.GCongr.CoreAttrs import Mathlib.Tactic.PushNeg import Mathlib.Util.AssertExists -import Batteries.Data.Nat.Basic /-! # Basic operations on the natural numbers @@ -59,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 @@ -139,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 @@ -157,8 +165,13 @@ lemma pred_eq_of_eq_succ (H : m = n.succ) : m.pred = n := by simp [H] @[simp] lemma pred_eq_succ_iff : n - 1 = m + 1 ↔ n = m + 2 := by cases n <;> constructor <;> rintro ⟨⟩ <;> rfl +#adaptation_note +/-- +After nightly-2024-09-06 we can remove both the `_root_` prefixes below. +-/ lemma forall_lt_succ : (∀ m < n + 1, p m) ↔ (∀ m < n, p m) ∧ p n := by - simp only [Nat.lt_succ_iff, Nat.le_iff_lt_or_eq, or_comm, forall_eq_or_imp, and_comm] + simp only [Nat.lt_succ_iff, Nat.le_iff_lt_or_eq, _root_.or_comm, forall_eq_or_imp, + _root_.and_comm] lemma exists_lt_succ : (∃ m < n + 1, p m) ↔ (∃ m < n, p m) ∨ p n := by rw [← not_iff_not] @@ -210,8 +223,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 @@ -300,11 +312,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) @@ -316,9 +328,9 @@ lemma mul_eq_left (ha : a ≠ 0) : a * b = a ↔ b = 1 := by simpa using Nat.mul lemma mul_eq_right (hb : b ≠ 0) : a * b = b ↔ a = 1 := by simpa using Nat.mul_left_inj hb (c := 1) -- TODO: Deprecate -lemma mul_right_eq_self_iff (ha : 0 < a) : a * b = a ↔ b = 1 := mul_eq_left $ ne_of_gt ha +lemma mul_right_eq_self_iff (ha : 0 < a) : a * b = a ↔ b = 1 := mul_eq_left <| ne_of_gt ha -lemma mul_left_eq_self_iff (hb : 0 < b) : a * b = b ↔ a = 1 := mul_eq_right $ ne_of_gt hb +lemma mul_left_eq_self_iff (hb : 0 < b) : a * b = b ↔ a = 1 := mul_eq_right <| ne_of_gt hb protected lemma le_of_mul_le_mul_right (h : a * c ≤ b * c) (hc : 0 < c) : a ≤ b := Nat.le_of_mul_le_mul_left (by simpa [Nat.mul_comm]) hc @@ -361,7 +373,7 @@ lemma succ_mul_pos (m : ℕ) (hn : 0 < n) : 0 < succ m * n := Nat.mul_pos m.succ lemma mul_self_le_mul_self (h : m ≤ n) : m * m ≤ n * n := Nat.mul_le_mul h h lemma mul_lt_mul'' (hac : a < c) (hbd : b < d) : a * b < c * d := - Nat.mul_lt_mul_of_lt_of_le hac (Nat.le_of_lt hbd) $ by omega + Nat.mul_lt_mul_of_lt_of_le hac (Nat.le_of_lt hbd) <| by omega lemma mul_self_lt_mul_self (h : m < n) : m * m < n * n := mul_lt_mul'' h h @@ -387,7 +399,7 @@ lemma add_sub_one_le_mul (ha : a ≠ 0) (hb : b ≠ 0) : a + b - 1 ≤ a * b := cases a · cases ha rfl · rw [succ_add, Nat.add_one_sub_one, succ_mul] - exact Nat.add_le_add_right (Nat.le_mul_of_pos_right _ $ Nat.pos_iff_ne_zero.2 hb) _ + exact Nat.add_le_add_right (Nat.le_mul_of_pos_right _ <| Nat.pos_iff_ne_zero.2 hb) _ protected lemma add_le_mul {a : ℕ} (ha : 2 ≤ a) : ∀ {b : ℕ} (_ : 2 ≤ b), a + b ≤ a * b | 2, _ => by omega @@ -421,10 +433,10 @@ protected lemma div_le_div_right (h : a ≤ b) : a / c ≤ b / c := (le_div_iff_mul_le' hc).2 <| Nat.le_trans (Nat.div_mul_le_self _ _) h lemma lt_of_div_lt_div (h : a / c < b / c) : a < b := - Nat.lt_of_not_le fun hab ↦ Nat.not_le_of_lt h $ Nat.div_le_div_right hab + Nat.lt_of_not_le fun hab ↦ Nat.not_le_of_lt h <| Nat.div_le_div_right hab protected lemma div_pos (hba : b ≤ a) (hb : 0 < b) : 0 < a / b := - Nat.pos_of_ne_zero fun h ↦ Nat.lt_irrefl a $ + Nat.pos_of_ne_zero fun h ↦ Nat.lt_irrefl a <| calc a = a % b := by simpa [h] using (mod_add_div a b).symm _ < b := mod_lt a hb @@ -504,7 +516,7 @@ protected lemma div_le_of_le_mul' (h : m ≤ k * n) : m / k ≤ n := by protected lemma div_le_div_of_mul_le_mul (hd : d ≠ 0) (hdc : d ∣ c) (h : a * d ≤ c * b) : a / b ≤ c / d := - Nat.div_le_of_le_mul' $ by + Nat.div_le_of_le_mul' <| by rwa [← Nat.mul_div_assoc _ hdc, Nat.le_div_iff_mul_le (Nat.pos_iff_ne_zero.2 hd), b.mul_comm] protected lemma div_le_self' (m n : ℕ) : m / n ≤ m := by @@ -588,9 +600,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] @@ -641,7 +650,7 @@ lemma one_lt_two_pow' (n : ℕ) : 1 < 2 ^ (n + 1) := one_lt_pow n.succ_ne_zero ( lemma mul_lt_mul_pow_succ (ha : 0 < a) (hb : 1 < b) : n * b < a * b ^ (n + 1) := by rw [Nat.pow_succ, ← Nat.mul_assoc, Nat.mul_lt_mul_right (Nat.lt_trans Nat.zero_lt_one hb)] exact Nat.lt_of_le_of_lt (Nat.le_mul_of_pos_left _ ha) - ((Nat.mul_lt_mul_left ha).2 $ Nat.lt_pow_self hb _) + ((Nat.mul_lt_mul_left ha).2 <| Nat.lt_pow_self hb _) lemma sq_sub_sq (a b : ℕ) : a ^ 2 - b ^ 2 = (a + b) * (a - b) := by simpa [Nat.pow_succ] using Nat.mul_self_sub_mul_self_eq a b @@ -824,7 +833,23 @@ 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) + (more : ∀ n, P n → P (n + 1) → P (n + 2)) : ∀ a, P a + | 0 => zero + | 1 => one + | _ + 2 => more _ (twoStepInduction zero one more _) (twoStepInduction zero one more _) + +@[elab_as_elim] +protected theorem strong_induction_on {p : ℕ → Prop} (n : ℕ) + (h : ∀ n, (∀ m, m < n → p m) → p n) : p n := + Nat.strongRecOn n h + +protected theorem case_strong_induction_on {p : ℕ → Prop} (a : ℕ) (hz : p 0) + (hi : ∀ n, (∀ m, m ≤ n → p m) → p (n + 1)) : p a := + Nat.caseStrongRecOn a hz hi /-- Decreasing induction: if `P (k+1)` implies `P k` for all `k < n`, then `P n` implies `P m` for all `m ≤ n`. @@ -925,8 +950,6 @@ theorem diag_induction (P : ℕ → ℕ → Prop) (ha : ∀ a, P (a + 1) (a + 1) have _ : a + (b + 1) < (a + 1) + (b + 1) := by simp apply diag_induction P ha hb hd a (b + 1) apply Nat.lt_of_le_of_lt (Nat.le_succ _) h - termination_by a b _c => a + b - decreasing_by all_goals assumption /-- A subset of `ℕ` containing `k : ℕ` and closed under `Nat.succ` contains every `n ≥ k`. -/ lemma set_induction_bounded {S : Set ℕ} (hk : k ∈ S) (h_ind : ∀ k : ℕ, k ∈ S → k + 1 ∈ S) @@ -943,10 +966,10 @@ lemma set_induction {S : Set ℕ} (hb : 0 ∈ S) (h_ind : ∀ k : ℕ, k ∈ S attribute [simp] Nat.dvd_zero @[simp] lemma mod_two_ne_one : ¬n % 2 = 1 ↔ n % 2 = 0 := by - cases' mod_two_eq_zero_or_one n with h h <;> simp [h] + cases mod_two_eq_zero_or_one n <;> simp [*] @[simp] lemma mod_two_ne_zero : ¬n % 2 = 0 ↔ n % 2 = 1 := by - cases' mod_two_eq_zero_or_one n with h h <;> simp [h] + cases mod_two_eq_zero_or_one n <;> simp [*] @[deprecated mod_mul_right_div_self (since := "2024-05-29")] lemma div_mod_eq_mod_mul_div (a b c : ℕ) : a / b % c = a % (b * c) / b := @@ -994,9 +1017,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 @@ -1038,7 +1058,7 @@ lemma eq_of_dvd_of_lt_two_mul (ha : a ≠ 0) (hdvd : b ∣ a) (hlt : a < 2 * b) cases Nat.not_le_of_lt hlt (Nat.mul_le_mul_right _ (by omega)) lemma mod_eq_iff_lt (hn : n ≠ 0) : m % n = m ↔ m < n := - ⟨fun h ↦ by rw [← h]; exact mod_lt _ $ Nat.pos_iff_ne_zero.2 hn, mod_eq_of_lt⟩ + ⟨fun h ↦ by rw [← h]; exact mod_lt _ <| Nat.pos_iff_ne_zero.2 hn, mod_eq_of_lt⟩ @[simp] lemma mod_succ_eq_iff_lt : m % n.succ = m ↔ m < n.succ := @@ -1066,8 +1086,11 @@ lemma sub_mod_eq_zero_of_mod_eq (h : m % k = n % k) : (m - n) % k = 0 := by @[simp] lemma one_mod (n : ℕ) : 1 % (n + 2) = 1 := Nat.mod_eq_of_lt (Nat.add_lt_add_right n.succ_pos 1) -lemma one_mod_of_ne_one : ∀ {n : ℕ}, n ≠ 1 → 1 % n = 1 - | 0, _ | (n + 2), _ => by simp +lemma one_mod_eq_one : ∀ {n : ℕ}, 1 % n = 1 ↔ n ≠ 1 + | 0 | 1 | n + 2 => by simp + +@[deprecated (since := "2024-08-28")] +lemma one_mod_of_ne_one : ∀ {n : ℕ}, n ≠ 1 → 1 % n = 1 := one_mod_eq_one.mpr lemma dvd_sub_mod (k : ℕ) : n ∣ k - k % n := ⟨k / n, Nat.sub_eq_of_eq_add (Nat.div_add_mod k n).symm⟩ @@ -1098,12 +1121,12 @@ protected lemma dvd_add_right (h : a ∣ b) : a ∣ b + c ↔ a ∣ c := (Nat.dv /-- special case of `mul_dvd_mul_iff_left` for `ℕ`. Duplicated here to keep simple imports for this file. -/ protected lemma mul_dvd_mul_iff_left (ha : 0 < a) : a * b ∣ a * c ↔ b ∣ c := - exists_congr fun d ↦ by rw [Nat.mul_assoc, Nat.mul_right_inj $ ne_of_gt ha] + exists_congr fun d ↦ by rw [Nat.mul_assoc, Nat.mul_right_inj <| ne_of_gt ha] /-- special case of `mul_dvd_mul_iff_right` for `ℕ`. Duplicated here to keep simple imports for this file. -/ protected lemma mul_dvd_mul_iff_right (hc : 0 < c) : a * c ∣ b * c ↔ a ∣ b := - exists_congr fun d ↦ by rw [Nat.mul_right_comm, Nat.mul_left_inj $ ne_of_gt hc] + exists_congr fun d ↦ by rw [Nat.mul_right_comm, Nat.mul_left_inj <| ne_of_gt hc] -- Moved to Batteries @@ -1280,201 +1303,11 @@ lemma div_lt_div_of_lt_of_dvd {a b d : ℕ} (hdb : d ∣ b) (h : a < b) : a / d rw [Nat.lt_div_iff_mul_lt hdb] exact lt_of_le_of_lt (mul_div_le a d) h -/-! -### `sqrt` - -See [Wikipedia, *Methods of computing square roots*] -(https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_(base_2)). --/ - -private lemma iter_fp_bound (n k : ℕ) : - let iter_next (n guess : ℕ) := (guess + n / guess) / 2; - sqrt.iter n k ≤ iter_next n (sqrt.iter n k) := by - intro iter_next - unfold sqrt.iter - if h : (k + n / k) / 2 < k then - simpa [if_pos h] using iter_fp_bound _ _ - else - simpa [if_neg h] using Nat.le_of_not_lt h - -private lemma AM_GM : {a b : ℕ} → (4 * a * b ≤ (a + b) * (a + b)) - | 0, _ => by rw [Nat.mul_zero, Nat.zero_mul]; exact zero_le _ - | _, 0 => by rw [Nat.mul_zero]; exact zero_le _ - | a + 1, b + 1 => by - simpa only [Nat.mul_add, Nat.add_mul, show (4 : ℕ) = 1 + 1 + 1 + 1 from rfl, Nat.one_mul, - Nat.mul_one, Nat.add_assoc, Nat.add_left_comm, Nat.add_le_add_iff_left] - using Nat.add_le_add_right (@AM_GM a b) 4 - --- These two lemmas seem like they belong to `Batteries.Data.Nat.Basic`. - -lemma sqrt.iter_sq_le (n guess : ℕ) : sqrt.iter n guess * sqrt.iter n guess ≤ n := by - unfold sqrt.iter - let next := (guess + n / guess) / 2 - if h : next < guess then - simpa only [dif_pos h] using sqrt.iter_sq_le n next - else - simp only [dif_neg h] - apply Nat.mul_le_of_le_div - apply Nat.le_of_add_le_add_left (a := guess) - rw [← Nat.mul_two, ← le_div_iff_mul_le] - · exact Nat.le_of_not_lt h - · exact Nat.zero_lt_two - -lemma sqrt.lt_iter_succ_sq (n guess : ℕ) (hn : n < (guess + 1) * (guess + 1)) : - n < (sqrt.iter n guess + 1) * (sqrt.iter n guess + 1) := by - unfold sqrt.iter - -- m was `next` - let m := (guess + n / guess) / 2 - dsimp - split_ifs with h - · suffices n < (m + 1) * (m + 1) by - simpa only [dif_pos h] using sqrt.lt_iter_succ_sq n m this - refine Nat.lt_of_mul_lt_mul_left ?_ (a := 4 * (guess * guess)) - apply Nat.lt_of_le_of_lt AM_GM - rw [show (4 : ℕ) = 2 * 2 from rfl] - rw [Nat.mul_mul_mul_comm 2, Nat.mul_mul_mul_comm (2 * guess)] - refine Nat.mul_self_lt_mul_self (?_ : _ < _ * ((_ / 2) + 1)) - rw [← add_div_right _ (by decide), Nat.mul_comm 2, Nat.mul_assoc, - show guess + n / guess + 2 = (guess + n / guess + 1) + 1 from rfl] - have aux_lemma {a : ℕ} : a ≤ 2 * ((a + 1) / 2) := by omega - refine lt_of_lt_of_le ?_ (Nat.mul_le_mul_left _ aux_lemma) - rw [Nat.add_assoc, Nat.mul_add] - exact Nat.add_lt_add_left (lt_mul_div_succ _ (lt_of_le_of_lt (Nat.zero_le m) h)) _ - · simpa only [dif_neg h] using hn --- Porting note: the implementation of `Nat.sqrt` in `Batteries` no longer needs `sqrt_aux`. -private def IsSqrt (n q : ℕ) : Prop := - q * q ≤ n ∧ n < (q + 1) * (q + 1) --- Porting note: as the definition of square root has changed, --- the proof of `sqrt_isSqrt` is attempted from scratch. -/- -Sketch of proof: -Up to rounding, in terms of the definition of `sqrt.iter`, - -* By AM-GM inequality, `next² ≥ n` giving one of the bounds. -* When we terminated, we have `guess ≥ next` from which we deduce the other bound `n ≥ next²`. - -To turn this into a lean proof we need to manipulate, use properties of natural number division etc. --/ -private lemma sqrt_isSqrt (n : ℕ) : IsSqrt n (sqrt n) := by - match n with - | 0 => simp [IsSqrt, sqrt] - | 1 => simp [IsSqrt, sqrt] - | n + 2 => - have h : ¬ (n + 2) ≤ 1 := by simp - simp only [IsSqrt, sqrt, h, ite_false] - refine ⟨sqrt.iter_sq_le _ _, sqrt.lt_iter_succ_sq _ _ ?_⟩ - simp only [Nat.mul_add, Nat.add_mul, Nat.one_mul, Nat.mul_one, ← Nat.add_assoc] - rw [Nat.lt_add_one_iff, Nat.add_assoc, ← Nat.mul_two] - refine le_trans (Nat.le_of_eq (div_add_mod' (n + 2) 2).symm) ?_ - rw [Nat.add_comm, Nat.add_le_add_iff_right, add_mod_right] - simp only [Nat.zero_lt_two, add_div_right, succ_mul_succ] - refine le_trans (b := 1) ?_ ?_ - · exact (lt_succ.1 <| mod_lt n Nat.zero_lt_two) - · exact Nat.le_add_left _ _ - -lemma sqrt_le (n : ℕ) : sqrt n * sqrt n ≤ n := (sqrt_isSqrt n).left - -lemma sqrt_le' (n : ℕ) : sqrt n ^ 2 ≤ n := by simpa [Nat.pow_two] using sqrt_le n - -lemma lt_succ_sqrt (n : ℕ) : n < succ (sqrt n) * succ (sqrt n) := (sqrt_isSqrt n).right - -lemma lt_succ_sqrt' (n : ℕ) : n < succ (sqrt n) ^ 2 := by simpa [Nat.pow_two] using lt_succ_sqrt n - -lemma sqrt_le_add (n : ℕ) : n ≤ sqrt n * sqrt n + sqrt n + sqrt n := by - rw [← succ_mul]; exact le_of_lt_succ (lt_succ_sqrt n) - -lemma le_sqrt : m ≤ sqrt n ↔ m * m ≤ n := - ⟨fun h ↦ le_trans (mul_self_le_mul_self h) (sqrt_le n), - fun h ↦ le_of_lt_succ <| Nat.mul_self_lt_mul_self_iff.1 <| lt_of_le_of_lt h (lt_succ_sqrt n)⟩ - -lemma le_sqrt' : m ≤ sqrt n ↔ m ^ 2 ≤ n := by simpa only [Nat.pow_two] using le_sqrt - -lemma sqrt_lt : sqrt m < n ↔ m < n * n := by simp only [← not_le, le_sqrt] - -lemma sqrt_lt' : sqrt m < n ↔ m < n ^ 2 := by simp only [← not_le, le_sqrt'] - -lemma sqrt_le_self (n : ℕ) : sqrt n ≤ n := le_trans (le_mul_self _) (sqrt_le n) - -lemma sqrt_le_sqrt (h : m ≤ n) : sqrt m ≤ sqrt n := le_sqrt.2 (le_trans (sqrt_le _) h) - -@[simp] lemma sqrt_zero : sqrt 0 = 0 := rfl - -@[simp] lemma sqrt_one : sqrt 1 = 1 := rfl - -lemma sqrt_eq_zero : sqrt n = 0 ↔ n = 0 := - ⟨fun h ↦ - Nat.eq_zero_of_le_zero <| le_of_lt_succ <| (@sqrt_lt n 1).1 <| by rw [h]; decide, - by rintro rfl; simp⟩ - -lemma eq_sqrt : a = sqrt n ↔ a * a ≤ n ∧ n < (a + 1) * (a + 1) := - ⟨fun e ↦ e.symm ▸ sqrt_isSqrt n, - fun ⟨h₁, h₂⟩ ↦ le_antisymm (le_sqrt.2 h₁) (le_of_lt_succ <| sqrt_lt.2 h₂)⟩ - -lemma eq_sqrt' : a = sqrt n ↔ a ^ 2 ≤ n ∧ n < (a + 1) ^ 2 := by - simpa only [Nat.pow_two] using eq_sqrt - -lemma le_three_of_sqrt_eq_one (h : sqrt n = 1) : n ≤ 3 := - le_of_lt_succ <| (@sqrt_lt n 2).1 <| by rw [h]; decide - -lemma sqrt_lt_self (h : 1 < n) : sqrt n < n := - sqrt_lt.2 <| by have := Nat.mul_lt_mul_of_pos_left h (lt_of_succ_lt h); rwa [Nat.mul_one] at this - -lemma sqrt_pos : 0 < sqrt n ↔ 0 < n := - le_sqrt - -lemma sqrt_add_eq (n : ℕ) (h : a ≤ n + n) : sqrt (n * n + a) = n := - le_antisymm - (le_of_lt_succ <| - sqrt_lt.2 <| by - rw [succ_mul, mul_succ, add_succ, Nat.add_assoc] - exact lt_succ_of_le (Nat.add_le_add_left h _)) - (le_sqrt.2 <| Nat.le_add_right _ _) - -lemma sqrt_add_eq' (n : ℕ) (h : a ≤ n + n) : sqrt (n ^ 2 + a) = n := by - simpa [Nat.pow_two] using sqrt_add_eq n h - -lemma sqrt_eq (n : ℕ) : sqrt (n * n) = n := sqrt_add_eq n (zero_le _) - -lemma sqrt_eq' (n : ℕ) : sqrt (n ^ 2) = n := sqrt_add_eq' n (zero_le _) - -lemma sqrt_succ_le_succ_sqrt (n : ℕ) : sqrt n.succ ≤ n.sqrt.succ := - le_of_lt_succ <| sqrt_lt.2 <| lt_succ_of_le <| - succ_le_succ <| le_trans (sqrt_le_add n) <| Nat.add_le_add_right - (by refine add_le_add (Nat.mul_le_mul_right _ ?_) ?_ <;> exact Nat.le_add_right _ 2) _ - -lemma exists_mul_self (x : ℕ) : (∃ n, n * n = x) ↔ sqrt x * sqrt x = x := - ⟨fun ⟨n, hn⟩ ↦ by rw [← hn, sqrt_eq], fun h ↦ ⟨sqrt x, h⟩⟩ - -lemma exists_mul_self' (x : ℕ) : (∃ n, n ^ 2 = x) ↔ sqrt x ^ 2 = x := by - simpa only [Nat.pow_two] using exists_mul_self x - -lemma sqrt_mul_sqrt_lt_succ (n : ℕ) : sqrt n * sqrt n < n + 1 := - Nat.lt_succ_iff.mpr (sqrt_le _) - -lemma sqrt_mul_sqrt_lt_succ' (n : ℕ) : sqrt n ^ 2 < n + 1 := - Nat.lt_succ_iff.mpr (sqrt_le' _) - -lemma succ_le_succ_sqrt (n : ℕ) : n + 1 ≤ (sqrt n + 1) * (sqrt n + 1) := - le_of_pred_lt (lt_succ_sqrt _) - -lemma succ_le_succ_sqrt' (n : ℕ) : n + 1 ≤ (sqrt n + 1) ^ 2 := - le_of_pred_lt (lt_succ_sqrt' _) - -/-- There are no perfect squares strictly between m² and (m+1)² -/ -lemma not_exists_sq (hl : m * m < n) (hr : n < (m + 1) * (m + 1)) : ¬∃ t, t * t = n := by - rintro ⟨t, rfl⟩ - have h1 : m < t := Nat.mul_self_lt_mul_self_iff.1 hl - have h2 : t < m + 1 := Nat.mul_self_lt_mul_self_iff.1 hr - exact (not_lt_of_ge <| le_of_lt_succ h2) h1 - -lemma not_exists_sq' : m ^ 2 < n → n < (m + 1) ^ 2 → ¬∃ t, t ^ 2 = n := by - simpa only [Nat.pow_two] using not_exists_sq - /-! ### Decidability of predicates -/ instance decidableLoHi (lo hi : ℕ) (P : ℕ → Prop) [H : DecidablePred P] : Decidable (∀ x, lo ≤ x → x < hi → P x) := - decidable_of_iff (∀ x < hi - lo, P (lo + x)) $ by + decidable_of_iff (∀ x < hi - lo, P (lo + x)) <| by refine ⟨fun al x hl hh ↦ ?_, fun al x h ↦ al _ (Nat.le_add_right _ _) (Nat.lt_sub_iff_add_lt'.1 h)⟩ have := al (x - lo) ((Nat.sub_lt_sub_iff_right hl).2 hh) diff --git a/Mathlib/Data/Nat/Digits.lean b/Mathlib/Data/Nat/Digits.lean index fd51916d69605..23cd40d657cba 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 @@ -246,9 +246,7 @@ theorem ofDigits_digits (b n : ℕ) : ofDigits b (digits b n) = n := by · rfl · rw [Nat.zero_add] at ih ⊢ simp only [ih, add_comm 1, ofDigits_one_cons, Nat.cast_id, digits_one_succ] - · apply Nat.strongInductionOn n _ - clear n - intro n h + · induction n using Nat.strongRecOn with | ind n h => ?_ cases n · rw [digits_zero] rfl @@ -258,9 +256,9 @@ theorem ofDigits_digits (b n : ℕ) : ofDigits b (digits b n) = n := by rw [Nat.mod_add_div] theorem ofDigits_one (L : List ℕ) : ofDigits 1 L = L.sum := by - induction' L with _ _ ih - · rfl - · simp [ofDigits, List.sum_cons, ih] + induction L with + | nil => rfl + | cons _ _ ih => simp [ofDigits, List.sum_cons, ih] /-! ### Properties @@ -328,8 +326,8 @@ theorem getLast_digit_ne_zero (b : ℕ) {m : ℕ} (hm : m ≠ 0) : simp only [zero_add, digits_one, List.getLast_replicate_succ m 1] exact Nat.one_ne_zero revert hm - apply Nat.strongInductionOn m - intro n IH hn + induction m using Nat.strongRecOn with | ind n IH => ?_ + intro hn by_cases hnb : n < b + 2 · simpa only [digits_of_lt (b + 2) n hn hnb] · rw [digits_getLast n (le_add_left 2 b)] @@ -345,7 +343,7 @@ theorem mul_ofDigits (n : ℕ) {b : ℕ} {l : List ℕ} : rw [List.map_cons, ofDigits_cons, ofDigits_cons, ← ih] ring -/-- The addition of ofDigits of two lists is equal to ofDigits of digit-wise addition of them-/ +/-- The addition of ofDigits of two lists is equal to ofDigits of digit-wise addition of them -/ theorem ofDigits_add_ofDigits_eq_ofDigits_zipWith_of_length_eq {b : ℕ} {l1 l2 : List ℕ} (h : l1.length = l2.length) : ofDigits b l1 + ofDigits b l2 = ofDigits b (l1.zipWith (· + ·) l2) := by @@ -362,8 +360,8 @@ theorem ofDigits_add_ofDigits_eq_ofDigits_zipWith_of_length_eq {b : ℕ} {l1 l2 /-- The digits in the base b+2 expansion of n are all less than b+2 -/ theorem digits_lt_base' {b m : ℕ} : ∀ {d}, d ∈ digits (b + 2) m → d < b + 2 := by - apply Nat.strongInductionOn m - intro n IH d hd + induction m using Nat.strongRecOn with | ind n IH => ?_ + intro d hd cases' n with n · rw [digits_zero] at hd cases hd @@ -440,9 +438,10 @@ theorem le_digits_len_le (b n m : ℕ) (h : n ≤ m) : (digits b n).length ≤ ( @[mono] theorem ofDigits_monotone {p q : ℕ} (L : List ℕ) (h : p ≤ q) : ofDigits p L ≤ ofDigits q L := by - induction' L with _ _ hi - · rfl - · simp only [ofDigits, cast_id, add_le_add_iff_left] + induction L with + | nil => rfl + | cons _ _ hi => + simp only [ofDigits, cast_id, add_le_add_iff_left] exact Nat.mul_le_mul h hi theorem sum_le_ofDigits {p : ℕ} (L : List ℕ) (h : 1 ≤ p) : L.sum ≤ ofDigits p L := @@ -544,8 +543,7 @@ theorem sub_one_mul_sum_div_pow_eq_sub_sum_digits {p : ℕ} Ico_zero_eq_range, mul_add, mul_add, ih, range_one, sum_singleton, List.drop, ofDigits, mul_zero, add_zero, ← Nat.add_sub_assoc <| sum_le_ofDigits _ <| Nat.le_of_lt h] nth_rw 2 [← one_mul <| ofDigits p tl] - rw [← add_mul, one_eq_succ_zero, Nat.sub_add_cancel <| zero_lt_of_lt h, - Nat.add_sub_add_left] + rw [← add_mul, Nat.sub_add_cancel (one_le_of_lt h), Nat.add_sub_add_left] · simp [ofDigits_one] · simp [lt_one_iff.mp h] cases L @@ -572,7 +570,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/Dist.lean b/Mathlib/Data/Nat/Dist.lean index 8151b3d7c07f2..b207d03af6224 100644 --- a/Mathlib/Data/Nat/Dist.lean +++ b/Mathlib/Data/Nat/Dist.lean @@ -89,7 +89,7 @@ theorem dist_succ_succ {i j : Nat} : dist (succ i) (succ j) = dist i j := by simp [dist, succ_sub_succ] theorem dist_pos_of_ne {i j : Nat} : i ≠ j → 0 < dist i j := fun hne => - Nat.ltByCases + ltByCases i j (fun h : i < j => by rw [dist_eq_sub_of_le (le_of_lt h)]; apply tsub_pos_of_lt h) (fun h : i = j => by contradiction) fun h : i > j => by rw [dist_eq_sub_of_le_right (le_of_lt h)]; apply tsub_pos_of_lt h diff --git a/Mathlib/Data/Nat/Factorial/Basic.lean b/Mathlib/Data/Nat/Factorial/Basic.lean index a72bcc344f845..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 @@ -61,9 +61,9 @@ theorem factorial_ne_zero (n : ℕ) : n ! ≠ 0 := ne_of_gt (factorial_pos _) theorem factorial_dvd_factorial {m n} (h : m ≤ n) : m ! ∣ n ! := by - induction' h with n _ ih - · exact Nat.dvd_refl _ - · exact Nat.dvd_trans ih (Nat.dvd_mul_left _ _) + induction h with + | refl => exact Nat.dvd_refl _ + | step _ ih => exact Nat.dvd_trans ih (Nat.dvd_mul_left _ _) theorem dvd_factorial : ∀ {m n}, 0 < m → m ≤ n → m ∣ n ! | succ _, _, _, h => Nat.dvd_trans (Nat.dvd_mul_right _ _) (factorial_dvd_factorial h) @@ -84,9 +84,9 @@ theorem factorial_lt (hn : 0 < n) : n ! < m ! ↔ n < m := by intro k hk rw [factorial_succ, succ_mul, Nat.lt_add_left_iff_pos] exact Nat.mul_pos hk k.factorial_pos - induction' h with k hnk ih generalizing hn - · exact this hn - · exact lt_trans (ih hn) $ this <| lt_trans hn <| lt_of_succ_le hnk + induction h generalizing hn with + | refl => exact this hn + | step hnk ih => exact lt_trans (ih hn) <| this <| lt_trans hn <| lt_of_succ_le hnk @[gcongr] lemma factorial_lt_of_lt {m n : ℕ} (hn : 0 < n) (h : n < m) : n ! < m ! := (factorial_lt hn).mpr h @@ -354,12 +354,32 @@ theorem factorial_mul_descFactorial : ∀ {n k : ℕ}, k ≤ n → (n - k)! * n. rw [succ_descFactorial_succ, succ_sub_succ, ← Nat.mul_assoc, Nat.mul_comm (n - k)!, Nat.mul_assoc, factorial_mul_descFactorial (Nat.succ_le_succ_iff.1 h), factorial_succ] +theorem descFactorial_mul_descFactorial {k m n : ℕ} (hkm : k ≤ m) : + (n - k).descFactorial (m - k) * n.descFactorial k = n.descFactorial m := by + by_cases hmn : m ≤ n + · apply Nat.mul_left_cancel (n - m).factorial_pos + rw [factorial_mul_descFactorial hmn, show n - m = (n - k) - (m - k) by omega, ← Nat.mul_assoc, + factorial_mul_descFactorial (show m - k ≤ n - k by omega), + factorial_mul_descFactorial (le_trans hkm hmn)] + · rw [descFactorial_eq_zero_iff_lt.mpr (show n < m by omega)] + by_cases hkn : k ≤ n + · rw [descFactorial_eq_zero_iff_lt.mpr (show n - k < m - k by omega), Nat.zero_mul] + · rw [descFactorial_eq_zero_iff_lt.mpr (show n < k by omega), Nat.mul_zero] + /-- Avoid in favor of `Nat.factorial_mul_descFactorial` if you can. ℕ-division isn't worth it. -/ theorem descFactorial_eq_div {n k : ℕ} (h : k ≤ n) : n.descFactorial k = n ! / (n - k)! := by apply Nat.mul_left_cancel (n - k).factorial_pos rw [factorial_mul_descFactorial h] exact (Nat.mul_div_cancel' <| factorial_dvd_factorial <| Nat.sub_le n k).symm +theorem descFactorial_le (n : ℕ) {k m : ℕ} (h : k ≤ m) : + k.descFactorial n ≤ m.descFactorial n := by + induction n with + | zero => rfl + | succ n ih => + rw [descFactorial_succ, descFactorial_succ] + exact Nat.mul_le_mul (Nat.sub_le_sub_right h n) ih + theorem pow_sub_le_descFactorial (n : ℕ) : ∀ k : ℕ, (n + 1 - k) ^ k ≤ n.descFactorial k | 0 => by rw [descFactorial_zero, Nat.pow_zero] | k + 1 => by diff --git a/Mathlib/Data/Nat/Factorization/Basic.lean b/Mathlib/Data/Nat/Factorization/Basic.lean index 3b99f2f2baaac..27ddcf0d3a424 100644 --- a/Mathlib/Data/Nat/Factorization/Basic.lean +++ b/Mathlib/Data/Nat/Factorization/Basic.lean @@ -7,12 +7,13 @@ import Mathlib.Data.Nat.PrimeFin import Mathlib.Data.Nat.Factorization.Defs import Mathlib.Data.Nat.GCD.BigOperators import Mathlib.Order.Interval.Finset.Nat +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 : ℕ} @@ -243,7 +244,7 @@ two `2 ^ k`. -/ theorem exists_eq_two_pow_mul_odd {n : ℕ} (hn : n ≠ 0) : ∃ k m : ℕ, Odd m ∧ n = 2 ^ k * m := let ⟨k, m, hm, hn⟩ := exists_eq_pow_mul_and_not_dvd hn 2 (succ_ne_self 1) - ⟨k, m, odd_iff_not_even.mpr (mt Even.two_dvd hm), hn⟩ + ⟨k, m, not_even_iff_odd.1 (mt Even.two_dvd hm), hn⟩ theorem dvd_iff_div_factorization_eq_tsub {d n : ℕ} (hd : d ≠ 0) (hdn : d ≤ n) : d ∣ n ↔ (n / d).factorization = n.factorization - d.factorization := by @@ -308,7 +309,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] @@ -387,7 +388,7 @@ lemma factorizationLCMRight_pos : rw [factorizationLCMRight, Finsupp.prod_ne_zero_iff] intro p _ H by_cases h : b.factorization p ≤ a.factorization p - · simp only [h, reduceIte, pow_eq_zero_iff', ne_eq] at H + · simp only [h, reduceIte, pow_eq_zero_iff', ne_eq, reduceCtorEq] at H · simp only [h, ↓reduceIte, pow_eq_zero_iff', ne_eq] at H simpa [H.1] using H.2 @@ -529,7 +530,7 @@ 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. -/ +See `Nat.card_multiples'` for an alternative spelling of the statement. -/ theorem card_multiples (n p : ℕ) : card ((Finset.range n).filter fun e => p ∣ e + 1) = n / p := by induction' n with n hn · simp diff --git a/Mathlib/Data/Nat/Factorization/Defs.lean b/Mathlib/Data/Nat/Factorization/Defs.lean index 5e73f5097014d..fb64f3dd9d2d6 100644 --- a/Mathlib/Data/Nat/Factorization/Defs.lean +++ b/Mathlib/Data/Nat/Factorization/Defs.lean @@ -4,7 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Stuart Presnell -/ import Mathlib.Data.Finsupp.Multiset -import Mathlib.NumberTheory.Padics.PadicVal +import Mathlib.Data.Nat.Prime.Defs +import Mathlib.Data.Nat.PrimeFin +import Mathlib.NumberTheory.Padics.PadicVal.Defs /-! # Prime factorizations @@ -84,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 @@ -170,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/Induction.lean b/Mathlib/Data/Nat/Factorization/Induction.lean index 1add41840d66f..df145576e8514 100644 --- a/Mathlib/Data/Nat/Factorization/Induction.lean +++ b/Mathlib/Data/Nat/Factorization/Induction.lean @@ -22,7 +22,7 @@ we can define `P` for all natural numbers. -/ @[elab_as_elim] def recOnPrimePow {P : ℕ → Sort*} (h0 : P 0) (h1 : P 1) (h : ∀ a p n : ℕ, p.Prime → ¬p ∣ a → 0 < n → P a → P (p ^ n * a)) : ∀ a : ℕ, P a := fun a => - Nat.strongRecOn a fun n => + Nat.strongRecOn' a fun n => match n with | 0 => fun _ => h0 | 1 => fun _ => h1 diff --git a/Mathlib/Data/Nat/Factorization/PrimePow.lean b/Mathlib/Data/Nat/Factorization/PrimePow.lean index 5f35804b888b8..37333d9e42ecf 100644 --- a/Mathlib/Data/Nat/Factorization/PrimePow.lean +++ b/Mathlib/Data/Nat/Factorization/PrimePow.lean @@ -137,6 +137,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/Factorization/Root.lean b/Mathlib/Data/Nat/Factorization/Root.lean index d0aa141fa8fcd..7e0c2c1f19bee 100644 --- a/Mathlib/Data/Nat/Factorization/Root.lean +++ b/Mathlib/Data/Nat/Factorization/Root.lean @@ -68,7 +68,7 @@ lemma floorRoot_ne_zero : floorRoot n a ≠ 0 ↔ n ≠ 0 ∧ a ≠ 0 := by simp (config := { contextual := true }) [floorRoot, not_imp_not, not_or] @[simp] lemma floorRoot_eq_zero : floorRoot n a = 0 ↔ n = 0 ∨ a = 0 := - floorRoot_ne_zero.not_right.trans $ by simp only [not_and_or, ne_eq, not_not] + floorRoot_ne_zero.not_right.trans <| by simp only [not_and_or, ne_eq, not_not] @[simp] lemma factorization_floorRoot (n a : ℕ) : (floorRoot n a).factorization = a.factorization ⌊/⌋ n := by @@ -130,7 +130,7 @@ lemma ceilRoot_ne_zero : ceilRoot n a ≠ 0 ↔ n ≠ 0 ∧ a ≠ 0 := by simp (config := { contextual := true }) [ceilRoot_def, not_imp_not, not_or] @[simp] lemma ceilRoot_eq_zero : ceilRoot n a = 0 ↔ n = 0 ∨ a = 0 := - ceilRoot_ne_zero.not_right.trans $ by simp only [not_and_or, ne_eq, not_not] + ceilRoot_ne_zero.not_right.trans <| by simp only [not_and_or, ne_eq, not_not] @[simp] lemma factorization_ceilRoot (n a : ℕ) : (ceilRoot n a).factorization = a.factorization ⌈/⌉ n := by diff --git a/Mathlib/Data/Nat/Factors.lean b/Mathlib/Data/Nat/Factors.lean index 3f99b646ebaa3..df65aa467ceea 100644 --- a/Mathlib/Data/Nat/Factors.lean +++ b/Mathlib/Data/Nat/Factors.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. 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.List.Prime import Mathlib.Data.List.Sort @@ -79,7 +80,7 @@ theorem prod_primeFactorsList : ∀ {n}, n ≠ 0 → List.prod (primeFactorsList Nat.mul_div_cancel' (minFac_dvd _)] theorem primeFactorsList_prime {p : ℕ} (hp : Nat.Prime p) : p.primeFactorsList = [p] := by - have : p = p - 2 + 2 := (Nat.sub_add_cancel hp.two_le).symm + have : p = p - 2 + 2 := Nat.eq_add_of_sub_eq hp.two_le rfl rw [this, primeFactorsList] simp only [Eq.symm this] have : Nat.minFac p = p := (Nat.prime_def_minFac.mp hp).2 diff --git a/Mathlib/Data/Nat/Fib/Basic.lean b/Mathlib/Data/Nat/Fib/Basic.lean index fb9601268e67e..4d5698a009a29 100644 --- a/Mathlib/Data/Nat/Fib/Basic.lean +++ b/Mathlib/Data/Nat/Fib/Basic.lean @@ -5,10 +5,8 @@ Authors: Kevin Kappelmann, Kyle Miller, Mario Carneiro -/ import Mathlib.Algebra.BigOperators.Group.Finset import Mathlib.Data.Finset.NatAntidiagonal -import Mathlib.Data.Nat.GCD.Basic import Mathlib.Data.Nat.Bits -import Mathlib.Init.Data.Nat.Lemmas -import Mathlib.Logic.Function.Iterate +import Mathlib.Data.Nat.GCD.Basic import Mathlib.Tactic.Ring import Mathlib.Tactic.Zify diff --git a/Mathlib/Data/Nat/Find.lean b/Mathlib/Data/Nat/Find.lean index 2f06a77d4afe8..84ee3406a3e5a 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 @@ -150,12 +150,14 @@ lemma findGreatest_of_not (h : ¬ P (n + 1)) : findGreatest P (n + 1) = findGrea lemma findGreatest_eq_iff : Nat.findGreatest P k = m ↔ m ≤ k ∧ (m ≠ 0 → P m) ∧ ∀ ⦃n⦄, m < n → n ≤ k → ¬P n := by - induction' k with k ihk generalizing m - · rw [eq_comm, Iff.comm] + induction k generalizing m with + | zero => + rw [eq_comm, Iff.comm] simp only [zero_eq, Nat.le_zero, ne_eq, findGreatest_zero, and_iff_left_iff_imp] rintro rfl exact ⟨fun h ↦ (h rfl).elim, fun n hlt heq ↦ by omega⟩ - · by_cases hk : P (k + 1) + | succ k ihk => + by_cases hk : P (k + 1) · rw [findGreatest_eq hk] constructor · rintro rfl @@ -196,21 +198,23 @@ lemma le_findGreatest (hmb : m ≤ n) (hm : P m) : m ≤ Nat.findGreatest P n := lemma findGreatest_mono_right (P : ℕ → Prop) [DecidablePred P] {m n} (hmn : m ≤ n) : Nat.findGreatest P m ≤ Nat.findGreatest P n := by - induction' hmn with k hmk ih - · simp - rw [findGreatest_succ] - split_ifs - · exact le_trans ih $ le_trans (findGreatest_le _) (le_succ _) - · exact ih + induction hmn with + | refl => simp + | step hmk ih => + rw [findGreatest_succ] + split_ifs + · exact le_trans ih <| le_trans (findGreatest_le _) (le_succ _) + · exact ih lemma findGreatest_mono_left [DecidablePred Q] (hPQ : ∀ n, P n → Q n) (n : ℕ) : Nat.findGreatest P n ≤ Nat.findGreatest Q n := by - induction' n with n hn - · rfl - by_cases h : P (n + 1) - · rw [findGreatest_eq h, findGreatest_eq (hPQ _ h)] - · rw [findGreatest_of_not h] - exact le_trans hn (Nat.findGreatest_mono_right _ <| le_succ _) + induction n with + | zero => rfl + | succ n hn => + by_cases h : P (n + 1) + · rw [findGreatest_eq h, findGreatest_eq (hPQ _ h)] + · rw [findGreatest_of_not h] + exact le_trans hn (Nat.findGreatest_mono_right _ <| le_succ _) lemma findGreatest_mono [DecidablePred Q] (hPQ : ∀ n, P n → Q n) (hmn : m ≤ n) : Nat.findGreatest P m ≤ Nat.findGreatest Q n := @@ -223,3 +227,5 @@ theorem findGreatest_of_ne_zero (h : Nat.findGreatest P n = m) (h0 : m ≠ 0) : (findGreatest_eq_iff.1 h).2.1 h0 end FindGreatest + +end Nat diff --git a/Mathlib/Data/Nat/GCD/Basic.lean b/Mathlib/Data/Nat/GCD/Basic.lean index ffce815884fb3..8d4d667ffa251 100644 --- a/Mathlib/Data/Nat/GCD/Basic.lean +++ b/Mathlib/Data/Nat/GCD/Basic.lean @@ -3,22 +3,25 @@ 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.Order.Lattice import Mathlib.Algebra.GroupWithZero.Divisibility import Mathlib.Algebra.Ring.Nat -import Mathlib.Init.Data.Nat.Lemmas /-! -# Definitions and properties of `Nat.gcd`, `Nat.lcm`, and `Nat.coprime` +# Properties of `Nat.gcd`, `Nat.lcm`, and `Nat.Coprime` + +Definitions are provided in batteries. Generalizations of these are provided in a later file as `GCDMonoid.gcd` and `GCDMonoid.lcm`. -Note that the global `IsCoprime` is not a straightforward generalization of `Nat.coprime`, see +Note that the global `IsCoprime` is not a straightforward generalization of `Nat.Coprime`, see `Nat.isCoprime_iff_coprime` for the connection between the two. +Most of this file could be moved to batteries as well. -/ +assert_not_exists OrderedCommMonoid + namespace Nat /-! ### `gcd` -/ @@ -129,8 +132,6 @@ theorem lcm_mul_right {m n k : ℕ} : (m * n).lcm (k * n) = m.lcm k * n := by See also `Nat.coprime_of_dvd` and `Nat.coprime_of_dvd'` to prove `Nat.Coprime m n`. -/ -instance (m n : ℕ) : Decidable (Coprime m n) := inferInstanceAs (Decidable (gcd m n = 1)) - theorem Coprime.lcm_eq_mul {m n : ℕ} (h : Coprime m n) : lcm m n = m * n := by rw [← one_mul (lcm m n), ← h.gcd_eq_one, gcd_mul_lcm] @@ -209,7 +210,7 @@ theorem coprime_self_sub_right {m n : ℕ} (h : m ≤ n) : Coprime n (n - m) ↔ @[simp] theorem coprime_pow_left_iff {n : ℕ} (hn : 0 < n) (a b : ℕ) : Nat.Coprime (a ^ n) b ↔ Nat.Coprime a b := by - obtain ⟨n, rfl⟩ := exists_eq_succ_of_ne_zero hn.ne' + obtain ⟨n, rfl⟩ := exists_eq_succ_of_ne_zero (Nat.ne_of_gt hn) rw [Nat.pow_succ, Nat.coprime_mul_iff_left] exact ⟨And.right, fun hab => ⟨hab.pow_left _, hab⟩⟩ @@ -233,7 +234,7 @@ theorem gcd_mul_of_coprime_of_dvd {a b c : ℕ} (hac : Coprime a c) (b_dvd_c : b theorem Coprime.eq_of_mul_eq_zero {m n : ℕ} (h : m.Coprime n) (hmn : m * n = 0) : m = 0 ∧ n = 1 ∨ m = 1 ∧ n = 0 := - (Nat.eq_zero_of_mul_eq_zero hmn).imp (fun hm => ⟨hm, n.coprime_zero_left.mp <| hm ▸ h⟩) fun hn => + (Nat.mul_eq_zero.mp hmn).imp (fun hm => ⟨hm, n.coprime_zero_left.mp <| hm ▸ h⟩) fun hn => let eq := hn ▸ h.symm ⟨m.coprime_zero_left.mp <| eq, hn⟩ @@ -270,7 +271,7 @@ theorem pow_dvd_pow_iff {a b n : ℕ} (n0 : n ≠ 0) : a ^ n ∣ b ^ n ↔ a ∣ · simp [eq_zero_of_gcd_eq_zero_right g0] rcases exists_coprime' g0 with ⟨g, a', b', g0', co, rfl, rfl⟩ rw [mul_pow, mul_pow] at h - replace h := Nat.dvd_of_mul_dvd_mul_right (Nat.pos_pow_of_pos _ g0') h + replace h := Nat.dvd_of_mul_dvd_mul_right (Nat.pow_pos g0') h have := pow_dvd_pow a' <| Nat.pos_of_ne_zero n0 rw [pow_one, (co.pow n n).eq_one_of_dvd h] at this simp [eq_one_of_dvd_one this] diff --git a/Mathlib/Data/Nat/Hyperoperation.lean b/Mathlib/Data/Nat/Hyperoperation.lean index 2aa1fb4b12173..ea0cc84e74cc6 100644 --- a/Mathlib/Data/Nat/Hyperoperation.lean +++ b/Mathlib/Data/Nat/Hyperoperation.lean @@ -104,7 +104,7 @@ theorem hyperoperation_ge_four_zero (n k : ℕ) : hyperoperation (n + 4) 0 k = if Even k then 1 else 0 := by induction' k with kk kih · rw [hyperoperation_ge_three_eq_one] - simp only [Nat.zero_eq, even_zero, if_true] + simp only [even_zero, if_true] · rw [hyperoperation_recursion] rw [kih] simp_rw [Nat.even_add_one] diff --git a/Mathlib/Data/Nat/Lattice.lean b/Mathlib/Data/Nat/Lattice.lean index dadaa5b902c92..46be67ef9f99d 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 diff --git a/Mathlib/Data/Nat/Log.lean b/Mathlib/Data/Nat/Log.lean index fef1cd6a9e339..f2cf3df6eca07 100644 --- a/Mathlib/Data/Nat/Log.lean +++ b/Mathlib/Data/Nat/Log.lean @@ -3,8 +3,6 @@ Copyright (c) 2020 Simon Hudon. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Simon Hudon, Yaël Dillies -/ -import Mathlib.Data.Nat.Defs -import Mathlib.Init.Data.Nat.Lemmas import Mathlib.Order.Interval.Set.Basic import Mathlib.Tactic.Bound.Attribute import Mathlib.Tactic.Monotonicity.Attr @@ -60,7 +58,7 @@ theorem log_of_one_lt_of_le {b n : ℕ} (h : 1 < b) (hn : b ≤ n) : log b n = l rw [log] exact if_pos ⟨hn, h⟩ -@[simp] lemma log_zero_left : ∀ n, log 0 n = 0 := log_of_left_le_one $ Nat.zero_le _ +@[simp] lemma log_zero_left : ∀ n, log 0 n = 0 := log_of_left_le_one <| Nat.zero_le _ @[simp] theorem log_zero_right (b : ℕ) : log b 0 = 0 := @@ -78,7 +76,7 @@ theorem log_one_right (b : ℕ) : log b 1 = 0 := `Nat.le_log_of_pow_le` for individual implications under weaker assumptions. -/ theorem pow_le_iff_le_log {b : ℕ} (hb : 1 < b) {x y : ℕ} (hy : y ≠ 0) : b ^ x ≤ y ↔ x ≤ log b y := by - induction' y using Nat.strong_induction_on with y ih generalizing x + induction y using Nat.strong_induction_on generalizing x with | h y ih => ?_ cases x with | zero => dsimp; omega | succ x => @@ -111,14 +109,23 @@ theorem log_lt_of_lt_pow {b x y : ℕ} (hy : y ≠ 0) : y < b ^ x → log b y < theorem lt_pow_of_log_lt {b x y : ℕ} (hb : 1 < b) : log b y < x → y < b ^ x := lt_imp_lt_of_le_imp_le (le_log_of_pow_le hb) +lemma log_lt_self (b : ℕ) {x : ℕ} (hx : x ≠ 0) : log b x < x := + match le_or_lt b 1 with + | .inl h => log_of_left_le_one h x ▸ Nat.pos_iff_ne_zero.2 hx + | .inr h => log_lt_of_lt_pow hx <| lt_pow_self h _ + +lemma log_le_self (b x : ℕ) : log b x ≤ x := + if hx : x = 0 then by simp [hx] + else (log_lt_self b hx).le + theorem lt_pow_succ_log_self {b : ℕ} (hb : 1 < b) (x : ℕ) : x < b ^ (log b x).succ := lt_pow_of_log_lt hb (lt_succ_self _) 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) @@ -181,7 +188,7 @@ theorem log_antitone_left {n : ℕ} : AntitoneOn (fun b => log b n) (Set.Ioi 1) theorem log_div_base (b n : ℕ) : log b (n / b) = log b n - 1 := by rcases le_or_lt b 1 with hb | hb · rw [log_of_left_le_one hb, log_of_left_le_one hb, Nat.zero_sub] - cases' lt_or_le n b with h h + rcases lt_or_le n b with h | h · rw [div_eq_of_lt h, log_of_lt h, log_zero_right] rw [log_of_one_lt_of_le hb h, Nat.add_sub_cancel_right] @@ -189,7 +196,7 @@ theorem log_div_base (b n : ℕ) : log b (n / b) = log b n - 1 := by theorem log_div_mul_self (b n : ℕ) : log b (n / b * b) = log b n := by rcases le_or_lt b 1 with hb | hb · rw [log_of_left_le_one hb, log_of_left_le_one hb] - cases' lt_or_le n b with h h + rcases lt_or_le n b with h | h · rw [div_eq_of_lt h, Nat.zero_mul, log_zero_right, log_of_lt h] rw [log_mul_base hb (Nat.div_pos h (by omega)).ne', log_div_base, Nat.sub_add_cancel (succ_le_iff.2 <| log_pos hb h)] @@ -199,6 +206,13 @@ theorem add_pred_div_lt {b n : ℕ} (hb : 1 < b) (hn : 2 ≤ n) : (n + b - 1) / succ_pred_eq_of_pos (by omega)] exact Nat.add_le_mul hn hb +lemma log2_eq_log_two {n : ℕ} : Nat.log2 n = Nat.log 2 n := by + rcases eq_or_ne n 0 with rfl | hn + · rw [log2_zero, log_zero_right] + apply eq_of_forall_le_iff + intro m + rw [Nat.le_log2 hn, ← Nat.pow_le_iff_le_log Nat.one_lt_two hn] + /-! ### Ceil logarithm -/ @@ -244,7 +258,7 @@ theorem clog_eq_one {b n : ℕ} (hn : 2 ≤ n) (h : n ≤ b) : clog b n = 1 := b /-- `clog b` and `pow b` form a Galois connection. -/ theorem le_pow_iff_clog_le {b : ℕ} (hb : 1 < b) {x y : ℕ} : x ≤ b ^ y ↔ clog b x ≤ y := by - induction' x using Nat.strong_induction_on with x ih generalizing y + induction x using Nat.strong_induction_on generalizing y with | h x ih => ?_ cases y · rw [Nat.pow_zero] refine ⟨fun h => (clog_of_right_le_one h b).le, ?_⟩ 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/Nth.lean b/Mathlib/Data/Nat/Nth.lean index 83719860919c9..13b3543cb9adc 100644 --- a/Mathlib/Data/Nat/Nth.lean +++ b/Mathlib/Data/Nat/Nth.lean @@ -1,18 +1,19 @@ /- 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 -This file defines a function for "what is the `n`th number that satisifies a given predicate `p`", +This file defines a function for "what is the `n`th number that satisfies a given predicate `p`", and provides lemmas that deal with this function and its connection to `Nat.count`. ## Main definitions @@ -237,7 +238,7 @@ 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 @@ -302,6 +303,10 @@ theorem count_nth_of_lt_card_finite {n : ℕ} (hp : (setOf p).Finite) (hlt : n < theorem count_nth_of_infinite (hp : (setOf p).Infinite) (n : ℕ) : count p (nth p n) = n := count_nth fun hf => absurd hf hp +theorem surjective_count_of_infinite_setOf (h : {n | p n}.Infinite) : + Function.Surjective (Nat.count p) := + fun n => ⟨nth p n, count_nth_of_infinite h n⟩ + theorem count_nth_succ {n : ℕ} (hn : ∀ hf : (setOf p).Finite, n < hf.toFinset.card) : count p (nth p n + 1) = n + 1 := by rw [count_succ, count_nth hn, if_pos (nth_mem _ hn)] diff --git a/Mathlib/Data/Nat/PSub.lean b/Mathlib/Data/Nat/PSub.lean index e752c7156034f..e4d0b1efeaaae 100644 --- a/Mathlib/Data/Nat/PSub.lean +++ b/Mathlib/Data/Nat/PSub.lean @@ -73,13 +73,11 @@ theorem psub_eq_some {m : ℕ} : ∀ {n k}, psub m n = some k ↔ k + n = m simp [add_comm, add_left_comm] theorem psub_eq_none {m n : ℕ} : psub m n = none ↔ m < n := by - cases s : psub m n <;> simp [eq_comm] - · show m < n - refine lt_of_not_ge fun h => ?_ - cases' le.dest h with k e + rcases s : psub m n <;> simp [eq_comm] + · refine lt_of_not_ge fun h => ?_ + obtain ⟨k, e⟩ := le.dest h injection s.symm.trans (psub_eq_some.2 <| (add_comm _ _).trans e) - · show n ≤ m - rw [← psub_eq_some.1 s] + · rw [← psub_eq_some.1 s] apply Nat.le_add_left theorem ppred_eq_pred {n} (h : 0 < n) : ppred n = some (pred n) := diff --git a/Mathlib/Data/Nat/Pairing.lean b/Mathlib/Data/Nat/Pairing.lean index b33b6e5f5723c..6265833d77e17 100644 --- a/Mathlib/Data/Nat/Pairing.lean +++ b/Mathlib/Data/Nat/Pairing.lean @@ -5,6 +5,7 @@ Authors: Leonardo de Moura, Mario Carneiro -/ import Mathlib.Algebra.Group.Prod import Mathlib.Data.Set.Lattice +import Mathlib.Data.Nat.Sqrt /-! # Naturals pairing function diff --git a/Mathlib/Data/Nat/PartENat.lean b/Mathlib/Data/Nat/PartENat.lean index 1111f4009e1b7..cc13db102cac5 100644 --- a/Mathlib/Data/Nat/PartENat.lean +++ b/Mathlib/Data/Nat/PartENat.lean @@ -88,8 +88,8 @@ 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 _ + zero_add x := Part.ext' (iff_of_eq (true_and _)) fun _ _ => zero_add _ + add_zero x := Part.ext' (iff_of_eq (and_true _)) fun _ _ => add_zero _ add_assoc x y z := Part.ext' and_assoc fun _ _ => add_assoc _ _ _ nsmul := nsmulRec @@ -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 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 419ca7d32efae..06a9ca4221721 100644 --- a/Mathlib/Data/Nat/Prime/Basic.lean +++ b/Mathlib/Data/Nat/Prime/Basic.lean @@ -132,7 +132,7 @@ theorem Prime.not_dvd_mul {p m n : ℕ} (pp : Prime p) (Hm : ¬p ∣ m) (Hn : ¬ mt pp.dvd_mul.1 <| by simp [Hm, Hn] @[simp] lemma coprime_two_left : Coprime 2 n ↔ Odd n := by - rw [prime_two.coprime_iff_not_dvd, odd_iff_not_even, even_iff_two_dvd] + rw [prime_two.coprime_iff_not_dvd, ← not_even_iff_odd, even_iff_two_dvd] @[simp] lemma coprime_two_right : n.Coprime 2 ↔ Odd n := coprime_comm.trans coprime_two_left @@ -156,7 +156,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] + rw [← h, hp.eq_one_of_pow, eq_self_iff_true, _root_.and_true, pow_one] theorem pow_minFac {n k : ℕ} (hk : k ≠ 0) : (n ^ k).minFac = n.minFac := by rcases eq_or_ne n 1 with (rfl | hn) @@ -247,7 +247,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 @@ -287,37 +287,6 @@ lemma Prime.pow_inj {p q m n : ℕ} (hp : p.Prime) (hq : q.Prime) (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 diff --git a/Mathlib/Data/Nat/Prime/Defs.lean b/Mathlib/Data/Nat/Prime/Defs.lean index 57010bbdfe78c..a7b24cb865b8f 100644 --- a/Mathlib/Data/Nat/Prime/Defs.lean +++ b/Mathlib/Data/Nat/Prime/Defs.lean @@ -5,7 +5,6 @@ Authors: Leonardo de Moura, Jeremy Avigad, Mario Carneiro -/ import Mathlib.Algebra.Associated.Basic import Mathlib.Algebra.Ring.Parity -import Mathlib.Data.Nat.GCD.Basic /-! # Prime numbers @@ -83,7 +82,7 @@ theorem prime_def_lt'' {p : ℕ} : Prime p ↔ 2 ≤ p ∧ ∀ m, m ∣ p → m simp only [Nat.isUnit_iff] apply Or.imp_right _ (h.2 a _) · rintro rfl - rw [← mul_right_inj' (zero_lt_of_lt h1).ne', ← hab, mul_one] + rw [← mul_right_inj' (not_eq_zero_of_lt h1), ← hab, mul_one] · rw [hab] exact dvd_mul_right _ _ @@ -104,7 +103,7 @@ theorem prime_def_lt' {p : ℕ} : Prime p ↔ 2 ≤ p ∧ ∀ m, 2 ≤ m → m < revert p2 decide · rfl - · exact (h (le_add_left _ _) l).elim d⟩ + · exact (h (le_add_left 2 m) l).elim d⟩ theorem prime_def_le_sqrt {p : ℕ} : Prime p ↔ 2 ≤ p ∧ ∀ m, 2 ≤ m → m ≤ sqrt p → ¬m ∣ p := prime_def_lt'.trans <| @@ -162,7 +161,7 @@ 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] + 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, *] @@ -338,7 +337,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 diff --git a/Mathlib/Data/Nat/Set.lean b/Mathlib/Data/Nat/Set.lean index 7da3f139267a2..26f1795892ced 100644 --- a/Mathlib/Data/Nat/Set.lean +++ b/Mathlib/Data/Nat/Set.lean @@ -35,10 +35,9 @@ theorem range_rec {α : Type*} (x : α) (f : ℕ → α → α) : convert (range_of_succ (fun n => Nat.rec x f n : ℕ → α)).symm using 4 dsimp rename_i n - induction' n with n ihn - · rfl - · dsimp at ihn ⊢ - rw [ihn] + induction n with + | zero => rfl + | succ n ihn => dsimp at ihn ⊢; rw [ihn] theorem range_casesOn {α : Type*} (x : α) (f : ℕ → α) : (Set.range fun n => Nat.casesOn n x f : Set α) = {x} ∪ Set.range f := diff --git a/Mathlib/Data/Nat/Size.lean b/Mathlib/Data/Nat/Size.lean index 322711980b545..f3f51b3aa4f02 100644 --- a/Mathlib/Data/Nat/Size.lean +++ b/Mathlib/Data/Nat/Size.lean @@ -57,20 +57,21 @@ end @[simp] theorem size_shiftLeft' {b m n} (h : shiftLeft' b m n ≠ 0) : size (shiftLeft' b m n) = size m + n := by - induction' n with n IH - · simp [shiftLeft'] - simp only [shiftLeft', ne_eq] at h ⊢ - rw [size_bit h, Nat.add_succ] - by_cases s0 : shiftLeft' b m n = 0 - case neg => rw [IH s0] - rw [s0] at h ⊢ - cases b; · exact absurd rfl h - have : shiftLeft' true m n + 1 = 1 := congr_arg (· + 1) s0 - rw [shiftLeft'_tt_eq_mul_pow] at this - obtain rfl := succ.inj (eq_one_of_dvd_one ⟨_, this.symm⟩) - simp only [zero_add, one_mul] at this - obtain rfl : n = 0 := not_ne_iff.1 fun hn ↦ ne_of_gt (Nat.one_lt_pow hn (by decide)) this - rw [add_zero] + induction n with + | zero => simp [shiftLeft'] + | succ n IH => + simp only [shiftLeft', ne_eq] at h ⊢ + rw [size_bit h, Nat.add_succ] + by_cases s0 : shiftLeft' b m n = 0 + case neg => rw [IH s0] + rw [s0] at h ⊢ + cases b; · exact absurd rfl h + have : shiftLeft' true m n + 1 = 1 := congr_arg (· + 1) s0 + rw [shiftLeft'_tt_eq_mul_pow] at this + obtain rfl := succ.inj (eq_one_of_dvd_one ⟨_, this.symm⟩) + simp only [zero_add, one_mul] at this + obtain rfl : n = 0 := not_ne_iff.1 fun hn ↦ ne_of_gt (Nat.one_lt_pow hn (by decide)) this + rw [add_zero] -- TODO: decide whether `Nat.shiftLeft_eq` (which rewrites the LHS into a power) should be a simp -- lemma; it was not in mathlib3. Until then, tell the simpNF linter to ignore the issue. @@ -99,9 +100,10 @@ theorem size_le {m n : ℕ} : size m ≤ n ↔ m < 2 ^ n := by_cases e : bit b m = 0 · simp [e] rw [size_bit e] - cases' n with n - · exact e.elim (Nat.eq_zero_of_le_zero (le_of_lt_succ h)) - · apply succ_le_succ (IH _) + cases n with + | zero => exact e.elim (Nat.eq_zero_of_le_zero (le_of_lt_succ h)) + | succ n => + apply succ_le_succ (IH _) apply Nat.lt_of_mul_lt_mul_left (a := 2) simp only [shiftLeft_succ] at * refine lt_of_le_of_lt ?_ h @@ -123,9 +125,11 @@ theorem size_le_size {m n : ℕ} (h : m ≤ n) : size m ≤ size n := size_le.2 <| lt_of_le_of_lt h (lt_size_self _) theorem size_eq_bits_len (n : ℕ) : n.bits.length = n.size := by - induction' n using Nat.binaryRec' with b n h ih; · simp - rw [size_bit, bits_append_bit _ _ h] - · simp [ih] - · simpa [bit_eq_zero_iff] + induction n using Nat.binaryRec' with + | z => simp + | f _ _ h ih => + rw [size_bit, bits_append_bit _ _ h] + · simp [ih] + · simpa [bit_eq_zero_iff] end Nat diff --git a/Mathlib/Data/Nat/Sqrt.lean b/Mathlib/Data/Nat/Sqrt.lean new file mode 100644 index 0000000000000..d5ebe7765840f --- /dev/null +++ b/Mathlib/Data/Nat/Sqrt.lean @@ -0,0 +1,210 @@ +/- +Copyright (c) 2014 Floris van Doorn (c) 2016 Microsoft Corporation. All rights reserved. +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.Data.Nat.Defs +import Batteries.Data.Nat.Basic + +/-! +# Properties of the natural number square root function. +-/ + +namespace Nat + +/- We don't want to import the algebraic hierarchy in this file. -/ +assert_not_exists Monoid + +variable {m n a : ℕ} + +/-! +### `sqrt` + +See [Wikipedia, *Methods of computing square roots*] +(https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_(base_2)). +-/ + +private lemma iter_fp_bound (n k : ℕ) : + let iter_next (n guess : ℕ) := (guess + n / guess) / 2; + sqrt.iter n k ≤ iter_next n (sqrt.iter n k) := by + intro iter_next + unfold sqrt.iter + if h : (k + n / k) / 2 < k then + simpa [if_pos h] using iter_fp_bound _ _ + else + simpa [if_neg h] using Nat.le_of_not_lt h + +private lemma AM_GM : {a b : ℕ} → (4 * a * b ≤ (a + b) * (a + b)) + | 0, _ => by rw [Nat.mul_zero, Nat.zero_mul]; exact zero_le _ + | _, 0 => by rw [Nat.mul_zero]; exact zero_le _ + | a + 1, b + 1 => by + simpa only [Nat.mul_add, Nat.add_mul, show (4 : ℕ) = 1 + 1 + 1 + 1 from rfl, Nat.one_mul, + Nat.mul_one, Nat.add_assoc, Nat.add_left_comm, Nat.add_le_add_iff_left] + using Nat.add_le_add_right (@AM_GM a b) 4 + +-- These two lemmas seem like they belong to `Batteries.Data.Nat.Basic`. + +lemma sqrt.iter_sq_le (n guess : ℕ) : sqrt.iter n guess * sqrt.iter n guess ≤ n := by + unfold sqrt.iter + let next := (guess + n / guess) / 2 + if h : next < guess then + simpa only [dif_pos h] using sqrt.iter_sq_le n next + else + simp only [dif_neg h] + apply Nat.mul_le_of_le_div + apply Nat.le_of_add_le_add_left (a := guess) + rw [← Nat.mul_two, ← le_div_iff_mul_le] + · exact Nat.le_of_not_lt h + · exact Nat.zero_lt_two + +lemma sqrt.lt_iter_succ_sq (n guess : ℕ) (hn : n < (guess + 1) * (guess + 1)) : + n < (sqrt.iter n guess + 1) * (sqrt.iter n guess + 1) := by + unfold sqrt.iter + -- m was `next` + let m := (guess + n / guess) / 2 + dsimp + split_ifs with h + · suffices n < (m + 1) * (m + 1) by + simpa only [dif_pos h] using sqrt.lt_iter_succ_sq n m this + refine Nat.lt_of_mul_lt_mul_left ?_ (a := 4 * (guess * guess)) + apply Nat.lt_of_le_of_lt AM_GM + rw [show (4 : ℕ) = 2 * 2 from rfl] + rw [Nat.mul_mul_mul_comm 2, Nat.mul_mul_mul_comm (2 * guess)] + refine Nat.mul_self_lt_mul_self (?_ : _ < _ * ((_ / 2) + 1)) + rw [← add_div_right _ (by decide), Nat.mul_comm 2, Nat.mul_assoc, + show guess + n / guess + 2 = (guess + n / guess + 1) + 1 from rfl] + have aux_lemma {a : ℕ} : a ≤ 2 * ((a + 1) / 2) := by omega + refine lt_of_lt_of_le ?_ (Nat.mul_le_mul_left _ aux_lemma) + rw [Nat.add_assoc, Nat.mul_add] + exact Nat.add_lt_add_left (lt_mul_div_succ _ (lt_of_le_of_lt (Nat.zero_le m) h)) _ + · simpa only [dif_neg h] using hn +-- Porting note: the implementation of `Nat.sqrt` in `Batteries` no longer needs `sqrt_aux`. +private def IsSqrt (n q : ℕ) : Prop := + q * q ≤ n ∧ n < (q + 1) * (q + 1) +-- Porting note: as the definition of square root has changed, +-- the proof of `sqrt_isSqrt` is attempted from scratch. +/- +Sketch of proof: +Up to rounding, in terms of the definition of `sqrt.iter`, + +* By AM-GM inequality, `next² ≥ n` giving one of the bounds. +* When we terminated, we have `guess ≥ next` from which we deduce the other bound `n ≥ next²`. + +To turn this into a lean proof we need to manipulate, use properties of natural number division etc. +-/ +private lemma sqrt_isSqrt (n : ℕ) : IsSqrt n (sqrt n) := by + match n with + | 0 => simp [IsSqrt, sqrt] + | 1 => simp [IsSqrt, sqrt] + | n + 2 => + have h : ¬ (n + 2) ≤ 1 := by simp + simp only [IsSqrt, sqrt, h, ite_false] + refine ⟨sqrt.iter_sq_le _ _, sqrt.lt_iter_succ_sq _ _ ?_⟩ + simp only [Nat.mul_add, Nat.add_mul, Nat.one_mul, Nat.mul_one, ← Nat.add_assoc] + rw [Nat.lt_add_one_iff, Nat.add_assoc, ← Nat.mul_two] + refine le_trans (Nat.le_of_eq (div_add_mod' (n + 2) 2).symm) ?_ + rw [Nat.add_comm, Nat.add_le_add_iff_right, add_mod_right] + simp only [Nat.zero_lt_two, add_div_right, succ_mul_succ] + refine le_trans (b := 1) ?_ ?_ + · exact (lt_succ.1 <| mod_lt n Nat.zero_lt_two) + · exact Nat.le_add_left _ _ + +lemma sqrt_le (n : ℕ) : sqrt n * sqrt n ≤ n := (sqrt_isSqrt n).left + +lemma sqrt_le' (n : ℕ) : sqrt n ^ 2 ≤ n := by simpa [Nat.pow_two] using sqrt_le n + +lemma lt_succ_sqrt (n : ℕ) : n < succ (sqrt n) * succ (sqrt n) := (sqrt_isSqrt n).right + +lemma lt_succ_sqrt' (n : ℕ) : n < succ (sqrt n) ^ 2 := by simpa [Nat.pow_two] using lt_succ_sqrt n + +lemma sqrt_le_add (n : ℕ) : n ≤ sqrt n * sqrt n + sqrt n + sqrt n := by + rw [← succ_mul]; exact le_of_lt_succ (lt_succ_sqrt n) + +lemma le_sqrt : m ≤ sqrt n ↔ m * m ≤ n := + ⟨fun h ↦ le_trans (mul_self_le_mul_self h) (sqrt_le n), + fun h ↦ le_of_lt_succ <| Nat.mul_self_lt_mul_self_iff.1 <| lt_of_le_of_lt h (lt_succ_sqrt n)⟩ + +lemma le_sqrt' : m ≤ sqrt n ↔ m ^ 2 ≤ n := by simpa only [Nat.pow_two] using le_sqrt + +lemma sqrt_lt : sqrt m < n ↔ m < n * n := by simp only [← not_le, le_sqrt] + +lemma sqrt_lt' : sqrt m < n ↔ m < n ^ 2 := by simp only [← not_le, le_sqrt'] + +lemma sqrt_le_self (n : ℕ) : sqrt n ≤ n := le_trans (le_mul_self _) (sqrt_le n) + +lemma sqrt_le_sqrt (h : m ≤ n) : sqrt m ≤ sqrt n := le_sqrt.2 (le_trans (sqrt_le _) h) + +@[simp] lemma sqrt_zero : sqrt 0 = 0 := rfl + +@[simp] lemma sqrt_one : sqrt 1 = 1 := rfl + +lemma sqrt_eq_zero : sqrt n = 0 ↔ n = 0 := + ⟨fun h ↦ + Nat.eq_zero_of_le_zero <| le_of_lt_succ <| (@sqrt_lt n 1).1 <| by rw [h]; decide, + by rintro rfl; simp⟩ + +lemma eq_sqrt : a = sqrt n ↔ a * a ≤ n ∧ n < (a + 1) * (a + 1) := + ⟨fun e ↦ e.symm ▸ sqrt_isSqrt n, + fun ⟨h₁, h₂⟩ ↦ le_antisymm (le_sqrt.2 h₁) (le_of_lt_succ <| sqrt_lt.2 h₂)⟩ + +lemma eq_sqrt' : a = sqrt n ↔ a ^ 2 ≤ n ∧ n < (a + 1) ^ 2 := by + simpa only [Nat.pow_two] using eq_sqrt + +lemma le_three_of_sqrt_eq_one (h : sqrt n = 1) : n ≤ 3 := + le_of_lt_succ <| (@sqrt_lt n 2).1 <| by rw [h]; decide + +lemma sqrt_lt_self (h : 1 < n) : sqrt n < n := + sqrt_lt.2 <| by have := Nat.mul_lt_mul_of_pos_left h (lt_of_succ_lt h); rwa [Nat.mul_one] at this + +lemma sqrt_pos : 0 < sqrt n ↔ 0 < n := + le_sqrt + +lemma sqrt_add_eq (n : ℕ) (h : a ≤ n + n) : sqrt (n * n + a) = n := + le_antisymm + (le_of_lt_succ <| + sqrt_lt.2 <| by + rw [succ_mul, mul_succ, add_succ, Nat.add_assoc] + exact lt_succ_of_le (Nat.add_le_add_left h _)) + (le_sqrt.2 <| Nat.le_add_right _ _) + +lemma sqrt_add_eq' (n : ℕ) (h : a ≤ n + n) : sqrt (n ^ 2 + a) = n := by + simpa [Nat.pow_two] using sqrt_add_eq n h + +lemma sqrt_eq (n : ℕ) : sqrt (n * n) = n := sqrt_add_eq n (zero_le _) + +lemma sqrt_eq' (n : ℕ) : sqrt (n ^ 2) = n := sqrt_add_eq' n (zero_le _) + +lemma sqrt_succ_le_succ_sqrt (n : ℕ) : sqrt n.succ ≤ n.sqrt.succ := + le_of_lt_succ <| sqrt_lt.2 <| lt_succ_of_le <| + succ_le_succ <| le_trans (sqrt_le_add n) <| Nat.add_le_add_right + (by refine add_le_add (Nat.mul_le_mul_right _ ?_) ?_ <;> exact Nat.le_add_right _ 2) _ + +lemma exists_mul_self (x : ℕ) : (∃ n, n * n = x) ↔ sqrt x * sqrt x = x := + ⟨fun ⟨n, hn⟩ ↦ by rw [← hn, sqrt_eq], fun h ↦ ⟨sqrt x, h⟩⟩ + +lemma exists_mul_self' (x : ℕ) : (∃ n, n ^ 2 = x) ↔ sqrt x ^ 2 = x := by + simpa only [Nat.pow_two] using exists_mul_self x + +lemma sqrt_mul_sqrt_lt_succ (n : ℕ) : sqrt n * sqrt n < n + 1 := + Nat.lt_succ_iff.mpr (sqrt_le _) + +lemma sqrt_mul_sqrt_lt_succ' (n : ℕ) : sqrt n ^ 2 < n + 1 := + Nat.lt_succ_iff.mpr (sqrt_le' _) + +lemma succ_le_succ_sqrt (n : ℕ) : n + 1 ≤ (sqrt n + 1) * (sqrt n + 1) := + le_of_pred_lt (lt_succ_sqrt _) + +lemma succ_le_succ_sqrt' (n : ℕ) : n + 1 ≤ (sqrt n + 1) ^ 2 := + le_of_pred_lt (lt_succ_sqrt' _) + +/-- There are no perfect squares strictly between m² and (m+1)² -/ +lemma not_exists_sq (hl : m * m < n) (hr : n < (m + 1) * (m + 1)) : ¬∃ t, t * t = n := by + rintro ⟨t, rfl⟩ + have h1 : m < t := Nat.mul_self_lt_mul_self_iff.1 hl + have h2 : t < m + 1 := Nat.mul_self_lt_mul_self_iff.1 hr + exact (not_lt_of_ge <| le_of_lt_succ h2) h1 + +lemma not_exists_sq' : m ^ 2 < n → n < (m + 1) ^ 2 → ¬∃ t, t ^ 2 = n := by + simpa only [Nat.pow_two] using not_exists_sq + +end Nat diff --git a/Mathlib/Data/Nat/Squarefree.lean b/Mathlib/Data/Nat/Squarefree.lean index 4f5bc89c79f72..d11d003343934 100644 --- a/Mathlib/Data/Nat/Squarefree.lean +++ b/Mathlib/Data/Nat/Squarefree.lean @@ -52,7 +52,7 @@ theorem _root_.Squarefree.natFactorization_le_one {n : ℕ} (p : ℕ) (hn : Squa rw [multiplicity.squarefree_iff_multiplicity_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] + simp only [multiplicity_eq_factorization hp hn', Nat.isUnit_iff, hp.ne_one, or_false] at this exact mod_cast this · rw [factorization_eq_zero_of_non_prime _ hp] @@ -87,7 +87,7 @@ theorem Squarefree.ext_iff {n m : ℕ} (hn : Squarefree n) (hm : Squarefree m) : · rwa [h₂, eq_comm, ← h₁] · rw [h₂, h₃.resolve_left] rw [← h₁, h₂] - simp only [Nat.one_ne_zero, not_false_iff] + simp only [Nat.one_ne_zero, not_false_iff, reduceCtorEq] rw [factorization_eq_zero_of_non_prime _ hp, factorization_eq_zero_of_non_prime _ hp] theorem squarefree_pow_iff {n k : ℕ} (hn : n ≠ 1) (hk : k ≠ 0) : diff --git a/Mathlib/Data/Nat/SuccPred.lean b/Mathlib/Data/Nat/SuccPred.lean index 262d0f7f1138c..8f04e28fb1012 100644 --- a/Mathlib/Data/Nat/SuccPred.lean +++ b/Mathlib/Data/Nat/SuccPred.lean @@ -4,8 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ import Mathlib.Algebra.Order.Ring.Nat +import Mathlib.Algebra.Order.SuccPred import Mathlib.Data.Fin.Basic -import Mathlib.Order.SuccPred.Basic +import Mathlib.Order.SuccPred.Archimedean /-! # Successors and predecessors of naturals @@ -23,6 +24,8 @@ variable {m n : ℕ} @[instance] abbrev instSuccOrder : SuccOrder ℕ := SuccOrder.ofSuccLeIff succ Nat.succ_le +instance instSuccAddOrder : SuccAddOrder ℕ := ⟨fun _ => rfl⟩ + -- so that Lean reads `Nat.pred` through `pred_order.pred` @[instance] abbrev instPredOrder : PredOrder ℕ where pred := pred @@ -35,10 +38,8 @@ variable {m n : ℕ} cases b · exact (a.not_lt_zero h).elim · exact le_of_succ_le_succ h - le_of_pred_lt {a} {b} h := by - cases a - · exact b.zero_le - · exact h + +instance instPredSubOrder : PredSubOrder ℕ := ⟨fun _ => rfl⟩ @[simp] theorem succ_eq_succ : Order.succ = succ := @@ -48,25 +49,22 @@ theorem succ_eq_succ : Order.succ = succ := theorem pred_eq_pred : Order.pred = pred := rfl -theorem succ_iterate (a : ℕ) : ∀ n, succ^[n] a = a + n - | 0 => rfl - | n + 1 => by - rw [Function.iterate_succ', add_succ] - exact congr_arg _ (succ_iterate a n) +protected theorem succ_iterate (a : ℕ) : ∀ n, succ^[n] a = a + n := + Order.succ_iterate a -theorem pred_iterate (a : ℕ) : ∀ n, pred^[n] a = a - n +protected theorem pred_iterate (a : ℕ) : ∀ n, pred^[n] a = a - n | 0 => rfl | n + 1 => by rw [Function.iterate_succ', sub_succ] - exact congr_arg _ (pred_iterate a n) + exact congr_arg _ (Nat.pred_iterate a n) lemma le_succ_iff_eq_or_le : m ≤ n.succ ↔ m = n.succ ∨ m ≤ n := Order.le_succ_iff_eq_or_le instance : IsSuccArchimedean ℕ := - ⟨fun {a} {b} h => ⟨b - a, by rw [succ_eq_succ, succ_iterate, add_tsub_cancel_of_le h]⟩⟩ + ⟨fun {a} {b} h => ⟨b - a, by rw [succ_eq_succ, Nat.succ_iterate, add_tsub_cancel_of_le h]⟩⟩ instance : IsPredArchimedean ℕ := - ⟨fun {a} {b} h => ⟨b - a, by rw [pred_eq_pred, pred_iterate, tsub_tsub_cancel_of_le h]⟩⟩ + ⟨fun {a} {b} h => ⟨b - a, by rw [pred_eq_pred, Nat.pred_iterate, tsub_tsub_cancel_of_le h]⟩⟩ lemma forall_ne_zero_iff (P : ℕ → Prop) : (∀ i, i ≠ 0 → P i) ↔ (∀ i, P (i + 1)) := @@ -75,8 +73,9 @@ lemma forall_ne_zero_iff (P : ℕ → Prop) : /-! ### Covering relation -/ +@[deprecated Order.covBy_iff_add_one_eq (since := "2024-09-04")] protected theorem covBy_iff_succ_eq {m n : ℕ} : m ⋖ n ↔ m + 1 = n := - succ_eq_iff_covBy.symm + covBy_iff_add_one_eq end Nat diff --git a/Mathlib/Data/Nat/Totient.lean b/Mathlib/Data/Nat/Totient.lean index 3bfd3d40e7e5c..ec08e85c219d9 100644 --- a/Mathlib/Data/Nat/Totient.lean +++ b/Mathlib/Data/Nat/Totient.lean @@ -8,6 +8,7 @@ import Mathlib.Data.Nat.Factorization.Basic import Mathlib.Data.Nat.Factorization.Induction import Mathlib.Data.Nat.Periodic import Mathlib.Data.ZMod.Basic +import Mathlib.NumberTheory.Divisors /-! # Euler's totient function @@ -76,7 +77,7 @@ theorem Ico_filter_coprime_le {a : ℕ} (k n : ℕ) (a_pos : 0 < a) : induction' n / a with i ih · rw [← filter_coprime_Ico_eq_totient a k] simp only [add_zero, mul_one, mul_zero, le_of_lt (mod_lt n a_pos), - Nat.zero_eq, zero_add] + zero_add] gcongr exact Ico_subset_Ico rfl.le (add_le_add_left (le_of_lt (mod_lt n a_pos)) k) simp only [mul_succ] @@ -228,7 +229,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 @@ -244,7 +245,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/Nat/Upto.lean b/Mathlib/Data/Nat/Upto.lean index 47b6802fa1c14..f62ea9e9062d1 100644 --- a/Mathlib/Data/Nat/Upto.lean +++ b/Mathlib/Data/Nat/Upto.lean @@ -28,7 +28,7 @@ no `j` less than `i` satisfies `p`. This is an initial segment of the natural numbers, up to and including the first value satisfying `p`. We will be particularly interested in the case where there exists a value -satisfying `p`, because in this case the `>` relation is well-founded. -/ +satisfying `p`, because in this case the `>` relation is well-founded. -/ abbrev Upto (p : ℕ → Prop) : Type := { i : ℕ // ∀ j < i, ¬p j } diff --git a/Mathlib/Data/Num/Basic.lean b/Mathlib/Data/Num/Basic.lean index 1353fdd100589..5e35ca5550ad8 100644 --- a/Mathlib/Data/Num/Basic.lean +++ b/Mathlib/Data/Num/Basic.lean @@ -169,33 +169,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 +587,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 54d7f68a2f02a..c95ab439e4cf4 100644 --- a/Mathlib/Data/Num/Lemmas.lean +++ b/Mathlib/Data/Num/Lemmas.lean @@ -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]) @@ -863,11 +863,11 @@ theorem castNum_testBit (m n) : testBit m n = Nat.testBit m n := by | pos m => rw [cast_pos] induction' n with n IH generalizing m <;> cases' m with m m - <;> dsimp only [PosNum.testBit, Nat.zero_eq] + <;> dsimp only [PosNum.testBit] · 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] @@ -1576,3 +1576,5 @@ instance SNum.lt : LT SNum := instance SNum.le : LE SNum := ⟨fun a b => (a : ℤ) ≤ b⟩ + +set_option linter.style.longFile 1700 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 db3660d4695ba..b0bab527487d9 100644 --- a/Mathlib/Data/Option/Basic.lean +++ b/Mathlib/Data/Option/Basic.lean @@ -137,29 +137,12 @@ 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 @@ -194,40 +177,20 @@ theorem pbind_eq_none {f : ∀ a : α, a ∈ x → Option β} (h' : ∀ a (H : a ∈ x), f a H = none → x = none) : x.pbind f = none ↔ x = none := by cases x · simp - · simp only [pbind, iff_false] + · simp only [pbind, iff_false, reduceCtorEq] intro h cases h' _ rfl h theorem pbind_eq_some {f : ∀ a : α, a ∈ x → Option β} {y : β} : x.pbind f = some y ↔ ∃ (z : α) (H : z ∈ x), f z H = some y := by rcases x with (_|x) - · simp only [pbind, false_iff, not_exists] - intro z h - simp at h + · simp · simp only [pbind] refine ⟨fun h ↦ ⟨x, rfl, h⟩, ?_⟩ rintro ⟨z, H, hz⟩ 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] - · 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) : @@ -253,11 +216,6 @@ theorem orElse_none' (x : Option α) : x.orElse (fun _ ↦ none) = x := by cases theorem exists_ne_none {p : Option α → Prop} : (∃ x ≠ none, p x) ↔ (∃ x : α, p x) := by simp only [← exists_prop, bex_ne_none] -@[simp] -theorem get_map (f : α → β) {o : Option α} (h : isSome (o.map f)) : - (o.map f).get h = f (o.get (by rwa [← isSome_map'])) := by - cases o <;> [simp at h; rfl] - theorem iget_mem [Inhabited α] : ∀ {o : Option α}, isSome o → o.iget ∈ o | some _, _ => rfl @@ -311,8 +269,8 @@ compile_inductive% Option theorem orElse_eq_some (o o' : Option α) (x : α) : (o <|> o') = some x ↔ o = some x ∨ o = none ∧ o' = some x := by cases o - · simp only [true_and, false_or, eq_self_iff_true, none_orElse] - · simp only [some_orElse, or_false, false_and] + · simp only [true_and, false_or, eq_self_iff_true, none_orElse, reduceCtorEq] + · simp only [some_orElse, or_false, false_and, reduceCtorEq] theorem orElse_eq_some' (o o' : Option α) (x : α) : @@ -323,7 +281,7 @@ theorem orElse_eq_some' (o o' : Option α) (x : α) : theorem orElse_eq_none (o o' : Option α) : (o <|> o') = none ↔ o = none ∧ o' = none := by cases o · simp only [true_and, none_orElse, eq_self_iff_true] - · simp only [some_orElse, false_and] + · simp only [some_orElse, reduceCtorEq, false_and] @[simp] theorem orElse_eq_none' (o o' : Option α) : o.orElse (fun _ ↦ o') = none ↔ o = none ∧ o' = none := @@ -355,7 +313,6 @@ theorem elim_apply {f : γ → α → β} {x : α → β} {i : Option γ} {y : @[simp] lemma bnot_isSome (a : Option α) : (! a.isSome) = a.isNone := by - funext cases a <;> simp @[simp] @@ -365,7 +322,6 @@ lemma bnot_comp_isSome : (! ·) ∘ @Option.isSome α = Option.isNone := by @[simp] lemma bnot_isNone (a : Option α) : (! a.isNone) = a.isSome := by - funext cases a <;> simp @[simp] diff --git a/Mathlib/Data/Option/Defs.lean b/Mathlib/Data/Option/Defs.lean index df47456532460..c15bedf853135 100644 --- a/Mathlib/Data/Option/Defs.lean +++ b/Mathlib/Data/Option/Defs.lean @@ -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]⟩ @@ -99,3 +95,5 @@ instance liftOrGet_isId (f : α → α → α) : Std.LawfulIdentity (liftOrGet f def _root_.Lean.LOption.toOption {α} : Lean.LOption α → Option α | .some a => some a | _ => none + +end Option diff --git a/Mathlib/Data/Ordering/Basic.lean b/Mathlib/Data/Ordering/Basic.lean index 64950a0331059..45c2f5778c1d4 100644 --- a/Mathlib/Data/Ordering/Basic.lean +++ b/Mathlib/Data/Ordering/Basic.lean @@ -3,7 +3,9 @@ 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 /-! # Helper definitions and instances for `Ordering` @@ -15,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/Ordering/Lemmas.lean b/Mathlib/Data/Ordering/Lemmas.lean index 2fd0f777cc70d..7b9714aa85ed5 100644 --- a/Mathlib/Data/Ordering/Lemmas.lean +++ b/Mathlib/Data/Ordering/Lemmas.lean @@ -3,8 +3,8 @@ 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.Algebra.Classes import Mathlib.Data.Ordering.Basic +import Mathlib.Order.Defs /-! # Some `Ordering` lemmas @@ -39,12 +39,12 @@ attribute [local simp] cmpUsing @[simp] theorem cmpUsing_eq_lt (a b : α) : (cmpUsing lt a b = Ordering.lt) = lt a b := by - simp only [cmpUsing, Ordering.ite_eq_lt_distrib, ite_self, if_false_right, and_true] + simp only [cmpUsing, Ordering.ite_eq_lt_distrib, ite_self, if_false_right, and_true, reduceCtorEq] @[simp] theorem cmpUsing_eq_gt [IsStrictOrder α lt] (a b : α) : cmpUsing lt a b = Ordering.gt ↔ lt b a := by simp only [cmpUsing, Ordering.ite_eq_gt_distrib, if_false_right, and_true, if_false_left, - and_iff_right_iff_imp] + and_iff_right_iff_imp, reduceCtorEq] exact fun hba hab ↦ (irrefl a) (_root_.trans hab hba) @[simp] diff --git a/Mathlib/Data/Ordmap/Ordnode.lean b/Mathlib/Data/Ordmap/Ordnode.lean index b72b6d54b107b..31245ed62ad9a 100644 --- a/Mathlib/Data/Ordmap/Ordnode.lean +++ b/Mathlib/Data/Ordmap/Ordnode.lean @@ -183,27 +183,27 @@ O(1). Rebalance a tree which was previously balanced but has had its left side grow by 1, or its right side shrink by 1. -/ def balanceL (l : Ordnode α) (x : α) (r : Ordnode α) : Ordnode α := by -- Porting note: removed `clean` - cases' id r with rs - · cases' id l with ls ll lx lr + rcases id r with _ | rs + · rcases id l with _ | ⟨ls, ll, lx, lr⟩ · exact ι x - · cases' id ll with lls - · cases' lr with _ _ lrx + · rcases id ll with _ | lls + · rcases lr with _ | ⟨_, _, lrx⟩ · exact node 2 l x nil · exact node 3 (ι lx) lrx ι x - · cases' id lr with lrs lrl lrx lrr + · rcases id lr with _ | ⟨lrs, lrl, lrx, lrr⟩ · exact node 3 ll lx ι x · exact if lrs < ratio * lls then node (ls + 1) ll lx (node (lrs + 1) lr x nil) else node (ls + 1) (node (lls + size lrl + 1) ll lx lrl) lrx (node (size lrr + 1) lrr x nil) - · cases' id l with ls ll lx lr + · rcases id l with _ | ⟨ls, ll, lx, lr⟩ · exact node (rs + 1) nil x r · refine if ls > delta * rs then ?_ else node (ls + rs + 1) l x r - cases' id ll with lls + rcases id ll with _ | lls · exact nil --should not happen - cases' id lr with lrs lrl lrx lrr + rcases id lr with _ | ⟨lrs, lrl, lrx, lrr⟩ · exact nil --should not happen exact @@ -218,27 +218,27 @@ O(1). Rebalance a tree which was previously balanced but has had its right side grow by 1, or its left side shrink by 1. -/ def balanceR (l : Ordnode α) (x : α) (r : Ordnode α) : Ordnode α := by -- Porting note: removed `clean` - cases' id l with ls - · cases' id r with rs rl rx rr + rcases id l with _ | ls + · rcases id r with _ | ⟨rs, rl, rx, rr⟩ · exact ι x - · cases' id rr with rrs - · cases' rl with _ _ rlx + · rcases id rr with _ | rrs + · rcases rl with _ | ⟨_, _, rlx⟩ · exact node 2 nil x r · exact node 3 (ι x) rlx ι rx - · cases' id rl with rls rll rlx rlr + · rcases id rl with _ | ⟨rls, rll, rlx, rlr⟩ · exact node 3 (ι x) rx rr · exact if rls < ratio * rrs then node (rs + 1) (node (rls + 1) nil x rl) rx rr else node (rs + 1) (node (size rll + 1) nil x rll) rlx (node (size rlr + rrs + 1) rlr rx rr) - · cases' id r with rs rl rx rr + · rcases id r with _ | ⟨rs, rl, rx, rr⟩ · exact node (ls + 1) l x nil · refine if rs > delta * ls then ?_ else node (ls + rs + 1) l x r - cases' id rr with rrs + rcases id rr with _ | rrs · exact nil --should not happen - cases' id rl with rls rll rlx rlr + rcases id rl with _ | ⟨rls, rll, rlx, rlr⟩ · exact nil --should not happen exact @@ -253,26 +253,26 @@ O(1). Rebalance a tree which was previously balanced but has had one side change by at most 1. -/ def balance (l : Ordnode α) (x : α) (r : Ordnode α) : Ordnode α := by -- Porting note: removed `clean` - cases' id l with ls ll lx lr - · cases' id r with rs rl rx rr + rcases id l with _ | ⟨ls, ll, lx, lr⟩ + · rcases id r with _ | ⟨rs, rl, rx, rr⟩ · exact ι x - · cases' id rl with rls rll rlx rlr + · rcases id rl with _ | ⟨rls, rll, rlx, rlr⟩ · cases id rr · exact node 2 nil x r · exact node 3 (ι x) rx rr - · cases' id rr with rrs + · rcases id rr with _ | rrs · exact node 3 (ι x) rlx ι rx · exact if rls < ratio * rrs then node (rs + 1) (node (rls + 1) nil x rl) rx rr else node (rs + 1) (node (size rll + 1) nil x rll) rlx (node (size rlr + rrs + 1) rlr rx rr) - · cases' id r with rs rl rx rr - · cases' id ll with lls - · cases' lr with _ _ lrx + · rcases id r with _ | ⟨rs, rl, rx, rr⟩ + · rcases id ll with _ | lls + · rcases lr with _ | ⟨_, _, lrx⟩ · exact node 2 l x nil · exact node 3 (ι lx) lrx ι x - · cases' id lr with lrs lrl lrx lrr + · rcases id lr with _ | ⟨lrs, lrl, lrx, lrr⟩ · exact node 3 ll lx ι x · exact if lrs < ratio * lls then node (ls + 1) ll lx (node (lrs + 1) lr x nil) @@ -281,10 +281,10 @@ def balance (l : Ordnode α) (x : α) (r : Ordnode α) : Ordnode α := by (node (size lrr + 1) lrr x nil) · refine if delta * ls < rs then ?_ else if delta * rs < ls then ?_ else node (ls + rs + 1) l x r - · cases' id rl with rls rll rlx rlr + · rcases id rl with _ | ⟨rls, rll, rlx, rlr⟩ · exact nil --should not happen - cases' id rr with rrs + rcases id rr with _ | rrs · exact nil --should not happen exact @@ -292,10 +292,10 @@ def balance (l : Ordnode α) (x : α) (r : Ordnode α) : Ordnode α := by else node (ls + rs + 1) (node (ls + size rll + 1) l x rll) rlx (node (size rlr + rrs + 1) rlr rx rr) - · cases' id ll with lls + · rcases id ll with _ | lls · exact nil --should not happen - cases' id lr with lrs lrl lrx lrr + rcases id lr with _ | ⟨lrs, lrl, lrx, lrr⟩ · exact nil --should not happen exact @@ -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. @@ -845,7 +846,7 @@ def find (x : α) : Ordnode α → Option α | Ordering.gt => find x r instance : Membership α (Ordnode α) := - ⟨fun x t => t.mem x⟩ + ⟨fun t x => t.mem x⟩ instance mem.decidable (x : α) (t : Ordnode α) : Decidable (x ∈ t) := Bool.decEq _ _ diff --git a/Mathlib/Data/Ordmap/Ordset.lean b/Mathlib/Data/Ordmap/Ordset.lean index fc25de56b3862..ca4d7b8c2efab 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 @@ -530,12 +530,12 @@ theorem splitMax_eq : | _, l, x, 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₃ @@ -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 @@ -1556,7 +1556,7 @@ def find (x : α) (s : Ordset α) : Option α := Ordnode.find x s.val instance instMembership : Membership α (Ordset α) := - ⟨fun x s => mem x s⟩ + ⟨fun s x => mem x s⟩ instance mem.decidable (x : α) (s : Ordset α) : Decidable (x ∈ s) := instDecidableEqBool _ _ @@ -1578,3 +1578,5 @@ def map {β} [Preorder β] (f : α → β) (f_strict_mono : StrictMono f) (s : O ⟨Ordnode.map f s.val, Ordnode.map.valid f_strict_mono s.property⟩ end Ordset + +set_option linter.style.longFile 1700 diff --git a/Mathlib/Data/PEquiv.lean b/Mathlib/Data/PEquiv.lean index 539fbcf90563e..920084d283b41 100644 --- a/Mathlib/Data/PEquiv.lean +++ b/Mathlib/Data/PEquiv.lean @@ -118,7 +118,7 @@ theorem symm_refl : (PEquiv.refl α).symm = PEquiv.refl α := rfl @[simp] -theorem symm_symm (f : α ≃. β) : f.symm.symm = f := by cases f; rfl +theorem symm_symm (f : α ≃. β) : f.symm.symm = f := rfl theorem symm_bijective : Function.Bijective (PEquiv.symm : (α ≃. β) → β ≃. α) := Function.bijective_iff_has_inverse.mpr ⟨_, symm_symm, symm_symm⟩ @@ -201,7 +201,7 @@ theorem mem_ofSet_iff {s : Set α} [DecidablePred (· ∈ s)] {a b : α} : · simp only [mem_def, eq_comm, some.injEq, iff_self_and] rintro rfl exact h - · simp only [mem_def, false_iff, not_and] + · simp only [mem_def, false_iff, not_and, reduceCtorEq] rintro rfl exact h @@ -294,9 +294,9 @@ def single (a : α) (b : β) : dsimp only split_ifs with h1 h2 · simp [*] - · simp only [mem_def, some.injEq, iff_false] at * + · simp only [mem_def, some.injEq, iff_false, reduceCtorEq] at * exact Ne.symm h2 - · simp only [mem_def, some.injEq, false_iff] at * + · simp only [mem_def, some.injEq, false_iff, reduceCtorEq] at * exact Ne.symm h1 · simp @@ -343,7 +343,7 @@ theorem trans_single_of_eq_none {b : β} (c : γ) {f : δ ≃. β} (h : f.symm b ext simp only [eq_none_iff_forall_not_mem, Option.mem_def, f.eq_some_iff] at h dsimp [PEquiv.trans, single] - simp only [mem_def, bind_eq_some, iff_false, not_exists, not_and] + simp only [mem_def, bind_eq_some, iff_false, not_exists, not_and, reduceCtorEq] intros split_ifs <;> simp_all @@ -367,7 +367,7 @@ instance instPartialOrderPEquiv : PartialOrder (α ≃. β) where ext (by intro a - cases' h : g a with b + rcases h : g a with _ | b · exact eq_none_iff_forall_not_mem.2 fun b hb => Option.not_mem_none b <| h ▸ fg a b hb · exact gf _ _ h) @@ -390,7 +390,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 3e342591b8463..376018c747f3e 100644 --- a/Mathlib/Data/PFun.lean +++ b/Mathlib/Data/PFun.lean @@ -58,7 +58,7 @@ open Function def PFun (α β : Type*) := α → Part β -/-- `α →. β` is notation for the type `PFun α β` of partial functions from `α` to `β`. -/ +/-- `α →. β` is notation for the type `PFun α β` of partial functions from `α` to `β`. -/ infixr:25 " →. " => PFun namespace PFun @@ -286,7 +286,7 @@ def fixInduction {C : α → Sort*} {f : α →. β ⊕ α} {b : β} {a : α} (h have h₂ := (Part.mem_assert_iff.1 h).snd generalize_proofs at h₂ clear h - induction' ‹Acc _ _› with a ha IH + induction ‹Acc _ _› with | intro a ha IH => _ have h : b ∈ f.fix a := Part.mem_assert_iff.2 ⟨⟨a, ha⟩, h₂⟩ exact H a h fun a' fa' => IH a' fa' (Part.mem_assert_iff.1 (fix_fwd h fa')).snd @@ -545,7 +545,7 @@ theorem mem_prodLift {f : α →. β} {g : α →. γ} {x : α} {y : β × γ} : trans ∃ hp hq, (f x).get hp = y.1 ∧ (g x).get hq = y.2 · simp only [prodLift, Part.mem_mk_iff, And.exists, Prod.ext_iff] -- Porting note: was just `[exists_and_left, exists_and_right]` - · simp only [exists_and_left, exists_and_right, (· ∈ ·), Part.Mem] + · simp only [exists_and_left, exists_and_right, Membership.mem, Part.Mem] /-- Product of partial functions. -/ def prodMap (f : α →. γ) (g : β →. δ) : α × β →. γ × δ := fun x => @@ -569,7 +569,7 @@ theorem mem_prodMap {f : α →. γ} {g : β →. δ} {x : α × β} {y : γ × y ∈ f.prodMap g x ↔ y.1 ∈ f x.1 ∧ y.2 ∈ g x.2 := by trans ∃ hp hq, (f x.1).get hp = y.1 ∧ (g x.2).get hq = y.2 · simp only [prodMap, Part.mem_mk_iff, And.exists, Prod.ext_iff] - · simp only [exists_and_left, exists_and_right, (· ∈ ·), Part.Mem] + · simp only [exists_and_left, exists_and_right, Membership.mem, Part.Mem] @[simp] theorem prodLift_fst_comp_snd_comp (f : α →. γ) (g : β →. δ) : diff --git a/Mathlib/Data/PFunctor/Multivariate/M.lean b/Mathlib/Data/PFunctor/Multivariate/M.lean index 8a40846b7c6fc..cb6ed15fd11ac 100644 --- a/Mathlib/Data/PFunctor/Multivariate/M.lean +++ b/Mathlib/Data/PFunctor/Multivariate/M.lean @@ -58,7 +58,7 @@ variable {n : ℕ} (P : MvPFunctor.{u} (n + 1)) /-- A path from the root of a tree to one of its node -/ inductive M.Path : P.last.M → Fin2 n → Type u - | root (x : P.last.M) + | root (x : P.last.M) (a : P.A) (f : P.last.B a → P.last.M) (h : PFunctor.M.dest x = ⟨a, f⟩) @@ -268,21 +268,21 @@ theorem M.bisim₀ {α : TypeVec n} (R : P.M α → P.M α → Prop) (h₀ : Equ intro i replace h₁ := congr_fun (congr_fun h₁ Fin2.fz) i simp only [TypeVec.comp, appendFun, splitFun] at h₁ - replace h₁ := Quot.exact _ h₁ + replace h₁ := Quot.eqvGen_exact h₁ rw [h₀.eqvGen_iff] at h₁ exact h₁ theorem M.bisim' {α : TypeVec n} (R : P.M α → P.M α → Prop) (h : ∀ x y, R x y → (id ::: Quot.mk R) <$$> M.dest _ x = (id ::: Quot.mk R) <$$> M.dest _ y) (x y) (r : R x y) : x = y := by - have := M.bisim₀ P (EqvGen R) ?_ ?_ - · solve_by_elim [EqvGen.rel] - · apply EqvGen.is_equivalence + have := M.bisim₀ P (Relation.EqvGen R) ?_ ?_ + · solve_by_elim [Relation.EqvGen.rel] + · apply Relation.EqvGen.is_equivalence · clear r x y introv Hr - have : ∀ x y, R x y → EqvGen R x y := @EqvGen.rel _ R + have : ∀ x y, R x y → Relation.EqvGen R x y := @Relation.EqvGen.rel _ R induction Hr - · rw [← Quot.factor_mk_eq R (EqvGen R) this] + · rw [← Quot.factor_mk_eq R (Relation.EqvGen R) this] rwa [appendFun_comp_id, ← MvFunctor.map_map, ← MvFunctor.map_map, h] all_goals aesop diff --git a/Mathlib/Data/PFunctor/Multivariate/W.lean b/Mathlib/Data/PFunctor/Multivariate/W.lean index 449da825496bd..369a12fd42178 100644 --- a/Mathlib/Data/PFunctor/Multivariate/W.lean +++ b/Mathlib/Data/PFunctor/Multivariate/W.lean @@ -169,7 +169,7 @@ theorem wRec_eq {α : TypeVec n} {C : Type*} (g : ∀ a : P.A, P.drop.B a ⟹ α → (P.last.B a → P.W α) → (P.last.B a → C) → C) (a : P.A) (f' : P.drop.B a ⟹ α) (f : P.last.B a → P.W α) : P.wRec g (P.wMk a f' f) = g a f' f fun i => P.wRec g (f i) := by - rw [wMk, wRec]; dsimp; rw [wpRec_eq] + rw [wMk, wRec]; rw [wpRec_eq] dsimp only [wPathDestLeft_wPathCasesOn, wPathDestRight_wPathCasesOn] congr diff --git a/Mathlib/Data/PFunctor/Univariate/M.lean b/Mathlib/Data/PFunctor/Univariate/M.lean index f0339ae9be2d7..73fe251a4dda5 100644 --- a/Mathlib/Data/PFunctor/Univariate/M.lean +++ b/Mathlib/Data/PFunctor/Univariate/M.lean @@ -91,7 +91,7 @@ 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, true_and_iff, eq_self_iff_true, heq_iff_eq] + simp only [truncate, Function.comp_def, eq_self_iff_true, heq_iff_eq] -- Porting note: used to be `ext y` rename_i n_ih a f y h₁ suffices (fun x => truncate (y x)) = f @@ -281,9 +281,7 @@ theorem mk_dest (x : M F) : M.mk (dest x) = x := by cases' h : x.approx (succ n) with _ hd ch have h' : hd = head' (x.approx 1) := by rw [← head_succ' n, h, head'] - · split - injections - · apply x.consistent + apply x.consistent revert ch rw [h'] intros ch h @@ -481,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' @@ -490,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/Defs.lean b/Mathlib/Data/PNat/Defs.lean index beb992780ee62..6eb644184ac56 100644 --- a/Mathlib/Data/PNat/Defs.lean +++ b/Mathlib/Data/PNat/Defs.lean @@ -3,12 +3,12 @@ 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 import Mathlib.Tactic.Coe import Mathlib.Tactic.Lift -import Mathlib.Init.Data.Int.Order +import Mathlib.Data.Int.Order.Basic /-! # The positive natural numbers @@ -17,29 +17,11 @@ This file contains the definitions, and basic results. Most algebraic facts are deferred to `Data.PNat.Basic`, as they need more imports. -/ - -/-- `ℕ+` is the type of positive natural numbers. It is defined as a subtype, - and the VM representation of `ℕ+` is the same as `ℕ` because the proof - is not stored. -/ -def PNat := { n : ℕ // 0 < n } - deriving DecidableEq, LinearOrder - -@[inherit_doc] -notation "ℕ+" => PNat +deriving instance LinearOrder for PNat instance : One ℕ+ := ⟨⟨1, Nat.zero_lt_one⟩⟩ -/-- The underlying natural number -/ -@[coe] -def PNat.val : ℕ+ → ℕ := Subtype.val - -instance coePNatNat : Coe ℕ+ ℕ := - ⟨PNat.val⟩ - -instance : Repr ℕ+ := - ⟨fun n n' => reprPrec n.1 n'⟩ - instance (n : ℕ) [NeZero n] : OfNat ℕ+ n := ⟨⟨n, Nat.pos_of_ne_zero <| NeZero.ne n⟩⟩ diff --git a/Mathlib/Data/PNat/Factors.lean b/Mathlib/Data/PNat/Factors.lean index 80e5d15d4b64e..103a0f6a9d279 100644 --- a/Mathlib/Data/PNat/Factors.lean +++ b/Mathlib/Data/PNat/Factors.lean @@ -6,6 +6,7 @@ Authors: Neil Strickland import Mathlib.Algebra.BigOperators.Group.Multiset import Mathlib.Data.PNat.Prime import Mathlib.Data.Nat.Factors +import Mathlib.Data.Multiset.OrderedMonoid import Mathlib.Data.Multiset.Sort /-! @@ -188,7 +189,7 @@ theorem prod_add (u v : PrimeMultiset) : (u + v).prod = u.prod * v.prod := by theorem prod_smul (d : ℕ) (u : PrimeMultiset) : (d • u).prod = u.prod ^ d := by induction d with - | zero => simp only [Nat.zero_eq, zero_nsmul, pow_zero, prod_zero] + | zero => simp only [zero_nsmul, pow_zero, prod_zero] | succ n ih => rw [succ_nsmul, prod_add, ih, pow_succ] end PrimeMultiset diff --git a/Mathlib/Data/PNat/Interval.lean b/Mathlib/Data/PNat/Interval.lean index 4a310ffe979ce..f10b5ea85500c 100644 --- a/Mathlib/Data/PNat/Interval.lean +++ b/Mathlib/Data/PNat/Interval.lean @@ -53,35 +53,19 @@ theorem map_subtype_embedding_uIcc : (uIcc a b).map (Embedding.subtype _) = uIcc @[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] + 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] + 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] + 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] + rw [← Nat.card_Ioo, ← map_subtype_embedding_Ioo, card_map] @[simp] theorem card_uIcc : (uIcc a b).card = (b - a : ℤ).natAbs + 1 := by diff --git a/Mathlib/Data/PNat/Xgcd.lean b/Mathlib/Data/PNat/Xgcd.lean index 03c2d2cb0227d..f5c3a61a1fe5f 100644 --- a/Mathlib/Data/PNat/Xgcd.lean +++ b/Mathlib/Data/PNat/Xgcd.lean @@ -202,7 +202,7 @@ theorem flip_v : (flip u).v = u.v.swap := by · simp only ring -/-- Properties of division with remainder for a / b. -/ +/-- Properties of division with remainder for a / b. -/ theorem rq_eq : u.r + (u.bp + 1) * u.q = u.ap + 1 := Nat.mod_add_div (u.ap + 1) (u.bp + 1) diff --git a/Mathlib/Data/PSigma/Order.lean b/Mathlib/Data/PSigma/Order.lean index 097dd92225da5..fe0d6b8051e5b 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 diff --git a/Mathlib/Data/Part.lean b/Mathlib/Data/Part.lean index cdbd018a1d088..c4903f9bf5b4a 100644 --- a/Mathlib/Data/Part.lean +++ b/Mathlib/Data/Part.lean @@ -81,7 +81,7 @@ theorem eta : ∀ o : Part α, (⟨o.Dom, fun h => o.get h⟩ : Part α) = o | ⟨_, _⟩ => rfl /-- `a ∈ o` means that `o` is defined and equal to `a` -/ -protected def Mem (a : α) (o : Part α) : Prop := +protected def Mem (o : Part α) (a : α) : Prop := ∃ h, o.get h = a instance : Membership α (Part α) := diff --git a/Mathlib/Data/Prod/Basic.lean b/Mathlib/Data/Prod/Basic.lean index c384a20b1de7c..125f987461805 100644 --- a/Mathlib/Data/Prod/Basic.lean +++ b/Mathlib/Data/Prod/Basic.lean @@ -20,18 +20,14 @@ variable {α : Type*} {β : Type*} {γ : Type*} {δ : Type*} namespace Prod +def mk.injArrow {x₁ : α} {y₁ : β} {x₂ : α} {y₂ : β} : + (x₁, y₁) = (x₂, y₂) → ∀ ⦃P : Sort*⦄, (x₁ = x₂ → y₁ = y₂ → P) → P := + fun h₁ _ h₂ ↦ Prod.noConfusion h₁ h₂ + @[simp] theorem mk.eta : ∀ {p : α × β}, (p.1, p.2) = p | (_, _) => rfl -@[simp] -theorem «forall» {p : α × β → Prop} : (∀ x, p x) ↔ ∀ a b, p (a, b) := - ⟨fun h a b ↦ h (a, b), fun h ⟨a, b⟩ ↦ h a b⟩ - -@[simp] -theorem «exists» {p : α × β → Prop} : (∃ x, p x) ↔ ∃ a b, p (a, b) := - ⟨fun ⟨⟨a, b⟩, h⟩ ↦ ⟨a, b, h⟩, fun ⟨a, b, h⟩ ↦ ⟨⟨a, b⟩, h⟩⟩ - theorem forall' {p : α → β → Prop} : (∀ x : α × β, p x.1 x.2) ↔ ∀ a b, p a b := Prod.forall @@ -175,6 +171,10 @@ is equal to the composition of `Prod.swap` with `Prod.map g f`.-/ theorem map_comp_swap (f : α → β) (g : γ → δ) : Prod.map f g ∘ Prod.swap = Prod.swap ∘ Prod.map g f := rfl +theorem _root_.Function.Semiconj.swap_map (f : α → α) (g : β → β) : + Function.Semiconj swap (map f g) (map g f) := + Function.semiconj_iff_comp_eq.2 (map_comp_swap g f).symm + theorem eq_iff_fst_eq_snd_eq : ∀ {p q : α × β}, p = q ↔ p.1 = q.1 ∧ p.2 = q.2 | ⟨p₁, p₂⟩, ⟨q₁, q₂⟩ => by simp @@ -186,12 +186,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 d0d7a66835728..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,30 +29,26 @@ 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. -/ +/-- Dictionary / lexicographic ordering on pairs. -/ instance instLE (α β : Type*) [LT α] [LE β] : LE (α ×ₗ β) where le := Prod.Lex (· < ·) (· ≤ ·) instance instLT (α β : Type*) [LT α] [LT β] : LT (α ×ₗ β) where lt := Prod.Lex (· < ·) (· < ·) 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 @@ -118,23 +114,42 @@ theorem toLex_strictMono : StrictMono (toLex : α × β → α ×ₗ β) := by end Preorder /-- Dictionary / lexicographic partial order for pairs. -/ -instance partialOrder (α β : Type*) [PartialOrder α] [PartialOrder β] : PartialOrder (α ×ₗ β) := - { Prod.Lex.preorder α β with - le_antisymm := by - haveI : IsStrictOrder α (· < ·) := { irrefl := lt_irrefl, trans := fun _ _ _ => lt_trans } - haveI : IsAntisymm β (· ≤ ·) := ⟨fun _ _ => le_antisymm⟩ - exact @antisymm _ (Prod.Lex _ _) _ } +instance partialOrder (α β : Type*) [PartialOrder α] [PartialOrder β] : PartialOrder (α ×ₗ β) where + le_antisymm _ _ := by + haveI : IsStrictOrder α (· < ·) := { irrefl := lt_irrefl, trans := fun _ _ _ => lt_trans } + 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/Prod/PProd.lean b/Mathlib/Data/Prod/PProd.lean index bd9537e4bf646..dbbf70e0f9842 100644 --- a/Mathlib/Data/Prod/PProd.lean +++ b/Mathlib/Data/Prod/PProd.lean @@ -16,6 +16,10 @@ variable {α β γ δ : Sort*} namespace PProd +def mk.injArrow {α : Type*} {β : Type*} {x₁ : α} {y₁ : β} {x₂ : α} {y₂ : β} : + (x₁, y₁) = (x₂, y₂) → ∀ ⦃P : Sort*⦄, (x₁ = x₂ → y₁ = y₂ → P) → P := + fun h₁ _ h₂ ↦ Prod.noConfusion h₁ h₂ + @[simp] theorem mk.eta {p : PProd α β} : PProd.mk p.1 p.2 = p := rfl diff --git a/Mathlib/Data/QPF/Multivariate/Basic.lean b/Mathlib/Data/QPF/Multivariate/Basic.lean index a0d0fd66952f8..9c13a82349a20 100644 --- a/Mathlib/Data/QPF/Multivariate/Basic.lean +++ b/Mathlib/Data/QPF/Multivariate/Basic.lean @@ -69,7 +69,7 @@ matched because they preserve the properties of QPF. The latter example, each proves that some operations on functors preserves the QPF structure -/ -set_option linter.longLine false in +set_option linter.style.longLine false in /-! ## Reference diff --git a/Mathlib/Data/QPF/Multivariate/Constructions/Fix.lean b/Mathlib/Data/QPF/Multivariate/Constructions/Fix.lean index 7a6f0204617b0..284cbecc9b925 100644 --- a/Mathlib/Data/QPF/Multivariate/Constructions/Fix.lean +++ b/Mathlib/Data/QPF/Multivariate/Constructions/Fix.lean @@ -315,7 +315,7 @@ def Fix.drec {β : Fix F α → Type u} rhs rw [← ih] rw [MvFunctor.map_map, ← appendFun_comp, id_comp] - simp only [Function.comp] + simp only [Function.comp_def] cast (by rw [this]) y.2 end MvQPF diff --git a/Mathlib/Data/QPF/Univariate/Basic.lean b/Mathlib/Data/QPF/Univariate/Basic.lean index 3f3dbf6911b6b..b767d995bd81b 100644 --- a/Mathlib/Data/QPF/Univariate/Basic.lean +++ b/Mathlib/Data/QPF/Univariate/Basic.lean @@ -176,7 +176,7 @@ theorem recF_eq_of_Wequiv {α : Type u} (u : F α → α) (x y : q.P.W) : Wequiv x y → recF u x = recF u y := by intro h induction h with - | ind a f f' _ ih => simp only [recF_eq', PFunctor.map_eq, Function.comp, ih] + | ind a f f' _ ih => simp only [recF_eq', PFunctor.map_eq, Function.comp_def, ih] | abs a f a' f' h => simp only [recF_eq', abs_map, h] | trans x y z _ _ ih₁ ih₂ => exact Eq.trans ih₁ ih₂ diff --git a/Mathlib/Data/Quot.lean b/Mathlib/Data/Quot.lean index c78bf64552825..05fbfe253206f 100644 --- a/Mathlib/Data/Quot.lean +++ b/Mathlib/Data/Quot.lean @@ -3,15 +3,17 @@ 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.Data.Quot -import Mathlib.Logic.Relator +import Mathlib.Logic.Relation import Mathlib.Logic.Unique import Mathlib.Util.Notation3 /-! # Quotient types + This module extends the core library's treatment of quotient types (`Init.Core`). + ## Tags + quotient -/ @@ -19,8 +21,15 @@ 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 }) + +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 @@ -46,6 +55,9 @@ instance (r : α → α → Prop) [Inhabited α] : Inhabited (Quot r) := protected instance Subsingleton [Subsingleton α] : Subsingleton (Quot ra) := ⟨fun x ↦ Quot.induction_on x fun _ ↦ Quot.ind fun _ ↦ congr_arg _ (Subsingleton.elim _ _)⟩ +@[deprecated (since := "2024-08-26")] alias recOn' := Quot.recOn +@[deprecated (since := "2024-08-26")] alias recOnSubsingleton' := Quot.recOnSubsingleton + instance [Unique α] : Unique (Quot ra) := Unique.mk' _ /-- Recursion on two `Quotient` arguments `a` and `b`, result type depends on `⟦a⟧` and `⟦b⟧`. -/ @@ -97,7 +109,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) : γ := @@ -111,7 +122,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) : γ := @@ -187,7 +197,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, @@ -226,7 +236,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`. @@ -263,11 +273,11 @@ instance (q₁ : Quotient sa) (q₂ : Quotient sb) (f : α → β → Prop) end Quotient theorem Quot.eq {α : Type*} {r : α → α → Prop} {x y : α} : - Quot.mk r x = Quot.mk r y ↔ EqvGen r x y := - ⟨Quot.exact r, Quot.EqvGen_sound⟩ + Quot.mk r x = Quot.mk r y ↔ Relation.EqvGen r 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⟧ ↔ x ≈ y := ⟨Quotient.exact, Quotient.sound⟩ theorem Quotient.forall {α : Sort*} {s : Setoid α} {p : Quotient s → Prop} : @@ -279,29 +289,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 @@ -336,22 +346,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 : α) : (⟦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] @@ -377,18 +387,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)] @@ -439,7 +449,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 @@ -548,9 +557,8 @@ 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 @@ -565,10 +573,9 @@ 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] @@ -680,19 +687,19 @@ 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 @@ -704,12 +711,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 @@ -719,24 +726,24 @@ 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/CharZero.lean b/Mathlib/Data/Rat/Cast/CharZero.lean index a6ea0dbb7aa1b..f9e4f204e7d9b 100644 --- a/Mathlib/Data/Rat/Cast/CharZero.lean +++ b/Mathlib/Data/Rat/Cast/CharZero.lean @@ -10,21 +10,15 @@ import Mathlib.Data.Rat.Cast.Defs # Casts of rational numbers into characteristic zero fields (or division rings). -/ +open Function variable {F ι α β : Type*} namespace Rat +variable [DivisionRing α] [CharZero α] {p q : ℚ} -open Rat - -section WithDivRing - -variable [DivisionRing α] - -@[simp, norm_cast] -theorem cast_inj [CharZero α] : ∀ {m n : ℚ}, (m : α) = n ↔ m = n - | ⟨n₁, d₁, d₁0, c₁⟩, ⟨n₂, d₂, d₂0, c₂⟩ => by - refine ⟨fun h => ?_, congr_arg _⟩ +lemma cast_injective : Injective ((↑) : ℚ → α) + | ⟨n₁, d₁, d₁0, c₁⟩, ⟨n₂, d₂, d₂0, c₂⟩, h => by have d₁a : (d₁ : α) ≠ 0 := Nat.cast_ne_zero.2 d₁0 have d₂a : (d₂ : α) ≠ 0 := Nat.cast_ne_zero.2 d₂0 rw [mk'_eq_divInt, mk'_eq_divInt] at h ⊢ @@ -34,30 +28,21 @@ theorem cast_inj [CharZero α] : ∀ {m n : ℚ}, (m : α) = n ↔ m = n Int.cast_mul, ← Int.cast_natCast d₂, ← Int.cast_mul, Int.cast_inj, ← mkRat_eq_iff d₁0 d₂0] at h -theorem cast_injective [CharZero α] : Function.Injective ((↑) : ℚ → α) - | _, _ => cast_inj.1 +@[simp, norm_cast] lemma cast_inj : (p : α) = q ↔ p = q := cast_injective.eq_iff -@[simp] -theorem cast_eq_zero [CharZero α] {n : ℚ} : (n : α) = 0 ↔ n = 0 := by rw [← cast_zero, cast_inj] - -theorem cast_ne_zero [CharZero α] {n : ℚ} : (n : α) ≠ 0 ↔ n ≠ 0 := - not_congr cast_eq_zero - -@[simp, norm_cast] -theorem cast_add [CharZero α] (m n) : ((m + n : ℚ) : α) = m + n := - cast_add_of_ne_zero (Nat.cast_ne_zero.2 <| ne_of_gt m.pos) (Nat.cast_ne_zero.2 <| ne_of_gt n.pos) +@[simp, norm_cast] lemma cast_eq_zero : (p : α) = 0 ↔ p = 0 := cast_injective.eq_iff' cast_zero +lemma cast_ne_zero : (p : α) ≠ 0 ↔ p ≠ 0 := cast_eq_zero.ne -@[simp, norm_cast] -theorem cast_sub [CharZero α] (m n) : ((m - n : ℚ) : α) = m - n := - cast_sub_of_ne_zero (Nat.cast_ne_zero.2 <| ne_of_gt m.pos) (Nat.cast_ne_zero.2 <| ne_of_gt n.pos) +@[simp, norm_cast] lemma cast_add (p q : ℚ) : ↑(p + q) = (p + q : α) := + cast_add_of_ne_zero (Nat.cast_ne_zero.2 p.pos.ne') (Nat.cast_ne_zero.2 q.pos.ne') -@[simp, norm_cast] -theorem cast_mul [CharZero α] (m n) : ((m * n : ℚ) : α) = m * n := - cast_mul_of_ne_zero (Nat.cast_ne_zero.2 <| ne_of_gt m.pos) (Nat.cast_ne_zero.2 <| ne_of_gt n.pos) +@[simp, norm_cast] lemma cast_sub (p q : ℚ) : ↑(p - q) = (p - q : α) := + cast_sub_of_ne_zero (Nat.cast_ne_zero.2 p.pos.ne') (Nat.cast_ne_zero.2 q.pos.ne') -variable (α) -variable [CharZero α] +@[simp, norm_cast] lemma cast_mul (p q : ℚ) : ↑(p * q) = (p * q : α) := + cast_mul_of_ne_zero (Nat.cast_ne_zero.2 p.pos.ne') (Nat.cast_ne_zero.2 q.pos.ne') +variable (α) in /-- Coercion `ℚ → α` as a `RingHom`. -/ def castHom : ℚ →+* α where toFun := (↑) @@ -66,32 +51,67 @@ def castHom : ℚ →+* α where map_zero' := cast_zero map_add' := cast_add -variable {α} - -@[simp] -theorem coe_cast_hom : ⇑(castHom α) = ((↑) : ℚ → α) := - rfl +@[simp] lemma coe_castHom : ⇑(castHom α) = ((↑) : ℚ → α) := rfl -@[simp, norm_cast] -theorem cast_inv (n) : ((n⁻¹ : ℚ) : α) = (n : α)⁻¹ := - map_inv₀ (castHom α) _ +@[deprecated (since := "2024-07-22")] alias coe_cast_hom := coe_castHom -@[simp, norm_cast] -theorem cast_div (m n) : ((m / n : ℚ) : α) = m / n := - map_div₀ (castHom α) _ _ +@[simp, norm_cast] lemma cast_inv (p : ℚ) : ↑(p⁻¹) = (p⁻¹ : α) := map_inv₀ (castHom α) _ +@[simp, norm_cast] lemma cast_div (p q : ℚ) : ↑(p / q) = (p / q : α) := map_div₀ (castHom α) .. @[simp, norm_cast] -theorem cast_zpow (q : ℚ) (n : ℤ) : ((q ^ n : ℚ) : α) = (q : α) ^ n := - map_zpow₀ (castHom α) q n +lemma cast_zpow (p : ℚ) (n : ℤ) : ↑(p ^ n) = (p ^ n : α) := map_zpow₀ (castHom α) .. @[norm_cast] theorem cast_mk (a b : ℤ) : (a /. b : α) = a / b := by simp only [divInt_eq_div, cast_div, cast_intCast] +end Rat + +namespace NNRat +variable [DivisionSemiring α] [CharZero α] {p q : ℚ≥0} + +lemma cast_injective : Injective ((↑) : ℚ≥0 → α) := by + rintro p q hpq + rw [NNRat.cast_def, NNRat.cast_def, Commute.div_eq_div_iff] at hpq + on_goal 1 => rw [← p.num_div_den, ← q.num_div_den, div_eq_div_iff] + · norm_cast at hpq ⊢ + any_goals norm_cast + any_goals apply den_ne_zero + exact Nat.cast_commute .. + +@[simp, norm_cast] lemma cast_inj : (p : α) = q ↔ p = q := cast_injective.eq_iff + +@[simp, norm_cast] lemma cast_eq_zero : (q : α) = 0 ↔ q = 0 := by rw [← cast_zero, cast_inj] +lemma cast_ne_zero : (q : α) ≠ 0 ↔ q ≠ 0 := cast_eq_zero.not + +@[simp, norm_cast] lemma cast_add (p q : ℚ≥0) : ↑(p + q) = (p + q : α) := + cast_add_of_ne_zero (Nat.cast_ne_zero.2 p.den_pos.ne') (Nat.cast_ne_zero.2 q.den_pos.ne') + +@[simp, norm_cast] lemma cast_mul (p q) : (p * q : ℚ≥0) = (p * q : α) := + cast_mul_of_ne_zero (Nat.cast_ne_zero.2 p.den_pos.ne') (Nat.cast_ne_zero.2 q.den_pos.ne') + +variable (α) in +/-- Coercion `ℚ≥0 → α` as a `RingHom`. -/ +def castHom : ℚ≥0 →+* α where + toFun := (↑) + map_one' := cast_one + map_mul' := cast_mul + map_zero' := cast_zero + map_add' := cast_add + +@[simp, norm_cast] lemma coe_castHom : ⇑(castHom α) = (↑) := rfl + +@[simp, norm_cast] lemma cast_inv (p) : (p⁻¹ : ℚ≥0) = (p : α)⁻¹ := map_inv₀ (castHom α) _ +@[simp, norm_cast] lemma cast_div (p q) : (p / q : ℚ≥0) = (p / q : α) := map_div₀ (castHom α) .. + @[simp, norm_cast] -theorem cast_pow (q : ℚ) (k : ℕ) : ↑(q ^ k) = (q : α) ^ k := - (castHom α).map_pow q k +lemma cast_zpow (q : ℚ≥0) (p : ℤ) : ↑(q ^ p) = ((q : α) ^ p : α) := map_zpow₀ (castHom α) .. -end WithDivRing +@[simp] +lemma cast_divNat (a b : ℕ) : (divNat a b : α) = a / b := by + rw [← cast_natCast, ← cast_natCast b, ← cast_div] + congr + ext + apply Rat.mkRat_eq_div -end Rat +end NNRat diff --git a/Mathlib/Data/Rat/Cast/Defs.lean b/Mathlib/Data/Rat/Cast/Defs.lean index e9e86730c7e10..739dbc17cb0ce 100644 --- a/Mathlib/Data/Rat/Cast/Defs.lean +++ b/Mathlib/Data/Rat/Cast/Defs.lean @@ -8,6 +8,7 @@ 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 /-! @@ -18,10 +19,6 @@ 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 @@ -222,19 +219,47 @@ theorem map_ratCast [DivisionRing α] [DivisionRing β] [RingHomClass F α β] ( @[simp] lemma eq_ratCast [DivisionRing α] [FunLike F ℚ α] [RingHomClass F ℚ α] (f : F) (q : ℚ) : f q = q := by rw [← map_ratCast f, Rat.cast_id] -namespace MonoidWithZeroHom +namespace MonoidWithZeroHomClass + +variable {M₀ : Type*} [MonoidWithZero M₀] + +section NNRat +variable [FunLike F ℚ≥0 M₀] [MonoidWithZeroHomClass F ℚ≥0 M₀] {f g : F} + +/-- If monoid with zero homs `f` and `g` from `ℚ≥0` agree on the naturals then they are equal. -/ +lemma ext_nnrat' (h : ∀ n : ℕ, f n = g n) : f = g := + (DFunLike.ext f g) fun r => by + rw [← r.num_div_den, div_eq_mul_inv, map_mul, map_mul, h, eq_on_inv₀ f g] + apply h + +/-- If monoid with zero homs `f` and `g` from `ℚ≥0` agree on the naturals then they are equal. -variable {M₀ : Type*} [MonoidWithZero M₀] [FunLike F ℚ M₀] [MonoidWithZeroHomClass F ℚ M₀] -variable {f g : F} +See note [partially-applied ext lemmas] for why `comp` is used here. -/ +@[ext] +lemma ext_nnrat {f g : ℚ≥0 →*₀ M₀} + (h : f.comp (Nat.castRingHom ℚ≥0 : ℕ →*₀ ℚ≥0) = g.comp (Nat.castRingHom ℚ≥0)) : f = g := + ext_nnrat' <| DFunLike.congr_fun h + +/-- If monoid with zero homs `f` and `g` from `ℚ≥0` agree on the positive naturals then they are +equal. -/ +lemma ext_nnrat_on_pnat (same_on_pnat : ∀ n : ℕ, 0 < n → f n = g n) : f = g := + ext_nnrat' <| DFunLike.congr_fun <| ext_nat'' + ((f : ℚ≥0 →*₀ M₀).comp (Nat.castRingHom ℚ≥0 : ℕ →*₀ ℚ≥0)) + ((g : ℚ≥0 →*₀ M₀).comp (Nat.castRingHom ℚ≥0 : ℕ →*₀ ℚ≥0)) (by simpa) + +end NNRat + +section Rat +variable [FunLike F ℚ M₀] [MonoidWithZeroHomClass F ℚ M₀] {f g : F} -/-- If `f` and `g` agree on the integers then they are equal `φ`. -/ +/-- If monoid with zero homs `f` and `g` from `ℚ` agree on the integers then they are equal. -/ theorem ext_rat' (h : ∀ m : ℤ, f m = g m) : f = g := (DFunLike.ext f g) fun r => by rw [← r.num_div_den, div_eq_mul_inv, map_mul, map_mul, h, ← Int.cast_natCast, eq_on_inv₀ f g] apply h -/-- If `f` and `g` agree on the integers then they are equal `φ`. +/-- If monoid with zero homs `f` and `g` from `ℚ` agree on the integers then they are equal. See note [partially-applied ext lemmas] for why `comp` is used here. -/ @[ext] @@ -242,7 +267,8 @@ theorem ext_rat {f g : ℚ →*₀ M₀} (h : f.comp (Int.castRingHom ℚ : ℤ →*₀ ℚ) = g.comp (Int.castRingHom ℚ)) : f = g := ext_rat' <| DFunLike.congr_fun h -/-- Positive integer values of a morphism `φ` and its value on `-1` completely determine `φ`. -/ +/-- If monoid with zero homs `f` and `g` from `ℚ` agree on the positive naturals and `-1` then +they are equal. -/ theorem ext_rat_on_pnat (same_on_neg_one : f (-1) = g (-1)) (same_on_pnat : ∀ n : ℕ, 0 < n → f n = g n) : f = g := ext_rat' <| @@ -252,16 +278,20 @@ theorem ext_rat_on_pnat (same_on_neg_one : f (-1) = g (-1)) (g : ℚ →*₀ M₀).comp (Int.castRingHom ℚ : ℤ →*₀ ℚ) from ext_int' (by simpa) (by simpa) -end MonoidWithZeroHom +end Rat +end MonoidWithZeroHomClass /-- Any two ring homomorphisms from `ℚ` to a semiring are equal. If the codomain is a division ring, then this lemma follows from `eq_ratCast`. -/ theorem RingHom.ext_rat {R : Type*} [Semiring R] [FunLike F ℚ R] [RingHomClass F ℚ R] (f g : F) : f = g := - MonoidWithZeroHom.ext_rat' <| + MonoidWithZeroHomClass.ext_rat' <| RingHom.congr_fun <| ((f : ℚ →+* R).comp (Int.castRingHom ℚ)).ext_int ((g : ℚ →+* R).comp (Int.castRingHom ℚ)) +instance NNRat.subsingleton_ringHom {R : Type*} [Semiring R] : Subsingleton (ℚ≥0 →+* R) where + allEq f g := MonoidWithZeroHomClass.ext_nnrat' <| by simp + instance Rat.subsingleton_ringHom {R : Type*} [Semiring R] : Subsingleton (ℚ →+* R) := ⟨RingHom.ext_rat⟩ diff --git a/Mathlib/Data/Rat/Cast/Lemmas.lean b/Mathlib/Data/Rat/Cast/Lemmas.lean index 5abedffa0bd2f..4089d6b56d2e4 100644 --- a/Mathlib/Data/Rat/Cast/Lemmas.lean +++ b/Mathlib/Data/Rat/Cast/Lemmas.lean @@ -3,8 +3,9 @@ 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.Data.Rat.Cast.Defs import Mathlib.Algebra.Field.Basic +import Mathlib.Data.Rat.Cast.Defs +import Mathlib.Tactic.Positivity.Basic /-! # Some exiled lemmas about casting @@ -20,13 +21,18 @@ namespace Rat variable {α : Type*} [DivisionRing α] +@[simp, norm_cast] +lemma cast_pow (p : ℚ) (n : ℕ) : ↑(p ^ n) = (p ^ n : α) := by + rw [cast_def, cast_def, den_pow, num_pow, Nat.cast_pow, Int.cast_pow, div_eq_mul_inv, ← inv_pow, + ← (Int.cast_commute _ _).mul_pow, ← div_eq_mul_inv] + -- Porting note: rewrote proof @[simp] theorem cast_inv_nat (n : ℕ) : ((n⁻¹ : ℚ) : α) = (n : α)⁻¹ := by cases' n with n · simp rw [cast_def, inv_natCast_num, inv_natCast_den, if_neg n.succ_ne_zero, - Int.sign_eq_one_of_pos (Nat.cast_pos.mpr n.succ_pos), Int.cast_one, one_div] + Int.sign_eq_one_of_pos (Int.ofNat_succ_pos n), Int.cast_one, one_div] -- Porting note: proof got a lot easier - is this still the intended statement? @[simp] @@ -41,7 +47,7 @@ theorem cast_nnratCast {K} [DivisionRing K] (q : ℚ≥0) : rw [Rat.cast_def, NNRat.cast_def, NNRat.cast_def] have hn := @num_div_eq_of_coprime q.num q.den ?hdp q.coprime_num_den on_goal 1 => have hd := @den_div_eq_of_coprime q.num q.den ?hdp q.coprime_num_den - case hdp => simpa only [Nat.cast_pos] using q.den_pos + case hdp => simpa only [Int.ofNat_pos] using q.den_pos simp only [Int.cast_natCast, Nat.cast_inj] at hn hd rw [hn, hd, Int.cast_natCast] diff --git a/Mathlib/Data/Rat/Cast/Order.lean b/Mathlib/Data/Rat/Cast/Order.lean index 01ee5b4fb33f1..2a4ebd3ceadb2 100644 --- a/Mathlib/Data/Rat/Cast/Order.lean +++ b/Mathlib/Data/Rat/Cast/Order.lean @@ -132,6 +132,27 @@ def castOrderEmbedding : ℚ≥0 ↪o K := @[simp] lemma cast_pos : (0 : K) < q ↔ 0 < q := by norm_cast @[norm_cast] lemma cast_lt_zero : (q : K) < 0 ↔ q < 0 := by norm_cast @[simp] lemma not_cast_lt_zero : ¬(q : K) < 0 := mod_cast not_lt_zero' +@[simp] lemma cast_le_one : (p : K) ≤ 1 ↔ p ≤ 1 := by norm_cast +@[simp] lemma one_le_cast : 1 ≤ (p : K) ↔ 1 ≤ p := by norm_cast +@[simp] lemma cast_lt_one : (p : K) < 1 ↔ p < 1 := by norm_cast +@[simp] lemma one_lt_cast : 1 < (p : K) ↔ 1 < p := by norm_cast + +section ofNat +variable {n : ℕ} [n.AtLeastTwo] + +@[simp] lemma cast_le_ofNat : (p : K) ≤ no_index (OfNat.ofNat n) ↔ p ≤ OfNat.ofNat n := by + simp [← cast_le (K := K)] + +@[simp] lemma ofNat_le_cast : no_index (OfNat.ofNat n) ≤ (p : K) ↔ OfNat.ofNat n ≤ p := by + simp [← cast_le (K := K)] + +@[simp] lemma cast_lt_ofNat : (p : K) < no_index (OfNat.ofNat n) ↔ p < OfNat.ofNat n := by + simp [← cast_lt (K := K)] + +@[simp] lemma ofNat_lt_cast : no_index (OfNat.ofNat n) < (p : K) ↔ OfNat.ofNat n < p := by + simp [← cast_lt (K := K)] + +end ofNat @[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/Encodable.lean b/Mathlib/Data/Rat/Encodable.lean index 077213e24cef7..4779cf7a54c82 100644 --- a/Mathlib/Data/Rat/Encodable.lean +++ b/Mathlib/Data/Rat/Encodable.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro -/ import Mathlib.Logic.Encodable.Basic -import Mathlib.Data.Nat.GCD.Basic import Mathlib.Data.Rat.Init /-! # The rationals are `Encodable`. diff --git a/Mathlib/Data/Rat/Lemmas.lean b/Mathlib/Data/Rat/Lemmas.lean index f684d39ce96de..0aa562b90bce1 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) diff --git a/Mathlib/Data/Rat/Star.lean b/Mathlib/Data/Rat/Star.lean index a09ca020eab6d..8f4b38afcab0e 100644 --- a/Mathlib/Data/Rat/Star.lean +++ b/Mathlib/Data/Rat/Star.lean @@ -5,7 +5,7 @@ Authors: Jireh Loreaux, Yaël Dillies -/ import Mathlib.Algebra.GroupWithZero.Commute import Mathlib.Algebra.Order.Ring.Abs -import Mathlib.Algebra.Star.Order +import Mathlib.Algebra.Order.Star.Basic import Mathlib.Data.NNRat.Lemmas import Mathlib.Algebra.Order.Monoid.Submonoid import Mathlib.Tactic.FieldSimp @@ -38,7 +38,7 @@ namespace NNRat simpa only [sq] using addSubmonoid_closure_range_pow two_ne_zero instance instStarOrderedRing : StarOrderedRing ℚ≥0 where - le_iff a b := by simp [le_iff_exists_nonneg_add a b] + le_iff a b := by simp [eq_comm, le_iff_exists_nonneg_add (a := a)] end NNRat @@ -57,6 +57,6 @@ lemma addSubmonoid_closure_range_mul_self : closure (range fun x : ℚ ↦ x * x simpa only [sq] using addSubmonoid_closure_range_pow two_ne_zero even_two instance instStarOrderedRing : StarOrderedRing ℚ where - le_iff a b := by simp [le_iff_exists_nonneg_add a b] + le_iff a b := by simp [eq_comm, le_iff_exists_nonneg_add (a := a)] end Rat diff --git a/Mathlib/Data/Real/Archimedean.lean b/Mathlib/Data/Real/Archimedean.lean index 9c2e636a07e34..5c7543769551c 100644 --- a/Mathlib/Data/Real/Archimedean.lean +++ b/Mathlib/Data/Real/Archimedean.lean @@ -3,8 +3,8 @@ 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.Interval.Set.Disjoint @@ -17,6 +17,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 +50,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 +61,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 + ⟨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 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 +82,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 +93,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 +101,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 +154,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 +166,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 +295,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,14 +359,13 @@ 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 ?_ intro q hq refine (ha q.den (by positivity)).trans ?_ - rw [← le_sub_iff_add_le, div_le_iff (by positivity), sub_mul, one_mul] + rw [← le_sub_iff_add_le, div_le_iff₀ (by positivity), sub_mul, one_mul] norm_cast at hq ⊢ rw [← q.num_div_den, one_lt_div (by positivity)] at hq rw [q.mul_den_eq_num] diff --git a/Mathlib/Data/Real/Basic.lean b/Mathlib/Data/Real/Basic.lean index a78b3dc25b856..7cec019cb7dbe 100644 --- a/Mathlib/Data/Real/Basic.lean +++ b/Mathlib/Data/Real/Basic.lean @@ -343,22 +343,25 @@ protected theorem zero_lt_one : (0 : ℝ) < 1 := by protected theorem fact_zero_lt_one : Fact ((0 : ℝ) < 1) := ⟨Real.zero_lt_one⟩ +@[deprecated mul_pos (since := "2024-08-15")] protected theorem mul_pos {a b : ℝ} : 0 < a → 0 < b → 0 < a * b := by induction' a using Real.ind_mk with a induction' b using Real.ind_mk with b simpa only [mk_lt, mk_pos, ← mk_mul] using CauSeq.mul_pos -instance : StrictOrderedCommRing ℝ := - { Real.commRing, Real.partialOrder, - Real.semiring with - exists_pair_ne := ⟨0, 1, Real.zero_lt_one.ne⟩ - add_le_add_left := by - simp only [le_iff_eq_or_lt] - rintro a b ⟨rfl, h⟩ - · simp only [lt_self_iff_false, or_false, forall_const] - · exact fun c => Or.inr ((add_lt_add_iff_left c).2 ‹_›) - zero_le_one := le_of_lt Real.zero_lt_one - mul_pos := @Real.mul_pos } +instance instStrictOrderedCommRing : StrictOrderedCommRing ℝ where + __ := Real.commRing + exists_pair_ne := ⟨0, 1, Real.zero_lt_one.ne⟩ + add_le_add_left := by + simp only [le_iff_eq_or_lt] + rintro a b ⟨rfl, h⟩ + · simp only [lt_self_iff_false, or_false, forall_const] + · exact fun c => Or.inr ((add_lt_add_iff_left c).2 ‹_›) + zero_le_one := le_of_lt Real.zero_lt_one + mul_pos a b := by + induction' a using Real.ind_mk with a + induction' b using Real.ind_mk with b + simpa only [mk_lt, mk_pos, ← mk_mul] using CauSeq.mul_pos instance strictOrderedRing : StrictOrderedRing ℝ := inferInstance @@ -597,3 +600,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 6b6586723f5c1..04bfc20da0ec1 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,16 +108,18 @@ 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 + .inv_inv ha₀ (sub_pos_of_lt ha₁) <| add_tsub_cancel_of_le ha₁.le lemma one_sub_inv_inv (ha₀ : 0 < a) (ha₁ : a < 1) : (1 - a)⁻¹.IsConjExponent a⁻¹ := (inv_one_sub_inv ha₀ ha₁).symm 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,17 +199,19 @@ 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)⁻¹ := - .inv_inv ha₀ (tsub_pos_of_lt ha₁).ne' $ add_tsub_cancel_of_le ha₁.le + .inv_inv ha₀ (tsub_pos_of_lt ha₁).ne' <| add_tsub_cancel_of_le ha₁.le lemma one_sub_inv_inv (ha₀ : a ≠ 0) (ha₁ : a < 1) : (1 - a)⁻¹.IsConjExponent a⁻¹ := (inv_one_sub_inv ha₀ ha₁).symm 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 + 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] + 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 3de259cbaf4d5..4ff49b8b9459b 100644 --- a/Mathlib/Data/Real/EReal.lean +++ b/Mathlib/Data/Real/EReal.lean @@ -929,6 +929,64 @@ lemma neg_sub {x y : EReal} (h1 : x ≠ ⊥ ∨ y ≠ ⊥) (h2 : x ≠ ⊤ ∨ y - (x - y) = - x + y := by rw [sub_eq_add_neg, neg_add _ _, sub_eq_add_neg, neg_neg] <;> simp_all +/-! ### Addition and order -/ + +lemma le_of_forall_lt_iff_le {x y : EReal} : (∀ z : ℝ, x < z → y ≤ z) ↔ y ≤ x := by + refine ⟨fun h ↦ WithBot.le_of_forall_lt_iff_le.1 ?_, fun h _ x_z ↦ h.trans x_z.le⟩ + rw [WithTop.forall] + aesop + +lemma ge_of_forall_gt_iff_ge {x y : EReal} : (∀ z : ℝ, z < y → z ≤ x) ↔ y ≤ x := by + refine ⟨fun h ↦ WithBot.ge_of_forall_gt_iff_ge.1 ?_, fun h _ x_z ↦ x_z.le.trans h⟩ + rw [WithTop.forall] + aesop + +/-- This lemma is superseded by `add_le_of_forall_add_le`. -/ +private lemma top_add_le_of_forall_add_le {a b : EReal} (h : ∀ c < ⊤, ∀ d < a, c + d ≤ b) : + ⊤ + a ≤ b := by + induction a with + | h_bot => exact add_bot ⊤ ▸ bot_le + | h_real a => + refine top_add_coe a ▸ le_of_forall_lt_iff_le.1 fun c b_c ↦ ?_ + specialize h (c - a + 1) (coe_lt_top (c - a + 1)) (a - 1) + rw [← coe_one, ← coe_sub, ← coe_sub, ← coe_add, ← coe_add, add_add_sub_cancel, sub_add_cancel, + EReal.coe_lt_coe_iff] at h + exact (not_le_of_lt b_c (h (sub_one_lt a))).rec + | h_top => + refine top_add_top ▸ le_of_forall_lt_iff_le.1 fun c b_c ↦ ?_ + specialize h c (coe_lt_top c) 0 zero_lt_top + rw [add_zero] at h + exact (not_le_of_lt b_c h).rec + +lemma add_le_of_forall_add_le {a b c : EReal} (h : ∀ d < a, ∀ e < b, d + e ≤ c) : a + b ≤ c := by + induction a with + | h_bot => exact bot_add b ▸ bot_le + | h_real a => induction b with + | h_bot => exact add_bot (a : EReal) ▸ bot_le + | h_real b => + refine (@ge_of_forall_gt_iff_ge c (a+b)).1 fun d d_ab ↦ ?_ + rw [← coe_add, EReal.coe_lt_coe_iff] at d_ab + rcases exists_between d_ab with ⟨e, e_d, e_ab⟩ + have key₁ : (a + d - e : ℝ) < (a : EReal) := by apply EReal.coe_lt_coe_iff.2; linarith + have key₂ : (e - a : ℝ) < (b : EReal) := by apply EReal.coe_lt_coe_iff.2; linarith + apply le_of_eq_of_le _ (h (a + d - e) key₁ (e - a) key₂) + rw [← coe_add, ← coe_sub, ← coe_sub, ← coe_add, sub_add_sub_cancel, add_sub_cancel_left] + | h_top => + rw [add_comm (a : EReal) ⊤] + exact top_add_le_of_forall_add_le fun d d_top e e_a ↦ (add_comm d e ▸ h e e_a d d_top) + | h_top => exact top_add_le_of_forall_add_le h + +lemma le_add_of_forall_le_add {a b c : EReal} (h₁ : a ≠ ⊥ ∨ b ≠ ⊤) (h₂ : a ≠ ⊤ ∨ b ≠ ⊥) + (h : ∀ d > a, ∀ e > b, c ≤ d + e) : + c ≤ a + b := by + rw [← neg_le_neg_iff, neg_add h₁ h₂] + refine add_le_of_forall_add_le fun d d_a e e_b ↦ ?_ + have h₃ : d ≠ ⊥ ∨ e ≠ ⊤ := Or.inr (ne_top_of_lt e_b) + have h₄ : d ≠ ⊤ ∨ e ≠ ⊥ := Or.inl (ne_top_of_lt d_a) + rw [← neg_neg d, neg_lt_iff_neg_lt, neg_neg a] at d_a + rw [← neg_neg e, neg_lt_iff_neg_lt, neg_neg b] at e_b + exact le_neg_of_le_neg <| neg_add h₃ h₄ ▸ h (- d) d_a (- e) e_b + /-! ### Subtraction @@ -1169,52 +1227,6 @@ lemma left_distrib_of_nonneg {a b c : EReal} (ha : 0 ≤ a) (hb : 0 ≤ b) : nth_rewrite 1 [EReal.mul_comm]; nth_rewrite 2 [EReal.mul_comm]; nth_rewrite 3 [EReal.mul_comm] exact right_distrib_of_nonneg ha hb -lemma le_iff_le_forall_real_gt (x y : EReal) : (∀ z : ℝ, x < z → y ≤ z) ↔ y ≤ x := by - symm - refine ⟨fun h z x_lt_z ↦ le_trans h (le_of_lt x_lt_z), ?_⟩ - intro h - induction x - · apply le_of_eq ((eq_bot_iff_forall_lt y).2 _) - intro z - specialize h (z-1) (bot_lt_coe (z-1)) - apply lt_of_le_of_lt h - rw [EReal.coe_lt_coe_iff] - exact sub_one_lt z - · induction y - · exact bot_le - · norm_cast - norm_cast at h - by_contra x_lt_y - rcases exists_between (lt_of_not_le x_lt_y) with ⟨z, x_lt_z, z_lt_y⟩ - specialize h z x_lt_z - exact not_le_of_lt z_lt_y h - · exfalso - specialize h (_+ 1) (EReal.coe_lt_coe_iff.2 (lt_add_one _)) - exact not_le_of_lt (coe_lt_top (_ + 1)) h - · exact le_top - -lemma ge_iff_le_forall_real_lt (x y : EReal) : (∀ z : ℝ, z < y → z ≤ x) ↔ y ≤ x := by - refine ⟨fun h ↦ ?_, fun h z z_lt_y ↦ le_trans (le_of_lt z_lt_y) h⟩ - induction x with - | h_bot => - refine ((eq_bot_iff_forall_lt y).2 fun z ↦ ?_).le - refine lt_of_not_le fun z_le_y ↦ (not_le_of_lt (bot_lt_coe (z - 1)) (h (z - 1) - (lt_of_lt_of_le ?_ z_le_y))) - exact_mod_cast sub_one_lt z - | h_real x => - induction y with - | h_bot => exact bot_le - | h_real y => - norm_cast at h ⊢ - by_contra! x_lt_y - rcases exists_between x_lt_y with ⟨z, x_lt_z, z_lt_y⟩ - exact not_le_of_lt x_lt_z (h z z_lt_y) - | h_top => - exfalso - norm_cast at h - exact not_le_of_lt (lt_add_one x) <| h (x + 1) (coe_lt_top (x + 1)) - | h_top => exact le_top - /-! ### Absolute value -/ -- Porting note (#11215): TODO: use `Real.nnabs` for the case `(x : ℝ)` @@ -1548,7 +1560,7 @@ lemma div_right_distrib_of_nonneg {a b c : EReal} (h : 0 ≤ a) (h' : 0 ≤ b) : (a + b) / c = (a / c) + (b / c) := EReal.right_distrib_of_nonneg h h' -/-! #### Division and Order s-/ +/-! #### Division and Order s -/ lemma monotone_div_right_of_nonneg {b : EReal} (h : 0 ≤ b) : Monotone fun a ↦ a / b := fun _ _ h' ↦ mul_le_mul_of_nonneg_right h' (inv_nonneg_of_nonneg h) @@ -1668,3 +1680,5 @@ unsafe def positivity_coe_ennreal_ereal : expr → tactic strictness end Tactic -/ + +set_option linter.style.longFile 1800 diff --git a/Mathlib/Data/Real/GoldenRatio.lean b/Mathlib/Data/Real/GoldenRatio.lean index 63905e911911d..42e9c2559ca88 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 diff --git a/Mathlib/Data/Real/Hyperreal.lean b/Mathlib/Data/Real/Hyperreal.lean index 3ec6b4835c02e..4b5d781f4224b 100644 --- a/Mathlib/Data/Real/Hyperreal.lean +++ b/Mathlib/Data/Real/Hyperreal.lean @@ -127,11 +127,11 @@ theorem ofSeq_surjective : Function.Surjective ofSeq := Quot.exists_rep theorem ofSeq_lt_ofSeq {f g : ℕ → ℝ} : ofSeq f < ofSeq g ↔ ∀ᶠ n in hyperfilter ℕ, f n < g n := Germ.coe_lt -/-- A sample infinitesimal hyperreal-/ +/-- A sample infinitesimal hyperreal -/ noncomputable def epsilon : ℝ* := ofSeq fun n => n⁻¹ -/-- A sample infinite hyperreal-/ +/-- A sample infinite hyperreal -/ noncomputable def omega : ℝ* := ofSeq Nat.cast @[inherit_doc] scoped notation "ε" => Hyperreal.epsilon @@ -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..666201507c599 100644 --- a/Mathlib/Data/Real/Irrational.lean +++ b/Mathlib/Data/Real/Irrational.lean @@ -79,7 +79,7 @@ theorem irrational_nrt_of_n_not_dvd_multiplicity {x : ℝ} (n : ℕ) {m : ℤ} ( rw [← Int.cast_pow, Int.cast_inj] at hxr subst m have : y ≠ 0 := by rintro rfl; rw [zero_pow hnpos.ne'] at hm; exact hm rfl - erw [multiplicity.pow' (Nat.prime_iff_prime_int.1 hp.1) (finite_int_iff.2 ⟨hp.1.ne_one, this⟩), + rw [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 exact hv rfl diff --git a/Mathlib/Data/Real/Pi/Bounds.lean b/Mathlib/Data/Real/Pi/Bounds.lean index 20aaebc121269..131af1b4136f2 100644 --- a/Mathlib/Data/Real/Pi/Bounds.lean +++ b/Mathlib/Data/Real/Pi/Bounds.lean @@ -11,56 +11,49 @@ 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'] + · 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)] - rw [le_div_iff (by norm_num), ← mul_pow] + rw [le_div_iff₀ (by norm_num), ← mul_pow] refine le_trans ?_ (le_of_eq (one_pow 3)); apply pow_le_pow_left · apply le_of_lt; apply mul_pos · apply div_pos pi_pos; apply pow_pos; norm_num · apply pow_pos; norm_num - · rw [← le_div_iff (by norm_num)] + · 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`. -/ @@ -124,7 +88,7 @@ theorem pi_upper_bound_start (n : ℕ) {a} sqrtTwoAddSeries ((0 : ℕ) / (1 : ℕ)) n) (h₂ : (1 : ℝ) / (4 : ℝ) ^ n ≤ a) : π < a := by refine lt_of_lt_of_le (pi_lt_sqrtTwoAddSeries n) ?_ - rw [← le_sub_iff_add_le, ← le_div_iff', sqrt_le_left, sub_le_comm] + rw [← le_sub_iff_add_le, ← le_div_iff₀', sqrt_le_left, sub_le_comm] · rwa [Nat.cast_zero, zero_div] at h · exact div_nonneg (sub_nonneg.2 h₂) (pow_nonneg (le_of_lt zero_lt_two) _) · exact pow_pos zero_lt_two _ @@ -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/Pi/Wallis.lean b/Mathlib/Data/Real/Pi/Wallis.lean index 096ffc009e98f..23aca82d62f0e 100644 --- a/Mathlib/Data/Real/Pi/Wallis.lean +++ b/Mathlib/Data/Real/Pi/Wallis.lean @@ -80,13 +80,11 @@ theorem W_le (k : ℕ) : W k ≤ π / 2 := by apply integral_sin_pow_succ_le theorem le_W (k : ℕ) : ((2 : ℝ) * k + 1) / (2 * k + 2) * (π / 2) ≤ W k := by - rw [← le_div_iff pi_div_two_pos, div_eq_inv_mul (W k) _] - rw [W_eq_integral_sin_pow_div_integral_sin_pow, le_div_iff (integral_sin_pow_pos _)] + rw [← le_div_iff₀ pi_div_two_pos, div_eq_inv_mul (W k) _] + rw [W_eq_integral_sin_pow_div_integral_sin_pow, le_div_iff₀ (integral_sin_pow_pos _)] convert integral_sin_pow_succ_le (2 * k + 1) rw [integral_sin_pow (2 * k)] - simp only [sin_zero, ne_eq, add_eq_zero, and_false, not_false_eq_true, zero_pow, cos_zero, - mul_one, sin_pi, cos_pi, mul_neg, neg_zero, sub_self, zero_div, zero_add] - norm_cast + simp theorem tendsto_W_nhds_pi_div_two : Tendsto W atTop (𝓝 <| π / 2) := by refine tendsto_of_tendsto_of_tendsto_of_le_of_le ?_ tendsto_const_nhds le_W W_le 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/Real/Sign.lean b/Mathlib/Data/Real/Sign.lean index e1b46f2c8ba69..d4b23cdfb07e2 100644 --- a/Mathlib/Data/Real/Sign.lean +++ b/Mathlib/Data/Real/Sign.lean @@ -104,8 +104,8 @@ theorem inv_sign (r : ℝ) : (sign r)⁻¹ = sign r := by @[simp] theorem sign_inv (r : ℝ) : sign r⁻¹ = sign r := by obtain hn | rfl | hp := lt_trichotomy r (0 : ℝ) - · rw [sign_of_neg hn, sign_of_neg (inv_lt_zero (α := ℝ) |>.mpr hn)] + · rw [sign_of_neg hn, sign_of_neg (inv_lt_zero.mpr hn)] · rw [sign_zero, inv_zero, sign_zero] - · rw [sign_of_pos hp, sign_of_pos (inv_pos (α := ℝ) |>.mpr hp)] + · rw [sign_of_pos hp, sign_of_pos (inv_pos.mpr hp)] end Real diff --git a/Mathlib/Data/Real/Sqrt.lean b/Mathlib/Data/Real/Sqrt.lean index 3c3768bf2fd11..48f8aad052901 100644 --- a/Mathlib/Data/Real/Sqrt.lean +++ b/Mathlib/Data/Real/Sqrt.lean @@ -115,15 +115,6 @@ noncomputable def sqrt (x : ℝ) : ℝ := @[inherit_doc] prefix:max "√" => Real.sqrt -/- quotient.lift_on x - (λ f, mk ⟨sqrt_aux f, (sqrt_aux_converges f).fst⟩) - (λ f g e, begin - rcases sqrt_aux_converges f with ⟨hf, x, x0, xf, xs⟩, - rcases sqrt_aux_converges g with ⟨hg, y, y0, yg, ys⟩, - refine xs.trans (eq.trans _ ys.symm), - rw [← @mul_self_inj_of_nonneg ℝ _ x y x0 y0, xf, yg], - congr' 1, exact quotient.sound e - end)-/ variable {x y : ℝ} @[simp, norm_cast] @@ -136,8 +127,7 @@ theorem continuous_sqrt : Continuous (√· : ℝ → ℝ) := theorem sqrt_eq_zero_of_nonpos (h : x ≤ 0) : sqrt x = 0 := by simp [sqrt, Real.toNNReal_eq_zero.2 h] -theorem sqrt_nonneg (x : ℝ) : 0 ≤ √x := - NNReal.coe_nonneg _ +@[simp] theorem sqrt_nonneg (x : ℝ) : 0 ≤ √x := NNReal.coe_nonneg _ @[simp] theorem mul_self_sqrt (h : 0 ≤ x) : √x * √x = x := by @@ -156,8 +146,12 @@ theorem sqrt_eq_cases : √x = y ↔ y * y = x ∧ 0 ≤ y ∨ x < 0 ∧ y = 0 : · rintro (⟨rfl, hy⟩ | ⟨hx, rfl⟩) exacts [sqrt_mul_self hy, sqrt_eq_zero_of_nonpos hx.le] -theorem sqrt_eq_iff_mul_self_eq (hx : 0 ≤ x) (hy : 0 ≤ y) : √x = y ↔ y * y = x := - ⟨fun h => by rw [← h, mul_self_sqrt hx], fun h => by rw [← h, sqrt_mul_self hy]⟩ +theorem sqrt_eq_iff_mul_self_eq (hx : 0 ≤ x) (hy : 0 ≤ y) : √x = y ↔ x = y * y := + ⟨fun h => by rw [← h, mul_self_sqrt hx], fun h => by rw [h, sqrt_mul_self hy]⟩ + +@[deprecated sqrt_eq_iff_mul_self_eq (since := "2024-08-25")] +theorem sqrt_eq_iff_eq_mul_self (hx : 0 ≤ x) (hy : 0 ≤ y) : √x = y ↔ y * y = x := by + rw [sqrt_eq_iff_mul_self_eq hx hy, eq_comm] theorem sqrt_eq_iff_mul_self_eq_of_pos (h : 0 < y) : √x = y ↔ y * y = x := by simp [sqrt_eq_cases, h.ne', h.le] @@ -174,9 +168,13 @@ theorem sq_sqrt (h : 0 ≤ x) : √x ^ 2 = x := by rw [sq, mul_self_sqrt h] @[simp] theorem sqrt_sq (h : 0 ≤ x) : √(x ^ 2) = x := by rw [sq, sqrt_mul_self h] -theorem sqrt_eq_iff_sq_eq (hx : 0 ≤ x) (hy : 0 ≤ y) : √x = y ↔ y ^ 2 = x := by +theorem sqrt_eq_iff_eq_sq (hx : 0 ≤ x) (hy : 0 ≤ y) : √x = y ↔ x = y ^ 2 := by rw [sq, sqrt_eq_iff_mul_self_eq hx hy] +@[deprecated sqrt_eq_iff_eq_sq (since := "2024-08-25")] +theorem sqrt_eq_iff_sq_eq (hx : 0 ≤ x) (hy : 0 ≤ y) : √x = y ↔ y ^ 2 = x := by + rw [sqrt_eq_iff_eq_sq hx hy, eq_comm] + theorem sqrt_mul_self_eq_abs (x : ℝ) : √(x * x) = |x| := by rw [← abs_mul_abs_self x, sqrt_mul_self (abs_nonneg _)] @@ -267,7 +265,7 @@ alias ⟨_, sqrt_pos_of_pos⟩ := sqrt_pos lemma sqrt_le_sqrt_iff' (hx : 0 < x) : √x ≤ √y ↔ x ≤ y := by obtain hy | hy := le_total y 0 - · exact iff_of_false ((sqrt_eq_zero_of_nonpos hy).trans_lt $ sqrt_pos.2 hx).not_le + · exact iff_of_false ((sqrt_eq_zero_of_nonpos hy).trans_lt <| sqrt_pos.2 hx).not_le (hy.trans_lt hx).not_le · exact sqrt_le_sqrt_iff hy @@ -433,7 +431,7 @@ open Finset /-- **Cauchy-Schwarz inequality** for finsets using square roots in `ℝ≥0`. -/ lemma sum_mul_le_sqrt_mul_sqrt (s : Finset ι) (f g : ι → ℝ≥0) : ∑ i ∈ s, f i * g i ≤ sqrt (∑ i ∈ s, f i ^ 2) * sqrt (∑ i ∈ s, g i ^ 2) := - (le_sqrt_iff_sq_le.2 $ sum_mul_sq_le_sq_mul_sq _ _ _).trans_eq <| sqrt_mul _ _ + (le_sqrt_iff_sq_le.2 <| sum_mul_sq_le_sq_mul_sq _ _ _).trans_eq <| sqrt_mul _ _ /-- **Cauchy-Schwarz inequality** for finsets using square roots in `ℝ≥0`. -/ lemma sum_sqrt_mul_sqrt_le (s : Finset ι) (f g : ι → ℝ≥0) : diff --git a/Mathlib/Data/Real/StarOrdered.lean b/Mathlib/Data/Real/StarOrdered.lean index 3bb4a4ddd017d..ef1ad46ac2800 100644 --- a/Mathlib/Data/Real/StarOrdered.lean +++ b/Mathlib/Data/Real/StarOrdered.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ -import Mathlib.Algebra.Star.Order +import Mathlib.Algebra.Order.Star.Basic import Mathlib.Data.Real.Sqrt /-! # `ℝ` and `ℝ≥0` are *-ordered rings. -/ diff --git a/Mathlib/Data/Rel.lean b/Mathlib/Data/Rel.lean index a0fbadb670218..27adb8a69b26d 100644 --- a/Mathlib/Data/Rel.lean +++ b/Mathlib/Data/Rel.lean @@ -333,7 +333,7 @@ theorem graph_injective : Injective (graph : (α → β) → Rel α β) := by @[simp] lemma graph_inj {f g : α → β} : f.graph = g.graph ↔ f = g := graph_injective.eq_iff -theorem graph_id : graph id = @Eq α := by simp (config := { unfoldPartialApp := true }) [graph] +theorem graph_id : graph id = @Eq α := by simp (config := { unfoldPartialApp := true }) [graph] theorem graph_comp {f : β → γ} {g : α → β} : graph (f ∘ g) = Rel.comp (graph g) (graph f) := by ext x y diff --git a/Mathlib/Data/Semiquot.lean b/Mathlib/Data/Semiquot.lean index 5557146ba9262..fb1f34b2cb8c3 100644 --- a/Mathlib/Data/Semiquot.lean +++ b/Mathlib/Data/Semiquot.lean @@ -34,7 +34,7 @@ namespace Semiquot variable {α : Type*} {β : Type*} instance : Membership α (Semiquot α) := - ⟨fun a q => a ∈ q.s⟩ + ⟨fun q a => a ∈ q.s⟩ /-- Construct a `Semiquot α` from `h : a ∈ s` where `s : Set α`. -/ def mk {a : α} {s : Set α} (h : a ∈ s) : Semiquot α := diff --git a/Mathlib/Data/Seq/Computation.lean b/Mathlib/Data/Seq/Computation.lean index 93868db28c7bc..9ff96e3dd47ef 100644 --- a/Mathlib/Data/Seq/Computation.lean +++ b/Mathlib/Data/Seq/Computation.lean @@ -2,8 +2,6 @@ Copyright (c) 2017 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro - -Coinductive formalization of unbounded computations. -/ import Mathlib.Data.Nat.Find import Mathlib.Data.Stream.Init @@ -236,18 +234,19 @@ section Bisim variable (R : Computation α → Computation α → Prop) -/-- bisimilarity relation-/ +/-- bisimilarity relation -/ local infixl:50 " ~ " => R -/-- Bisimilarity over a sum of `Computation`s-/ +/-- Bisimilarity over a sum of `Computation`s -/ def BisimO : α ⊕ (Computation α) → α ⊕ (Computation α) → Prop | Sum.inl a, Sum.inl a' => a = a' | Sum.inr s, Sum.inr s' => R s s' | _, _ => False attribute [simp] BisimO +attribute [nolint simpNF] BisimO.eq_3 -/-- Attribute expressing bisimilarity over two `Computation`s-/ +/-- Attribute expressing bisimilarity over two `Computation`s -/ def IsBisimulation := ∀ ⦃s₁ s₂⦄, s₁ ~ s₂ → BisimO R (destruct s₁) (destruct s₂) @@ -280,7 +279,7 @@ end Bisim -- It's more of a stretch to use ∈ for this relation, but it -- asserts that the computation limits to the given value. /-- Assertion that a `Computation` limits to a given value-/ -protected def Mem (a : α) (s : Computation α) := +protected def Mem (s : Computation α) (a : α) := some a ∈ s.1 instance : Membership α (Computation α) := @@ -504,7 +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 n IH <;> 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 @@ -519,7 +519,7 @@ theorem eq_thinkN' (s : Computation α) [_h : Terminates s] : s = thinkN (pure (get s)) (length s) := eq_thinkN (results_of_terminates _) -/-- Recursor based on membership-/ +/-- Recursor based on membership -/ def memRecOn {C : Computation α → Sort v} {a s} (M : a ∈ s) (h1 : C (pure a)) (h2 : ∀ s, C s → C (think s)) : C s := by haveI T := terminates_of_mem M @@ -694,8 +694,9 @@ 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 with n IH generalizing s <;> apply recOn s (fun a => _) fun s' => _ <;> intro e h - · simp only [ret_bind, Nat.zero_eq] at h + induction k generalizing s with | zero => _ | succ n IH => _ + <;> 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) contradiction @@ -753,7 +754,7 @@ theorem exists_of_mem_map {f : α → β} {b : β} {s : Computation α} (h : b exact ⟨a, as, mem_unique (ret_mem _) fb⟩ instance terminates_map (f : α → β) (s : Computation α) [Terminates s] : Terminates (map f s) := by - rw [← bind_pure]; exact terminates_of_mem (mem_bind (get_mem s) (get_mem (f (get s)))) + rw [← bind_pure]; exact terminates_of_mem (mem_bind (get_mem s) (get_mem (α := β) (f (get s)))) theorem terminates_map_iff (f : α → β) (s : Computation α) : Terminates (map f s) ↔ Terminates s := ⟨fun ⟨⟨_, h⟩⟩ => @@ -820,7 +821,7 @@ theorem orElse_empty (c : Computation α) : (c <|> empty α) = c := by def Equiv (c₁ c₂ : Computation α) : Prop := ∀ a, a ∈ c₁ ↔ a ∈ c₂ -/-- equivalence relation for computations-/ +/-- equivalence relation for computations -/ scoped infixl:50 " ~ " => Equiv @[refl] @@ -1041,7 +1042,7 @@ theorem map_congr {s1 s2 : Computation α} {f : α → β} rw [← lift_eq_iff_equiv] exact liftRel_map Eq _ ((lift_eq_iff_equiv _ _).2 h1) fun {a} b => congr_arg _ -/-- Alternate definition of `LiftRel` over relations between `Computation`s-/ +/-- Alternate definition of `LiftRel` over relations between `Computation`s -/ def LiftRelAux (R : α → β → Prop) (C : Computation α → Computation β → Prop) : α ⊕ (Computation α) → β ⊕ (Computation β) → Prop | Sum.inl a, Sum.inl b => R a b diff --git a/Mathlib/Data/Seq/Parallel.lean b/Mathlib/Data/Seq/Parallel.lean index 95a1d67f43238..ee4bdac0f33db 100644 --- a/Mathlib/Data/Seq/Parallel.lean +++ b/Mathlib/Data/Seq/Parallel.lean @@ -128,7 +128,6 @@ theorem terminates_parallel {S : WSeq (Computation α)} {c} (h : c ∈ S) [T : T · have C : corec parallel.aux1 (l, S) = pure a := by apply destruct_eq_pure rw [corec_eq, parallel.aux1] - dsimp only [] rw [h] simp only [rmap] rw [C] @@ -146,7 +145,6 @@ theorem terminates_parallel {S : WSeq (Computation α)} {c} (h : c ∈ S) [T : T · have C : corec parallel.aux1 (l, S) = pure a := by apply destruct_eq_pure rw [corec_eq, parallel.aux1] - dsimp only [] rw [h] simp only [rmap] rw [C] diff --git a/Mathlib/Data/Seq/Seq.lean b/Mathlib/Data/Seq/Seq.lean index 974c780ddf181..d8dfa6e7ed037 100644 --- a/Mathlib/Data/Seq/Seq.lean +++ b/Mathlib/Data/Seq/Seq.lean @@ -126,7 +126,7 @@ def tail (s : Seq α) : Seq α := exact al n'⟩ /-- member definition for `Seq`-/ -protected def Mem (a : α) (s : Seq α) := +protected def Mem (s : Seq α) (a : α) := some a ∈ s.1 instance : Membership α (Seq α) := @@ -258,7 +258,7 @@ theorem mem_rec_on {C : Seq α → Prop} {a s} (M : a ∈ s) rw [h_eq] at e apply h1 _ _ (Or.inr (IH e)) -/-- Corecursor over pairs of `Option` values-/ +/-- Corecursor over pairs of `Option` values -/ def Corec.f (f : β → Option (α × β)) : Option β → Option α × Option β | none => (none, none) | some b => @@ -315,8 +315,9 @@ def BisimO : Option (Seq1 α) → Option (Seq1 α) → Prop | _, _ => False attribute [simp] BisimO +attribute [nolint simpNF] BisimO.eq_3 -/-- a relation is bisimilar if it meets the `BisimO` test-/ +/-- a relation is bisimilar if it meets the `BisimO` test -/ def IsBisimulation := ∀ ⦃s₁ s₂⦄, s₁ ~ s₂ → BisimO R (destruct s₁) (destruct s₂) @@ -511,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 9d86f9ce4e599..4817d9024ec51 100644 --- a/Mathlib/Data/Seq/WSeq.lean +++ b/Mathlib/Data/Seq/WSeq.lean @@ -106,8 +106,8 @@ def recOn {C : WSeq α → Sort v} (s : WSeq α) (h1 : C nil) (h2 : ∀ x s, C ( Seq.recOn s h1 fun o => Option.recOn o h3 h2 /-- membership for weak sequences-/ -protected def Mem (a : α) (s : WSeq α) := - Seq.Mem (some a) s +protected def Mem (s : WSeq α) (a : α) := + Seq.Mem s (some a) instance membership : Membership α (WSeq α) := ⟨WSeq.Mem⟩ @@ -394,6 +394,7 @@ def LiftRelO (R : α → β → Prop) (C : WSeq α → WSeq β → Prop) : | none, none => True | some (a, s), some (b, t) => R a b ∧ C s t | _, _ => False +attribute [nolint simpNF] LiftRelO.eq_3 theorem LiftRelO.imp {R S : α → β → Prop} {C D : WSeq α → WSeq β → Prop} (H1 : ∀ a b, R a b → S a b) (H2 : ∀ s t, C s t → D s t) : ∀ {o p}, LiftRelO R C o p → LiftRelO S D o p @@ -406,7 +407,7 @@ theorem LiftRelO.imp_right (R : α → β → Prop) {C D : WSeq α → WSeq β (H : ∀ s t, C s t → D s t) {o p} : LiftRelO R C o p → LiftRelO R D o p := LiftRelO.imp (fun _ _ => id) H -/-- Definition of bisimilarity for weak sequences-/ +/-- Definition of bisimilarity for weak sequences -/ @[simp] def BisimO (R : WSeq α → WSeq α → Prop) : Option (α × WSeq α) → Option (α × WSeq α) → Prop := LiftRelO (· = ·) R @@ -684,7 +685,7 @@ theorem append_nil (s : WSeq α) : append s nil = s := theorem append_assoc (s t u : WSeq α) : append (append s t) u = append s (append t u) := Seq.append_assoc _ _ _ -/-- auxiliary definition of tail over weak sequences-/ +/-- auxiliary definition of tail over weak sequences -/ @[simp] def tail.aux : Option (α × WSeq α) → Computation (Option (α × WSeq α)) | none => Computation.pure none @@ -694,7 +695,7 @@ theorem destruct_tail (s : WSeq α) : destruct (tail s) = destruct s >>= tail.au simp only [tail, destruct_flatten, tail.aux]; rw [← bind_pure_comp, LawfulMonad.bind_assoc] apply congr_arg; ext1 (_ | ⟨a, s⟩) <;> apply (@pure_bind Computation _ _ _ _ _ _).trans _ <;> simp -/-- auxiliary definition of drop over weak sequences-/ +/-- auxiliary definition of drop over weak sequences -/ @[simp] def drop.aux : ℕ → Option (α × WSeq α) → Computation (Option (α × WSeq α)) | 0 => Computation.pure @@ -716,12 +717,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 @@ -816,7 +814,7 @@ theorem eq_or_mem_iff_mem {s : WSeq α} {a a' s'} : · cases' this with i1 i2 rw [i1, i2] cases' s' with f al - dsimp only [cons, (· ∈ ·), WSeq.Mem, Seq.Mem, Seq.cons] + dsimp only [cons, Membership.mem, WSeq.Mem, Seq.Mem, Seq.cons] have h_a_eq_a' : a = a' ↔ some (some a) = some (some a') := by simp rw [h_a_eq_a'] refine ⟨Stream'.eq_or_mem_of_mem_cons, fun o => ?_⟩ @@ -1330,7 +1328,7 @@ theorem liftRel_map {δ} (R : α → β → Prop) (S : γ → δ → Prop) {s1 : theorem map_congr (f : α → β) {s t : WSeq α} (h : s ~ʷ t) : map f s ~ʷ map f t := liftRel_map _ _ h fun {_ _} => congr_arg _ -/-- auxiliary definition of `destruct_append` over weak sequences-/ +/-- auxiliary definition of `destruct_append` over weak sequences -/ @[simp] def destruct_append.aux (t : WSeq α) : Option (α × WSeq α) → Computation (Option (α × WSeq α)) | none => destruct t @@ -1349,7 +1347,7 @@ theorem destruct_append (s t : WSeq α) : · refine ⟨nil, t, ?_, ?_⟩ <;> simp · exact ⟨s, t, rfl, rfl⟩ -/-- auxiliary definition of `destruct_join` over weak sequences-/ +/-- auxiliary definition of `destruct_join` over weak sequences -/ @[simp] def destruct_join.aux : Option (WSeq α × WSeq (WSeq α)) → Computation (Option (α × WSeq α)) | none => Computation.pure none @@ -1407,7 +1405,7 @@ theorem liftRel_join.lem (R : α → β → Prop) {S T} {U : WSeq α → WSeq β U s1 s2) {a} (ma : a ∈ destruct (join S)) : ∃ b, b ∈ destruct (join T) ∧ LiftRelO R U a b := by cases' exists_results_of_mem ma with n h; clear ma; revert S T ST a - induction' n using Nat.strongInductionOn with n IH + induction' n using Nat.strongRecOn with n IH intro S T ST a ra; simp only [destruct_join] at ra exact let ⟨o, m, k, rs1, rs2, en⟩ := of_results_bind ra @@ -1622,3 +1620,5 @@ instance lawfulMonad : LawfulMonad WSeq := end WSeq end Stream' + +set_option linter.style.longFile 1800 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 c2505bdf4d84b..691836860b538 100644 --- a/Mathlib/Data/Set/Basic.lean +++ b/Mathlib/Data/Set/Basic.lean @@ -4,7 +4,7 @@ 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.Defs +import Mathlib.Data.Set.Operations import Mathlib.Order.Basic import Mathlib.Order.SymmDiff import Mathlib.Tactic.Tauto @@ -435,6 +435,11 @@ theorem Nonempty.to_type : s.Nonempty → Nonempty α := fun ⟨x, _⟩ => ⟨x instance univ.nonempty [Nonempty α] : Nonempty (↥(Set.univ : Set α)) := Set.univ_nonempty.to_subtype +-- Redeclare for refined keys +-- `Nonempty (@Subtype _ (@Membership.mem _ (Set _) _ (@Top.top (Set _) _)))` +instance instNonemptyTop [Nonempty α] : Nonempty (⊤ : Set α) := + inferInstanceAs (Nonempty (univ : Set α)) + theorem nonempty_of_nonempty_subtype [Nonempty (↥s)] : s.Nonempty := nonempty_subtype.mp ‹_› @@ -617,11 +622,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 @@ -735,11 +740,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 @@ -962,7 +967,7 @@ theorem insert_union_distrib (a : α) (s t : Set α) : insert a (s ∪ t) = inse ext fun _ => or_or_distrib_left theorem insert_inj (ha : a ∉ s) : insert a s = insert b s ↔ a = b := - ⟨fun h => eq_of_not_mem_of_mem_insert (h.subst <| mem_insert a s) ha, + ⟨fun h => eq_of_not_mem_of_mem_insert (h ▸ mem_insert a s) ha, congr_arg (fun x => insert x s)⟩ -- useful in proofs by induction @@ -1129,7 +1134,7 @@ 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 := @@ -1182,7 +1187,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 @@ -1428,8 +1433,9 @@ theorem not_mem_of_mem_diff {s t : Set α} {x : α} (h : x ∈ s \ t) : x ∉ t theorem diff_eq_compl_inter {s t : Set α} : s \ t = tᶜ ∩ s := by rw [diff_eq, inter_comm] -theorem nonempty_diff {s t : Set α} : (s \ t).Nonempty ↔ ¬s ⊆ t := +theorem diff_nonempty {s t : Set α} : (s \ t).Nonempty ↔ ¬s ⊆ t := inter_compl_nonempty_iff +@[deprecated (since := "2024-08-27")] alias nonempty_diff := diff_nonempty theorem diff_subset {s t : Set α} : s \ t ⊆ s := show s \ t ≤ s from sdiff_le @@ -1575,7 +1581,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 @@ -1952,7 +1958,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 @@ -1972,9 +1978,8 @@ section Inclusion variable {α : Type*} {s t u : Set α} /-- `inclusion` is the "identity" function between two subsets `s` and `t`, where `s ⊆ t` -/ -def inclusion (h : s ⊆ t) : s → t := fun x : s => (⟨x, h x.2⟩ : t) +abbrev inclusion (h : s ⊆ t) : s → t := fun x : s => (⟨x, h x.2⟩ : t) -@[simp] theorem inclusion_self (x : s) : inclusion Subset.rfl x = x := by cases x rfl @@ -2011,7 +2016,6 @@ theorem val_comp_inclusion (h : s ⊆ t) : Subtype.val ∘ inclusion h = Subtype theorem inclusion_injective (h : s ⊆ t) : Injective (inclusion h) | ⟨_, _⟩, ⟨_, _⟩ => Subtype.ext_iff_val.2 ∘ Subtype.ext_iff_val.1 -@[simp] theorem inclusion_inj (h : s ⊆ t) {x y : s} : inclusion h x = inclusion h y ↔ x = y := (inclusion_injective h).eq_iff @@ -2021,11 +2025,9 @@ theorem eq_of_inclusion_surjective {s t : Set α} {h : s ⊆ t} obtain ⟨y, hy⟩ := h_surj ⟨x, hx⟩ exact mem_of_eq_of_mem (congr_arg Subtype.val hy).symm y.prop -@[simp] theorem inclusion_le_inclusion [Preorder α] {s t : Set α} (h : s ⊆ t) {x y : s} : inclusion h x ≤ inclusion h y ↔ x ≤ y := Iff.rfl -@[simp] theorem inclusion_lt_inclusion [Preorder α] {s t : Set α} (h : s ⊆ t) {x y : s} : inclusion h x < inclusion h y ↔ x < y := Iff.rfl @@ -2139,7 +2141,7 @@ end Monotone /-! ### Disjoint sets -/ -variable {α β : Type*} {s t u : Set α} {f : α → β} +variable {α : Type*} {s t u : Set α} namespace Disjoint @@ -2171,3 +2173,5 @@ end Disjoint @[simp] theorem Prop.compl_singleton (p : Prop) : ({p}ᶜ : Set Prop) = {¬p} := ext fun q ↦ by simpa [@Iff.comm q] using not_iff + +set_option linter.style.longFile 2300 diff --git a/Mathlib/Data/Set/Card.lean b/Mathlib/Data/Set/Card.lean index 115d6555eaac1..57aba3430a761 100644 --- a/Mathlib/Data/Set/Card.lean +++ b/Mathlib/Data/Set/Card.lean @@ -544,7 +544,7 @@ theorem nonempty_of_ncard_ne_zero (hs : s.ncard ≠ 0) : s.Nonempty := by rw [nonempty_iff_ne_empty]; rintro rfl; simp at hs @[simp] theorem ncard_singleton (a : α) : ({a} : Set α).ncard = 1 := by - simpa [ncard, encard_singleton] using ENat.toNat_coe 1 + simp [ncard] theorem ncard_singleton_inter (a : α) (s : Set α) : ({a} ∩ s).ncard ≤ 1 := by rw [← Nat.cast_le (α := ℕ∞), (toFinite _).cast_ncard_eq, Nat.cast_one] @@ -557,7 +557,7 @@ section InsertErase hs.cast_ncard_eq, encard_insert_of_not_mem h] theorem ncard_insert_of_mem {a : α} (h : a ∈ s) : ncard (insert a s) = s.ncard := by - rw [insert_eq_of_mem h] + rw [insert_eq_of_mem h] theorem ncard_insert_le (a : α) (s : Set α) : (insert a s).ncard ≤ s.ncard + 1 := by obtain hs | hs := s.finite_or_infinite @@ -616,6 +616,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 : α → β} @@ -753,7 +762,7 @@ theorem surj_on_of_inj_on_of_ncard_le {t : Set β} (f : ∀ a ∈ s, β) (hf : have hft := ht.fintype have hft' := Fintype.ofInjective f' finj set f'' : ∀ a, a ∈ s.toFinset → β := fun a h ↦ f a (by simpa using h) - convert @Finset.surj_on_of_inj_on_of_card_le _ _ _ t.toFinset f'' _ _ _ _ (by simpa) + convert @Finset.surj_on_of_inj_on_of_card_le _ _ _ t.toFinset f'' _ _ _ _ (by simpa) using 1 · simp · simp [hf] · intros a₁ a₂ ha₁ ha₂ h @@ -947,7 +956,8 @@ theorem exists_eq_insert_iff_ncard (hs : s.Finite := by toFinite_tac) : convert Iff.rfl using 2; simp only [Finite.mem_toFinset] ext x simp [Finset.ext_iff, Set.ext_iff] - simp only [ht.ncard, exists_prop, add_eq_zero, and_false, iff_false, not_exists, not_and] + simp only [ht.ncard, exists_prop, add_eq_zero, and_false, iff_false, not_exists, not_and, + reduceCtorEq] rintro x - rfl exact ht (hs.insert x) @@ -991,6 +1001,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] @@ -1012,9 +1028,8 @@ theorem eq_insert_of_ncard_eq_succ {n : ℕ} (h : s.ncard = n + 1) : obtain ⟨a, t, hat, hts, rfl⟩ := h simp only [Finset.ext_iff, Finset.mem_insert, Finite.mem_toFinset] at hts refine ⟨a, t, hat, ?_, ?_⟩ - · simp only [Finset.mem_coe, Set.ext_iff, mem_insert_iff] - tauto - simp + · simp [Set.ext_iff, hts] + · simp theorem ncard_eq_succ {n : ℕ} (hs : s.Finite := by toFinite_tac) : s.ncard = n + 1 ↔ ∃ a t, a ∉ t ∧ insert a t = s ∧ t.ncard = n := by @@ -1026,16 +1041,13 @@ theorem ncard_eq_two : s.ncard = 2 ↔ ∃ x y, x ≠ y ∧ s = {x, y} := by rw [← encard_eq_two, ncard_def, ← Nat.cast_inj (R := ℕ∞), Nat.cast_ofNat] refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ · rwa [ENat.coe_toNat] at h; rintro h'; simp [h'] at h - rw [h]; rfl + simp [h] theorem ncard_eq_three : s.ncard = 3 ↔ ∃ x y z, x ≠ y ∧ x ≠ z ∧ y ≠ z ∧ s = {x, y, z} := by rw [← encard_eq_three, ncard_def, ← Nat.cast_inj (R := ℕ∞), Nat.cast_ofNat] refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ · rwa [ENat.coe_toNat] at h; rintro h'; simp [h'] at h - rw [h]; rfl + 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/Constructions.lean b/Mathlib/Data/Set/Constructions.lean index 9011537864b94..6690c61075cd1 100644 --- a/Mathlib/Data/Set/Constructions.lean +++ b/Mathlib/Data/Set/Constructions.lean @@ -59,12 +59,14 @@ theorem finiteInter_mem (cond : FiniteInter S) (F : Finset (Set α)) : theorem finiteInterClosure_insert {A : Set α} (cond : FiniteInter S) (P) (H : P ∈ finiteInterClosure (insert A S)) : P ∈ S ∨ ∃ Q ∈ S, P = A ∩ Q := by - induction' H with S h T1 T2 _ _ h1 h2 - · cases h + induction H with + | basic h => + cases h · exact Or.inr ⟨Set.univ, cond.univ_mem, by simpa⟩ · exact Or.inl (by assumption) - · exact Or.inl cond.univ_mem - · rcases h1 with (h | ⟨Q, hQ, rfl⟩) <;> rcases h2 with (i | ⟨R, hR, rfl⟩) + | univ => exact Or.inl cond.univ_mem + | @inter T1 T2 _ _ h1 h2 => + rcases h1 with (h | ⟨Q, hQ, rfl⟩) <;> rcases h2 with (i | ⟨R, hR, rfl⟩) · exact Or.inl (cond.inter_mem h i) · exact Or.inr ⟨T1 ∩ R, cond.inter_mem h hR, by simp only [← Set.inter_assoc, Set.inter_comm _ A]⟩ diff --git a/Mathlib/Data/Set/Countable.lean b/Mathlib/Data/Set/Countable.lean index bd1f3720faffe..4add89c35bb25 100644 --- a/Mathlib/Data/Set/Countable.lean +++ b/Mathlib/Data/Set/Countable.lean @@ -101,8 +101,8 @@ lemma range_enumerateCountable_of_mem {s : Set α} (h : s.Countable) {default : lemma enumerateCountable_mem {s : Set α} (h : s.Countable) {default : α} (h_mem : default ∈ s) (n : ℕ) : enumerateCountable h default n ∈ s := by - conv_rhs => rw [← range_enumerateCountable_of_mem h h_mem] - exact mem_range_self n + convert mem_range_self n + exact (range_enumerateCountable_of_mem h h_mem).symm end Enumerate @@ -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 @@ -257,6 +257,10 @@ theorem countable_setOf_finite_subset {s : Set α} (hs : s.Countable) : lift t to Finset s using ht.of_finite_image Subtype.val_injective.injOn exact mem_range_self _ +/-- The set of finite sets in a countable type is countable. -/ +theorem Countable.setOf_finite [Countable α] : {s : Set α | s.Finite}.Countable := by + simpa using countable_setOf_finite_subset countable_univ + theorem countable_univ_pi {π : α → Type*} [Finite α] {s : ∀ a, Set (π a)} (hs : ∀ a, (s a).Countable) : (pi univ s).Countable := have := fun a ↦ (hs a).to_subtype; .of_equiv _ (Equiv.Set.univPi s).symm @@ -287,9 +291,9 @@ theorem countable_setOf_nonempty_of_disjoint {f : β → Set α} have A : Injective F := by rintro ⟨t, ht⟩ ⟨t', ht'⟩ htt' have A : (f t ∩ f t').Nonempty := by - refine ⟨F ⟨t, ht⟩, hF _, ?_⟩ + refine ⟨F ⟨t, ht⟩, hF ⟨t, _⟩, ?_⟩ rw [htt'] - exact hF _ + exact hF ⟨t', _⟩ simp only [Subtype.mk.injEq] by_contra H exact not_disjoint_iff_nonempty_inter.2 A (hf H) diff --git a/Mathlib/Data/Set/Defs.lean b/Mathlib/Data/Set/Defs.lean index 620c7afe1b44c..4ffdc4697e45f 100644 --- a/Mathlib/Data/Set/Defs.lean +++ b/Mathlib/Data/Set/Defs.lean @@ -1,297 +1,263 @@ /- -Copyright (c) 2016 Jeremy Avigad. All rights reserved. +Copyright (c) 2016 Microsoft Corporation. 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, -Minchao Wu, Yury Kudryashov, Floris van Doorn +Authors: Leonardo de Moura -/ -import Mathlib.Data.SProd -import Mathlib.Data.Subtype -import Mathlib.Order.Notation -import Mathlib.Util.CompileInductive +import Mathlib.Init +import Batteries.Util.ExtendedBinder +import Lean.Elab.Term /-! -# Basic definitions about sets +# Sets -In this file we define various operations on sets. -We also provide basic lemmas needed to unfold the definitions. -More advanced theorems about these definitions are located in other files in `Mathlib/Data/Set`. +This file sets up the theory of sets whose elements have a given type. ## Main definitions -- complement of a set and set difference; -- `Set.Elem`: coercion of a set to a type; it is reducibly equal to `{x // x ∈ s}`; -- `Set.preimage f s`, a.k.a. `f ⁻¹' s`: preimage of a set; -- `Set.range f`: the range of a function; - it is more general than `f '' univ` because it allows functions from `Sort*`; -- `s ×ˢ t`: product of `s : Set α` and `t : Set β` as a set in `α × β`; -- `Set.diagonal`: the diagonal in `α × α`; -- `Set.offDiag s`: the part of `s ×ˢ s` that is off the diagonal; -- `Set.pi`: indexed product of a family of sets `∀ i, Set (α i)`, - as a set in `∀ i, α i`; -- `Set.EqOn f g s`: the predicate saying that two functions are equal on a set; -- `Set.MapsTo f s t`: the predicate syaing that `f` sends all points of `s` to `t; -- `Set.MapsTo.restrict`: restrict `f : α → β` to `f' : s → t` provided that `Set.MapsTo f s t`; -- `Set.restrictPreimage`: restrict `f : α → β` to `f' : (f ⁻¹' t) → t`; -- `Set.InjOn`: the predicate saying that `f` is injective on a set; -- `Set.SurjOn f s t`: the prediate saying that `t ⊆ f '' s`; -- `Set.BijOn f s t`: the predicate saying that `f` is injective on `s` and `f '' s = t`; -- `Set.graphOn`: the graph of a function on a set; -- `Set.LeftInvOn`, `Set.RightInvOn`, `Set.InvOn`: - the predicates saying that `f'` is a left, right or two-sided inverse of `f` on `s`, `t`, or both; -- `Set.image2`: the image of a pair of sets under a binary operation, - mostly useful to define pointwise algebraic operations on sets; -- `Set.seq`: monadic `seq` operation on sets; - we don't use monadic notation to ensure support for maps between different universes; - -## Notations - -- `f '' s`: image of a set; -- `f ⁻¹' s`: preimage of a set; -- `s ×ˢ t`: the product of sets; -- `s ∪ t`: the union of two sets; -- `s ∩ t`: the intersection of two sets; -- `sᶜ`: the complement of a set; -- `s \ t`: the difference of two sets. - -## Keywords - -set, image, preimage --/ - --- https://github.com/leanprover/lean4/issues/2096 -compile_def% Union.union -compile_def% Inter.inter -compile_def% SDiff.sdiff -compile_def% HasCompl.compl -compile_def% EmptyCollection.emptyCollection -compile_def% Insert.insert -compile_def% Singleton.singleton - -attribute [ext] Set.ext - -universe u v w - -namespace Set - -variable {α : Type u} {β : Type v} {γ : Type w} - -@[simp, mfld_simps] theorem mem_setOf_eq {x : α} {p : α → Prop} : (x ∈ {y | p y}) = p x := rfl - -@[simp, mfld_simps] theorem mem_univ (x : α) : x ∈ @univ α := trivial - -instance : HasCompl (Set α) := ⟨fun s ↦ {x | x ∉ s}⟩ - -@[simp] theorem mem_compl_iff (s : Set α) (x : α) : x ∈ sᶜ ↔ x ∉ s := Iff.rfl - -theorem diff_eq (s t : Set α) : s \ t = s ∩ tᶜ := rfl - -@[simp] theorem mem_diff {s t : Set α} (x : α) : x ∈ s \ t ↔ x ∈ s ∧ x ∉ t := Iff.rfl - -theorem mem_diff_of_mem {s t : Set α} {x : α} (h1 : x ∈ s) (h2 : x ∉ t) : x ∈ s \ t := ⟨h1, h2⟩ - --- Porting note: I've introduced this abbreviation, with the `@[coe]` attribute, --- so that `norm_cast` has something to index on. --- It is currently an abbreviation so that instance coming from `Subtype` are available. --- If you're interested in making it a `def`, as it probably should be, --- you'll then need to create additional instances (and possibly prove lemmas about them). --- The first error should appear below at `monotoneOn_iff_monotone`. -/-- Given the set `s`, `Elem s` is the `Type` of element of `s`. -/ -@[coe, reducible] def Elem (s : Set α) : Type u := {x // x ∈ s} - -/-- Coercion from a set to the corresponding subtype. -/ -instance : CoeSort (Set α) (Type u) := ⟨Elem⟩ - -/-- The preimage of `s : Set β` by `f : α → β`, written `f ⁻¹' s`, - is the set of `x : α` such that `f x ∈ s`. -/ -def preimage (f : α → β) (s : Set β) : Set α := {x | f x ∈ s} - -/-- `f ⁻¹' t` denotes the preimage of `t : Set β` under the function `f : α → β`. -/ -infixl:80 " ⁻¹' " => preimage - -@[simp, mfld_simps] -theorem mem_preimage {f : α → β} {s : Set β} {a : α} : a ∈ f ⁻¹' s ↔ f a ∈ s := Iff.rfl - -/-- `f '' s` denotes the image of `s : Set α` under the function `f : α → β`. -/ -infixl:80 " '' " => image - -@[simp] -theorem mem_image (f : α → β) (s : Set α) (y : β) : y ∈ f '' s ↔ ∃ x ∈ s, f x = y := - Iff.rfl +Given a type `X` and a predicate `p : X → Prop`: -@[mfld_simps] -theorem mem_image_of_mem (f : α → β) {x : α} {a : Set α} (h : x ∈ a) : f x ∈ f '' a := - ⟨_, h, rfl⟩ +* `Set X` : the type of sets whose elements have type `X` +* `{a : X | p a} : Set X` : the set of all elements of `X` satisfying `p` +* `{a | p a} : Set X` : a more concise notation for `{a : X | p a}` +* `{f x y | (x : X) (y : Y)} : Set Z` : a more concise notation for `{z : Z | ∃ x y, f x y = z}` +* `{a ∈ S | p a} : Set X` : given `S : Set X`, the subset of `S` consisting of + its elements satisfying `p`. -/-- Restriction of `f` to `s` factors through `s.imageFactorization f : s → f '' s`. -/ -def imageFactorization (f : α → β) (s : Set α) : s → f '' s := fun p => - ⟨f p.1, mem_image_of_mem f p.2⟩ +## Implementation issues -/-- `kernImage f s` is the set of `y` such that `f ⁻¹ y ⊆ s`. -/ -def kernImage (f : α → β) (s : Set α) : Set β := {y | ∀ ⦃x⦄, f x = y → x ∈ s} +As in Lean 3, `Set X := X → Prop` +This file is a port of the core Lean 3 file `lib/lean/library/init/data/set.lean`. -lemma subset_kernImage_iff {s : Set β} {t : Set α} {f : α → β} : s ⊆ kernImage f t ↔ f ⁻¹' s ⊆ t := - ⟨fun h _ hx ↦ h hx rfl, - fun h _ hx y hy ↦ h (show f y ∈ s from hy.symm ▸ hx)⟩ - -section Range - -variable {ι : Sort*} {f : ι → α} - -/-- Range of a function. - -This function is more flexible than `f '' univ`, as the image requires that the domain is in Type -and not an arbitrary Sort. -/ -def range (f : ι → α) : Set α := {x | ∃ y, f y = x} - -@[simp] theorem mem_range {x : α} : x ∈ range f ↔ ∃ y, f y = x := Iff.rfl - -@[mfld_simps] theorem mem_range_self (i : ι) : f i ∈ range f := ⟨i, rfl⟩ - -/-- Any map `f : ι → α` factors through a map `rangeFactorization f : ι → range f`. -/ -def rangeFactorization (f : ι → α) : ι → range f := fun i => ⟨f i, mem_range_self i⟩ - -end Range - -/-- We can use the axiom of choice to pick a preimage for every element of `range f`. -/ -noncomputable def rangeSplitting (f : α → β) : range f → α := fun x => x.2.choose - --- This can not be a `@[simp]` lemma because the head of the left hand side is a variable. -theorem apply_rangeSplitting (f : α → β) (x : range f) : f (rangeSplitting f x) = x := - x.2.choose_spec - -@[simp] -theorem comp_rangeSplitting (f : α → β) : f ∘ rangeSplitting f = Subtype.val := by - ext - simp only [Function.comp_apply] - apply apply_rangeSplitting - -section Prod +-/ -/-- The cartesian product `Set.prod s t` is the set of `(a, b)` such that `a ∈ s` and `b ∈ t`. -/ -def prod (s : Set α) (t : Set β) : Set (α × β) := {p | p.1 ∈ s ∧ p.2 ∈ t} +open Lean Elab Term Meta Batteries.ExtendedBinder -@[default_instance] -instance instSProd : SProd (Set α) (Set β) (Set (α × β)) where - sprod := Set.prod +universe u +variable {α : Type u} -theorem prod_eq (s : Set α) (t : Set β) : s ×ˢ t = Prod.fst ⁻¹' s ∩ Prod.snd ⁻¹' t := rfl +/-- A set is a collection of elements of some type `α`. -variable {a : α} {b : β} {s : Set α} {t : Set β} {p : α × β} +Although `Set` is defined as `α → Prop`, this is an implementation detail which should not be +relied on. Instead, `setOf` and membership of a set (`∈`) should be used to convert between sets +and predicates. +-/ +def Set (α : Type u) := α → Prop -theorem mem_prod_eq : (p ∈ s ×ˢ t) = (p.1 ∈ s ∧ p.2 ∈ t) := rfl +/-- Turn a predicate `p : α → Prop` into a set, also written as `{x | p x}` -/ +def setOf {α : Type u} (p : α → Prop) : Set α := + p -@[simp, mfld_simps] -theorem mem_prod : p ∈ s ×ˢ t ↔ p.1 ∈ s ∧ p.2 ∈ t := .rfl +namespace Set -@[mfld_simps] -theorem prod_mk_mem_set_prod_eq : ((a, b) ∈ s ×ˢ t) = (a ∈ s ∧ b ∈ t) := rfl +/-- Membership in a set -/ +protected def Mem (s : Set α) (a : α) : Prop := + s a -theorem mk_mem_prod (ha : a ∈ s) (hb : b ∈ t) : (a, b) ∈ s ×ˢ t := ⟨ha, hb⟩ +instance : Membership α (Set α) := + ⟨Set.Mem⟩ -end Prod +theorem ext {a b : Set α} (h : ∀ (x : α), x ∈ a ↔ x ∈ b) : a = b := + funext (fun x ↦ propext (h x)) -section Diagonal -/-- `diagonal α` is the set of `α × α` consisting of all pairs of the form `(a, a)`. -/ -def diagonal (α : Type*) : Set (α × α) := {p | p.1 = p.2} +/-- The subset relation on sets. `s ⊆ t` means that all elements of `s` are elements of `t`. -theorem mem_diagonal (x : α) : (x, x) ∈ diagonal α := rfl +Note that you should **not** use this definition directly, but instead write `s ⊆ t`. -/ +protected def Subset (s₁ s₂ : Set α) := + ∀ ⦃a⦄, a ∈ s₁ → a ∈ s₂ -@[simp] theorem mem_diagonal_iff {x : α × α} : x ∈ diagonal α ↔ x.1 = x.2 := .rfl +/-- Porting note: we introduce `≤` before `⊆` to help the unifier when applying lattice theorems +to subset hypotheses. -/ +instance : LE (Set α) := + ⟨Set.Subset⟩ -/-- The off-diagonal of a set `s` is the set of pairs `(a, b)` with `a, b ∈ s` and `a ≠ b`. -/ -def offDiag (s : Set α) : Set (α × α) := {x | x.1 ∈ s ∧ x.2 ∈ s ∧ x.1 ≠ x.2} +instance : HasSubset (Set α) := + ⟨(· ≤ ·)⟩ -@[simp] -theorem mem_offDiag {x : α × α} {s : Set α} : x ∈ s.offDiag ↔ x.1 ∈ s ∧ x.2 ∈ s ∧ x.1 ≠ x.2 := - Iff.rfl +instance : EmptyCollection (Set α) := + ⟨fun _ ↦ False⟩ -end Diagonal +end Set -section Pi +namespace Mathlib.Meta -variable {ι : Type*} {α : ι → Type*} +/-- Set builder syntax. This can be elaborated to either a `Set` or a `Finset` depending on context. -/-- Given an index set `ι` and a family of sets `t : Π i, Set (α i)`, `pi s t` -is the set of dependent functions `f : Πa, π a` such that `f a` belongs to `t a` -whenever `a ∈ s`. -/ -def pi (s : Set ι) (t : ∀ i, Set (α i)) : Set (∀ i, α i) := {f | ∀ i ∈ s, f i ∈ t i} +The elaborators for this syntax are located in: +* `Data.Set.Defs` for the `Set` builder notation elaborator for syntax of the form `{x | p x}`, + `{x : α | p x}`, `{binder x | p x}`. +* `Data.Finset.Basic` for the `Finset` builder notation elaborator for syntax of the form + `{x ∈ s | p x}`. +* `Data.Fintype.Basic` for the `Finset` builder notation elaborator for syntax of the form + `{x | p x}`, `{x : α | p x}`, `{x ∉ s | p x}`, `{x ≠ a | p x}`. +* `Order.LocallyFinite.Basic` for the `Finset` builder notation elaborator for syntax of the form + `{x ≤ a | p x}`, `{x ≥ a | p x}`, `{x < a | p x}`, `{x > a | p x}`. +-/ +syntax (name := setBuilder) "{" extBinder " | " term "}" : term + +/-- Elaborate set builder notation for `Set`. + +* `{x | p x}` is elaborated as `Set.setOf fun x ↦ p x` +* `{x : α | p x}` is elaborated as `Set.setOf fun x : α ↦ p x` +* `{binder x | p x}`, where `x` is bound by the `binder` binder, is elaborated as + `{x | binder x ∧ p x}`. The typical example is `{x ∈ s | p x}`, which is elaborated as + `{x | x ∈ s ∧ p x}`. The possible binders are + * `· ∈ s`, `· ∉ s` + * `· ⊆ s`, `· ⊂ s`, `· ⊇ s`, `· ⊃ s` + * `· ≤ a`, `· ≥ a`, `· < a`, `· > a`, `· ≠ a` + + More binders can be declared using the `binder_predicate` command, see `Init.BinderPredicates` for + more info. + +See also +* `Data.Finset.Basic` for the `Finset` builder notation elaborator partly overriding this one for + syntax of the form `{x ∈ s | p x}`. +* `Data.Fintype.Basic` for the `Finset` builder notation elaborator partly overriding this one for + syntax of the form `{x | p x}`, `{x : α | p x}`, `{x ∉ s | p x}`, `{x ≠ a | p x}`. +* `Order.LocallyFinite.Basic` for the `Finset` builder notation elaborator partly overriding this + one for syntax of the form `{x ≤ a | p x}`, `{x ≥ a | p x}`, `{x < a | p x}`, `{x > a | p x}`. +-/ +@[term_elab setBuilder] +def elabSetBuilder : TermElab + | `({ $x:ident | $p }), expectedType? => do + elabTerm (← `(setOf fun $x:ident ↦ $p)) expectedType? + | `({ $x:ident : $t | $p }), expectedType? => do + elabTerm (← `(setOf fun $x:ident : $t ↦ $p)) expectedType? + | `({ $x:ident $b:binderPred | $p }), expectedType? => do + elabTerm (← `(setOf fun $x:ident ↦ satisfies_binder_pred% $x $b ∧ $p)) expectedType? + | _, _ => throwUnsupportedSyntax + +/-- Unexpander for set builder notation. -/ +@[app_unexpander setOf] +def setOf.unexpander : Lean.PrettyPrinter.Unexpander + | `($_ fun $x:ident ↦ $p) => `({ $x:ident | $p }) + | `($_ fun ($x:ident : $ty:term) ↦ $p) => `({ $x:ident : $ty:term | $p }) + | _ => throw () + +open Batteries.ExtendedBinder in +/-- +`{ f x y | (x : X) (y : Y) }` is notation for the set of elements `f x y` constructed from the +binders `x` and `y`, equivalent to `{z : Z | ∃ x y, f x y = z}`. + +If `f x y` is a single identifier, it must be parenthesized to avoid ambiguity with `{x | p x}`; +for instance, `{(x) | (x : Nat) (y : Nat) (_hxy : x = y^2)}`. +-/ +macro (priority := low) "{" t:term " | " bs:extBinders "}" : term => + `({x | ∃ᵉ $bs:extBinders, $t = x}) + +/-- +* `{ pat : X | p }` is notation for pattern matching in set-builder notation, + where `pat` is a pattern that is matched by all objects of type `X` + and `p` is a proposition that can refer to variables in the pattern. + It is the set of all objects of type `X` which, when matched with the pattern `pat`, + make `p` come out true. +* `{ pat | p }` is the same, but in the case when the type `X` can be inferred. + +For example, `{ (m, n) : ℕ × ℕ | m * n = 12 }` denotes the set of all ordered pairs of +natural numbers whose product is 12. + +Note that if the type ascription is left out and `p` can be interpreted as an extended binder, +then the extended binder interpretation will be used. For example, `{ n + 1 | n < 3 }` will +be interpreted as `{ x : Nat | ∃ n < 3, n + 1 = x }` rather than using pattern matching. +-/ +macro (name := macroPattSetBuilder) (priority := low-1) + "{" pat:term " : " t:term " | " p:term "}" : term => + `({ x : $t | match x with | $pat => $p }) + +@[inherit_doc macroPattSetBuilder] +macro (priority := low-1) "{" pat:term " | " p:term "}" : term => + `({ x | match x with | $pat => $p }) + +/-- Pretty printing for set-builder notation with pattern matching. -/ +@[app_unexpander setOf] +def setOfPatternMatchUnexpander : Lean.PrettyPrinter.Unexpander + | `($_ fun $x:ident ↦ match $y:ident with | $pat => $p) => + if x == y then + `({ $pat:term | $p:term }) + else + throw () + | `($_ fun ($x:ident : $ty:term) ↦ match $y:ident with | $pat => $p) => + if x == y then + `({ $pat:term : $ty:term | $p:term }) + else + throw () + | _ => throw () + +end Mathlib.Meta -variable {s : Set ι} {t : ∀ i, Set (α i)} {f : ∀ i, α i} +namespace Set -@[simp] theorem mem_pi : f ∈ s.pi t ↔ ∀ i ∈ s, f i ∈ t i := .rfl +/-- The universal set on a type `α` is the set containing all elements of `α`. -theorem mem_univ_pi : f ∈ pi univ t ↔ ∀ i, f i ∈ t i := by simp +This is conceptually the "same as" `α` (in set theory, it is actually the same), but type theory +makes the distinction that `α` is a type while `Set.univ` is a term of type `Set α`. `Set.univ` can +itself be coerced to a type `↥Set.univ` which is in bijection with (but distinct from) `α`. -/ +def univ : Set α := {_a | True} -end Pi +/-- `Set.insert a s` is the set `{a} ∪ s`. -/-- Two functions `f₁ f₂ : α → β` are equal on `s` if `f₁ x = f₂ x` for all `x ∈ s`. -/ -def EqOn (f₁ f₂ : α → β) (s : Set α) : Prop := ∀ ⦃x⦄, x ∈ s → f₁ x = f₂ x +Note that you should **not** use this definition directly, but instead write `insert a s` (which is +mediated by the `Insert` typeclass). -/ +protected def insert (a : α) (s : Set α) : Set α := {b | b = a ∨ b ∈ s} -/-- `MapsTo f a b` means that the image of `a` is contained in `b`. -/ -def MapsTo (f : α → β) (s : Set α) (t : Set β) : Prop := ∀ ⦃x⦄, x ∈ s → f x ∈ t +instance : Insert α (Set α) := ⟨Set.insert⟩ -theorem mapsTo_image (f : α → β) (s : Set α) : MapsTo f s (f '' s) := fun _ ↦ mem_image_of_mem f +/-- The singleton of an element `a` is the set with `a` as a single element. -theorem mapsTo_preimage (f : α → β) (t : Set β) : MapsTo f (f ⁻¹' t) t := fun _ ↦ id +Note that you should **not** use this definition directly, but instead write `{a}`. -/ +protected def singleton (a : α) : Set α := {b | b = a} -/-- Given a map `f` sending `s : Set α` into `t : Set β`, restrict domain of `f` to `s` -and the codomain to `t`. Same as `Subtype.map`. -/ -def MapsTo.restrict (f : α → β) (s : Set α) (t : Set β) (h : MapsTo f s t) : s → t := - Subtype.map f h +instance instSingletonSet : Singleton α (Set α) := ⟨Set.singleton⟩ -/-- The restriction of a function onto the preimage of a set. -/ -@[simps!] -def restrictPreimage (t : Set β) (f : α → β) : f ⁻¹' t → t := - (Set.mapsTo_preimage f t).restrict _ _ _ +/-- The union of two sets `s` and `t` is the set of elements contained in either `s` or `t`. -/-- `f` is injective on `a` if the restriction of `f` to `a` is injective. -/ -def InjOn (f : α → β) (s : Set α) : Prop := - ∀ ⦃x₁ : α⦄, x₁ ∈ s → ∀ ⦃x₂ : α⦄, x₂ ∈ s → f x₁ = f x₂ → x₁ = x₂ +Note that you should **not** use this definition directly, but instead write `s ∪ t`. -/ +protected def union (s₁ s₂ : Set α) : Set α := {a | a ∈ s₁ ∨ a ∈ s₂} -/-- The graph of a function `f : α → β` on a set `s`. -/ -def graphOn (f : α → β) (s : Set α) : Set (α × β) := (fun x ↦ (x, f x)) '' s +instance : Union (Set α) := ⟨Set.union⟩ -/-- `f` is surjective from `a` to `b` if `b` is contained in the image of `a`. -/ -def SurjOn (f : α → β) (s : Set α) (t : Set β) : Prop := t ⊆ f '' s +/-- The intersection of two sets `s` and `t` is the set of elements contained in both `s` and `t`. -/-- `f` is bijective from `s` to `t` if `f` is injective on `s` and `f '' s = t`. -/ -def BijOn (f : α → β) (s : Set α) (t : Set β) : Prop := MapsTo f s t ∧ InjOn f s ∧ SurjOn f s t +Note that you should **not** use this definition directly, but instead write `s ∩ t`. -/ +protected def inter (s₁ s₂ : Set α) : Set α := {a | a ∈ s₁ ∧ a ∈ s₂} -/-- `g` is a left inverse to `f` on `a` means that `g (f x) = x` for all `x ∈ a`. -/ -def LeftInvOn (f' : β → α) (f : α → β) (s : Set α) : Prop := ∀ ⦃x⦄, x ∈ s → f' (f x) = x +instance : Inter (Set α) := ⟨Set.inter⟩ -/-- `g` is a right inverse to `f` on `b` if `f (g x) = x` for all `x ∈ b`. -/ -abbrev RightInvOn (f' : β → α) (f : α → β) (t : Set β) : Prop := LeftInvOn f f' t +/-- The complement of a set `s` is the set of elements not contained in `s`. -/-- `g` is an inverse to `f` viewed as a map from `a` to `b` -/ -def InvOn (g : β → α) (f : α → β) (s : Set α) (t : Set β) : Prop := - LeftInvOn g f s ∧ RightInvOn g f t +Note that you should **not** use this definition directly, but instead write `sᶜ`. -/ +protected def compl (s : Set α) : Set α := {a | a ∉ s} -section image2 +/-- The difference of two sets `s` and `t` is the set of elements contained in `s` but not in `t`. -/-- The image of a binary function `f : α → β → γ` as a function `Set α → Set β → Set γ`. -Mathematically this should be thought of as the image of the corresponding function `α × β → γ`. -/ -def image2 (f : α → β → γ) (s : Set α) (t : Set β) : Set γ := {c | ∃ a ∈ s, ∃ b ∈ t, f a b = c} +Note that you should **not** use this definition directly, but instead write `s \ t`. -/ +protected def diff (s t : Set α) : Set α := {a ∈ s | a ∉ t} -variable {f : α → β → γ} {s : Set α} {t : Set β} {a : α} {b : β} {c : γ} +instance : SDiff (Set α) := ⟨Set.diff⟩ -@[simp] theorem mem_image2 : c ∈ image2 f s t ↔ ∃ a ∈ s, ∃ b ∈ t, f a b = c := .rfl +/-- `𝒫 s` is the set of all subsets of `s`. -/ +def powerset (s : Set α) : Set (Set α) := {t | t ⊆ s} -theorem mem_image2_of_mem (ha : a ∈ s) (hb : b ∈ t) : f a b ∈ image2 f s t := - ⟨a, ha, b, hb, rfl⟩ +@[inherit_doc] prefix:100 "𝒫" => powerset -end image2 +universe v in +/-- The image of `s : Set α` by `f : α → β`, written `f '' s`, is the set of `b : β` such that +`f a = b` for some `a ∈ s`. -/ +def image {β : Type v} (f : α → β) (s : Set α) : Set β := {f a | a ∈ s} -/-- Given a set `s` of functions `α → β` and `t : Set α`, `seq s t` is the union of `f '' t` over -all `f ∈ s`. -/ -def seq (s : Set (α → β)) (t : Set α) : Set β := image2 (fun f ↦ f) s t +instance : Functor Set where map := @Set.image -@[simp] -theorem mem_seq_iff {s : Set (α → β)} {t : Set α} {b : β} : - b ∈ seq s t ↔ ∃ f ∈ s, ∃ a ∈ t, (f : α → β) a = b := - Iff.rfl +instance : LawfulFunctor Set where + id_map _ := funext fun _ ↦ propext ⟨fun ⟨_, sb, rfl⟩ ↦ sb, fun sb ↦ ⟨_, sb, rfl⟩⟩ + comp_map g h _ := funext <| fun c ↦ propext + ⟨fun ⟨a, ⟨h₁, h₂⟩⟩ ↦ ⟨g a, ⟨⟨a, ⟨h₁, rfl⟩⟩, h₂⟩⟩, + fun ⟨_, ⟨⟨a, ⟨h₁, h₂⟩⟩, h₃⟩⟩ ↦ ⟨a, ⟨h₁, show h (g a) = c from h₂ ▸ h₃⟩⟩⟩ + map_const := rfl -lemma seq_eq_image2 (s : Set (α → β)) (t : Set α) : seq s t = image2 (fun f a ↦ f a) s t := rfl +/-- The property `s.Nonempty` expresses the fact that the set `s` is not empty. It should be used +in theorem assumptions instead of `∃ x, x ∈ s` or `s ≠ ∅` as it gives access to a nice API thanks +to the dot notation. -/ +protected def Nonempty (s : Set α) : Prop := + ∃ x, x ∈ s end Set diff --git a/Mathlib/Data/Set/Enumerate.lean b/Mathlib/Data/Set/Enumerate.lean index 51a53f2a30a03..fd4f8dbb791b1 100644 --- a/Mathlib/Data/Set/Enumerate.lean +++ b/Mathlib/Data/Set/Enumerate.lean @@ -81,14 +81,15 @@ theorem enumerate_inj {n₁ n₂ : ℕ} {a : α} {s : Set α} (h_sel : ∀ s a, | zero => rfl | succ m => have h' : enumerate sel (s \ {a}) m = some a := by - simp_all only [enumerate, Nat.zero_eq, Nat.add_eq, zero_add]; exact h₂ + simp_all only [enumerate, Nat.add_eq, zero_add]; exact h₂ have : a ∈ s \ {a} := enumerate_mem sel h_sel h' simp_all [Set.mem_diff_singleton] | succ k ih => cases h : sel s with /- Porting note: The original covered both goals with just `simp_all <;> tauto` -/ | none => - simp_all only [add_comm, self_eq_add_left, Nat.add_succ, enumerate_eq_none_of_sel _ h] + simp_all only [add_comm, self_eq_add_left, Nat.add_succ, enumerate_eq_none_of_sel _ h, + reduceCtorEq] | some => simp_all only [add_comm, self_eq_add_left, enumerate, Option.some.injEq, Nat.add_succ, Nat.succ.injEq] diff --git a/Mathlib/Data/Set/Finite.lean b/Mathlib/Data/Set/Finite.lean index 933b71188dd78..cf7a2bfbb02d2 100644 --- a/Mathlib/Data/Set/Finite.lean +++ b/Mathlib/Data/Set/Finite.lean @@ -3,8 +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, 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 @@ -280,6 +280,9 @@ section FintypeInstances instance fintypeUniv [Fintype α] : Fintype (@univ α) := Fintype.ofEquiv α (Equiv.Set.univ α).symm +-- Redeclared with appropriate keys +instance fintypeTop [Fintype α] : Fintype (⊤ : Set α) := inferInstanceAs (Fintype (univ : Set α)) + /-- If `(Set.univ : Set α)` is finite then `α` is a finite type. -/ noncomputable def fintypeOfFiniteUniv (H : (univ (α := α)).Finite) : Fintype α := @Fintype.ofEquiv _ (univ : Set α) H.fintype (Equiv.Set.univ _) @@ -894,7 +897,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 @@ -1348,9 +1351,10 @@ theorem exists_upper_bound_image [Nonempty α] [LinearOrder β] (s : Set α) (f theorem Finite.iSup_biInf_of_monotone {ι ι' α : Type*} [Preorder ι'] [Nonempty ι'] [IsDirected ι' (· ≤ ·)] [Order.Frame α] {s : Set ι} (hs : s.Finite) {f : ι → ι' → α} (hf : ∀ i ∈ s, Monotone (f i)) : ⨆ j, ⨅ i ∈ s, f i j = ⨅ i ∈ s, ⨆ j, f i j := by - induction' s, hs using Set.Finite.dinduction_on with a s _ _ ihs hf - · simp [iSup_const] - · rw [forall_mem_insert] at hf + induction s, hs using Set.Finite.dinduction_on with + | H0 => simp [iSup_const] + | H1 _ _ ihs => + rw [forall_mem_insert] at hf simp only [iInf_insert, ← ihs hf.2] exact iSup_inf_of_monotone hf.1 fun j₁ j₂ hj => iInf₂_mono fun i hi => hf.2 i hi hj @@ -1524,6 +1528,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 @@ -1563,3 +1568,20 @@ theorem DirectedOn.exists_mem_subset_of_finset_subset_biUnion {α ι : Type*} {f rw [Set.biUnion_eq_iUnion] at hs 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 := 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 141de079ea67a..0ae9780c502d9 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 @@ -303,8 +247,9 @@ theorem MapsTo.val_restrict_apply (h : MapsTo f s t) (x : s) : (h.restrict f s t theorem MapsTo.coe_iterate_restrict {f : α → α} (h : MapsTo f s s) (x : s) (k : ℕ) : h.restrict^[k] x = f^[k] x := by - induction' k with k ih; · simp - simp only [iterate_succ', comp_apply, val_restrict_apply, ih] + induction k with + | zero => simp + | succ k ih => simp only [iterate_succ', comp_apply, val_restrict_apply, ih] /-- Restricting the domain and then the codomain is the same as `MapsTo.restrict`. -/ @[simp] @@ -327,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 := @@ -379,9 +324,9 @@ theorem MapsTo.iterate_restrict {f : α → α} {s : Set α} (h : MapsTo f s s) (h.restrict f s s)^[n] = (h.iterate n).restrict _ _ _ := by funext x rw [Subtype.ext_iff, MapsTo.val_restrict_apply] - induction' n with n ihn generalizing x - · rfl - · simp [Nat.iterate, ihn] + induction n generalizing x with + | zero => rfl + | succ n ihn => simp [Nat.iterate, ihn] lemma mapsTo_of_subsingleton' [Subsingleton β] (f : α → β) (h : s.Nonempty → t.Nonempty) : MapsTo f s t := @@ -416,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⟩ @@ -436,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⟩ @@ -451,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 @@ -501,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 @@ -688,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 := @@ -708,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 ↦ ?_⟩ @@ -929,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 a 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 @@ -1132,15 +1094,17 @@ end Set /-! ### `invFunOn` is a left/right inverse -/ namespace Function -variable [Nonempty α] {s : Set α} {f : α → β} {a : α} {b : β} +variable {s : Set α} {f : α → β} {a : α} {b : β} attribute [local instance] Classical.propDecidable /-- Construct the inverse for a function `f` on domain `s`. This function is a right inverse of `f` on `f '' s`. For a computable version, see `Function.Embedding.invOfMemRange`. -/ -noncomputable def invFunOn (f : α → β) (s : Set α) (b : β) : α := +noncomputable def invFunOn [Nonempty α] (f : α → β) (s : Set α) (b : β) : α := if h : ∃ a, a ∈ s ∧ f a = b then Classical.choose h else Classical.choice ‹Nonempty α› +variable [Nonempty α] + theorem invFunOn_pos (h : ∃ a ∈ s, f a = b) : invFunOn f s b ∈ s ∧ f (invFunOn f s b) = b := by rw [invFunOn, dif_pos h] exact Classical.choose_spec h @@ -1309,23 +1273,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 @@ -1348,10 +1295,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] @@ -1392,11 +1335,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] @@ -1491,46 +1437,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 @@ -1618,21 +1524,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 @@ -1738,3 +1632,5 @@ lemma bijOn_swap (ha : a ∈ s) (hb : b ∈ s) : BijOn (swap a b) s s := simp [*, swap_apply_of_ne_of_ne] end Equiv + +set_option linter.style.longFile 1800 diff --git a/Mathlib/Data/Set/Functor.lean b/Mathlib/Data/Set/Functor.lean index c907a7750a067..86ef698729203 100644 --- a/Mathlib/Data/Set/Functor.lean +++ b/Mathlib/Data/Set/Functor.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura -/ import Mathlib.Data.Set.Lattice -import Mathlib.Init.Set +import Mathlib.Data.Set.Defs import Mathlib.Control.Basic import Mathlib.Data.Set.Notation diff --git a/Mathlib/Data/Set/Image.lean b/Mathlib/Data/Set/Image.lean index c0e717e96f023..83a5f73df751d 100644 --- a/Mathlib/Data/Set/Image.lean +++ b/Mathlib/Data/Set/Image.lean @@ -4,9 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Leonardo de Moura -/ import Mathlib.Data.Set.Subsingleton -import Mathlib.Order.WithBot import Mathlib.Tactic.Use import Batteries.Tactic.Congr +import Mathlib.Order.TypeTags +import Mathlib.Data.Option.Basic /-! # Images and preimages of sets @@ -135,8 +136,9 @@ theorem preimage_comp_eq : preimage (g ∘ f) = preimage f ∘ preimage g := rfl theorem preimage_iterate_eq {f : α → α} {n : ℕ} : Set.preimage f^[n] = (Set.preimage f)^[n] := by - induction' n with n ih; · simp - rw [iterate_succ, iterate_succ', preimage_comp_eq, ih] + induction n with + | zero => simp + | succ n ih => rw [iterate_succ, iterate_succ', preimage_comp_eq, ih] theorem preimage_preimage {g : β → γ} {f : α → β} {s : Set γ} : f ⁻¹' (g ⁻¹' s) = (fun x => g (f x)) ⁻¹' s := @@ -175,7 +177,7 @@ section Image variable {f : α → β} {s t : Set α} --- Porting note: `Set.image` is already defined in `Init.Set` +-- Porting note: `Set.image` is already defined in `Data.Set.Defs` @[deprecated mem_image (since := "2024-03-23")] theorem mem_image_iff_bex {f : α → β} {s : Set α} {y : β} : @@ -191,7 +193,7 @@ theorem _root_.Function.Injective.mem_set_image {f : α → β} (hf : Injective lemma preimage_subset_of_surjOn {t : Set β} (hf : Injective f) (h : SurjOn f s t) : f ⁻¹' t ⊆ s := fun _ hx ↦ - hf.mem_set_image.1 $ h hx + hf.mem_set_image.1 <| h hx theorem forall_mem_image {f : α → β} {s : Set α} {p : β → Prop} : (∀ y ∈ f '' s, p y) ↔ ∀ ⦃x⦄, x ∈ s → p (f x) := by simp @@ -299,7 +301,7 @@ theorem image_eq_empty {α β} {f : α → β} {s : Set α} : f '' s = ∅ ↔ s simp only [eq_empty_iff_forall_not_mem] exact ⟨fun H a ha => H _ ⟨_, ha, rfl⟩, fun H b ⟨_, ha, _⟩ => H _ ha⟩ --- Porting note: `compl` is already defined in `Init.Set` +-- Porting note: `compl` is already defined in `Data.Set.Defs` theorem preimage_compl_eq_image_compl [BooleanAlgebra α] (S : Set α) : HasCompl.compl ⁻¹' S = HasCompl.compl '' S := Set.ext fun x => @@ -815,9 +817,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] @@ -938,19 +939,7 @@ theorem range_diff_image {f : α → β} (H : Injective f) (s : Set α) : range @[simp] theorem range_inclusion (h : s ⊆ t) : range (inclusion h) = { x : t | (x : α) ∈ s } := by ext ⟨x, hx⟩ - -- Porting note: `simp [inclusion]` doesn't solve goal - apply Iff.intro - · rw [mem_range] - rintro ⟨a, ha⟩ - rw [inclusion, Subtype.mk.injEq] at ha - rw [mem_setOf, Subtype.coe_mk, ← ha] - exact Subtype.coe_prop _ - · rw [mem_setOf, Subtype.coe_mk, mem_range] - intro hx' - use ⟨x, hx'⟩ - trivial - -- simp_rw [inclusion, mem_range, Subtype.mk_eq_mk] - -- rw [SetCoe.exists, Subtype.coe_mk, exists_prop, exists_eq_right, mem_set_of, Subtype.coe_mk] + simp -- When `f` is injective, see also `Equiv.ofInjective`. theorem leftInverse_rangeSplitting (f : α → β) : @@ -997,24 +986,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) @@ -1023,29 +1012,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 _ _ @@ -1090,6 +1089,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 @@ -1100,13 +1102,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 @@ -1295,13 +1301,13 @@ theorem preimage_injective : Injective (preimage f) ↔ Surjective f := by @[simp] theorem preimage_surjective : Surjective (preimage f) ↔ Injective f := by refine ⟨fun h x x' hx => ?_, Injective.preimage_surjective⟩ - cases' h {x} with s hs; have := mem_singleton x + rcases h {x} with ⟨s, hs⟩; have := mem_singleton x rwa [← hs, mem_preimage, hx, ← mem_preimage, hs, mem_singleton_iff, eq_comm] at this @[simp] theorem image_surjective : Surjective (image f) ↔ Surjective f := by refine ⟨fun h y => ?_, Surjective.image_surjective⟩ - cases' h {y} with s hs + rcases h {y} with ⟨s, hs⟩ have := mem_singleton y; rw [← hs] at this; rcases this with ⟨x, _, hx⟩ exact ⟨x, hx⟩ diff --git a/Mathlib/Data/Set/Lattice.lean b/Mathlib/Data/Set/Lattice.lean index c994bb0f5366b..b6f29fa406fdf 100644 --- a/Mathlib/Data/Set/Lattice.lean +++ b/Mathlib/Data/Set/Lattice.lean @@ -686,6 +686,10 @@ theorem iInter_iInter_eq_or_left {b : β} {p : β → Prop} {s : ∀ x : β, x = ⋂ (x) (h), s x h = s b (Or.inl rfl) ∩ ⋂ (x) (h : p x), s x (Or.inr h) := by simp only [iInter_or, iInter_inter_distrib, iInter_iInter_eq_left] +lemma iUnion_sum {s : α ⊕ β → Set γ} : ⋃ x, s x = (⋃ x, s (.inl x)) ∪ ⋃ x, s (.inr x) := iSup_sum + +lemma iInter_sum {s : α ⊕ β → Set γ} : ⋂ x, s x = (⋂ x, s (.inl x)) ∩ ⋂ x, s (.inr x) := iInf_sum + /-! ### Bounded unions and intersections -/ @@ -1239,6 +1243,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` -/ @@ -1571,6 +1583,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 β) : @@ -1606,6 +1626,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] @@ -1931,3 +1961,5 @@ lemma forall_sUnion {S : Set (Set α)} {p : α → Prop} : lemma exists_sUnion {S : Set (Set α)} {p : α → Prop} : (∃ x ∈ ⋃₀ S, p x) ↔ ∃ s ∈ S, ∃ x ∈ s, p x := by simp_rw [← exists_prop, ← iSup_Prop_eq, iSup_sUnion] + +set_option linter.style.longFile 2100 diff --git a/Mathlib/Data/Set/List.lean b/Mathlib/Data/Set/List.lean index bbd932e0d0918..60839e4f416e6 100644 --- a/Mathlib/Data/Set/List.lean +++ b/Mathlib/Data/Set/List.lean @@ -22,10 +22,12 @@ namespace Set theorem range_list_map (f : α → β) : range (map f) = { l | ∀ x ∈ l, x ∈ range f } := by refine antisymm (range_subset_iff.2 fun l => forall_mem_map.2 fun y _ => mem_range_self _) fun l hl => ?_ - induction' l with a l ihl; · exact ⟨[], rfl⟩ - rcases ihl fun x hx => hl x <| subset_cons_self _ _ hx with ⟨l, rfl⟩ - rcases hl a (mem_cons_self _ _) with ⟨a, rfl⟩ - exact ⟨a :: l, map_cons _ _ _⟩ + induction l with + | nil => exact ⟨[], rfl⟩ + | cons a l ihl => + rcases ihl fun x hx => hl x <| subset_cons_self _ _ hx with ⟨l, rfl⟩ + rcases hl a (mem_cons_self _ _) with ⟨a, rfl⟩ + exact ⟨a :: l, map_cons _ _ _⟩ theorem range_list_map_coe (s : Set α) : range (map ((↑) : s → α)) = { l | ∀ x ∈ l, x ∈ s } := by rw [range_list_map, Subtype.range_coe] @@ -46,7 +48,7 @@ theorem range_list_get? : range l.get? = insert none (some '' { x | x ∈ l }) : theorem range_list_getD (d : α) : (range fun n : Nat => l[n]?.getD d) = insert d { x | x ∈ l } := calc (range fun n => l[n]?.getD d) = (fun o : Option α => o.getD d) '' range l.get? := by - simp [← range_comp, (· ∘ ·)] + simp [← range_comp, Function.comp_def] _ = insert d { x | x ∈ l } := by simp only [range_list_get?, image_insert_eq, Option.getD, image_image, image_id'] diff --git a/Mathlib/Data/Set/MemPartition.lean b/Mathlib/Data/Set/MemPartition.lean index eb38326f9234c..5a13d62ad7baf 100644 --- a/Mathlib/Data/Set/MemPartition.lean +++ b/Mathlib/Data/Set/MemPartition.lean @@ -54,7 +54,7 @@ lemma disjoint_memPartition (f : ℕ → Set α) (n : ℕ) {u v : Set α} induction n with | zero => intro u v hu hv huv - simp only [Nat.zero_eq, memPartition_zero, mem_insert_iff, mem_singleton_iff] at hu hv + simp only [memPartition_zero, mem_insert_iff, mem_singleton_iff] at hu hv rw [hu, hv] at huv exact absurd rfl huv | succ n ih => @@ -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 b6b66e2d2c290..487d0d5850eb3 100644 --- a/Mathlib/Data/Set/MulAntidiagonal.lean +++ b/Mathlib/Data/Set/MulAntidiagonal.lean @@ -83,7 +83,9 @@ end CancelCommMonoid section OrderedCancelCommMonoid -variable [OrderedCancelCommMonoid α] (s t : Set α) (a : α) {x y : mulAntidiagonal s t a} +variable [CancelCommMonoid α] [PartialOrder α] [CovariantClass α α (· * ·) (· ≤ ·)] + [CovariantClass α α (Function.swap (· * ·)) (· < ·)] + (s t : Set α) (a : α) {x y : mulAntidiagonal s t a} @[to_additive Set.AddAntidiagonal.eq_of_fst_le_fst_of_snd_le_snd] theorem eq_of_fst_le_fst_of_snd_le_snd (h₁ : (x : α × α).1 ≤ (y : α × α).1) @@ -110,8 +112,11 @@ theorem finite_of_isPWO (hs : s.IsPWO) (ht : t.IsPWO) (a) : (mulAntidiagonal s t end OrderedCancelCommMonoid +variable [CancelCommMonoid α] [LinearOrder α] [CovariantClass α α (· * ·) (· ≤ ·)] + [CovariantClass α α (Function.swap (· * ·)) (· < ·)] + @[to_additive Set.AddAntidiagonal.finite_of_isWF] -theorem finite_of_isWF [LinearOrderedCancelCommMonoid α] {s t : Set α} (hs : s.IsWF) (ht : t.IsWF) +theorem finite_of_isWF {s t : Set α} (hs : s.IsWF) (ht : t.IsWF) (a) : (mulAntidiagonal s t a).Finite := finite_of_isPWO hs.isPWO ht.isPWO a diff --git a/Mathlib/Data/Set/Operations.lean b/Mathlib/Data/Set/Operations.lean new file mode 100644 index 0000000000000..bed6dc9156d8b --- /dev/null +++ b/Mathlib/Data/Set/Operations.lean @@ -0,0 +1,297 @@ +/- +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, Kim Morrison, Patrick Massot, Kyle Miller, +Minchao Wu, Yury Kudryashov, Floris van Doorn +-/ +import Mathlib.Data.SProd +import Mathlib.Data.Subtype +import Mathlib.Order.Notation +import Mathlib.Util.CompileInductive + +/-! +# Basic definitions about sets + +In this file we define various operations on sets. +We also provide basic lemmas needed to unfold the definitions. +More advanced theorems about these definitions are located in other files in `Mathlib/Data/Set`. + +## Main definitions + +- complement of a set and set difference; +- `Set.Elem`: coercion of a set to a type; it is reducibly equal to `{x // x ∈ s}`; +- `Set.preimage f s`, a.k.a. `f ⁻¹' s`: preimage of a set; +- `Set.range f`: the range of a function; + it is more general than `f '' univ` because it allows functions from `Sort*`; +- `s ×ˢ t`: product of `s : Set α` and `t : Set β` as a set in `α × β`; +- `Set.diagonal`: the diagonal in `α × α`; +- `Set.offDiag s`: the part of `s ×ˢ s` that is off the diagonal; +- `Set.pi`: indexed product of a family of sets `∀ i, Set (α i)`, + as a set in `∀ i, α i`; +- `Set.EqOn f g s`: the predicate saying that two functions are equal on a set; +- `Set.MapsTo f s t`: the predicate syaing that `f` sends all points of `s` to `t; +- `Set.MapsTo.restrict`: restrict `f : α → β` to `f' : s → t` provided that `Set.MapsTo f s t`; +- `Set.restrictPreimage`: restrict `f : α → β` to `f' : (f ⁻¹' t) → t`; +- `Set.InjOn`: the predicate saying that `f` is injective on a set; +- `Set.SurjOn f s t`: the prediate saying that `t ⊆ f '' s`; +- `Set.BijOn f s t`: the predicate saying that `f` is injective on `s` and `f '' s = t`; +- `Set.graphOn`: the graph of a function on a set; +- `Set.LeftInvOn`, `Set.RightInvOn`, `Set.InvOn`: + the predicates saying that `f'` is a left, right or two-sided inverse of `f` on `s`, `t`, or both; +- `Set.image2`: the image of a pair of sets under a binary operation, + mostly useful to define pointwise algebraic operations on sets; +- `Set.seq`: monadic `seq` operation on sets; + we don't use monadic notation to ensure support for maps between different universes; + +## Notations + +- `f '' s`: image of a set; +- `f ⁻¹' s`: preimage of a set; +- `s ×ˢ t`: the product of sets; +- `s ∪ t`: the union of two sets; +- `s ∩ t`: the intersection of two sets; +- `sᶜ`: the complement of a set; +- `s \ t`: the difference of two sets. + +## Keywords + +set, image, preimage +-/ + +-- https://github.com/leanprover/lean4/issues/2096 +compile_def% Union.union +compile_def% Inter.inter +compile_def% SDiff.sdiff +compile_def% HasCompl.compl +compile_def% EmptyCollection.emptyCollection +compile_def% Insert.insert +compile_def% Singleton.singleton + +attribute [ext] Set.ext + +universe u v w + +namespace Set + +variable {α : Type u} {β : Type v} {γ : Type w} + +@[simp, mfld_simps] theorem mem_setOf_eq {x : α} {p : α → Prop} : (x ∈ {y | p y}) = p x := rfl + +@[simp, mfld_simps] theorem mem_univ (x : α) : x ∈ @univ α := trivial + +instance : HasCompl (Set α) := ⟨fun s ↦ {x | x ∉ s}⟩ + +@[simp] theorem mem_compl_iff (s : Set α) (x : α) : x ∈ sᶜ ↔ x ∉ s := Iff.rfl + +theorem diff_eq (s t : Set α) : s \ t = s ∩ tᶜ := rfl + +@[simp] theorem mem_diff {s t : Set α} (x : α) : x ∈ s \ t ↔ x ∈ s ∧ x ∉ t := Iff.rfl + +theorem mem_diff_of_mem {s t : Set α} {x : α} (h1 : x ∈ s) (h2 : x ∉ t) : x ∈ s \ t := ⟨h1, h2⟩ + +-- Porting note: I've introduced this abbreviation, with the `@[coe]` attribute, +-- so that `norm_cast` has something to index on. +-- It is currently an abbreviation so that instance coming from `Subtype` are available. +-- If you're interested in making it a `def`, as it probably should be, +-- you'll then need to create additional instances (and possibly prove lemmas about them). +-- The first error should appear below at `monotoneOn_iff_monotone`. +/-- Given the set `s`, `Elem s` is the `Type` of element of `s`. -/ +@[coe, reducible] def Elem (s : Set α) : Type u := {x // x ∈ s} + +/-- Coercion from a set to the corresponding subtype. -/ +instance : CoeSort (Set α) (Type u) := ⟨Elem⟩ + +/-- The preimage of `s : Set β` by `f : α → β`, written `f ⁻¹' s`, + is the set of `x : α` such that `f x ∈ s`. -/ +def preimage (f : α → β) (s : Set β) : Set α := {x | f x ∈ s} + +/-- `f ⁻¹' t` denotes the preimage of `t : Set β` under the function `f : α → β`. -/ +infixl:80 " ⁻¹' " => preimage + +@[simp, mfld_simps] +theorem mem_preimage {f : α → β} {s : Set β} {a : α} : a ∈ f ⁻¹' s ↔ f a ∈ s := Iff.rfl + +/-- `f '' s` denotes the image of `s : Set α` under the function `f : α → β`. -/ +infixl:80 " '' " => image + +@[simp] +theorem mem_image (f : α → β) (s : Set α) (y : β) : y ∈ f '' s ↔ ∃ x ∈ s, f x = y := + Iff.rfl + +@[mfld_simps] +theorem mem_image_of_mem (f : α → β) {x : α} {a : Set α} (h : x ∈ a) : f x ∈ f '' a := + ⟨_, h, rfl⟩ + +/-- Restriction of `f` to `s` factors through `s.imageFactorization f : s → f '' s`. -/ +def imageFactorization (f : α → β) (s : Set α) : s → f '' s := fun p => + ⟨f p.1, mem_image_of_mem f p.2⟩ + +/-- `kernImage f s` is the set of `y` such that `f ⁻¹ y ⊆ s`. -/ +def kernImage (f : α → β) (s : Set α) : Set β := {y | ∀ ⦃x⦄, f x = y → x ∈ s} + +lemma subset_kernImage_iff {s : Set β} {t : Set α} {f : α → β} : s ⊆ kernImage f t ↔ f ⁻¹' s ⊆ t := + ⟨fun h _ hx ↦ h hx rfl, + fun h _ hx y hy ↦ h (show f y ∈ s from hy.symm ▸ hx)⟩ + +section Range + +variable {ι : Sort*} {f : ι → α} + +/-- Range of a function. + +This function is more flexible than `f '' univ`, as the image requires that the domain is in Type +and not an arbitrary Sort. -/ +def range (f : ι → α) : Set α := {x | ∃ y, f y = x} + +@[simp] theorem mem_range {x : α} : x ∈ range f ↔ ∃ y, f y = x := Iff.rfl + +@[mfld_simps] theorem mem_range_self (i : ι) : f i ∈ range f := ⟨i, rfl⟩ + +/-- Any map `f : ι → α` factors through a map `rangeFactorization f : ι → range f`. -/ +def rangeFactorization (f : ι → α) : ι → range f := fun i => ⟨f i, mem_range_self i⟩ + +end Range + +/-- We can use the axiom of choice to pick a preimage for every element of `range f`. -/ +noncomputable def rangeSplitting (f : α → β) : range f → α := fun x => x.2.choose + +-- This can not be a `@[simp]` lemma because the head of the left hand side is a variable. +theorem apply_rangeSplitting (f : α → β) (x : range f) : f (rangeSplitting f x) = x := + x.2.choose_spec + +@[simp] +theorem comp_rangeSplitting (f : α → β) : f ∘ rangeSplitting f = Subtype.val := by + ext + simp only [Function.comp_apply] + apply apply_rangeSplitting + +section Prod + +/-- The cartesian product `Set.prod s t` is the set of `(a, b)` such that `a ∈ s` and `b ∈ t`. -/ +def prod (s : Set α) (t : Set β) : Set (α × β) := {p | p.1 ∈ s ∧ p.2 ∈ t} + +@[default_instance] +instance instSProd : SProd (Set α) (Set β) (Set (α × β)) where + sprod := Set.prod + +theorem prod_eq (s : Set α) (t : Set β) : s ×ˢ t = Prod.fst ⁻¹' s ∩ Prod.snd ⁻¹' t := rfl + +variable {a : α} {b : β} {s : Set α} {t : Set β} {p : α × β} + +theorem mem_prod_eq : (p ∈ s ×ˢ t) = (p.1 ∈ s ∧ p.2 ∈ t) := rfl + +@[simp, mfld_simps] +theorem mem_prod : p ∈ s ×ˢ t ↔ p.1 ∈ s ∧ p.2 ∈ t := .rfl + +@[mfld_simps] +theorem prod_mk_mem_set_prod_eq : ((a, b) ∈ s ×ˢ t) = (a ∈ s ∧ b ∈ t) := rfl + +theorem mk_mem_prod (ha : a ∈ s) (hb : b ∈ t) : (a, b) ∈ s ×ˢ t := ⟨ha, hb⟩ + +end Prod + +section Diagonal + +/-- `diagonal α` is the set of `α × α` consisting of all pairs of the form `(a, a)`. -/ +def diagonal (α : Type*) : Set (α × α) := {p | p.1 = p.2} + +theorem mem_diagonal (x : α) : (x, x) ∈ diagonal α := rfl + +@[simp] theorem mem_diagonal_iff {x : α × α} : x ∈ diagonal α ↔ x.1 = x.2 := .rfl + +/-- The off-diagonal of a set `s` is the set of pairs `(a, b)` with `a, b ∈ s` and `a ≠ b`. -/ +def offDiag (s : Set α) : Set (α × α) := {x | x.1 ∈ s ∧ x.2 ∈ s ∧ x.1 ≠ x.2} + +@[simp] +theorem mem_offDiag {x : α × α} {s : Set α} : x ∈ s.offDiag ↔ x.1 ∈ s ∧ x.2 ∈ s ∧ x.1 ≠ x.2 := + Iff.rfl + +end Diagonal + +section Pi + +variable {ι : Type*} {α : ι → Type*} + +/-- Given an index set `ι` and a family of sets `t : Π i, Set (α i)`, `pi s t` +is the set of dependent functions `f : Πa, π a` such that `f a` belongs to `t a` +whenever `a ∈ s`. -/ +def pi (s : Set ι) (t : ∀ i, Set (α i)) : Set (∀ i, α i) := {f | ∀ i ∈ s, f i ∈ t i} + +variable {s : Set ι} {t : ∀ i, Set (α i)} {f : ∀ i, α i} + +@[simp] theorem mem_pi : f ∈ s.pi t ↔ ∀ i ∈ s, f i ∈ t i := .rfl + +theorem mem_univ_pi : f ∈ pi univ t ↔ ∀ i, f i ∈ t i := by simp + +end Pi + +/-- Two functions `f₁ f₂ : α → β` are equal on `s` if `f₁ x = f₂ x` for all `x ∈ s`. -/ +def EqOn (f₁ f₂ : α → β) (s : Set α) : Prop := ∀ ⦃x⦄, x ∈ s → f₁ x = f₂ x + +/-- `MapsTo f a b` means that the image of `a` is contained in `b`. -/ +def MapsTo (f : α → β) (s : Set α) (t : Set β) : Prop := ∀ ⦃x⦄, x ∈ s → f x ∈ t + +theorem mapsTo_image (f : α → β) (s : Set α) : MapsTo f s (f '' s) := fun _ ↦ mem_image_of_mem f + +theorem mapsTo_preimage (f : α → β) (t : Set β) : MapsTo f (f ⁻¹' t) t := fun _ ↦ id + +/-- Given a map `f` sending `s : Set α` into `t : Set β`, restrict domain of `f` to `s` +and the codomain to `t`. Same as `Subtype.map`. -/ +def MapsTo.restrict (f : α → β) (s : Set α) (t : Set β) (h : MapsTo f s t) : s → t := + Subtype.map f h + +/-- The restriction of a function onto the preimage of a set. -/ +@[simps!] +def restrictPreimage (t : Set β) (f : α → β) : f ⁻¹' t → t := + (Set.mapsTo_preimage f t).restrict _ _ _ + +/-- `f` is injective on `a` if the restriction of `f` to `a` is injective. -/ +def InjOn (f : α → β) (s : Set α) : Prop := + ∀ ⦃x₁ : α⦄, x₁ ∈ s → ∀ ⦃x₂ : α⦄, x₂ ∈ s → f x₁ = f x₂ → x₁ = x₂ + +/-- The graph of a function `f : α → β` on a set `s`. -/ +def graphOn (f : α → β) (s : Set α) : Set (α × β) := (fun x ↦ (x, f x)) '' s + +/-- `f` is surjective from `a` to `b` if `b` is contained in the image of `a`. -/ +def SurjOn (f : α → β) (s : Set α) (t : Set β) : Prop := t ⊆ f '' s + +/-- `f` is bijective from `s` to `t` if `f` is injective on `s` and `f '' s = t`. -/ +def BijOn (f : α → β) (s : Set α) (t : Set β) : Prop := MapsTo f s t ∧ InjOn f s ∧ SurjOn f s t + +/-- `g` is a left inverse to `f` on `a` means that `g (f x) = x` for all `x ∈ a`. -/ +def LeftInvOn (f' : β → α) (f : α → β) (s : Set α) : Prop := ∀ ⦃x⦄, x ∈ s → f' (f x) = x + +/-- `g` is a right inverse to `f` on `b` if `f (g x) = x` for all `x ∈ b`. -/ +abbrev RightInvOn (f' : β → α) (f : α → β) (t : Set β) : Prop := LeftInvOn f f' t + +/-- `g` is an inverse to `f` viewed as a map from `a` to `b` -/ +def InvOn (g : β → α) (f : α → β) (s : Set α) (t : Set β) : Prop := + LeftInvOn g f s ∧ RightInvOn g f t + +section image2 + +/-- The image of a binary function `f : α → β → γ` as a function `Set α → Set β → Set γ`. +Mathematically this should be thought of as the image of the corresponding function `α × β → γ`. -/ +def image2 (f : α → β → γ) (s : Set α) (t : Set β) : Set γ := {c | ∃ a ∈ s, ∃ b ∈ t, f a b = c} + +variable {f : α → β → γ} {s : Set α} {t : Set β} {a : α} {b : β} {c : γ} + +@[simp] theorem mem_image2 : c ∈ image2 f s t ↔ ∃ a ∈ s, ∃ b ∈ t, f a b = c := .rfl + +theorem mem_image2_of_mem (ha : a ∈ s) (hb : b ∈ t) : f a b ∈ image2 f s t := + ⟨a, ha, b, hb, rfl⟩ + +end image2 + +/-- Given a set `s` of functions `α → β` and `t : Set α`, `seq s t` is the union of `f '' t` over +all `f ∈ s`. -/ +def seq (s : Set (α → β)) (t : Set α) : Set β := image2 (fun f ↦ f) s t + +@[simp] +theorem mem_seq_iff {s : Set (α → β)} {t : Set α} {b : β} : + b ∈ seq s t ↔ ∃ f ∈ s, ∃ a ∈ t, (f : α → β) a = b := + Iff.rfl + +lemma seq_eq_image2 (s : Set (α → β)) (t : Set α) : seq s t = image2 (fun f a ↦ f a) s t := rfl + +end Set diff --git a/Mathlib/Data/Set/Opposite.lean b/Mathlib/Data/Set/Opposite.lean index 77e16fe7c9064..b513d07864d91 100644 --- a/Mathlib/Data/Set/Opposite.lean +++ b/Mathlib/Data/Set/Opposite.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Markus Himmel -/ import Mathlib.Data.Opposite -import Mathlib.Data.Set.Defs +import Mathlib.Data.Set.Operations /-! # The opposite of a set diff --git a/Mathlib/Data/Set/Pairwise/Basic.lean b/Mathlib/Data/Set/Pairwise/Basic.lean index 64e482ceb8858..a40768a7e768d 100644 --- a/Mathlib/Data/Set/Pairwise/Basic.lean +++ b/Mathlib/Data/Set/Pairwise/Basic.lean @@ -39,7 +39,7 @@ variable {f g : ι → α} {s t u : 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 := diff --git a/Mathlib/Data/Set/Pairwise/Lattice.lean b/Mathlib/Data/Set/Pairwise/Lattice.lean index 9830f4e15681f..6e82a9acdc83d 100644 --- a/Mathlib/Data/Set/Pairwise/Lattice.lean +++ b/Mathlib/Data/Set/Pairwise/Lattice.lean @@ -71,7 +71,7 @@ theorem PairwiseDisjoint.biUnion {s : Set ι'} {g : ι' → Set ι} {f : ι → obtain ⟨c, hc, ha⟩ := ha obtain ⟨d, hd, hb⟩ := hb obtain hcd | hcd := eq_or_ne (g c) (g d) - · exact hg d hd (hcd.subst ha) hb hab + · exact hg d hd (hcd ▸ ha) hb hab -- Porting note: the elaborator couldn't figure out `f` here. · exact (hs hc hd <| ne_of_apply_ne _ hcd).mono (le_iSup₂ (f := fun i (_ : i ∈ g c) => f i) a ha) diff --git a/Mathlib/Data/Set/Pointwise/BigOperators.lean b/Mathlib/Data/Set/Pointwise/BigOperators.lean index 8ad41832d91c2..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.Data.Set.Pointwise.Basic +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 b98cbbde6ca66..2d630b685665e 100644 --- a/Mathlib/Data/Set/Pointwise/BoundedMul.lean +++ b/Mathlib/Data/Set/Pointwise/BoundedMul.lean @@ -3,8 +3,8 @@ 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.Basic import Mathlib.Algebra.Order.Monoid.Defs -import Mathlib.Data.Set.Pointwise.Basic /-! diff --git a/Mathlib/Data/Set/Pointwise/Finite.lean b/Mathlib/Data/Set/Pointwise/Finite.lean index 6e4932af9c42e..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 α} @@ -62,7 +53,7 @@ instance decidableMemMul [Fintype α] [DecidableEq α] [DecidablePred (· ∈ s) instance decidableMemPow [Fintype α] [DecidableEq α] [DecidablePred (· ∈ s)] (n : ℕ) : DecidablePred (· ∈ s ^ n) := by induction' n with n ih - · simp only [Nat.zero_eq, pow_zero, mem_one] + · simp only [pow_zero, mem_one] infer_instance · letI := ih rw [pow_succ] @@ -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 06375bbd88b1d..96c008f454acd 100644 --- a/Mathlib/Data/Set/Pointwise/Interval.lean +++ b/Mathlib/Data/Set/Pointwise/Interval.lean @@ -3,11 +3,11 @@ 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.Order.Interval.Set.UnorderedInterval -import Mathlib.Algebra.Order.Interval.Set.Monoid -import Mathlib.Data.Set.Pointwise.Basic +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 +import Mathlib.Order.Interval.Set.UnorderedInterval /-! # (Pre)images of intervals @@ -509,22 +509,22 @@ 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) : (fun x => x * c) ⁻¹' Iic a = Iic (a / c) := - ext fun _x => (le_div_iff h).symm + ext fun _x => (le_div_iff₀ h).symm @[simp] theorem preimage_mul_const_Ici (a : α) {c : α} (h : 0 < c) : (fun x => x * c) ⁻¹' Ici a = Ici (a / c) := - ext fun _x => (div_le_iff h).symm + ext fun _x => (div_le_iff₀ h).symm @[simp] theorem preimage_mul_const_Ioo (a b : α) {c : α} (h : 0 < c) : @@ -582,19 +582,19 @@ 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) := - ext fun _x => (le_div_iff' h).symm + ext fun _x => (le_div_iff₀' h).symm @[simp] theorem preimage_const_mul_Ici (a : α) {c : α} (h : 0 < c) : (c * ·) ⁻¹' Ici a = Ici (a / c) := - ext fun _x => (div_le_iff' h).symm + ext fun _x => (div_le_iff₀' h).symm @[simp] theorem preimage_const_mul_Ioo (a b : α) {c : α} (h : 0 < c) : @@ -718,18 +718,18 @@ 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 => - ⟨inv_pos (α := α) |>.2 <| (inv_pos (α := α) |>.2 ha).trans h, - inv_inv a ▸ (inv_lt_inv ((inv_pos (α := α) |>.2 ha).trans h) - (inv_pos (α := α) |>.2 ha)).2 h⟩⟩ + ⟨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_pos.2 ha)).2 h⟩⟩ theorem inv_Ioi {a : α} (ha : 0 < a) : (Ioi a)⁻¹ = Ioo 0 a⁻¹ := by - rw [inv_eq_iff_eq_inv, inv_Ioo_0_left (inv_pos (α := α) |>.2 ha), inv_inv] + rw [inv_eq_iff_eq_inv, inv_Ioo_0_left (inv_pos.2 ha), inv_inv] theorem image_const_mul_Ioi_zero {k : Type*} [LinearOrderedField k] {x : k} (hx : 0 < x) : (fun y => x * y) '' Ioi (0 : k) = Ioi 0 := by erw [(Units.mk0 x hx.ne').mulLeft.image_eq_preimage, - preimage_const_mul_Ioi 0 (inv_pos (α := k) |>.mpr hx), zero_div] + preimage_const_mul_Ioi 0 (inv_pos.mpr hx), zero_div] /-! ### Images under `x ↦ a * x + b` diff --git a/Mathlib/Data/Set/Pointwise/ListOfFn.lean b/Mathlib/Data/Set/Pointwise/ListOfFn.lean index c87a75ed34d9d..120059da9dfca 100644 --- a/Mathlib/Data/Set/Pointwise/ListOfFn.lean +++ b/Mathlib/Data/Set/Pointwise/ListOfFn.lean @@ -4,8 +4,8 @@ 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.Basic import Mathlib.Data.List.OfFn -import Mathlib.Data.Set.Pointwise.Basic /-! # Pointwise operations with lists of sets @@ -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 fd2bf0cf217e8..e3ed79c944b46 100644 --- a/Mathlib/Data/Set/Pointwise/SMul.lean +++ b/Mathlib/Data/Set/Pointwise/SMul.lean @@ -4,29 +4,16 @@ 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.Basic import Mathlib.Algebra.GroupWithZero.Action.Basic import Mathlib.Algebra.Module.Defs import Mathlib.Data.Set.Pairwise.Basic -import Mathlib.Data.Set.Pointwise.Basic -import Mathlib.GroupTheory.GroupAction.Group /-! -# 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 @@ -50,255 +37,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 : α} @@ -328,19 +66,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 @@ -459,141 +184,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 α) : diff --git a/Mathlib/Data/Set/Prod.lean b/Mathlib/Data/Set/Prod.lean index 6210548212b18..d147798baa0d9 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 @@ -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 @@ -730,7 +728,7 @@ theorem union_pi_inter simp only [mem_pi, mem_union, mem_inter_iff] refine ⟨fun h ↦ ⟨fun i his₁ ↦ (h i (Or.inl his₁)).1, fun i his₂ ↦ (h i (Or.inr his₂)).2⟩, fun h i hi ↦ ?_⟩ - cases' hi with hi hi + rcases hi with hi | hi · by_cases hi2 : i ∈ s₂ · exact ⟨h.1 i hi, h.2 i hi2⟩ · refine ⟨h.1 i hi, ?_⟩ @@ -802,6 +800,33 @@ 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 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 + intro i + if hi : i ∈ s then + exact (hb i hi).imp fun a ⟨hat, hab⟩ ↦ ⟨hab, fun _ ↦ hat⟩ + else + exact (hf i hi (b i)).imp fun a ha ↦ ⟨ha, (absurd · hi)⟩ + choose a hab hat using this + exact ⟨a, hat, funext hab⟩ + +@[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 ⟨fun h => or_iff_not_imp_right.2 ?_, fun h => h.elim pi_mono fun h' => h'.symm ▸ empty_subset _⟩ @@ -837,7 +862,10 @@ theorem update_preimage_pi [DecidableEq ι] {f : ∀ i, α i} (hi : i ∈ s) theorem update_image [DecidableEq ι] (x : (i : ι) → β i) (i : ι) (s : Set (β i)) : update x i '' s = Set.univ.pi (update (fun j ↦ {x j}) i s) := by ext y - simp [update_eq_iff, and_left_comm (a := _ ∈ s), forall_update_iff, eq_comm (a := y _)] + simp only [mem_image, update_eq_iff, ne_eq, and_left_comm (a := _ ∈ s), exists_eq_left, mem_pi, + mem_univ, true_implies] + rw [forall_update_iff (p := fun x s => y x ∈ s)] + simp [eq_comm] theorem update_preimage_univ_pi [DecidableEq ι] {f : ∀ i, α i} (hf : ∀ j ≠ i, f j ∈ t j) : update f i ⁻¹' pi univ t = t i := diff --git a/Mathlib/Data/Set/Semiring.lean b/Mathlib/Data/Set/Semiring.lean index 9acda7f2291a3..e6ff5cf305201 100644 --- a/Mathlib/Data/Set/Semiring.lean +++ b/Mathlib/Data/Set/Semiring.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.Algebra.Group.Pointwise.Set.Basic import Mathlib.Algebra.Order.Kleene import Mathlib.Algebra.Order.Ring.Canonical -import Mathlib.Data.Set.Pointwise.Basic /-! # Sets as a semiring under union diff --git a/Mathlib/Data/Set/Sigma.lean b/Mathlib/Data/Set/Sigma.lean index d8a73c0f8e40f..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 := @@ -191,7 +193,7 @@ theorem mk_preimage_sigma_fn_eq_if {β : Type*} [DecidablePred (· ∈ s)] (g : theorem sigma_univ_range_eq {f : ∀ i, α i → β i} : (univ : Set ι).sigma (fun i ↦ range (f i)) = range fun x : Σ i, α i ↦ ⟨x.1, f _ x.2⟩ := - ext <| by simp [range] + ext <| by simp [range, Sigma.forall] protected theorem Nonempty.sigma : s.Nonempty → (∀ i, (t i).Nonempty) → (s.sigma t).Nonempty := fun ⟨i, hi⟩ h ↦ 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/UnionLift.lean b/Mathlib/Data/Set/UnionLift.lean index 9b8184a95693c..cd2d6ffd31433 100644 --- a/Mathlib/Data/Set/UnionLift.lean +++ b/Mathlib/Data/Set/UnionLift.lean @@ -62,7 +62,6 @@ variable {S : ι → Set α} {f : ∀ i, S i → β} theorem iUnionLift_mk {i : ι} (x : S i) (hx : (x : α) ∈ T) : iUnionLift S f hf T hT ⟨x, hx⟩ = f i x := hf _ i x _ _ -@[simp] theorem iUnionLift_inclusion {i : ι} (x : S i) (h : S i ⊆ T) : iUnionLift S f hf T hT (Set.inclusion h x) = f i x := iUnionLift_mk x _ @@ -139,7 +138,6 @@ theorem iUnionLift_binary (dir : Directed (· ≤ ·) S) (op : T → T → T) (o have hxy : (Set.inclusion (Set.subset_iUnion S k) (opi k ⟨x, hik hi⟩ ⟨y, hjk hj⟩) : α) ∈ S k := (opi k ⟨x, hik hi⟩ ⟨y, hjk hj⟩).prop conv_lhs => rw [hx, hy, ← hopi, iUnionLift_of_mem _ hxy] - rfl end UnionLift diff --git a/Mathlib/Data/SetLike/Basic.lean b/Mathlib/Data/SetLike/Basic.lean index bd1f5ca66f08e..2a07db5d06280 100644 --- a/Mathlib/Data/SetLike/Basic.lean +++ b/Mathlib/Data/SetLike/Basic.lean @@ -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. @@ -106,7 +106,7 @@ variable {A : Type*} {B : Type*} [i : SetLike A B] instance : CoeTC A (Set B) where coe := SetLike.coe instance (priority := 100) instMembership : Membership B A := - ⟨fun x p => x ∈ (p : Set B)⟩ + ⟨fun p x => x ∈ (p : Set B)⟩ instance (priority := 100) : CoeSort A (Type _) := ⟨fun p => { x : B // x ∈ p }⟩ @@ -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 294f426f6d013..8734d5bf5b8d2 100644 --- a/Mathlib/Data/Setoid/Basic.lean +++ b/Mathlib/Data/Setoid/Basic.lean @@ -91,7 +91,7 @@ def ker (f : α → β) : Setoid α := theorem ker_mk_eq (r : Setoid α) : ker (@Quotient.mk'' _ r) = r := 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 : α) : @@ -111,6 +111,49 @@ protected def prod (r : Setoid α) (s : Setoid β) : ⟨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 => @@ -192,10 +235,14 @@ def map_sInf {S : Set (Setoid α)} {s : Setoid α} (h : s ∈ S) : Quotient (sInf S) → Quotient s := Setoid.map_of_le fun _ _ a ↦ a s h +section EqvGen + +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.Rel x y } := le_antisymm (fun _ _ H => EqvGen.rec (fun _ _ h _ hs => hs h) (refl' _) (fun _ _ _ => symm' _) @@ -205,20 +252,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.Rel x y ∨ s.Rel 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.Rel ⊔ s.Rel) := 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.Rel x y := by rw [eqvGen_eq] apply congr_arg sInf simp only [upperBounds, le_def, and_imp, exists_imp] @@ -227,39 +274,41 @@ 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 (Rel '' s)) := by rw [sSup_eq_eqvGen, sSup_image] congr with (x y) simp only [iSup_apply, iSup_Prop_eq, exists_prop] /-- The equivalence closure of an equivalence relation r is r. -/ @[simp] -theorem eqvGen_of_setoid (r : Setoid α) : EqvGen.Setoid r.r = r := +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).Rel = 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) : - EqvGen.Setoid r ≤ s := by rw [eqvGen_eq]; exact sInf_le h + EqvGen.setoid r ≤ s := by rw [eqvGen_eq]; exact sInf_le h /-- Equivalence closure of binary relations is monotone. -/ theorem eqvGen_mono {r s : α → α → Prop} (h : ∀ x y, r x y → s x y) : - EqvGen.Setoid r ≤ EqvGen.Setoid s := + EqvGen.setoid r ≤ EqvGen.setoid s := eqvGen_le fun _ _ hr => EqvGen.rel _ _ <| h _ _ hr /-- 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 - choice r _ := EqvGen.Setoid r +def gi : @GaloisInsertion (α → α → Prop) (Setoid α) _ _ EqvGen.setoid Rel 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 choice_eq _ _ := rfl +end EqvGen + open Function /-- A function from α to β is injective iff its kernel is the bottom element of the complete lattice @@ -335,7 +384,7 @@ 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 β := - 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.Rel 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 @@ -414,7 +463,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 @@ -428,7 +477,8 @@ theorem Quotient.subsingleton_iff {s : Setoid α} : Subsingleton (Quotient s) simp_rw [Prop.top_eq_true, true_implies, Quotient.eq'] rfl -theorem Quot.subsingleton_iff (r : α → α → Prop) : Subsingleton (Quot r) ↔ EqvGen r = ⊤ := by +theorem Quot.subsingleton_iff (r : α → α → Prop) : + Subsingleton (Quot r) ↔ Relation.EqvGen r = ⊤ := by simp only [_root_.subsingleton_iff, _root_.eq_top_iff, Pi.le_def, Pi.top_apply, forall_const] refine (surjective_quot_mk _).forall.trans (forall_congr' fun a => ?_) refine (surjective_quot_mk _).forall.trans (forall_congr' fun b => ?_) diff --git a/Mathlib/Data/Setoid/Partition.lean b/Mathlib/Data/Setoid/Partition.lean index ecf06ea7c220d..7813b2de0bebe 100644 --- a/Mathlib/Data/Setoid/Partition.lean +++ b/Mathlib/Data/Setoid/Partition.lean @@ -156,8 +156,8 @@ theorem sUnion_classes (r : Setoid α) : ⋃₀ r.classes = Set.univ := /-- 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] @@ -301,7 +301,7 @@ This type is primarily useful for definitional control of `s` - if this is not n structure IndexedPartition {ι α : Type*} (s : ι → Set α) where /-- two indexes are equal if they are equal in membership -/ eq_of_mem : ∀ {x i j}, x ∈ s i → x ∈ s j → i = j - /-- sends an index to an element of the corresponding set-/ + /-- sends an index to an element of the corresponding set -/ some : ι → α /-- membership invariance for `some`-/ some_mem : ∀ i, some i ∈ s i diff --git a/Mathlib/Data/Sigma/Basic.lean b/Mathlib/Data/Sigma/Basic.lean index 238a6f84ac8a5..552e884b81259 100644 --- a/Mathlib/Data/Sigma/Basic.lean +++ b/Mathlib/Data/Sigma/Basic.lean @@ -61,6 +61,10 @@ theorem mk.inj_iff {a₁ a₂ : α} {b₁ : β a₁} {b₂ : β a₂} : theorem eta : ∀ x : Σa, β a, Sigma.mk x.1 x.2 = x | ⟨_, _⟩ => rfl +protected theorem eq {α : Type*} {β : α → Type*} : ∀ {p₁ p₂ : Σ a, β a} (h₁ : p₁.1 = p₂.1), + (Eq.recOn h₁ p₁.2 : β p₂.1) = p₂.2 → p₁ = p₂ + | ⟨_, _⟩, _, rfl, rfl => rfl + /-- A version of `Iff.mp Sigma.ext_iff` for functions from a nonempty type to a sigma type. -/ theorem _root_.Function.eq_of_sigmaMk_comp {γ : Type*} [Nonempty γ] {a b : α} {f : γ → β a} {g : γ → β b} (h : Sigma.mk a ∘ f = Sigma.mk b ∘ g) : @@ -75,7 +79,7 @@ theorem subtype_ext {β : Type*} {p : α → β → Prop} : ∀ {x₀ x₁ : Σa, Subtype (p a)}, x₀.fst = x₁.fst → (x₀.snd : β) = x₁.snd → x₀ = x₁ | ⟨_, _, _⟩, ⟨_, _, _⟩, rfl, rfl => rfl -@[simp] +-- This is not a good simp lemma, as its discrimination tree key is just an arrow. theorem «forall» {p : (Σa, β a) → Prop} : (∀ x, p x) ↔ ∀ a b, p ⟨a, b⟩ := ⟨fun h a b ↦ h ⟨a, b⟩, fun h ⟨a, b⟩ ↦ h a b⟩ @@ -209,6 +213,8 @@ def elim {γ} (f : ∀ a, β a → γ) (a : PSigma β) : γ := theorem elim_val {γ} (f : ∀ a, β a → γ) (a b) : PSigma.elim f ⟨a, b⟩ = f a b := rfl +@[deprecated (since := "2024-07-27")] alias ex_of_psig := ex_of_PSigma + instance [Inhabited α] [Inhabited (β default)] : Inhabited (PSigma β) := ⟨⟨default, default⟩⟩ @@ -232,16 +238,16 @@ theorem mk.inj_iff {a₁ a₂ : α} {b₁ : β a₁} {b₂ : β a₂} : match a₁, a₂, b₁, b₂, h₁, h₂ with | _, _, _, _, Eq.refl _, HEq.refl _ => rfl -@[simp] +@[deprecated PSigma.ext_iff (since := "2024-07-27")] +protected theorem eq {α : Sort*} {β : α → Sort*} : ∀ {p₁ p₂ : Σ' a, β a} (h₁ : p₁.1 = p₂.1), + (Eq.recOn h₁ p₁.2 : β p₂.1) = p₂.2 → p₁ = p₂ + | ⟨_, _⟩, _, rfl, rfl => rfl + +-- This should not be a simp lemma, since its discrimination tree key would just be `→`. theorem «forall» {p : (Σ'a, β a) → Prop} : (∀ x, p x) ↔ ∀ a b, p ⟨a, b⟩ := ⟨fun h a b ↦ h ⟨a, b⟩, fun h ⟨a, b⟩ ↦ h a b⟩ -#adaptation_note -/-- -This should be renamed back to `exists` after `nightly-2024-07-31`. --/ -@[simp] -theorem exists' {p : (Σ'a, β a) → Prop} : (∃ x, p x) ↔ ∃ a b, p ⟨a, b⟩ := +@[simp] lemma «exists» {p : (Σ' a, β a) → Prop} : (∃ x, p x) ↔ ∃ a b, p ⟨a, b⟩ := ⟨fun ⟨⟨a, b⟩, h⟩ ↦ ⟨a, b, h⟩, fun ⟨a, b, h⟩ ↦ ⟨⟨a, b⟩, h⟩⟩ /-- A specialized ext lemma for equality of `PSigma` types over an indexed subtype. -/ 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/Stream/Defs.lean b/Mathlib/Data/Stream/Defs.lean index 2a596ea48dac9..787e4441675ac 100644 --- a/Mathlib/Data/Stream/Defs.lean +++ b/Mathlib/Data/Stream/Defs.lean @@ -48,7 +48,7 @@ def Any (p : α → Prop) (s : Stream' α) := ∃ n, p (get s n) /-- `a ∈ s` means that `a = Stream'.get n s` for some `n`. -/ instance : Membership α (Stream' α) := - ⟨fun a s => Any (fun b => a = b) s⟩ + ⟨fun s a => Any (fun b => a = b) s⟩ /-- Apply a function `f` to all elements of a stream `s`. -/ def map (f : α → β) (s : Stream' α) : Stream' β := fun n => f (get s n) @@ -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 c8fb6c851095e..c90ad62ac925d 100644 --- a/Mathlib/Data/Stream/Init.lean +++ b/Mathlib/Data/Stream/Init.lean @@ -5,7 +5,6 @@ Authors: Leonardo de Moura -/ import Mathlib.Data.Stream.Defs import Mathlib.Logic.Function.Basic -import Mathlib.Init.Data.List.Basic import Mathlib.Data.List.Basic /-! @@ -13,7 +12,7 @@ import Mathlib.Data.List.Basic Porting note: This file used to be in the core library. It was moved to `mathlib` and renamed to `init` to avoid -name clashes. -/ +name clashes. -/ open Nat Function Option @@ -494,7 +493,7 @@ theorem length_take (n : ℕ) (s : Stream' α) : (take n s).length = n := by theorem take_take {s : Stream' α} : ∀ {m n}, (s.take n).take m = s.take (min n m) | 0, n => by rw [Nat.min_zero, List.take_zero, take_zero] | m, 0 => by rw [Nat.zero_min, take_zero, List.take_nil] - | m+1, n+1 => by rw [take_succ, List.take_cons, Nat.succ_min_succ, take_succ, take_take] + | m+1, n+1 => by rw [take_succ, List.take_succ_cons, Nat.succ_min_succ, take_succ, take_take] @[simp] theorem concat_take_get {n : ℕ} {s : Stream' α} : s.take n ++ [s.get n] = s.take (n+1) := (take_succ' n).symm diff --git a/Mathlib/Data/String/Basic.lean b/Mathlib/Data/String/Basic.lean index 1208ee3912785..d30479b15e611 100644 --- a/Mathlib/Data/String/Basic.lean +++ b/Mathlib/Data/String/Basic.lean @@ -3,6 +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.String.Lemmas import Mathlib.Data.List.Lex import Mathlib.Data.Char import Mathlib.Tactic.AdaptationNote @@ -60,7 +61,7 @@ theorem ltb_cons_addChar (c : Char) (cs₁ cs₂ : List Char) (i₁ i₂ : Pos) intro ⟨cs₁⟩ ⟨cs₂⟩ i₁ i₂ <;> intros <;> (conv => lhs; unfold ltb) <;> (conv => rhs; unfold ltb) <;> - simp only [Iterator.hasNext_cons_addChar, ite_false, ite_true, *] + simp only [Iterator.hasNext_cons_addChar, ite_false, ite_true, *, reduceCtorEq] · rename_i h₂ h₁ heq ih simp only [Iterator.next, next, heq, Iterator.curr, get_cons_addChar, ite_true] at ih ⊢ repeat rw [Pos.addChar_right_comm _ c] diff --git a/Mathlib/Data/String/Defs.lean b/Mathlib/Data/String/Defs.lean index 0df9b21527948..a6c9b5e9fd401 100644 --- a/Mathlib/Data/String/Defs.lean +++ b/Mathlib/Data/String/Defs.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Simon Hudon, Keeley Hoek, Floris van Doorn, Chris Bailey -/ +import Mathlib.Init /-! # Definitions for `String` 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 9265b7b297c2d..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 @@ -133,7 +133,7 @@ theorem isRight_right (h : LiftRel r s (inr b) y) : y.isRight := by cases h; rfl theorem exists_of_isLeft_left (h₁ : LiftRel r s x y) (h₂ : x.isLeft) : ∃ a c, r a c ∧ x = inl a ∧ y = inl c := by rcases isLeft_iff.mp h₂ with ⟨_, rfl⟩ - simp only [liftRel_iff, false_and, and_false, exists_false, or_false] at h₁ + simp only [liftRel_iff, false_and, and_false, exists_false, or_false, reduceCtorEq] at h₁ exact h₁ theorem exists_of_isLeft_right (h₁ : LiftRel r s x y) (h₂ : y.isLeft) : @@ -142,7 +142,7 @@ theorem exists_of_isLeft_right (h₁ : LiftRel r s x y) (h₂ : y.isLeft) : theorem exists_of_isRight_left (h₁ : LiftRel r s x y) (h₂ : x.isRight) : ∃ b d, s b d ∧ x = inr b ∧ y = inr d := by rcases isRight_iff.mp h₂ with ⟨_, rfl⟩ - simp only [liftRel_iff, false_and, and_false, exists_false, false_or] at h₁ + simp only [liftRel_iff, false_and, and_false, exists_false, false_or, reduceCtorEq] at h₁ exact h₁ theorem exists_of_isRight_right (h₁ : LiftRel r s x y) (h₂ : y.isRight) : diff --git a/Mathlib/Data/Sum/Interval.lean b/Mathlib/Data/Sum/Interval.lean index fa3850967d3d3..75478d551bcc8 100644 --- a/Mathlib/Data/Sum/Interval.lean +++ b/Mathlib/Data/Sum/Interval.lean @@ -300,7 +300,7 @@ local elab "simp_lex" : tactic => do map_empty, not_mem_empty, true_and, inl_mem_disjSum, inr_mem_disjSum, and_true, ofLex_toLex, mem_map, Embedding.coeFn_mk, exists_prop, exists_eq_right, Embedding.inl_apply, -- Porting note: added - inl.injEq, inr.injEq] + inl.injEq, inr.injEq, reduceCtorEq] ) instance locallyFiniteOrder : LocallyFiniteOrder (α ⊕ₗ β) where diff --git a/Mathlib/Data/Sum/Order.lean b/Mathlib/Data/Sum/Order.lean index ae5edfa7ffcf1..7eef753b32d1a 100644 --- a/Mathlib/Data/Sum/Order.lean +++ b/Mathlib/Data/Sum/Order.lean @@ -651,7 +651,7 @@ def orderIsoPUnitSumLex : WithBot α ≃o PUnit ⊕ₗ α := ⟨(Equiv.optionEquivSumPUnit α).trans <| (Equiv.sumComm _ _).trans toLex, fun {a b} => by simp only [Equiv.optionEquivSumPUnit, Option.elim, Equiv.trans_apply, Equiv.coe_fn_mk, Equiv.sumComm_apply, swap, Lex.toLex_le_toLex, le_refl] - cases' a <;> cases' b + cases a <;> cases b · simp only [elim_inr, lex_inl_inl, bot_le, le_rfl] · simp only [elim_inr, elim_inl, Lex.sep, bot_le] · simp only [elim_inl, elim_inr, lex_inr_inl, false_iff] @@ -688,7 +688,7 @@ def orderIsoSumLexPUnit : WithTop α ≃o α ⊕ₗ PUnit := ⟨(Equiv.optionEquivSumPUnit α).trans toLex, fun {a b} => by simp only [Equiv.optionEquivSumPUnit, Option.elim, Equiv.trans_apply, Equiv.coe_fn_mk, Lex.toLex_le_toLex, le_refl, lex_inr_inr, le_top] - cases' a <;> cases' b + cases a <;> cases b · simp only [lex_inr_inr, le_top] · simp only [lex_inr_inl, false_iff] exact not_top_le_coe _ diff --git a/Mathlib/Data/Sym/Basic.lean b/Mathlib/Data/Sym/Basic.lean index aa85d9183ee69..4378b439653ed 100644 --- a/Mathlib/Data/Sym/Basic.lean +++ b/Mathlib/Data/Sym/Basic.lean @@ -142,7 +142,7 @@ theorem card_coe : Multiset.card (s : Multiset α) = n := s.prop /-- `α ∈ s` means that `a` appears as one of the factors in `s`. -/ instance : Membership α (Sym α n) := - ⟨fun a s => a ∈ s.1⟩ + ⟨fun s a => a ∈ s.1⟩ instance decidableMem [DecidableEq α] (a : α) (s : Sym α n) : Decidable (a ∈ s) := s.1.decidableMem _ diff --git a/Mathlib/Data/Sym/Sym2.lean b/Mathlib/Data/Sym/Sym2.lean index 4e94151a85335..945179cd192f3 100644 --- a/Mathlib/Data/Sym/Sym2.lean +++ b/Mathlib/Data/Sym/Sym2.lean @@ -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] @@ -318,7 +317,7 @@ theorem mem_mk_left (x y : α) : x ∈ s(x, y) := ⟨y, rfl⟩ theorem mem_mk_right (x y : α) : y ∈ s(x, y) := - eq_swap.subst <| mem_mk_left y x + eq_swap ▸ mem_mk_left y x @[simp, aesop norm (rule_sets := [Sym2])] theorem mem_iff {a b c : α} : a ∈ s(b, c) ↔ a = b ∨ a = c := diff --git a/Mathlib/Data/Sym/Sym2/Init.lean b/Mathlib/Data/Sym/Sym2/Init.lean index 8735d0d7603cd..9c7fdd617d017 100644 --- a/Mathlib/Data/Sym/Sym2/Init.lean +++ b/Mathlib/Data/Sym/Sym2/Init.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jannis Limperg -/ +import Mathlib.Init import Aesop /-! diff --git a/Mathlib/Data/TypeVec.lean b/Mathlib/Data/TypeVec.lean index 104d68020ce33..ed974cab4a625 100644 --- a/Mathlib/Data/TypeVec.lean +++ b/Mathlib/Data/TypeVec.lean @@ -448,16 +448,16 @@ end @[simp] theorem prod_fst_mk {α β : TypeVec n} (i : Fin2 n) (a : α i) (b : β i) : TypeVec.prod.fst i (prod.mk i a b) = a := by - induction' i with _ _ _ i_ih - · simp_all only [prod.fst, prod.mk] - apply i_ih + induction i with + | fz => simp_all only [prod.fst, prod.mk] + | fs _ i_ih => apply i_ih @[simp] theorem prod_snd_mk {α β : TypeVec n} (i : Fin2 n) (a : α i) (b : β i) : TypeVec.prod.snd i (prod.mk i a b) = b := by - induction' i with _ _ _ i_ih - · simp_all [prod.snd, prod.mk] - apply i_ih + induction i with + | fz => simp_all [prod.snd, prod.mk] + | fs _ i_ih => apply i_ih /-- `prod` is functorial -/ protected def prod.map : ∀ {n} {α α' β β' : TypeVec.{u} n}, α ⟹ β → α' ⟹ β' → α ⊗ α' ⟹ β ⊗ β' @@ -493,9 +493,9 @@ theorem snd_diag {α : TypeVec n} : TypeVec.prod.snd ⊚ (prod.diag : α ⟹ _) theorem repeatEq_iff_eq {α : TypeVec n} {i x y} : ofRepeat (repeatEq α i (prod.mk _ x y)) ↔ x = y := by - induction' i with _ _ _ i_ih - · rfl - erw [repeatEq, i_ih] + induction i with + | fz => rfl + | fs _ i_ih => erw [repeatEq, i_ih] /-- given a predicate vector `p` over vector `α`, `Subtype_ p` is the type of vectors that contain an `α` that satisfies `p` -/ @@ -547,17 +547,16 @@ theorem subtypeVal_nil {α : TypeVec.{u} 0} (ps : α ⟹ «repeat» 0 Prop) : theorem diag_sub_val {n} {α : TypeVec.{u} n} : subtypeVal (repeatEq α) ⊚ diagSub = prod.diag := by ext i x - induction' i with _ _ _ i_ih - · simp only [comp, subtypeVal, repeatEq.eq_2, diagSub, prod.diag] - apply @i_ih (drop α) + induction i with + | fz => simp only [comp, subtypeVal, repeatEq.eq_2, diagSub, prod.diag] + | fs _ i_ih => apply @i_ih (drop α) theorem prod_id : ∀ {n} {α β : TypeVec.{u} n}, (id ⊗' id) = (id : α ⊗ β ⟹ _) := by intros ext i a - induction' i with _ _ _ i_ih - · cases a - rfl - · apply i_ih + induction i with + | fz => cases a; rfl + | fs _ i_ih => apply i_ih theorem append_prod_appendFun {n} {α α' β β' : TypeVec.{u} n} {φ φ' ψ ψ' : Type u} {f₀ : α ⟹ α'} {g₀ : β ⟹ β'} {f₁ : φ → φ'} {g₁ : ψ → ψ'} : @@ -655,9 +654,10 @@ theorem prod_map_id {α β : TypeVec n} : (@TypeVec.id _ α ⊗' @TypeVec.id _ @[simp] theorem subtypeVal_diagSub {α : TypeVec n} : subtypeVal (repeatEq α) ⊚ diagSub = prod.diag := by ext i x - induction' i with _ _ _ i_ih - · simp [comp, diagSub, subtypeVal, prod.diag] - · simp only [comp, subtypeVal, diagSub, prod.diag] at * + induction i with + | fz => simp [comp, diagSub, subtypeVal, prod.diag] + | fs _ i_ih => + simp only [comp, subtypeVal, diagSub, prod.diag] at * apply i_ih @[simp] diff --git a/Mathlib/Data/ULift.lean b/Mathlib/Data/ULift.lean index 45fa5cad19423..29aed3723b5e7 100644 --- a/Mathlib/Data/ULift.lean +++ b/Mathlib/Data/ULift.lean @@ -56,7 +56,7 @@ theorem down_surjective : Surjective (@down α) := theorem down_bijective : Bijective (@down α) := Equiv.plift.bijective -@[simp] +-- This is not a good simp lemma, as its discrimination tree key is just an arrow. theorem «forall» {p : PLift α → Prop} : (∀ x, p x) ↔ ∀ x : α, p (PLift.up x) := up_surjective.forall diff --git a/Mathlib/Data/Vector/Basic.lean b/Mathlib/Data/Vector/Basic.lean index f28e84a817f60..5db96436f76b0 100644 --- a/Mathlib/Data/Vector/Basic.lean +++ b/Mathlib/Data/Vector/Basic.lean @@ -17,18 +17,14 @@ import Mathlib.Control.Traversable.Basic This file introduces the infix notation `::ᵥ` for `Vector.cons`. -/ -set_option autoImplicit true - universe u -variable {n : ℕ} +variable {α β γ σ φ : Type*} {m n : ℕ} namespace Mathlib namespace Vector -variable {α : Type*} - @[inherit_doc] infixr:67 " ::ᵥ " => Vector.cons @@ -312,7 +308,7 @@ retrieved via `head`, is the starting value `b : β`. @[simp] theorem scanl_head : (scanl f b v).head = b := by cases n - · have : v = nil := by simp only [Nat.zero_eq, eq_iff_true_of_subsingleton] + · have : v = nil := by simp only [eq_iff_true_of_subsingleton] simp only [this, scanl_nil, head_cons] · rw [← cons_head_tail v] simp only [← get_zero, get_eq_get, toList_scanl, toList_cons, List.scanl, Fin.val_zero, @@ -640,7 +636,7 @@ protected theorem comp_traverse (f : β → F γ) (g : α → G β) (x : Vector · simp! [cast, *, functor_norm] rfl · rw [Vector.traverse_def, ih] - simp [functor_norm, (· ∘ ·)] + simp [functor_norm, Function.comp_def] protected theorem traverse_eq_map_id {α β} (f : α → β) : ∀ x : Vector α n, x.traverse ((pure : _ → Id _) ∘ f) = (pure : _ → Id _) (map f x) := by @@ -690,7 +686,7 @@ instance : LawfulTraversable.{u} (flip Vector n) where section Simp -variable (xs : Vector α n) +variable {x : α} {y : β} {s : σ} (xs : Vector α n) @[simp] theorem replicate_succ (val : α) : @@ -729,7 +725,7 @@ theorem get_map₂ (v₁ : Vector α n) (v₂ : Vector β n) (f : α → β → · simp only [get_cons_succ, ih] @[simp] -theorem mapAccumr_cons : +theorem mapAccumr_cons {f : α → σ → σ × β} : mapAccumr f (x ::ᵥ xs) s = let r := mapAccumr f xs s let q := f x r.1 @@ -737,7 +733,7 @@ theorem mapAccumr_cons : rfl @[simp] -theorem mapAccumr₂_cons : +theorem mapAccumr₂_cons {f : α → β → σ → σ × φ} : mapAccumr₂ f (x ::ᵥ xs) (y ::ᵥ ys) s = let r := mapAccumr₂ f xs ys s let q := f x y r.1 diff --git a/Mathlib/Data/Vector/Defs.lean b/Mathlib/Data/Vector/Defs.lean index c25f510f74bd1..8c08c0254b502 100644 --- a/Mathlib/Data/Vector/Defs.lean +++ b/Mathlib/Data/Vector/Defs.lean @@ -3,7 +3,7 @@ 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 Mathlib.Init.Data.List.Lemmas +import Mathlib.Data.List.Defs import Mathlib.Tactic.Common /-! @@ -20,8 +20,7 @@ def Vector (α : Type u) (n : ℕ) := namespace Vector -variable {α : Type u} {β : Type v} {φ : Type w} -variable {n : ℕ} +variable {α β σ φ : Type*} {n : ℕ} instance [DecidableEq α] : DecidableEq (Vector α n) := inferInstanceAs (DecidableEq {l : List α // l.length = n}) @@ -53,7 +52,7 @@ def head : Vector α (Nat.succ n) → α theorem head_cons (a : α) : ∀ v : Vector α n, head (cons a v) = a | ⟨_, _⟩ => rfl -/-- The tail of a vector, with an empty vector having empty tail. -/ +/-- The tail of a vector, with an empty vector having empty tail. -/ def tail : Vector α n → Vector α (n - 1) | ⟨[], h⟩ => ⟨[], congrArg pred h⟩ | ⟨_ :: v, h⟩ => ⟨v, congrArg pred h⟩ @@ -120,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 @@ -137,8 +136,6 @@ section Accum open Prod -variable {σ : Type} - /-- Runs a function over a vector returning the intermediate results and a final result. -/ @@ -150,15 +147,14 @@ def mapAccumr (f : α → σ → σ × β) : Vector α n → σ → σ × Vector /-- Runs a function over a pair of vectors returning the intermediate results and a final result. -/ -def mapAccumr₂ {α β σ φ : Type} (f : α → β → σ → σ × φ) : - Vector α n → Vector β n → σ → σ × Vector φ n +def mapAccumr₂ (f : α → β → σ → σ × φ) : Vector α n → Vector β n → σ → σ × Vector φ n | ⟨x, px⟩, ⟨y, py⟩, c => let res := List.mapAccumr₂ f x y c ⟨res.1, res.2, by simp [*, res]⟩ end Accum -/-! ### Shift Primitives-/ +/-! ### Shift Primitives -/ section Shift /-- `shiftLeftFill v i` is the vector obtained by left-shifting `v` `i` times and padding with the @@ -185,7 +181,7 @@ protected theorem eq_nil (v : Vector α 0) : v = nil := v.eq nil (List.eq_nil_of_length_eq_zero v.2) /-- Vector of length from a list `v` -with witness that `v` has length `n` maps to `v` under `toList`. -/ +with witness that `v` has length `n` maps to `v` under `toList`. -/ @[simp] theorem toList_mk (v : List α) (P : List.length v = n) : toList (Subtype.mk v P) = v := rfl diff --git a/Mathlib/Data/Vector/MapLemmas.lean b/Mathlib/Data/Vector/MapLemmas.lean index 3c67c95406853..54dc2f7a0d4ae 100644 --- a/Mathlib/Data/Vector/MapLemmas.lean +++ b/Mathlib/Data/Vector/MapLemmas.lean @@ -10,7 +10,7 @@ import Mathlib.Data.Vector.Snoc This file establishes a set of normalization lemmas for `map`/`mapAccumr` operations on vectors -/ -set_option autoImplicit true +variable {α β γ ζ σ σ₁ σ₂ φ : Type*} {n : ℕ} {s : σ} {s₁ : σ₁} {s₂ : σ₂} namespace Mathlib @@ -36,12 +36,12 @@ theorem mapAccumr_mapAccumr : induction xs using Vector.revInductionOn generalizing s₁ s₂ <;> simp_all @[simp] -theorem mapAccumr_map (f₂ : α → β) : +theorem mapAccumr_map {s : σ₁} (f₂ : α → β) : (mapAccumr f₁ (map f₂ xs) s) = (mapAccumr (fun x s => f₁ (f₂ x) s) xs s) := by induction xs using Vector.revInductionOn generalizing s <;> simp_all @[simp] -theorem map_mapAccumr (f₁ : β → γ) : +theorem map_mapAccumr {s : σ₂} (f₁ : β → γ) : (map f₁ (mapAccumr f₂ xs s).snd) = (mapAccumr (fun x s => let r := (f₂ x s); (r.fst, f₁ r.snd) ) xs s).snd := by @@ -222,7 +222,7 @@ accumulation state section RedundantState variable {xs : Vector α n} {ys : Vector β n} -protected theorem map_eq_mapAccumr : +protected theorem map_eq_mapAccumr {f : α → β} : map f xs = (mapAccumr (fun x (_ : Unit) ↦ ((), f x)) xs ()).snd := by induction xs using Vector.revInductionOn <;> simp_all @@ -240,7 +240,7 @@ theorem mapAccumr_eq_map {f : α → σ → σ × β} {s₀ : σ} (S : Set σ) ( use fun s _ => s ∈ S, h₀ exact @fun s _q a h => ⟨closure a s h, out a s s₀ h h₀⟩ -protected theorem map₂_eq_mapAccumr₂ : +protected theorem map₂_eq_mapAccumr₂ {f : α → β → γ} : map₂ f xs ys = (mapAccumr₂ (fun x y (_ : Unit) ↦ ((), f x y)) xs ys ()).snd := by induction xs, ys using Vector.revInductionOn₂ <;> simp_all diff --git a/Mathlib/Data/Vector/Mem.lean b/Mathlib/Data/Vector/Mem.lean index 220b1cac938b6..3eb0fe6678d82 100644 --- a/Mathlib/Data/Vector/Mem.lean +++ b/Mathlib/Data/Vector/Mem.lean @@ -58,9 +58,9 @@ theorem mem_cons_of_mem (v : Vector α n) (ha' : a' ∈ v.toList) : a' ∈ (a :: (Vector.mem_cons_iff a a' v).2 (Or.inr ha') theorem mem_of_mem_tail (v : Vector α n) (ha : a ∈ v.tail.toList) : a ∈ v.toList := by - induction' n with n _ - · exact False.elim (Vector.not_mem_zero a v.tail ha) - · exact (mem_succ_iff a v).2 (Or.inr ha) + induction n with + | zero => exact False.elim (Vector.not_mem_zero a v.tail ha) + | succ n _ => exact (mem_succ_iff a v).2 (Or.inr ha) theorem mem_map_iff (b : β) (v : Vector α n) (f : α → β) : b ∈ (v.map f).toList ↔ ∃ a : α, a ∈ v.toList ∧ f a = b := by diff --git a/Mathlib/Data/Vector/Snoc.lean b/Mathlib/Data/Vector/Snoc.lean index 41b4c9e7e94c8..ec5dccd5f02c9 100644 --- a/Mathlib/Data/Vector/Snoc.lean +++ b/Mathlib/Data/Vector/Snoc.lean @@ -16,21 +16,21 @@ import Mathlib.Data.Vector.Basic `snoc xs x` for its inductive case. Effectively doing induction from right-to-left -/ -set_option autoImplicit true - namespace Mathlib namespace Vector +variable {α β σ φ : Type*} {n : ℕ} {x : α} {s : σ} (xs : Vector α n) + /-- Append a single element to the end of a vector -/ def snoc : Vector α n → α → Vector α (n+1) := fun xs x => append xs (x ::ᵥ Vector.nil) -/-! -## Simplification lemmas --/ +/-! ## Simplification lemmas -/ + section Simp -variable (xs : Vector α n) + +variable {y : α} @[simp] theorem snoc_cons : (x ::ᵥ xs).snoc y = x ::ᵥ (xs.snoc y) := @@ -64,9 +64,8 @@ theorem replicate_succ_to_snoc (val : α) : end Simp -/-! -## Reverse induction principle --/ +/-! ## Reverse induction principle -/ + section Induction /-- Define `C v` by *reverse* induction on `v : Vector α n`. @@ -115,24 +114,20 @@ def revCasesOn {C : ∀ {n : ℕ}, Vector α n → Sort*} {n : ℕ} (v : Vector end Induction -/-! -## More simplification lemmas --/ +/-! ## More simplification lemmas -/ section Simp -variable (xs : Vector α n) - @[simp] -theorem map_snoc : map f (xs.snoc x) = (map f xs).snoc (f x) := by +theorem map_snoc {f : α → β} : map f (xs.snoc x) = (map f xs).snoc (f x) := by induction xs <;> simp_all @[simp] -theorem mapAccumr_nil : mapAccumr f Vector.nil s = (s, Vector.nil) := +theorem mapAccumr_nil {f : α → σ → σ × β} {s : σ} : mapAccumr f Vector.nil s = (s, Vector.nil) := rfl @[simp] -theorem mapAccumr_snoc : +theorem mapAccumr_snoc {f : α → σ → σ × β} {s : σ} : mapAccumr f (xs.snoc x) s = let q := f x s let r := mapAccumr f xs q.1 @@ -144,17 +139,19 @@ theorem mapAccumr_snoc : variable (ys : Vector β n) @[simp] -theorem map₂_snoc : map₂ f (xs.snoc x) (ys.snoc y) = (map₂ f xs ys).snoc (f x y) := by +theorem map₂_snoc {f : α → β → σ} {y : β} : + map₂ f (xs.snoc x) (ys.snoc y) = (map₂ f xs ys).snoc (f x y) := by induction xs, ys using Vector.inductionOn₂ <;> simp_all @[simp] -theorem mapAccumr₂_nil : mapAccumr₂ f Vector.nil Vector.nil s = (s, Vector.nil) := +theorem mapAccumr₂_nil {f : α → β → σ → σ × φ} : + mapAccumr₂ f Vector.nil Vector.nil s = (s, Vector.nil) := rfl @[simp] theorem mapAccumr₂_snoc (f : α → β → σ → σ × φ) (x : α) (y : β) : - mapAccumr₂ f (xs.snoc x) (ys.snoc y) c - = let q := f x y c + mapAccumr₂ f (xs.snoc x) (ys.snoc y) s + = let q := f x y s let r := mapAccumr₂ f xs ys q.1 (r.1, r.2.snoc q.2) := by induction xs, ys using Vector.inductionOn₂ <;> simp_all 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..9ec3dea934529 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 @@ -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/Cardinal.lean b/Mathlib/Data/W/Cardinal.lean index 911d370ca2ef1..5841bc9d66bd1 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 diff --git a/Mathlib/Data/ZMod/Basic.lean b/Mathlib/Data/ZMod/Basic.lean index 0a65bb9d6fac8..ba4a441a9fdfe 100644 --- a/Mathlib/Data/ZMod/Basic.lean +++ b/Mathlib/Data/ZMod/Basic.lean @@ -4,9 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ import Mathlib.Algebra.Ring.Prod +import Mathlib.GroupTheory.GroupAction.SubMulAction import Mathlib.GroupTheory.OrderOfElement import Mathlib.Tactic.FinCases import Mathlib.Tactic.Linarith +import Mathlib.Data.Fintype.Units /-! @@ -100,7 +102,7 @@ instance charP (n : ℕ) : CharP (ZMod n) n where cast_eq_zero_iff' := by intro k cases' n with n - · simp [zero_dvd_iff, Int.natCast_eq_zero, Nat.zero_eq] + · simp [zero_dvd_iff, Int.natCast_eq_zero] · exact Fin.natCast_eq_zero @[simp] @@ -112,7 +114,7 @@ where `a ≠ 0` is `addOrderOf_coe'`. -/ @[simp] theorem addOrderOf_coe (a : ℕ) {n : ℕ} (n0 : n ≠ 0) : addOrderOf (a : ZMod n) = n / n.gcd a := by cases' a with a - · simp only [Nat.zero_eq, Nat.cast_zero, addOrderOf_zero, Nat.gcd_zero_right, + · simp only [Nat.cast_zero, addOrderOf_zero, Nat.gcd_zero_right, Nat.pos_of_ne_zero n0, Nat.div_self] rw [← Nat.smul_one_eq_cast, addOrderOf_nsmul' _ a.succ_ne_zero, ZMod.addOrderOf_one] @@ -231,6 +233,9 @@ theorem intCast_surjective : Function.Surjective ((↑) : ℤ → ZMod n) := @[deprecated (since := "2024-04-17")] alias int_cast_surjective := intCast_surjective +lemma «forall» {P : ZMod n → Prop} : (∀ x, P x) ↔ ∀ x : ℤ, P x := intCast_surjective.forall +lemma «exists» {P : ZMod n → Prop} : (∃ x, P x) ↔ ∃ x : ℤ, P x := intCast_surjective.exists + theorem cast_id : ∀ (n) (i : ZMod n), (ZMod.cast i : ZMod n) = i | 0, _ => Int.cast_id | _ + 1, i => natCast_zmod_val i @@ -430,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` @@ -441,7 +446,7 @@ noncomputable def ringEquiv [Fintype R] (h : Fintype.card R = n) : ZMod n ≃+* /-- The unique ring isomorphism between `ZMod p` and a ring `R` of cardinality a prime `p`. If you need any property of this isomorphism, first of all use `ringEquivOfPrime_eq_ringEquiv` -below (after `have : CharP R p := ...`) and deduce it by the results about `ZMod.ringEquiv`. -/ +below (after `have : CharP R p := ...`) and deduce it by the results about `ZMod.ringEquiv`. -/ noncomputable def ringEquivOfPrime [Fintype R] {p : ℕ} (hp : p.Prime) (hR : Fintype.card R = p) : ZMod p ≃+* R := have : Nontrivial R := Fintype.one_lt_card_iff_nontrivial.1 (hR ▸ hp.one_lt) @@ -747,6 +752,12 @@ theorem val_mul_of_lt {n : ℕ} {a b : ZMod n} (h : a.val * b.val < n) : rw [val_mul] apply Nat.mod_eq_of_lt h +theorem val_mul_iff_lt {n : ℕ} [NeZero n] (a b : ZMod n) : + (a * b).val = a.val * b.val ↔ a.val * b.val < n := by + constructor <;> intro h + · rw [← h]; apply ZMod.val_lt + · apply ZMod.val_mul_of_lt h + instance nontrivial (n : ℕ) [Fact (1 < n)] : Nontrivial (ZMod n) := ⟨⟨0, 1, fun h => zero_ne_one <| @@ -815,6 +826,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 @@ -983,10 +1005,18 @@ theorem natAbs_mod_two (a : ℤ) : (a.natAbs : ZMod 2) = a := by theorem val_ne_zero {n : ℕ} (a : ZMod n) : a.val ≠ 0 ↔ a ≠ 0 := (val_eq_zero a).not +theorem val_pos {n : ℕ} {a : ZMod n} : 0 < a.val ↔ a ≠ 0 := by + simp [pos_iff_ne_zero] + +theorem val_eq_one : ∀ {n : ℕ} (_ : 1 < n) (a : ZMod n), a.val = 1 ↔ a = 1 + | 0, hn, _ + | 1, hn, _ => by simp at hn + | n + 2, _, _ => by simp only [val, ZMod, Fin.ext_iff, Fin.val_one] + 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)⟩ @@ -995,7 +1025,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 @@ -1013,6 +1043,17 @@ theorem neg_eq_self_iff {n : ℕ} (a : ZMod n) : -a = a ↔ a = 0 ∨ 2 * a.val theorem val_cast_of_lt {n : ℕ} {a : ℕ} (h : a < n) : (a : ZMod n).val = a := by rw [val_natCast, Nat.mod_eq_of_lt h] +theorem val_cast_zmod_lt {m : ℕ} [NeZero m] (n : ℕ) [NeZero n] (a : ZMod m) : + (a.cast : ZMod n).val < m := by + rcases m with (⟨⟩|⟨m⟩); · cases NeZero.ne 0 rfl + by_cases h : m < n + · rcases n with (⟨⟩|⟨n⟩); · simp at h + rw [← natCast_val, val_cast_of_lt] + · apply a.val_lt + apply lt_of_le_of_lt (Nat.le_of_lt_succ (ZMod.val_lt a)) h + · rw [not_lt] at h + apply lt_of_lt_of_le (ZMod.val_lt _) (le_trans h (Nat.le_succ m)) + theorem neg_val' {n : ℕ} [NeZero n] (a : ZMod n) : (-a).val = (n - a.val) % n := calc (-a).val = val (-a) % n := by rw [Nat.mod_eq_of_lt (-a).val_lt] @@ -1058,6 +1099,28 @@ theorem cast_cast_zmod_of_le {m n : ℕ} [hm : NeZero m] (h : m ≤ n) (a : ZMod have : NeZero n := ⟨((Nat.zero_lt_of_ne_zero hm.out).trans_le h).ne'⟩ rw [cast_eq_val, val_cast_eq_val_of_lt (a.val_lt.trans_le h), natCast_zmod_val] +theorem val_pow {m n : ℕ} {a : ZMod n} [ilt : Fact (1 < n)] (h : a.val ^ m < n) : + (a ^ m).val = a.val ^ m := by + induction m with + | zero => simp [ZMod.val_one] + | succ m ih => + have : a.val ^ m < n := by + obtain rfl | ha := eq_or_ne a 0 + · by_cases hm : m = 0 + · cases hm; simp [ilt.out] + · simp only [val_zero, ne_eq, hm, not_false_eq_true, zero_pow, Nat.zero_lt_of_lt h] + · exact lt_of_le_of_lt + (Nat.pow_le_pow_of_le_right (by rwa [gt_iff_lt, ZMod.val_pos]) (Nat.le_succ m)) h + rw [pow_succ, ZMod.val_mul, ih this, ← pow_succ, Nat.mod_eq_of_lt h] + +theorem val_pow_le {m n : ℕ} [Fact (1 < n)] {a : ZMod n} : (a ^ m).val ≤ a.val ^ m := by + induction m with + | zero => simp [ZMod.val_one] + | succ m ih => + rw [pow_succ, pow_succ] + apply le_trans (ZMod.val_mul_le _ _) + apply Nat.mul_le_mul_right _ ih + /-- `valMinAbs x` returns the integer in the same equivalence class as `x` that is closest to `0`, The result will be in the interval `(-n/2, n/2]`. -/ def valMinAbs : ∀ {n : ℕ}, ZMod n → ℤ @@ -1155,7 +1218,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 @@ -1369,6 +1432,29 @@ end lift end ZMod +section Module +variable {S G : Type*} [AddCommGroup G] {n : ℕ} [Module (ZMod n) G] [SetLike S G] + [AddSubgroupClass S G] {K : S} {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 + +/-- This cannot be made an instance because of the `[Module (ZMod n) G]` argument and the fact that +`n` only appears in the second argument of `SMulMemClass`, which is an `OutParam`. -/ +lemma smulMemClass : SMulMemClass S (ZMod n) G where smul_mem _ _ {_x} hx := zmod_smul_mem hx _ + +namespace AddSubgroupClass + +instance instZModSMul : SMul (ZMod n) K where smul a x := ⟨a • x, zmod_smul_mem x.2 _⟩ + +@[simp, norm_cast] lemma coe_zmod_smul (a : ZMod n) (x : K) : ↑(a • x) = (a • x : G) := rfl + +instance instZModModule : Module (ZMod n) K := + Subtype.coe_injective.module _ (AddSubmonoidClass.subtype K) coe_zmod_smul + +end AddSubgroupClass +end Module + section AddGroup variable {α : Type*} [AddGroup α] {n : ℕ} @@ -1401,6 +1487,8 @@ lemma pow_pow_zmod_val_inv (hn : (Nat.card α).Coprime n) (a : α) : end Group +open ZMod + /-- The range of `(m * · + k)` on natural numbers is the set of elements `≥ k` in the residue class of `k` mod `m`. -/ lemma Nat.range_mul_add (m k : ℕ) : @@ -1414,3 +1502,17 @@ lemma Nat.range_mul_add (m k : ℕ) : simp only [ha, Nat.cast_add, add_right_eq_self, ZMod.natCast_zmod_eq_zero_iff_dvd] at H₁ obtain ⟨b, rfl⟩ := H₁ exact ⟨b, ha⟩ + +/-- Equivalence between `ℕ` and `ZMod N × ℕ`, sending `n` to `(n mod N, n / N)`. -/ +def Nat.residueClassesEquiv (N : ℕ) [NeZero N] : ℕ ≃ ZMod N × ℕ where + toFun n := (↑n, n / N) + invFun p := p.1.val + N * p.2 + left_inv n := by simpa only [val_natCast] using mod_add_div n N + right_inv p := by + ext1 + · simp only [add_comm p.1.val, cast_add, cast_mul, natCast_self, zero_mul, natCast_val, + cast_id', id_eq, zero_add] + · simp only [add_comm p.1.val, mul_add_div (NeZero.pos _), + (Nat.div_eq_zero_iff <| (NeZero.pos _)).2 p.1.val_lt, add_zero] + +set_option linter.style.longFile 1700 diff --git a/Mathlib/Data/ZMod/Defs.lean b/Mathlib/Data/ZMod/Defs.lean index 324dec3252219..76e27012548a5 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 @@ -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/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 39ff9a8cdf6d4..3ea9499281fd8 100644 --- a/Mathlib/Data/ZMod/Quotient.lean +++ b/Mathlib/Data/ZMod/Quotient.lean @@ -57,6 +57,10 @@ def quotientSpanNatEquivZMod : ℤ ⧸ Ideal.span {(n : ℤ)} ≃+* ZMod n := def quotientSpanEquivZMod (a : ℤ) : ℤ ⧸ Ideal.span ({a} : Set ℤ) ≃+* ZMod a.natAbs := (Ideal.quotEquivOfEq (span_natAbs a)).symm.trans (quotientSpanNatEquivZMod a.natAbs) +@[simp] +lemma index_zmultiples (a : ℤ) : (AddSubgroup.zmultiples a).index = a.natAbs := by + rw [AddSubgroup.index, Nat.card_congr (quotientZMultiplesEquivZMod a).toEquiv, Nat.card_zmod] + end Int noncomputable section ChineseRemainder 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/Deprecated/Aliases.lean b/Mathlib/Deprecated/Aliases.lean index 3ccfb1ced2c07..5e63adabb8005 100644 --- a/Mathlib/Deprecated/Aliases.lean +++ b/Mathlib/Deprecated/Aliases.lean @@ -3,6 +3,7 @@ Copyright (c) 2024 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison -/ +import Mathlib.Init import Batteries.Tactic.Alias import Batteries.Data.String.Basic diff --git a/Mathlib/Deprecated/Combinator.lean b/Mathlib/Deprecated/Combinator.lean new file mode 100644 index 0000000000000..a19596bdeb6eb --- /dev/null +++ b/Mathlib/Deprecated/Combinator.lean @@ -0,0 +1,20 @@ +/- +Copyright (c) 2014 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Leonardo de Moura, Mario Carneiro +-/ + +/-! +# Deprecated combinators, ported from Lean 3 core. +-/ + +namespace Combinator + +universe u v w +variable {α : Sort u} {β : Sort v} {γ : Sort w} + +@[deprecated (since := "2024-07-27")] def I (a : α) := a +@[deprecated (since := "2024-07-27")] def K (a : α) (_b : β) := a +@[deprecated (since := "2024-07-27")] def S (x : α → β → γ) (y : α → β) (z : α) := x z (y z) + +end Combinator 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 8fa961c5642c6..b5c815bd6e5a0 100644 --- a/Mathlib/Deprecated/HashMap.lean +++ b/Mathlib/Deprecated/HashMap.lean @@ -1,22 +1,23 @@ /- -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 - -As `HashMap` has been completely reimplemented in `Batteries`, -nothing from the mathlib3 file `data.hash_map` is reflected here. -The porting header is just here to mark that no further work on `data.hash_map` is desired. +Authors: Kim Morrison -/ + +import Mathlib.Init +import Mathlib.Tactic.TypeStar import Batteries.Data.HashMap.Basic import Batteries.Data.RBMap.Basic /-! # Additional API for `HashMap` and `RBSet`. -These should be replaced by proper implementations in Batteries. +As `HashMap` has been completely reimplemented in `Batteries`, +nothing from the mathlib3 file `data.hash_map` is reflected here. +The porting header is just here to mark that no further work on `data.hash_map` is desired. -/ -set_option autoImplicit true +variable {α β : Type*} namespace Batteries.HashMap 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 17691db27d6d4..f30ed0f0e3ca3 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 @@ -453,7 +453,8 @@ 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 => @@ -589,11 +590,11 @@ theorem normalClosure.is_normal : IsNormalSubgroup (normalClosure s) := /-- The normal closure of s is the smallest normal subgroup containing s. -/ theorem normalClosure_subset {s t : Set G} (ht : IsNormalSubgroup t) (h : s ⊆ t) : normalClosure s ⊆ t := fun a w => by - induction' w with x hx x _ ihx x y _ _ ihx ihy - · exact conjugatesOfSet_subset' ht h <| hx - · exact ht.toIsSubgroup.toIsSubmonoid.one_mem - · exact ht.toIsSubgroup.inv_mem ihx - · exact ht.toIsSubgroup.toIsSubmonoid.mul_mem ihx ihy + induction w with + | basic hx => exact conjugatesOfSet_subset' ht h <| hx + | one => exact ht.toIsSubgroup.toIsSubmonoid.one_mem + | inv _ ihx => exact ht.toIsSubgroup.inv_mem ihx + | mul _ _ ihx ihy => exact ht.toIsSubgroup.toIsSubmonoid.mul_mem ihx ihy theorem normalClosure_subset_iff {s t : Set G} (ht : IsNormalSubgroup t) : s ⊆ t ↔ normalClosure s ⊆ t := diff --git a/Mathlib/Deprecated/Subring.lean b/Mathlib/Deprecated/Subring.lean index 6a652a4c798a3..20fc691ea4b93 100644 --- a/Mathlib/Deprecated/Subring.lean +++ b/Mathlib/Deprecated/Subring.lean @@ -97,14 +97,15 @@ 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⟩ => ⟨L1.map (List.cons (-1)), fun L2 h2 ↦ match L2, List.mem_map.1 h2 with | _, ⟨L3, h3, rfl⟩ => List.forall_mem_cons.2 ⟨Or.inr rfl, h1 L3 h3⟩, by - simp only [List.map_map, (· ∘ ·), List.prod_cons, neg_one_mul] + simp only [List.map_map, Function.comp_def, List.prod_cons, neg_one_mul] refine List.recOn L1 neg_zero.symm fun hd tl ih ↦ ?_ rw [List.map_cons, List.sum_cons, ih, List.map_cons, List.sum_cons, neg_add]⟩ fun {r1 r2} _ _ ih1 ih2 ↦ match r1, r2, ih1, ih2 with diff --git a/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean b/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean index 7a0cf2877f279..bf93db2355a6d 100644 --- a/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean +++ b/Mathlib/Dynamics/Circle/RotationNumber/TranslationNumber.lean @@ -115,7 +115,6 @@ Here are some short-term goals. circle homeomorphism, rotation number -/ - open Filter Set Int Topology open Function hiding Commute @@ -566,7 +565,7 @@ theorem translationNumber_eq_of_tendsto_aux {τ' : ℝ} (h : Tendsto f.transnumA theorem translationNumber_eq_of_tendsto₀ {τ' : ℝ} (h : Tendsto (fun n : ℕ => f^[n] 0 / n) atTop (𝓝 τ')) : τ f = τ' := f.translationNumber_eq_of_tendsto_aux <| by - simpa [(· ∘ ·), transnumAuxSeq_def, coe_pow] using + simpa [Function.comp_def, transnumAuxSeq_def, coe_pow] using h.comp (Nat.tendsto_pow_atTop_atTop_of_one_lt one_lt_two) theorem translationNumber_eq_of_tendsto₀' {τ' : ℝ} @@ -708,7 +707,7 @@ theorem le_translationNumber_of_add_le {z : ℝ} (hz : ∀ x, x + z ≤ f x) : z theorem translationNumber_le_of_le_add_int {x : ℝ} {m : ℤ} (h : f x ≤ x + m) : τ f ≤ m := le_of_tendsto' (f.tendsto_translation_number' x) fun n => - (div_le_iff' (n.cast_add_one_pos : (0 : ℝ) < _)).mpr <| sub_le_iff_le_add'.2 <| + (div_le_iff₀' (n.cast_add_one_pos : (0 : ℝ) < _)).mpr <| sub_le_iff_le_add'.2 <| (coe_pow f (n + 1)).symm ▸ @Nat.cast_add_one ℝ _ n ▸ f.iterate_le_of_map_le_add_int h (n + 1) theorem translationNumber_le_of_le_add_nat {x : ℝ} {m : ℕ} (h : f x ≤ x + m) : τ f ≤ m := @@ -716,7 +715,7 @@ theorem translationNumber_le_of_le_add_nat {x : ℝ} {m : ℕ} (h : f x ≤ x + theorem le_translationNumber_of_add_int_le {x : ℝ} {m : ℤ} (h : x + m ≤ f x) : ↑m ≤ τ f := ge_of_tendsto' (f.tendsto_translation_number' x) fun n => - (le_div_iff (n.cast_add_one_pos : (0 : ℝ) < _)).mpr <| le_sub_iff_add_le'.2 <| by + (le_div_iff₀ (n.cast_add_one_pos : (0 : ℝ) < _)).mpr <| le_sub_iff_add_le'.2 <| by simp only [coe_pow, mul_comm (m : ℝ), ← Nat.cast_add_one, f.le_iterate_of_add_int_le_map h] theorem le_translationNumber_of_add_nat_le {x : ℝ} {m : ℕ} (h : x + m ≤ f x) : ↑m ≤ τ f := @@ -853,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/Basic.lean b/Mathlib/Dynamics/Ergodic/Action/Basic.lean index 06740aa5a6bad..8dfe2a8de714c 100644 --- a/Mathlib/Dynamics/Ergodic/Action/Basic.lean +++ b/Mathlib/Dynamics/Ergodic/Action/Basic.lean @@ -85,12 +85,10 @@ theorem ergodicSMul_iterateMulAct {f : α → α} (hf : Measurable f) : simp only [ergodicSMul_iff, smulInvariantMeasure_iterateMulAct, hf] refine ⟨fun ⟨h₁, h₂⟩ ↦ ⟨h₁, ⟨?_⟩⟩, fun h ↦ ⟨h.1, ?_⟩⟩ · intro s hm hs - rw [← eventuallyConst_set'] refine h₂ hm fun n ↦ ?_ nth_rewrite 2 [← Function.IsFixedPt.preimage_iterate hs n.val] rfl · intro s hm hs - rw [eventuallyConst_set'] - exact h.quasiErgodic.ae_empty_or_univ' hm <| hs (.mk 1) + exact h.quasiErgodic.aeconst_set₀ hm.nullMeasurableSet <| hs (.mk 1) end MeasureTheory 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/AddCircle.lean b/Mathlib/Dynamics/Ergodic/AddCircle.lean index 5bd20dcdead3d..d19dedb1a3963 100644 --- a/Mathlib/Dynamics/Ergodic/AddCircle.lean +++ b/Mathlib/Dynamics/Ergodic/AddCircle.lean @@ -100,7 +100,7 @@ theorem ae_empty_or_univ_of_forall_vadd_ae_eq_self {s : Set <| AddCircle T} theorem ergodic_zsmul {n : ℤ} (hn : 1 < |n|) : Ergodic fun y : AddCircle T => n • y := { measurePreserving_zsmul volume (abs_pos.mp <| lt_trans zero_lt_one hn) with - ae_empty_or_univ := fun s hs hs' => by + aeconst_set := fun s hs hs' => by let u : ℕ → AddCircle T := fun j => ↑((↑1 : ℝ) / ↑(n.natAbs ^ j) * T) replace hn : 1 < n.natAbs := by rwa [Int.abs_eq_natAbs, Nat.one_lt_cast] at hn have hu₀ : ∀ j, addOrderOf (u j) = n.natAbs ^ j := fun j => by @@ -114,6 +114,7 @@ theorem ergodic_zsmul {n : ℤ} (hn : 1 < |n|) : Ergodic fun y : AddCircle T => rw [vadd_eq_self_of_preimage_zsmul_eq_self hs' (hnu j)] have hu₂ : Tendsto (fun j => addOrderOf <| u j) atTop atTop := by simp_rw [hu₀]; exact Nat.tendsto_pow_atTop_atTop_of_one_lt hn + rw [eventuallyConst_set'] exact ae_empty_or_univ_of_forall_vadd_ae_eq_self hs.nullMeasurableSet hu₁ hu₂ } theorem ergodic_nsmul {n : ℕ} (hn : 1 < n) : Ergodic fun y : AddCircle T => n • y := diff --git a/Mathlib/Dynamics/Ergodic/Conservative.lean b/Mathlib/Dynamics/Ergodic/Conservative.lean index 4853d8c9c1bfc..f89c15dd99f1b 100644 --- a/Mathlib/Dynamics/Ergodic/Conservative.lean +++ b/Mathlib/Dynamics/Ergodic/Conservative.lean @@ -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 μ) @@ -147,7 +158,7 @@ theorem measure_inter_frequently_image_mem_eq (hf : Conservative f μ) (hs : Nul /-- Poincaré recurrence theorem: if `f` is a conservative dynamical system and `s` is a measurable set, then for `μ`-a.e. `x`, if the orbit of `x` visits `s` at least once, then it visits `s` -infinitely many times. -/ +infinitely many times. -/ theorem ae_forall_image_mem_imp_frequently_image_mem (hf : Conservative f μ) (hs : NullMeasurableSet s μ) : ∀ᵐ x ∂μ, ∀ k, f^[k] x ∈ s → ∃ᶠ n in atTop, f^[n] x ∈ s := by refine ae_all_iff.2 fun k => ?_ diff --git a/Mathlib/Dynamics/Ergodic/Ergodic.lean b/Mathlib/Dynamics/Ergodic/Ergodic.lean index 0198ed3650021..eb2fbac4d06d4 100644 --- a/Mathlib/Dynamics/Ergodic/Ergodic.lean +++ b/Mathlib/Dynamics/Ergodic/Ergodic.lean @@ -33,36 +33,40 @@ open Set Function Filter MeasureTheory MeasureTheory.Measure open ENNReal -variable {α : Type*} {m : MeasurableSpace α} (f : α → α) {s : Set α} +variable {α : Type*} {m : MeasurableSpace α} {s : Set α} /-- A map `f : α → α` is said to be pre-ergodic with respect to a measure `μ` if any measurable strictly invariant set is either almost empty or full. -/ -structure PreErgodic (μ : Measure α := by volume_tac) : Prop where - ae_empty_or_univ : ∀ ⦃s⦄, MeasurableSet s → f ⁻¹' s = s → s =ᵐ[μ] (∅ : Set α) ∨ s =ᵐ[μ] univ +structure PreErgodic (f : α → α) (μ : Measure α := by volume_tac) : Prop where + aeconst_set ⦃s⦄ : MeasurableSet s → f ⁻¹' s = s → EventuallyConst s (ae μ) /-- A map `f : α → α` is said to be ergodic with respect to a measure `μ` if it is measure preserving and pre-ergodic. -/ -- porting note (#5171): removed @[nolint has_nonempty_instance] -structure Ergodic (μ : Measure α := by volume_tac) extends +structure Ergodic (f : α → α) (μ : Measure α := by volume_tac) extends MeasurePreserving f μ μ, PreErgodic f μ : Prop /-- A map `f : α → α` is said to be quasi ergodic with respect to a measure `μ` if it is quasi measure preserving and pre-ergodic. -/ -- porting note (#5171): removed @[nolint has_nonempty_instance] -structure QuasiErgodic (μ : Measure α := by volume_tac) extends +structure QuasiErgodic (f : α → α) (μ : Measure α := by volume_tac) extends QuasiMeasurePreserving f μ μ, PreErgodic f μ : Prop -variable {f} {μ : Measure α} +variable {f : α → α} {μ : Measure α} namespace PreErgodic +theorem ae_empty_or_univ (hf : PreErgodic f μ) (hs : MeasurableSet s) (hfs : f ⁻¹' s = s) : + s =ᵐ[μ] (∅ : Set α) ∨ s =ᵐ[μ] univ := by + simpa only [eventuallyConst_set'] using hf.aeconst_set hs hfs + theorem measure_self_or_compl_eq_zero (hf : PreErgodic f μ) (hs : MeasurableSet s) (hs' : f ⁻¹' s = s) : μ s = 0 ∨ μ sᶜ = 0 := by simpa using hf.ae_empty_or_univ hs hs' theorem ae_mem_or_ae_nmem (hf : PreErgodic f μ) (hsm : MeasurableSet s) (hs : f ⁻¹' s = s) : (∀ᵐ x ∂μ, x ∈ s) ∨ ∀ᵐ x ∂μ, x ∉ s := - (hf.ae_empty_or_univ hsm hs).symm.imp eventuallyEq_univ.1 eventuallyEq_empty.1 + eventuallyConst_set.1 <| hf.aeconst_set hsm hs /-- On a probability space, the (pre)ergodicity condition is a zero one law. -/ theorem prob_eq_zero_or_one [IsProbabilityMeasure μ] (hf : PreErgodic f μ) (hs : MeasurableSet s) @@ -70,7 +74,7 @@ theorem prob_eq_zero_or_one [IsProbabilityMeasure μ] (hf : PreErgodic f μ) (hs simpa [hs] using hf.measure_self_or_compl_eq_zero hs hs' theorem of_iterate (n : ℕ) (hf : PreErgodic f^[n] μ) : PreErgodic f μ := - ⟨fun _ hs hs' => hf.ae_empty_or_univ hs <| IsFixedPt.preimage_iterate hs' n⟩ + ⟨fun _ hs hs' => hf.aeconst_set hs <| IsFixedPt.preimage_iterate hs' n⟩ end PreErgodic @@ -79,23 +83,18 @@ namespace MeasureTheory.MeasurePreserving variable {β : Type*} {m' : MeasurableSpace β} {μ' : Measure β} {s' : Set β} {g : α → β} theorem preErgodic_of_preErgodic_conjugate (hg : MeasurePreserving g μ μ') (hf : PreErgodic f μ) - {f' : β → β} (h_comm : g ∘ f = f' ∘ g) : PreErgodic f' μ' := - ⟨by - intro s hs₀ hs₁ - replace hs₁ : f ⁻¹' (g ⁻¹' s) = g ⁻¹' s := by rw [← preimage_comp, h_comm, preimage_comp, hs₁] - cases' hf.ae_empty_or_univ (hg.measurable hs₀) hs₁ with hs₂ hs₂ <;> [left; right] - · simpa only [ae_eq_empty, hg.measure_preimage hs₀.nullMeasurableSet] using hs₂ - · simpa only [ae_eq_univ, ← preimage_compl, - hg.measure_preimage hs₀.compl.nullMeasurableSet] using hs₂⟩ + {f' : β → β} (h_comm : Semiconj g f f') : PreErgodic f' μ' where + aeconst_set s hs₀ hs₁ := by + rw [← hg.aeconst_preimage hs₀.nullMeasurableSet] + apply hf.aeconst_set (hg.measurable hs₀) + rw [← preimage_comp, h_comm.comp_eq, preimage_comp, hs₁] theorem preErgodic_conjugate_iff {e : α ≃ᵐ β} (h : MeasurePreserving e μ μ') : PreErgodic (e ∘ f ∘ e.symm) μ' ↔ PreErgodic f μ := by refine ⟨fun hf => preErgodic_of_preErgodic_conjugate (h.symm e) hf ?_, fun hf => preErgodic_of_preErgodic_conjugate h hf ?_⟩ - · change (e.symm ∘ e) ∘ f ∘ e.symm = f ∘ e.symm - rw [MeasurableEquiv.symm_comp_self, id_comp] - · change e ∘ f = e ∘ f ∘ e.symm ∘ e - rw [MeasurableEquiv.symm_comp_self, comp_id] + · simp [Semiconj] + · simp [Semiconj] theorem ergodic_conjugate_iff {e : α ≃ᵐ β} (h : MeasurePreserving e μ μ') : Ergodic (e ∘ f ∘ e.symm) μ' ↔ Ergodic f μ := by @@ -109,27 +108,26 @@ end MeasureTheory.MeasurePreserving namespace QuasiErgodic -/-- For a quasi ergodic map, sets that are almost invariant (rather than strictly invariant) are -still either almost empty or full. -/ -theorem ae_empty_or_univ' (hf : QuasiErgodic f μ) (hs : MeasurableSet s) (hs' : f ⁻¹' s =ᵐ[μ] s) : - s =ᵐ[μ] (∅ : Set α) ∨ s =ᵐ[μ] univ := by - obtain ⟨t, h₀, h₁, h₂⟩ := hf.toQuasiMeasurePreserving.exists_preimage_eq_of_preimage_ae hs hs' - rcases hf.ae_empty_or_univ h₀ h₂ with (h₃ | h₃) <;> [left; right] <;> exact ae_eq_trans h₁.symm h₃ +theorem aeconst_set₀ (hf : QuasiErgodic f μ) (hsm : NullMeasurableSet s μ) (hs : f ⁻¹' s =ᵐ[μ] s) : + EventuallyConst s (ae μ) := + let ⟨_t, h₀, h₁, h₂⟩ := hf.toQuasiMeasurePreserving.exists_preimage_eq_of_preimage_ae hsm hs + (hf.aeconst_set h₀ h₂).congr h₁ /-- For a quasi ergodic map, sets that are almost invariant (rather than strictly invariant) are still either almost empty or full. -/ theorem ae_empty_or_univ₀ (hf : QuasiErgodic f μ) (hsm : NullMeasurableSet s μ) - (hs : f ⁻¹' s =ᵐ[μ] s) : s =ᵐ[μ] (∅ : Set α) ∨ s =ᵐ[μ] univ := - let ⟨t, htm, hst⟩ := hsm - have : f ⁻¹' t =ᵐ[μ] t := (hf.preimage_ae_eq hst.symm).trans <| hs.trans hst - (hf.ae_empty_or_univ' htm this).imp hst.trans hst.trans + (hs : f ⁻¹' s =ᵐ[μ] s) : + s =ᵐ[μ] (∅ : Set α) ∨ s =ᵐ[μ] univ := + eventuallyConst_set'.mp <| hf.aeconst_set₀ hsm hs + +@[deprecated (since := "2024-07-21")] alias ae_empty_or_univ' := ae_empty_or_univ₀ /-- For a quasi ergodic map, sets that are almost invariant (rather than strictly invariant) are still either almost empty or full. -/ theorem ae_mem_or_ae_nmem₀ (hf : QuasiErgodic f μ) (hsm : NullMeasurableSet s μ) (hs : f ⁻¹' s =ᵐ[μ] s) : (∀ᵐ x ∂μ, x ∈ s) ∨ ∀ᵐ x ∂μ, x ∉ s := - (hf.ae_empty_or_univ₀ hsm hs).symm.imp (by simp [mem_ae_iff]) (by simp [ae_iff]) + eventuallyConst_set.mp <| hf.aeconst_set₀ hsm hs end QuasiErgodic @@ -140,23 +138,21 @@ theorem quasiErgodic (hf : Ergodic f μ) : QuasiErgodic f μ := { hf.toPreErgodic, hf.toMeasurePreserving.quasiMeasurePreserving with } /-- See also `Ergodic.ae_empty_or_univ_of_preimage_ae_le`. -/ -theorem ae_empty_or_univ_of_preimage_ae_le' (hf : Ergodic f μ) (hs : MeasurableSet s) +theorem ae_empty_or_univ_of_preimage_ae_le' (hf : Ergodic f μ) (hs : NullMeasurableSet s μ) (hs' : f ⁻¹' s ≤ᵐ[μ] s) (h_fin : μ s ≠ ∞) : s =ᵐ[μ] (∅ : Set α) ∨ s =ᵐ[μ] univ := by - refine hf.quasiErgodic.ae_empty_or_univ' hs ?_ - refine ae_eq_of_ae_subset_of_measure_ge hs' - (hf.measure_preimage hs.nullMeasurableSet).symm.le ?_ h_fin - exact measurableSet_preimage hf.measurable hs + refine hf.quasiErgodic.ae_empty_or_univ₀ hs ?_ + refine ae_eq_of_ae_subset_of_measure_ge hs' (hf.measure_preimage hs).ge ?_ h_fin + exact hs.preimage hf.quasiMeasurePreserving /-- See also `Ergodic.ae_empty_or_univ_of_ae_le_preimage`. -/ -theorem ae_empty_or_univ_of_ae_le_preimage' (hf : Ergodic f μ) (hs : MeasurableSet s) +theorem ae_empty_or_univ_of_ae_le_preimage' (hf : Ergodic f μ) (hs : NullMeasurableSet s μ) (hs' : s ≤ᵐ[μ] f ⁻¹' s) (h_fin : μ s ≠ ∞) : s =ᵐ[μ] (∅ : Set α) ∨ s =ᵐ[μ] univ := by - replace h_fin : μ (f ⁻¹' s) ≠ ∞ := by rwa [hf.measure_preimage hs.nullMeasurableSet] - refine hf.quasiErgodic.ae_empty_or_univ' hs ?_ - exact (ae_eq_of_ae_subset_of_measure_ge hs' - (hf.measure_preimage hs.nullMeasurableSet).le hs h_fin).symm + replace h_fin : μ (f ⁻¹' s) ≠ ∞ := by rwa [hf.measure_preimage hs] + refine hf.quasiErgodic.ae_empty_or_univ₀ hs ?_ + exact (ae_eq_of_ae_subset_of_measure_ge hs' (hf.measure_preimage hs).le hs h_fin).symm /-- See also `Ergodic.ae_empty_or_univ_of_image_ae_le`. -/ -theorem ae_empty_or_univ_of_image_ae_le' (hf : Ergodic f μ) (hs : MeasurableSet s) +theorem ae_empty_or_univ_of_image_ae_le' (hf : Ergodic f μ) (hs : NullMeasurableSet s μ) (hs' : f '' s ≤ᵐ[μ] s) (h_fin : μ s ≠ ∞) : s =ᵐ[μ] (∅ : Set α) ∨ s =ᵐ[μ] univ := by replace hs' : s ≤ᵐ[μ] f ⁻¹' s := (HasSubset.Subset.eventuallyLE (subset_preimage_image f s)).trans @@ -167,15 +163,15 @@ section IsFiniteMeasure variable [IsFiniteMeasure μ] -theorem ae_empty_or_univ_of_preimage_ae_le (hf : Ergodic f μ) (hs : MeasurableSet s) +theorem ae_empty_or_univ_of_preimage_ae_le (hf : Ergodic f μ) (hs : NullMeasurableSet s μ) (hs' : f ⁻¹' s ≤ᵐ[μ] s) : s =ᵐ[μ] (∅ : Set α) ∨ s =ᵐ[μ] univ := ae_empty_or_univ_of_preimage_ae_le' hf hs hs' <| measure_ne_top μ s -theorem ae_empty_or_univ_of_ae_le_preimage (hf : Ergodic f μ) (hs : MeasurableSet s) +theorem ae_empty_or_univ_of_ae_le_preimage (hf : Ergodic f μ) (hs : NullMeasurableSet s μ) (hs' : s ≤ᵐ[μ] f ⁻¹' s) : s =ᵐ[μ] (∅ : Set α) ∨ s =ᵐ[μ] univ := ae_empty_or_univ_of_ae_le_preimage' hf hs hs' <| measure_ne_top μ s -theorem ae_empty_or_univ_of_image_ae_le (hf : Ergodic f μ) (hs : MeasurableSet s) +theorem ae_empty_or_univ_of_image_ae_le (hf : Ergodic f μ) (hs : NullMeasurableSet s μ) (hs' : f '' s ≤ᵐ[μ] s) : s =ᵐ[μ] (∅ : Set α) ∨ s =ᵐ[μ] univ := ae_empty_or_univ_of_image_ae_le' hf hs hs' <| measure_ne_top μ s diff --git a/Mathlib/Dynamics/Ergodic/MeasurePreserving.lean b/Mathlib/Dynamics/Ergodic/MeasurePreserving.lean index 3a4d7509a3c58..aeb910c97b9ae 100644 --- a/Mathlib/Dynamics/Ergodic/MeasurePreserving.lean +++ b/Mathlib/Dynamics/Ergodic/MeasurePreserving.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.MeasureTheory.Measure.AEMeasurable +import Mathlib.Order.Filter.EventuallyConst /-! # Measure preserving maps @@ -101,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 := @@ -126,13 +127,25 @@ theorem measure_preimage_equiv {f : α ≃ᵐ β} (hf : MeasurePreserving f μa μa (f ⁻¹' s) = μb s := measure_preimage_emb hf f.measurableEmbedding s -protected theorem iterate {f : α → α} (hf : MeasurePreserving f μa μa) : - ∀ n, MeasurePreserving f^[n] μa μa - | 0 => MeasurePreserving.id μa - | n + 1 => (MeasurePreserving.iterate hf n).comp hf +theorem aeconst_comp [MeasurableSingletonClass γ] {f : α → β} (hf : MeasurePreserving f μa μb) + {g : β → γ} (hg : NullMeasurable g μb) : + Filter.EventuallyConst (g ∘ f) (ae μa) ↔ Filter.EventuallyConst g (ae μb) := + exists_congr fun s ↦ and_congr_left fun hs ↦ by + simp only [Filter.mem_map, mem_ae_iff, ← hf.measure_preimage (hg hs.measurableSet).compl, + preimage_comp, preimage_compl] + +theorem aeconst_preimage {f : α → β} (hf : MeasurePreserving f μa μb) {s : Set β} + (hs : NullMeasurableSet s μb) : + Filter.EventuallyConst (f ⁻¹' s) (ae μa) ↔ Filter.EventuallyConst s (ae μb) := + aeconst_comp hf hs.mem variable {μ : Measure α} {f : α → α} {s : Set α} +protected theorem iterate (hf : MeasurePreserving f μ μ) : + ∀ n, MeasurePreserving f^[n] μ μ + | 0 => .id μ + | n + 1 => (MeasurePreserving.iterate hf n).comp hf + open scoped symmDiff in lemma measure_symmDiff_preimage_iterate_le (hf : MeasurePreserving f μ μ) (hs : NullMeasurableSet s μ) (n : ℕ) : diff --git a/Mathlib/Dynamics/OmegaLimit.lean b/Mathlib/Dynamics/OmegaLimit.lean index 898b206987a20..7de977bddf6ba 100644 --- a/Mathlib/Dynamics/OmegaLimit.lean +++ b/Mathlib/Dynamics/OmegaLimit.lean @@ -86,14 +86,14 @@ theorem mapsTo_omegaLimit' {α' β' : Type*} [TopologicalSpace β'] {f : Filter intro y hy u hu refine map_mem_closure hgc (hy _ (inter_mem hu hg)) (forall_image2_iff.2 fun t ht x hx ↦ ?_) calc - gb (ϕ t x) = ϕ' t (ga x) := ht.2 hx - _ ∈ image2 ϕ' u s' := mem_image2_of_mem ht.1 (hs hx) + ϕ' t (ga x) ∈ image2 ϕ' u s' := mem_image2_of_mem ht.1 (hs hx) + _ = gb (ϕ t x) := ht.2 hx |>.symm theorem mapsTo_omegaLimit {α' β' : Type*} [TopologicalSpace β'] {f : Filter τ} {ϕ : τ → α → β} {ϕ' : τ → α' → β'} {ga : α → α'} {s' : Set α'} (hs : MapsTo ga s s') {gb : β → β'} (hg : ∀ t x, gb (ϕ t x) = ϕ' t (ga x)) (hgc : Continuous gb) : MapsTo gb (ω f ϕ s) (ω f ϕ' s') := - mapsTo_omegaLimit' _ hs (eventually_of_forall fun t x _hx ↦ hg t x) hgc + mapsTo_omegaLimit' _ hs (Eventually.of_forall fun t x _hx ↦ hg t x) hgc theorem omegaLimit_image_eq {α' : Type*} (ϕ : τ → α' → β) (f : Filter τ) (g : α → α') : ω f ϕ (g '' s) = ω f (fun t x ↦ ϕ t (g x)) s := by simp only [omegaLimit, image2_image_right] @@ -192,6 +192,9 @@ theorem omegaLimit_subset_closure_fw_image {u : Set τ} (hu : u ∈ f) : rw [mem_iInter] at hx exact hx ⟨u, hu⟩ +-- An instance with better keys +instance : Inhabited f.sets := Filter.inhabitedMem + /-! ### ω-limits and compactness -/ diff --git a/Mathlib/Dynamics/PeriodicPts.lean b/Mathlib/Dynamics/PeriodicPts.lean index 658cf28c6f47d..160a6606f5e0f 100644 --- a/Mathlib/Dynamics/PeriodicPts.lean +++ b/Mathlib/Dynamics/PeriodicPts.lean @@ -6,6 +6,7 @@ Authors: Yury Kudryashov import Mathlib.Algebra.GroupPower.IterateHom import Mathlib.Algebra.Ring.Divisibility.Basic import Mathlib.Data.List.Cycle +import Mathlib.Data.Nat.GCD.Basic import Mathlib.Data.Nat.Prime.Basic import Mathlib.Data.PNat.Basic import Mathlib.Dynamics.FixedPoints.Basic @@ -337,7 +338,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 @@ -432,7 +433,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 new file mode 100644 index 0000000000000..2b8f40fded2bf --- /dev/null +++ b/Mathlib/Dynamics/TopologicalEntropy/CoverEntropy.lean @@ -0,0 +1,599 @@ +/- +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.Analysis.SpecialFunctions.Log.ENNRealLog +import Mathlib.Data.Real.ENatENNReal +import Mathlib.Dynamics.TopologicalEntropy.DynamicalEntourage + +/-! +# Topological entropy via covers +We implement Bowen-Dinaburg's definitions of the topological entropy, via covers. + +All is stated in the vocabulary of uniform spaces. For compact spaces, the uniform structure +is canonical, so the topological entropy depends only on the topological structure. This will give +a clean proof that the topological entropy is a topological invariant of the dynamics. + +A notable choice is that we define the topological entropy of a subset `F` of the whole space. +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.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 +keep the possibility for the entropy to be infinite. Hence, the entropy takes values in the extended +reals `[-∞, +∞]`. The consequence is that we use `ℕ∞`, `ℝ≥0∞` and `EReal` numbers. + +## Main definitions +- `IsDynCoverOf`: property that dynamical balls centered on a subset `s` cover a subset `F`. +- `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 +There are two competing definitions of topological entropy in this file: one uses a `liminf`, +the other a `limsup`. These two topological entropies are equal as soon as they are applied to an +invariant subset by theorem `coverEntropyInf_eq_coverEntropy`. We choose the default definition +to be the definition using a `limsup`, and give it the simpler name `coverEntropy` (instead of +`coverEntropySup`). Theorems about the topological entropy of invariant subsets will be stated +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.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`. + +## Tags +cover, entropy + +## TODO +The most painful part of many manipulations involving topological entropy is going from +`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. +-/ + +namespace Dynamics + +open Set Uniformity UniformSpace + +variable {X : Type*} + +/-! ### Dynamical covers -/ + +/-- Given a subset `F`, an entourage `U` and an integer `n`, a subset `s` is a `(U, n)`- +dynamical cover of `F` if any orbit of length `n` in `F` is `U`-shadowed by an orbit of length `n` +of a point in `s`.-/ +def IsDynCoverOf (T : X → X) (F : Set X) (U : Set (X × X)) (n : ℕ) (s : Set X) : Prop := + F ⊆ ⋃ x ∈ s, ball x (dynEntourage T U n) + +lemma IsDynCoverOf.of_le {T : X → X} {F : Set X} {U : Set (X × X)} {m n : ℕ} (m_n : m ≤ n) + {s : Set X} (h : IsDynCoverOf T F U n s) : + IsDynCoverOf T F U m s := by + exact Subset.trans (c := ⋃ x ∈ s, ball x (dynEntourage T U m)) h + (iUnion₂_mono fun x _ ↦ ball_mono (dynEntourage_antitone T U m_n) x) + +lemma IsDynCoverOf.of_entourage_subset {T : X → X} {F : Set X} {U V : Set (X × X)} (U_V : U ⊆ V) + {n : ℕ} {s : Set X} (h : IsDynCoverOf T F U n s) : + IsDynCoverOf T F V n s := by + exact Subset.trans (c := ⋃ x ∈ s, ball x (dynEntourage T V n)) h + (iUnion₂_mono fun x _ ↦ ball_mono (dynEntourage_monotone T n U_V) x) + +@[simp] +lemma isDynCoverOf_empty {T : X → X} {U : Set (X × X)} {n : ℕ} {s : Set X} : + IsDynCoverOf T ∅ U n s := by + simp only [IsDynCoverOf, empty_subset] + +lemma IsDynCoverOf.nonempty {T : X → X} {F : Set X} (h : F.Nonempty) {U : Set (X × X)} {n : ℕ} + {s : Set X} (h' : IsDynCoverOf T F U n s) : + s.Nonempty := by + rcases nonempty_biUnion.1 (Nonempty.mono h' h) with ⟨x, x_s, _⟩ + exact nonempty_of_mem x_s + +lemma isDynCoverOf_zero (T : X → X) (F : Set X) (U : Set (X × X)) {s : Set X} (h : s.Nonempty) : + IsDynCoverOf T F U 0 s := by + simp only [IsDynCoverOf, ball, dynEntourage, not_lt_zero', Prod.map_iterate, iInter_of_empty, + iInter_univ, preimage_univ] + rcases h with ⟨x, x_s⟩ + exact subset_iUnion₂_of_subset x x_s (subset_univ F) + +lemma isDynCoverOf_univ (T : X → X) (F : Set X) (n : ℕ) {s : Set X} (h : s.Nonempty) : + IsDynCoverOf T F univ n s := by + simp only [IsDynCoverOf, ball, dynEntourage, Prod.map_iterate, preimage_univ, iInter_univ, + iUnion_coe_set] + rcases h with ⟨x, x_s⟩ + exact subset_iUnion₂_of_subset x x_s (subset_univ F) + +lemma IsDynCoverOf.nonempty_inter {T : X → X} {F : Set X} {U : Set (X × X)} {n : ℕ} {s : Finset X} + (h : IsDynCoverOf T F U n s) : + ∃ t : Finset X, IsDynCoverOf T F U n t ∧ t.card ≤ s.card + ∧ ∀ x ∈ t, ((ball x (dynEntourage T U n)) ∩ F).Nonempty := by + classical + use Finset.filter (fun x : X ↦ ((ball x (dynEntourage T U n)) ∩ F).Nonempty) s + simp only [Finset.coe_filter, Finset.mem_filter, and_imp, imp_self, implies_true, and_true] + refine ⟨fun y y_F ↦ ?_, Finset.card_mono (Finset.filter_subset _ s)⟩ + specialize h y_F + simp only [Finset.coe_sort_coe, mem_iUnion, Subtype.exists, exists_prop] at h + rcases h with ⟨z, z_s, y_Bz⟩ + simp only [coe_setOf, mem_setOf_eq, mem_iUnion, Subtype.exists, exists_prop] + exact ⟨z, ⟨z_s, nonempty_of_mem ⟨y_Bz, y_F⟩⟩, y_Bz⟩ + +/-- 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 (`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 + classical + -- Deal with the edge cases: `F = ∅` or `m = 0`. + rcases F.eq_empty_or_nonempty with rfl | F_nemp + · exact ⟨∅, by simp⟩ + have _ : Nonempty X := nonempty_of_exists F_nemp + have s_nemp := h.nonempty F_nemp + rcases F_nemp with ⟨x, x_F⟩ + rcases m.eq_zero_or_pos with rfl | m_pos + · use {x} + simp only [zero_mul, Finset.coe_singleton, Finset.card_singleton] + exact And.intro (isDynCoverOf_zero T F (U ○ U) (singleton_nonempty x)) + <| one_le_pow_of_one_le' (Nat.one_le_of_lt (Finset.Nonempty.card_pos s_nemp)) n + -- The proof goes as follows. Given an orbit of length `(m * n)` starting from `y`, each of its + -- iterates `y`, `T^[m] y`, `T^[m]^[2] y` ... is `(dynEntourage T U m)`-close to a point of `s`. + -- Conversely, given a sequence `t 0`, `t 1`, `t 2` of points in `s`, we choose a point + -- `z = dyncover t` such that `z`, `T^[m] z`, `T^[m]^[2] z` ... are `(dynEntourage T U m)`-close + -- to `t 0`, `t 1`, `t 2`... Then `y`, `T^[m] y`, `T^[m]^[2] y` ... are + -- `(dynEntourage T (U ○ U) m)`-close to `z`, `T^[m] z`, `T^[m]^[2] z`, so that the union of such + -- `z` provides the desired cover. Since there are at most `s.card ^ n` sequences of + -- length `n` with values in `s`, we get the upper bound we want on the cardinality. + -- First step: construct `dyncover`. Given `t 0`, `t 1`, `t 2`, if we cannot find such a point + -- `dyncover t`, we use the dummy `x`. + have (t : Fin n → s) : ∃ y : X, (⋂ k : Fin n, T^[m * k] ⁻¹' ball (t k) (dynEntourage T U m)) ⊆ + ball y (dynEntourage T (U ○ U) (m * n)) := by + rcases (⋂ k : Fin n, T^[m * k] ⁻¹' ball (t k) (dynEntourage T U m)).eq_empty_or_nonempty + with inter_empt | inter_nemp + · exact inter_empt ▸ ⟨x, empty_subset _⟩ + · rcases inter_nemp with ⟨y, y_int⟩ + refine ⟨y, fun z z_int ↦ ?_⟩ + simp only [ball, dynEntourage, Prod.map_iterate, mem_preimage, mem_iInter, + Prod.map_apply] at y_int z_int ⊢ + intro k k_mn + replace k_mn := Nat.div_lt_of_lt_mul k_mn + specialize z_int ⟨(k / m), k_mn⟩ (k % m) (Nat.mod_lt k m_pos) + specialize y_int ⟨(k / m), k_mn⟩ (k % m) (Nat.mod_lt k m_pos) + rw [← Function.iterate_add_apply T (k % m) (m * (k / m)), Nat.mod_add_div k m] at y_int z_int + exact mem_comp_of_mem_ball U_symm y_int z_int + choose! dyncover h_dyncover using this + -- The cover we want is the set of all `dyncover t`, that is, `range dyncover`. We need to check + -- that it is indeed a `(U ○ U, m * n)` cover, and that its cardinality is at most `card s ^ n`. + -- Only the first point requires significant work. + let sn := range dyncover + have := fintypeRange dyncover + refine ⟨sn.toFinset, ?_, ?_⟩ + · -- We implement the argument at the beginning: given `y ∈ F`, we extract `t 0`, `t 1`, `t 2` + -- such that `y`, `T^[m] y`, `T^[m]^[2] y` ... is `(dynEntourage T U m)`-close to `t 0`, `t 1`, + -- `t 2`... Then `dyncover t` is a point of `range dyncover` which satisfies the conclusion + -- of the lemma. + rw [Finset.coe_nonempty] at s_nemp + have _ : Nonempty s := Finset.Nonempty.coe_sort s_nemp + intro y y_F + have key : ∀ k : Fin n, ∃ z : s, y ∈ T^[m * k] ⁻¹' ball z (dynEntourage T U m) := by + intro k + have := h (MapsTo.iterate F_inv (m * k) y_F) + simp only [Finset.coe_sort_coe, mem_iUnion, Subtype.exists, exists_prop] at this + rcases this with ⟨z, z_s, hz⟩ + exact ⟨⟨z, z_s⟩, hz⟩ + choose! t ht using key + simp only [toFinset_range, Finset.coe_image, Finset.coe_univ, image_univ, mem_range, + iUnion_exists, iUnion_iUnion_eq', mem_iUnion, sn] + use t + apply h_dyncover t + simp only [mem_iInter, mem_preimage] at ht ⊢ + exact ht + · rw [toFinset_card] + apply (Fintype.card_range_le dyncover).trans + simp only [Fintype.card_fun, Fintype.card_coe, Fintype.card_fin, le_refl] + +lemma exists_isDynCoverOf_of_isCompact_uniformContinuous [UniformSpace X] {T : X → X} {F : Set X} + (F_comp : IsCompact F) (h : UniformContinuous T) {U : Set (X × X)} (U_uni : U ∈ 𝓤 X) (n : ℕ) : + ∃ s : Finset X, IsDynCoverOf T F U n s := by + have uni_ite := dynEntourage_mem_uniformity h U_uni n + let open_cover := fun x : X ↦ ball x (dynEntourage T U n) + obtain ⟨s, _, s_cover⟩ := IsCompact.elim_nhds_subcover F_comp open_cover + (fun (x : X) _ ↦ ball_mem_nhds x uni_ite) + exact ⟨s, s_cover⟩ + +lemma exists_isDynCoverOf_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 : ℕ) : + ∃ s : Finset X, IsDynCoverOf T F U n s := by + rcases comp_symm_mem_uniformity_sets U_uni with ⟨V, V_uni, V_symm, V_U⟩ + obtain ⟨s, _, s_cover⟩ := IsCompact.elim_nhds_subcover F_comp (fun x : X ↦ ball x V) + (fun (x : X) _ ↦ ball_mem_nhds x V_uni) + have : IsDynCoverOf T F V 1 s := by + simp only [IsDynCoverOf, Finset.mem_coe, dynEntourage_one, s_cover] + rcases this.iterate_le_pow F_inv V_symm n with ⟨t, t_dyncover, t_card⟩ + rw [one_mul n] at t_dyncover + exact ⟨t, t_dyncover.of_entourage_subset V_U⟩ + +/-! ### Minimal cardinality of dynamical covers -/ + +/-- The smallest cardinality of a `(U, n)`-dynamical cover of `F`. Takes values in `ℕ∞`, and is + infinite if and only if `F` admits no finite dynamical cover.-/ +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 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)) : + Monotone (fun n : ℕ ↦ coverMincard T F U n) := + fun _ _ m_n ↦ biInf_mono fun _ h ↦ h.of_le m_n + +lemma coverMincard_antitone (T : X → X) (F : Set X) (n : ℕ) : + Antitone (fun U : Set (X × X) ↦ coverMincard T F U n) := + fun _ _ U_V ↦ biInf_mono fun _ h ↦ h.of_entourage_subset U_V + +lemma coverMincard_finite_iff (T : X → X) (F : Set X) (U : Set (X × X)) (n : ℕ) : + coverMincard T F U n < ⊤ ↔ + ∃ s : Finset X, IsDynCoverOf T F U n s ∧ s.card = coverMincard T F U n := by + refine ⟨fun h_fin ↦ ?_, (fun ⟨s, _, s_coverMincard⟩ ↦ s_coverMincard ▸ WithTop.coe_lt_top s.card)⟩ + rcases WithTop.ne_top_iff_exists.1 (ne_of_lt h_fin) with ⟨k, k_min⟩ + rw [← k_min] + simp only [ENat.some_eq_coe, Nat.cast_inj] + have : Nonempty {s : Finset X // IsDynCoverOf T F U n s} := by + by_contra h + apply ENat.coe_ne_top k + rw [← ENat.some_eq_coe, k_min, coverMincard, iInf₂_eq_top] + simp only [ENat.coe_ne_top, imp_false] + rw [nonempty_subtype, not_exists] at h + exact h + have key := ciInf_mem (fun s : {s : Finset X // IsDynCoverOf T F U n s} ↦ (s.val.card : ℕ∞)) + rw [coverMincard, iInf_subtype'] at k_min + rw [← k_min, mem_range, Subtype.exists] at key + simp only [ENat.some_eq_coe, Nat.cast_inj, exists_prop] at key + exact key + +@[simp] +lemma coverMincard_empty {T : X → X} {U : Set (X × X)} {n : ℕ} : coverMincard T ∅ U n = 0 := + (sInf_le (by simp [IsDynCoverOf])).antisymm (zero_le (coverMincard T ∅ U n)) + +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 + 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 + +lemma one_le_coverMincard_iff (T : X → X) (F : Set X) (U : Set (X × X)) (n : ℕ) : + 1 ≤ coverMincard T F U n ↔ F.Nonempty := by + rw [ENat.one_le_iff_ne_zero, nonempty_iff_ne_empty, not_iff_not] + exact coverMincard_eq_zero_iff T F U n + +lemma coverMincard_zero (T : X → X) {F : Set X} (h : F.Nonempty) (U : Set (X × X)) : + coverMincard T F U 0 = 1 := by + apply le_antisymm _ ((one_le_coverMincard_iff T F U 0).2 h) + rcases h with ⟨x, _⟩ + have := isDynCoverOf_zero T F U (singleton_nonempty x) + rw [← Finset.coe_singleton] at 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 : ℕ) : + coverMincard T F univ n = 1 := by + apply le_antisymm _ ((one_le_coverMincard_iff T F univ n).2 h) + rcases h with ⟨x, _⟩ + have := isDynCoverOf_univ T F n (singleton_nonempty x) + rw [← Finset.coe_singleton] at 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)} + (U_symm : SymmetricRel U) (m n : ℕ) : + coverMincard T F (U ○ U) (m * n) ≤ coverMincard T F U m ^ n := by + rcases F.eq_empty_or_nonempty with rfl | F_nonempty + · rw [coverMincard_empty]; exact zero_le _ + 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_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 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) (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} + {F : Set X} (F_comp : IsCompact F) (h : UniformContinuous T) {U : Set (X × X)} (U_uni : U ∈ 𝓤 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 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 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 + of topological entropy with nets.-/ +lemma nonempty_inter_of_coverMincard {T : X → X} {F : Set X} {U : Set (X × X)} {n : ℕ} + {s : Finset X} (h : IsDynCoverOf T F U n s) (h' : s.card = coverMincard T F U n) : + ∀ x ∈ s, (F ∩ ball x (dynEntourage T U n)).Nonempty := by + -- Otherwise, there is a ball which does not intersect `F`. Removing it yields a smaller cover. + classical + by_contra! hypo + rcases hypo with ⟨x, x_s, ball_empt⟩ + have smaller_cover : IsDynCoverOf T F U n (Finset.erase s x) := by + intro y y_F + specialize h y_F + simp only [Finset.mem_coe, mem_iUnion, exists_prop] at h + rcases h with ⟨z, z_s, hz⟩ + simp only [Finset.coe_erase, mem_diff, Finset.mem_coe, mem_singleton_iff, mem_iUnion, + exists_prop] + refine ⟨z, And.intro (And.intro z_s fun z_x ↦ not_mem_empty y ?_) hz⟩ + rw [← ball_empt] + rw [z_x] at hz + exact mem_inter y_F hz + apply smaller_cover.coverMincard_le_card.not_lt + rw [← h'] + exact_mod_cast Finset.card_erase_lt_of_mem x_s + +open ENNReal EReal + +lemma log_coverMincard_nonneg (T : X → X) {F : Set X} (h : F.Nonempty) (U : Set (X × X)) (n : ℕ) : + 0 ≤ log (coverMincard T F U n) := by + apply zero_le_log_iff.2 + rw [← ENat.toENNReal_one, ENat.toENNReal_le] + exact (one_le_coverMincard_iff T F U n).2 h + +lemma log_coverMincard_iterate_le {T : X → X} {F : Set X} (F_inv : MapsTo T F F) {U : Set (X × X)} + (U_symm : SymmetricRel U) (m : ℕ) {n : ℕ} (n_pos : 0 < n) : + log (coverMincard T F (U ○ U) (m * n)) / n ≤ log (coverMincard T F U m) := by + apply (EReal.div_le_iff_le_mul (b := n) (Nat.cast_pos'.2 n_pos) (natCast_ne_top n)).2 + rw [← log_pow, StrictMono.le_iff_le log_strictMono] + nth_rw 2 [← ENat.toENNRealRingHom_apply] + rw [← RingHom.map_pow ENat.toENNRealRingHom _ n, ENat.toENNRealRingHom_apply, ENat.toENNReal_le] + exact coverMincard_mul_le_pow F_inv U_symm m n + +lemma log_coverMincard_le_add {T : X → X} {F : Set X} (F_inv : MapsTo T F F) + {U : Set (X × X)} (U_symm : SymmetricRel U) {m n : ℕ} (m_pos : 0 < m) (n_pos : 0 < n) : + log (coverMincard T F (U ○ U) n) / n + ≤ log (coverMincard T F U m) / m + log (coverMincard T F U m) / n := by + -- If `n` is a multiple of `m`, this follows directly from `log_coverMincard_iterate_le`. + -- Otherwise, we bound the LHS by the smallest multiple of `m` larger than `n`, which gives the + -- error term `log (coverMincard T F U m) / n`. + rcases F.eq_empty_or_nonempty with rfl | F_nemp + · rw [coverMincard_empty, ENat.toENNReal_zero, log_zero, + bot_div_of_pos_ne_top (Nat.cast_pos'.2 n_pos) (natCast_ne_top n)] + exact bot_le + 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) + (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 (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`, 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`, 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 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 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 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 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 [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 coverEntropyInfEntourage_empty {T : X → X} {U : Set (X × X)} : + coverEntropyInfEntourage T ∅ U = ⊥ := + eq_bot_mono (coverEntropyInfEntourage_le_coverEntropyEntourage T ∅ U) coverEntropyEntourage_empty + +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 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 coverEntropyEntourage_univ (T : X → X) {F : Set X} (h : F.Nonempty) : + coverEntropyEntourage T F univ = 0 := by + simp [coverEntropyEntourage, 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 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) : + 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, + coverMincard_eq_zero_iff T F U n] at logm_bot + simp [logm_bot] + rcases eq_or_ne (log (coverMincard T F U n)) ⊤ with logm_top | logm_fin + · rw [logm_top, top_div_of_pos_ne_top (Nat.cast_pos'.2 n_pos) (natCast_ne_top n)] + exact le_top + -- The general case follows from `log_coverMincard_le_add`, with careful manipulation of limits. + let u := fun _ : ℕ ↦ log (coverMincard T F U n) / n + let v := fun m : ℕ ↦ log (coverMincard T F U n) / m + let w := fun m : ℕ ↦ log (coverMincard T F (U ○ U) m) / m + have key : w ≤ᶠ[atTop] u + v := + eventually_atTop.2 ⟨1, fun m m_pos ↦ log_coverMincard_le_add F_inv U_symm n_pos m_pos⟩ + apply ((limsup_le_limsup) key).trans + suffices h : atTop.limsup v = 0 by + 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 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.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 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 ↦ coverEntropyEntourage_le_log_coverMincard_div F_inv U_symm m_pos⟩) + +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) : + 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 (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 + 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, coverEntropyEntourage T F U + +/-- 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, coverEntropyInfEntourage T F U + +lemma coverEntropyInf_antitone (T : X → X) (F : Set X) : + Antitone fun (u : UniformSpace X) ↦ @coverEntropyInf X u T F := + fun _ _ h ↦ iSup₂_mono' fun U U_uni ↦ ⟨U, (le_def.1 h) U U_uni, le_refl _⟩ + +lemma coverEntropy_antitone (T : X → X) (F : Set X) : + Antitone fun (u : UniformSpace X) ↦ @coverEntropy X u T F := + fun _ _ h ↦ iSup₂_mono' fun U U_uni ↦ ⟨U, (le_def.1 h) U U_uni, le_refl _⟩ + +variable [UniformSpace X] + +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 coverEntropyInfEntourage_le_coverEntropyInf (T : X → X) (F : Set X) {U : Set (X × X)} + (h : U ∈ 𝓤 X) : + 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), 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 (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), 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 (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) ↦ + coverEntropyInfEntourage_le_coverEntropyEntourage T F U + +@[simp] +lemma coverEntropy_empty {T : X → X} : coverEntropy T ∅ = ⊥ := by + simp only [coverEntropy, coverEntropyEntourage_empty, iSup_bot] + +@[simp] +lemma coverEntropyInf_empty {T : X → X} : coverEntropyInf T ∅ = ⊥ := by + simp only [coverEntropyInf, coverEntropyInfEntourage_empty, iSup_bot] + +lemma coverEntropyInf_nonneg (T : X → X) {F : Set X} (h : F.Nonempty) : + 0 ≤ coverEntropyInf T F := + (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 := + (coverEntropyInf_nonneg T h).trans (coverEntropyInf_le_coverEntropy T F) + +lemma coverEntropyInf_eq_coverEntropy (T : X → X) {F : Set X} (h : MapsTo T F 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 (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 bb6ec619c92ea..c83073349810a 100644 --- a/Mathlib/FieldTheory/Adjoin.lean +++ b/Mathlib/FieldTheory/Adjoin.lean @@ -4,10 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Thomas Browning, Patrick Lutz -/ import Mathlib.Algebra.Algebra.Subalgebra.Directed -import Mathlib.FieldTheory.IntermediateField +import Mathlib.FieldTheory.IntermediateField.Algebraic import Mathlib.FieldTheory.Separable import Mathlib.FieldTheory.SplittingField.IsSplittingField import Mathlib.RingTheory.TensorProduct.Basic +import Mathlib.LinearAlgebra.Dimension.FreeAndStrongRankCondition /-! # Adjoining Elements to Fields @@ -27,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 @@ -251,6 +252,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 @@ -356,12 +365,12 @@ theorem adjoin_adjoin_left (T : Set E) : apply Set.eq_of_subset_of_subset <;> 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: orginal proof times out +-- Porting note: original proof times out · rintro x ⟨f, rfl⟩ refine Subfield.subset_closure ?_ left exact ⟨f, rfl⟩ --- Porting note: orginal proof times out +-- Porting note: original proof times out · refine Set.union_subset (fun x hx => Subfield.subset_closure ?_) (fun x hx => Subfield.subset_closure ?_) · left @@ -863,7 +872,7 @@ theorem adjoin_natCast (n : ℕ) : F⟮(n : E)⟯ = ⊥ := section AdjoinRank -open FiniteDimensional Module +open Module Module variable {K L : IntermediateField F E} @@ -997,6 +1006,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 @@ -1029,7 +1043,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 @@ -1069,6 +1083,8 @@ theorem adjoin_minpoly_coeff_of_exists_primitive_element ((g.monic_toSubring _ _).mpr <| (minpoly.monic <| .of_finite K α).map _).ne_zero using 1 rw [natDegree_toSubring, natDegree_map] +instance : Module.Finite F (⊥ : IntermediateField F E) := Subalgebra.finite_bot + variable {F} in /-- If `E / F` is an infinite algebraic extension, then there exists an intermediate field `L / F` with arbitrarily large finite extension degree. -/ @@ -1098,6 +1114,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} @@ -1153,7 +1177,7 @@ 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) @@ -1201,7 +1225,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 diff --git a/Mathlib/FieldTheory/Cardinality.lean b/Mathlib/FieldTheory/Cardinality.lean index 498e3b8d326c7..045db9322dcbf 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 @@ -75,5 +75,5 @@ theorem Field.nonempty_iff {α : Type u} : Nonempty (Field α) ↔ IsPrimePow # 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/ChevalleyWarning.lean b/Mathlib/FieldTheory/ChevalleyWarning.lean index 7102e3a92e24b..134f4e650952c 100644 --- a/Mathlib/FieldTheory/ChevalleyWarning.lean +++ b/Mathlib/FieldTheory/ChevalleyWarning.lean @@ -105,11 +105,9 @@ theorem char_dvd_card_solutions_of_sum_lt {s : Finset ι} {f : ι → MvPolynomi (h : (∑ i ∈ s, (f i).totalDegree) < Fintype.card σ) : p ∣ Fintype.card { x : σ → K // ∀ i ∈ s, eval x (f i) = 0 } := by have hq : 0 < q - 1 := by rw [← Fintype.card_units, Fintype.card_pos_iff]; exact ⟨1⟩ - let S : Finset (σ → K) := { x ∈ univ | ∀ i ∈ s, eval x (f i) = 0 }.toFinset - have hS : ∀ x : σ → K, x ∈ S ↔ ∀ i : ι, i ∈ s → eval x (f i) = 0 := by - intro x - simp only [S, Set.toFinset_setOf, mem_univ, true_and, mem_filter] - /- The polynomial `F = ∏ i ∈ s, (1 - (f i)^(q - 1))` has the nice property + let S : Finset (σ → K) := {x | ∀ i ∈ s, eval x (f i) = 0} + have hS (x : σ → K) : x ∈ S ↔ ∀ i ∈ s, eval x (f i) = 0 := by simp [S] + /- The polynomial `F = ∏ i in s, (1 - (f i)^(q - 1))` has the nice property that it takes the value `1` on elements of `{x : σ → K // ∀ i ∈ s, (f i).eval x = 0}` while it is `0` outside that locus. Hence the sum of its values is equal to the cardinality of 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/Extension.lean b/Mathlib/FieldTheory/Extension.lean index 4fca6eb496228..abfd3dbf451d7 100644 --- a/Mathlib/FieldTheory/Extension.lean +++ b/Mathlib/FieldTheory/Extension.lean @@ -144,7 +144,7 @@ end variable (hK : ∀ s ∈ S, IsIntegral F s ∧ (minpoly F s).Splits (algebraMap F K)) (hK' : ∀ s : E, IsIntegral F s ∧ (minpoly F s).Splits (algebraMap F K)) - {L : IntermediateField F E} (f : L →ₐ[F] K) (hL : L ≤ adjoin F S) {x : E} {y : K} + {L : IntermediateField F E} (f : L →ₐ[F] K) (hL : L ≤ adjoin F S) {x : E} {y : K} section include hK diff --git a/Mathlib/FieldTheory/Finite/Basic.lean b/Mathlib/FieldTheory/Finite/Basic.lean index dad50e120b86c..715387ba0669b 100644 --- a/Mathlib/FieldTheory/Finite/Basic.lean +++ b/Mathlib/FieldTheory/Finite/Basic.lean @@ -145,9 +145,8 @@ theorem sum_subgroup_units_eq_zero [Ring K] [NoZeroDivisors K] have h_sum_map := Finset.univ.sum_map a_mul_emb fun x => ((x : Kˣ) : K) -- ... and the former is the sum of x over G. -- By algebraic manipulation, we have Σ G, x = ∑ G, a x = a ∑ G, x - simp only [a_mul_emb, h_unchanged, Function.Embedding.coeFn_mk, Function.Embedding.toFun_eq_coe, - mulLeftEmbedding_apply, Submonoid.coe_mul, Subgroup.coe_toSubmonoid, Units.val_mul, - ← Finset.mul_sum] at h_sum_map + simp only [h_unchanged, mulLeftEmbedding_apply, Subgroup.coe_mul, Units.val_mul, ← mul_sum, + a_mul_emb] at h_sum_map -- thus one of (a - 1) or ∑ G, x is zero have hzero : (((a : Kˣ) : K) - 1) = 0 ∨ ∑ x : ↥G, ((x : Kˣ) : K) = 0 := by rw [← mul_eq_zero, sub_mul, ← h_sum_map, one_mul, sub_self] @@ -163,8 +162,9 @@ theorem sum_subgroup_units [Ring K] [NoZeroDivisors K] ∑ x : G, (x.val : K) = if G = ⊥ then 1 else 0 := by by_cases G_bot : G = ⊥ · subst G_bot - simp only [ite_true, Subgroup.mem_bot, Fintype.card_ofSubsingleton, Nat.cast_ite, Nat.cast_one, - Nat.cast_zero, univ_unique, Set.default_coe_singleton, sum_singleton, Units.val_one] + simp only [univ_unique, sum_singleton, ↓reduceIte, Units.val_eq_one, OneMemClass.coe_eq_one] + rw [Set.default_coe_singleton] + rfl · simp only [G_bot, ite_false] exact sum_subgroup_units_eq_zero G_bot @@ -184,7 +184,7 @@ theorem sum_subgroup_pow_eq_zero [CommRing K] [NoZeroDivisors K] (fun x : ↥G => (((x : Kˣ) : K) * ((a : Kˣ) : K)) ^ k) = (fun x : ↥G => ((x : Kˣ) : K) ^ k) ∘ fun x : ↥G => x * a := by funext x - simp only [Function.comp_apply, Submonoid.coe_mul, Subgroup.coe_toSubmonoid, Units.val_mul] + simp only [Function.comp_apply, Subgroup.coe_mul, Units.val_mul] rw [as_comp, ← Multiset.map_map] congr rw [eq_comm] @@ -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 @@ -455,9 +455,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 c2262e4cf2be6..89b627d0328c8 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,11 +88,11 @@ 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 - -- Porting note: in the statment of `key`, replaced `g_poly` by its value otherwise the + -- Porting note: in the statement of `key`, replaced `g_poly` by its value otherwise the -- proof fails have key : Fintype.card (g_poly.rootSet (GaloisField p n)) = g_poly.natDegree := card_rootSet_eq_natDegree (galois_poly_separable p _ (dvd_pow (dvd_refl p) h)) @@ -139,7 +139,7 @@ theorem finrank {n} (h : n ≠ 0) : FiniteDimensional.finrank (ZMod p) (GaloisFi 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 @@ -189,7 +189,7 @@ namespace FiniteField variable {K : Type*} [Field K] [Fintype K] {K' : Type*} [Field K'] [Fintype K'] /-- Uniqueness of finite fields: - Any two finite fields of the same cardinality are (possibly non canonically) isomorphic-/ + Any two finite fields of the same cardinality are (possibly non canonically) isomorphic -/ def algEquivOfCardEq (p : ℕ) [h_prime : Fact p.Prime] [Algebra (ZMod p) K] [Algebra (ZMod p) K'] (hKK' : Fintype.card K = Fintype.card K') : K ≃ₐ[ZMod p] K' := by have : CharP K p := by rw [← Algebra.charP_iff (ZMod p) K p]; exact ZMod.charP p @@ -203,7 +203,7 @@ def algEquivOfCardEq (p : ℕ) [h_prime : Fact p.Prime] [Algebra (ZMod p) K] [Al exact AlgEquiv.trans hGalK hK'Gal /-- Uniqueness of finite fields: - Any two finite fields of the same cardinality are (possibly non canonically) isomorphic-/ + Any two finite fields of the same cardinality are (possibly non canonically) isomorphic -/ def ringEquivOfCardEq (hKK' : Fintype.card K = Fintype.card K') : K ≃+* K' := by choose p _char_p_K using CharP.exists K choose p' _char_p'_K' using CharP.exists K' diff --git a/Mathlib/FieldTheory/Finite/Polynomial.lean b/Mathlib/FieldTheory/Finite/Polynomial.lean index 8207de7d06c14..00e92545eba5b 100644 --- a/Mathlib/FieldTheory/Finite/Polynomial.lean +++ b/Mathlib/FieldTheory/Finite/Polynomial.lean @@ -215,8 +215,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 +228,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 11e8c66077f0c..4b86ac581b736 100644 --- a/Mathlib/FieldTheory/Fixed.lean +++ b/Mathlib/FieldTheory/Fixed.lean @@ -8,7 +8,7 @@ import Mathlib.Algebra.Ring.Action.Field import Mathlib.Algebra.Ring.Action.Invariant import Mathlib.FieldTheory.Normal import Mathlib.FieldTheory.Separable -import Mathlib.FieldTheory.Tower +import Mathlib.LinearAlgebra.FreeModule.Finite.Matrix /-! # Fixed field under a group action. @@ -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 @@ -118,8 +118,8 @@ theorem linearIndependent_smul_of_linearIndependent {s : Finset F} : rw [coe_insert] at hs ⊢ rw [linearIndependent_insert (mt mem_coe.1 has)] at hs rw [linearIndependent_insert' (mt mem_coe.1 has)]; refine ⟨ih hs.1, fun ha => ?_⟩ - rw [Finsupp.mem_span_image_iff_total] at ha; rcases ha with ⟨l, hl, hla⟩ - rw [Finsupp.total_apply_of_mem_supported F hl] at hla + rw [Finsupp.mem_span_image_iff_linearCombination] at ha; rcases ha with ⟨l, hl, hla⟩ + rw [Finsupp.linearCombination_apply_of_mem_supported F hl] at hla suffices ∀ i ∈ s, l i ∈ FixedPoints.subfield G F by replace hla := (sum_apply _ _ fun i => l i • toFun G F i).symm.trans (congr_fun hla 1) simp_rw [Pi.smul_apply, toFun_apply, one_smul] at hla @@ -166,7 +166,8 @@ def minpoly : Polynomial (FixedPoints.subfield G F) := namespace minpoly theorem monic : (minpoly G F x).Monic := by - simp only [minpoly, Polynomial.monic_toSubring] + simp only [minpoly] + rw [Polynomial.monic_toSubring] exact prodXSubSMul.monic G F x theorem eval₂ : @@ -192,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 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 97c0878478581..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 @@ -380,32 +380,23 @@ theorem of_separable_splitting_field [sp : p.IsSplittingField F E] (hp : p.Separ rw [IntermediateField.adjoin_zero] intro K x hx hK simp only [P] at * - -- Porting note: need to specify two implicit arguments of `finrank_mul_finrank` - letI := K⟮x⟯.module - letI := K⟮x⟯.isScalarTower (R := F) rw [of_separable_splitting_field_aux hp K (Multiset.mem_toFinset.mp hx), hK, finrank_mul_finrank] symm refine LinearEquiv.finrank_eq ?_ rfl -/-- Equivalent characterizations of a Galois extension of finite degree-/ +/-- Equivalent characterizations of a Galois extension of finite degree -/ theorem tfae [FiniteDimensional F E] : List.TFAE [ IsGalois F E, 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/IntermediateField/Algebraic.lean b/Mathlib/FieldTheory/IntermediateField/Algebraic.lean new file mode 100644 index 0000000000000..55ecc96148306 --- /dev/null +++ b/Mathlib/FieldTheory/IntermediateField/Algebraic.lean @@ -0,0 +1,116 @@ +/- +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.FieldTheory.IntermediateField.Basic +import Mathlib.RingTheory.Algebraic +import Mathlib.FieldTheory.Tower +import Mathlib.FieldTheory.Minpoly.Basic +import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition + +/-! +# Results on finite dimensionality and algebraicity of intermediate fields. +-/ + +open Module + +variable {K : Type*} {L : Type*} [Field K] [Field L] [Algebra K L] + {S : IntermediateField K L} + +namespace IntermediateField + +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 + +@[simp] +theorem rank_eq_rank_subalgebra : Module.rank K F.toSubalgebra = Module.rank K F := + rfl + +@[simp] +theorem finrank_eq_finrank_subalgebra : finrank K F.toSubalgebra = finrank K F := + rfl + +variable {F} {E} + +@[simp] +theorem toSubalgebra_eq_iff : F.toSubalgebra = E.toSubalgebra ↔ F = E := by + rw [SetLike.ext_iff, SetLike.ext'_iff, Set.ext_iff] + rfl + +/-- If `F ≤ E` are two intermediate fields of `L / K` such that `[E : K] ≤ [F : K]` are finite, +then `F = E`. -/ +theorem eq_of_le_of_finrank_le [hfin : FiniteDimensional K E] (h_le : F ≤ E) + (h_finrank : finrank K E ≤ finrank K F) : F = E := + haveI : Module.Finite K E.toSubalgebra := hfin + toSubalgebra_injective <| Subalgebra.eq_of_le_of_finrank_le h_le h_finrank + +/-- If `F ≤ E` are two intermediate fields of `L / K` such that `[F : K] = [E : K]` are finite, +then `F = E`. -/ +theorem eq_of_le_of_finrank_eq [FiniteDimensional K E] (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 + +-- If `F ≤ E` are two intermediate fields of a finite extension `L / K` such that +-- `[L : F] ≤ [L : E]`, then `F = E`. Marked as private since it's a direct corollary of +-- `eq_of_le_of_finrank_le'` (the `FiniteDimensional K L` implies `FiniteDimensional F L` +-- automatically by typeclass resolution). +private theorem eq_of_le_of_finrank_le'' [FiniteDimensional K L] (h_le : F ≤ E) + (h_finrank : finrank F L ≤ finrank E L) : F = E := by + apply eq_of_le_of_finrank_le h_le + have h1 := finrank_mul_finrank K F L + have h2 := finrank_mul_finrank K E L + have h3 : 0 < finrank E L := finrank_pos + nlinarith + +/-- If `F ≤ E` are two intermediate fields of `L / K` such that `[L : F] ≤ [L : E]` are finite, +then `F = E`. -/ +theorem eq_of_le_of_finrank_le' [FiniteDimensional F L] (h_le : F ≤ E) + (h_finrank : finrank F L ≤ finrank E L) : F = E := by + refine le_antisymm h_le (fun l hl ↦ ?_) + rwa [← mem_extendScalars (le_refl F), eq_of_le_of_finrank_le'' + ((extendScalars_le_extendScalars_iff (le_refl F) h_le).2 h_le) h_finrank, mem_extendScalars] + +/-- If `F ≤ E` are two intermediate fields of `L / K` such that `[L : F] = [L : E]` are finite, +then `F = E`. -/ +theorem eq_of_le_of_finrank_eq' [FiniteDimensional F L] (h_le : F ≤ E) + (h_finrank : finrank F L = finrank E L) : F = E := + eq_of_le_of_finrank_le' h_le h_finrank.le + +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 minpoly_eq (x : S) : minpoly K x = minpoly K (x : L) := + (minpoly.algebraMap_eq (algebraMap S L).injective x).symm + +end IntermediateField + +/-- If `L/K` is algebraic, the `K`-subalgebras of `L` are all fields. -/ +def subalgebraEquivIntermediateField [Algebra.IsAlgebraic K L] : + Subalgebra K L ≃o IntermediateField K L where + toFun S := S.toIntermediateField fun x hx => S.inv_mem_of_algebraic + (Algebra.IsAlgebraic.isAlgebraic ((⟨x, hx⟩ : S) : L)) + invFun S := S.toSubalgebra + left_inv _ := toSubalgebra_toIntermediateField _ _ + right_inv := toIntermediateField_toSubalgebra + map_rel_iff' := Iff.rfl + +@[simp] +theorem mem_subalgebraEquivIntermediateField [Algebra.IsAlgebraic K L] {S : Subalgebra K L} + {x : L} : x ∈ subalgebraEquivIntermediateField S ↔ x ∈ S := + Iff.rfl + +@[simp] +theorem mem_subalgebraEquivIntermediateField_symm [Algebra.IsAlgebraic K L] + {S : IntermediateField K L} {x : L} : + x ∈ subalgebraEquivIntermediateField.symm S ↔ x ∈ S := + Iff.rfl diff --git a/Mathlib/FieldTheory/IntermediateField.lean b/Mathlib/FieldTheory/IntermediateField/Basic.lean similarity index 85% rename from Mathlib/FieldTheory/IntermediateField.lean rename to Mathlib/FieldTheory/IntermediateField/Basic.lean index 1f54cb6acfb38..27a9fb8cd57cd 100644 --- a/Mathlib/FieldTheory/IntermediateField.lean +++ b/Mathlib/FieldTheory/IntermediateField/Basic.lean @@ -3,9 +3,10 @@ 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.FieldTheory.Tower -import Mathlib.RingTheory.Algebraic -import Mathlib.FieldTheory.Minpoly.Basic +import Mathlib.Algebra.Field.Subfield +import Mathlib.Algebra.Polynomial.AlgebraMap +import Mathlib.RingTheory.LocalRing.Basic +import Mathlib.RingTheory.IntegralClosure.IsIntegral.Defs /-! # Intermediate fields @@ -36,7 +37,7 @@ intermediate field, field extension -/ -open FiniteDimensional Polynomial +open Polynomial open Polynomial @@ -306,29 +307,31 @@ theorem coe_prod {ι : Type*} [Fintype ι] (f : ι → S) : (↑(∏ i, f i) : L /-! `IntermediateField`s inherit structure from their `Subalgebra` coercions. -/ +instance toAlgebra : Algebra S L := + inferInstanceAs (Algebra S.toSubalgebra L) instance module' {R} [Semiring R] [SMul R K] [Module R L] [IsScalarTower R K L] : Module R S := - S.toSubalgebra.module' + inferInstanceAs (Module R S.toSubalgebra) -instance module : Module K S := - inferInstanceAs (Module K S.toSubsemiring) +instance algebra' {R' K L : Type*} [Field K] [Field L] [Algebra K L] (S : IntermediateField K L) + [CommSemiring R'] [SMul R' K] [Algebra R' L] [IsScalarTower R' K L] : Algebra R' S := + inferInstanceAs (Algebra R' S.toSubalgebra) instance isScalarTower {R} [Semiring R] [SMul R K] [Module R L] [IsScalarTower R K L] : IsScalarTower R K S := - inferInstanceAs (IsScalarTower R K S.toSubsemiring) + inferInstanceAs (IsScalarTower R K S.toSubalgebra) @[simp] theorem coe_smul {R} [Semiring R] [SMul R K] [Module R L] [IsScalarTower R K L] (r : R) (x : S) : ↑(r • x : S) = (r • (x : L)) := rfl -instance algebra : Algebra K S := - inferInstanceAs (Algebra K S.toSubsemiring) - @[simp] lemma algebraMap_apply (x : S) : algebraMap S L x = x := rfl @[simp] lemma coe_algebraMap_apply (x : K) : ↑(algebraMap K S x) = algebraMap K L x := rfl +instance {R : Type*} [Semiring R] [Algebra L R] : SMul S R := S.instSMulSubtypeMem + instance isScalarTower_bot {R : Type*} [Semiring R] [Algebra L R] : IsScalarTower S L R := IsScalarTower.subalgebra _ _ _ S.toSubalgebra @@ -340,6 +343,8 @@ instance isScalarTower_mid {R : Type*} [Semiring R] [Algebra L R] [Algebra K R] instance isScalarTower_mid' : IsScalarTower K S L := S.isScalarTower_mid +instance {E} [Semiring E] [Algebra L E] : Algebra S E := inferInstanceAs (Algebra S.toSubalgebra E) + section shortcut_instances variable {E} [Field E] [Algebra L E] (T : IntermediateField S E) {S} instance : Algebra S T := T.algebra @@ -752,100 +757,4 @@ end Restrict end Tower -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 - -@[simp] -theorem rank_eq_rank_subalgebra : Module.rank K F.toSubalgebra = Module.rank K F := - rfl - -@[simp] -theorem finrank_eq_finrank_subalgebra : finrank K F.toSubalgebra = finrank K F := - rfl - -variable {F} {E} - -@[simp] -theorem toSubalgebra_eq_iff : F.toSubalgebra = E.toSubalgebra ↔ F = E := by - rw [SetLike.ext_iff, SetLike.ext'_iff, Set.ext_iff] - rfl - -/-- If `F ≤ E` are two intermediate fields of `L / K` such that `[E : K] ≤ [F : K]` are finite, -then `F = E`. -/ -theorem eq_of_le_of_finrank_le [hfin : FiniteDimensional K E] (h_le : F ≤ E) - (h_finrank : finrank K E ≤ finrank K F) : F = E := - haveI : Module.Finite K E.toSubalgebra := hfin - toSubalgebra_injective <| Subalgebra.eq_of_le_of_finrank_le h_le h_finrank - -/-- If `F ≤ E` are two intermediate fields of `L / K` such that `[F : K] = [E : K]` are finite, -then `F = E`. -/ -theorem eq_of_le_of_finrank_eq [FiniteDimensional K E] (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 - --- If `F ≤ E` are two intermediate fields of a finite extension `L / K` such that --- `[L : F] ≤ [L : E]`, then `F = E`. Marked as private since it's a direct corollary of --- `eq_of_le_of_finrank_le'` (the `FiniteDimensional K L` implies `FiniteDimensional F L` --- automatically by typeclass resolution). -private theorem eq_of_le_of_finrank_le'' [FiniteDimensional K L] (h_le : F ≤ E) - (h_finrank : finrank F L ≤ finrank E L) : F = E := by - apply eq_of_le_of_finrank_le h_le - have h1 := finrank_mul_finrank K F L - have h2 := finrank_mul_finrank K E L - have h3 : 0 < finrank E L := finrank_pos - nlinarith - -/-- If `F ≤ E` are two intermediate fields of `L / K` such that `[L : F] ≤ [L : E]` are finite, -then `F = E`. -/ -theorem eq_of_le_of_finrank_le' [FiniteDimensional F L] (h_le : F ≤ E) - (h_finrank : finrank F L ≤ finrank E L) : F = E := by - refine le_antisymm h_le (fun l hl ↦ ?_) - rwa [← mem_extendScalars (le_refl F), eq_of_le_of_finrank_le'' - ((extendScalars_le_extendScalars_iff (le_refl F) h_le).2 h_le) h_finrank, mem_extendScalars] - -/-- If `F ≤ E` are two intermediate fields of `L / K` such that `[L : F] = [L : E]` are finite, -then `F = E`. -/ -theorem eq_of_le_of_finrank_eq' [FiniteDimensional F L] (h_le : F ≤ E) - (h_finrank : finrank F L = finrank E L) : F = E := - eq_of_le_of_finrank_le' h_le h_finrank.le - -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 minpoly_eq (x : S) : minpoly K x = minpoly K (x : L) := - (minpoly.algebraMap_eq (algebraMap S L).injective x).symm - end IntermediateField - -/-- If `L/K` is algebraic, the `K`-subalgebras of `L` are all fields. -/ -def subalgebraEquivIntermediateField [Algebra.IsAlgebraic K L] : - Subalgebra K L ≃o IntermediateField K L where - toFun S := S.toIntermediateField fun x hx => S.inv_mem_of_algebraic - (Algebra.IsAlgebraic.isAlgebraic ((⟨x, hx⟩ : S) : L)) - invFun S := S.toSubalgebra - left_inv _ := toSubalgebra_toIntermediateField _ _ - right_inv := toIntermediateField_toSubalgebra - map_rel_iff' := Iff.rfl - -@[simp] -theorem mem_subalgebraEquivIntermediateField [Algebra.IsAlgebraic K L] {S : Subalgebra K L} - {x : L} : x ∈ subalgebraEquivIntermediateField S ↔ x ∈ S := - Iff.rfl - -@[simp] -theorem mem_subalgebraEquivIntermediateField_symm [Algebra.IsAlgebraic K L] - {S : IntermediateField K L} {x : L} : - x ∈ subalgebraEquivIntermediateField.symm S ↔ x ∈ S := - Iff.rfl diff --git a/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean b/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean index 662deae08d25c..787429c5e3827 100644 --- a/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean +++ b/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean @@ -73,13 +73,13 @@ theorem toSplittingField_evalXSelf {s : Finset (MonicIrreducible k)} {f} (hf : f theorem spanEval_ne_top : spanEval k ≠ ⊤ := by rw [Ideal.ne_top_iff_one, spanEval, Ideal.span, ← Set.image_univ, - Finsupp.mem_span_image_iff_total] + Finsupp.mem_span_image_iff_linearCombination] rintro ⟨v, _, hv⟩ replace hv := congr_arg (toSplittingField k v.support) hv - rw [map_one, Finsupp.total_apply, Finsupp.sum, map_sum, Finset.sum_eq_zero] at hv + 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` -/ @@ -250,8 +250,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 := @@ -379,7 +378,7 @@ instance instGroupWithZero : GroupWithZero (AlgebraicClosure k) := let e := algEquivAlgebraicClosureAux k { inv := fun a ↦ e.symm (e a)⁻¹ inv_zero := by simp - mul_inv_cancel := fun a ha ↦ e.injective $ by simp [(AddEquivClass.map_ne_zero_iff _).2 ha] + mul_inv_cancel := fun a ha ↦ e.injective <| by simp [(AddEquivClass.map_ne_zero_iff _).2 ha] __ := e.surjective.nontrivial } instance instField : Field (AlgebraicClosure k) where @@ -392,9 +391,9 @@ instance instField : Field (AlgebraicClosure k) where nnratCast_def q := by change algebraMap k _ _ = _; simp_rw [NNRat.cast_def, map_div₀, map_natCast] ratCast_def q := by change algebraMap k _ _ = _; rw [Rat.cast_def, map_div₀, map_intCast, map_natCast] - nnqsmul_def q x := Quotient.inductionOn x fun p ↦ congr_arg Quotient.mk'' $ by + nnqsmul_def q x := Quotient.inductionOn x fun p ↦ congr_arg Quotient.mk'' <| by ext; simp [MvPolynomial.algebraMap_eq, NNRat.smul_def] - qsmul_def q x := Quotient.inductionOn x fun p ↦ congr_arg Quotient.mk'' $ by + qsmul_def q x := Quotient.inductionOn x fun p ↦ congr_arg Quotient.mk'' <| by ext; simp [MvPolynomial.algebraMap_eq, Rat.smul_def] instance isAlgClosed : IsAlgClosed (AlgebraicClosure k) := diff --git a/Mathlib/FieldTheory/IsAlgClosed/Classification.lean b/Mathlib/FieldTheory/IsAlgClosed/Classification.lean index 1a9f0ce2972f9..e0fb0cd9df594 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 `ℵ₀` -/ diff --git a/Mathlib/FieldTheory/IsPerfectClosure.lean b/Mathlib/FieldTheory/IsPerfectClosure.lean index 70d3708472eb5..743199124c340 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 diff --git a/Mathlib/FieldTheory/IsSepClosed.lean b/Mathlib/FieldTheory/IsSepClosed.lean index a986c4144c374..1a11e8d38dff7 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 diff --git a/Mathlib/FieldTheory/KrullTopology.lean b/Mathlib/FieldTheory/KrullTopology.lean index 18d9b02736673..7f7f53c3109a7 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 diff --git a/Mathlib/FieldTheory/KummerExtension.lean b/Mathlib/FieldTheory/KummerExtension.lean index c36f3f23e6e98..671a4b1bb374a 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 /-! @@ -63,7 +63,7 @@ lemma root_X_pow_sub_C_ne_zero {n : ℕ} (hn : 1 < n) (a : K) : lemma root_X_pow_sub_C_ne_zero' {n : ℕ} {a : K} (hn : 0 < n) (ha : a ≠ 0) : (AdjoinRoot.root (X ^ n - C a)) ≠ 0 := by obtain (rfl|hn) := (Nat.succ_le_iff.mpr hn).eq_or_lt - · rw [← Nat.one_eq_succ_zero, pow_one] + · rw [pow_one] intro e refine mk_ne_zero_of_natDegree_lt (monic_X_sub_C a) (C_ne_zero.mpr ha) (by simp) ?_ trans AdjoinRoot.mk (X - C a) (X - (X - C a)) @@ -197,7 +197,7 @@ theorem X_pow_sub_C_irreducible_of_odd {n : ℕ} (hn : Odd n) {a : K} (ha : ∀ p : ℕ, p.Prime → p ∣ n → ∀ b : K, b ^ p ≠ a) : Irreducible (X ^ n - C a) := by induction n using induction_on_primes generalizing K a with - | h₀ => simp at hn + | h₀ => simp [← Nat.not_even_iff_odd] at hn | h₁ => simpa using irreducible_X_sub_C a | h p n hp IH => rw [mul_comm] @@ -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')) _) @@ -412,8 +417,8 @@ variable {α : L} (hα : α ^ n = algebraMap K L a) /-- Suppose `L/K` is the splitting field of `Xⁿ - a`, then a choice of `ⁿ√a` gives an equivalence of `L` with `K[n√a]`. -/ noncomputable -def adjoinRootXPowSubCEquiv : - K[n√a] ≃ₐ[K] L := +def adjoinRootXPowSubCEquiv (hζ : (primitiveRoots n K).Nonempty) (H : Irreducible (X ^ n - C a)) + (hα : α ^ n = algebraMap K L a) : K[n√a] ≃ₐ[K] L := AlgEquiv.ofBijective (AdjoinRoot.liftHom (X ^ n - C a) α (by simp [hα])) <| by haveI := Fact.mk H letI := isSplittingField_AdjoinRoot_X_pow_sub_C hζ H @@ -450,7 +455,8 @@ variable (a) (L) /-- An arbitrary choice of `ⁿ√a` in the splitting field of `Xⁿ - a`. -/ noncomputable -abbrev rootOfSplitsXPowSubC : L := +abbrev rootOfSplitsXPowSubC (hn : 0 < n) (a : K) + (L) [Field L] [Algebra K L] [IsSplittingField K L (X ^ n - C a)] : L := (rootOfSplits _ (IsSplittingField.splits L (X ^ n - C a)) (by simpa [degree_X_pow_sub_C hn] using Nat.pos_iff_ne_zero.mp hn)) @@ -529,7 +535,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) @@ -544,9 +550,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 @@ -622,7 +628,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 @@ -630,21 +636,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..ee4583757d618 100644 --- a/Mathlib/FieldTheory/Minpoly/Basic.lean +++ b/Mathlib/FieldTheory/Minpoly/Basic.lean @@ -60,8 +60,8 @@ theorem eq_zero (hx : ¬IsIntegral A x) : minpoly A x = 0 := 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..b129b8a0ecbc5 100644 --- a/Mathlib/FieldTheory/Minpoly/Field.lean +++ b/Mathlib/FieldTheory/Minpoly/Field.lean @@ -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 @@ -158,7 +183,7 @@ variable (F E K : Type*) [Field F] [Ring E] [CommRing K] [IsDomain K] [Algebra F -- 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 +194,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/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 317ae7f335968..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) @@ -164,8 +164,8 @@ lemma span_coeff_minpolyDiv : Submodule.span_le] simp only [Finset.coe_image, Finset.coe_range, Set.image_subset_iff] intro i - apply Nat.strongInductionOn i - intro i hi hi' + induction i using Nat.strongRecOn with | ind i hi => ?_ + intro hi' have : coeff (minpolyDiv R x) (natDegree (minpolyDiv R x) - i) ∈ Submodule.span R (Set.range (coeff (minpolyDiv R x))) := Submodule.subset_span (Set.mem_range_self _) diff --git a/Mathlib/FieldTheory/Normal.lean b/Mathlib/FieldTheory/Normal.lean index 0b609f7d4d2a1..98ae051a5fd57 100644 --- a/Mathlib/FieldTheory/Normal.lean +++ b/Mathlib/FieldTheory/Normal.lean @@ -174,6 +174,26 @@ instance normal_sup Normal F (E ⊔ E' : IntermediateField F K) := iSup_bool_eq (f := Bool.rec E' E) ▸ normal_iSup (h := by rintro (_|_) <;> infer_instance) +/-- An intersection of normal extensions is normal -/ +instance normal_iInf {ι : Type*} [hι : Nonempty ι] + (t : ι → IntermediateField F K) [h : ∀ i, Normal F (t i)] : + Normal F (⨅ i, t i : IntermediateField F K) := by + refine { toIsAlgebraic := ?_, splits' := fun x => ?_ } + · let f := inclusion (iInf_le t hι.some) + exact Algebra.IsAlgebraic.of_injective f f.injective + · have hx : ∀ i, Splits (algebraMap F (t i)) (minpoly F x) := by + intro i + rw [← minpoly.algHom_eq (inclusion (iInf_le t i)) (inclusion (iInf_le t i)).injective] + exact (h i).splits' (inclusion (iInf_le t i) x) + simp only [splits_iff_mem (splits_of_isScalarTower K (hx hι.some))] at hx ⊢ + rintro y hy - ⟨-, ⟨i, rfl⟩, rfl⟩ + exact hx i y hy + +instance normal_inf + (E E' : IntermediateField F K) [Normal F E] [Normal F E'] : + Normal F (E ⊓ E' : IntermediateField F K) := + iInf_bool_eq (f := Bool.rec E' E) ▸ normal_iInf (h := by rintro (_|_) <;> infer_instance) + variable {F K} variable {L : Type*} [Field L] [Algebra F L] [Algebra K L] [IsScalarTower F K L] diff --git a/Mathlib/FieldTheory/NormalClosure.lean b/Mathlib/FieldTheory/NormalClosure.lean index a1d7bf881f7dd..680dc94bf8709 100644 --- a/Mathlib/FieldTheory/NormalClosure.lean +++ b/Mathlib/FieldTheory/NormalClosure.lean @@ -6,6 +6,7 @@ Authors: Thomas Browning import Mathlib.FieldTheory.Normal import Mathlib.Order.Closure +import Mathlib.LinearAlgebra.FreeModule.Finite.Matrix /-! # Normal closures @@ -98,8 +99,8 @@ lemma isNormalClosure_normalClosure : IsNormalClosure F K (normalClosure F K L) SetLike.coe_subset_coe.mpr <| by apply le_iSup _ x) simp_rw [normalClosure, ← top_le_iff] refine fun x _ ↦ (IntermediateField.val _).injective.mem_set_image.mp ?_ - change x.val ∈ IntermediateField.map (IntermediateField.val _) _ - rw [IntermediateField.map_iSup] + rw [AlgHom.toRingHom_eq_coe, RingHom.coe_coe, coe_val, ← IntermediateField.coe_val, + ← IntermediateField.coe_map, IntermediateField.map_iSup] refine (iSup_le fun f ↦ ?_ : normalClosure F K L ≤ _) x.2 refine le_iSup_of_le (f.codRestrict _ fun x ↦ f.fieldRange_le_normalClosure ⟨x, rfl⟩) ?_ rw [AlgHom.map_fieldRange, val, AlgHom.val_comp_codRestrict] @@ -173,7 +174,7 @@ variable [Algebra K L] [IsScalarTower F K L] noncomputable instance algebra : Algebra K (normalClosure F K L) := - IntermediateField.algebra + IntermediateField.algebra' { ⨆ f : K →ₐ[F] L, f.fieldRange with algebraMap_mem' := fun r ↦ (toAlgHom F K L).fieldRange_le_normalClosure ⟨r, rfl⟩ } diff --git a/Mathlib/FieldTheory/Perfect.lean b/Mathlib/FieldTheory/Perfect.lean index f0725115ada01..6e4aecef5c66e 100644 --- a/Mathlib/FieldTheory/Perfect.lean +++ b/Mathlib/FieldTheory/Perfect.lean @@ -376,7 +376,7 @@ variable [PerfectRing R p] a bijection from the set of roots of `Polynomial.expand R p f` to the set of roots of `f`. It's given by `x ↦ x ^ p`, see `rootsExpandEquivRoots_apply`. -/ noncomputable def rootsExpandEquivRoots : (expand R p f).roots.toFinset ≃ f.roots.toFinset := - ((frobeniusEquiv R p).image _).trans <| .Set.ofEq <| show _ '' (setOf _) = setOf _ by + ((frobeniusEquiv R p).image _).trans <| .Set.ofEq <| show _ '' setOf (· ∈ _) = setOf (· ∈ _) by classical simp_rw [← roots_expand_image_frobenius (p := p) (f := f), Finset.mem_val, Finset.setOf_mem, Finset.coe_image, RingEquiv.toEquiv_eq_coe, EquivLike.coe_coe, frobeniusEquiv_apply] @@ -389,7 +389,8 @@ a bijection from the set of roots of `Polynomial.expand R (p ^ n) f` to the set It's given by `x ↦ x ^ (p ^ n)`, see `rootsExpandPowEquivRoots_apply`. -/ noncomputable def rootsExpandPowEquivRoots (n : ℕ) : (expand R (p ^ n) f).roots.toFinset ≃ f.roots.toFinset := - ((iterateFrobeniusEquiv R p n).image _).trans <| .Set.ofEq <| show _ '' (setOf _) = setOf _ by + ((iterateFrobeniusEquiv R p n).image _).trans <| + .Set.ofEq <| show _ '' (setOf (· ∈ _)) = setOf (· ∈ _) by classical simp_rw [← roots_expand_image_iterateFrobenius (p := p) (f := f) (n := n), Finset.mem_val, Finset.setOf_mem, Finset.coe_image, RingEquiv.toEquiv_eq_coe, EquivLike.coe_coe, iterateFrobeniusEquiv_apply] diff --git a/Mathlib/FieldTheory/PerfectClosure.lean b/Mathlib/FieldTheory/PerfectClosure.lean index 8572b59904f89..50b237cb61ab0 100644 --- a/Mathlib/FieldTheory/PerfectClosure.lean +++ b/Mathlib/FieldTheory/PerfectClosure.lean @@ -92,7 +92,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 @@ -224,12 +223,17 @@ instance instZero : Zero (PerfectClosure K p) := theorem zero_def : (0 : PerfectClosure K p) = mk K p (0, 0) := rfl +/-- Prior to #15862, this lemma was called `mk_zero_zero`. +See `mk_zero_right` for the lemma used to be called `mk_zero`. -/ @[simp] -theorem mk_zero_zero : mk K p (0, 0) = 0 := +theorem mk_zero : mk K p 0 = 0 := rfl +@[deprecated (since := "2024-08-16")] alias mk_zero_zero := mk_zero + -- Porting note: improved proof structure -theorem mk_zero (n : ℕ) : mk K p (n, 0) = 0 := by +@[simp] +theorem mk_zero_right (n : ℕ) : mk K p (n, 0) = 0 := by induction' n with n ih · rfl rw [← ih] @@ -243,7 +247,7 @@ theorem R.sound (m n : ℕ) (x y : K) (H : (frobenius K p)^[m] x = y) : mk K p (n, x) = mk K p (m + n, y) := by subst H induction' m with m ih - · simp only [Nat.zero_eq, zero_add, iterate_zero_apply] + · simp only [zero_add, iterate_zero_apply] rw [ih, Nat.succ_add, iterate_succ'] apply Quot.sound apply R.intro @@ -270,7 +274,7 @@ instance instAddCommGroup : AddCommGroup (PerfectClosure K p) := sub_eq_add_neg := fun a b => 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] + simp only [quot_mk_eq_mk, neg_mk, mk_add_mk, iterate_map_neg, neg_add_cancel, mk_zero_right] add_comm := fun e f => Quot.inductionOn e fun ⟨m, x⟩ => Quot.inductionOn f fun ⟨n, y⟩ => congr_arg (Quot.mk _) <| by simp only [add_comm] @@ -284,11 +288,11 @@ instance instCommRing : CommRing (PerfectClosure K p) := zero_mul := fun a => by refine Quot.inductionOn a fun ⟨m, x⟩ => ?_ rw [zero_def, quot_mk_eq_mk, mk_mul_mk] - simp only [zero_add, iterate_zero, id_eq, iterate_map_zero, zero_mul, mk_zero] + simp only [zero_add, iterate_zero, id_eq, iterate_map_zero, zero_mul, mk_zero_right] mul_zero := fun a => by refine Quot.inductionOn a fun ⟨m, x⟩ => ?_ rw [zero_def, quot_mk_eq_mk, mk_mul_mk] - simp only [zero_add, iterate_zero, id_eq, iterate_map_zero, mul_zero, mk_zero] + simp only [zero_add, iterate_zero, id_eq, iterate_map_zero, mul_zero, mk_zero_right] left_distrib := fun e f g => Quot.inductionOn e fun ⟨m, x⟩ => Quot.inductionOn f fun ⟨n, y⟩ => @@ -312,7 +316,7 @@ theorem mk_eq_iff (x y : ℕ × K) : mk K p x = mk K p y ↔ ∃ z, (frobenius K p)^[y.1 + z] x.2 = (frobenius K p)^[x.1 + z] y.2 := by constructor · intro H - replace H := Quot.exact _ H + replace H := Quot.eqvGen_exact H induction H with | rel x y H => cases' H with n x; exact ⟨0, rfl⟩ | refl H => exact ⟨0, rfl⟩ @@ -491,7 +495,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 qsmul := _ + qsmul_def := fun q a => 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 3c936d1dc75f4..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 @@ -253,7 +253,7 @@ theorem restrictDvd_surjective (hpq : p ∣ q) (hq : q ≠ 0) : variable (p q) -/-- The Galois group of a product maps into the product of the Galois groups. -/ +/-- The Galois group of a product maps into the product of the Galois groups. -/ def restrictProd : (p * q).Gal →* p.Gal × q.Gal := MonoidHom.prod (restrictDvd (dvd_mul_right p q)) (restrictDvd (dvd_mul_left q p)) @@ -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..da215b5d8dbf4 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 := FiniteDimensional.finite_of_finite F E 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 a2d8f90ef45d9..93c3226de53d7 100644 --- a/Mathlib/FieldTheory/PurelyInseparable.lean +++ b/Mathlib/FieldTheory/PurelyInseparable.lean @@ -127,19 +127,22 @@ separable degree, degree, separable closure, purely inseparable -/ -open FiniteDimensional Polynomial IntermediateField Field +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 +153,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 +166,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 +182,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 +199,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 +237,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 +256,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 @@ -282,7 +303,7 @@ theorem mem_perfectClosure_iff_pow_mem (q : ℕ) [ExpChar F q] {x : E} : x ∈ perfectClosure F E ↔ ∃ n : ℕ, x ^ q ^ n ∈ (algebraMap F E).range := by rw [mem_perfectClosure_iff, ringExpChar.eq F q] -/-- An element is contained in the relative perfect closure if and only if its mininal polynomial +/-- An element is contained in the relative perfect closure if and only if its minimal polynomial has separable degree one. -/ theorem mem_perfectClosure_iff_natSepDegree_eq_one {x : E} : x ∈ perfectClosure F E ↔ (minpoly F x).natSepDegree = 1 := by @@ -583,7 +604,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 @@ -629,7 +650,7 @@ namespace IntermediateField instance isPurelyInseparable_bot : IsPurelyInseparable F (⊥ : IntermediateField F E) := (botEquiv F E).symm.isPurelyInseparable -/-- `F⟮x⟯ / F` is a purely inseparable extension if and only if the mininal polynomial of `x` +/-- `F⟮x⟯ / F` is a purely inseparable extension if and only if the minimal polynomial of `x` has separable degree one. -/ theorem isPurelyInseparable_adjoin_simple_iff_natSepDegree_eq_one {x : E} : IsPurelyInseparable F F⟮x⟯ ↔ (minpoly F x).natSepDegree = 1 := by @@ -735,13 +756,14 @@ 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 let f (i : ι) : ι' := ⟨v i, h'.subset_extend _ ⟨i, rfl⟩⟩ convert H.comp f fun _ _ heq ↦ h.injective (by simpa only [f, Subtype.mk.injEq] using heq) - simp_rw [Function.comp_apply, b, Basis.extend_apply_self] + simp_rw [Function.comp_apply, b] + rw [Basis.extend_apply_self] /-- If `E / F` is a separable extension of exponential characteristic `q`, if `{ u_i }` is a family of elements of `E` which is `F`-linearly independent, then `{ u_i ^ (q ^ n) }` is also @@ -920,8 +942,8 @@ theorem LinearIndependent.map_of_isPurelyInseparable_of_isSeparable [IsPurelyIns rw [hlF, Finsupp.not_mem_support_iff.1 hs, zero_pow this] replace h := linearIndependent_iff.1 (h.map_pow_expChar_pow_of_isIntegral' q n hsep) lF₀ <| by replace hl := congr($hl ^ q ^ n) - rw [Finsupp.total_apply, Finsupp.sum, sum_pow_char_pow, zero_pow this] at hl - rw [← hl, Finsupp.total_apply, Finsupp.onFinset_sum _ (fun _ ↦ by exact zero_smul _ _)] + rw [linearCombination_apply, Finsupp.sum, sum_pow_char_pow, zero_pow this] at hl + rw [← hl, linearCombination_apply, onFinset_sum _ (fun _ ↦ by exact zero_smul _ _)] refine Finset.sum_congr rfl fun i _ ↦ ?_ simp_rw [Algebra.smul_def, mul_pow, IsScalarTower.algebraMap_apply F E K, hlF, map_pow] refine pow_eq_zero ((hlF _).symm.trans ?_) @@ -1049,7 +1071,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 323ae1661d472..66d5c87abee7c 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]) @@ -522,7 +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 qsmul := _ + qsmul_def := fun q a => rfl section IsFractionRing @@ -636,16 +638,8 @@ theorem algebraMap_injective : Function.Injective (algebraMap K[X] (RatFunc K)) rw [← ofFractionRing_comp_algebraMap] exact ofFractionRing_injective.comp (IsFractionRing.injective _ _) -@[simp] -theorem algebraMap_eq_zero_iff {x : K[X]} : algebraMap K[X] (RatFunc K) x = 0 ↔ x = 0 := - ⟨(injective_iff_map_eq_zero _).mp (algebraMap_injective K) _, fun hx => by - rw [hx, RingHom.map_zero]⟩ - variable {K} -theorem algebraMap_ne_zero {x : K[X]} (hx : x ≠ 0) : algebraMap K[X] (RatFunc K) x ≠ 0 := - mt (algebraMap_eq_zero_iff K).mp hx - section LiftAlgHom variable {L R S : Type*} [Field L] [CommRing R] [IsDomain R] [CommSemiring S] [Algebra S K[X]] @@ -710,8 +704,15 @@ instance : IsFractionRing K[X] (RatFunc K) where simp only [← ofFractionRing_algebraMap, Function.comp_apply, ← ofFractionRing_mul] rw [ofFractionRing.injEq] -- Porting note: added +@[deprecated "Use NoZeroSMulDivisors.algebraMap_eq_zero_iff instead." (since := "2024-09-08")] +theorem algebraMap_eq_zero_iff {x : K[X]} : algebraMap K[X] (RatFunc K) x = 0 ↔ x = 0 := by + simp + variable {K} +theorem algebraMap_ne_zero {x : K[X]} (hx : x ≠ 0) : algebraMap K[X] (RatFunc K) x ≠ 0 := by + simpa + @[simp] 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') diff --git a/Mathlib/FieldTheory/RatFunc/Defs.lean b/Mathlib/FieldTheory/RatFunc/Defs.lean index b1ffa6109ae6d..b45d1838b3eb7 100644 --- a/Mathlib/FieldTheory/RatFunc/Defs.lean +++ b/Mathlib/FieldTheory/RatFunc/Defs.lean @@ -63,7 +63,7 @@ the maps between `RatFunc K` and another field of fractions of `K[X]`, especially `FractionRing K[X]`, are given by `IsLocalization.algEquiv`. -/ structure RatFunc [CommRing K] : Type u where ofFractionRing :: -/-- the coercion to the fraction ring of the polynomial ring-/ +/-- the coercion to the fraction ring of the polynomial ring -/ toFractionRing : FractionRing K[X] namespace RatFunc diff --git a/Mathlib/FieldTheory/Separable.lean b/Mathlib/FieldTheory/Separable.lean index fddc5fbc1dcee..11f14b5edd03f 100644 --- a/Mathlib/FieldTheory/Separable.lean +++ b/Mathlib/FieldTheory/Separable.lean @@ -22,7 +22,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`. -/ @@ -337,8 +337,7 @@ theorem separable_or {f : F[X]} (hf : Irreducible f) : 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 @@ -503,7 +502,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 +513,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 +546,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,72 +558,132 @@ 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] [CommRing 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 + + +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 -lemma Algebra.IsSeparable.of_equiv_equiv {A₁ B₁ A₂ B₂ : Type*} [Field A₁] [Field B₁] +end Field + +section AlgEquiv + +variable {A₁ B₁ A₂ B₂ : Type*} [Field A₁] [Field B₁] [Field A₂] [Field B₂] [Algebra A₁ B₁] [Algebra A₂ B₂] (e₁ : A₁ ≃+* A₂) (e₂ : B₁ ≃+* B₂) (he : RingHom.comp (algebraMap A₂ B₂) ↑e₁ = RingHom.comp ↑e₂ (algebraMap A₁ B₁)) - [Algebra.IsSeparable A₁ B₁] : Algebra.IsSeparable A₂ B₂ := by +include e₁ e₂ 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 @@ -628,10 +692,15 @@ lemma Algebra.IsSeparable.of_equiv_equiv {A₁ B₁ A₂ B₂ : Type*} [Field A { 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 + have := IsSeparable.tower_top A₂ h + IsSeparable.of_algHom e.symm ((e₂.symm_apply_apply x).symm ▸ this) + +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..fb1ec8ab2843c 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 @@ -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 E[X] X (C x) (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⟩ + 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 0a11bdfa13be0..fb0572b56c8b9 100644 --- a/Mathlib/FieldTheory/SplittingField/Construction.lean +++ b/Mathlib/FieldTheory/SplittingField/Construction.lean @@ -245,7 +245,7 @@ instance instGroupWithZero : GroupWithZero (SplittingField f) := let e := algEquivSplittingFieldAux f { inv := fun a ↦ e.symm (e a)⁻¹ inv_zero := by simp - mul_inv_cancel := fun a ha ↦ e.injective $ by simp [(AddEquivClass.map_ne_zero_iff _).2 ha] + mul_inv_cancel := fun a ha ↦ e.injective <| by simp [(AddEquivClass.map_ne_zero_iff _).2 ha] __ := e.surjective.nontrivial } instance instField : Field (SplittingField f) where @@ -258,9 +258,9 @@ instance instField : Field (SplittingField f) where nnratCast_def q := by change algebraMap K _ _ = _; simp_rw [NNRat.cast_def, map_div₀, map_natCast] ratCast_def q := by change algebraMap K _ _ = _; rw [Rat.cast_def, map_div₀, map_intCast, map_natCast] - nnqsmul_def q x := Quotient.inductionOn x fun p ↦ congr_arg Quotient.mk'' $ by + nnqsmul_def q x := Quotient.inductionOn x fun p ↦ congr_arg Quotient.mk'' <| by ext; simp [MvPolynomial.algebraMap_eq, NNRat.smul_def] - qsmul_def q x := Quotient.inductionOn x fun p ↦ congr_arg Quotient.mk'' $ by + qsmul_def q x := Quotient.inductionOn x fun p ↦ congr_arg Quotient.mk'' <| by ext; simp [MvPolynomial.algebraMap_eq, Rat.smul_def] instance instCharZero [CharZero K] : CharZero (SplittingField f) := diff --git a/Mathlib/FieldTheory/SplittingField/IsSplittingField.lean b/Mathlib/FieldTheory/SplittingField/IsSplittingField.lean index 4ca9cadac0e55..79a96d25426a0 100644 --- a/Mathlib/FieldTheory/SplittingField/IsSplittingField.lean +++ b/Mathlib/FieldTheory/SplittingField/IsSplittingField.lean @@ -3,8 +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.FieldTheory.IntermediateField import Mathlib.RingTheory.Adjoin.Field +import Mathlib.FieldTheory.IntermediateField.Basic /-! # Splitting fields @@ -150,6 +150,13 @@ theorem IntermediateField.splits_of_splits (h : p.Splits (algebraMap K L)) simp_rw [← F.fieldRange_val, rootSet_def, Finset.mem_coe, Multiset.mem_toFinset] at hF exact splits_of_comp _ F.val.toRingHom h hF +theorem IntermediateField.splits_iff_mem (h : p.Splits (algebraMap K L)) : + p.Splits (algebraMap K F) ↔ ∀ x ∈ p.rootSet L, x ∈ F := by + refine ⟨?_, IntermediateField.splits_of_splits h⟩ + intro hF + rw [← Polynomial.image_rootSet hF F.val, Set.forall_mem_image] + exact fun x _ ↦ x.2 + theorem IsIntegral.mem_intermediateField_of_minpoly_splits {x : L} (int : IsIntegral K x) {F : IntermediateField K L} (h : Splits (algebraMap K F) (minpoly K x)) : x ∈ F := by rw [← F.fieldRange_val]; exact int.mem_range_algebraMap_of_minpoly_splits h diff --git a/Mathlib/FieldTheory/Tower.lean b/Mathlib/FieldTheory/Tower.lean index 160ecd9442513..297650824b8be 100644 --- a/Mathlib/FieldTheory/Tower.lean +++ b/Mathlib/FieldTheory/Tower.lean @@ -3,27 +3,19 @@ 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.Data.Nat.Prime.Defs import Mathlib.RingTheory.AlgebraTower -import Mathlib.LinearAlgebra.FiniteDimensional.Defs -import Mathlib.LinearAlgebra.FreeModule.Finite.Matrix -import Mathlib.RingTheory.LocalRing.Basic +import Mathlib.RingTheory.Noetherian /-! -# Tower of field extensions +# Finiteness of `IsScalarTower` -In this file we prove the tower law for arbitrary extensions and finite extensions. -Suppose `L` is a field extension of `K` and `K` is a field extension of `F`. -Then `[L:F] = [L:K] [K:F]` where `[E₁:E₂]` means the `E₂`-dimension of `E₁`. +We prove that given `IsScalarTower F K A`, if `A` is finite as a module over `F` then +`A` is finite over `K`, and +(as long as `A` is Noetherian over `F` and we have `NoZeroSMulDivisors K A`) `K` is finite over `F`. -In fact we generalize it to rings and modules, where `L` is not necessarily a field, -but just a free module over `K`. +In particular these conditions hold when `A`, `F`, and `K` are fields. -## Implementation notes - -We prove two versions, since there are two notions of dimensions: `Module.rank` which gives -the dimension of an arbitrary vector space as a cardinal, and `FiniteDimensional.finrank` which -gives the dimension of a finite-dimensional vector space as a natural number. +The formulas for the dimensions are given elsewhere by `Module.finrank_mul_finrank`. ## Tags @@ -38,49 +30,31 @@ open Cardinal Submodule variable (F : Type u) (K : Type v) (A : Type w) -section Field - -variable [DivisionRing F] [DivisionRing K] [AddCommGroup A] -variable [Module F K] [Module K A] [Module F A] [IsScalarTower F K A] - -namespace FiniteDimensional - -open IsNoetherian +namespace Module.Finite +variable [Ring F] [Ring K] [Module F K] + [AddCommGroup A] [Module K A] [NoZeroSMulDivisors K A] + [Module F A] [IsNoetherian F A] [IsScalarTower F K A] in /-- In a tower of field extensions `A / K / F`, if `A / F` is finite, so is `K / F`. (In fact, it suffices that `A` is a nontrivial ring.) Note this cannot be an instance as Lean cannot infer `A`. -/ -theorem left [Nontrivial A] [FiniteDimensional F A] : FiniteDimensional F K := +theorem left [Nontrivial A] : Module.Finite F K := let ⟨x, hx⟩ := exists_ne (0 : A) - FiniteDimensional.of_injective + Module.Finite.of_injective (LinearMap.ringLmapEquivSelf K ℕ A |>.symm x |>.restrictScalars F) (smul_left_injective K hx) -theorem right [hf : FiniteDimensional F A] : FiniteDimensional K A := +variable [Semiring F] [Semiring K] [Module F K] + [AddCommMonoid A] [Module K A] [Module F A] [IsScalarTower F K A] in +theorem right [hf : Module.Finite F A] : Module.Finite K A := let ⟨⟨b, hb⟩⟩ := hf ⟨⟨b, Submodule.restrictScalars_injective F _ _ <| by rw [Submodule.restrictScalars_top, eq_top_iff, ← hb, Submodule.span_le] exact Submodule.subset_span⟩⟩ -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) := - { toNontrivial := - ⟨⟨⊥, ⊤, fun he => - Nat.not_prime_one ((Subalgebra.bot_eq_top_iff_finrank_eq_one.1 he).subst hp)⟩⟩ - eq_bot_or_eq_top := fun K => by - haveI : FiniteDimensional _ _ := .of_finrank_pos hp.pos - letI := divisionRingOfFiniteDimensional F K - refine (hp.eq_one_or_self_of_dvd _ ⟨_, (finrank_mul_finrank F K A).symm⟩).imp ?_ fun h => ?_ - · exact fun h' => Subalgebra.eq_bot_of_finrank_one h' - · exact - Algebra.toSubmodule_eq_top.1 (eq_top_of_finrank_eq <| K.finrank_toSubmodule.trans h) } --- TODO: `IntermediateField` version - -@[deprecated (since := "2024-01-12")] -alias finrank_linear_map' := FiniteDimensional.finrank_linearMap_self - -end FiniteDimensional - -end Field +end Module.Finite + +alias FiniteDimensional.left := Module.Finite.left +alias FiniteDimensional.right := Module.Finite.right diff --git a/Mathlib/Geometry/Euclidean/Angle/Oriented/Affine.lean b/Mathlib/Geometry/Euclidean/Angle/Oriented/Affine.lean index 1a4c7dfdf186b..6e6e991b9b0b4 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 @@ -622,7 +622,7 @@ theorem _root_.Collinear.oangle_sign_of_sameRay_vsub {p₁ p₂ p₃ p₄ : P} ( 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 ?_ ?_ 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 _ _)) diff --git a/Mathlib/Geometry/Euclidean/Angle/Oriented/Basic.lean b/Mathlib/Geometry/Euclidean/Angle/Oriented/Basic.lean index eb15d01c7e2d7..3f2938cdce408 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 @@ -758,7 +758,7 @@ 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 occurences of the bound variable `i` are of type + -- 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]` 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 1bdfc60311837..b58876fe73b9d 100644 --- a/Mathlib/Geometry/Euclidean/Angle/Unoriented/Affine.lean +++ b/Mathlib/Geometry/Euclidean/Angle/Unoriented/Affine.lean @@ -134,7 +134,7 @@ nonrec theorem angle_le_pi (p1 p2 p3 : P) : ∠ p1 p2 p3 ≤ π := @[simp] lemma angle_self_right (p₀ p : P) : ∠ p p₀ p₀ = π / 2 := by rw [angle_comm, angle_self_left] /-- The angle ∠ABA at a point is `0`, unless `A = B`. -/ -theorem angle_self_of_ne (h : p ≠ p₀) : ∠ p p₀ p = 0 := angle_self $ vsub_ne_zero.2 h +theorem angle_self_of_ne (h : p ≠ p₀) : ∠ p p₀ p = 0 := angle_self <| vsub_ne_zero.2 h @[deprecated (since := "2024-02-14")] alias angle_eq_left := angle_self_left @[deprecated (since := "2024-02-14")] alias angle_eq_right := angle_self_right @@ -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 61e9e1a2ede92..b9807b923e2cb 100644 --- a/Mathlib/Geometry/Euclidean/Basic.lean +++ b/Mathlib/Geometry/Euclidean/Basic.lean @@ -44,11 +44,8 @@ theorems that need it. -/ - noncomputable section -open scoped Classical - open RealInnerProductSpace namespace EuclideanGeometry @@ -116,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] @@ -127,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 @@ -153,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 @@ -164,6 +162,7 @@ theorem eq_of_dist_eq_of_dist_eq_of_mem_of_finrank_eq_two {s : AffineSubspace intro v hv have hr : Set.range b = {c₂ -ᵥ c₁, p₂ -ᵥ p₁} := by have hu : (Finset.univ : Finset (Fin 2)) = {0, 1} := by decide + classical rw [← Fintype.coe_image_univ, hu] simp [b] rw [← hbs, hr, Submodule.mem_span_insert] at hv @@ -173,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₁] diff --git a/Mathlib/Geometry/Euclidean/Circumcenter.lean b/Mathlib/Geometry/Euclidean/Circumcenter.lean index 9961e0140f7fa..ab715d6d83899 100644 --- a/Mathlib/Geometry/Euclidean/Circumcenter.lean +++ b/Mathlib/Geometry/Euclidean/Circumcenter.lean @@ -27,11 +27,8 @@ the circumcenter. -/ - noncomputable section -open scoped Classical - open RealInnerProductSpace namespace EuclideanGeometry @@ -205,6 +202,7 @@ theorem _root_.AffineIndependent.existsUnique_dist_eq {ι : Type*} [hne : Nonemp rw [hi default, hdist] · have i := hne.some let ι2 := { x // x ≠ i } + classical have hc : Fintype.card ι2 = m + 1 := by rw [Fintype.card_of_subtype (Finset.univ.filter fun x => x ≠ i)] · rw [Finset.filter_not] @@ -318,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. -/ @@ -429,7 +427,7 @@ theorem dist_circumcenter_sq_eq_sq_sub_circumradius {n : ℕ} {r : ℝ} (s : Sim /-- If there exists a distance that a point has from all vertices of a simplex, the orthogonal projection of that point onto the subspace -spanned by that simplex is its circumcenter. -/ +spanned by that simplex is its circumcenter. -/ theorem orthogonalProjection_eq_circumcenter_of_exists_dist_eq {n : ℕ} (s : Simplex ℝ P n) {p : P} (hr : ∃ r, ∀ i, dist (s.points i) p = r) : ↑(s.orthogonalProjectionSpan p) = s.circumcenter := by @@ -447,7 +445,7 @@ theorem orthogonalProjection_eq_circumcenter_of_exists_dist_eq {n : ℕ} (s : Si /-- If a point has the same distance from all vertices of a simplex, the orthogonal projection of that point onto the subspace spanned by -that simplex is its circumcenter. -/ +that simplex is its circumcenter. -/ theorem orthogonalProjection_eq_circumcenter_of_dist_eq {n : ℕ} (s : Simplex ℝ P n) {p : P} {r : ℝ} (hr : ∀ i, dist (s.points i) p = r) : ↑(s.orthogonalProjectionSpan p) = s.circumcenter := s.orthogonalProjection_eq_circumcenter_of_exists_dist_eq ⟨r, hr⟩ @@ -498,6 +496,7 @@ def pointIndexEmbedding (n : ℕ) : Fin (n + 1) ↪ PointsWithCircumcenterIndex theorem sum_pointsWithCircumcenter {α : Type*} [AddCommMonoid α] {n : ℕ} (f : PointsWithCircumcenterIndex n → α) : ∑ i, f i = (∑ i : Fin (n + 1), f (pointIndex i)) + f circumcenterIndex := by + classical have h : univ = insert circumcenterIndex (univ.map (pointIndexEmbedding n)) := by ext x refine ⟨fun h => ?_, fun _ => mem_univ _⟩ @@ -539,6 +538,7 @@ def pointWeightsWithCircumcenter {n : ℕ} (i : Fin (n + 1)) : PointsWithCircumc @[simp] theorem sum_pointWeightsWithCircumcenter {n : ℕ} (i : Fin (n + 1)) : ∑ j, pointWeightsWithCircumcenter i j = 1 := by + classical convert sum_ite_eq' univ (pointIndex i) (Function.const _ (1 : ℝ)) with j · cases j <;> simp [pointWeightsWithCircumcenter] · simp @@ -599,6 +599,7 @@ def circumcenterWeightsWithCircumcenter (n : ℕ) : PointsWithCircumcenterIndex @[simp] theorem sum_circumcenterWeightsWithCircumcenter (n : ℕ) : ∑ i, circumcenterWeightsWithCircumcenter n i = 1 := by + classical convert sum_ite_eq' univ circumcenterIndex (Function.const _ (1 : ℝ)) with j · cases j <;> simp [circumcenterWeightsWithCircumcenter] · simp @@ -666,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] @@ -865,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/MongePoint.lean b/Mathlib/Geometry/Euclidean/MongePoint.lean index 95434096a7f94..fbf488bef44b3 100644 --- a/Mathlib/Geometry/Euclidean/MongePoint.lean +++ b/Mathlib/Geometry/Euclidean/MongePoint.lean @@ -46,11 +46,8 @@ generalization, the Monge point of a simplex. -/ - noncomputable section -open scoped Classical - open scoped RealInnerProductSpace namespace Affine @@ -347,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)) : @@ -364,6 +361,7 @@ theorem finrank_direction_altitude {n : ℕ} (s : Simplex ℝ P (n + 1)) (i : Fi (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 refine add_left_cancel (_root_.trans h ?_) + classical rw [s.independent.finrank_vectorSpan (Fintype.card_fin _), ← Finset.coe_image, s.independent.finrank_vectorSpan_image_finset hc] @@ -394,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] @@ -406,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] @@ -550,7 +548,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!` @@ -604,7 +603,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] @@ -652,6 +651,7 @@ theorem exists_of_range_subset_orthocentricSystem {t : Triangle ℝ P} · right have hs := Set.subset_diff_singleton hps h rw [Set.insert_diff_self_of_not_mem ho] at hs + classical refine Set.eq_of_subset_of_card_le hs ?_ rw [Set.card_range_of_injective hpi, Set.card_range_of_injective t.independent.injective] @@ -707,7 +707,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/Sphere/Basic.lean b/Mathlib/Geometry/Euclidean/Sphere/Basic.lean index 0b37ec458a9f3..6c5067aad4c23 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. -/ @@ -57,7 +57,7 @@ instance : Coe (Sphere P) (Set P) := ⟨fun s => Metric.sphere s.center s.radius⟩ instance : Membership P (Sphere P) := - ⟨fun p s => p ∈ (s : Set P)⟩ + ⟨fun s p => p ∈ (s : Set P)⟩ theorem Sphere.mk_center (c : P) (r : ℝ) : (⟨c, r⟩ : Sphere P).center = c := rfl diff --git a/Mathlib/Geometry/Euclidean/Triangle.lean b/Mathlib/Geometry/Euclidean/Triangle.lean index c76fa197f9315..9e2ab6a89582d 100644 --- a/Mathlib/Geometry/Euclidean/Triangle.lean +++ b/Mathlib/Geometry/Euclidean/Triangle.lean @@ -33,16 +33,9 @@ unnecessarily. -/ - noncomputable section -open scoped CharZero - -open scoped Classical - -open scoped Real - -open scoped RealInnerProductSpace +open scoped CharZero Real RealInnerProductSpace namespace InnerProductGeometry @@ -250,9 +243,7 @@ This section develops some geometrical definitions and results on (possibly degenerate) triangles in Euclidean affine spaces. -/ - open InnerProductGeometry - open scoped EuclideanGeometry variable {V : Type*} {P : Type*} [NormedAddCommGroup V] [InnerProductSpace ℝ V] [MetricSpace P] @@ -304,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 b624c050ba3ce..5e70b3f083574 100644 --- a/Mathlib/Geometry/Manifold/Algebra/LeftInvariantDerivation.lean +++ b/Mathlib/Geometry/Manifold/Algebra/LeftInvariantDerivation.lean @@ -207,7 +207,7 @@ theorem evalAt_mul : evalAt (g * h) X = 𝒅ₕ (L_apply I g h) (evalAt h X) := ext f rw [← left_invariant, apply_hfdifferential, apply_hfdifferential, L_mul, fdifferential_comp, apply_fdifferential] - -- Porting note: more agressive here + -- Porting note: more aggressive here erw [LinearMap.comp_apply] -- This used to be `rw`, but we need `erw` after leanprover/lean4#2644 erw [apply_fdifferential, ← apply_hfdifferential, left_invariant] diff --git a/Mathlib/Geometry/Manifold/Algebra/LieGroup.lean b/Mathlib/Geometry/Manifold/Algebra/LieGroup.lean index 47d6a6e3e4f01..8bec2b7fa5b4f 100644 --- a/Mathlib/Geometry/Manifold/Algebra/LieGroup.lean +++ b/Mathlib/Geometry/Manifold/Algebra/LieGroup.lean @@ -41,7 +41,7 @@ groups here are not necessarily finite dimensional. A priori, a Lie group here is a manifold with corners. The definition of Lie group cannot require `I : ModelWithCorners 𝕜 E E` with the same space as the -model space and as the model vector space, as one might hope, beause in the product situation, +model space and as the model vector space, as one might hope, because in the product situation, the model space is `ModelProd E E'` and the model vector space is `E × E'`, which are not the same, so the definition does not apply. Hence the definition should be more general, allowing `I : ModelWithCorners 𝕜 E H`. diff --git a/Mathlib/Geometry/Manifold/Algebra/SmoothFunctions.lean b/Mathlib/Geometry/Manifold/Algebra/SmoothFunctions.lean index 594cfdfdde353..067e86f792acd 100644 --- a/Mathlib/Geometry/Manifold/Algebra/SmoothFunctions.lean +++ b/Mathlib/Geometry/Manifold/Algebra/SmoothFunctions.lean @@ -159,7 +159,7 @@ end GroupStructure section RingStructure /-! -### Ring stucture +### Ring structure In this section we show that smooth functions valued in a smooth ring `R` inherit a ring structure under pointwise multiplication. @@ -223,7 +223,7 @@ end RingStructure section ModuleStructure /-! -### Semimodule stucture +### Semimodule structure In this section we show that smooth functions valued in a vector space `M` over a normed field `𝕜` inherit a vector space structure. diff --git a/Mathlib/Geometry/Manifold/AnalyticManifold.lean b/Mathlib/Geometry/Manifold/AnalyticManifold.lean index 86f101cc015ef..8ef606a4540a1 100644 --- a/Mathlib/Geometry/Manifold/AnalyticManifold.lean +++ b/Mathlib/Geometry/Manifold/AnalyticManifold.lean @@ -1,10 +1,9 @@ /- Copyright (c) 2023 Michael Lee. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Michael Lee +Authors: Michael Lee, Geoffrey Irving -/ -import Mathlib.Analysis.Analytic.Composition -import Mathlib.Analysis.Analytic.Linear +import Mathlib.Analysis.Analytic.Constructions import Mathlib.Analysis.Calculus.FDeriv.Analytic import Mathlib.Geometry.Manifold.SmoothManifoldWithCorners @@ -17,8 +16,8 @@ interior and smooth everywhere (including at the boundary). The definition mirr `SmoothManifoldWithCorners`, but using an `analyticGroupoid` in place of `contDiffGroupoid`. All analytic manifolds are smooth manifolds. -For now we define only `analyticGroupoid`; an upcoming commit will add `AnalyticManifold` (see -https://github.com/leanprover-community/mathlib4/pull/10853). +Completeness is required throughout, but this is nonessential: it is due to many of the lemmas about +AnalyticOn` requiring completeness for ease of proof. -/ noncomputable section @@ -42,117 +41,53 @@ analytic on the interior, and map the interior to itself. This allows us to def section analyticGroupoid -/-- Given a model with corners `(E, H)`, we define the groupoid of analytic transformations of `H` -as the maps that are analytic and map interior to interior when read in `E` through `I`. We also -explicitly define that they are `C^∞` on the whole domain, since we are only requiring -analyticity on the interior of the domain. -/ +/-- Given a model with corners `(E, H)`, we define the pregroupoid of analytic transformations of +`H` as the maps that are `AnalyticOn` when read in `E` through `I`. Using `AnalyticOn` +rather than `AnalyticOnNhd` gives us meaningful definitions at boundary points. -/ +def analyticPregroupoid : Pregroupoid H where + 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] + apply hg.comp + · exact hf.mono fun _ ⟨hx1, hx2⟩ ↦ ⟨hx1.1, hx2⟩ + · rintro x ⟨hx1, _⟩ + simpa only [mfld_simps] using hx1.2 + id_mem := by + 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 analyticOn_of_locally_analyticOn + rintro y ⟨hy1, hy2⟩ + obtain ⟨x, hx⟩ := mem_range.1 hy2 + simp only [mfld_simps, ← hx] at hy1 ⊢ + obtain ⟨v, v_open, xv, hv⟩ := H x hy1 + have : I.symm ⁻¹' (u ∩ v) ∩ range I = I.symm ⁻¹' u ∩ range I ∩ I.symm ⁻¹' v := by + rw [preimage_inter, inter_assoc, inter_assoc, inter_comm _ (range I)] + exact ⟨I.symm ⁻¹' v, v_open.preimage I.continuous_symm, by simpa, this ▸ hv⟩ + congr {f g u} _ fg hf := by + apply hf.congr + rintro y ⟨hy1, hy2⟩ + obtain ⟨x, hx⟩ := mem_range.1 hy2 + simp only [mfld_simps, ← hx] at hy1 ⊢ + rw [fg _ hy1] + +/-- Given a model with corners `(E, H)`, we define the groupoid of analytic transformations of +`H` as the maps that are `AnalyticOn` when read in `E` through `I`. Using `AnalyticOn` +rather than `AnalyticOnNhd` gives us meaningful definitions at boundary points. -/ def analyticGroupoid : StructureGroupoid H := - (contDiffGroupoid ∞ I) ⊓ Pregroupoid.groupoid - { property := fun f s => AnalyticOn 𝕜 (I ∘ f ∘ I.symm) (I.symm ⁻¹' s ∩ interior (range I)) ∧ - (I.symm ⁻¹' s ∩ interior (range I)).image (I ∘ f ∘ I.symm) ⊆ interior (range I) - comp := fun {f g u v} hf hg _ _ _ => by - simp only [] at hf hg ⊢ - have comp : I ∘ (g ∘ f) ∘ I.symm = (I ∘ g ∘ I.symm) ∘ I ∘ f ∘ I.symm := by ext x; simp - apply And.intro - · simp only [comp, preimage_inter] - refine hg.left.comp (hf.left.mono ?_) ?_ - · simp only [subset_inter_iff, inter_subset_right] - rw [inter_assoc] - simp - · intro x hx - apply And.intro - · rw [mem_preimage, comp_apply, I.left_inv] - exact hx.left.right - · apply hf.right - rw [mem_image] - exact ⟨x, ⟨⟨hx.left.left, hx.right⟩, rfl⟩⟩ - · simp only [comp] - rw [image_comp] - intro x hx - rw [mem_image] at hx - rcases hx with ⟨x', hx'⟩ - refine hg.right ⟨x', And.intro ?_ hx'.right⟩ - apply And.intro - · have hx'1 : x' ∈ ((v.preimage f).preimage (I.symm)).image (I ∘ f ∘ I.symm) := by - refine image_subset (I ∘ f ∘ I.symm) ?_ hx'.left - rw [preimage_inter] - refine Subset.trans ?_ (u.preimage I.symm).inter_subset_right - apply inter_subset_left - rcases hx'1 with ⟨x'', hx''⟩ - rw [hx''.right.symm] - simp only [comp_apply, mem_preimage, I.left_inv] - exact hx''.left - · rw [mem_image] at hx' - rcases hx'.left with ⟨x'', hx''⟩ - exact hf.right ⟨x'', ⟨⟨hx''.left.left.left, hx''.left.right⟩, hx''.right⟩⟩ - id_mem := by - apply And.intro - · simp only [preimage_univ, univ_inter] - exact AnalyticOn.congr isOpen_interior - (f := (1 : E →L[𝕜] E)) (fun x _ => (1 : E →L[𝕜] E).analyticAt x) - (fun z hz => (I.right_inv (interior_subset hz)).symm) - · intro x hx - simp only [id_comp, comp_apply, preimage_univ, univ_inter, mem_image] at hx - rcases hx with ⟨y, hy⟩ - rw [← hy.right, I.right_inv (interior_subset hy.left)] - exact hy.left - locality := fun {f u} _ h => by - simp only [] at h - simp only [AnalyticOn] - apply And.intro - · intro x hx - rcases h (I.symm x) (mem_preimage.mp hx.left) with ⟨v, hv⟩ - exact hv.right.right.left x ⟨mem_preimage.mpr ⟨hx.left, hv.right.left⟩, hx.right⟩ - · apply mapsTo'.mp - simp only [MapsTo] - intro x hx - rcases h (I.symm x) hx.left with ⟨v, hv⟩ - apply hv.right.right.right - rw [mem_image] - have hx' := And.intro hx (mem_preimage.mpr hv.right.left) - rw [← mem_inter_iff, inter_comm, ← inter_assoc, ← preimage_inter, inter_comm v u] at hx' - exact ⟨x, ⟨hx', rfl⟩⟩ - congr := fun {f g u} hu fg hf => by - simp only [] at hf ⊢ - apply And.intro - · refine AnalyticOn.congr (IsOpen.inter (hu.preimage I.continuous_symm) isOpen_interior) - hf.left ?_ - intro z hz - simp only [comp_apply] - rw [fg (I.symm z) hz.left] - · intro x hx - apply hf.right - rw [mem_image] at hx ⊢ - rcases hx with ⟨y, hy⟩ - refine ⟨y, ⟨hy.left, ?_⟩⟩ - rw [comp_apply, comp_apply, fg (I.symm y) hy.left.left] at hy - exact hy.right } + (analyticPregroupoid I).groupoid /-- An identity partial homeomorphism belongs to the analytic groupoid. -/ theorem ofSet_mem_analyticGroupoid {s : Set H} (hs : IsOpen s) : PartialHomeomorph.ofSet s hs ∈ analyticGroupoid I := by - rw [analyticGroupoid] - refine And.intro (ofSet_mem_contDiffGroupoid ∞ I hs) ?_ - apply mem_groupoid_of_pregroupoid.mpr - suffices h : AnalyticOn 𝕜 (I ∘ I.symm) (I.symm ⁻¹' s ∩ interior (range I)) ∧ - (I.symm ⁻¹' s ∩ interior (range I)).image (I ∘ I.symm) ⊆ interior (range I) by - simp only [PartialHomeomorph.ofSet_apply, id_comp, PartialHomeomorph.ofSet_toPartialEquiv, - PartialEquiv.ofSet_source, h, comp_apply, mem_range, image_subset_iff, true_and, - PartialHomeomorph.ofSet_symm, PartialEquiv.ofSet_target, and_self] - intro x hx - refine mem_preimage.mpr ?_ - rw [← I.right_inv (interior_subset hx.right)] at hx - exact hx.right - apply And.intro - · have : AnalyticOn 𝕜 (1 : E →L[𝕜] E) (univ : Set E) := (fun x _ => (1 : E →L[𝕜] E).analyticAt x) - exact (this.mono (subset_univ (s.preimage (I.symm) ∩ interior (range I)))).congr - ((hs.preimage I.continuous_symm).inter isOpen_interior) - fun z hz => (I.right_inv (interior_subset hz.right)).symm - · intro x hx - simp only [comp_apply, mem_image] at hx - rcases hx with ⟨y, hy⟩ - rw [← hy.right, I.right_inv (interior_subset hy.left.right)] - exact hy.left.right + rw [analyticGroupoid, mem_groupoid_of_pregroupoid] + suffices h : AnalyticOn 𝕜 (I ∘ I.symm) (I.symm ⁻¹' s ∩ range I) by + simp [h, analyticPregroupoid] + 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. -/ @@ -168,25 +103,73 @@ instance : ClosedUnderRestriction (analyticGroupoid I) := (by rw [StructureGroupoid.le_iff] rintro e ⟨s, hs, hes⟩ - apply (analyticGroupoid I).mem_of_eqOnSource' _ _ _ hes - exact ofSet_mem_analyticGroupoid I hs) + exact (analyticGroupoid I).mem_of_eqOnSource' _ _ (ofSet_mem_analyticGroupoid I 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 ↔ + 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 [CompleteSpace E] [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 - apply Iff.intro - · intro he - have := mem_groupoid_of_pregroupoid.mp he.right - simp only [I.image_eq, I.range_eq_univ, interior_univ, subset_univ, and_true] at this ⊢ - exact this - · intro he - apply And.intro - all_goals apply mem_groupoid_of_pregroupoid.mpr; simp only [I.image_eq, I.range_eq_univ, - interior_univ, subset_univ, and_true, contDiffPregroupoid] at he ⊢ - · exact ⟨he.left.contDiffOn, he.right.contDiffOn⟩ - · exact he +theorem mem_analyticGroupoid_of_boundaryless [I.Boundaryless] (e : PartialHomeomorph H H) : + 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.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] + [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 ⟨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 + +section AnalyticManifold + +/-- An analytic manifold w.r.t. a model `I : ModelWithCorners 𝕜 E H` is a charted space over `H` +s.t. all extended chart conversion maps are analytic. -/ +class AnalyticManifold (I : ModelWithCorners 𝕜 E H) (M : Type*) [TopologicalSpace M] + [ChartedSpace H M] extends HasGroupoid M (analyticGroupoid I) : Prop + +/-- Normed spaces are analytic manifolds over themselves. -/ +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] + [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 + compatible := by + intro f g ⟨f1, f2, hf1, hf2, fe⟩ ⟨g1, g2, hg1, hg2, ge⟩ + rw [← fe, ← ge, PartialHomeomorph.prod_symm, PartialHomeomorph.prod_trans] + exact analyticGroupoid_prod (m.toHasGroupoid.compatible f2 g2) + (n.toHasGroupoid.compatible hf2 hg2) + +/-- Analytic manifolds are smooth manifolds. -/ +instance AnalyticManifold.smoothManifoldWithCorners [ChartedSpace H M] + [cm : AnalyticManifold I M] [CompleteSpace E] : + SmoothManifoldWithCorners I M where + compatible := by + intro f g hf hg + have m := cm.compatible hf hg + exact ⟨m.1.contDiffOn, m.2.contDiffOn⟩ + +end AnalyticManifold diff --git a/Mathlib/Geometry/Manifold/BumpFunction.lean b/Mathlib/Geometry/Manifold/BumpFunction.lean index d32ef29050ef2..16f7d52a36180 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 diff --git a/Mathlib/Geometry/Manifold/ChartedSpace.lean b/Mathlib/Geometry/Manifold/ChartedSpace.lean index c1ce4ba8838db..d62d89afae12c 100644 --- a/Mathlib/Geometry/Manifold/ChartedSpace.lean +++ b/Mathlib/Geometry/Manifold/ChartedSpace.lean @@ -176,7 +176,7 @@ structure StructureGroupoid (H : Type u) [TopologicalSpace H] where variable [TopologicalSpace H] instance : Membership (PartialHomeomorph H H) (StructureGroupoid H) := - ⟨fun (e : PartialHomeomorph H H) (G : StructureGroupoid H) ↦ e ∈ G.members⟩ + ⟨fun (G : StructureGroupoid H) (e : PartialHomeomorph H H) ↦ e ∈ G.members⟩ instance (H : Type u) [TopologicalSpace H] : SetLike (StructureGroupoid H) (PartialHomeomorph H H) where @@ -1161,15 +1161,15 @@ theorem chartAt_subtype_val_symm_eventuallyEq (U : Opens M) {x : U} : exact Filter.eventuallyEq_of_mem heUx_nhds (e.subtypeRestr_symm_eqOn ⟨x⟩) theorem chartAt_inclusion_symm_eventuallyEq {U V : Opens M} (hUV : U ≤ V) {x : U} : - (chartAt H (Set.inclusion hUV x)).symm - =ᶠ[𝓝 (chartAt H (Set.inclusion hUV x) (Set.inclusion hUV x))] - Set.inclusion hUV ∘ (chartAt H x).symm := by + (chartAt H (Opens.inclusion hUV x)).symm + =ᶠ[𝓝 (chartAt H (Opens.inclusion hUV x) (Set.inclusion hUV x))] + Opens.inclusion hUV ∘ (chartAt H x).symm := by set e := chartAt H (x : M) have heUx_nhds : (e.subtypeRestr ⟨x⟩).target ∈ 𝓝 (e x) := by apply (e.subtypeRestr ⟨x⟩).open_target.mem_nhds exact e.map_subtype_source ⟨x⟩ (mem_chart_source _ _) exact Filter.eventuallyEq_of_mem heUx_nhds <| e.subtypeRestr_symm_eqOn_of_le ⟨x⟩ - ⟨Set.inclusion hUV x⟩ hUV + ⟨Opens.inclusion hUV x⟩ hUV end TopologicalSpace.Opens /-- Restricting a chart of `M` to an open subset `s` yields a chart in the maximal atlas of `s`. @@ -1289,7 +1289,13 @@ theorem StructureGroupoid.restriction_mem_maximalAtlas_subtype rw [PartialHomeomorph.subtypeRestr_def, PartialHomeomorph.trans_refl] let goal := e.toHomeomorphSourceTarget.toPartialHomeomorph ≫ₕ (t.partialHomeomorphSubtypeCoe this) have : goal ≈ e.subtypeRestr (s := s) hs := - (goal.eqOnSource_iff (e.subtypeRestr (s := s) hs)).mpr ⟨by simp [s, goal], by intro _ _; rfl⟩ + (goal.eqOnSource_iff (e.subtypeRestr (s := s) hs)).mpr + ⟨by + simp only [trans_toPartialEquiv, PartialEquiv.trans_source, + Homeomorph.toPartialHomeomorph_source, toFun_eq_coe, Homeomorph.toPartialHomeomorph_apply, + Opens.partialHomeomorphSubtypeCoe_source, preimage_univ, inter_self, subtypeRestr_source, + goal, s] + exact Subtype.coe_preimage_self _ |>.symm, by intro _ _; rfl⟩ exact G.mem_maximalAtlas_of_eqOnSource (M := s) this (G.restriction_in_maximalAtlas he hs) /-- Each chart of a charted space is a structomorphism between its source and target. -/ diff --git a/Mathlib/Geometry/Manifold/Complex.lean b/Mathlib/Geometry/Manifold/Complex.lean index a0110600277bb..a9ea94cdde69c 100644 --- a/Mathlib/Geometry/Manifold/Complex.lean +++ b/Mathlib/Geometry/Manifold/Complex.lean @@ -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/Basic.lean b/Mathlib/Geometry/Manifold/ContMDiff/Basic.lean index a8f5c4d77931c..cd4f4365ba286 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Basic.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Basic.lean @@ -64,13 +64,13 @@ theorem ContMDiffWithinAt.comp {t : Set M'} {g : M' → M''} (x : M) filter_upwards [hf.1.tendsto (extChartAt_source_mem_nhds I' (f x)), inter_mem_nhdsWithin s (extChartAt_source_mem_nhds 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, *] + simp only [e.map_source hx', true_and, e.left_inv hx', st hx's, *] refine ((hg.2.comp _ (hf.2.mono inter_subset_right) inter_subset_left).mono_of_mem (inter_mem ?_ self_mem_nhdsWithin)).congr_of_eventuallyEq ?_ ?_ · 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'⟩ @@ -217,7 +217,7 @@ variable {c : M'} theorem contMDiff_const : ContMDiff I I' n fun _ : M => c := by intro x refine ⟨continuousWithinAt_const, ?_⟩ - simp only [ContDiffWithinAtProp, (· ∘ ·)] + simp only [ContDiffWithinAtProp, Function.comp_def] exact contDiffWithinAt_const @[to_additive] @@ -322,12 +322,13 @@ theorem ContMDiff.extend_one [T2Space M] [One M'] {n : ℕ∞} {U : Opens M} {f refine contMDiff_of_mulTSupport (fun x h ↦ ?_) _ lift x to U using Subtype.coe_image_subset _ _ (supp.mulTSupport_extend_one_subset continuous_subtype_val h) - rw [← contMdiffAt_subtype_iff, ← comp_def] - erw [extend_comp Subtype.val_injective] + rw [← contMdiffAt_subtype_iff] + simp_rw [← comp_def] + rw [extend_comp Subtype.val_injective] exact diff.contMDiffAt theorem contMDiff_inclusion {n : ℕ∞} {U V : Opens M} (h : U ≤ V) : - ContMDiff I I n (Set.inclusion h : U → V) := by + ContMDiff I I n (Opens.inclusion h : U → V) := by rintro ⟨x, hx : x ∈ U⟩ apply (contDiffWithinAt_localInvariantProp I I n).liftProp_inclusion intro y @@ -345,7 +346,8 @@ theorem Smooth.extend_one [T2Space M] [One M'] {U : Opens M} {f : U → M'} (supp : HasCompactMulSupport f) (diff : Smooth I I' f) : Smooth I I' (Subtype.val.extend f 1) := ContMDiff.extend_one supp diff -theorem smooth_inclusion {U V : Opens M} (h : U ≤ V) : Smooth I I (Set.inclusion h : U → V) := +theorem smooth_inclusion {U V : Opens M} (h : U ≤ V) : + Smooth I I (Opens.inclusion h : U → V) := contMDiff_inclusion h end Inclusion diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean b/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean index 3028f6318c3cd..cde9ee6782c47 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean @@ -769,7 +769,7 @@ 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 -/ diff --git a/Mathlib/Geometry/Manifold/ContMDiff/NormedSpace.lean b/Mathlib/Geometry/Manifold/ContMDiff/NormedSpace.lean index 3f612e90bddc7..0b857f12e00f4 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/NormedSpace.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/NormedSpace.lean @@ -192,7 +192,7 @@ theorem ContMDiffWithinAt.clm_apply {g : M → F₁ →L[𝕜] F₂} {f : M → (hg : ContMDiffWithinAt I 𝓘(𝕜, F₁ →L[𝕜] F₂) n g s x) (hf : ContMDiffWithinAt I 𝓘(𝕜, F₁) n f s x) : ContMDiffWithinAt I 𝓘(𝕜, F₂) n (fun x => g x (f x)) s x := - ContDiffWithinAt.comp_contMDiffWithinAt + ContDiffWithinAt.comp_contMDiffWithinAt (t := univ) (g := fun x : (F₁ →L[𝕜] F₂) × F₁ => x.1 x.2) (by apply ContDiff.contDiffAt; exact contDiff_fst.clm_apply contDiff_snd) (hg.prod_mk_space hf) (by simp_rw [preimage_univ, subset_univ]) diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Product.lean b/Mathlib/Geometry/Manifold/ContMDiff/Product.lean index 6cd5c2919d09b..5208fce1bdcc3 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Product.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Product.lean @@ -337,7 +337,7 @@ theorem contMDiffWithinAt_pi_space : ContMDiffWithinAt I 𝓘(𝕜, ∀ i, Fi i) n φ s x ↔ ∀ i, ContMDiffWithinAt I 𝓘(𝕜, Fi i) n (fun x => φ x i) s x := by simp only [contMDiffWithinAt_iff, continuousWithinAt_pi, contDiffWithinAt_pi, forall_and, - writtenInExtChartAt, extChartAt_model_space_eq_id, (· ∘ ·), PartialEquiv.refl_coe, id] + writtenInExtChartAt, extChartAt_model_space_eq_id, Function.comp_def, PartialEquiv.refl_coe, id] theorem contMDiffOn_pi_space : ContMDiffOn I 𝓘(𝕜, ∀ i, Fi i) n φ s ↔ ∀ i, ContMDiffOn I 𝓘(𝕜, Fi i) n (fun x => φ x i) s := diff --git a/Mathlib/Geometry/Manifold/ContMDiffMFDeriv.lean b/Mathlib/Geometry/Manifold/ContMDiffMFDeriv.lean index 2daa9b0a934c0..98fc2cc47a1e1 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 /-! @@ -94,9 +94,9 @@ protected theorem ContMDiffAt.mfderiv {x₀ : N} (f : N → M → M') (g : N → (range I) (extChartAt I (g x₀) (g ((extChartAt J x₀).symm x)))) (range J) (extChartAt J x₀ x₀) := by rw [contMDiffAt_iff] at hf hg - simp_rw [Function.comp, uncurry, extChartAt_prod, PartialEquiv.prod_coe_symm, + 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⟩ @@ -108,7 +108,7 @@ protected theorem ContMDiffAt.mfderiv {x₀ : N} (f : N → M → M') (g : N → (extChartAt I (g x₀) (g x))) x₀ := by simp_rw [contMDiffAt_iff_source_of_mem_source (mem_chart_source G x₀), - contMDiffWithinAt_iff_contDiffWithinAt, Function.comp] + contMDiffWithinAt_iff_contDiffWithinAt, Function.comp_def] exact this have : ContMDiffAt J 𝓘(𝕜, E →L[𝕜] E') m @@ -165,7 +165,7 @@ protected theorem ContMDiffAt.mfderiv {x₀ : N} (f : N → M → M') (g : N → PartialEquiv.mem_symm_trans_source _ (mem_extChartAt_source I' (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, @@ -577,7 +577,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/DerivationBundle.lean b/Mathlib/Geometry/Manifold/DerivationBundle.lean index d9bfdfd389518..fad0b9a9bd14e 100644 --- a/Mathlib/Geometry/Manifold/DerivationBundle.lean +++ b/Mathlib/Geometry/Manifold/DerivationBundle.lean @@ -10,7 +10,7 @@ import Mathlib.RingTheory.Derivation.Basic # Derivation bundle -In this file we define the derivations at a point of a manifold on the algebra of smooth fuctions. +In this file we define the derivations at a point of a manifold on the algebra of smooth functions. Moreover, we define the differential of a function in terms of derivations. The content of this file is not meant to be regarded as an alternative definition to the current diff --git a/Mathlib/Geometry/Manifold/Diffeomorph.lean b/Mathlib/Geometry/Manifold/Diffeomorph.lean index 45a273cc452b0..425037472ff7a 100644 --- a/Mathlib/Geometry/Manifold/Diffeomorph.lean +++ b/Mathlib/Geometry/Manifold/Diffeomorph.lean @@ -282,7 +282,7 @@ theorem contMDiffWithinAt_comp_diffeomorph_iff {m} (h : M ≃ₘ^n⟮I, J⟯ N) constructor · intro Hfh rw [← h.symm_apply_apply x] at Hfh - simpa only [(· ∘ ·), h.apply_symm_apply] using + simpa only [Function.comp_def, h.apply_symm_apply] using Hfh.comp (h x) (h.symm.contMDiffWithinAt.of_le hm) (mapsTo_preimage _ _) · rw [← h.image_eq_preimage] exact fun hf => hf.comp x (h.contMDiffWithinAt.of_le hm) (mapsTo_image _ _) @@ -308,7 +308,7 @@ theorem contMDiff_comp_diffeomorph_iff {m} (h : M ≃ₘ^n⟮I, J⟯ N) {f : N theorem contMDiffWithinAt_diffeomorph_comp_iff {m} (h : M ≃ₘ^n⟮I, J⟯ N) {f : M' → M} (hm : m ≤ n) {s x} : ContMDiffWithinAt I' J m (h ∘ f) s x ↔ ContMDiffWithinAt I' I m f s x := ⟨fun Hhf => by - simpa only [(· ∘ ·), h.symm_apply_apply] using + simpa only [Function.comp_def, h.symm_apply_apply] using (h.symm.contMDiffAt.of_le hm).comp_contMDiffWithinAt _ Hhf, fun Hf => (h.contMDiffAt.of_le hm).comp_contMDiffWithinAt _ Hf⟩ @@ -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 diff --git a/Mathlib/Geometry/Manifold/Instances/Real.lean b/Mathlib/Geometry/Manifold/Instances/Real.lean index cdb390895e851..43cbf79926a58 100644 --- a/Mathlib/Geometry/Manifold/Instances/Real.lean +++ b/Mathlib/Geometry/Manifold/Instances/Real.lean @@ -47,7 +47,7 @@ open scoped Manifold /-- The half-space in `ℝ^n`, used to model manifolds with boundary. We only define it when `1 ≤ n`, as the definition only makes sense in this case. -/ -def EuclideanHalfSpace (n : ℕ) [Zero (Fin n)] : Type := +def EuclideanHalfSpace (n : ℕ) [NeZero n] : Type := { x : EuclideanSpace ℝ (Fin n) // 0 ≤ x 0 } /-- @@ -64,13 +64,13 @@ without the following reducibility attribute (which is only set in this section) variable {n : ℕ} -instance [Zero (Fin n)] : TopologicalSpace (EuclideanHalfSpace n) := +instance [NeZero n] : TopologicalSpace (EuclideanHalfSpace n) := instTopologicalSpaceSubtype instance : TopologicalSpace (EuclideanQuadrant n) := instTopologicalSpaceSubtype -instance [Zero (Fin n)] : Inhabited (EuclideanHalfSpace n) := +instance [NeZero n] : Inhabited (EuclideanHalfSpace n) := ⟨⟨0, le_rfl⟩⟩ instance : Inhabited (EuclideanQuadrant n) := @@ -81,15 +81,37 @@ theorem EuclideanQuadrant.ext (x y : EuclideanQuadrant n) (h : x.1 = y.1) : x = Subtype.eq h @[ext] -theorem EuclideanHalfSpace.ext [Zero (Fin n)] (x y : EuclideanHalfSpace n) +theorem EuclideanHalfSpace.ext [NeZero n] (x y : EuclideanHalfSpace n) (h : x.1 = y.1) : x = y := Subtype.eq h -theorem range_euclideanHalfSpace (n : ℕ) [Zero (Fin n)] : +theorem range_euclideanHalfSpace (n : ℕ) [NeZero n] : (range fun x : EuclideanHalfSpace n => x.val) = { y | 0 ≤ y 0 } := Subtype.range_val @[deprecated (since := "2024-04-05")] alias range_half_space := range_euclideanHalfSpace +open ENNReal in +@[simp] +theorem interior_halfspace {n : ℕ} (p : ℝ≥0∞) (a : ℝ) (i : Fin n) : + interior { y : PiLp p (fun _ : Fin n ↦ ℝ) | a ≤ y i } = { y | a < y i } := by + let f : PiLp p (fun _ : Fin n ↦ ℝ) →L[ℝ] ℝ := ContinuousLinearMap.proj i + simpa [interior_Ici] using f.interior_preimage (Function.surjective_eval _) (Ici a) + +open ENNReal in +@[simp] +theorem closure_halfspace {n : ℕ} (p : ℝ≥0∞) (a : ℝ) (i : Fin n) : + closure { y : PiLp p (fun _ : Fin n ↦ ℝ) | a ≤ y i } = { y | a ≤ y i } := by + let f : PiLp p (fun _ : Fin n ↦ ℝ) →L[ℝ] ℝ := ContinuousLinearMap.proj i + simpa [closure_Ici] using f.closure_preimage (Function.surjective_eval _) (Ici a) + +open ENNReal in +@[simp] +theorem frontier_halfspace {n : ℕ} (p : ℝ≥0∞) (a : ℝ) (i : Fin n) : + frontier { y : PiLp p (fun _ : Fin n ↦ ℝ) | a ≤ y i } = { y | a = y i } := by + rw [frontier, closure_halfspace, interior_halfspace] + ext y + simpa only [mem_diff, mem_setOf_eq, not_lt] using antisymm_iff + theorem range_euclideanQuadrant (n : ℕ) : (range fun x : EuclideanQuadrant n => x.val) = { y | ∀ i : Fin n, 0 ≤ y i } := Subtype.range_val @@ -101,7 +123,7 @@ end Definition of the model with corners `(EuclideanSpace ℝ (Fin n), EuclideanHalfSpace n)`, used as a model for manifolds with boundary. In the locale `Manifold`, use the shortcut `𝓡∂ n`. -/ -def modelWithCornersEuclideanHalfSpace (n : ℕ) [Zero (Fin n)] : +def modelWithCornersEuclideanHalfSpace (n : ℕ) [NeZero n] : ModelWithCorners ℝ (EuclideanSpace ℝ (Fin n)) (EuclideanHalfSpace n) where toFun := Subtype.val invFun x := ⟨update x 0 (max (x 0) 0), by simp [le_refl]⟩ @@ -114,7 +136,7 @@ def modelWithCornersEuclideanHalfSpace (n : ℕ) [Zero (Fin n)] : exact ⟨max_eq_left xprop, fun i _ => rfl⟩ right_inv' x hx := update_eq_iff.2 ⟨max_eq_left hx, fun i _ => 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 @@ -129,7 +151,7 @@ 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 @@ -137,7 +159,7 @@ def modelWithCornersEuclideanQuadrant (n : ℕ) : 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 @@ -157,6 +179,25 @@ scoped[Manifold] (modelWithCornersEuclideanHalfSpace n : ModelWithCorners ℝ (EuclideanSpace ℝ (Fin n)) (EuclideanHalfSpace n)) +lemma range_modelWithCornersEuclideanHalfSpace (n : ℕ) [NeZero n] : + range (𝓡∂ n) = { y | 0 ≤ y 0 } := range_euclideanHalfSpace n + +lemma interior_range_modelWithCornersEuclideanHalfSpace (n : ℕ) [NeZero n] : + interior (range (𝓡∂ n)) = { y | 0 < y 0 } := by + calc interior (range (𝓡∂ n)) + _ = interior ({ y | 0 ≤ y 0}) := by + congr! + apply range_euclideanHalfSpace + _ = { y | 0 < y 0 } := interior_halfspace _ _ _ + +lemma frontier_range_modelWithCornersEuclideanHalfSpace (n : ℕ) [NeZero n] : + frontier (range (𝓡∂ n)) = { y | 0 = y 0 } := by + calc frontier (range (𝓡∂ n)) + _ = frontier ({ y | 0 ≤ y 0 }) := by + congr! + apply range_euclideanHalfSpace + _ = { y | 0 = y 0 } := frontier_halfspace 2 _ _ + /-- The left chart for the topological space `[x, y]`, defined on `[x,y)` and sending `x` to `0` in `EuclideanHalfSpace 1`. -/ diff --git a/Mathlib/Geometry/Manifold/Instances/Sphere.lean b/Mathlib/Geometry/Manifold/Instances/Sphere.lean index 41a32a5f566cb..f5d59a6f08222 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] @@ -421,7 +405,7 @@ instance (n : ℕ) : haveI := Fact.mk (@finrank_euclideanSpace_fin ℝ _ (n + 1)) EuclideanSpace.instSmoothManifoldWithCornersSphere -/-- The inclusion map (i.e., `coe`) from the sphere in `E` to `E` is smooth. -/ +/-- The inclusion map (i.e., `coe`) from the sphere in `E` to `E` is smooth. -/ theorem contMDiff_coe_sphere {n : ℕ} [Fact (finrank ℝ E = n + 1)] : ContMDiff (𝓡 n) 𝓘(ℝ, E) ∞ ((↑) : sphere (0 : E) 1 → E) := by -- Porting note: trouble with filling these implicit variables in the instance diff --git a/Mathlib/Geometry/Manifold/IntegralCurve.lean b/Mathlib/Geometry/Manifold/IntegralCurve.lean index beb8c885abb24..b16bd2c24cde9 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) @@ -168,10 +169,11 @@ lemma IsIntegralCurveOn.hasDerivAt (hγ : IsIntegralCurveOn γ v s) {t : ℝ} (h mfderiv_chartAt_eq_tangentCoordChange I 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 + apply eventually_mem_nhds_iff.mpr (hγ.continuousAt.preimage_mem_nhds (extChartAt_source_mem_nhds I _)) |>.and hγ |>.mono rintro t ⟨ht1, ht2⟩ have hsrc := mem_of_mem_nhds ht1 @@ -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 @@ -391,7 +393,7 @@ 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 <| + ∀ᶠ t in 𝓝 t₀, g ⁻¹' (extChartAt I (g t₀)).source ∈ 𝓝 t := eventually_mem_nhds_iff.mpr <| continuousAt_def.mp hg.continuousAt _ <| extChartAt_source_mem_nhds I (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 @@ -492,7 +494,7 @@ theorem isIntegralCurve_eq_of_contMDiff (hγt : ∀ t, I.IsInteriorPoint (γ t)) obtain ⟨hS₂, hS₃⟩ := abs_lt.mp hS₂ exact ⟨T + S, by constructor <;> constructor <;> linarith⟩ exact isIntegralCurveOn_Ioo_eqOn_of_contMDiff ht (fun t _ ↦ hγt t) hv - ((hγ.isIntegralCurveOn _).mono (subset_univ _)) + ((hγ.isIntegralCurveOn _).mono (subset_univ _)) ((hγ'.isIntegralCurveOn _).mono (subset_univ _)) h ht₀ theorem isIntegralCurve_Ioo_eq_of_contMDiff_boundaryless [BoundarylessManifold I M] diff --git a/Mathlib/Geometry/Manifold/InteriorBoundary.lean b/Mathlib/Geometry/Manifold/InteriorBoundary.lean index 1bfcd8ec40979..ae3c3a754f493 100644 --- a/Mathlib/Geometry/Manifold/InteriorBoundary.lean +++ b/Mathlib/Geometry/Manifold/InteriorBoundary.lean @@ -21,10 +21,12 @@ Define the interior and boundary of a manifold. - `ModelWithCorners.univ_eq_interior_union_boundary`: `M` is the union of its interior and boundary - `ModelWithCorners.interior_boundary_disjoint`: interior and boundary of `M` are disjoint - `BoundarylessManifold.isInteriorPoint`: if `M` is boundaryless, every point is an interior point - +- `ModelWithCorners.Boundaryless.boundary_eq_empty` and `of_boundary_eq_empty`: +`M` is boundaryless if and only if its boundary is empty - `ModelWithCorners.interior_prod`: the interior of `M × N` is the product of the interiors of `M` and `N`. - `ModelWithCorners.boundary_prod`: the boundary of `M × N` is `∂M × N ∪ (M × ∂N)`. +- `ModelWithCorners.BoundarylessManifold.prod`: if `M` and `N` are boundaryless, so is `M × N` ## Tags manifold, interior, boundary @@ -96,10 +98,14 @@ lemma disjoint_interior_boundary : Disjoint (I.interior M) (I.boundary M) := by exact ⟨h1, h2⟩ /-- The boundary is the complement of the interior. -/ -lemma boundary_eq_complement_interior : I.boundary M = (I.interior M)ᶜ := by - apply (compl_unique ?_ I.interior_union_boundary_eq_univ).symm +lemma compl_interior : (I.interior M)ᶜ = I.boundary M:= by + apply compl_unique ?_ I.interior_union_boundary_eq_univ exact disjoint_iff_inter_eq_empty.mp (I.disjoint_interior_boundary) +/-- The interior is the complement of the boundary. -/ +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 @@ -123,36 +129,47 @@ instance : BoundarylessManifold I M where let r := ((chartAt H x).isOpen_extend_target I).interior_eq have : extChartAt I x = (chartAt H x).extend I := rfl rw [← this] at r - rw [ModelWithCorners.isInteriorPoint_iff, r] + rw [isInteriorPoint_iff, r] exact PartialEquiv.map_source _ (mem_extChartAt_source _ _) end Boundaryless section BoundarylessManifold -variable [BoundarylessManifold I M] /-- The empty manifold is boundaryless. -/ instance BoundarylessManifold.of_empty [IsEmpty M] : BoundarylessManifold I M where isInteriorPoint' x := (IsEmpty.false x).elim -lemma _root_.BoundarylessManifold.isInteriorPoint {x : M} : +lemma _root_.BoundarylessManifold.isInteriorPoint {x : M} [BoundarylessManifold I M] : IsInteriorPoint I x := BoundarylessManifold.isInteriorPoint' x /-- If `I` is boundaryless, `M` has full interior. -/ -lemma interior_eq_univ : I.interior M = univ := +lemma interior_eq_univ [BoundarylessManifold I M] : I.interior M = univ := eq_univ_of_forall fun _ => BoundarylessManifold.isInteriorPoint I /-- Boundaryless manifolds have empty boundary. -/ -lemma Boundaryless.boundary_eq_empty : I.boundary M = ∅ := by - rw [I.boundary_eq_complement_interior, I.interior_eq_univ, compl_empty_iff] +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) +/-- `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⟩ + intro x + show x ∈ I.interior M + rw [← compl_interior, compl_empty_iff] at h + rw [h] + trivial + +/-- Manifolds with empty boundary are boundaryless. -/ +lemma Boundaryless.of_boundary_eq_empty (h : I.boundary M = ∅) : BoundarylessManifold I M := + (Boundaryless.iff_boundary_eq_empty (I := I)).mp h + end BoundarylessManifold -end ModelWithCorners --- Interior and boundary of the product of two manifolds. +/-! Interior and boundary of the product of two manifolds. -/ section prod variable {I} @@ -162,43 +179,54 @@ variable {I} (J : ModelWithCorners 𝕜 E' H') {x : M} {y : N} /-- The interior of `M × N` is the product of the interiors of `M` and `N`. -/ -lemma ModelWithCorners.interior_prod : +lemma interior_prod : (I.prod J).interior (M × N) = (I.interior M) ×ˢ (J.interior N) := by ext p have aux : (interior (range ↑I)) ×ˢ (interior (range J)) = interior (range (I.prod J)) := by rw [← interior_prod_eq, ← Set.range_prod_map, modelWithCorners_prod_coe] constructor <;> intro hp · replace hp : (I.prod J).IsInteriorPoint p := hp - rw [ModelWithCorners.IsInteriorPoint, ← aux] at hp + rw [IsInteriorPoint, ← aux] at hp exact hp - · obtain ⟨h₁, h₂⟩ := Set.mem_prod.mp hp - rw [ModelWithCorners.interior] at h₁ h₂ - show (I.prod J).IsInteriorPoint p - rw [ModelWithCorners.IsInteriorPoint, ← aux, mem_prod] - exact ⟨h₁, h₂⟩ + · show (I.prod J).IsInteriorPoint p + rw [IsInteriorPoint, ← aux, mem_prod] + obtain h := Set.mem_prod.mp hp + rw [ModelWithCorners.interior] at h + exact h /-- The boundary of `M × N` is `∂M × N ∪ (M × ∂N)`. -/ -lemma ModelWithCorners.boundary_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).boundary_eq_complement_interior - _ = ((I.interior M) ×ˢ (J.interior N))ᶜ := by rw [ModelWithCorners.interior_prod] + _ = ((I.prod J).interior (M × N))ᶜ := (I.prod J).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.boundary_eq_complement_interior, J.boundary_eq_complement_interior, union_comm] + rw [h, I.compl_interior, J.compl_interior, union_comm] rfl /-- If `M` is boundaryless, `∂(M×N) = M × ∂N`. -/ -lemma boundary_of_boundaryless_left [I.Boundaryless] : +lemma boundary_of_boundaryless_left [BoundarylessManifold I M] : (I.prod J).boundary (M × N) = Set.prod (univ : Set M) (J.boundary N) := by - rw [ModelWithCorners.boundary_prod, ModelWithCorners.Boundaryless.boundary_eq_empty I] + rw [boundary_prod, Boundaryless.boundary_eq_empty 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 [J.Boundaryless] : +lemma boundary_of_boundaryless_right [BoundarylessManifold J N] : (I.prod J).boundary (M × N) = Set.prod (I.boundary M) (univ : Set N) := by - rw [ModelWithCorners.boundary_prod, ModelWithCorners.Boundaryless.boundary_eq_empty J] + rw [boundary_prod, Boundaryless.boundary_eq_empty J] have : Set.prod (univ : Set M) (∅ : Set N) = ∅ := Set.prod_empty rw [this, empty_union] +/-- The product of two boundaryless manifolds is boundaryless. -/ +instance BoundarylessManifold.prod [BoundarylessManifold I M] [BoundarylessManifold J N] : + BoundarylessManifold (I.prod J) (M × N) := by + apply Boundaryless.of_boundary_eq_empty + simp only [boundary_prod, Boundaryless.boundary_eq_empty, union_empty_iff] + -- These are simp lemmas, but `simp` does not apply them on its own: + -- presumably because of the distinction between `Prod` and `ModelProd` + exact ⟨Set.prod_empty, Set.empty_prod⟩ + end prod + +end ModelWithCorners diff --git a/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean b/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean index 13b8450ed5ea7..5ea4b4a42e6b8 100644 --- a/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean +++ b/Mathlib/Geometry/Manifold/LocalInvariantProperties.lean @@ -42,13 +42,10 @@ coincide on `s`, then `LiftPropWithinAt P g' s x` holds. We can't call it in the one for `LiftPropWithinAt`. -/ - noncomputable section -open scoped Classical -open Manifold Topology - open Set Filter TopologicalSpace +open scoped Manifold Topology variable {H M H' M' X : Type*} variable [TopologicalSpace H] [TopologicalSpace M] [ChartedSpace H M] @@ -71,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 @@ -275,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') @@ -295,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') @@ -305,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 @@ -433,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) @@ -485,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} @@ -518,9 +515,9 @@ theorem liftProp_subtype_val {Q : (H → H) → Set H → H → Prop} (hG : Loca theorem liftProp_inclusion {Q : (H → H) → Set H → H → Prop} (hG : LocalInvariantProp G G Q) (hQ : ∀ y, Q id univ y) {U V : Opens M} (hUV : U ≤ V) : - LiftProp Q (Set.inclusion hUV : U → V) := by + LiftProp Q (Opens.inclusion hUV : U → V) := by intro x - show LiftPropAt Q (id ∘ inclusion hUV) x + show LiftPropAt Q (id ∘ Opens.inclusion hUV) x rw [← hG.liftPropAt_iff_comp_inclusion hUV] apply hG.liftProp_id hQ diff --git a/Mathlib/Geometry/Manifold/MFDeriv/Atlas.lean b/Mathlib/Geometry/Manifold/MFDeriv/Atlas.lean index cd4d98910c206..cbdbcb8afc391 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/Atlas.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/Atlas.lean @@ -127,37 +127,6 @@ theorem mdifferentiable_of_mem_atlas (h : e ∈ atlas H M) : e.MDifferentiable I 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] - end Charts @@ -176,9 +145,6 @@ 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 @@ -198,7 +164,8 @@ theorem comp_symm_deriv {x : M'} (hx : x ∈ e.target) : /-- The derivative of a differentiable partial homeomorphism, as a continuous linear equivalence between the tangent spaces at `x` and `e x`. -/ -protected def mfderiv {x : M} (hx : x ∈ e.source) : TangentSpace I x ≃L[𝕜] TangentSpace I' (e x) := +protected def mfderiv (he : e.MDifferentiable I I') {x : M} (hx : x ∈ e.source) : + TangentSpace I x ≃L[𝕜] TangentSpace I' (e x) := { mfderiv I I' e x with invFun := mfderiv I' I e.symm (e x) continuous_toFun := (mfderiv I I' e x).cont diff --git a/Mathlib/Geometry/Manifold/MFDeriv/Basic.lean b/Mathlib/Geometry/Manifold/MFDeriv/Basic.lean index 29f6ccec46202..077f630896244 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 @@ -44,7 +47,7 @@ variable 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 I I').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 I I').liftPropWithinAt_inter' ht] theorem MDifferentiableAt.mdifferentiableWithinAt (h : MDifferentiableAt I I' f x) : MDifferentiableWithinAt I I' f s x := @@ -256,30 +259,26 @@ theorem writtenInExtChartAt_comp (h : ContinuousWithinAt f s x) : (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₁ /-! ### General lemmas on derivatives of functions between manifolds -We mimick the API for functions between vector spaces +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 I I').liftPropWithinAt_indep_chart (StructureGroupoid.chart_mem_maximalAtlas _ x) hx (StructureGroupoid.chart_mem_maximalAtlas _ y) hy @@ -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' ↔ diff --git a/Mathlib/Geometry/Manifold/MFDeriv/Defs.lean b/Mathlib/Geometry/Manifold/MFDeriv/Defs.lean index 7fd0dbf7af7cc..88e42b72004c0 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 @@ -98,7 +99,7 @@ derivative, manifold noncomputable section -open scoped Classical Topology Manifold +open scoped Topology open Set ChartedSpace section DerivativesDefinitions @@ -128,7 +129,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,6 +174,9 @@ 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 + /-- 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) := @@ -296,6 +300,7 @@ def HasMFDerivAt (f : M → M') (x : M) (f' : TangentSpace I x →L[𝕜] Tangen ContinuousAt f x ∧ HasFDerivWithinAt (writtenInExtChartAt I I' x f : E → E') f' (range I) ((extChartAt I x) x) +open Classical 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`. -/ @@ -306,6 +311,7 @@ def mfderivWithin (f : M → M') (s : Set M) (x : M) : TangentSpace I x →L[ _) else 0 +open Classical 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`. -/ diff --git a/Mathlib/Geometry/Manifold/MFDeriv/SpecificFunctions.lean b/Mathlib/Geometry/Manifold/MFDeriv/SpecificFunctions.lean index efe86094c46e5..e80b20105886e 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/SpecificFunctions.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/SpecificFunctions.lean @@ -28,12 +28,12 @@ section SpecificFunctions 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*} + [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''] + {E'' : Type*} [NormedAddCommGroup E''] [NormedSpace 𝕜 E''] {H'' : Type*} [TopologicalSpace H''] (I'' : ModelWithCorners 𝕜 E'' H'') {M'' : Type*} - [TopologicalSpace M''] [ChartedSpace H'' M''] [SmoothManifoldWithCorners I'' M''] + [TopologicalSpace M''] [ChartedSpace H'' M''] namespace ContinuousLinearMap @@ -158,7 +158,7 @@ variable {c : M'} theorem hasMFDerivAt_const (c : M') (x : M) : HasMFDerivAt I I' (fun _ : M => c) x (0 : TangentSpace I x →L[𝕜] TangentSpace I' c) := by refine ⟨continuous_const.continuousAt, ?_⟩ - simp only [writtenInExtChartAt, (· ∘ ·), hasFDerivWithinAt_const] + simp only [writtenInExtChartAt, Function.comp_def, hasFDerivWithinAt_const] 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) := @@ -324,7 +324,7 @@ 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 _)) + hg.differentiableWithinAt_writtenInExtChartAt (I.uniqueDiffOn _ (mem_range_self _)) variable (I I' I'') diff --git a/Mathlib/Geometry/Manifold/MFDeriv/Tangent.lean b/Mathlib/Geometry/Manifold/MFDeriv/Tangent.lean new file mode 100644 index 0000000000000..b1da80bc215d6 --- /dev/null +++ b/Mathlib/Geometry/Manifold/MFDeriv/Tangent.lean @@ -0,0 +1,64 @@ +/- +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] + {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''] + [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 (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..076089056c123 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`. -/ @@ -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) : @@ -94,6 +95,7 @@ theorem UniqueMDiffOn.uniqueDiffOn_target_inter (hs : UniqueMDiffOn I s) (x : M) (fun y hy ↦ hasMFDerivWithinAt_extChartAt I 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. -/ @@ -120,8 +122,6 @@ theorem Trivialization.mdifferentiable (e : Trivialization F (π F Z)) [MemTrivi e.toPartialHomeomorph.MDifferentiable (I.prod 𝓘(𝕜, F)) (I.prod 𝓘(𝕜, F)) := ⟨(e.smoothOn I).mdifferentiableOn, (e.smoothOn_symm I).mdifferentiableOn⟩ -variable [SmoothManifoldWithCorners I M] - theorem UniqueMDiffWithinAt.smooth_bundle_preimage {p : TotalSpace F Z} (hs : UniqueMDiffWithinAt I s p.proj) : UniqueMDiffWithinAt (I.prod 𝓘(𝕜, F)) (π F Z ⁻¹' s) p := by @@ -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 7b50a99e3073a..d0c29cb8d57a6 100644 --- a/Mathlib/Geometry/Manifold/PartitionOfUnity.lean +++ b/Mathlib/Geometry/Manifold/PartitionOfUnity.lean @@ -55,12 +55,10 @@ function from local functions. smooth bump function, partition of unity -/ - universe uι uE uH uM uF -open Function Filter FiniteDimensional Set - -open scoped Topology Manifold Classical Filter +open Function Filter Module Set +open scoped Topology Manifold noncomputable section @@ -466,12 +464,14 @@ theorem toSmoothPartitionOfUnity_apply (i : ι) (x : M) : fs.toSmoothPartitionOfUnity i x = fs i x * ∏ᶠ (j) (_ : WellOrderingRel j i), (1 - fs j x) := rfl +open Classical in theorem toSmoothPartitionOfUnity_eq_mul_prod (i : ι) (x : M) (t : Finset ι) (ht : ∀ j, WellOrderingRel j i → fs j x ≠ 0 → j ∈ t) : fs.toSmoothPartitionOfUnity i x = fs i x * ∏ j ∈ t.filter fun j => WellOrderingRel j i, (1 - fs j x) := fs.toBumpCovering.toPartitionOfUnity_eq_mul_prod i x t ht +open Classical in theorem exists_finset_toSmoothPartitionOfUnity_eventuallyEq (i : ι) (x : M) : ∃ t : Finset ι, fs.toSmoothPartitionOfUnity i =ᶠ[𝓝 x] @@ -553,6 +553,7 @@ namespace SmoothPartitionOfUnity defined as an example for `Inhabited` instance. -/ def single (i : ι) (s : Set M) : SmoothPartitionOfUnity ι I M s := (BumpCovering.single i s).toSmoothPartitionOfUnity fun j => by + classical rcases eq_or_ne j i with (rfl | h) · simp only [smooth_one, ContinuousMap.coe_one, BumpCovering.coe_single, Pi.single_eq_same] · simp only [smooth_zero, BumpCovering.coe_single, Pi.single_eq_of_ne h, ContinuousMap.coe_zero] @@ -739,6 +740,7 @@ theorem exists_msmooth_support_eq_eq_one_iff · have : 0 < f x := lt_of_le_of_ne (f_pos x) (Ne.symm xs) linarith [g_pos x] · have : 0 < g x := by + classical apply lt_of_le_of_ne (g_pos x) (Ne.symm ?_) rw [← mem_support, g_supp] contrapose! xs @@ -750,7 +752,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/Basic.lean b/Mathlib/Geometry/Manifold/Sheaf/Basic.lean index 1eacc748c2ec9..2368052ad3acf 100644 --- a/Mathlib/Geometry/Manifold/Sheaf/Basic.lean +++ b/Mathlib/Geometry/Manifold/Sheaf/Basic.lean @@ -55,7 +55,7 @@ def StructureGroupoid.LocalInvariantProp.localPredicate (hG : LocalInvariantProp res := by intro U V i f h x have hUV : U ≤ V := CategoryTheory.leOfHom i - show ChartedSpace.LiftPropAt P (f ∘ Set.inclusion hUV) x + show ChartedSpace.LiftPropAt P (f ∘ Opens.inclusion hUV) x rw [← hG.liftPropAt_iff_comp_inclusion hUV] apply h locality := by @@ -63,7 +63,7 @@ def StructureGroupoid.LocalInvariantProp.localPredicate (hG : LocalInvariantProp obtain ⟨U, hxU, i, hU : ChartedSpace.LiftProp P (f ∘ i)⟩ := h x let x' : U := ⟨x, hxU⟩ have hUV : U ≤ V := CategoryTheory.leOfHom i - have : ChartedSpace.LiftPropAt P f (inclusion hUV x') := by + have : ChartedSpace.LiftPropAt P f (Opens.inclusion hUV x') := by rw [hG.liftPropAt_iff_comp_inclusion hUV] exact hU x' convert this 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..d8ac4a298bca8 100644 --- a/Mathlib/Geometry/Manifold/Sheaf/Smooth.lean +++ b/Mathlib/Geometry/Manifold/Sheaf/Smooth.lean @@ -132,10 +132,10 @@ 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 IM I ⊤).localPredicate M N) _ _ _ _ lemma smoothSheaf.smooth_section {U : (Opens (TopCat.of M))ᵒᵖ} (f : (smoothSheaf IM I M N).presheaf.obj 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 8d56a55352b79..55142a16d8ebd 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) @@ -20,13 +22,13 @@ With this groupoid at hand and the general machinery of charted spaces, we thus of `C^n` manifold with respect to any model with corners `I` on `(E, H)`. We also introduce a specific type class for `C^∞` manifolds as these are the most commonly used. -Some texts assume manifolds to be Hausdorff and secound countable. We (in mathlib) assume neither, +Some texts assume manifolds to be Hausdorff and second countable. We (in mathlib) assume neither, but add these assumptions later as needed. (Quite a few results still do not require them.) ## Main definitions * `ModelWithCorners 𝕜 E H` : - a structure containing informations on the way a space `H` embeds in a + a structure containing information on the way a space `H` embeds in a model vector space E over the field `𝕜`. This is all that is needed to define a smooth manifold with model space `H`, and model vector space `E`. * `modelWithCornersSelf 𝕜 E` : @@ -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 @@ -129,7 +139,7 @@ scoped[Manifold] notation "∞" => (⊤ : ℕ∞) /-! ### Models with corners. -/ -/-- A structure containing informations on the way a space `H` embeds in a +/-- A structure containing information on the way a space `H` embeds in a model vector space `E` over the field `𝕜`. This is all what is needed to define a smooth manifold with model space `H`, and model vector space `E`. -/ @@ -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 @@ -290,17 +303,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 unique_diff_at_image {x : H} : UniqueDiffWithinAt 𝕜 (range I) (I x) := - I.unique_diff _ (mem_range_self _) +theorem uniqueDiffWithinAt_image {x : H} : UniqueDiffWithinAt 𝕜 (range I) (I x) := + I.uniqueDiffOn _ (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 +331,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) : @@ -369,9 +391,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 +404,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) @@ -427,7 +449,7 @@ section Boundaryless /-- Property ensuring that the model with corners `I` defines manifolds without boundary. This differs from the more general `BoundarylessManifold`, which requires every point on the manifold - to be an interior point. -/ + to be an interior point. -/ class ModelWithCorners.Boundaryless {𝕜 : Type*} [NontriviallyNormedField 𝕜] {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) : Prop where @@ -1057,7 +1079,7 @@ theorem extChartAt_target (x : M) : 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) := @@ -1351,3 +1373,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 b4db2a8aa2149..02abb186cc8f9 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/Basic.lean @@ -175,7 +175,7 @@ theorem contMDiffWithinAt_totalSpace (f : M → TotalSpace F E) {s : Set M} {x simp (config := { singlePass := true }) only [contMDiffWithinAt_iff_target] rw [and_and_and_comm, ← FiberBundle.continuousWithinAt_totalSpace, and_congr_right_iff] intro hf - simp_rw [modelWithCornersSelf_prod, FiberBundle.extChartAt, Function.comp, + simp_rw [modelWithCornersSelf_prod, FiberBundle.extChartAt, Function.comp_def, PartialEquiv.trans_apply, PartialEquiv.prod_coe, PartialEquiv.refl_coe, extChartAt_self_apply, modelWithCornersSelf_coe, Function.id_def, ← chartedSpaceSelf_prod] refine (contMDiffWithinAt_prod_iff _).trans (and_congr ?_ Iff.rfl) 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/SmoothSection.lean b/Mathlib/Geometry/Manifold/VectorBundle/SmoothSection.lean index ff5840676376f..10e4fe0a92fe3 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 diff --git a/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean b/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean index fed71bc4299df..7c85fe03db9fd 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. -/ @@ -55,7 +59,7 @@ 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 (ContDiffWithinAt.fderivWithin_right ?_ I.uniqueDiffOn le_top <| h hx).mono h refine (PartialHomeomorph.contDiffOn_extend_coord_change I (subset_maximalAtlas I j.2) (subset_maximalAtlas I i.2) x hx).mono_of_mem ?_ exact i.1.extend_coord_change_source_mem_nhdsWithin j.1 I hx @@ -65,7 +69,7 @@ variable (M) open SmoothManifoldWithCorners /-- 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,7 +88,7 @@ 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 + · exact I.uniqueDiffWithinAt_image · filter_upwards [i.1.extend_target_mem_nhdsWithin I hx] with y hy exact (i.1.extend I).right_inv hy · simp_rw [Function.comp_apply, i.1.extend_left_inv I hx] @@ -105,7 +109,7 @@ def tangentBundleCore : VectorBundleCore 𝕜 M E (atlas H M) where · exact (contDiffWithinAt_extend_coord_change' I (subset_maximalAtlas I j.2) (subset_maximalAtlas I i.2) hxj hxi).differentiableWithinAt le_top · intro x _; exact mem_range_self _ - · exact I.unique_diff_at_image + · exact I.uniqueDiffWithinAt_image · rw [Function.comp_apply, i.1.extend_left_inv I hxi] -- Porting note: moved to a separate `simp high` lemma b/c `simp` can simplify the LHS @@ -164,49 +168,12 @@ 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 @@ -448,13 +415,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 09569f2558908..3e3f2e4bb92fd 100644 --- a/Mathlib/Geometry/Manifold/WhitneyEmbedding.lean +++ b/Mathlib/Geometry/Manifold/WhitneyEmbedding.lean @@ -25,16 +25,14 @@ for sufficiently large `n` there exists a smooth embedding `M → ℝ^n`. partition of unity, smooth bump function, whitney theorem -/ - universe uι uE uH uM 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 scoped Topology Manifold Classical Filter +open Function Filter Module Set +open scoped Manifold noncomputable section diff --git a/Mathlib/Geometry/RingedSpace/Basic.lean b/Mathlib/Geometry/RingedSpace/Basic.lean index 5b110af7a48ad..a1960cb7b7970 100644 --- a/Mathlib/Geometry/RingedSpace/Basic.lean +++ b/Mathlib/Geometry/RingedSpace/Basic.lean @@ -51,24 +51,24 @@ instance : CoeSort RingedSpace Type* where 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 +76,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 +89,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 +115,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 +182,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 +200,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 340c62513dedd..30d7e6eaa301e 100644 --- a/Mathlib/Geometry/RingedSpace/LocallyRingedSpace.lean +++ b/Mathlib/Geometry/RingedSpace/LocallyRingedSpace.lean @@ -14,7 +14,7 @@ stalks are local rings), and morphisms between these (morphisms in `SheafedSpace `IsLocalRingHom` on the stalk maps). -/ --- Explicit universe annotations were used in this file to improve perfomance #12737 +-- Explicit universe annotations were used in this file to improve performance #12737 universe u @@ -89,10 +89,11 @@ noncomputable def Hom.stalkMap {X Y : LocallyRingedSpace.{u}} (f : Hom X Y) (x : Y.presheaf.stalk (f.1.1 x) ⟶ X.presheaf.stalk x := f.val.stalkMap x -instance {X Y : LocallyRingedSpace.{u}} (f : X ⟶ Y) (x : X) : IsLocalRingHom (f.stalkMap x) := +instance isLocalRingHomStalkMap {X Y : LocallyRingedSpace.{u}} (f : X ⟶ Y) (x : X) : + IsLocalRingHom (f.stalkMap x) := f.2 x -instance {X Y : LocallyRingedSpace.{u}} (f : X ⟶ Y) (x : X) : +instance isLocalRingHomValStalkMap {X Y : LocallyRingedSpace.{u}} (f : X ⟶ Y) (x : X) : IsLocalRingHom (f.val.stalkMap x) := f.2 x @@ -108,7 +109,7 @@ instance (X : LocallyRingedSpace.{u}) : Inhabited (Hom X X) := 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 erw [PresheafedSpace.stalkMap.comp] - exact @isLocalRingHom_comp _ _ _ _ _ _ _ _ (f.2 _) (g.2 _)⟩ + exact @RingHom.isLocalRingHom_comp _ _ _ _ _ _ _ _ (f.2 _) (g.2 _)⟩ /-- The category of locally ringed spaces. -/ instance : Category LocallyRingedSpace.{u} where @@ -258,21 +259,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,7 +286,7 @@ 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) : @@ -398,30 +384,33 @@ lemma stalkMap_inv_hom_apply (e : X ≅ Y) (x : 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.val.base x ∈ U) : + Y.presheaf.germ U (f.val.base x) hx ≫ f.stalkMap x = + f.val.c.app (op U) ≫ X.presheaf.germ ((Opens.map f.1.base).obj U) x hx := + PresheafedSpace.stalkMap_germ f.val 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.val.base x ∈ U) (y) : + f.stalkMap x (Y.presheaf.germ U (f.val.base x) hx y) = + X.presheaf.germ ((Opens.map f.1.base).obj U) x hx (f.val.c.app (op U) y) := + PresheafedSpace.stalkMap_germ_apply f.val U x hx y + +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 ⟨hxU, hx⟩ + rw [SetLike.mem_coe, X.toRingedSpace.mem_basicOpen _ _ hxU] + delta toRingedSpace + rw [← stalkMap_germ_apply] + exact (f.val.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.1.base x) hxU] + rw [← stalkMap_germ_apply] at hx + exact (isUnit_map_iff (f.val.stalkMap _) _).mp hx variable {U : TopCat} (X : LocallyRingedSpace.{u}) {f : U ⟶ X.toTopCat} (h : OpenEmbedding f) (V : Opens U) (x : U) (hx : x ∈ V) @@ -434,25 +423,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..60b7cb47198e4 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 @@ -215,7 +214,7 @@ instance coequalizer_π_stalk_isLocalRingHom (x : Y) : 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.π f.1 g.1 : _) 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 := imageBasicOpen_image_preimage f g U s @@ -226,10 +225,10 @@ instance coequalizer_π_stalk_isLocalRingHom (x : Y) : imageBasicOpen_image_open f g U s have VleU : (⟨(coequalizer.π f.val g.val).base '' V.1, V_open⟩ : TopologicalSpace.Opens _) ≤ 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.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] apply RingHom.isUnit_map rw [← isUnit_map_iff ((coequalizer.π f.val g.val : _).c.app _), ← comp_apply, NatTrans.naturality, comp_apply, ← isUnit_map_iff (Y.presheaf.map (eqToHom hV').op)] @@ -247,6 +246,8 @@ noncomputable def coequalizer : LocallyRingedSpace where localRing x := by obtain ⟨y, rfl⟩ := (TopCat.epi_iff_surjective (coequalizer.π f.val g.val).base).mp inferInstance x + -- TODO: this instance was found automatically before #6045 + have _ : IsLocalRingHom ((coequalizer.π f.val g.val).stalkMap y) := inferInstance exact ((coequalizer.π f.val g.val : _).stalkMap y).domain_localRing /-- The explicit coequalizer cofork of locally ringed spaces. -/ @@ -275,9 +276,12 @@ noncomputable def coequalizerCoforkIsColimit : IsColimit (coequalizerCofork f g) -- 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) + suffices _ : IsLocalRingHom (((coequalizerCofork f g).π.1.stalkMap _).comp h) by + apply isLocalRingHom_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 IsLocalRingHom (h ≫ (coequalizerCofork f g).π.val.stalkMap y) erw [← PresheafedSpace.stalkMap.comp] apply isLocalRingHom_stalkMap_congr _ _ (coequalizer.π_desc s.π.1 e).symm y infer_instance diff --git a/Mathlib/Geometry/RingedSpace/LocallyRingedSpace/ResidueField.lean b/Mathlib/Geometry/RingedSpace/LocallyRingedSpace/ResidueField.lean index e4395a78b6708..44d7e9d141d92 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,7 +61,7 @@ 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)) : @@ -77,7 +77,15 @@ 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) + +-- TODO: This instance is found before #6045. +-- We need this strange instance for `residueFieldMap`, the type of `F` must be fixed +-- like this. The instance `IsLocalRingHom (f.stalkMap x)` already exists, but does not work for +-- `residueFieldMap`. +instance : IsLocalRingHom (F := Y.presheaf.stalk (f.val.base x) →+* X.presheaf.stalk x) + (f.stalkMap x) := + f.2 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. -/ @@ -101,6 +109,8 @@ lemma residueFieldMap_comp {Z : LocallyRingedSpace.{u}} (g : Y ⟶ Z) (x : X) : simp only [comp_val, SheafedSpace.comp_base, Function.comp_apply, residueFieldMap] simp_rw [stalkMap_comp] haveI : IsLocalRingHom (g.stalkMap (f.val.base x)) := inferInstance + -- TODO: This instance is found before #6045. + haveI : IsLocalRingHom (f.stalkMap x) := inferInstance apply LocalRing.ResidueField.map_comp @[reassoc] @@ -112,7 +122,7 @@ lemma evaluation_naturality {V : Opens Y} (x : (Opens.map f.1.base).obj V) : 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) diff --git a/Mathlib/Geometry/RingedSpace/OpenImmersion.lean b/Mathlib/Geometry/RingedSpace/OpenImmersion.lean index bd741b1f3e58f..408d39010d7d3 100644 --- a/Mathlib/Geometry/RingedSpace/OpenImmersion.lean +++ b/Mathlib/Geometry/RingedSpace/OpenImmersion.lean @@ -27,11 +27,11 @@ Abbreviations are also provided for `SheafedSpace`, `LocallyRingedSpace` and `Sc contained in an open immersion factors though the open immersion. * `AlgebraicGeometry.PresheafedSpace.IsOpenImmersion.toSheafedSpace`: If `f : X ⟶ Y` is an open immersion of presheafed spaces, and `Y` is a sheafed space, then `X` is also a sheafed - space. The morphism as morphisms of sheafed spaces is given by `to_SheafedSpaceHom`. + space. The morphism as morphisms of sheafed spaces is given by `toSheafedSpaceHom`. * `AlgebraicGeometry.PresheafedSpace.IsOpenImmersion.toLocallyRingedSpace`: If `f : X ⟶ Y` is an open immersion of presheafed spaces, and `Y` is a locally ringed space, then `X` is also a locally ringed space. The morphism as morphisms of locally ringed spaces is given by - `to_LocallyRingedSpace_hom`. + `toLocallyRingedSpaceHom`. ## Main results @@ -69,7 +69,7 @@ class PresheafedSpace.IsOpenImmersion {X Y : PresheafedSpace C} (f : X ⟶ Y) : /-- the underlying continuous map of underlying spaces from the source to an open subset of the target. -/ base_open : OpenEmbedding f.base - /-- the underlying sheaf morphism is an isomorphism on each open subset-/ + /-- 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))) /-- A morphism of SheafedSpaces is an open immersion if it is an open immersion as a morphism @@ -118,7 +118,7 @@ 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)] @@ -152,7 +152,7 @@ instance comp {Z : PresheafedSpace C} (g : Y ⟶ Z) [hg : IsOpenImmersion g] : generalize_proofs h dsimp only [AlgebraicGeometry.PresheafedSpace.comp_c_app, unop_op, Functor.op, comp_base, Opens.map_comp_obj] - apply (config := { allowSynthFailures := true }) IsIso.comp_isIso + apply IsIso.comp_isIso' · exact c_iso' g ((opensFunctor f).obj U) (by ext; simp) · apply c_iso' f U ext1 @@ -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 @@ -244,7 +244,7 @@ instance ofRestrict {X : TopCat} (Y : PresheafedSpace C) {f : X ⟶ Y.carrier} @[elementwise, simp] theorem ofRestrict_invApp {C : Type*} [Category C] (X : PresheafedSpace C) {Y : TopCat} {f : Y ⟶ TopCat.of X.carrier} (h : OpenEmbedding f) (U : Opens (X.restrict h).carrier) : - (PresheafedSpace.IsOpenImmersion.ofRestrict X h).invApp U = 𝟙 _ := by + (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 _ @@ -290,7 +290,7 @@ def pullbackConeOfLeftFst : 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 @@ -515,16 +515,17 @@ open CategoryTheory.Limits.WalkingCospan section ToSheafedSpace variable {X : PresheafedSpace C} (Y : SheafedSpace C) -variable (f : X ⟶ Y.toPresheafedSpace) [H : IsOpenImmersion f] /-- If `X ⟶ Y` is an open immersion, and `Y` is a SheafedSpace, then so is `X`. -/ -def toSheafedSpace : SheafedSpace C where +def toSheafedSpace (f : X ⟶ Y.toPresheafedSpace) [H : IsOpenImmersion f] : SheafedSpace C where IsSheaf := by apply TopCat.Presheaf.isSheaf_of_iso (sheafIsoOfIso (isoRestrict f).symm).symm apply TopCat.Sheaf.pushforward_sheaf_of_sheaf exact (Y.restrict H.base_open).IsSheaf toPresheafedSpace := X +variable (f : X ⟶ Y.toPresheafedSpace) [H : IsOpenImmersion f] + @[simp] theorem toSheafedSpace_toPresheafedSpace : (toSheafedSpace Y f).toPresheafedSpace = X := rfl @@ -738,7 +739,7 @@ theorem of_stalk_iso {X Y : SheafedSpace C} (f : X ⟶ Y) (hf : OpenEmbedding f. delta PresheafedSpace.Hom.stalkMap at H haveI H' := TopCat.Presheaf.stalkPushforward.stalkPushforward_iso_of_openEmbedding C hf X.presheaf y - have := @IsIso.comp_isIso _ _ _ _ _ _ _ H (@IsIso.inv_isIso _ _ _ _ _ H') + have := IsIso.comp_isIso' H (@IsIso.inv_isIso _ _ _ _ _ H') rwa [Category.assoc, IsIso.hom_inv_id, Category.comp_id] at this } end OfStalkIso @@ -771,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 @@ -793,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))) := @@ -817,7 +818,7 @@ instance ofRestrict {X : TopCat} (Y : SheafedSpace C) {f : X ⟶ Y.carrier} @[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 = 𝟙 _ := + (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. -/ @@ -945,6 +946,8 @@ instance mono : Mono f := instance : SheafedSpace.IsOpenImmersion (LocallyRingedSpace.forgetToSheafedSpace.map f) := H +-- note to reviewers: is there a `count_heartbeats` for this? +set_option synthInstance.maxHeartbeats 30000 in /-- An explicit pullback cone over `cospan f g` if `f` is an open immersion. -/ def pullbackConeOfLeft : PullbackCone f g := by refine PullbackCone.mk ?_ @@ -963,6 +966,7 @@ def pullbackConeOfLeft : PullbackCone f g := by instance : LocallyRingedSpace.IsOpenImmersion (pullbackConeOfLeft f g).snd := show PresheafedSpace.IsOpenImmersion (Y.toPresheafedSpace.ofRestrict _) by infer_instance +set_option synthInstance.maxHeartbeats 80000 in /-- The constructed `pullbackConeOfLeft` is indeed limiting. -/ def pullbackConeOfLeftIsLimit : IsLimit (pullbackConeOfLeft f g) := PullbackCone.isLimitAux' _ fun s => by @@ -981,7 +985,8 @@ def pullbackConeOfLeftIsLimit : IsLimit (pullbackConeOfLeft f g) := change _ = _ ≫ s.snd.1.stalkMap x at this rw [PresheafedSpace.stalkMap.comp, ← IsIso.eq_inv_comp] at this rw [this] - infer_instance + -- TODO: This instance is found by `infer_instance` before #6045. + apply CommRingCat.isLocalRingHom_comp · intro m _ h₂ rw [← cancel_mono (pullbackConeOfLeft f g).snd] exact h₂.trans <| LocallyRingedSpace.Hom.ext @@ -1086,7 +1091,7 @@ theorem pullback_snd_isIso_of_range_subset (H' : Set.range g.1.base ⊆ Set.rang erw [← PreservesPullback.iso_hom_snd (LocallyRingedSpace.forgetToSheafedSpace ⋙ SheafedSpace.forgetToPresheafedSpace) f g] -- Porting note: was `inferInstance` - exact @IsIso.comp_isIso _ _ _ _ _ _ _ _ <| + exact IsIso.comp_isIso' inferInstance <| PresheafedSpace.IsOpenImmersion.pullback_snd_isIso_of_range_subset _ _ H' /-- The universal property of open immersions: @@ -1153,7 +1158,7 @@ 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) [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 @@ -1179,21 +1184,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) = + inv (H.invApp _ U) = f.1.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.1.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 @@ -1201,7 +1206,7 @@ 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.1.c.app (op U) ≫ H.invApp _ ((Opens.map f.1.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))) := @@ -1210,7 +1215,7 @@ theorem app_invApp (U : Opens Y) : /-- 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) = + f.1.c.app (op U) ≫ H.invApp _ ((Opens.map f.1.base).obj U) = Y.presheaf.map (eqToHom <| le_antisymm (Set.image_preimage_subset f.1.base U.1) <| @@ -1225,7 +1230,7 @@ instance ofRestrict {X : TopCat} (Y : LocallyRingedSpace) {f : X ⟶ Y.carrier} @[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 = 𝟙 _ := + (LocallyRingedSpace.IsOpenImmersion.ofRestrict X h).invApp _ U = 𝟙 _ := PresheafedSpace.IsOpenImmersion.ofRestrict_invApp _ h U instance stalk_iso (x : X) : IsIso (f.stalkMap x) := diff --git a/Mathlib/Geometry/RingedSpace/PresheafedSpace.lean b/Mathlib/Geometry/RingedSpace/PresheafedSpace.lean index b94f7d8b249c7..43d40b52b040c 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] @@ -340,7 +340,7 @@ theorem restrict_top_presheaf (X : PresheafedSpace C) : (X.restrict (Opens.openEmbedding ⊤)).presheaf = (Opens.inclusionTopIso X.carrier).inv _* X.presheaf := by dsimp - rw [Opens.inclusion_top_functor X.carrier] + rw [Opens.inclusion'_top_functor X.carrier] rfl theorem ofRestrict_top_c (X : PresheafedSpace C) : diff --git a/Mathlib/Geometry/RingedSpace/PresheafedSpace/Gluing.lean b/Mathlib/Geometry/RingedSpace/PresheafedSpace/Gluing.lean index be48cb8051370..93d358233ae90 100644 --- a/Mathlib/Geometry/RingedSpace/PresheafedSpace/Gluing.lean +++ b/Mathlib/Geometry/RingedSpace/PresheafedSpace/Gluing.lean @@ -37,7 +37,7 @@ Analogous results are also provided for `SheafedSpace` and `LocallyRingedSpace`. ## Implementation details -Almost the whole file is dedicated to showing tht `ι i` is an open immersion. The fact that +Almost the whole file is dedicated to showing that `ι i` is an open immersion. The fact that this is an open embedding of topological spaces follows from `Mathlib/Topology/Gluing.lean`, and it remains to construct `Γ(𝒪_{U_i}, U) ⟶ Γ(𝒪_X, ι i '' U)` for each `U ⊆ U i`. Since `Γ(𝒪_X, ι i '' U)` is the limit of `diagram_over_open`, the components of the structure @@ -140,16 +140,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 +160,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, @@ -271,7 +270,7 @@ def opensImagePreimageMap (i j : D.J) (U : Opens (D.U i).carrier) : (Opens.map (𝖣.ι j).base).obj ((D.ι_openEmbedding 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) : @@ -334,9 +333,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 +367,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 +379,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 } } @@ -436,11 +437,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 +465,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) : diff --git a/Mathlib/Geometry/RingedSpace/PresheafedSpace/HasColimits.lean b/Mathlib/Geometry/RingedSpace/PresheafedSpace/HasColimits.lean index 1a3dd8fdd7585..ce942b2c84104 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 @@ -97,7 +97,7 @@ def pushforwardDiagramToColimit (F : J ⥤ PresheafedSpace.{_, _, v} C) : obj j := op (colimit.ι (F ⋙ PresheafedSpace.forget C) j _* (F.obj j).presheaf) map {j j'} f := ((pushforward C (colimit.ι (F ⋙ PresheafedSpace.forget C) j')).map (F.map f).c ≫ - (Pushforward.comp ((F ⋙ PresheafedSpace.forget C).map f) + (Pushforward.comp ((F ⋙ PresheafedSpace.forget C).map f) (colimit.ι (F ⋙ PresheafedSpace.forget C) j') (F.obj j).presheaf).inv ≫ (pushforwardEq (colimit.w (F ⋙ PresheafedSpace.forget C) f) (F.obj j).presheaf).hom).op map_id j := by @@ -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..b77aabfada5a7 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) := @@ -226,7 +226,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..12c20e0348392 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 @@ -71,8 +68,8 @@ def restrictStalkIso {U : TopCat} (X : PresheafedSpace.{_, _, v} C) {f : U ⟶ ( @[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⟩⟩ := + (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⟩) @@ -81,9 +78,9 @@ theorem restrictStalkIso_hom_eq_germ {U : TopCat} (X : PresheafedSpace.{_, _, v} @[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⟩⟩ ≫ + 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) @@ -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 0b848d11ae3ab..5ee8a835a60c4 100644 --- a/Mathlib/GroupTheory/Abelianization.lean +++ b/Mathlib/GroupTheory/Abelianization.lean @@ -3,8 +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, Michael Howes -/ -import Mathlib.GroupTheory.Commutator +import Mathlib.Data.Finite.Card import Mathlib.GroupTheory.Finiteness +import Mathlib.GroupTheory.Commutator.Basic /-! # The abelianization of a group @@ -124,7 +125,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 diff --git a/Mathlib/GroupTheory/Archimedean.lean b/Mathlib/GroupTheory/Archimedean.lean index 77957e91b3685..4105f66700e0c 100644 --- a/Mathlib/GroupTheory/Archimedean.lean +++ b/Mathlib/GroupTheory/Archimedean.lean @@ -25,70 +25,81 @@ 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} := diff --git a/Mathlib/GroupTheory/ArchimedeanDensely.lean b/Mathlib/GroupTheory/ArchimedeanDensely.lean new file mode 100644 index 0000000000000..8b00a52cd33de --- /dev/null +++ b/Mathlib/GroupTheory/ArchimedeanDensely.lean @@ -0,0 +1,235 @@ +/- +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.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 ordered + +This file proves a few additional facts about linearly ordered additive groups which satisfy the + `Archimedean` property -- + they are either order-isomorphic and additvely isomorphic to the integers, + or they are densely ordered. + +They are placed here in a separate file (rather than incorporated as a continuation of +`GroupTheory.Archimedean`) because they rely on some imports from pointwise lemmas. +-/ + +open Multiplicative Set + +-- no earlier file imports the necessary requirements for the next two + +/-- The subgroup generated by an element of a group equals the set of +integer powers of the element, such that each power is a unique element. +This is the stronger version of `Subgroup.mem_closure_singleton`. -/ +@[to_additive "The additive subgroup generated by an element of an additive group equals the set of +integer multiples of the element, such that each multiple is a unique element. +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 + 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 +is isomorphic (and order-isomorphic) to the closure of an element in the other group. -/ +@[to_additive "In two linearly ordered additive groups, the closure of an element of one group +is isomorphic (and order-isomorphic) to the closure of an element in the other group."] +noncomputable def LinearOrderedCommGroup.closure_equiv_closure {G G' : Type*} + [LinearOrderedCommGroup G] [LinearOrderedCommGroup G'] (x : G) (y : G') (hxy : x = 1 ↔ y = 1) : + closure ({x} : Set G) ≃*o closure ({y} : Set G') := + if hx : x = 1 then by + refine ⟨⟨⟨fun _ ↦ ⟨1, by simp [hxy.mp hx]⟩, fun _ ↦ ⟨1, by simp [hx]⟩, ?_, ?_⟩, ?_⟩, ?_⟩ + · intro ⟨a, ha⟩ + simpa [hx, closure_singleton_one, eq_comm] using ha + · intro ⟨a, ha⟩ + simpa [hxy.mp hx, closure_singleton_one, eq_comm] using ha + · intros + simp + · intro ⟨a, ha⟩ ⟨b, hb⟩ + simp only [hx, closure_singleton_one, mem_bot] at ha hb + simp [ha, hb] + else by + set x' := max x x⁻¹ with hx' + have xpos : 1 < x' := by + simp [hx', eq_comm, hx] + set y' := max y y⁻¹ with hy' + have ypos : 1 < y' := by + simp [hy', eq_comm, ← hxy, hx] + have hxc : closure {x} = closure {x'} := by + rcases max_cases x x⁻¹ with H|H <;> + simp [hx', H.left] + have hyc : closure {y} = closure {y'} := by + rcases max_cases y y⁻¹ with H|H <;> + simp [hy', H.left] + refine ⟨⟨⟨ + fun a ↦ ⟨y' ^ ((mem_closure_singleton).mp + (by simpa [hxc] using a.prop)).choose, ?_⟩, + fun a ↦ ⟨x' ^ ((mem_closure_singleton).mp + (by simpa [hyc] using a.prop)).choose, ?_⟩, + ?_, ?_⟩, ?_⟩, ?_⟩ + · rw [hyc, mem_closure_singleton] + exact ⟨_, rfl⟩ + · rw [hxc, mem_closure_singleton] + exact ⟨_, rfl⟩ + · intro a + generalize_proofs A B C D + rw [Subtype.ext_iff, ← (C a).choose_spec, zpow_right_inj xpos, + ← zpow_right_inj ypos, (A ⟨_, D a⟩).choose_spec] + · intro a + generalize_proofs A B C D + rw [Subtype.ext_iff, ← (C a).choose_spec, zpow_right_inj ypos, + ← zpow_right_inj xpos, (A ⟨_, D a⟩).choose_spec] + · intro a b + generalize_proofs A B C D E F + simp only [Submonoid.coe_mul, coe_toSubmonoid, Submonoid.mk_mul_mk, Subtype.mk.injEq, + coe_mul, MulMemClass.mk_mul_mk, Subtype.ext_iff] + rw [← zpow_add, zpow_right_inj ypos, ← zpow_right_inj xpos, zpow_add, + (A a).choose_spec, (A b).choose_spec, (A (a * b)).choose_spec] + simp + · intro a b + simp only [MulEquiv.coe_mk, Equiv.coe_fn_mk, Subtype.mk_le_mk] + 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*} [LinearOrderedCommGroup G] [MulArchimedean G] + +@[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 := Subgroup.cyclic_of_min h + have ha : a ∈ closure ({b} : Set G) := by + simp [← this] + rw [mem_closure_singleton] at ha + obtain ⟨n, rfl⟩ := ha + have := h.left + simp only [mem_closure_singleton, mem_setOf_eq, ← mul_zsmul] at this + obtain ⟨m, hm⟩ := this.left + have key : m * n = 1 := by + 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, mabs] + · wlog ha : 1 ≤ a generalizing a + · convert @this (a⁻¹) ?_ (by simpa using le_of_not_le ha) using 4 + · simp + · 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 [← 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.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 {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 + let e : G ≃+o (⊤ : AddSubgroup G) := ⟨AddSubsemigroup.topEquiv.symm, + (AddEquiv.strictMono_symm AddSubsemigroup.strictMono_topEquiv).le_iff_le⟩ + let e' : (⊤ : AddSubgroup G) ≃+o AddSubgroup.closure {x} := + ⟨AddEquiv.subsemigroupCongr (by simp [this]), + (AddEquiv.strictMono_subsemigroupCongr _).le_iff_le⟩ + let g : (⊤ : AddSubgroup ℤ) ≃+o ℤ := ⟨AddSubsemigroup.topEquiv, + (AddSubsemigroup.strictMono_topEquiv).le_iff_le⟩ + let g' : AddSubgroup.closure ({1} : Set ℤ) ≃+o (⊤ : AddSubgroup ℤ) := + ⟨(.subsemigroupCongr (by simp [AddSubgroup.closure_singleton_int_one_eq_top])), + (AddEquiv.strictMono_subsemigroupCongr _).le_iff_le⟩ + let f := closure_equiv_closure x (1 : ℤ) (by simp [h.left.ne']) + exact ((((e.trans e').trans f).trans g').trans g : G ≃+o ℤ) + +/-- 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 (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 + exact Or.inl ⟨(int_orderAddMonoidIso_of_isLeast_pos hx)⟩ + · push_neg at H + refine Or.inr ⟨?_⟩ + intro x y hxy + specialize H (y - x) + obtain ⟨z, hz⟩ : ∃ z : G, 0 < z ∧ z < y - x := by + contrapose! H + refine ⟨by simp [hxy], fun _ ↦ H _⟩ + refine ⟨x + z, ?_, ?_⟩ + · simp [hz.left] + · simpa [lt_sub_iff_add_lt'] using hz.right + +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⟩ + +/-- Any nontrivial (has other than 0 and 1) linearly ordered mul-archimedean group with zero is +either isomorphic (and order-isomorphic) to `ℤₘ₀`, or is densely ordered. -/ +lemma LinearOrderedCommGroupWithZero.discrete_or_denselyOrdered (G : Type*) + [LinearOrderedCommGroupWithZero G] [Nontrivial Gˣ] [MulArchimedean G] : + Nonempty (G ≃*o ℤₘ₀) ∨ DenselyOrdered G := by + classical + refine (LinearOrderedCommGroup.discrete_or_denselyOrdered Gˣ).imp ?_ ?_ + · intro ⟨f⟩ + refine ⟨OrderMonoidIso.trans + ⟨WithZero.withZeroUnitsEquiv.symm, ?_⟩ ⟨f.withZero, ?_⟩⟩ + · intro + simp only [WithZero.withZeroUnitsEquiv, MulEquiv.symm_mk, + MulEquiv.toEquiv_eq_coe, Equiv.toFun_as_coe, EquivLike.coe_coe, MulEquiv.coe_mk, + Equiv.coe_fn_symm_mk ] + split_ifs <;> + simp_all [← Units.val_le_val] + · intro a b + induction a <;> induction b <;> + simp [MulEquiv.withZero] + · 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] diff --git a/Mathlib/GroupTheory/Commutator.lean b/Mathlib/GroupTheory/Commutator/Basic.lean similarity index 92% rename from Mathlib/GroupTheory/Commutator.lean rename to Mathlib/GroupTheory/Commutator/Basic.lean index 9f7244cd843dc..8e4f605d4f565 100644 --- a/Mathlib/GroupTheory/Commutator.lean +++ b/Mathlib/GroupTheory/Commutator/Basic.lean @@ -3,7 +3,6 @@ Copyright (c) 2021 Jordan Brown, Thomas Browning, Patrick Lutz. All rights reser Released under Apache 2.0 license as described in the file LICENSE. Authors: Jordan Brown, Thomas Browning, Patrick Lutz -/ -import Mathlib.Algebra.Group.Subgroup.Finite import Mathlib.GroupTheory.Subgroup.Centralizer import Mathlib.Tactic.Group @@ -20,6 +19,8 @@ is the subgroup of `G` generated by the commutators `h₁ * h₂ * h₁⁻¹ * h * `⁅H₁, H₂⁆` : the commutator of the subgroups `H₁` and `H₂`. -/ +assert_not_exists Cardinal +assert_not_exists Multiset variable {G G' F : Type*} [Group G] [Group G'] [FunLike F G G'] [MonoidHomClass F G G'] variable (f : F) {g₁ g₂ g₃ g : G} @@ -186,25 +187,6 @@ theorem commutator_pi_pi_le {η : Type*} {Gs : η → Type*} [∀ i, Group (Gs i ⁅Subgroup.pi Set.univ H, Subgroup.pi Set.univ K⁆ ≤ Subgroup.pi Set.univ fun i => ⁅H i, K i⁆ := commutator_le.mpr fun _p hp _q hq i hi => commutator_mem_commutator (hp i hi) (hq i hi) -/-- The commutator of a finite direct product is contained in the direct product of the commutators. --/ -theorem commutator_pi_pi_of_finite {η : Type*} [Finite η] {Gs : η → Type*} [∀ i, Group (Gs i)] - (H K : ∀ i, Subgroup (Gs i)) : ⁅Subgroup.pi Set.univ H, Subgroup.pi Set.univ K⁆ = - Subgroup.pi Set.univ fun i => ⁅H i, K i⁆ := by - classical - apply le_antisymm (commutator_pi_pi_le H K) - rw [pi_le_iff] - intro i hi - rw [map_commutator] - apply commutator_mono <;> - · rw [le_pi_iff] - intro j _hj - rintro _ ⟨_, ⟨x, hx, rfl⟩, rfl⟩ - by_cases h : j = i - · subst h - simpa using hx - · simp [h, one_mem] - end Subgroup variable (G) diff --git a/Mathlib/GroupTheory/Commutator/Finite.lean b/Mathlib/GroupTheory/Commutator/Finite.lean new file mode 100644 index 0000000000000..0109ea7274cb1 --- /dev/null +++ b/Mathlib/GroupTheory/Commutator/Finite.lean @@ -0,0 +1,35 @@ +/- +Copyright (c) 2021 Jordan Brown, Thomas Browning, Patrick Lutz. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jordan Brown, Thomas Browning, Patrick Lutz +-/ +import Mathlib.Algebra.Group.Subgroup.Finite +import Mathlib.GroupTheory.Commutator.Basic + +/-! +The commutator of a finite direct product is contained in the direct product of the commutators. +-/ + + +namespace Subgroup + +/-- The commutator of a finite direct product is contained in the direct product of the commutators. +-/ +theorem commutator_pi_pi_of_finite {η : Type*} [Finite η] {Gs : η → Type*} [∀ i, Group (Gs i)] + (H K : ∀ i, Subgroup (Gs i)) : ⁅Subgroup.pi Set.univ H, Subgroup.pi Set.univ K⁆ = + Subgroup.pi Set.univ fun i => ⁅H i, K i⁆ := by + classical + apply le_antisymm (commutator_pi_pi_le H K) + rw [pi_le_iff] + intro i hi + rw [map_commutator] + apply commutator_mono <;> + · rw [le_pi_iff] + intro j _hj + rintro _ ⟨_, ⟨x, hx, rfl⟩, rfl⟩ + by_cases h : j = i + · subst h + simpa using hx + · simp [h, one_mem] + +end Subgroup diff --git a/Mathlib/GroupTheory/CommutingProbability.lean b/Mathlib/GroupTheory/CommutingProbability.lean index 95d545452fa22..dc3739fd84c36 100644 --- a/Mathlib/GroupTheory/CommutingProbability.lean +++ b/Mathlib/GroupTheory/CommutingProbability.lean @@ -4,7 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Thomas Browning -/ import Mathlib.GroupTheory.Abelianization +import Mathlib.GroupTheory.GroupAction.CardCommute import Mathlib.GroupTheory.SpecificGroups.Dihedral +import Mathlib.Tactic.FieldSimp import Mathlib.Tactic.LinearCombination import Mathlib.Tactic.Qify @@ -66,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] @@ -95,7 +97,7 @@ variable [Finite G] (H : Subgroup G) theorem Subgroup.commProb_subgroup_le : commProb H ≤ commProb G * (H.index : ℚ) ^ 2 := by /- After rewriting with `commProb_def`, we reduce to showing that `G` has at least as many commuting pairs as `H`. -/ - rw [commProb_def, commProb_def, div_le_iff, mul_assoc, ← mul_pow, ← Nat.cast_mul, + rw [commProb_def, commProb_def, div_le_iff₀, mul_assoc, ← mul_pow, ← Nat.cast_mul, mul_comm H.index, H.card_mul_index, div_mul_cancel₀, Nat.cast_le] · refine Finite.card_le_of_injective (fun p ↦ ⟨⟨p.1.1, p.1.2⟩, Subtype.ext_iff.mp p.2⟩) ?_ exact fun p q h ↦ by simpa only [Subtype.ext_iff, Prod.ext_iff] using h @@ -105,7 +107,7 @@ theorem Subgroup.commProb_subgroup_le : commProb H ≤ commProb G * (H.index : theorem Subgroup.commProb_quotient_le [H.Normal] : commProb (G ⧸ H) ≤ commProb G * Nat.card H := by /- After rewriting with `commProb_def'`, we reduce to showing that `G` has at least as many conjugacy classes as `G ⧸ H`. -/ - rw [commProb_def', commProb_def', div_le_iff, mul_assoc, ← Nat.cast_mul, ← Subgroup.index, + rw [commProb_def', commProb_def', div_le_iff₀, mul_assoc, ← Nat.cast_mul, ← Subgroup.index, H.card_mul_index, div_mul_cancel₀, Nat.cast_le] · apply Finite.card_le_of_surjective show Function.Surjective (ConjClasses.map (QuotientGroup.mk' H)) @@ -116,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 @@ -129,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) @@ -163,8 +166,8 @@ lemma reciprocalFactors_odd {n : ℕ} (h1 : n ≠ 1) (h2 : Odd n) : reciprocalFactors n = n % 4 * n :: reciprocalFactors (n / 4 + 1) := by have h0 : n ≠ 0 := by rintro rfl - norm_num at h2 - rw [reciprocalFactors, dif_neg h0, dif_neg h1, if_neg (Nat.odd_iff_not_even.mp h2)] + norm_num [← Nat.not_even_iff_odd] at h2 + rw [reciprocalFactors, dif_neg h0, dif_neg h1, if_neg (Nat.not_even_iff_odd.2 h2)] /-- A finite product of Dihedral groups. -/ abbrev Product (l : List ℕ) : Type := diff --git a/Mathlib/GroupTheory/Congruence/Basic.lean b/Mathlib/GroupTheory/Congruence/Basic.lean index f9137be6f7410..fe6cfe5261d0a 100644 --- a/Mathlib/GroupTheory/Congruence/Basic.lean +++ b/Mathlib/GroupTheory/Congruence/Basic.lean @@ -110,12 +110,11 @@ variable [Mul M] [Mul N] [Mul P] (c : Con M) 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 + coe_injective' x y h := by rcases x with ⟨⟨x, _⟩, _⟩ rcases y with ⟨⟨y, _⟩, _⟩ have : x = y := h @@ -151,7 +150,7 @@ theorem rel_mk {s : Setoid M} {h a b} : Con.mk s h a b ↔ r a b := @[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 x c => c x.1 x.2⟩ + ⟨fun c x => c x.1 x.2⟩ variable {c} @@ -377,7 +376,7 @@ theorem coe_sInf (S : Set (Con M)) : @[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] + rw [iInf, coe_sInf, ← Set.range_comp, sInf_range, Function.comp_def] @[to_additive] instance : PartialOrder (Con M) where diff --git a/Mathlib/GroupTheory/CoprodI.lean b/Mathlib/GroupTheory/CoprodI.lean index 71732e3b60cb4..67d5fdc6738bd 100644 --- a/Mathlib/GroupTheory/CoprodI.lean +++ b/Mathlib/GroupTheory/CoprodI.lean @@ -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 @@ -772,9 +772,10 @@ theorem mulHead_head {i j : ι} (w : NeWord M i j) (x : M i) (hnotone : x * w.he theorem mulHead_prod {i j : ι} (w : NeWord M i j) (x : M i) (hnotone : x * w.head ≠ 1) : (mulHead w x hnotone).prod = of x * w.prod := by unfold mulHead - induction' w with _ _ _ _ _ _ _ _ _ _ w_ih_w₁ w_ih_w₂ - · simp [mulHead, replaceHead] - · specialize w_ih_w₁ _ hnotone + induction w with + | singleton => simp [mulHead, replaceHead] + | append _ _ _ w_ih_w₁ w_ih_w₂ => + specialize w_ih_w₁ _ hnotone clear w_ih_w₂ simp? [replaceHead, ← mul_assoc] at * says simp only [replaceHead, head, append_prod, ← mul_assoc] at * diff --git a/Mathlib/GroupTheory/Coset.lean b/Mathlib/GroupTheory/Coset/Basic.lean similarity index 92% rename from Mathlib/GroupTheory/Coset.lean rename to Mathlib/GroupTheory/Coset/Basic.lean index a4c0c84b15acb..44bb4b0f21528 100644 --- a/Mathlib/GroupTheory/Coset.lean +++ b/Mathlib/GroupTheory/Coset/Basic.lean @@ -1,13 +1,11 @@ /- 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.Actions import Mathlib.Algebra.Group.Subgroup.MulOpposite import Mathlib.GroupTheory.GroupAction.Basic -import Mathlib.SetTheory.Cardinal.Finite /-! # Cosets @@ -40,6 +38,7 @@ If instead `G` is an additive group, we can write (with `open scoped Pointwise` Properly merge with pointwise actions on sets, by renaming and deduplicating lemmas as appropriate. -/ +assert_not_exists Cardinal open Function MulOpposite Set open scoped Pointwise @@ -236,7 +235,7 @@ def leftRel : Setoid α := variable {s} @[to_additive] -theorem leftRel_apply {x y : α} : @Setoid.r _ (leftRel s) x y ↔ x⁻¹ * y ∈ s := +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 @@ -247,13 +246,13 @@ theorem leftRel_apply {x y : α} : @Setoid.r _ (leftRel s) x y ↔ x⁻¹ * y variable (s) @[to_additive] -theorem leftRel_eq : @Setoid.r _ (leftRel s) = fun x y => x⁻¹ * y ∈ s := +theorem leftRel_eq : ⇑(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 @@ -280,7 +279,7 @@ def rightRel : Setoid α := variable {s} @[to_additive] -theorem rightRel_apply {x y : α} : @Setoid.r _ (rightRel s) x y ↔ y * x⁻¹ ∈ s := +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] @@ -289,13 +288,13 @@ theorem rightRel_apply {x y : α} : @Setoid.r _ (rightRel s) x y ↔ y * x⁻¹ variable (s) @[to_additive] -theorem rightRel_eq : @Setoid.r _ (rightRel s) = fun x y => y * x⁻¹ ∈ s := +theorem rightRel_eq : ⇑(rightRel s) = fun x y => y * x⁻¹ ∈ s := funext₂ <| by simp only [eq_iff_iff] apply rightRel_apply 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 @@ -392,7 +391,7 @@ instance (s : Subgroup α) : Inhabited (α ⧸ s) := @[to_additive] protected theorem eq {a b : α} : (a : α ⧸ s) = b ↔ a⁻¹ * b ∈ s := calc - _ ↔ @Setoid.r _ (leftRel s) a b := Quotient.eq'' + _ ↔ leftRel s a b := Quotient.eq'' _ ↔ _ := by rw [leftRel_apply] @[to_additive (attr := deprecated (since := "2024-08-04"))] alias eq' := QuotientGroup.eq @@ -403,6 +402,21 @@ theorem out_eq' (a : α ⧸ s) : mk a.out' = a := variable (s) +/-- 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 + /- 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'`. -/ @@ -438,6 +452,12 @@ theorem preimage_image_mk_eq_iUnion_image (N : Subgroup α) (s : Set α) : 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 @@ -609,41 +629,6 @@ theorem quotientiInfEmbedding_apply_mk {ι : Type*} (f : ι → Subgroup α) (g quotientiInfEmbedding f (QuotientGroup.mk g) i = QuotientGroup.mk g := rfl -@[to_additive AddSubgroup.card_eq_card_quotient_mul_card_addSubgroup] -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 - -/-- **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."] -theorem card_subgroup_dvd_card (s : Subgroup α) : Nat.card s ∣ Nat.card α := by - classical simp [card_eq_card_quotient_mul_card_subgroup s, @dvd_mul_left ℕ] - -@[to_additive] -theorem card_quotient_dvd_card (s : Subgroup α) : Nat.card (α ⧸ s) ∣ Nat.card α := by - simp [card_eq_card_quotient_mul_card_subgroup s, @dvd_mul_right ℕ] - -variable {H : Type*} [Group H] - -@[to_additive] -theorem card_dvd_of_injective (f : α →* H) (hf : Function.Injective f) : - Nat.card α ∣ Nat.card H := by - classical calc - Nat.card α = Nat.card (f.range : Subgroup H) := Nat.card_congr (Equiv.ofInjective f hf) - _ ∣ Nat.card H := card_subgroup_dvd_card _ - -@[to_additive] -theorem card_dvd_of_le {H K : Subgroup α} (hHK : H ≤ K) : Nat.card H ∣ Nat.card K := - card_dvd_of_injective (inclusion hHK) (inclusion_injective hHK) - -@[to_additive] -theorem card_comap_dvd_of_injective (K : Subgroup H) (f : α →* H) - (hf : Function.Injective f) : Nat.card (K.comap f) ∣ Nat.card K := - calc Nat.card (K.comap f) = Nat.card ((K.comap f).map f) := - Nat.card_congr (equivMapOfInjective _ _ hf).toEquiv - _ ∣ Nat.card K := card_dvd_of_le (map_comap_le _ _) - end Subgroup namespace MonoidHom diff --git a/Mathlib/GroupTheory/Coset/Card.lean b/Mathlib/GroupTheory/Coset/Card.lean new file mode 100644 index 0000000000000..67a686a06e9b1 --- /dev/null +++ b/Mathlib/GroupTheory/Coset/Card.lean @@ -0,0 +1,52 @@ +/- +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.GroupTheory.Coset.Basic +import Mathlib.SetTheory.Cardinal.Finite + +/-! +# Lagrange's theorem: the order of a subgroup divides the order of the group. +-/ + +namespace Subgroup + +variable {α : Type*} [Group α] + +@[to_additive AddSubgroup.card_eq_card_quotient_mul_card_addSubgroup] +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 + +/-- **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."] +theorem card_subgroup_dvd_card (s : Subgroup α) : Nat.card s ∣ Nat.card α := by + classical simp [card_eq_card_quotient_mul_card_subgroup s, @dvd_mul_left ℕ] + +@[to_additive] +theorem card_quotient_dvd_card (s : Subgroup α) : Nat.card (α ⧸ s) ∣ Nat.card α := by + simp [card_eq_card_quotient_mul_card_subgroup s, @dvd_mul_right ℕ] + +variable {H : Type*} [Group H] + +@[to_additive] +theorem card_dvd_of_injective (f : α →* H) (hf : Function.Injective f) : + Nat.card α ∣ Nat.card H := by + classical calc + Nat.card α = Nat.card (f.range : Subgroup H) := Nat.card_congr (Equiv.ofInjective f hf) + _ ∣ Nat.card H := card_subgroup_dvd_card _ + +@[to_additive] +theorem card_dvd_of_le {H K : Subgroup α} (hHK : H ≤ K) : Nat.card H ∣ Nat.card K := + card_dvd_of_injective (inclusion hHK) (inclusion_injective hHK) + +@[to_additive] +theorem card_comap_dvd_of_injective (K : Subgroup H) (f : α →* H) + (hf : Function.Injective f) : Nat.card (K.comap f) ∣ Nat.card K := + calc Nat.card (K.comap f) = Nat.card ((K.comap f).map f) := + Nat.card_congr (equivMapOfInjective _ _ hf).toEquiv + _ ∣ Nat.card K := card_dvd_of_le (map_comap_le _ _) + +end Subgroup diff --git a/Mathlib/GroupTheory/CosetCover.lean b/Mathlib/GroupTheory/CosetCover.lean index c9cefdcb06558..03164c5973c5e 100644 --- a/Mathlib/GroupTheory/CosetCover.lean +++ b/Mathlib/GroupTheory/CosetCover.lean @@ -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')] diff --git a/Mathlib/GroupTheory/Coxeter/Basic.lean b/Mathlib/GroupTheory/Coxeter/Basic.lean index 5fc6d5c513a62..fd14569331ee8 100644 --- a/Mathlib/GroupTheory/Coxeter/Basic.lean +++ b/Mathlib/GroupTheory/Coxeter/Basic.lean @@ -8,6 +8,7 @@ import Mathlib.GroupTheory.PresentedGroup import Mathlib.GroupTheory.Coxeter.Matrix import Mathlib.Tactic.Ring import Mathlib.Tactic.Use +import Mathlib.Tactic.NormNum.DivMod /-! # Coxeter groups and Coxeter systems @@ -398,7 +399,7 @@ theorem alternatingWord_succ' (i i' : B) (m : ℕ) : · rw [alternatingWord] nth_rw 1 [ih i' i] rw [alternatingWord] - simp [Nat.even_add_one] + simp [Nat.even_add_one, ← Nat.not_even_iff_odd] @[simp] theorem length_alternatingWord (i i' : B) (m : ℕ) : @@ -436,10 +437,10 @@ theorem prod_alternatingWord_eq_prod_alternatingWord_sub (i i' : B) (m : ℕ) (h repeat rw [Int.mul_ediv_cancel _ (by norm_num)] rw [zpow_sub, zpow_natCast, simple_mul_simple_pow' cs i i', ← inv_zpow] simp - · have : ¬Even (2 * k + 1) := Int.odd_iff_not_even.mp ⟨k, rfl⟩ + · have : ¬Even (2 * k + 1) := Int.not_even_iff_odd.2 ⟨k, rfl⟩ rw [if_neg this] have : ¬Even (↑(M i i') * 2 - (2 * k + 1)) := - Int.odd_iff_not_even.mp ⟨↑(M i i') - k - 1, by ring⟩ + Int.not_even_iff_odd.2 ⟨↑(M i i') - k - 1, by ring⟩ rw [if_neg this] rw [(by ring : ↑(M i i') * 2 - (2 * k + 1) = -1 + (-k + ↑(M i i')) * 2), diff --git a/Mathlib/GroupTheory/Coxeter/Inversion.lean b/Mathlib/GroupTheory/Coxeter/Inversion.lean index 4901cbdf6ff8b..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 /-! @@ -300,13 +299,11 @@ theorem rightInvSeq_drop (ω : List B) (j : ℕ) : theorem leftInvSeq_take (ω : List B) (j : ℕ) : lis (ω.take j) = (lis ω).take j := by - obtain le | ge := Nat.le_or_ge j ω.length - · simp only [leftInvSeq_eq_reverse_rightInvSeq_reverse] - rw [List.take_reverse (by simpa)] - nth_rw 1 [← List.reverse_reverse ω] - rw [List.take_reverse (by simpa)] - simp [rightInvSeq_drop] - · rw [take_of_length_le ge, take_of_length_le (by simpa)] + simp only [leftInvSeq_eq_reverse_rightInvSeq_reverse] + rw [List.take_reverse] + nth_rw 1 [← List.reverse_reverse ω] + rw [List.take_reverse] + simp [rightInvSeq_drop] theorem isReflection_of_mem_rightInvSeq (ω : List B) {t : W} (ht : t ∈ ris ω) : cs.IsReflection t := by diff --git a/Mathlib/GroupTheory/Divisible.lean b/Mathlib/GroupTheory/Divisible.lean index 1dc47a2cc80bd..4276c6c3fd8b1 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 +import Mathlib.GroupTheory.QuotientGroup.Basic +import Mathlib.Tactic.NormNum.Eq /-! # Divisible Group and rootable group diff --git a/Mathlib/GroupTheory/DoubleCoset.lean b/Mathlib/GroupTheory/DoubleCoset.lean index 4b564ca369672..771be71a00bb9 100644 --- a/Mathlib/GroupTheory/DoubleCoset.lean +++ b/Mathlib/GroupTheory/DoubleCoset.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Birkbeck -/ import Mathlib.Algebra.Group.Subgroup.Pointwise -import Mathlib.GroupTheory.Coset +import Mathlib.GroupTheory.Coset.Basic /-! # Double cosets @@ -74,8 +74,8 @@ def Quotient (H K : Set G) : Type _ := theorem rel_iff {H K : Subgroup G} {x y : G} : (setoid ↑H ↑K).Rel x y ↔ ∃ a ∈ H, ∃ b ∈ K, y = a * x * b := Iff.trans - ⟨fun hxy => (congr_arg _ hxy).mpr (mem_doset_self H K y), fun hxy => (doset_eq_of_mem hxy).symm⟩ - mem_doset + ⟨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 @@ -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 801c4d8d5a2c0..f408bce7cb363 100644 --- a/Mathlib/GroupTheory/Exponent.lean +++ b/Mathlib/GroupTheory/Exponent.lean @@ -8,7 +8,7 @@ import Mathlib.Algebra.GCDMonoid.Finset import Mathlib.Algebra.GCDMonoid.Nat import Mathlib.Data.Nat.Factorization.Basic import Mathlib.Tactic.Peel -import Mathlib.Algebra.Order.Archimedean.Basic +import Mathlib.Algebra.Order.BigOperators.Ring.Finset /-! # Exponent of a group @@ -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 6ec1d539f832d..8ac8ceb36aec7 100644 --- a/Mathlib/GroupTheory/FiniteAbelian.lean +++ b/Mathlib/GroupTheory/FiniteAbelian.lean @@ -75,7 +75,7 @@ private def directSumNeZeroMulEquiv (ι : Type) [DecidableEq ι] (p : ι → ℕ · rw [map_zero, map_zero] · rw [DirectSum.toAddMonoid_of] split_ifs with h - · simp [(ZMod.subsingleton_iff.2 $ by rw [h, pow_zero]).elim x 0] + · simp [(ZMod.subsingleton_iff.2 <| by rw [h, pow_zero]).elim x 0] · simp_rw [directSumNeZeroMulHom, DirectSum.toAddMonoid_of] · rw [map_add, map_add, hx, hy] map_add' := map_add (directSumNeZeroMulHom p n) @@ -131,7 +131,7 @@ theorem equiv_directSum_zmod_of_finite [Finite G] : obtain ⟨n, ι, fι, p, hp, e, ⟨f⟩⟩ := equiv_free_prod_directSum_zmod G cases' n with n · have : Unique (Fin Nat.zero →₀ ℤ) := - { uniq := by simp only [Nat.zero_eq, eq_iff_true_of_subsingleton]; trivial } + { uniq := by simp only [eq_iff_true_of_subsingleton]; trivial } exact ⟨ι, fι, p, hp, e, ⟨f.trans AddEquiv.uniqueProd⟩⟩ · haveI := @Fintype.prodLeft _ _ _ (Fintype.ofEquiv G f.toEquiv) _ exact @@ -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 86ceab0ad5626..6d7da785053a0 100644 --- a/Mathlib/GroupTheory/Finiteness.lean +++ b/Mathlib/GroupTheory/Finiteness.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Riccardo Brasca -/ import Mathlib.Data.Set.Pointwise.Finite -import Mathlib.GroupTheory.QuotientGroup +import Mathlib.GroupTheory.QuotientGroup.Basic +import Mathlib.SetTheory.Cardinal.Finite /-! # Finitely generated monoids and groups diff --git a/Mathlib/GroupTheory/FixedPointFree.lean b/Mathlib/GroupTheory/FixedPointFree.lean index 49ae5c66a0f12..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 @@ -84,7 +84,7 @@ theorem odd_card_of_involutive (hφ : FixedPointFree φ) (h2 : Function.Involuti Odd (Nat.card G) := by have := Fintype.ofFinite G by_contra h - rw [← Nat.even_iff_not_odd, even_iff_two_dvd, Nat.card_eq_fintype_card] at h + rw [Nat.not_odd_iff_even, even_iff_two_dvd, Nat.card_eq_fintype_card] at h obtain ⟨g, hg⟩ := exists_prime_orderOf_dvd_card 2 h exact hφ.orderOf_ne_two_of_involutive h2 g hg diff --git a/Mathlib/GroupTheory/FreeAbelianGroup.lean b/Mathlib/GroupTheory/FreeAbelianGroup.lean index 2fc7ca86f0f66..475386ea7d3df 100644 --- a/Mathlib/GroupTheory/FreeAbelianGroup.lean +++ b/Mathlib/GroupTheory/FreeAbelianGroup.lean @@ -419,7 +419,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 74da573c0472e..4dfea2fbf13f6 100644 --- a/Mathlib/GroupTheory/FreeGroup/Basic.lean +++ b/Mathlib/GroupTheory/FreeGroup/Basic.lean @@ -128,7 +128,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} : @@ -287,7 +287,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 @@ -312,8 +313,8 @@ theorem inv_of_red_of_ne {x1 b1 x2 b2} (H1 : (x1, b1) ≠ (x2, b2)) open List -- for <+ notation @[to_additive] -theorem Step.sublist (H : Red.Step L₁ L₂) : Sublist L₂ L₁ := by - cases H; simp; constructor; constructor; rfl +theorem Step.sublist (H : Red.Step L₁ L₂) : L₂ <+ L₁ := by + cases H; simp /-- If `w₁ w₂` are words such that `w₁` reduces to `w₂`, then `w₂` is a sublist of `w₁`. -/ @[to_additive "If `w₁ w₂` are words such that `w₁` reduces to `w₂`, then `w₂` is a sublist of @@ -383,8 +384,8 @@ theorem eqvGen_step_iff_join_red : EqvGen Red.Step L₁ L₂ ↔ Join Red L₁ L (fun h => have : EqvGen (Join Red) L₁ L₂ := h.mono fun _ _ => join_red_of_step equivalence_join_red.eqvGen_iff.1 this) - (join_of_equivalence (EqvGen.is_equivalence _) fun _ _ => - reflTransGen_of_equivalence (EqvGen.is_equivalence _) EqvGen.rel) + (join_of_equivalence (Relation.EqvGen.is_equivalence _) fun _ _ => + reflTransGen_of_equivalence (Relation.EqvGen.is_equivalence _) EqvGen.rel) end FreeGroup @@ -462,7 +463,7 @@ theorem invRev_length : (invRev L₁).length = L₁.length := by simp [invRev] @[to_additive (attr := simp)] theorem invRev_invRev : invRev (invRev L₁) = L₁ := by - simp [invRev, List.map_reverse, (· ∘ ·)] + simp [invRev, List.map_reverse, Function.comp_def] @[to_additive (attr := simp)] theorem invRev_empty : invRev ([] : List (α × Bool)) = [] := @@ -538,7 +539,7 @@ def of (x : α) : FreeGroup α := @[to_additive] theorem Red.exact : mk L₁ = mk L₂ ↔ Join Red L₁ L₂ := calc - mk L₁ = mk L₂ ↔ EqvGen Red.Step L₁ L₂ := Iff.intro (Quot.exact _) Quot.EqvGen_sound + mk L₁ = mk L₂ ↔ EqvGen Red.Step L₁ L₂ := Iff.intro Quot.eqvGen_exact Quot.eqvGen_sound _ ↔ Join Red L₁ L₂ := eqvGen_step_iff_join_red /-- The canonical map from the type to the free group is an injection. -/ @@ -571,7 +572,7 @@ def lift : (α → β) ≃ (FreeGroup α →* β) where MonoidHom.mk' (Quot.lift (Lift.aux f) fun L₁ L₂ => 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 +593,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} : @@ -669,7 +670,7 @@ theorem map.id' (x : FreeGroup α) : map (fun z => z) x = x := @[to_additive] theorem map.comp {γ : Type w} (f : α → β) (g : β → γ) (x) : map g (map f x) = map (g ∘ f) x := by - rcases x with ⟨L⟩; simp [(· ∘ ·)] + rcases x with ⟨L⟩; simp [Function.comp_def] @[to_additive (attr := simp)] theorem map.of {x} : map f (of x) = of (f x) := diff --git a/Mathlib/GroupTheory/FreeGroup/IsFreeGroup.lean b/Mathlib/GroupTheory/FreeGroup/IsFreeGroup.lean index ff82a3c54c8d9..5999f4a20b721 100644 --- a/Mathlib/GroupTheory/FreeGroup/IsFreeGroup.lean +++ b/Mathlib/GroupTheory/FreeGroup/IsFreeGroup.lean @@ -149,7 +149,7 @@ def ofLift {G : Type u} [Group G] (X : Type u) (of : X → G) /-- If a group satisfies the universal property of a free group with respect to a given type, then it admits a free group basis based on this type. Here -the universal property is expressed as in `IsFreeGroup.unique_lift`. -/ +the universal property is expressed as in `IsFreeGroup.unique_lift`. -/ def ofUniqueLift {G : Type u} [Group G] (X : Type u) (of : X → G) (h : ∀ {H : Type u} [Group H] (f : X → H), ∃! F : G →* H, ∀ a, F (of a) = f a) : FreeGroupBasis X G := @@ -212,7 +212,7 @@ theorem ext_hom ⦃f g : G →* H⦄ (h : ∀ a : Generators G, f (of a) = g (of 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. -/ +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 @@ -226,7 +226,7 @@ lemma ofLift {G : Type u} [Group G] (X : Type u) (of : X → G) (FreeGroupBasis.ofLift X of lift lift_of).isFreeGroup /-- 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.unique_lift`. -/ +it is free. Here the universal property is expressed as in `IsFreeGroup.unique_lift`. -/ lemma ofUniqueLift {G : Type u} [Group G] (X : Type u) (of : X → G) (h : ∀ {H : Type u} [Group H] (f : X → H), ∃! F : G →* H, ∀ a, F (of a) = f a) : IsFreeGroup G := diff --git a/Mathlib/GroupTheory/GroupAction/Basic.lean b/Mathlib/GroupTheory/GroupAction/Basic.lean index 70bf6218e1236..cc847556ec7f8 100644 --- a/Mathlib/GroupTheory/GroupAction/Basic.lean +++ b/Mathlib/GroupTheory/GroupAction/Basic.lean @@ -9,7 +9,6 @@ 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.Group /-! # Basic properties of group actions @@ -328,6 +327,10 @@ theorem mem_orbit_smul (g : G) (a : α) : a ∈ orbit G (g • a) := by 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 @@ -346,11 +349,10 @@ 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⟩ - simp_rw [Submonoid.smul_def, Subgroup.coe_toSubmonoid, orbit.coe_smul, ← Submonoid.smul_def] exact MulAction.mem_orbit _ g · rcases h with ⟨g, h⟩ - simp_rw [Submonoid.smul_def, Subgroup.coe_toSubmonoid, ← orbit.coe_smul, - ← Submonoid.smul_def, ← Subtype.ext_iff] at h + dsimp at h + erw [← orbit.coe_smul, ← Subtype.ext_iff] at h subst h exact MulAction.mem_orbit _ g @@ -564,12 +566,11 @@ lemma orbitRel.Quotient.mem_subgroup_orbit_iff {H : Subgroup G} {x : orbitRel.Qu {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⟩ - simp_rw [Submonoid.smul_def, Subgroup.coe_toSubmonoid, ← orbit.coe_smul, - ← Submonoid.smul_def, ← Subtype.ext_iff] at 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⟩ - simp_rw [Submonoid.smul_def, Subgroup.coe_toSubmonoid, orbit.coe_smul, ← Submonoid.smul_def] exact MulAction.mem_orbit _ g @[to_additive] @@ -771,6 +772,7 @@ theorem le_stabilizer_iff_smul_le (s : Set α) (H : Subgroup G) : theorem mem_stabilizer_of_finite_iff_smul_le (s : Set α) (hs : s.Finite) (g : G) : g ∈ stabilizer G s ↔ g • s ⊆ s := by haveI : Fintype s := Set.Finite.fintype hs + haveI : Finite (g • s : Set α) := Finite.Set.finite_image .. haveI : Fintype (g • s : Set α) := Fintype.ofFinite _ rw [mem_stabilizer_iff] constructor diff --git a/Mathlib/GroupTheory/GroupAction/BigOperators.lean b/Mathlib/GroupTheory/GroupAction/BigOperators.lean deleted file mode 100644 index 4ab2659b3a283..0000000000000 --- a/Mathlib/GroupTheory/GroupAction/BigOperators.lean +++ /dev/null @@ -1,62 +0,0 @@ -/- -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.Algebra.GroupWithZero.Action.Defs -import Mathlib.Data.Finset.Basic -import Mathlib.Data.Multiset.Basic - -/-! -# Lemmas about group actions on big operators - -Note that analogous lemmas for `Module`s like `Finset.sum_smul` appear in other files. --/ - - -variable {α β γ : Type*} - -section - -variable [AddMonoid β] [DistribSMul α β] - -theorem List.smul_sum {r : α} {l : List β} : r • l.sum = (l.map (r • ·)).sum := - map_list_sum (DistribSMul.toAddMonoidHom β r) l - -end - -section - -variable [Monoid α] [Monoid β] [MulDistribMulAction α β] - -theorem List.smul_prod {r : α} {l : List β} : r • l.prod = (l.map (r • ·)).prod := - map_list_prod (MulDistribMulAction.toMonoidHom β r) l - -end - -section - -variable [AddCommMonoid β] [DistribSMul α β] - -theorem Multiset.smul_sum {r : α} {s : Multiset β} : r • s.sum = (s.map (r • ·)).sum := - (DistribSMul.toAddMonoidHom β r).map_multiset_sum s - -theorem Finset.smul_sum {r : α} {f : γ → β} {s : Finset γ} : - (r • ∑ x ∈ s, f x) = ∑ x ∈ s, r • f x := - map_sum (DistribSMul.toAddMonoidHom β r) f s - -end - -section - -variable [Monoid α] [CommMonoid β] [MulDistribMulAction α β] - -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 γ} : - (r • ∏ x ∈ s, f x) = ∏ x ∈ s, r • f x := - map_prod (MulDistribMulAction.toMonoidHom β r) f s - -end diff --git a/Mathlib/GroupTheory/GroupAction/Blocks.lean b/Mathlib/GroupTheory/GroupAction/Blocks.lean index c82066c332d33..9fbae888310e9 100644 --- a/Mathlib/GroupTheory/GroupAction/Blocks.lean +++ b/Mathlib/GroupTheory/GroupAction/Blocks.lean @@ -8,6 +8,7 @@ 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 /-! # Blocks @@ -135,7 +136,8 @@ theorem IsBlock.def_one {B : Set X} : rw [Set.disjoint_iff] at h ⊢ rintro x hx suffices g'⁻¹ • x ∈ (g'⁻¹ * g) • B ∩ B by apply h this - simp only [Set.mem_inter_iff, ← Set.mem_smul_set_iff_inv_smul_mem, ← smul_smul, smul_inv_smul] + 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} : @@ -356,11 +358,11 @@ lemma smul_orbit_eq_orbit_smul (N : Subgroup G) [nN : N.Normal] (a : X) (g : G) constructor · rintro ⟨⟨k, hk⟩, rfl⟩ use ⟨g * k * g⁻¹, nN.conj_mem k hk g⟩ - simp only [Submonoid.mk_smul] + simp only [Subgroup.mk_smul] rw [smul_smul, inv_mul_cancel_right, ← smul_smul] · rintro ⟨⟨k, hk⟩, rfl⟩ use ⟨g⁻¹ * k * g, nN.conj_mem' k hk g⟩ - simp only [Submonoid.mk_smul] + simp only [Subgroup.mk_smul] simp only [← mul_assoc, ← smul_smul, smul_inv_smul, inv_inv] /-- An orbit of a normal subgroup is a block -/ @@ -396,7 +398,7 @@ theorem IsBlock.of_orbit {H : Subgroup G} {a : X} (hH : stabilizer G a ≤ H) : simp_rw [IsBlock.def_one, or_iff_not_imp_right, Set.not_disjoint_iff] rintro g ⟨-, ⟨-, ⟨h₁, rfl⟩, h⟩, ⟨h₂, rfl⟩⟩ suffices g ∈ H by - rw [← Subgroup.coe_mk H g this, ← H.smul_def, smul_orbit (⟨g, this⟩ : H) a] + 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] @@ -419,7 +421,7 @@ theorem IsBlock.orbit_stabilizer_eq ext x constructor · rintro ⟨⟨k, k_mem⟩, rfl⟩ - simp only [Submonoid.mk_smul] + simp only [Subgroup.mk_smul] rw [← k_mem, Set.smul_mem_smul_set_iff] exact ha · intro hx @@ -434,11 +436,11 @@ theorem stabilizer_orbit_eq {a : X} {H : Subgroup G} (hH : stabilizer G a ≤ H) constructor · intro hg obtain ⟨-, ⟨b, rfl⟩, h⟩ := hg.symm ▸ mem_orbit_self a - simp_rw [H.smul_def, ← mul_smul, ← mem_stabilizer_iff] at h + simp_rw [H.toSubmonoid.smul_def, ← mul_smul, ← mem_stabilizer_iff] at h exact (mul_mem_cancel_right b.2).mp (hH h) · intro hg - rw [mem_stabilizer_iff, ← Subgroup.coe_mk H g hg, ← Submonoid.smul_def] - apply smul_orbit + rw [mem_stabilizer_iff, ← Subgroup.coe_mk H g hg, ← Submonoid.smul_def (S := H.toSubmonoid)] + apply smul_orbit (G := H) variable (G) diff --git a/Mathlib/GroupTheory/GroupAction/CardCommute.lean b/Mathlib/GroupTheory/GroupAction/CardCommute.lean new file mode 100644 index 0000000000000..4be202b059262 --- /dev/null +++ b/Mathlib/GroupTheory/GroupAction/CardCommute.lean @@ -0,0 +1,32 @@ +/- +Copyright (c) 2018 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes, Thomas Browning +-/ +import Mathlib.Algebra.Group.ConjFinite +import Mathlib.GroupTheory.GroupAction.Quotient + +/-! +# A consequence of Burnside's lemma + +See `Mathlib.GroupTheory.GroupAction.Quotient` for Burnside's lemma itself. +This lemma is separate because it requires `Nat.card` +and hence transitively the development of cardinals. +-/ + +open Fintype + +theorem card_comm_eq_card_conjClasses_mul_card (G : Type*) [Group G] : + Nat.card { p : G × G // Commute p.1 p.2 } = Nat.card (ConjClasses G) * Nat.card G := by + classical + rcases fintypeOrInfinite G; swap + · rw [mul_comm, Nat.card_eq_zero_of_infinite, Nat.card_eq_zero_of_infinite, zero_mul] + simp only [Nat.card_eq_fintype_card] + -- Porting note: Changed `calc` proof into a `rw` proof. + rw [card_congr (Equiv.subtypeProdEquivSigmaSubtype Commute), card_sigma, + sum_equiv ConjAct.toConjAct.toEquiv (fun a ↦ card { b // Commute a b }) + (fun g ↦ card (MulAction.fixedBy G g)) + fun g ↦ card_congr' <| congr_arg _ <| funext fun h ↦ mul_inv_eq_iff_eq_mul.symm.eq, + MulAction.sum_card_fixedBy_eq_card_orbits_mul_card_group] + congr 1; apply card_congr'; congr; ext + exact (Setoid.comm' _).trans isConj_iff.symm diff --git a/Mathlib/GroupTheory/GroupAction/FixingSubgroup.lean b/Mathlib/GroupTheory/GroupAction/FixingSubgroup.lean index 4fd82a9683bf7..afcac247ac820 100644 --- a/Mathlib/GroupTheory/GroupAction/FixingSubgroup.lean +++ b/Mathlib/GroupTheory/GroupAction/FixingSubgroup.lean @@ -3,7 +3,6 @@ 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.Algebra.Group.Subgroup.Actions import Mathlib.GroupTheory.GroupAction.Basic import Mathlib.GroupTheory.GroupAction.FixedPoints diff --git a/Mathlib/GroupTheory/GroupAction/Group.lean b/Mathlib/GroupTheory/GroupAction/Group.lean deleted file mode 100644 index ae6ba4516d404..0000000000000 --- a/Mathlib/GroupTheory/GroupAction/Group.lean +++ /dev/null @@ -1,112 +0,0 @@ -/- -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.Action.Basic -import Mathlib.Algebra.Group.Invertible.Basic -import Mathlib.Algebra.GroupWithZero.Action.Units -import Mathlib.Algebra.GroupWithZero.Units.Basic -import Mathlib.Algebra.SMulWithZero - -/-! -# Group actions applied to various types of group - -This file contains lemmas about `SMul` on `GroupWithZero`, and `Group`. --/ - - -universe u v w - -variable {α : Type u} {β : Type v} {γ : Type w} - -section MulAction - -/-- `Monoid.toMulAction` is faithful on nontrivial cancellative monoids with zero. -/ -instance CancelMonoidWithZero.faithfulSMul [CancelMonoidWithZero α] [Nontrivial α] : - FaithfulSMul α α := - ⟨fun h => mul_left_injective₀ one_ne_zero (h 1)⟩ - -section Gwz - -variable [GroupWithZero α] [MulAction α β] {a : α} - -@[simp] -theorem inv_smul_smul₀ {c : α} (hc : c ≠ 0) (x : β) : c⁻¹ • c • x = x := - inv_smul_smul (Units.mk0 c hc) x - -@[simp] -theorem smul_inv_smul₀ {c : α} (hc : c ≠ 0) (x : β) : c • c⁻¹ • x = x := - smul_inv_smul (Units.mk0 c hc) x - -theorem inv_smul_eq_iff₀ {a : α} (ha : a ≠ 0) {x y : β} : a⁻¹ • x = y ↔ x = a • y := - ⟨fun h => by rw [← h, smul_inv_smul₀ ha], fun h => by rw [h, inv_smul_smul₀ ha]⟩ - -theorem eq_inv_smul_iff₀ {a : α} (ha : a ≠ 0) {x y : β} : x = a⁻¹ • y ↔ a • x = y := - (MulAction.toPerm (Units.mk0 a ha)).eq_symm_apply - -@[simp] -theorem Commute.smul_right_iff₀ [Mul β] [SMulCommClass α β β] [IsScalarTower α β β] {a b : β} - {c : α} (hc : c ≠ 0) : Commute a (c • b) ↔ Commute a b := - Commute.smul_right_iff (g := Units.mk0 c hc) - -@[simp] -theorem Commute.smul_left_iff₀ [Mul β] [SMulCommClass α β β] [IsScalarTower α β β] {a b : β} {c : α} - (hc : c ≠ 0) : Commute (c • a) b ↔ Commute a b := - Commute.smul_left_iff (g := Units.mk0 c hc) - -/-- 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 Gwz - -end MulAction - -section DistribMulAction - -section Group - -variable [Group α] [AddMonoid β] [DistribMulAction α β] -variable (β) - -variable (α) - -/-- 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 {α β} - -theorem smul_eq_zero_iff_eq (a : α) {x : β} : a • x = 0 ↔ x = 0 := - ⟨fun h => by rw [← inv_smul_smul a x, h, smul_zero], fun h => h.symm ▸ smul_zero _⟩ - -theorem smul_ne_zero_iff_ne (a : α) {x : β} : a • x ≠ 0 ↔ x ≠ 0 := - not_congr <| smul_eq_zero_iff_eq a - -end Group - -end DistribMulAction - -namespace IsUnit - -section DistribMulAction - -variable [Monoid α] [AddMonoid β] [DistribMulAction α β] - -@[simp] -theorem smul_eq_zero {u : α} (hu : IsUnit u) {x : β} : u • x = 0 ↔ x = 0 := - (Exists.elim hu) fun u hu => hu ▸ show u • x = 0 ↔ x = 0 from smul_eq_zero_iff_eq u - -end DistribMulAction - -end IsUnit diff --git a/Mathlib/GroupTheory/GroupAction/Hom.lean b/Mathlib/GroupTheory/GroupAction/Hom.lean index d843581eba0b4..e2fc5be8f79d8 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 @@ -59,7 +58,7 @@ variable (Z : Type*) [SMul P Z] /-- Equivariant functions : When `φ : M → N` is a function, and types `X` and `Y` are endowed with actions of `M` and `N`, -a function `f : X → Y` is `φ`-equivariant if `f (m • x) = (φ m) • (f x)`. -/ +a function `f : X → Y` is `φ`-equivariant if `f (m • x) = (φ m) • (f x)`. -/ -- Porting note(#5171): this linter isn't ported yet. -- @[nolint has_nonempty_instance] structure MulActionHom where 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 a03534bfbc10f..3cd5bab40dafd 100644 --- a/Mathlib/GroupTheory/GroupAction/Quotient.lean +++ b/Mathlib/GroupTheory/GroupAction/Quotient.lean @@ -3,13 +3,13 @@ Copyright (c) 2018 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes, Thomas Browning -/ -import Mathlib.Algebra.Group.ConjFinite import Mathlib.Data.Fintype.BigOperators import Mathlib.Dynamics.PeriodicPts -import Mathlib.GroupTheory.Commutator -import Mathlib.GroupTheory.Coset 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 /-! # Properties of group actions involving quotient groups @@ -20,7 +20,6 @@ This file proves properties of group actions which use the quotient group constr * Burnside's lemma `sum_card_fixedBy_eq_card_orbits_mul_card_group` -/ - universe u v w variable {α : Type u} {β : Type v} {γ : Type w} @@ -364,6 +363,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_r_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_r_apply] + exact ⟨⟨_, h⟩, by simp [mul_smul]⟩) + left_inv := fun y ↦ by + induction' y using Quotient.inductionOn' with y + simp only [Quotient.liftOn'_mk''] + rw [← @Quotient.mk''_eq_mk, Quotient.eq'', orbitRel_r_apply] + 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) @@ -422,24 +463,3 @@ theorem quotientCenterEmbedding_apply {S : Set G} (hS : closure S = ⊤) (g : G) rfl end Subgroup - -section conjClasses - -open Fintype - -theorem card_comm_eq_card_conjClasses_mul_card (G : Type*) [Group G] : - Nat.card { p : G × G // Commute p.1 p.2 } = Nat.card (ConjClasses G) * Nat.card G := by - classical - rcases fintypeOrInfinite G; swap - · rw [mul_comm, Nat.card_eq_zero_of_infinite, Nat.card_eq_zero_of_infinite, zero_mul] - simp only [Nat.card_eq_fintype_card] - -- Porting note: Changed `calc` proof into a `rw` proof. - rw [card_congr (Equiv.subtypeProdEquivSigmaSubtype Commute), card_sigma, - sum_equiv ConjAct.toConjAct.toEquiv (fun a ↦ card { b // Commute a b }) - (fun g ↦ card (MulAction.fixedBy G g)) - fun g ↦ card_congr' <| congr_arg _ <| funext fun h ↦ mul_inv_eq_iff_eq_mul.symm.eq, - MulAction.sum_card_fixedBy_eq_card_orbits_mul_card_group] - congr 1; apply card_congr'; congr; ext - exact (Setoid.comm' _).trans isConj_iff.symm - -end conjClasses diff --git a/Mathlib/GroupTheory/GroupAction/Ring.lean b/Mathlib/GroupTheory/GroupAction/Ring.lean index b993a6401f328..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,21 +21,24 @@ 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 smul_comm n x y := by - induction' n with n ih - · simp [zero_nsmul] - · simp_rw [succ_nsmul, smul_eq_mul, mul_add, ← smul_eq_mul, ih] + induction n with + | zero => simp [zero_nsmul] + | succ n ih => simp_rw [succ_nsmul, smul_eq_mul, mul_add, ← smul_eq_mul, ih] /-- Note that `AddCommMonoid.nat_isScalarTower` requires stronger assumptions on `α`. -/ instance NonUnitalNonAssocSemiring.nat_isScalarTower [NonUnitalNonAssocSemiring α] : IsScalarTower ℕ α α where smul_assoc n x y := by - induction' n with n ih - · simp [zero_nsmul] - · simp_rw [succ_nsmul, ← ih, smul_eq_mul, add_mul] + induction n with + | zero => simp [zero_nsmul] + | succ n ih => simp_rw [succ_nsmul, ← ih, smul_eq_mul, add_mul] /-- Note that `AddMonoid.int_smulCommClass` requires stronger assumptions on `α`. -/ instance NonUnitalNonAssocRing.int_smulCommClass [NonUnitalNonAssocRing α] : diff --git a/Mathlib/GroupTheory/GroupAction/SubMulAction.lean b/Mathlib/GroupTheory/GroupAction/SubMulAction.lean index 0d6267151258e..6f4c858afeb02 100644 --- a/Mathlib/GroupTheory/GroupAction/SubMulAction.lean +++ b/Mathlib/GroupTheory/GroupAction/SubMulAction.lean @@ -153,7 +153,7 @@ end OfTower end SetLike -/-- A SubMulAction is a set which is closed under scalar multiplication. -/ +/-- A SubMulAction is a set which is closed under scalar multiplication. -/ structure SubMulAction (R : Type u) (M : Type v) [SMul R M] : Type v where /-- The underlying set of a `SubMulAction`. -/ carrier : Set M @@ -243,7 +243,7 @@ variable [Monoid R] [MulAction R M] {A : Type*} [SetLike A M] variable [hA : SMulMemClass A R M] (S' : A) -- Prefer subclasses of `MulAction` over `SMulMemClass`. -/-- A `SubMulAction` of a `MulAction` is a `MulAction`. -/ +/-- A `SubMulAction` of a `MulAction` is a `MulAction`. -/ instance (priority := 75) toMulAction : MulAction R S' := Subtype.coe_injective.mulAction Subtype.val (SetLike.val_smul S') diff --git a/Mathlib/GroupTheory/GroupAction/Support.lean b/Mathlib/GroupTheory/GroupAction/Support.lean index d0f3000e1c542..392881eb03ad9 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 diff --git a/Mathlib/GroupTheory/HNNExtension.lean b/Mathlib/GroupTheory/HNNExtension.lean index f6df864683e3c..2ba02b333a426 100644 --- a/Mathlib/GroupTheory/HNNExtension.lean +++ b/Mathlib/GroupTheory/HNNExtension.lean @@ -42,7 +42,7 @@ def HNNExtension.con (G : Type*) [Group G] (A B : Subgroup G) (φ : A ≃* B) : /-- The HNN Extension of a group `G`, `HNNExtension G A B φ`. Given a group `G`, subgroups `A` and `B` and an isomorphism `φ` of `A` and `B`, we adjoin a letter `t` to `G`, such that for any `a ∈ A`, the conjugate of `of a` by `t` is `of (φ a)`, where `of` is the canonical -map from `G` into the `HNNExtension`. -/ +map from `G` into the `HNNExtension`. -/ def HNNExtension (G : Type*) [Group G] (A B : Subgroup G) (φ : A ≃* B) : Type _ := (HNNExtension.con G A B φ).Quotient @@ -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 @@ -281,7 +281,7 @@ def cons (g : G) (u : ℤˣ) (w : NormalWord d) (h1 : w.head ∈ d.set u) rintro ⟨u', g'⟩ hu' hw1 exact h2 _ (by simp_all) hw1 } -/-- A recursor to induct on a `NormalWord`, by proving the propert is preserved under `cons` -/ +/-- A recursor to induct on a `NormalWord`, by proving the property is preserved under `cons` -/ @[elab_as_elim] def consRecOn {motive : NormalWord d → Sort*} (w : NormalWord d) (ofGroup : ∀g, motive (ofGroup g)) @@ -347,8 +347,8 @@ theorem unitsSMulGroup_snd (u : ℤˣ) (g : G) : variable {d} -/-- `Cancels u w` is a predicate expressing whether `t^u` cancels with some occurence -of `t^-u` when when we multiply `t^u` by `w`. -/ +/-- `Cancels u w` is a predicate expressing whether `t^u` cancels with some occurrence +of `t^-u` when we multiply `t^u` by `w`. -/ def Cancels (u : ℤˣ) (w : NormalWord d) : Prop := (w.head ∈ (toSubgroup A B u : Subgroup G)) ∧ w.toList.head?.map Prod.fst = some (-u) @@ -473,9 +473,8 @@ theorem unitsSMul_one_group_smul (g : A) (w : NormalWord d) : dsimp congr 1 · conv_lhs => erw [IsComplement.equiv_mul_left] - simp? says - simp only [toSubgroup_one, SetLike.coe_sort_coe, map_mul, Submonoid.coe_mul, - coe_toSubmonoid] + simp_rw [toSubgroup_one] + simp only [SetLike.coe_sort_coe, map_mul, Subgroup.coe_mul] conv_lhs => erw [IsComplement.equiv_mul_left] rfl @@ -653,9 +652,9 @@ theorem exists_normalWord_prod_eq simp [mul_assoc, unitsSMulGroup, (d.compl _).coe_equiv_snd_eq_one_iff_mem] /-- Two reduced words representing the same element of the `HNNExtension G A B φ` have the same -length corresponding list, with the same pattern of occurences of `t^1` and `t^(-1)`, +length corresponding list, with the same pattern of occurrences of `t^1` and `t^(-1)`, and also the `head` is in the same left coset of `toSubgroup A B (-u)`, where `u : ℤˣ` -is the exponent of the first occurence of `t` in the word. -/ +is the exponent of the first occurrence of `t` in the word. -/ theorem map_fst_eq_and_of_prod_eq {w₁ w₂ : ReducedWord G A B} (hprod : w₁.prod φ = w₂.prod φ) : w₁.toList.map Prod.fst = w₂.toList.map Prod.fst ∧ @@ -674,7 +673,7 @@ theorem map_fst_eq_and_of_prod_eq {w₁ w₂ : ReducedWord G A B} rwa [← List.head?_map, ← hw₂'2, hw₁'2, List.head?_map] /-- **Britton's Lemma**. Any reduced word whose product is an element of `G`, has no -occurences of `t`. -/ +occurrences of `t`. -/ theorem toList_eq_nil_of_mem_of_range (w : ReducedWord G A B) (hw : w.prod φ ∈ (of.range : Subgroup (HNNExtension G A B φ))) : w.toList = [] := by diff --git a/Mathlib/GroupTheory/Index.lean b/Mathlib/GroupTheory/Index.lean index a389d1051072c..99284c35f6952 100644 --- a/Mathlib/GroupTheory/Index.lean +++ b/Mathlib/GroupTheory/Index.lean @@ -3,7 +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.Data.Finite.Card import Mathlib.Algebra.BigOperators.GroupWithZero.Finset +import Mathlib.GroupTheory.Coset.Card import Mathlib.GroupTheory.Finiteness import Mathlib.GroupTheory.GroupAction.Quotient @@ -54,9 +56,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) ⟨?_, ?_⟩) @@ -156,9 +157,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)] @@ -447,6 +448,25 @@ 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] +@[simp] +lemma index_toAddSubgroup : (Subgroup.toAddSubgroup H).index = H.index := + rfl + +@[simp] +lemma _root_.AddSubgroup.index_toSubgroup {G : Type*} [AddGroup G] (H : AddSubgroup G) : + (AddSubgroup.toSubgroup H).index = H.index := + rfl + +@[simp] +lemma relindex_toAddSubgroup : + (Subgroup.toAddSubgroup H).relindex (Subgroup.toAddSubgroup K) = H.relindex K := + rfl + +@[simp] +lemma _root_.AddSubgroup.relindex_toSubgroup {G : Type*} [AddGroup G] (H K : AddSubgroup G) : + (AddSubgroup.toSubgroup H).relindex (AddSubgroup.toSubgroup K) = H.relindex K := + rfl + section FiniteIndex variable (H K) diff --git a/Mathlib/GroupTheory/MonoidLocalization/Basic.lean b/Mathlib/GroupTheory/MonoidLocalization/Basic.lean index 61f01685b604e..aae0ac762fc97 100644 --- a/Mathlib/GroupTheory/MonoidLocalization/Basic.lean +++ b/Mathlib/GroupTheory/MonoidLocalization/Basic.lean @@ -268,8 +268,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 +291,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 +544,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 +769,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) : @@ -797,12 +791,12 @@ theorem lift_id (x) : f.lift f.map_units x = x := /-- Given Localization maps `f : M →* N` for a Submonoid `S ⊆ M` and `k : M →* Q` for a Submonoid `T ⊆ M`, such that `S ≤ T`, and we have `l : M →* A`, the composition of the induced map `f.lift` for `k` with -the induced map `k.lift` for `l` is equal to the induced map `f.lift` for `l`. -/ +the induced map `k.lift` for `l` is equal to the induced map `f.lift` for `l`. -/ @[to_additive "Given Localization maps `f : M →+ N` for a Submonoid `S ⊆ M` and `k : M →+ Q` for a Submonoid `T ⊆ M`, such that `S ≤ T`, and we have `l : M →+ A`, the composition of the induced map `f.lift` for `k` with -the induced map `k.lift` for `l` is equal to the induced map `f.lift` for `l`"] +the induced map `k.lift` for `l` is equal to the induced map `f.lift` for `l`"] theorem lift_comp_lift {T : Submonoid M} (hST : S ≤ T) {Q : Type*} [CommMonoid Q] (k : LocalizationMap T Q) {A : Type*} [CommMonoid A] {l : M →* A} (hl : ∀ w : T, IsUnit (l w)) : @@ -834,8 +828,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 @@ -1131,9 +1125,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)] @@ -1203,18 +1197,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) : diff --git a/Mathlib/GroupTheory/MonoidLocalization/MonoidWithZero.lean b/Mathlib/GroupTheory/MonoidLocalization/MonoidWithZero.lean index b0c5d7e2cac4a..3c6c5f38a066e 100644 --- a/Mathlib/GroupTheory/MonoidLocalization/MonoidWithZero.lean +++ b/Mathlib/GroupTheory/MonoidLocalization/MonoidWithZero.lean @@ -42,7 +42,7 @@ namespace Submonoid variable {S N} in /-- If `S` contains `0` then the localization at `S` is trivial. -/ -theorem LocalizationMap.subsingleton (f : Submonoid.LocalizationMap S N) (h : 0 ∈ S) : +theorem LocalizationMap.subsingleton (f : Submonoid.LocalizationMap S N) (h : 0 ∈ S) : Subsingleton N := by refine ⟨fun a b ↦ ?_⟩ rw [← LocalizationMap.mk'_sec f a, ← LocalizationMap.mk'_sec f b, LocalizationMap.eq] @@ -152,7 +152,7 @@ theorem leftCancelMulZero_of_le_isLeftRegular /-- Given a Localization map `f : M →*₀ N` for a Submonoid `S ⊆ M`, if `M` is a cancellative monoid with zero, and all elements of `S` are -regular, then N is a cancellative monoid with zero. -/ +regular, then N is a cancellative monoid with zero. -/ theorem isLeftRegular_of_le_isCancelMulZero (f : LocalizationWithZeroMap S N) [IsCancelMulZero M] (h : ∀ ⦃x⦄, x ∈ S → IsRegular x) : IsCancelMulZero N := by have : IsLeftCancelMulZero N := diff --git a/Mathlib/GroupTheory/MonoidLocalization/Order.lean b/Mathlib/GroupTheory/MonoidLocalization/Order.lean index c25bc39fbfb7a..ccdd1707f6e4d 100644 --- a/Mathlib/GroupTheory/MonoidLocalization/Order.lean +++ b/Mathlib/GroupTheory/MonoidLocalization/Order.lean @@ -3,6 +3,7 @@ Copyright (c) 2019 Amelia Livingston. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Amelia Livingston -/ +import Mathlib.Algebra.Order.Monoid.Defs import Mathlib.GroupTheory.MonoidLocalization.Basic /-! diff --git a/Mathlib/GroupTheory/Nilpotent.lean b/Mathlib/GroupTheory/Nilpotent.lean index 6ec49137ba22e..90196dde62882 100644 --- a/Mathlib/GroupTheory/Nilpotent.lean +++ b/Mathlib/GroupTheory/Nilpotent.lean @@ -6,6 +6,7 @@ Authors: Kevin Buzzard, Ines Wright, Joachim Breitner import Mathlib.GroupTheory.Solvable import Mathlib.GroupTheory.Sylow import Mathlib.Algebra.Group.Subgroup.Order +import Mathlib.GroupTheory.Commutator.Finite /-! @@ -284,7 +285,7 @@ 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 _ _ _) rintro y ⟨z, hz, a, ha⟩ @@ -446,7 +447,7 @@ theorem upperCentralSeries.map {H : Type*} [Group H] {f : G →* H} (h : Functio theorem lowerCentralSeries.map {H : Type*} [Group H] (f : G →* H) (n : ℕ) : Subgroup.map f (lowerCentralSeries G n) ≤ lowerCentralSeries H n := by induction' n with d hd - · simp [Nat.zero_eq] + · 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 @@ -534,7 +535,7 @@ private theorem comap_center_subst {H₁ H₂ : Subgroup G} [Normal H₁] [Norma theorem comap_upperCentralSeries_quotient_center (n : ℕ) : comap (mk' (center G)) (upperCentralSeries (G ⧸ center G) n) = upperCentralSeries G n.succ := by induction' n with n ih - · simp only [Nat.zero_eq, upperCentralSeries_zero, MonoidHom.comap_bot, ker_mk', + · simp only [upperCentralSeries_zero, MonoidHom.comap_bot, ker_mk', (upperCentralSeries_one G).symm] · let Hn := upperCentralSeries (G ⧸ center G) n calc @@ -810,16 +811,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/OrderOfElement.lean b/Mathlib/GroupTheory/OrderOfElement.lean index faa4010f0d09f..9e33d48b21996 100644 --- a/Mathlib/GroupTheory/OrderOfElement.lean +++ b/Mathlib/GroupTheory/OrderOfElement.lean @@ -6,6 +6,7 @@ Authors: Johannes Hölzl, Julian Kuelshammer import Mathlib.Algebra.CharP.Defs import Mathlib.GroupTheory.Index import Mathlib.Order.Interval.Set.Infinite +import Mathlib.Algebra.Group.Subgroup.Finite /-! # Order of an element @@ -716,7 +717,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] : @@ -744,7 +745,7 @@ end Finite variable [Fintype G] {x : G} @[to_additive] -lemma orderOf_eq_card_powers : orderOf x = Fintype.card (powers x : Set G) := +lemma orderOf_eq_card_powers : orderOf x = Fintype.card (powers x : Submonoid G) := (Fintype.card_fin (orderOf x)).symm.trans <| Fintype.card_eq.2 ⟨finEquivPowers x <| isOfFinOrder_of_finite _⟩ @@ -820,6 +821,7 @@ variable [Fintype G] {x : G} {n : ℕ} /-- See also `Nat.card_addSubgroupZPowers`. -/ @[to_additive "See also `Nat.card_subgroup`."] theorem Fintype.card_zpowers : Fintype.card (zpowers x) = orderOf x := + letI : Fintype (zpowers x) := (Subgroup.zpowers x).instFintypeSubtypeMemOfDecidablePred (Fintype.card_eq.2 ⟨finEquivZPowers x <| isOfFinOrder_of_finite _⟩).symm.trans <| Fintype.card_fin (orderOf x) @@ -901,12 +903,12 @@ theorem zpow_mod_card (a : G) (n : ℤ) : a ^ (n % Fintype.card G : ℤ) = a ^ n @[to_additive (attr := simp) mod_natCard_nsmul] lemma pow_mod_natCard {G} [Group G] (a : G) (n : ℕ) : a ^ (n % Nat.card G) = a ^ n := by - rw [eq_comm, ← pow_mod_orderOf, ← Nat.mod_mod_of_dvd n $ orderOf_dvd_natCard _, pow_mod_orderOf] + rw [eq_comm, ← pow_mod_orderOf, ← Nat.mod_mod_of_dvd n <| orderOf_dvd_natCard _, pow_mod_orderOf] @[to_additive (attr := simp) mod_natCard_zsmul] lemma zpow_mod_natCard {G} [Group G] (a : G) (n : ℤ) : a ^ (n % Nat.card G : ℤ) = a ^ n := by - rw [eq_comm, ← zpow_mod_orderOf, - ← Int.emod_emod_of_dvd n $ Int.natCast_dvd_natCast.2 $ orderOf_dvd_natCard _, zpow_mod_orderOf] + rw [eq_comm, ← zpow_mod_orderOf, ← Int.emod_emod_of_dvd n <| + Int.natCast_dvd_natCast.2 <| orderOf_dvd_natCard _, zpow_mod_orderOf] /-- If `gcd(|G|,n)=1` then the `n`th power map is a bijection -/ @[to_additive (attr := simps) "If `gcd(|G|,n)=1` then the smul by `n` is a bijection"] @@ -947,7 +949,9 @@ theorem inf_eq_bot_of_coprime {G : Type*} [Group G] {H K : Subgroup G} /- TODO: Generalise to `Submonoid.powers`. -/ @[to_additive] theorem image_range_orderOf [DecidableEq G] : + letI : Fintype (zpowers x) := (Subgroup.zpowers x).instFintypeSubtypeMemOfDecidablePred Finset.image (fun i => x ^ i) (Finset.range (orderOf x)) = (zpowers x : Set G).toFinset := by + letI : Fintype (zpowers x) := (Subgroup.zpowers x).instFintypeSubtypeMemOfDecidablePred ext x rw [Set.mem_toFinset, SetLike.mem_coe, mem_zpowers_iff_mem_range_orderOf] @@ -966,9 +970,12 @@ section PowIsSubgroup @[to_additive "A nonempty idempotent subset of a finite cancellative add monoid is a submonoid"] def submonoidOfIdempotent {M : Type*} [LeftCancelMonoid M] [Finite M] (S : Set M) (hS1 : S.Nonempty) (hS2 : S * S = S) : Submonoid M := - have pow_mem : ∀ a : M, a ∈ S → ∀ n : ℕ, a ^ (n + 1) ∈ S := fun a ha => - Nat.rec (by rwa [Nat.zero_eq, zero_add, pow_one]) fun n ih => - (congr_arg₂ (· ∈ ·) (pow_succ a (n + 1)).symm hS2).mp (Set.mul_mem_mul ih ha) + have pow_mem (a : M) (ha : a ∈ S) (n : ℕ) : a ^ (n + 1) ∈ S := by + induction n with + | zero => rwa [zero_add, pow_one] + | succ n ih => + rw [← hS2, pow_succ] + exact Set.mul_mem_mul ih ha { carrier := S one_mem' := by obtain ⟨a, ha⟩ := hS1 @@ -1024,8 +1031,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 @@ -1110,7 +1117,7 @@ lemma charP_of_prime_pow_injective (R) [Ring R] [Fintype R] (p n : ℕ) [hp : Fa obtain ⟨c, hc⟩ := CharP.exists R have hcpn : c ∣ p ^ n := by rw [← CharP.cast_eq_zero_iff R c, ← hn, Nat.cast_card_eq_zero] obtain ⟨i, hi, rfl⟩ : ∃ i ≤ n, c = p ^ i := by rwa [Nat.dvd_prime_pow hp.1] at hcpn - obtain rfl : i = n := hR i hi $ by rw [← Nat.cast_pow, CharP.cast_eq_zero] + obtain rfl : i = n := hR i hi <| by rw [← Nat.cast_pow, CharP.cast_eq_zero] assumption namespace SemiconjBy diff --git a/Mathlib/GroupTheory/PGroup.lean b/Mathlib/GroupTheory/PGroup.lean index 1b48a93653134..52fcaf2fb7a60 100644 --- a/Mathlib/GroupTheory/PGroup.lean +++ b/Mathlib/GroupTheory/PGroup.lean @@ -37,7 +37,7 @@ theorem of_card {n : ℕ} (hG : Nat.card G = p ^ n) : IsPGroup p G := fun g => ⟨n, by rw [← hG, pow_card_eq_one']⟩ theorem of_bot : IsPGroup p (⊥ : Subgroup G) := - of_card (by rw [Subgroup.card_bot, pow_zero]) + of_card (n := 0) (by rw [Subgroup.card_bot, pow_zero]) theorem iff_card [Fact p.Prime] [Finite G] : IsPGroup p G ↔ ∃ n : ℕ, Nat.card G = p ^ n := by have hG : Nat.card G ≠ 0 := Nat.card_pos.ne' @@ -136,7 +136,7 @@ theorem nontrivial_iff_card [Finite G] : Nontrivial G ↔ ∃ n > 0, Nat.card G hk⟩, fun ⟨k, 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 α] @@ -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 fbe49dd2f60d0..5dc3ff87f4586 100644 --- a/Mathlib/GroupTheory/Perm/Basic.lean +++ b/Mathlib/GroupTheory/Perm/Basic.lean @@ -36,9 +36,9 @@ instance permGroup : Group (Perm α) where 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 n f := 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' n f := coe_fn_injective <| Function.iterate_succ _ _ @[simp] theorem default_eq : (default : Perm α) = 1 := @@ -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 113024e8329e4..9564bafaf6fcc 100644 --- a/Mathlib/GroupTheory/Perm/Closure.lean +++ b/Mathlib/GroupTheory/Perm/Closure.lean @@ -40,24 +40,26 @@ 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 σ _) have h4 : swap x (σ x) ∈ H := subset_closure (Set.mem_insert_of_mem _ (Set.mem_singleton _)) have step1 : ∀ n : ℕ, swap ((σ ^ n) x) ((σ ^ (n + 1) : Perm α) x) ∈ H := by intro n - induction' n with n ih - · exact subset_closure (Set.mem_insert_of_mem _ (Set.mem_singleton _)) - · 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 + induction n with + | 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', coe_mul, comp_apply] have step2 : ∀ n : ℕ, swap x ((σ ^ n) x) ∈ H := by intro n - induction' n with n ih - · simp only [Nat.zero_eq, pow_zero, coe_one, id_eq, swap_self, Set.mem_singleton_iff] + induction n with + | zero => + simp only [pow_zero, coe_one, id_eq, swap_self, Set.mem_singleton_iff] convert H.one_mem - · by_cases h5 : x = (σ ^ n) x + | succ n ih => + by_cases h5 : x = (σ ^ n) x · rw [pow_succ', mul_apply, ← h5] exact h4 by_cases h6 : x = (σ ^ (n + 1) : Perm α) x @@ -67,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] @@ -94,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/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..a13b28ec141ca 100644 --- a/Mathlib/GroupTheory/Perm/Cycle/Basic.lean +++ b/Mathlib/GroupTheory/Perm/Cycle/Basic.lean @@ -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 @@ -985,3 +987,140 @@ theorem sum_mul_sum_eq_sum_perm (hσ : σ.IsCycleOn s) (f g : ι → α) : 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.card = 0 := by + set q := n / g.support.card + set r := n % g.support.card + have div_euc : r + g.support.card * q = n ∧ 0 ≤ r ∧ r < g.support.card := by + 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 924cd62e58286..624873b85abc2 100644 --- a/Mathlib/GroupTheory/Perm/Cycle/Concrete.lean +++ b/Mathlib/GroupTheory/Perm/Cycle/Concrete.lean @@ -109,11 +109,10 @@ theorem cycleType_formPerm (hl : Nodup l) (hn : 2 ≤ l.length) : · simpa using isCycle_formPerm hl hn · simp -set_option linter.deprecated false in theorem formPerm_apply_mem_eq_next (hl : Nodup l) (x : α) (hx : x ∈ l) : formPerm l x = next l x hx := by obtain ⟨k, rfl⟩ := get_of_mem hx - rw [next_get _ hl, formPerm_apply_get _ hl] + rw [next_get _ hl, get_eq_getElem, formPerm_apply_getElem _ hl]; rfl end List @@ -221,16 +220,6 @@ theorem get_toList (n : ℕ) (hn : n < length (toList p x)) : theorem toList_get_zero (h : x ∈ p.support) : (toList p x).get ⟨0, (length_toList_pos_of_mem_support _ _ h)⟩ = x := by simp [toList] -set_option linter.deprecated false in -@[deprecated get_toList (since := "2024-05-08")] -theorem nthLe_toList (n : ℕ) (hn : n < length (toList p x)) : - (toList p x).nthLe n hn = (p ^ n) x := by simp [toList] - -set_option linter.deprecated false in -@[deprecated toList_get_zero (since := "2024-05-08")] -theorem toList_nthLe_zero (h : x ∈ p.support) : - (toList p x).nthLe 0 (length_toList_pos_of_mem_support _ _ h) = x := by simp [toList] - variable {p} {x} theorem mem_toList_iff {y : α} : y ∈ toList p x ↔ SameCycle p x y ∧ x ∈ p.support := by @@ -244,17 +233,16 @@ theorem mem_toList_iff {y : α} : y ∈ toList p x ↔ SameCycle p x y ∧ x ∈ · rintro ⟨h, hx⟩ simpa using h.exists_pow_eq_of_mem_support hx -set_option linter.deprecated false in theorem nodup_toList (p : Perm α) (x : α) : Nodup (toList p x) := by by_cases hx : p x = x · rw [← not_mem_support, ← toList_eq_nil_iff] at hx simp [hx] have hc : IsCycle (cycleOf p x) := isCycle_cycleOf p hx - rw [nodup_iff_nthLe_inj] - rintro n m hn hm + rw [nodup_iff_injective_get] + intro ⟨n, hn⟩ ⟨m, hm⟩ rw [length_toList, ← hc.orderOf] at hm hn rw [← cycleOf_apply_self, ← Ne, ← mem_support] at hx - rw [nthLe_toList, nthLe_toList, ← cycleOf_pow_apply_self p x n, ← + rw [get_toList, get_toList, ← cycleOf_pow_apply_self p x n, ← cycleOf_pow_apply_self p x m] cases' n with n <;> cases' m with m · simp @@ -268,7 +256,7 @@ theorem nodup_toList (p : Perm α) (x : α) : Nodup (toList p x) := by have hn' : ¬orderOf (p.cycleOf x) ∣ n.succ := Nat.not_dvd_of_pos_of_lt n.zero_lt_succ hn have hm' : ¬orderOf (p.cycleOf x) ∣ m.succ := Nat.not_dvd_of_pos_of_lt m.zero_lt_succ hm rw [← hc.support_pow_eq_iff] at hn' hm' - rw [← Nat.mod_eq_of_lt hn, ← Nat.mod_eq_of_lt hm, ← pow_inj_mod] + rw [Fin.mk_eq_mk, ← Nat.mod_eq_of_lt hn, ← Nat.mod_eq_of_lt hm, ← pow_inj_mod] refine support_congr ?_ ?_ · rw [hm', hn'] · rw [hm'] @@ -277,31 +265,30 @@ theorem nodup_toList (p : Perm α) (x : α) : Nodup (toList p x) := by rw [← mul_apply, (Commute.pow_pow_self _ _ _).eq, mul_apply, h, ← mul_apply, ← mul_apply, (Commute.pow_pow_self _ _ _).eq] -set_option linter.deprecated false in theorem next_toList_eq_apply (p : Perm α) (x y : α) (hy : y ∈ toList p x) : next (toList p x) y hy = p y := by rw [mem_toList_iff] at hy obtain ⟨k, hk, hk'⟩ := hy.left.exists_pow_eq_of_mem_support hy.right - rw [← nthLe_toList p x k (by simpa using hk)] at hk' + rw [← get_toList p x k (by simpa using hk)] at hk' simp_rw [← hk'] - rw [next_nthLe _ (nodup_toList _ _), nthLe_toList, nthLe_toList, ← mul_apply, ← pow_succ', - length_toList, ← pow_mod_orderOf_cycleOf_apply p (k + 1), IsCycle.orderOf] + rw [next_get _ (nodup_toList _ _), get_toList, get_toList, ← mul_apply, ← pow_succ'] + simp_rw [length_toList] + rw [← pow_mod_orderOf_cycleOf_apply p (k + 1), IsCycle.orderOf] exact isCycle_cycleOf _ (mem_support.mp hy.right) -set_option linter.deprecated false in theorem toList_pow_apply_eq_rotate (p : Perm α) (x : α) (k : ℕ) : p.toList ((p ^ k) x) = (p.toList x).rotate k := by - apply ext_nthLe + apply ext_get · simp only [length_toList, cycleOf_self_apply_pow, length_rotate] · intro n hn hn' - rw [nthLe_toList, nthLe_rotate, nthLe_toList, length_toList, + rw [get_toList, get_rotate, get_toList, length_toList, pow_mod_card_support_cycleOf_self_apply, pow_add, mul_apply] theorem SameCycle.toList_isRotated {f : Perm α} {x y : α} (h : SameCycle f x y) : toList f x ~r toList f y := by by_cases hx : x ∈ f.support · obtain ⟨_ | k, _, hy⟩ := h.exists_pow_eq_of_mem_support hx - · simp only [coe_one, id, pow_zero, Nat.zero_eq] at hy + · simp only [coe_one, id, pow_zero] at hy -- Porting note: added `IsRotated.refl` simp [hy, IsRotated.refl] use k.succ @@ -329,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 @@ -338,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 a718ff65870f1..e2fc3224e97be 100644 --- a/Mathlib/GroupTheory/Perm/Cycle/Factors.lean +++ b/Mathlib/GroupTheory/Perm/Cycle/Factors.lean @@ -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 @@ -281,7 +281,7 @@ theorem SameCycle.exists_pow_eq [DecidableEq α] [Fintype α] (f : Perm α) (h : · refine ⟨(f.cycleOf x).support.card, ?_, self_le_add_right _ _, ?_⟩ · refine zero_lt_one.trans (one_lt_card_support_of_ne_one ?_) simpa using hx - · simp only [Nat.zero_eq, pow_zero, coe_one, id_eq] at hk' + · simp only [pow_zero, coe_one, id_eq] at hk' subst hk' rw [← (isCycle_cycleOf _ <| mem_support.1 hx).orderOf, ← cycleOf_pow_apply_self, pow_orderOf_eq_one, one_apply] @@ -291,6 +291,19 @@ 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.card = n % (g.cycleOf x).support.card := 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 @@ -303,14 +316,12 @@ section cycleFactors open scoped List in /-- Given a list `l : List α` and a permutation `f : Perm α` whose nonfixed points are all in `l`, recursively factors `f` into cycles. -/ -def cycleFactorsAux [DecidableEq α] [Fintype α] : - ∀ (l : List α) (f : Perm α), - (∀ {x}, f x ≠ x → x ∈ l) → - { l : List (Perm α) // l.prod = f ∧ (∀ g ∈ l, IsCycle g) ∧ l.Pairwise Disjoint } := by - intro l f h - exact match l with +def cycleFactorsAux [DecidableEq α] [Fintype α] (l : List α) (f : Perm α) + (h : ∀ {x}, f x ≠ x → x ∈ l) : + { 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 [*]}⟩ @@ -318,7 +329,7 @@ def cycleFactorsAux [DecidableEq α] [Fintype α] : if hx : f x = x then cycleFactorsAux l f (by intro y hy; exact List.mem_of_ne_of_mem (fun h => hy (by rwa [h])) (h hy)) else - let ⟨m, hm₁, hm₂, hm₃⟩ := + let ⟨m, hm⟩ := cycleFactorsAux l ((cycleOf f x)⁻¹ * f) (by intro y hy exact List.mem_of_ne_of_mem @@ -328,10 +339,8 @@ def cycleFactorsAux [DecidableEq α] [Fintype α] : (h fun h : f y = y => by rw [mul_apply, h, Ne, inv_eq_iff_eq, cycleOf_apply] at hy split_ifs at hy <;> tauto)) - ⟨cycleOf f x::m, by - rw [List.prod_cons, hm₁] - simp, - fun g hg ↦ ((List.mem_cons).1 hg).elim (fun hg => hg.symm ▸ isCycle_cycleOf _ hx) (hm₂ g), + ⟨cycleOf f x :: m, by simp [List.prod_cons, hm.1], + fun g hg ↦ ((List.mem_cons).1 hg).elim (fun hg => hg ▸ isCycle_cycleOf _ hx) (hm.2.1 g), List.pairwise_cons.2 ⟨fun g hg y => or_iff_not_imp_left.2 fun hfy => @@ -340,16 +349,17 @@ def cycleFactorsAux [DecidableEq α] [Fintype α] : have hgm : (g::m.erase g) ~ m := List.cons_perm_iff_perm_erase.2 ⟨hg, List.Perm.refl _⟩ have : ∀ h ∈ m.erase g, Disjoint g h := - (List.pairwise_cons.1 ((hgm.pairwise_iff Disjoint.symm).2 hm₃)).1 + (List.pairwise_cons.1 ((hgm.pairwise_iff Disjoint.symm).2 hm.2.2)).1 by_cases id fun hgy : g y ≠ y => (disjoint_prod_right _ this y).resolve_right <| by have hsc : SameCycle f⁻¹ x (f y) := by rwa [sameCycle_inv, sameCycle_apply_right] - rw [disjoint_prod_perm hm₃ hgm.symm, List.prod_cons, + have hm₁ := hm.1 + rw [disjoint_prod_perm hm.2.2 hgm.symm, List.prod_cons, ← eq_inv_mul_iff_mul_eq] at hm₁ rwa [hm₁, mul_apply, mul_apply, cycleOf_inv, hsc.cycleOf_apply, inv_apply_self, inv_eq_iff_eq, eq_comm], - hm₃⟩⟩ + hm.2.2⟩⟩ theorem mem_list_cycles_iff {α : Type*} [Finite α] {l : List (Perm α)} (h1 : ∀ σ : Perm α, σ ∈ l → σ.IsCycle) (h2 : l.Pairwise Disjoint) {σ : Perm α} : @@ -492,6 +502,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 @@ -578,6 +593,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] @@ -647,6 +729,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 0b0d600b9a079..5a823f43577e4 100644 --- a/Mathlib/GroupTheory/Perm/Cycle/Type.lean +++ b/Mathlib/GroupTheory/Perm/Cycle/Type.lean @@ -31,7 +31,6 @@ In this file we define the cycle type of a permutation. there exists an element of order `p` in `G`. This is known as Cauchy's theorem. -/ - namespace Equiv.Perm open Mathlib (Vector) @@ -65,7 +64,7 @@ theorem cycleType_eq {σ : Perm α} (l : List (Perm α)) (h0 : l.prod = σ) σ.cycleType = l.map (Finset.card ∘ support) := by have hl : l.Nodup := nodup_of_pairwise_disjoint_cycles h1 h2 rw [cycleType_eq' l.toFinset] - · simp [List.dedup_eq_self.mpr hl, (· ∘ ·)] + · simp [List.dedup_eq_self.mpr hl, Function.comp_def] · simpa using h1 · simpa [hl] using h2 · simp [hl, h0] @@ -135,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 @@ -418,7 +422,7 @@ theorem rotate_length : rotate v n = v := end VectorsProdEqOne --- TODO: Make make the `Finite` version of this theorem the default +-- TODO: Make the `Finite` version of this theorem the default /-- For every prime `p` dividing the order of a finite group `G` there exists an element of order `p` in `G`. This is known as Cauchy's theorem. -/ theorem _root_.exists_prime_orderOf_dvd_card {G : Type*} [Group G] [Fintype G] (p : ℕ) @@ -453,7 +457,7 @@ theorem _root_.exists_prime_orderOf_dvd_card {G : Type*} [Group G] [Fintype G] ( · rw [Subtype.ext_iff_val, Subtype.ext_iff_val, hg, hg', v.1.2] simp only [v₀, Vector.replicate] --- TODO: Make make the `Finite` version of this theorem the default +-- TODO: Make the `Finite` version of this theorem the default /-- 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 : ℕ) @@ -462,7 +466,7 @@ theorem _root_.exists_prime_addOrderOf_dvd_card {G : Type*} [AddGroup G] [Fintyp attribute [to_additive existing] exists_prime_orderOf_dvd_card --- TODO: Make make the `Finite` version of this theorem the default +-- TODO: Make the `Finite` version of this theorem the default /-- For every prime `p` dividing the order of a finite group `G` there exists an element of order `p` in `G`. This is known as Cauchy's theorem. -/ @[to_additive] diff --git a/Mathlib/GroupTheory/Perm/DomMulAct.lean b/Mathlib/GroupTheory/Perm/DomMulAct.lean index 716f2084d8364..4bfd4c758ab0d 100644 --- a/Mathlib/GroupTheory/Perm/DomMulAct.lean +++ b/Mathlib/GroupTheory/Perm/DomMulAct.lean @@ -6,9 +6,9 @@ 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.Data.Fintype.Basic import Mathlib.Data.Fintype.Perm +import Mathlib.Data.Set.Card 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 : α → ι} @@ -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 [Function.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 b5ba110fa6dae..7df1d1ceaefbe 100644 --- a/Mathlib/GroupTheory/Perm/Fin.lean +++ b/Mathlib/GroupTheory/Perm/Fin.lean @@ -92,9 +92,10 @@ theorem finRotate_succ_eq_decomposeFin {n : ℕ} : @[simp] theorem sign_finRotate (n : ℕ) : Perm.sign (finRotate (n + 1)) = (-1) ^ n := by - induction' n with n ih - · simp - · rw [finRotate_succ_eq_decomposeFin] + induction n with + | zero => simp + | succ n ih => + rw [finRotate_succ_eq_decomposeFin] simp [ih, pow_succ] @[simp] diff --git a/Mathlib/GroupTheory/Perm/Finite.lean b/Mathlib/GroupTheory/Perm/Finite.lean index 3e5fb88d4607f..4c4f0cfef47b7 100644 --- a/Mathlib/GroupTheory/Perm/Finite.lean +++ b/Mathlib/GroupTheory/Perm/Finite.lean @@ -13,7 +13,7 @@ import Mathlib.Logic.Equiv.Fintype # Permutations on `Fintype`s This file contains miscellaneous lemmas about `Equiv.Perm` and `Equiv.swap`, building on top -of those in `Data/Equiv/Basic` and other files in `GroupTheory/Perm/*`. +of those in `Logic/Equiv/Basic.lean` and other files in `GroupTheory/Perm/*`. -/ universe u v diff --git a/Mathlib/GroupTheory/Perm/List.lean b/Mathlib/GroupTheory/Perm/List.lean index 092595ac44ce4..1cdc01f35e5cd 100644 --- a/Mathlib/GroupTheory/Perm/List.lean +++ b/Mathlib/GroupTheory/Perm/List.lean @@ -144,12 +144,6 @@ theorem formPerm_apply_get_length (x : α) (xs : List α) : formPerm (x :: xs) ((x :: xs).get (Fin.mk xs.length (by simp))) = x := formPerm_apply_getElem_length .. -set_option linter.deprecated false in -@[deprecated formPerm_apply_getElem_length (since := "2024-05-30")] -theorem formPerm_apply_nthLe_length (x : α) (xs : List α) : - formPerm (x :: xs) ((x :: xs).nthLe xs.length (by simp)) = x := - formPerm_apply_getElem_length .. - theorem formPerm_apply_head (x y : α) (xs : List α) (h : Nodup (x :: y :: xs)) : formPerm (x :: y :: xs) x = y := by simp [formPerm_apply_of_not_mem h.not_mem] @@ -165,12 +159,6 @@ theorem formPerm_apply_get_zero (l : List α) (h : Nodup l) (hl : 1 < l.length) formPerm l (l.get (Fin.mk 0 (by omega))) = l.get (Fin.mk 1 hl) := formPerm_apply_getElem_zero l h hl -set_option linter.deprecated false in -@[deprecated formPerm_apply_getElem_zero (since := "2024-05-30")] -theorem formPerm_apply_nthLe_zero (l : List α) (h : Nodup l) (hl : 1 < l.length) : - formPerm l (l.nthLe 0 (by omega)) = l.nthLe 1 hl := by - apply formPerm_apply_get_zero _ h - variable (l) theorem formPerm_eq_head_iff_eq_getLast (x y : α) : @@ -199,12 +187,6 @@ theorem formPerm_apply_lt_get (xs : List α) (h : Nodup xs) (n : ℕ) (hn : n + xs.get (Fin.mk (n + 1) hn) := by simp_all [formPerm_apply_lt_getElem] -set_option linter.deprecated false in -@[deprecated formPerm_apply_lt_get (since := "2024-05-30")] -theorem formPerm_apply_lt (xs : List α) (h : Nodup xs) (n : ℕ) (hn : n + 1 < xs.length) : - formPerm xs (xs.nthLe n ((Nat.lt_succ_self n).trans hn)) = xs.nthLe (n + 1) hn := by - apply formPerm_apply_lt_get _ h - theorem formPerm_apply_getElem (xs : List α) (w : Nodup xs) (i : ℕ) (h : i < xs.length) : formPerm xs xs[i] = xs[(i + 1) % xs.length]'(Nat.mod_lt _ (i.zero_le.trans_lt h)) := by @@ -225,13 +207,6 @@ theorem formPerm_apply_get (xs : List α) (h : Nodup xs) (i : Fin xs.length) : xs.get ⟨((i.val + 1) % xs.length), (Nat.mod_lt _ (i.val.zero_le.trans_lt i.isLt))⟩ := by simp [formPerm_apply_getElem, h] -set_option linter.deprecated false in -@[deprecated formPerm_apply_get (since := "2024-04-23")] -theorem formPerm_apply_nthLe (xs : List α) (h : Nodup xs) (n : ℕ) (hn : n < xs.length) : - formPerm xs (xs.nthLe n hn) = - xs.nthLe ((n + 1) % xs.length) (Nat.mod_lt _ (n.zero_le.trans_lt hn)) := by - apply formPerm_apply_get _ h - theorem support_formPerm_of_nodup' (l : List α) (h : Nodup l) (h' : ∀ x : α, l ≠ [x]) : { x | formPerm l x ≠ x } = l.toFinset := by apply _root_.le_antisymm @@ -307,13 +282,6 @@ theorem formPerm_pow_apply_get (l : List α) (h : Nodup l) (n : ℕ) (i : Fin l. l.get ⟨((i.val + n) % l.length), (Nat.mod_lt _ (i.val.zero_le.trans_lt i.isLt))⟩ := by simp [formPerm_pow_apply_getElem, h] -set_option linter.deprecated false in -@[deprecated formPerm_pow_apply_get (since := "2024-04-23")] -theorem formPerm_pow_apply_nthLe (l : List α) (h : Nodup l) (n k : ℕ) (hk : k < l.length) : - (formPerm l ^ n) (l.nthLe k hk) = - l.nthLe ((k + n) % l.length) (Nat.mod_lt _ (k.zero_le.trans_lt hk)) := - formPerm_pow_apply_get l h n ⟨k, hk⟩ - theorem formPerm_pow_apply_head (x : α) (l : List α) (h : Nodup (x :: l)) (n : ℕ) : (formPerm (x :: l) ^ n) x = (x :: l)[(n % (x :: l).length)]'(Nat.mod_lt _ (Nat.zero_lt_succ _)) := by diff --git a/Mathlib/GroupTheory/Perm/Sign.lean b/Mathlib/GroupTheory/Perm/Sign.lean index 1f4c096e2337d..269920ef0aab3 100644 --- a/Mathlib/GroupTheory/Perm/Sign.lean +++ b/Mathlib/GroupTheory/Perm/Sign.lean @@ -47,7 +47,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. -/ @@ -159,7 +159,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 @@ -255,7 +255,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 @@ -417,7 +417,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⟩ @@ -526,7 +526,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 @@ -549,7 +549,7 @@ theorem sign_prodCongrRight (σ : α → Perm β) : sign (prodCongrRight σ) = exact List.mem_toFinset.mpr (mem_l b) rw [← prod_prodExtendRight σ hl mem_l, map_list_prod sign, List.map_map, ← l_to_finset, List.prod_toFinset _ hl] - simp_rw [← fun a => sign_prodExtendRight a (σ a), Function.comp] + simp_rw [← fun a => sign_prodExtendRight a (σ a), Function.comp_def] theorem sign_prodCongrLeft (σ : α → Perm β) : sign (prodCongrLeft σ) = ∏ k, sign (σ k) := by refine (sign_eq_sign_of_equiv _ _ (prodComm β α) ?_).trans (sign_prodCongrRight σ) diff --git a/Mathlib/GroupTheory/Perm/Support.lean b/Mathlib/GroupTheory/Perm/Support.lean index 63593ca5a6715..f95ba42476e2a 100644 --- a/Mathlib/GroupTheory/Perm/Support.lean +++ b/Mathlib/GroupTheory/Perm/Support.lean @@ -279,7 +279,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 +296,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] @@ -326,6 +332,37 @@ theorem support_inv (σ : Perm α) : support σ⁻¹ = σ.support := by theorem apply_mem_support {x : α} : f x ∈ f.support ↔ x ∈ f.support := by rw [mem_support, mem_support, Ne, Ne, apply_eq_iff_eq] +/-- 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 + -- @[simp] -- Porting note (#10618): simp can prove this theorem pow_apply_mem_support {n : ℕ} {x : α} : (f ^ n) x ∈ f.support ↔ x ∈ f.support := by simp only [mem_support, ne_eq, apply_pow_apply_eq_iff] @@ -390,7 +427,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,7 +524,7 @@ 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 _) diff --git a/Mathlib/GroupTheory/PresentedGroup.lean b/Mathlib/GroupTheory/PresentedGroup.lean index 184b89f21a66b..35916a0da95d5 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 +import Mathlib.GroupTheory.QuotientGroup.Basic /-! # 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 6f3baeb1be190..ab561721ed4f6 100644 --- a/Mathlib/GroupTheory/PushoutI.lean +++ b/Mathlib/GroupTheory/PushoutI.lean @@ -301,7 +301,7 @@ theorem prod_empty : (empty : NormalWord d).prod = 1 := by simp [prod, empty] /-- A constructor that multiplies a `NormalWord` by an element, with condition to make -sure the underlying list does get longer. -/ +sure the underlying list does get longer. -/ @[simps!] noncomputable def cons {i} (g : G i) (w : NormalWord d) (hmw : w.fstIdx ≠ some i) (hgr : g ∉ (φ i).range) : NormalWord d := @@ -328,7 +328,7 @@ variable [DecidableEq ι] [∀ i, DecidableEq (G i)] /-- Given a word in `CoprodI`, if every letter is in the transversal and when we multiply by an element of the base group it still has this property, -then the element of the base group we multiplied by was one. -/ +then the element of the base group we multiplied by was one. -/ theorem eq_one_of_smul_normalized (w : CoprodI.Word G) {i : ι} (h : H) (hw : ∀ i g, ⟨i, g⟩ ∈ w.toList → g ∈ d.set i) (hφw : ∀ j g, ⟨j, g⟩ ∈ (CoprodI.of (φ i h) • w).toList → g ∈ d.set j) : @@ -355,8 +355,9 @@ theorem eq_one_of_smul_normalized (w : CoprodI.Word G) {i : ι} (h : H) equiv_mul_left_of_mem (d.compl i) ⟨_, rfl⟩ , hhead, Subtype.ext_iff, Prod.ext_iff, Subgroup.coe_mul] at h rcases h with ⟨h₁, h₂⟩ - rw [h₂, equiv_one (d.compl i) (one_mem _) (d.one_mem _), mul_one, - ((injective_iff_map_eq_one' _).1 (d.injective i))] at h₁ + rw [h₂, equiv_one (d.compl i) (one_mem _) (d.one_mem _)] at h₁ + erw [mul_one] at h₁ + simp only [((injective_iff_map_eq_one' _).1 (d.injective i))] at h₁ contradiction · rw [Word.equivPair_head] dsimp diff --git a/Mathlib/GroupTheory/QuotientGroup.lean b/Mathlib/GroupTheory/QuotientGroup/Basic.lean similarity index 91% rename from Mathlib/GroupTheory/QuotientGroup.lean rename to Mathlib/GroupTheory/QuotientGroup/Basic.lean index b1570f17976f1..2172f44a0ecee 100644 --- a/Mathlib/GroupTheory/QuotientGroup.lean +++ b/Mathlib/GroupTheory/QuotientGroup/Basic.lean @@ -2,13 +2,12 @@ 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.Algebra.Group.Subgroup.Finite +-- 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.Coset +import Mathlib.GroupTheory.Coset.Basic /-! # Quotients of groups by normal subgroups @@ -52,13 +51,13 @@ variable {G : Type u} [Group G] (N : Subgroup G) [nN : N.Normal] {H : Type v} [G @[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 + mul' := fun {a b c d} hab hcd => by rw [leftRel_eq] at hab hcd ⊢ dsimp only calc - (a * c)⁻¹ * (b * d) = c⁻¹ * (a⁻¹ * b) * c⁻¹⁻¹ * (c⁻¹ * d) := by + 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] - _ ∈ N := N.mul_mem (nN.conj_mem _ hab _) hcd @[to_additive] instance Quotient.group : Group (G ⧸ N) := @@ -168,6 +167,11 @@ theorem mk_prod {G ι : Type*} [CommGroup G] (N : Subgroup G) (s : Finset ι) {f @[to_additive (attr := simp)] lemma map_mk'_self : N.map (mk' N) = ⊥ := by aesop +@[to_additive QuotientAddGroup.strictMono_comap_prod_map] +theorem strictMono_comap_prod_map : + StrictMono fun H : Subgroup G ↦ (H.comap N.subtype, H.map (mk' N)) := + strictMono_comap_prod_image N + /-- A group homomorphism `φ : G →* M` with `N ⊆ ker(φ)` descends (i.e. `lift`s) to a group homomorphism `G/N →* M`. -/ @[to_additive "An `AddGroup` homomorphism `φ : G →+ M` with `N ⊆ ker(φ)` descends (i.e. `lift`s) @@ -321,7 +325,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 := @@ -341,7 +345,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 => @@ -424,7 +428,7 @@ Applying this equiv is nicer than rewriting along the equalities, since the type -/ @[to_additive "Let `A', A, B', B` be subgroups of `G`. If `A' = B'` and `A = B`, then the quotients `A / (A' ⊓ A)` and `B / (B' ⊓ B)` are isomorphic. Applying this equiv is nicer than rewriting along -the equalities, since the type of `(A'.addSubgroupOf A : AddSubgroup A)` depends on on `A`. "] +the equalities, since the type of `(A'.addSubgroupOf A : AddSubgroup A)` depends on `A`. "] 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 := @@ -520,7 +524,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] @@ -611,38 +615,3 @@ theorem mk_int_mul (n : ℤ) (a : R) : ((n * a : R) : R ⧸ N) = n • ↑a := b rw [← zsmul_eq_mul, mk_zsmul N a n] end QuotientAddGroup - -namespace Group - -open scoped Classical - -open QuotientGroup Subgroup - -variable {F G H : Type u} [Group F] [Group G] [Group H] [Fintype F] [Fintype H] -variable (f : F →* G) (g : G →* H) - -/-- If `F` and `H` are finite such that `ker(G →* H) ≤ im(F →* G)`, then `G` is finite. -/ -@[to_additive "If `F` and `H` are finite such that `ker(G →+ H) ≤ im(F →+ G)`, then `G` is finite."] -noncomputable def fintypeOfKerLeRange (h : g.ker ≤ f.range) : Fintype G := - @Fintype.ofEquiv _ _ - (@instFintypeProd _ _ (Fintype.ofInjective _ <| kerLift_injective g) <| - Fintype.ofInjective _ <| inclusion_injective h) - groupEquivQuotientProdSubgroup.symm - -/-- If `F` and `H` are finite such that `ker(G →* H) = im(F →* G)`, then `G` is finite. -/ -@[to_additive "If `F` and `H` are finite such that `ker(G →+ H) = im(F →+ G)`, then `G` is finite."] -noncomputable def fintypeOfKerEqRange (h : g.ker = f.range) : Fintype G := - fintypeOfKerLeRange _ _ h.le - -/-- If `ker(G →* H)` and `H` are finite, then `G` is finite. -/ -@[to_additive "If `ker(G →+ H)` and `H` are finite, then `G` is finite."] -noncomputable def fintypeOfKerOfCodom [Fintype g.ker] : Fintype G := - fintypeOfKerLeRange ((topEquiv : _ ≃* G).toMonoidHom.comp <| inclusion le_top) g fun x hx => - ⟨⟨x, hx⟩, rfl⟩ - -/-- If `F` and `coker(F →* G)` are finite, then `G` is finite. -/ -@[to_additive "If `F` and `coker(F →+ G)` are finite, then `G` is finite."] -noncomputable def fintypeOfDomOfCoker [Normal f.range] [Fintype <| G ⧸ f.range] : Fintype G := - fintypeOfKerLeRange _ (mk' f.range) fun x => (eq_one_iff x).mp - -end Group diff --git a/Mathlib/GroupTheory/QuotientGroup/Finite.lean b/Mathlib/GroupTheory/QuotientGroup/Finite.lean new file mode 100644 index 0000000000000..76877f51f87b7 --- /dev/null +++ b/Mathlib/GroupTheory/QuotientGroup/Finite.lean @@ -0,0 +1,53 @@ +/- +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.Algebra.Group.Subgroup.Finite +import Mathlib.GroupTheory.QuotientGroup.Basic + +/-! +# Deducing finiteness of a group. +-/ + +open Function +open scoped Pointwise + +universe u v w x + +namespace Group + +open scoped Classical + +open QuotientGroup Subgroup + +variable {F G H : Type u} [Group F] [Group G] [Group H] [Fintype F] [Fintype H] +variable (f : F →* G) (g : G →* H) + +/-- If `F` and `H` are finite such that `ker(G →* H) ≤ im(F →* G)`, then `G` is finite. -/ +@[to_additive "If `F` and `H` are finite such that `ker(G →+ H) ≤ im(F →+ G)`, then `G` is finite."] +noncomputable def fintypeOfKerLeRange (h : g.ker ≤ f.range) : Fintype G := + @Fintype.ofEquiv _ _ + (@instFintypeProd _ _ (Fintype.ofInjective _ <| kerLift_injective g) <| + Fintype.ofInjective _ <| inclusion_injective h) + groupEquivQuotientProdSubgroup.symm + +/-- If `F` and `H` are finite such that `ker(G →* H) = im(F →* G)`, then `G` is finite. -/ +@[to_additive "If `F` and `H` are finite such that `ker(G →+ H) = im(F →+ G)`, then `G` is finite."] +noncomputable def fintypeOfKerEqRange (h : g.ker = f.range) : Fintype G := + fintypeOfKerLeRange _ _ h.le + +/-- If `ker(G →* H)` and `H` are finite, then `G` is finite. -/ +@[to_additive "If `ker(G →+ H)` and `H` are finite, then `G` is finite."] +noncomputable def fintypeOfKerOfCodom [Fintype g.ker] : Fintype G := + fintypeOfKerLeRange ((topEquiv : _ ≃* G).toMonoidHom.comp <| inclusion le_top) g fun x hx => + ⟨⟨x, hx⟩, rfl⟩ + +/-- If `F` and `coker(F →* G)` are finite, then `G` is finite. -/ +@[to_additive "If `F` and `coker(F →+ G)` are finite, then `G` is finite."] +noncomputable def fintypeOfDomOfCoker [Normal f.range] [Fintype <| G ⧸ f.range] : Fintype G := + fintypeOfKerLeRange _ (mk' f.range) fun x => (eq_one_iff x).mp + +end Group diff --git a/Mathlib/GroupTheory/SchurZassenhaus.lean b/Mathlib/GroupTheory/SchurZassenhaus.lean index 1cb524d82f333..a143963c7cc26 100644 --- a/Mathlib/GroupTheory/SchurZassenhaus.lean +++ b/Mathlib/GroupTheory/SchurZassenhaus.lean @@ -262,8 +262,8 @@ private theorem exists_right_complement'_of_coprime_aux' [Finite G] (hG : Nat.ca {N : Subgroup G} [N.Normal] (hN : Nat.Coprime (Nat.card N) N.index) : ∃ H : Subgroup G, IsComplement' N H := by revert G - apply Nat.strongInductionOn n - rintro n ih G _ _ rfl N _ hN + induction n using Nat.strongRecOn with | ind n ih => ?_ + rintro G _ _ rfl N _ hN refine not_forall_not.mp fun h3 => ?_ haveI := SchurZassenhausInduction.step7 hN (fun G' _ _ hG' => by apply ih _ hG'; rfl) h3 exact not_exists_of_forall_not h3 (exists_right_complement'_of_coprime_aux hN) diff --git a/Mathlib/GroupTheory/SemidirectProduct.lean b/Mathlib/GroupTheory/SemidirectProduct.lean index 904d910b72cfa..6996df7ab8182 100644 --- a/Mathlib/GroupTheory/SemidirectProduct.lean +++ b/Mathlib/GroupTheory/SemidirectProduct.lean @@ -222,7 +222,7 @@ section Map variable {N₁ : Type*} {G₁ : Type*} [Group N₁] [Group G₁] {φ₁ : G₁ →* MulAut N₁} /-- Define a map from `N ⋊[φ] G` to `N₁ ⋊[φ₁] G₁` given maps `N →* N₁` and `G →* G₁` that - satisfy a commutativity condition `∀ n g, f₁ (φ g n) = φ₁ (f₂ g) (f₁ n)`. -/ + satisfy a commutativity condition `∀ n g, f₁ (φ g n) = φ₁ (f₂ g) (f₁ n)`. -/ def map (f₁ : N →* N₁) (f₂ : G →* G₁) (h : ∀ g : G, f₁.comp (φ g).toMonoidHom = (φ₁ (f₂ g)).toMonoidHom.comp f₁) : N ⋊[φ] G →* N₁ ⋊[φ₁] G₁ where diff --git a/Mathlib/GroupTheory/Solvable.lean b/Mathlib/GroupTheory/Solvable.lean index 9082598ea518c..f3783500b961a 100644 --- a/Mathlib/GroupTheory/Solvable.lean +++ b/Mathlib/GroupTheory/Solvable.lean @@ -66,17 +66,17 @@ variable (f) theorem map_derivedSeries_le_derivedSeries (n : ℕ) : (derivedSeries G n).map f ≤ derivedSeries G' n := by - induction' n with n ih - · exact le_top - · simp only [derivedSeries_succ, map_commutator, commutator_mono, ih] + induction n with + | zero => exact le_top + | succ n ih => simp only [derivedSeries_succ, map_commutator, commutator_mono, ih] variable {f} theorem derivedSeries_le_map_derivedSeries (hf : Function.Surjective f) (n : ℕ) : derivedSeries G' n ≤ (derivedSeries G n).map f := by - induction' n with n ih - · exact (map_top_of_surjective f hf).ge - · exact commutator_le_map_commutator ih ih + induction n with + | zero => exact (map_top_of_surjective f hf).ge + | succ n ih => exact commutator_le_map_commutator ih ih theorem map_derivedSeries_eq (hf : Function.Surjective f) (n : ℕ) : (derivedSeries G n).map f = derivedSeries G' n := @@ -152,12 +152,13 @@ section IsSimpleGroup variable [IsSimpleGroup G] theorem IsSimpleGroup.derivedSeries_succ {n : ℕ} : derivedSeries G n.succ = commutator G := by - induction' n with n ih - · exact derivedSeries_one G - rw [_root_.derivedSeries_succ, ih, _root_.commutator] - cases' (commutator_normal (⊤ : Subgroup G) (⊤ : Subgroup G)).eq_bot_or_eq_top with h h - · rw [h, commutator_bot_left] - · rwa [h] + induction n with + | zero => exact derivedSeries_one G + | succ n ih => + rw [_root_.derivedSeries_succ, ih, _root_.commutator] + cases' (commutator_normal (⊤ : Subgroup G) (⊤ : Subgroup G)).eq_bot_or_eq_top with h h + · rw [h, commutator_bot_left] + · rwa [h] theorem IsSimpleGroup.comm_iff_isSolvable : (∀ a b : G, a * b = b * a) ↔ IsSolvable G := ⟨isSolvable_of_comm, fun ⟨⟨n, hn⟩⟩ => by @@ -179,7 +180,7 @@ theorem not_solvable_of_mem_derivedSeries {g : G} (h1 : g ≠ 1) (h2 : ∀ n : ℕ, g ∈ derivedSeries G n) : ¬IsSolvable G := mt (isSolvable_def _).mp (not_exists_of_forall_not fun n h => - h1 (Subgroup.mem_bot.mp ((congr_arg (Membership.mem g) h).mp (h2 n)))) + h1 (Subgroup.mem_bot.mp ((congr_arg (g ∈ ·) h).mp (h2 n)))) theorem Equiv.Perm.fin_5_not_solvable : ¬IsSolvable (Equiv.Perm (Fin 5)) := by let x : Equiv.Perm (Fin 5) := ⟨![1, 2, 0, 3, 4], ![2, 0, 1, 3, 4], by decide, by decide⟩ @@ -187,9 +188,10 @@ theorem Equiv.Perm.fin_5_not_solvable : ¬IsSolvable (Equiv.Perm (Fin 5)) := by let z : Equiv.Perm (Fin 5) := ⟨![0, 3, 2, 1, 4], ![0, 3, 2, 1, 4], by decide, by decide⟩ have key : x = z * ⁅x, y * x * y⁻¹⁆ * z⁻¹ := by unfold_let; decide refine not_solvable_of_mem_derivedSeries (show x ≠ 1 by decide) fun n => ?_ - induction' n with n ih - · exact mem_top x - · rw [key, (derivedSeries_normal _ _).mem_comm_iff, inv_mul_cancel_left] + induction n with + | zero => exact mem_top x + | succ n ih => + rw [key, (derivedSeries_normal _ _).mem_comm_iff, inv_mul_cancel_left] exact commutator_mem_commutator ih ((derivedSeries_normal _ _).conj_mem _ ih _) theorem Equiv.Perm.not_solvable (X : Type*) (hX : 5 ≤ Cardinal.mk X) : diff --git a/Mathlib/GroupTheory/SpecificGroups/Alternating.lean b/Mathlib/GroupTheory/SpecificGroups/Alternating.lean index 4836d6d64026d..200e6d06c39ac 100644 --- a/Mathlib/GroupTheory/SpecificGroups/Alternating.lean +++ b/Mathlib/GroupTheory/SpecificGroups/Alternating.lean @@ -3,10 +3,10 @@ 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.Group.ConjFinite import Mathlib.GroupTheory.Perm.Fin import Mathlib.GroupTheory.Subgroup.Simple import Mathlib.Tactic.IntervalCases +import Mathlib.Data.Fintype.Units /-! # Alternating Groups diff --git a/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean b/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean index 965253cc75dc7..38b5ab4ee0b07 100644 --- a/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean +++ b/Mathlib/GroupTheory/SpecificGroups/Cyclic.lean @@ -109,7 +109,7 @@ theorem isCyclic_of_orderOf_eq_card [Fintype α] (x : α) (hx : orderOf x = Fint use x rw [← Set.range_iff_surjective, ← coe_zpowers] rw [← Fintype.card_congr (Equiv.Set.univ α), ← Fintype.card_zpowers] at hx - exact Set.eq_of_subset_of_card_le (Set.subset_univ _) (ge_of_eq hx) + convert Set.eq_of_subset_of_card_le (Set.subset_univ _) (ge_of_eq hx) @[deprecated (since := "2024-02-21")] alias isAddCyclic_of_orderOf_eq_card := isAddCyclic_of_addOrderOf_eq_card @@ -428,7 +428,7 @@ private theorem card_orderOf_eq_totient_aux₁ : 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) = @@ -512,10 +512,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 +539,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 +656,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 26ff5fc37728e..53949cd3a109b 100644 --- a/Mathlib/GroupTheory/SpecificGroups/Dihedral.lean +++ b/Mathlib/GroupTheory/SpecificGroups/Dihedral.lean @@ -5,6 +5,7 @@ Authors: Shing Tak Lam -/ import Mathlib.Data.ZMod.Basic import Mathlib.GroupTheory.Exponent +import Mathlib.GroupTheory.GroupAction.CardCommute /-! # Dihedral Groups @@ -110,7 +111,7 @@ instance : Infinite (DihedralGroup 0) := DihedralGroup.fintypeHelper.infinite_iff.mp inferInstance instance : Nontrivial (DihedralGroup n) := - ⟨⟨r 0, sr 0, by simp_rw [ne_eq, not_false_eq_true]⟩⟩ + ⟨⟨r 0, sr 0, by simp_rw [ne_eq, reduceCtorEq, not_false_eq_true]⟩⟩ /-- If `0 < n`, then `DihedralGroup n` has `2n` elements. -/ @@ -149,7 +150,7 @@ theorem orderOf_sr (i : ZMod n) : orderOf (sr i) = 2 := by · rw [sq, sr_mul_self] · -- Porting note: Previous proof was `decide` revert n - simp_rw [one_def, ne_eq, forall_const, not_false_eq_true] + simp_rw [one_def, ne_eq, reduceCtorEq, forall_const, not_false_eq_true] /-- If `0 < n`, then `r 1` has order `n`. -/ diff --git a/Mathlib/GroupTheory/SpecificGroups/Quaternion.lean b/Mathlib/GroupTheory/SpecificGroups/Quaternion.lean index be7d8cba6dabf..0db9e8be9fe21 100644 --- a/Mathlib/GroupTheory/SpecificGroups/Quaternion.lean +++ b/Mathlib/GroupTheory/SpecificGroups/Quaternion.lean @@ -204,7 +204,7 @@ theorem orderOf_xa [NeZero n] (i : ZMod (2 * n)) : orderOf (xa i) = 4 := by apply_fun ZMod.val at h' apply_fun (· / n) at h' simp only [ZMod.val_natCast, ZMod.val_zero, Nat.zero_div, Nat.mod_mul_left_div_self, - Nat.div_self (NeZero.pos n)] at h' + Nat.div_self (NeZero.pos n), reduceCtorEq] at h' · norm_num /-- In the special case `n = 1`, `Quaternion 1` is a cyclic group (of order `4`). -/ diff --git a/Mathlib/GroupTheory/Subgroup/Center.lean b/Mathlib/GroupTheory/Subgroup/Center.lean index a3b3323d2c5ff..a3733d06b31fb 100644 --- a/Mathlib/GroupTheory/Subgroup/Center.lean +++ b/Mathlib/GroupTheory/Subgroup/Center.lean @@ -15,9 +15,6 @@ import Mathlib.GroupTheory.Submonoid.Center assert_not_exists Multiset assert_not_exists Ring -open Function -open Int - variable {G : Type*} [Group G] namespace Subgroup diff --git a/Mathlib/GroupTheory/Subgroup/Centralizer.lean b/Mathlib/GroupTheory/Subgroup/Centralizer.lean index d5639da747843..19e40261c4734 100644 --- a/Mathlib/GroupTheory/Subgroup/Centralizer.lean +++ b/Mathlib/GroupTheory/Subgroup/Centralizer.lean @@ -10,10 +10,6 @@ import Mathlib.GroupTheory.Submonoid.Centralizer # Centralizers of subgroups -/ - -open Function -open Int - variable {G : Type*} [Group G] namespace Subgroup diff --git a/Mathlib/GroupTheory/Sylow.lean b/Mathlib/GroupTheory/Sylow.lean index 45a76037e7714..a534e244575fe 100644 --- a/Mathlib/GroupTheory/Sylow.lean +++ b/Mathlib/GroupTheory/Sylow.lean @@ -332,7 +332,8 @@ theorem Sylow.conj_eq_normalizer_conj_of_mem_centralizer [Fact p.Prime] [Finite theorem Sylow.conj_eq_normalizer_conj_of_mem [Fact p.Prime] [Finite (Sylow p G)] (P : Sylow p G) [_hP : (P : Subgroup G).IsCommutative] (x g : G) (hx : x ∈ P) (hy : g⁻¹ * x * g ∈ P) : ∃ n ∈ (P : Subgroup G).normalizer, g⁻¹ * x * g = n⁻¹ * x * n := - P.conj_eq_normalizer_conj_of_mem_centralizer x g (le_centralizer P hx) (le_centralizer P hy) + P.conj_eq_normalizer_conj_of_mem_centralizer x g + (le_centralizer (P : Subgroup G) hx) (le_centralizer (P : Subgroup G) hy) /-- Sylow `p`-subgroups are in bijection with cosets of the normalizer of a Sylow `p`-subgroup -/ noncomputable def Sylow.equivQuotientNormalizer [Fact p.Prime] [Finite (Sylow p G)] @@ -458,7 +459,7 @@ def fixedPointsMulLeftCosetsEquivQuotient (H : Subgroup G) [Finite (H : Set G)] rfl) /-- If `H` is a `p`-subgroup of `G`, then the index of `H` inside its normalizer is congruent - mod `p` to the index of `H`. -/ + mod `p` to the index of `H`. -/ theorem card_quotient_normalizer_modEq_card_quotient [Finite G] {p : ℕ} {n : ℕ} [hp : Fact p.Prime] {H : Subgroup G} (hH : Nat.card H = p ^ n) : Nat.card (normalizer H ⧸ Subgroup.comap ((normalizer H).subtype : normalizer H →* G) H) ≡ @@ -467,7 +468,7 @@ theorem card_quotient_normalizer_modEq_card_quotient [Finite G] {p : ℕ} {n : exact ((IsPGroup.of_card hH).card_modEq_card_fixedPoints _).symm /-- If `H` is a subgroup of `G` of cardinality `p ^ n`, then the cardinality of the - normalizer of `H` is congruent mod `p ^ (n + 1)` to the cardinality of `G`. -/ + normalizer of `H` is congruent mod `p ^ (n + 1)` to the cardinality of `G`. -/ theorem card_normalizer_modEq_card [Finite G] {p : ℕ} {n : ℕ} [hp : Fact p.Prime] {H : Subgroup G} (hH : Nat.card H = p ^ n) : Nat.card (normalizer H) ≡ Nat.card G [MOD p ^ (n + 1)] := by have : H.subgroupOf (normalizer H) ≃ H := (subgroupOfEquivOfLe le_normalizer).toEquiv diff --git a/Mathlib/GroupTheory/Torsion.lean b/Mathlib/GroupTheory/Torsion.lean index ec5b8b580bb9e..08d223f5db3ba 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 @@ -201,7 +201,10 @@ variable {G} {p} @[to_additive primaryComponent.exists_orderOf_eq_prime_nsmul "Elements of the `p`-primary component have additive order `p^n` for some `n`"] theorem primaryComponent.exists_orderOf_eq_prime_pow (g : CommMonoid.primaryComponent G p) : - ∃ n : ℕ, orderOf g = p ^ n := by simpa [primaryComponent] using g.property + ∃ n : ℕ, orderOf g = p ^ n := by + obtain ⟨_, hn⟩ := g.property + rw [orderOf_submonoid g] at hn + exact ⟨_, hn⟩ /-- The `p`- and `q`-primary components are disjoint for `p ≠ q`. -/ @[to_additive "The `p`- and `q`-primary components are disjoint for `p ≠ q`."] @@ -294,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. -/ @@ -323,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 @@ -368,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 @@ -380,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 0cd94971008a5..63b352144a998 100644 --- a/Mathlib/InformationTheory/Hamming.lean +++ b/Mathlib/InformationTheory/Hamming.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Wrenna Robson -/ import Mathlib.Analysis.Normed.Group.Basic -import Mathlib.Topology.Instances.Discrete /-! # Hamming spaces @@ -263,12 +262,12 @@ instance (α) [Semiring α] (β : ι → Type*) [∀ i, AddCommMonoid (β i)] [ /-! API to/from the type synonym. -/ -/-- `Hamming.toHamming` is the identity function to the `Hamming` of a type. -/ +/-- `Hamming.toHamming` is the identity function to the `Hamming` of a type. -/ @[match_pattern] def toHamming : (∀ i, β i) ≃ Hamming β := Equiv.refl _ -/-- `Hamming.ofHamming` is the identity function from the `Hamming` of a type. -/ +/-- `Hamming.ofHamming` is the identity function from the `Hamming` of a type. -/ @[match_pattern] def ofHamming : Hamming β ≃ ∀ i, β i := Equiv.refl _ diff --git a/Mathlib/Init.lean b/Mathlib/Init.lean new file mode 100644 index 0000000000000..dff297db373ea --- /dev/null +++ b/Mathlib/Init.lean @@ -0,0 +1,34 @@ +import Mathlib.Tactic.Linter.DocPrime +import Mathlib.Tactic.Linter.HashCommandLinter +import Mathlib.Tactic.Linter.GlobalAttributeIn +-- This file imports Batteries.Tactic.Lint, where the `env_linter` attribute is defined. +import Mathlib.Tactic.Linter.Lint +import Mathlib.Tactic.Linter.OldObtain +import Mathlib.Tactic.Linter.RefineLinter +import Mathlib.Tactic.Linter.UnusedTactic +import Mathlib.Tactic.Linter.Style + +/-! +This is the root file in Mathlib: it is imported by virtually *all* Mathlib files. +For this reason, the imports of this files are carefully curated. +Any modification involving a change in the imports of this file should be discussed beforehand. + +Here are some general guidelines: +* no bucket imports (e.g. `Batteries`/`Lean`/etc); +* every import needs to have a comment explaining why the import is there; +* strong preference for avoiding files that themselves have imports beyond `Lean`, and + any exception to this rule should by accompanied by a comment explaining the transitive imports. + +## Linters + +All syntax linters defined in Mathlib which are active by default are imported here. +Syntax linters need to be imported to take effect, hence we would like them to be imported +as early as possible. + +All linters imported here have no bulk imports; +**Not** imported in this file are +- the text-based linters in `Linters/TextBased.lean`, as they can be imported later +- the `minImports` linter, as that is still disabled by default. +- the `haveLet` linter, as it is currently disabled by default + +-/ diff --git a/Mathlib/Init/Algebra/Classes.lean b/Mathlib/Init/Algebra/Classes.lean index 0f9108a20df5d..bb4475917a4fd 100644 --- a/Mathlib/Init/Algebra/Classes.lean +++ b/Mathlib/Init/Algebra/Classes.lean @@ -3,7 +3,7 @@ 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/` @@ -15,183 +15,28 @@ Contributions assisting with this are appreciated. # 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 -/ -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 +set_option linter.deprecated false --- class IsLeftNull (α : Sort u) (op : α → α → α) (o : outParam α) : Prop where --- left_null : ∀ a, op o a = o +universe u v --- 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) --/ - -/-- `IsIrrefl X r` means the binary relation `r` on `X` is irreflexive (that is, `r x x` never -holds). -/ -class IsIrrefl (α : Sort u) (r : α → α → Prop) : Prop where - irrefl : ∀ a, ¬r a a - -/-- `IsRefl X r` means the binary relation `r` on `X` is reflexive. -/ -class IsRefl (α : Sort u) (r : α → α → Prop) : Prop where - refl : ∀ a, r a a - -/-- `IsSymm X r` means the binary relation `r` on `X` is symmetric. -/ -class IsSymm (α : Sort u) (r : α → α → Prop) : Prop where - symm : ∀ a b, r a b → r b 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) - -/-- `IsAsymm X r` means that the binary relation `r` on `X` is asymmetric, that is, -`r a b → ¬ r b a`. -/ -class IsAsymm (α : Sort u) (r : α → α → Prop) : Prop where - asymm : ∀ a b, r a b → ¬r b a - -/-- `IsAntisymm X r` means the binary relation `r` on `X` is antisymmetric. -/ -class IsAntisymm (α : Sort u) (r : α → α → Prop) : Prop where - antisymm : ∀ a b, r a b → r b a → a = b - -instance (priority := 100) IsAsymm.toIsAntisymm {α : Sort u} (r : α → α → Prop) [IsAsymm α r] : - IsAntisymm α r where - antisymm _ _ hx hy := (IsAsymm.asymm _ _ hx hy).elim - -/-- `IsTrans X r` means the binary relation `r` on `X` is transitive. -/ -class IsTrans (α : Sort u) (r : α → α → Prop) : Prop where - trans : ∀ a b c, r a b → r b c → r a c - -instance {α : Sort u} {r : α → α → Prop} [IsTrans α r] : Trans r r r := - ⟨IsTrans.trans _ _ _⟩ - -instance (priority := 100) {α : Sort u} {r : α → α → Prop} [Trans r r r] : IsTrans α r := - ⟨fun _ _ _ => Trans.trans⟩ - -/-- `IsTotal X r` means that the binary relation `r` on `X` is total, that is, that for any -`x y : X` we have `r x y` or `r y x`. -/ -class IsTotal (α : Sort u) (r : α → α → Prop) : Prop where - total : ∀ a b, r a b ∨ r b a - -/-- `IsPreorder X r` means that the binary relation `r` on `X` is a pre-order, that is, reflexive -and transitive. -/ -class IsPreorder (α : Sort u) (r : α → α → Prop) extends IsRefl α r, IsTrans α r : Prop - /-- `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 /-- Every total pre-order is a pre-order. -/ @@ -200,120 +45,32 @@ instance (priority := 100) isTotalPreorder_isPreorder (α : Sort u) (r : α → trans := s.trans refl a := Or.elim (@IsTotal.total _ r _ a a) id id -/-- `IsPartialOrder X r` means that the binary relation `r` on `X` is a partial order, that is, -`IsPreorder X r` and `IsAntisymm X r`. -/ -class IsPartialOrder (α : Sort u) (r : α → α → Prop) extends IsPreorder α r, IsAntisymm α r : Prop - -/-- `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 - -/-- `IsEquiv X r` means that the binary relation `r` on `X` is an equivalence relation, that -is, `IsPreorder X r` and `IsSymm X r`. -/ -class IsEquiv (α : Sort u) (r : α → α → Prop) extends IsPreorder α r, IsSymm α r : Prop - --- /-- `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 - -/-- `IsStrictOrder X r` means that the binary relation `r` on `X` is a strict order, that is, -`IsIrrefl X r` and `IsTrans X r`. -/ -class IsStrictOrder (α : Sort u) (r : α → α → Prop) extends IsIrrefl α 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")] class IsIncompTrans (α : Sort u) (lt : α → α → Prop) : 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 -/-- `IsStrictWeakOrder X lt` means that the binary relation `lt` on `X` is a strict weak order, -that is, `IsStrictOrder X lt` and `IsIncompTrans X lt`. -/ -class IsStrictWeakOrder (α : Sort u) (lt : α → α → Prop) extends IsStrictOrder α lt, - IsIncompTrans α lt : Prop - -/-- `IsTrichotomous X lt` means that the binary relation `lt` on `X` is trichotomous, that is, -either `lt a b` or `a = b` or `lt b a` for any `a` and `b`. -/ -class IsTrichotomous (α : Sort u) (lt : α → α → Prop) : Prop where - trichotomous : ∀ a b, lt a b ∨ a = b ∨ lt b a - -/-- `IsStrictTotalOrder X lt` means that the binary relation `lt` on `X` is a strict total order, -that is, `IsTrichotomous X lt` and `IsStrictOrder X lt`. -/ -class IsStrictTotalOrder (α : Sort u) (lt : α → α → Prop) extends IsTrichotomous α lt, - IsStrictOrder α lt : Prop - -/-- Equality is an equivalence relation. -/ -instance eq_isEquiv (α : Sort u) : IsEquiv α (· = ·) where - symm := @Eq.symm _ - trans := @Eq.trans _ - refl := Eq.refl +@[deprecated (since := "2024-07-30")] +instance (priority := 100) (α : Sort u) (lt : α → α → Prop) [IsStrictWeakOrder α lt] : + IsIncompTrans α lt := { ‹IsStrictWeakOrder α lt› with } section -variable {α : Sort u} {r : α → α → Prop} +variable {r : α → α → Prop} local infixl:50 " ≺ " => r -theorem irrefl [IsIrrefl α r] (a : α) : ¬a ≺ a := - IsIrrefl.irrefl a - -theorem refl [IsRefl α r] (a : α) : a ≺ a := - IsRefl.refl a - -theorem trans [IsTrans α r] {a b c : α} : a ≺ b → b ≺ c → a ≺ c := - IsTrans.trans _ _ _ - -theorem symm [IsSymm α r] {a b : α} : a ≺ b → b ≺ a := - IsSymm.symm _ _ - -theorem antisymm [IsAntisymm α r] {a b : α} : a ≺ b → b ≺ a → a = b := - IsAntisymm.antisymm _ _ - -theorem asymm [IsAsymm α r] {a b : α} : a ≺ b → ¬b ≺ a := - IsAsymm.asymm _ _ - -theorem trichotomous [IsTrichotomous α r] : ∀ a b : α, a ≺ b ∨ a = b ∨ b ≺ a := - IsTrichotomous.trichotomous - +@[deprecated (since := "2024-07-30")] theorem incomp_trans [IsIncompTrans α r] {a b c : α} : ¬a ≺ b ∧ ¬b ≺ a → ¬b ≺ c ∧ ¬c ≺ b → ¬a ≺ c ∧ ¬c ≺ a := IsIncompTrans.incomp_trans _ _ _ -instance (priority := 90) isAsymm_of_isTrans_of_isIrrefl [IsTrans α r] [IsIrrefl α r] : - IsAsymm α r := - ⟨fun a _b h₁ h₂ => absurd (_root_.trans h₁ h₂) (irrefl a)⟩ - section ExplicitRelationVariants variable (r) -@[elab_without_expected_type] -theorem irrefl_of [IsIrrefl α r] (a : α) : ¬a ≺ a := - irrefl a - -@[elab_without_expected_type] -theorem refl_of [IsRefl α r] (a : α) : a ≺ a := - refl a - -@[elab_without_expected_type] -theorem trans_of [IsTrans α r] {a b c : α} : a ≺ b → b ≺ c → a ≺ c := - _root_.trans - -@[elab_without_expected_type] -theorem symm_of [IsSymm α r] {a b : α} : a ≺ b → b ≺ a := - symm - -@[elab_without_expected_type] -theorem asymm_of [IsAsymm α r] {a b : α} : a ≺ b → ¬b ≺ a := - asymm - -@[elab_without_expected_type] -theorem total_of [IsTotal α r] (a b : α) : a ≺ b ∨ b ≺ a := - IsTotal.total _ _ - -@[elab_without_expected_type] -theorem trichotomous_of [IsTrichotomous α r] : ∀ a b : α, a ≺ b ∨ a = b ∨ b ≺ a := - trichotomous - -@[elab_without_expected_type] +@[elab_without_expected_type, deprecated (since := "2024-07-30")] theorem incomp_trans_of [IsIncompTrans α r] {a b c : α} : ¬a ≺ b ∧ ¬b ≺ a → ¬b ≺ c ∧ ¬c ≺ b → ¬a ≺ c ∧ ¬c ≺ a := incomp_trans @@ -326,29 +83,36 @@ namespace StrictWeakOrder section -variable {α : Sort u} {r : α → α → Prop} +variable {r : α → α → Prop} local infixl:50 " ≺ " => r +@[deprecated (since := "2024-07-30")] def Equiv (a b : α) : Prop := ¬a ≺ b ∧ ¬b ≺ a local infixl:50 " ≈ " => @Equiv _ r +@[deprecated (since := "2024-07-30")] theorem esymm {a b : α} : a ≈ b → b ≈ a := fun ⟨h₁, h₂⟩ => ⟨h₂, h₁⟩ +@[deprecated (since := "2024-07-30")] theorem not_lt_of_equiv {a b : α} : a ≈ b → ¬a ≺ b := fun h => h.1 +@[deprecated (since := "2024-07-30")] theorem not_lt_of_equiv' {a b : α} : a ≈ b → ¬b ≺ a := fun h => h.2 variable [IsStrictWeakOrder α r] +@[deprecated (since := "2024-07-30")] theorem erefl (a : α) : a ≈ a := ⟨irrefl a, irrefl a⟩ +@[deprecated (since := "2024-07-30")] theorem etrans {a b c : α} : a ≈ b → b ≈ c → a ≈ c := incomp_trans +@[deprecated (since := "2024-07-30")] instance isEquiv : IsEquiv α (@Equiv _ r) where refl := erefl trans _ _ _ := etrans @@ -357,10 +121,11 @@ 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 +@[deprecated (since := "2024-07-30")] theorem isStrictWeakOrder_of_isTotalPreorder {α : Sort u} {le : α → α → Prop} {lt : α → α → Prop} [DecidableRel le] [IsTotalPreorder α le] (h : ∀ a b, lt a b ↔ ¬le b a) : IsStrictWeakOrder α lt := @@ -382,22 +147,42 @@ theorem isStrictWeakOrder_of_isTotalPreorder {α : Sort u} {le : α → α → P have hca : le c a := trans_of le hcb hba And.intro (fun n => absurd hca (Iff.mp (h _ _) n)) fun n => absurd hac (Iff.mp (h _ _) n) } +section LinearOrder +variable {α : Type*} [LinearOrder α] + +set_option linter.deprecated false in +@[deprecated (since := "2024-07-30")] +instance : IsTotalPreorder α (· ≤ ·) where + trans := @le_trans _ _ + total := le_total + +set_option linter.deprecated false in +@[deprecated (since := "2024-07-30")] +instance isStrictWeakOrder_of_linearOrder : IsStrictWeakOrder α (· < ·) := + have : IsTotalPreorder α (· ≤ ·) := by infer_instance -- Porting note: added + isStrictWeakOrder_of_isTotalPreorder lt_iff_not_ge + +end LinearOrder + +@[deprecated (since := "2024-07-30")] theorem lt_of_lt_of_incomp {α : Sort u} {lt : α → α → Prop} [IsStrictWeakOrder α lt] [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 +@[deprecated (since := "2024-07-30")] theorem lt_of_incomp_of_lt {α : Sort u} {lt : α → α → Prop} [IsStrictWeakOrder α lt] [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 +@[deprecated (since := "2024-07-30")] theorem eq_of_incomp {α : Sort u} {lt : α → α → Prop} [IsTrichotomous α lt] {a b} : ¬lt a b ∧ ¬lt b a → a = b := fun ⟨nab, nba⟩ => match trichotomous_of lt a b with @@ -405,17 +190,17 @@ theorem eq_of_incomp {α : Sort u} {lt : α → α → Prop} [IsTrichotomous α | Or.inr (Or.inl hab) => hab | Or.inr (Or.inr hba) => absurd hba nba +@[deprecated (since := "2024-07-30")] theorem eq_of_eqv_lt {α : Sort u} {lt : α → α → Prop} [IsTrichotomous α lt] {a b} : a ≈[lt]b → a = b := eq_of_incomp +@[deprecated (since := "2024-07-30")] theorem incomp_iff_eq {α : Sort u} {lt : α → α → Prop} [IsTrichotomous α lt] [IsIrrefl α lt] (a b) : ¬lt a b ∧ ¬lt b a ↔ a = b := Iff.intro eq_of_incomp fun hab => hab ▸ And.intro (irrefl_of lt a) (irrefl_of lt a) +@[deprecated (since := "2024-07-30")] theorem eqv_lt_iff_eq {α : Sort u} {lt : α → α → Prop} [IsTrichotomous α lt] [IsIrrefl α lt] (a b) : a ≈[lt]b ↔ a = b := incomp_iff_eq a b - -theorem not_lt_of_lt {α : Sort u} {lt : α → α → Prop} [IsStrictOrder α lt] {a b} : - lt a b → ¬lt b a := fun h₁ h₂ => absurd (trans_of lt h₁ h₂) (irrefl_of lt _) diff --git a/Mathlib/Init/Classical.lean b/Mathlib/Init/Classical.lean deleted file mode 100644 index 2fd70039da0cb..0000000000000 --- a/Mathlib/Init/Classical.lean +++ /dev/null @@ -1,41 +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.Tactic.IrreducibleDef - -/-! -# 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.) - -We intend to move all the content of these files out into the main `Mathlib` directory structure. -Contributions assisting with this are appreciated. - -### alignments from lean 3 `init.classical` --/ - -namespace Classical - -attribute [local instance] propDecidable -attribute [local instance] decidableInhabited - -alias axiom_of_choice := axiomOfChoice -- TODO: fix in core -alias prop_complete := propComplete -- TODO: fix in core - -@[elab_as_elim] theorem cases_true_false (p : Prop → Prop) - (h1 : p True) (h2 : p False) (a : Prop) : p a := - Or.elim (prop_complete a) (fun ht : a = True ↦ ht.symm ▸ h1) fun hf : a = False ↦ hf.symm ▸ h2 - -theorem cases_on (a : Prop) {p : Prop → Prop} (h1 : p True) (h2 : p False) : p a := - @cases_true_false p h1 h2 a - -theorem cases {p : Prop → Prop} (h1 : p True) (h2 : p False) (a) : p a := cases_on a h1 h2 - -alias by_cases := byCases -alias by_contradiction := byContradiction - -theorem eq_false_or_eq_true (a : Prop) : a = False ∨ a = True := (prop_complete a).symm - -end Classical diff --git a/Mathlib/Init/Core.lean b/Mathlib/Init/Core.lean deleted file mode 100644 index 1627fc02f1afc..0000000000000 --- a/Mathlib/Init/Core.lean +++ /dev/null @@ -1,54 +0,0 @@ -/- -Copyright (c) 2014 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.Tactic.Relation.Trans - -/-! -# 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.) - -We intend to move all the content of these files out into the main `Mathlib` directory structure. -Contributions assisting with this are appreciated. - -# Notation, basic datatypes and type classes - -This file contains alignments from lean 3 `init.core`. --/ - --- Note: we do not currently auto-align constants. - --- TODO --- attribute [elab_as_elim, subst] Eq.subst - -attribute [trans] Eq.trans -attribute [symm] Eq.symm - -universe u v w - -def Prod.mk.injArrow {α : Type u} {β : Type v} {x₁ : α} {y₁ : β} {x₂ : α} {y₂ : β} : - (x₁, y₁) = (x₂, y₂) → ∀ ⦃P : Sort w⦄, (x₁ = x₂ → y₁ = y₂ → P) → P := - fun h₁ _ h₂ ↦ Prod.noConfusion h₁ h₂ - -def PProd.mk.injArrow {α : Type u} {β : Type v} {x₁ : α} {y₁ : β} {x₂ : α} {y₂ : β} : - (x₁, y₁) = (x₂, y₂) → ∀ ⦃P : Sort w⦄, (x₁ = x₂ → y₁ = y₂ → P) → P := - fun h₁ _ h₂ ↦ Prod.noConfusion h₁ h₂ - --- attribute [pp_using_anonymous_constructor] Sigma PSigma Subtype PProd And - --- Generic 'has'-stripping --- Note: we don't currently strip automatically for various reasons. - -attribute [simp] insert_emptyc_eq - --- Combinator calculus -namespace Combinator - -variable {α : Sort u} {β : Sort v} {γ : Sort w} -def I (a : α) := a -def K (a : α) (_b : β) := a -def S (x : α → β → γ) (y : α → β) (z : α) := x z (y z) - -end Combinator diff --git a/Mathlib/Init/Data/Fin/Basic.lean b/Mathlib/Init/Data/Fin/Basic.lean deleted file mode 100644 index 65540086b8caa..0000000000000 --- a/Mathlib/Init/Data/Fin/Basic.lean +++ /dev/null @@ -1,34 +0,0 @@ -/- -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 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.) - -We intend to move all the content of these files out into the main `Mathlib` directory structure. -Contributions assisting with this are appreciated. - -# Theorems about equality in `Fin`. --/ - -namespace Fin - -variable {n : ℕ} {i j : Fin n} - -@[deprecated eq_of_val_eq (since := "2024-02-15")] -theorem eq_of_veq : i.val = j.val → i = j := eq_of_val_eq - -@[deprecated val_eq_of_eq (since := "2024-02-15")] -theorem veq_of_eq : i = j → i.val = j.val := val_eq_of_eq - --- These two aren't deprecated because `ne_of_val_ne` and `val_ne_of_ne` --- use `¬a = b` instead of `a ≠ b`. TODO: fix or rename in Lean core. -theorem ne_of_vne (h : i.val ≠ j.val) : i ≠ j := ne_of_val_ne h -theorem vne_of_ne (h : i ≠ j) : i.val ≠ j.val := val_ne_of_ne h - -end Fin diff --git a/Mathlib/Init/Data/Int/Order.lean b/Mathlib/Init/Data/Int/Order.lean deleted file mode 100644 index abe8b3642eaa5..0000000000000 --- a/Mathlib/Init/Data/Int/Order.lean +++ /dev/null @@ -1,78 +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.Data.Int.Notation -import Mathlib.Data.Nat.Notation -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.) - -We intend to move all the content of these files out into the main `Mathlib` directory structure. -Contributions assisting with this are appreciated. - -# The order relation on the integers --/ - -open Nat - -namespace Int - -export private decNonneg from Init.Data.Int.Basic - -theorem le.elim {a b : ℤ} (h : a ≤ b) {P : Prop} (h' : ∀ n : ℕ, a + ↑n = b → P) : P := - Exists.elim (le.dest h) h' - -alias ⟨le_of_ofNat_le_ofNat, ofNat_le_ofNat_of_le⟩ := ofNat_le - -theorem lt.elim {a b : ℤ} (h : a < b) {P : Prop} (h' : ∀ n : ℕ, a + ↑(Nat.succ n) = b → P) : P := - Exists.elim (lt.dest h) h' - -alias ⟨lt_of_ofNat_lt_ofNat, ofNat_lt_ofNat_of_lt⟩ := ofNat_lt - -instance instLinearOrder : LinearOrder ℤ where - le := (·≤·) - le_refl := Int.le_refl - le_trans := @Int.le_trans - le_antisymm := @Int.le_antisymm - lt := (·<·) - lt_iff_le_not_le := @Int.lt_iff_le_not_le - le_total := Int.le_total - decidableEq := by infer_instance - decidableLE := by infer_instance - decidableLT := by infer_instance - -theorem neg_mul_eq_neg_mul_symm (a b : ℤ) : -a * b = -(a * b) := (Int.neg_mul_eq_neg_mul a b).symm - -theorem mul_neg_eq_neg_mul_symm (a b : ℤ) : a * -b = -(a * b) := (Int.neg_mul_eq_mul_neg a b).symm - -protected theorem eq_zero_or_eq_zero_of_mul_eq_zero {a b : ℤ} (h : a * b = 0) : a = 0 ∨ b = 0 := - match lt_trichotomy 0 a with - | Or.inl hlt₁ => - match lt_trichotomy 0 b with - | Or.inl hlt₂ => by - have : 0 < a * b := Int.mul_pos hlt₁ hlt₂ - rw [h] at this - exact absurd this (lt_irrefl _) - | Or.inr (Or.inl heq₂) => Or.inr heq₂.symm - | Or.inr (Or.inr hgt₂) => by - have : 0 > a * b := Int.mul_neg_of_pos_of_neg hlt₁ hgt₂ - rw [h] at this - exact absurd this (lt_irrefl _) - | Or.inr (Or.inl heq₁) => Or.inl heq₁.symm - | Or.inr (Or.inr hgt₁) => - match lt_trichotomy 0 b with - | Or.inl hlt₂ => by - have : 0 > a * b := Int.mul_neg_of_neg_of_pos hgt₁ hlt₂ - rw [h] at this - exact absurd this (lt_irrefl _) - | Or.inr (Or.inl heq₂) => Or.inr heq₂.symm - | Or.inr (Or.inr hgt₂) => by - have : 0 < a * b := Int.mul_pos_of_neg_of_neg hgt₁ hgt₂ - rw [h] at this - exact absurd this (lt_irrefl _) diff --git a/Mathlib/Init/Data/List/Basic.lean b/Mathlib/Init/Data/List/Basic.lean deleted file mode 100644 index f0b5deabfcfcc..0000000000000 --- a/Mathlib/Init/Data/List/Basic.lean +++ /dev/null @@ -1,51 +0,0 @@ -/- -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 Mathlib.Data.Nat.Notation -import Batteries.Tactic.Alias - -/-! -# 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.) - -We intend to move all the content of these files out into the main `Mathlib` directory structure. -Contributions assisting with this are appreciated. - -## Definitions for `List` not (yet) in `Batteries` --/ - -open Decidable List - -universe u v w -variable {α : Type u} - -namespace List - -/-- The head of a list, or the default element of the type is the list is `nil`. -/ -def headI [Inhabited α] : List α → α - | [] => default - | (a :: _) => a - -@[simp] theorem headI_nil [Inhabited α] : ([] : List α).headI = default := rfl -@[simp] theorem headI_cons [Inhabited α] {h : α} {t : List α} : (h :: t).headI = h := rfl - -/-- The last element of a list, with the default if list empty -/ -def getLastI [Inhabited α] : List α → α - | [] => default - | [a] => a - | [_, b] => b - | _ :: _ :: l => getLastI l - -/-- List with a single given element. -/ -@[inline, deprecated List.pure (since := "2024-03-24")] -protected def ret {α : Type u} (a : α) : List α := [a] - -/-- `≤` implies not `>` for lists. -/ -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 - -end List diff --git a/Mathlib/Init/Data/List/Lemmas.lean b/Mathlib/Init/Data/List/Lemmas.lean deleted file mode 100644 index d3326d2be2dba..0000000000000 --- a/Mathlib/Init/Data/List/Lemmas.lean +++ /dev/null @@ -1,96 +0,0 @@ -/- -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 --/ -import Mathlib.Tactic.Cases -import Batteries.Logic - -/-! -# 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.) - -We intend to move all the content of these files out into the main `Mathlib` directory structure. -Contributions assisting with this are appreciated. - -# Lemmas for `List` not (yet) in `Batteries` --/ - -universe u v w w₁ w₂ - -variable {α : Type u} {β : Type v} {γ : Type w} - -namespace List - -open Nat - -/-! mem -/ - -theorem mem_cons_eq (a y : α) (l : List α) : (a ∈ y :: l) = (a = y ∨ a ∈ l) := - propext List.mem_cons - -alias ⟨eq_or_mem_of_mem_cons, _⟩ := mem_cons - -theorem not_exists_mem_nil (p : α → Prop) : ¬∃ x ∈ @nil α, p x := - fun ⟨_, hx, _⟩ => List.not_mem_nil _ hx - -@[deprecated (since := "2024-03-23")] alias not_bex_nil := not_exists_mem_nil -@[deprecated (since := "2024-03-23")] alias bex_cons := exists_mem_cons - -/-! sublists -/ - -alias length_le_of_sublist := Sublist.length_le - -/-! map_accumr -/ - -section MapAccumr - -variable {φ : Type w₁} {σ : Type w₂} - -/-- Runs a function over a list returning the intermediate results and a final result. -/ -def mapAccumr (f : α → σ → σ × β) : List α → σ → σ × List β - | [], c => (c, []) - | y :: yr, c => - let r := mapAccumr f yr c - let z := f y r.1 - (z.1, z.2 :: r.2) - -/-- Length of the list obtained by `mapAccumr`. -/ -@[simp] -theorem length_mapAccumr : - ∀ (f : α → σ → σ × β) (x : List α) (s : σ), length (mapAccumr f x s).2 = length x - | f, _ :: x, s => congr_arg succ (length_mapAccumr f x s) - | _, [], _ => rfl - -end MapAccumr - -section MapAccumr₂ - -variable {φ : Type w₁} {σ : Type w₂} - -/-- Runs a function over two lists returning the intermediate results and a final result. -/ -def mapAccumr₂ (f : α → β → σ → σ × φ) : List α → List β → σ → σ × List φ - | [], _, c => (c, []) - | _, [], c => (c, []) - | x :: xr, y :: yr, c => - let r := mapAccumr₂ f xr yr c - let q := f x y r.1 - (q.1, q.2 :: r.2) - -/-- Length of a list obtained using `mapAccumr₂`. -/ -@[simp] -theorem length_mapAccumr₂ : - ∀ (f : α → β → σ → σ × φ) (x y c), length (mapAccumr₂ f x y c).2 = min (length x) (length y) - | f, _ :: x, _ :: y, c => - calc - succ (length (mapAccumr₂ f x y c).2) = succ (min (length x) (length y)) := - congr_arg succ (length_mapAccumr₂ f x y c) - _ = min (succ (length x)) (succ (length y)) := Eq.symm (succ_min_succ (length x) (length y)) - | _, _ :: _, [], _ => rfl - | _, [], _ :: _, _ => rfl - | _, [], [], _ => rfl - -end MapAccumr₂ - -end List diff --git a/Mathlib/Init/Data/Nat/Lemmas.lean b/Mathlib/Init/Data/Nat/Lemmas.lean index d580fa8f4aed0..fe8bd94cacac2 100644 --- a/Mathlib/Init/Data/Nat/Lemmas.lean +++ b/Mathlib/Init/Data/Nat/Lemmas.lean @@ -24,84 +24,43 @@ namespace Nat /-! multiplication -/ -theorem eq_zero_of_mul_eq_zero : ∀ {n m : ℕ}, n * m = 0 → n = 0 ∨ m = 0 - | 0, m => fun _ => Or.inl rfl - | succ n, m => by - rw [succ_mul]; intro h - exact Or.inr (Nat.eq_zero_of_add_eq_zero_left h) - -/-! properties of inequality -/ - -protected def ltGeByCases {a b : ℕ} {C : Sort u} (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) - -protected def ltByCases {a b : ℕ} {C : Sort u} (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₁) +@[deprecated (since := "2024-08-23")] alias ⟨eq_zero_of_mul_eq_zero, _⟩ := mul_eq_zero -- TODO: there are four variations, depending on which variables we assume to be nonneg -/-! bit0/bit1 properties -/ -section bit - -end bit - /-! successor and predecessor -/ +@[deprecated (since := "2024-08-23")] def discriminate {B : Sort u} {n : ℕ} (H1 : n = 0 → B) (H2 : ∀ m, n = succ m → B) : B := by induction n with | zero => exact H1 rfl | succ n _ => apply H2 _ rfl +-- Unused in Mathlib; +-- if downstream projects find this essential please copy it or remove the deprecation. +@[deprecated (since := "2024-07-27")] theorem one_eq_succ_zero : 1 = succ 0 := rfl -/-! subtraction - -Many lemmas are proven more generally in mathlib `Algebra/Order/Sub` -/ - -/-! min -/ - /-! induction principles -/ - -def twoStepInduction {P : ℕ → Sort u} (H1 : P 0) (H2 : P 1) - (H3 : ∀ (n : ℕ) (_IH1 : P n) (_IH2 : P (succ n)), P (succ (succ n))) : ∀ a : ℕ, P a - | 0 => H1 - | 1 => H2 - | succ (succ _n) => H3 _ (twoStepInduction H1 H2 H3 _) (twoStepInduction H1 H2 H3 _) - +-- Unused in Mathlib; +-- if downstream projects find this essential please copy it or remove the deprecation. +@[deprecated (since := "2024-07-27")] def subInduction {P : ℕ → ℕ → Sort u} (H1 : ∀ m, P 0 m) (H2 : ∀ n, P (succ n) 0) (H3 : ∀ n m, P n m → P (succ n) (succ m)) : ∀ n m : ℕ, P n m | 0, _m => H1 _ | succ _n, 0 => H2 _ | succ n, succ m => H3 _ _ (subInduction H1 H2 H3 n m) --- Porting note: added `elab_as_elim` -@[elab_as_elim] -protected theorem strong_induction_on {p : Nat → Prop} (n : Nat) - (h : ∀ n, (∀ m, m < n → p m) → p n) : p n := - Nat.strongRecOn n h - -protected theorem case_strong_induction_on {p : Nat → Prop} (a : Nat) (hz : p 0) - (hi : ∀ n, (∀ m, m ≤ n → p m) → p (succ n)) : p a := - Nat.strong_induction_on a fun n => - match n with - | 0 => fun _ => hz - | n + 1 => fun h₁ => hi n fun _m h₂ => h₁ _ (lt_succ_of_le h₂) - /-! mod -/ +-- Unused in Mathlib; +-- if downstream projects find this essential please copy it or remove the deprecation. +@[deprecated (since := "2024-07-27")] theorem cond_decide_mod_two (x : ℕ) [d : Decidable (x % 2 = 1)] : cond (@decide (x % 2 = 1) d) 1 0 = x % 2 := by - by_cases h : x % 2 = 1 - · simp! [*] - · cases mod_two_eq_zero_or_one x <;> simp! [*, Nat.zero_ne_one] - -/-! div -/ - -/-! dvd -/ - - + simp only [cond_eq_if, decide_eq_true_eq] + split <;> omega end Nat diff --git a/Mathlib/Init/Data/Quot.lean b/Mathlib/Init/Data/Quot.lean deleted file mode 100644 index 29dc0adb33bd0..0000000000000 --- a/Mathlib/Init/Data/Quot.lean +++ /dev/null @@ -1,68 +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 --/ - -/-! -# 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.) - -We intend to move all the content of these files out into the main `Mathlib` directory structure. -Contributions assisting with this are appreciated. - -# Quotient types - -These are ported from the Lean 3 standard library file `init/data/quot.lean`. --/ - -universe u - -section - -variable {α : Type u} -variable (r : α → α → Prop) - -/-- `EqvGen r` is the equivalence relation generated by `r`. -/ -inductive EqvGen : α → α → Prop - | rel : ∀ x y, r x y → EqvGen x y - | refl : ∀ x, EqvGen x x - | symm : ∀ x y, EqvGen x y → EqvGen y x - | trans : ∀ x y z, EqvGen x y → EqvGen y z → EqvGen x z - -theorem EqvGen.is_equivalence : Equivalence (@EqvGen α r) := - Equivalence.mk EqvGen.refl (EqvGen.symm _ _) (EqvGen.trans _ _ _) - -/-- `EqvGen.Setoid r` is the setoid generated by a relation `r`. - -The motivation for this definition is that `Quot r` behaves like `Quotient (EqvGen.Setoid r)`, -see for example `Quot.exact` and `Quot.EqvGen_sound`. --/ -def EqvGen.Setoid : Setoid α := - Setoid.mk _ (EqvGen.is_equivalence r) - -theorem Quot.exact {a b : α} (H : Quot.mk r a = Quot.mk r b) : EqvGen r a b := - @Quotient.exact _ (EqvGen.Setoid r) a b (congrArg - (Quot.lift (Quotient.mk (EqvGen.Setoid r)) (fun x y h ↦ Quot.sound (EqvGen.rel x y h))) H) - -theorem Quot.EqvGen_sound {r : α → α → Prop} {a b : α} (H : EqvGen r a b) : - Quot.mk r a = Quot.mk r b := - EqvGen.rec - (fun _ _ h ↦ Quot.sound h) - (fun _ ↦ rfl) - (fun _ _ _ IH ↦ Eq.symm IH) - (fun _ _ _ _ _ IH₁ IH₂ ↦ Eq.trans IH₁ IH₂) - H - -end - -open Decidable -instance Quotient.decidableEq {α : Sort u} {s : Setoid α} [d : ∀ a b : α, Decidable (a ≈ b)] : - DecidableEq (Quotient s) := - fun q₁ q₂ : Quotient s ↦ - Quotient.recOnSubsingleton₂ q₁ q₂ - (fun a₁ a₂ ↦ - match (d a₁ a₂) with - | (isTrue h₁) => isTrue (Quotient.sound h₁) - | (isFalse h₂) => isFalse (fun h ↦ absurd (Quotient.exact h) h₂)) diff --git a/Mathlib/Init/Data/Sigma/Basic.lean b/Mathlib/Init/Data/Sigma/Basic.lean deleted file mode 100644 index 47e27c6f72e55..0000000000000 --- a/Mathlib/Init/Data/Sigma/Basic.lean +++ /dev/null @@ -1,29 +0,0 @@ -/- -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 --/ - -/-! -# 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.) - -We intend to move all the content of these files out into the main `Mathlib` directory structure. -Contributions assisting with this are appreciated. - -# Lemmas about `Sigma` from Lean 3 core. --/ - -universe u v - -theorem ex_of_psig {α : Sort u} {p : α → Prop} : (Σ' x, p x) → ∃ x, p x - | ⟨x, hx⟩ => ⟨x, hx⟩ - -protected theorem Sigma.eq {α : Type u} {β : α → Type v} : ∀ {p₁ p₂ : Σ a, β a} (h₁ : p₁.1 = p₂.1), - (Eq.recOn h₁ p₁.2 : β p₂.1) = p₂.2 → p₁ = p₂ - | ⟨_, _⟩, _, rfl, rfl => rfl - -protected theorem PSigma.eq {α : Sort u} {β : α → Sort v} : ∀ {p₁ p₂ : Σ' a, β a} (h₁ : p₁.1 = p₂.1), - (Eq.recOn h₁ p₁.2 : β p₂.1) = p₂.2 → p₁ = p₂ - | ⟨_, _⟩, _, rfl, rfl => rfl diff --git a/Mathlib/Init/Data/Sigma/Lex.lean b/Mathlib/Init/Data/Sigma/Lex.lean deleted file mode 100644 index 80a3ad677bc92..0000000000000 --- a/Mathlib/Init/Data/Sigma/Lex.lean +++ /dev/null @@ -1,61 +0,0 @@ -/- -Copyright (c) 2016 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Leonardo de Moura --/ - -/-! -# 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.) - -We intend to move all the content of these files out into the main `Mathlib` directory structure. -Contributions assisting with this are appreciated. - -# Well-foundedness of orders of well-founded relations - -Porting note: many declarations that were here in mathlib3 have been moved to `Init.WF` -in Lean 4 core. The ones below are all the exceptions. --/ - -universe u v - -namespace PSigma - -section - -open WellFounded - -variable {α : Sort u} {β : α → Sort v} {r : α → α → Prop} {s : ∀ a : α, β a → β a → Prop} - -/-- The lexicographical order of well-founded relations is well-founded. -/ -theorem lex_wf (ha : WellFounded r) (hb : ∀ x, WellFounded (s x)) : WellFounded (Lex r s) := - WellFounded.intro fun ⟨a, b⟩ => lexAccessible (WellFounded.apply ha a) hb b - -end - -section - -open WellFounded - -variable {α : Sort u} {β : Sort v} {r : α → α → Prop} {s : β → β → Prop} - -theorem revLex_wf (ha : WellFounded r) (hb : WellFounded s) : WellFounded (RevLex r s) := - WellFounded.intro fun ⟨a, b⟩ => revLexAccessible (apply hb b) (WellFounded.apply ha) a - -end - -section - -theorem skipLeft_wf (α : Type u) {β : Type v} {s : β → β → Prop} (hb : WellFounded s) : - WellFounded (SkipLeft α s) := - revLex_wf emptyWf.wf hb - -end - -instance hasWellFounded {α : Type u} {β : α → Type v} [s₁ : WellFoundedRelation α] - [s₂ : ∀ a, WellFoundedRelation (β a)] : WellFoundedRelation (PSigma β) where - rel := Lex s₁.rel fun a => (s₂ a).rel - wf := lex_wf s₁.wf fun a => (s₂ a).wf - -end PSigma diff --git a/Mathlib/Init/Logic.lean b/Mathlib/Init/Logic.lean index 0496c9b280296..5fae3e2475809 100644 --- a/Mathlib/Init/Logic.lean +++ b/Mathlib/Init/Logic.lean @@ -3,11 +3,7 @@ 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 /-! # Note about `Mathlib/Init/` @@ -18,234 +14,157 @@ We intend to move all the content of these files out into the main `Mathlib` dir Contributions assisting with this are appreciated. -/ +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} - -/- or -/ +-- 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 - --- This is needed for `calc` to work with `iff`. -instance : Trans Iff Iff Iff where - trans := fun p q ↦ p.trans q - -alias ⟨not_of_not_not_not, _⟩ := not_not_not - --- FIXME --- attribute [congr] not_congr - -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 _) - --- TODO --- attribute [intro] Exists.intro - -/- 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 -alias not_not_iff := not_not +@[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 @@ -253,6 +172,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₁) := @@ -260,24 +180,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 @@ -287,10 +210,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: @@ -298,6 +223,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: @@ -305,18 +231,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) @@ -327,111 +242,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/Init/Order/LinearOrder.lean b/Mathlib/Init/Order/LinearOrder.lean deleted file mode 100644 index 6a9a98b19129a..0000000000000 --- a/Mathlib/Init/Order/LinearOrder.lean +++ /dev/null @@ -1,150 +0,0 @@ -/- -Copyright (c) 2016 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Jeremy Avigad, Leonardo de Moura --/ -import Mathlib.Order.Defs - -/-! -# Note about `Mathlib/Init/` -The files in `Mathlib/Init` are leftovers from the port from Mathlib3. -(They contain content moved from lean3 itself that Mathlib needed but was not moved to lean4.) - -We intend to move all the content of these files out into the main `Mathlib` directory structure. -Contributions assisting with this are appreciated. - -# Basic lemmas about linear orders. - -The contents of this file came from `init.algebra.functions` in Lean 3, -and it would be good to find everything a better home. --/ - -universe u - -section - -open Decidable - -variable {α : Type u} [LinearOrder α] - -theorem min_def (a b : α) : min a b = if a ≤ b then a else b := by - rw [LinearOrder.min_def a] - -theorem max_def (a b : α) : max a b = if a ≤ b then b else a := by - rw [LinearOrder.max_def a] - -theorem min_le_left (a b : α) : min a b ≤ a := by - -- Porting note: no `min_tac` tactic - if h : a ≤ b - then simp [min_def, if_pos h, le_refl] - else simp [min_def, if_neg h]; exact le_of_not_le h - -theorem min_le_right (a b : α) : min a b ≤ b := by - -- Porting note: no `min_tac` tactic - if h : a ≤ b - then simp [min_def, if_pos h]; exact h - else simp [min_def, if_neg h, le_refl] - -theorem le_min {a b c : α} (h₁ : c ≤ a) (h₂ : c ≤ b) : c ≤ min a b := by - -- Porting note: no `min_tac` tactic - if h : a ≤ b - then simp [min_def, if_pos h]; exact h₁ - else simp [min_def, if_neg h]; exact h₂ - -theorem le_max_left (a b : α) : a ≤ max a b := by - -- Porting note: no `min_tac` tactic - if h : a ≤ b - then simp [max_def, if_pos h]; exact h - else simp [max_def, if_neg h, le_refl] - -theorem le_max_right (a b : α) : b ≤ max a b := by - -- Porting note: no `min_tac` tactic - if h : a ≤ b - then simp [max_def, if_pos h, le_refl] - else simp [max_def, if_neg h]; exact le_of_not_le h - -theorem max_le {a b c : α} (h₁ : a ≤ c) (h₂ : b ≤ c) : max a b ≤ c := by - -- Porting note: no `min_tac` tactic - if h : a ≤ b - then simp [max_def, if_pos h]; exact h₂ - else simp [max_def, if_neg h]; exact h₁ - -theorem eq_min {a b c : α} (h₁ : c ≤ a) (h₂ : c ≤ b) (h₃ : ∀ {d}, d ≤ a → d ≤ b → d ≤ c) : - c = min a b := - le_antisymm (le_min h₁ h₂) (h₃ (min_le_left a b) (min_le_right a b)) - -theorem min_comm (a b : α) : min a b = min b a := - eq_min (min_le_right a b) (min_le_left a b) fun h₁ h₂ => le_min h₂ h₁ - -theorem 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 - -theorem min_left_comm : ∀ a b c : α, min a (min b c) = min b (min a c) := - left_comm (@min α _) (@min_comm α _) (@min_assoc α _) - -@[simp] -theorem min_self (a : α) : min a a = a := by simp [min_def] - -theorem min_eq_left {a b : α} (h : a ≤ b) : min a b = a := by - apply Eq.symm; apply eq_min (le_refl _) h; intros; assumption - -theorem min_eq_right {a b : α} (h : b ≤ a) : min a b = b := - min_comm b a ▸ min_eq_left h - -theorem eq_max {a b c : α} (h₁ : a ≤ c) (h₂ : b ≤ c) (h₃ : ∀ {d}, a ≤ d → b ≤ d → c ≤ d) : - c = max a b := - le_antisymm (h₃ (le_max_left a b) (le_max_right a b)) (max_le h₁ h₂) - -theorem max_comm (a b : α) : max a b = max b a := - eq_max (le_max_right a b) (le_max_left a b) fun h₁ h₂ => max_le h₂ h₁ - -theorem 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₂ - -theorem max_left_comm : ∀ a b c : α, max a (max b c) = max b (max a c) := - left_comm (@max α _) (@max_comm α _) (@max_assoc α _) - -@[simp] -theorem max_self (a : α) : max a a = a := by simp [max_def] - -theorem max_eq_left {a b : α} (h : b ≤ a) : max a b = a := by - apply Eq.symm; apply eq_max (le_refl _) h; intros; assumption - -theorem max_eq_right {a b : α} (h : a ≤ b) : max a b = b := - max_comm b a ▸ max_eq_left h - --- these rely on lt_of_lt -theorem min_eq_left_of_lt {a b : α} (h : a < b) : min a b = a := - min_eq_left (le_of_lt h) - -theorem min_eq_right_of_lt {a b : α} (h : b < a) : min a b = b := - min_eq_right (le_of_lt h) - -theorem max_eq_left_of_lt {a b : α} (h : b < a) : max a b = a := - max_eq_left (le_of_lt h) - -theorem max_eq_right_of_lt {a b : α} (h : a < b) : max a b = b := - max_eq_right (le_of_lt h) - --- these use the fact that it is a linear ordering -theorem lt_min {a b c : α} (h₁ : a < b) (h₂ : a < c) : a < min b c := - -- Porting note: no `min_tac` tactic - Or.elim (le_or_gt b c) - (fun h : b ≤ c ↦ by rwa [min_eq_left h]) - (fun h : b > c ↦ by rwa [min_eq_right_of_lt h]) - -theorem max_lt {a b c : α} (h₁ : a < c) (h₂ : b < c) : max a b < c := - -- Porting note: no `min_tac` tactic - Or.elim (le_or_gt a b) - (fun h : a ≤ b ↦ by rwa [max_eq_right h]) - (fun h : a > b ↦ by rwa [max_eq_left_of_lt h]) - -end diff --git a/Mathlib/Init/Quot.lean b/Mathlib/Init/Quot.lean deleted file mode 100644 index ba61a53e97488..0000000000000 --- a/Mathlib/Init/Quot.lean +++ /dev/null @@ -1,43 +0,0 @@ -/- -Copyright (c) 2023 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Johan Commelin --/ - -/-! -# 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.) - -We intend to move all the content of these files out into the main `Mathlib` directory structure. -Contributions assisting with this are appreciated. - -# Quot - -Some induction principles tagged with `elab_as_elim`, since the attribute is missing in core. --/ - -universe u v -variable {α : Sort u} {r : α → α → Prop} {motive : Quot r → Sort v} - -@[inherit_doc Quot.rec, elab_as_elim] -- Porting note: adding `elab_as_elim` -protected abbrev Quot.recOn' - (q : Quot r) - (f : (a : α) → motive (Quot.mk r a)) - (h : (a b : α) → (p : r a b) → Eq.ndrec (f a) (Quot.sound p) = f b) : - motive q := - q.rec f h --- expected token - -/-- Version of `Quot.recOnSubsingleton` tagged with `elab_as_elim` -/ -@[elab_as_elim] -- Porting note: this attribute is missing in core -protected abbrev Quot.recOnSubsingleton' - [h : (a : α) → Subsingleton (motive (Quot.mk r a))] - (q : Quot r) - (f : (a : α) → motive (Quot.mk r a)) : - motive q := by - induction q using Quot.rec - apply f - apply Subsingleton.elim - -theorem Quotient.mk'_eq_mk [s : Setoid α] : Quotient.mk' = Quotient.mk s := rfl diff --git a/Mathlib/Init/Set.lean b/Mathlib/Init/Set.lean deleted file mode 100644 index 4999dfe196e03..0000000000000 --- a/Mathlib/Init/Set.lean +++ /dev/null @@ -1,224 +0,0 @@ -/- -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.Util.ExtendedBinder - -/-! -# 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.) - -We intend to move all the content of these files out into the main `Mathlib` directory structure. -Contributions assisting with this are appreciated. - -# Sets - -This file sets up the theory of sets whose elements have a given type. - -## Main definitions - -Given a type `X` and a predicate `p : X → Prop`: - -* `Set X` : the type of sets whose elements have type `X` -* `{a : X | p a} : Set X` : the set of all elements of `X` satisfying `p` -* `{a | p a} : Set X` : a more concise notation for `{a : X | p a}` -* `{f x y | (x : X) (y : Y)} : Set Z` : a more concise notation for `{z : Z | ∃ x y, f x y = z}` -* `{a ∈ S | p a} : Set X` : given `S : Set X`, the subset of `S` consisting of - its elements satisfying `p`. - -## Implementation issues - -As in Lean 3, `Set X := X → Prop` - -I didn't call this file Data.Set.Basic because it contains core Lean 3 -stuff which happens before mathlib3's data.set.basic . -This file is a port of the core Lean 3 file `lib/lean/library/init/data/set.lean`. - --/ - -open Batteries.ExtendedBinder - -universe u -variable {α : Type u} - -/-- A set is a collection of elements of some type `α`. - -Although `Set` is defined as `α → Prop`, this is an implementation detail which should not be -relied on. Instead, `setOf` and membership of a set (`∈`) should be used to convert between sets -and predicates. --/ -def Set (α : Type u) := α → Prop - -/-- Turn a predicate `p : α → Prop` into a set, also written as `{x | p x}` -/ -def setOf {α : Type u} (p : α → Prop) : Set α := - p - -namespace Set - -/-- Membership in a set -/ -protected def Mem (a : α) (s : Set α) : Prop := - s a - -instance : Membership α (Set α) := - ⟨Set.Mem⟩ - -theorem ext {a b : Set α} (h : ∀ (x : α), x ∈ a ↔ x ∈ b) : a = b := - funext (fun x ↦ propext (h x)) - - -/-- The subset relation on sets. `s ⊆ t` means that all elements of `s` are elements of `t`. - -Note that you should **not** use this definition directly, but instead write `s ⊆ t`. -/ -protected def Subset (s₁ s₂ : Set α) := - ∀ ⦃a⦄, a ∈ s₁ → a ∈ s₂ - -/-- Porting note: we introduce `≤` before `⊆` to help the unifier when applying lattice theorems -to subset hypotheses. -/ -instance : LE (Set α) := - ⟨Set.Subset⟩ - -instance : HasSubset (Set α) := - ⟨(· ≤ ·)⟩ - -instance : EmptyCollection (Set α) := - ⟨fun _ ↦ False⟩ - -syntax "{" extBinder " | " term "}" : term - -macro_rules - | `({ $x:ident | $p }) => `(setOf fun $x:ident ↦ $p) - | `({ $x:ident : $t | $p }) => `(setOf fun $x:ident : $t ↦ $p) - | `({ $x:ident $b:binderPred | $p }) => - `(setOf fun $x:ident ↦ satisfies_binder_pred% $x $b ∧ $p) - -@[app_unexpander setOf] -def setOf.unexpander : Lean.PrettyPrinter.Unexpander - | `($_ fun $x:ident ↦ $p) => `({ $x:ident | $p }) - | `($_ fun ($x:ident : $ty:term) ↦ $p) => `({ $x:ident : $ty:term | $p }) - | _ => throw () - -open Batteries.ExtendedBinder in -/-- -`{ f x y | (x : X) (y : Y) }` is notation for the set of elements `f x y` constructed from the -binders `x` and `y`, equivalent to `{z : Z | ∃ x y, f x y = z}`. - -If `f x y` is a single identifier, it must be parenthesized to avoid ambiguity with `{x | p x}`; -for instance, `{(x) | (x : Nat) (y : Nat) (_hxy : x = y^2)}`. --/ -macro (priority := low) "{" t:term " | " bs:extBinders "}" : term => - `({x | ∃ᵉ $bs:extBinders, $t = x}) - -/-- -* `{ pat : X | p }` is notation for pattern matching in set-builder notation, - where `pat` is a pattern that is matched by all objects of type `X` - and `p` is a proposition that can refer to variables in the pattern. - It is the set of all objects of type `X` which, when matched with the pattern `pat`, - make `p` come out true. -* `{ pat | p }` is the same, but in the case when the type `X` can be inferred. - -For example, `{ (m, n) : ℕ × ℕ | m * n = 12 }` denotes the set of all ordered pairs of -natural numbers whose product is 12. - -Note that if the type ascription is left out and `p` can be interpreted as an extended binder, -then the extended binder interpretation will be used. For example, `{ n + 1 | n < 3 }` will -be interpreted as `{ x : Nat | ∃ n < 3, n + 1 = x }` rather than using pattern matching. --/ -macro (name := macroPattSetBuilder) (priority := low-1) - "{" pat:term " : " t:term " | " p:term "}" : term => - `({ x : $t | match x with | $pat => $p }) - -@[inherit_doc macroPattSetBuilder] -macro (priority := low-1) "{" pat:term " | " p:term "}" : term => - `({ x | match x with | $pat => $p }) - -/-- Pretty printing for set-builder notation with pattern matching. -/ -@[app_unexpander setOf] -def setOfPatternMatchUnexpander : Lean.PrettyPrinter.Unexpander - | `($_ fun $x:ident ↦ match $y:ident with | $pat => $p) => - if x == y then - `({ $pat:term | $p:term }) - else - throw () - | `($_ fun ($x:ident : $ty:term) ↦ match $y:ident with | $pat => $p) => - if x == y then - `({ $pat:term : $ty:term | $p:term }) - else - throw () - | _ => throw () - -/-- The universal set on a type `α` is the set containing all elements of `α`. - -This is conceptually the "same as" `α` (in set theory, it is actually the same), but type theory -makes the distinction that `α` is a type while `Set.univ` is a term of type `Set α`. `Set.univ` can -itself be coerced to a type `↥Set.univ` which is in bijection with (but distinct from) `α`. -/ -def univ : Set α := {_a | True} - -/-- `Set.insert a s` is the set `{a} ∪ s`. - -Note that you should **not** use this definition directly, but instead write `insert a s` (which is -mediated by the `Insert` typeclass). -/ -protected def insert (a : α) (s : Set α) : Set α := {b | b = a ∨ b ∈ s} - -instance : Insert α (Set α) := ⟨Set.insert⟩ - -/-- The singleton of an element `a` is the set with `a` as a single element. - -Note that you should **not** use this definition directly, but instead write `{a}`. -/ -protected def singleton (a : α) : Set α := {b | b = a} - -instance instSingletonSet : Singleton α (Set α) := ⟨Set.singleton⟩ - -/-- The union of two sets `s` and `t` is the set of elements contained in either `s` or `t`. - -Note that you should **not** use this definition directly, but instead write `s ∪ t`. -/ -protected def union (s₁ s₂ : Set α) : Set α := {a | a ∈ s₁ ∨ a ∈ s₂} - -instance : Union (Set α) := ⟨Set.union⟩ - -/-- The intersection of two sets `s` and `t` is the set of elements contained in both `s` and `t`. - -Note that you should **not** use this definition directly, but instead write `s ∩ t`. -/ -protected def inter (s₁ s₂ : Set α) : Set α := {a | a ∈ s₁ ∧ a ∈ s₂} - -instance : Inter (Set α) := ⟨Set.inter⟩ - -/-- The complement of a set `s` is the set of elements not contained in `s`. - -Note that you should **not** use this definition directly, but instead write `sᶜ`. -/ -protected def compl (s : Set α) : Set α := {a | a ∉ s} - -/-- The difference of two sets `s` and `t` is the set of elements contained in `s` but not in `t`. - -Note that you should **not** use this definition directly, but instead write `s \ t`. -/ -protected def diff (s t : Set α) : Set α := {a ∈ s | a ∉ t} - -instance : SDiff (Set α) := ⟨Set.diff⟩ - -/-- `𝒫 s` is the set of all subsets of `s`. -/ -def powerset (s : Set α) : Set (Set α) := {t | t ⊆ s} - -@[inherit_doc] prefix:100 "𝒫" => powerset - -universe v in -/-- The image of `s : Set α` by `f : α → β`, written `f '' s`, is the set of `b : β` such that -`f a = b` for some `a ∈ s`. -/ -def image {β : Type v} (f : α → β) (s : Set α) : Set β := {f a | a ∈ s} - -instance : Functor Set where map := @Set.image - -instance : LawfulFunctor Set where - id_map _ := funext fun _ ↦ propext ⟨fun ⟨_, sb, rfl⟩ ↦ sb, fun sb ↦ ⟨_, sb, rfl⟩⟩ - comp_map g h _ := funext <| fun c ↦ propext - ⟨fun ⟨a, ⟨h₁, h₂⟩⟩ ↦ ⟨g a, ⟨⟨a, ⟨h₁, rfl⟩⟩, h₂⟩⟩, - fun ⟨_, ⟨⟨a, ⟨h₁, h₂⟩⟩, h₃⟩⟩ ↦ ⟨a, ⟨h₁, show h (g a) = c from h₂ ▸ h₃⟩⟩⟩ - map_const := rfl - -/-- The property `s.Nonempty` expresses the fact that the set `s` is not empty. It should be used -in theorem assumptions instead of `∃ x, x ∈ s` or `s ≠ ∅` as it gives access to a nice API thanks -to the dot notation. -/ -protected def Nonempty (s : Set α) : Prop := - ∃ x, x ∈ s - -end Set 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/Elab/Term.lean b/Mathlib/Lean/Elab/Term.lean index b5b43079267c6..d536cad0358b2 100644 --- a/Mathlib/Lean/Elab/Term.lean +++ b/Mathlib/Lean/Elab/Term.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 Mathlib.Init import Lean.Elab.SyntheticMVars /-! @@ -21,3 +22,5 @@ def elabPattern (patt : Term) (expectedType? : Option Expr) : TermElabM Expr := let t ← elabTerm patt expectedType? synthesizeSyntheticMVars (postpone := .no) (ignoreStuckTC := true) instantiateMVars t + +end Lean.Elab.Term diff --git a/Mathlib/Lean/EnvExtension.lean b/Mathlib/Lean/EnvExtension.lean index dc33d0f890559..6ca1adad43b48 100644 --- a/Mathlib/Lean/EnvExtension.lean +++ b/Mathlib/Lean/EnvExtension.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Floris van Doorn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn -/ +import Mathlib.Init import Lean.ScopedEnvExtension /-! diff --git a/Mathlib/Lean/Exception.lean b/Mathlib/Lean/Exception.lean index 9eb2a70deb8a5..c15fad88d8c23 100644 --- a/Mathlib/Lean/Exception.lean +++ b/Mathlib/Lean/Exception.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Edward Ayers. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Edward Ayers -/ +import Mathlib.Init import Lean.Exception /-! @@ -37,3 +38,7 @@ and the only commonality is the prefix of the string, so that's what we look for -/ def isFailedToSynthesize (e : Exception) : IO Bool := do pure <| (← e.toMessageData.toString).startsWith "failed to synthesize" + +end Exception + +end Lean 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 b7a76c6339391..5991b42748293 100644 --- a/Mathlib/Lean/Expr/Basic.lean +++ b/Mathlib/Lean/Expr/Basic.lean @@ -1,13 +1,15 @@ /- 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.Data.List.Basic +import Batteries.Tactic.Alias +import Lean.Elab.Binders /-! # Additional operations on Expr and related types @@ -322,6 +324,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/ExtraRecognizers.lean b/Mathlib/Lean/Expr/ExtraRecognizers.lean index ebb2efb0cde41..b8ca5f661228f 100644 --- a/Mathlib/Lean/Expr/ExtraRecognizers.lean +++ b/Mathlib/Lean/Expr/ExtraRecognizers.lean @@ -3,7 +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 Mathlib.Data.Set.Defs +import Mathlib.Data.Set.Operations /-! # Additional Expr recognizers needing theory imports 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/GoalsLocation.lean b/Mathlib/Lean/GoalsLocation.lean index 59acb29c1015d..b9efb1a01e8fe 100644 --- a/Mathlib/Lean/GoalsLocation.lean +++ b/Mathlib/Lean/GoalsLocation.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Jovan Gerbscheid. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jovan Gerbscheid -/ +import Mathlib.Init import Lean.Meta.Tactic.Util import Lean.SubExpr @@ -29,3 +30,5 @@ def location : GoalsLocation → MetaM (Option Name) | ⟨_, .hypType fvarId _⟩ => some <$> fvarId.getUserName | ⟨_, .hypValue fvarId _⟩ => some <$> fvarId.getUserName | ⟨_, .target _⟩ => return none + +end Lean.SubExpr.GoalsLocation diff --git a/Mathlib/Lean/Json.lean b/Mathlib/Lean/Json.lean index 93889905d6351..c5ab7ec132470 100644 --- a/Mathlib/Lean/Json.lean +++ b/Mathlib/Lean/Json.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ +import Mathlib.Init import Lean.Data.Json.FromToJson /-! @@ -38,3 +39,5 @@ instance {α : Type u} [FromJson α] (p : α → Prop) [DecidablePred p] : FromJ instance {α : Type u} [ToJson α] (p : α → Prop) : ToJson (Subtype p) where toJson x := toJson x.val + +end Lean diff --git a/Mathlib/Lean/LocalContext.lean b/Mathlib/Lean/LocalContext.lean index f5ba66bd1e966..3c410ec6b63e6 100644 --- a/Mathlib/Lean/LocalContext.lean +++ b/Mathlib/Lean/LocalContext.lean @@ -1,8 +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 import Lean.LocalContext /-! diff --git a/Mathlib/Lean/Message.lean b/Mathlib/Lean/Message.lean index abfd4e902ad74..a9b79ad767566 100644 --- a/Mathlib/Lean/Message.lean +++ b/Mathlib/Lean/Message.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Floris van Doorn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn -/ +import Mathlib.Init import Lean.Message /-! diff --git a/Mathlib/Lean/Meta.lean b/Mathlib/Lean/Meta.lean index 852de4f890fc9..a4dd8825343f5 100644 --- a/Mathlib/Lean/Meta.lean +++ b/Mathlib/Lean/Meta.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.Init import Lean.Elab.Term import Lean.Elab.Tactic.Basic import Lean.Meta.Tactic.Assert diff --git a/Mathlib/Lean/Meta/Basic.lean b/Mathlib/Lean/Meta/Basic.lean index de0b468cfe711..71d36a1cdcc99 100644 --- a/Mathlib/Lean/Meta/Basic.lean +++ b/Mathlib/Lean/Meta/Basic.lean @@ -1,8 +1,9 @@ /- -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 import Lean.Meta.Basic diff --git a/Mathlib/Lean/Meta/CongrTheorems.lean b/Mathlib/Lean/Meta/CongrTheorems.lean index 0d86cfc7904ae..a8dafe249c20f 100644 --- a/Mathlib/Lean/Meta/CongrTheorems.lean +++ b/Mathlib/Lean/Meta/CongrTheorems.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kyle Miller -/ import Lean.Meta.Tactic.Cleanup -import Lean.Meta.Tactic.Cases import Lean.Meta.Tactic.Refl import Mathlib.Logic.IsEmpty @@ -129,7 +128,7 @@ instance {α : Sort u} [inst : FastIsEmpty α] {β : (x : α) → Sort v} : instance {α : Sort u} {β : (x : α) → Sort v} [inst : ∀ x, FastSubsingleton (β x)] : FastSubsingleton ((x : α) → β x) where - inst := have := λ x => (inst x).inst; inferInstance + inst := have := fun x ↦ (inst x).inst; inferInstance /-- Runs `mx` in a context where all local `Subsingleton` and `IsEmpty` instances @@ -285,8 +284,8 @@ where let rec loop (i : Nat) (ftyx ftyy : Expr) (xs ys : Array Expr) (fixed' : Array Bool) : MetaM α := do if i < numVars then - let ftyx ← whnf ftyx - let ftyy ← whnf ftyy + let ftyx ← whnfD ftyx + let ftyy ← whnfD ftyy unless ftyx.isForall do throwError "doubleTelescope: function doesn't have enough parameters" withLocalDeclD ftyx.bindingName! ftyx.bindingDomain! fun fvarx => do diff --git a/Mathlib/Lean/Meta/DiscrTree.lean b/Mathlib/Lean/Meta/DiscrTree.lean index 04468c7d9eba0..4698847cefc5a 100644 --- a/Mathlib/Lean/Meta/DiscrTree.lean +++ b/Mathlib/Lean/Meta/DiscrTree.lean @@ -1,8 +1,9 @@ /- -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/KAbstractPositions.lean b/Mathlib/Lean/Meta/KAbstractPositions.lean index c6e9ecaf3c7bf..60d3ded29a824 100644 --- a/Mathlib/Lean/Meta/KAbstractPositions.lean +++ b/Mathlib/Lean/Meta/KAbstractPositions.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Jovan Gerbscheid. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jovan Gerbscheid -/ +import Mathlib.Init import Lean.HeadIndex import Lean.Meta.ExprLens import Lean.Meta.Check @@ -86,3 +87,5 @@ example (h : [5] ≠ []) : List.getLast [5] h = 5 := by def kabstractIsTypeCorrect (e subExpr : Expr) (pos : SubExpr.Pos) : MetaM Bool := do withLocalDeclD `_a (← inferType subExpr) fun fvar => do isTypeCorrect (← replaceSubexpr (fun _ => pure fvar) pos e) + +end Lean.Meta diff --git a/Mathlib/Lean/Meta/Simp.lean b/Mathlib/Lean/Meta/Simp.lean index 82573b55fb821..5f38f103a0dcc 100644 --- a/Mathlib/Lean/Meta/Simp.lean +++ b/Mathlib/Lean/Meta/Simp.lean @@ -1,8 +1,9 @@ /- -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 84f0943244ae3..4f3b4e06b54e3 100644 --- a/Mathlib/Lean/Name.lean +++ b/Mathlib/Lean/Name.lean @@ -1,8 +1,9 @@ /- -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 import Lean.Meta.Tactic.Delta import Std.Data.HashMap.Basic diff --git a/Mathlib/Lean/PrettyPrinter/Delaborator.lean b/Mathlib/Lean/PrettyPrinter/Delaborator.lean index 2359d34e4d778..557bdf947198a 100644 --- a/Mathlib/Lean/PrettyPrinter/Delaborator.lean +++ b/Mathlib/Lean/PrettyPrinter/Delaborator.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 Mathlib.Init import Lean.PrettyPrinter.Delaborator.Basic /-! @@ -13,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 @@ -36,3 +30,5 @@ def OptionsPerPos.setBool (opts : OptionsPerPos) (p : SubExpr.Pos) (n : Name) (v OptionsPerPos := let e := opts.findD p {} |>.setBool n v opts.insert p e + +end Lean.PrettyPrinter.Delaborator diff --git a/Mathlib/Lean/Thunk.lean b/Mathlib/Lean/Thunk.lean index 6b67ce032964f..9ec29601a07ca 100644 --- a/Mathlib/Lean/Thunk.lean +++ b/Mathlib/Lean/Thunk.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 Batteries.Data.Thunk +import Mathlib.Init /-! # Basic facts about `Thunk`. diff --git a/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean b/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean index 75c1550c86990..7f6518bb77f2e 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/AffineMap.lean @@ -65,7 +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] + rw [← 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] @@ -565,6 +565,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 @@ -710,7 +717,7 @@ variable [Finite ι] [DecidableEq ι] {f g : ((i : ι) → φv i) →ᵃ[k] P2} /-- Two affine maps from a Pi-tyoe of modules `(i : ι) → φv i` are equal if they are equal in their operation on `Pi.single` and at zero. Analogous to `LinearMap.pi_ext`. See also `pi_ext_nonempty`, - which instead of agrement at zero requires `Nonempty ι`. -/ + which instead of agreement at zero requires `Nonempty ι`. -/ theorem pi_ext_zero (h : ∀ i x, f (Pi.single i x) = g (Pi.single i x)) (h₂ : f 0 = g 0) : f = g := by apply ext_linear diff --git a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean index 3dff1b6db9f72..ab4b6063b2c23 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean @@ -230,7 +230,6 @@ theorem vadd_mem_of_mem_direction {s : AffineSubspace k P} {v : V} (hv : v ∈ s rw [hv] convert s.smul_vsub_vadd_mem 1 hp1 hp2 hp rw [one_smul] - exact s.mem_coe k P _ /-- Subtracting two points in the subspace produces a vector in the direction. -/ theorem vsub_mem_direction {s : AffineSubspace k P} {p1 p2 : P} (hp1 : p1 ∈ s) (hp2 : p2 ∈ s) : @@ -732,8 +731,10 @@ theorem card_pos_of_affineSpan_eq_top {ι : Type*} [Fintype ι] {p : ι → P} attribute [local instance] toAddTorsor -/-- The top affine subspace is linearly equivalent to the affine space. +-- An instance with better keys for the context +instance : Nonempty (⊤ : AffineSubspace k P) := inferInstanceAs (Nonempty (⊤ : Set P)) +/-- The top affine subspace is linearly equivalent to the affine space. This is the affine version of `Submodule.topEquiv`. -/ @[simps! linear apply symm_apply_coe] def topEquiv : (⊤ : AffineSubspace k P) ≃ᵃ[k] P where @@ -1691,3 +1692,5 @@ theorem affineSpan_pair_parallel_iff_vectorSpan_eq {p₁ p₂ p₃ p₄ : P} : not_nonempty_iff_eq_empty] end AffineSubspace + +set_option linter.style.longFile 1800 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 e1d31428561b4..8d58836617812 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 => @@ -783,7 +783,7 @@ theorem centroid_pair [DecidableEq ι] [Invertible (2 : k)] (p : ι → P) (i₁ · have hc : (card ({i₁, i₂} : Finset ι) : k) ≠ 0 := by rw [card_insert_of_not_mem (not_mem_singleton.2 h), card_singleton] norm_num - exact nonzero_of_invertible _ + exact Invertible.ne_zero _ rw [centroid_def, affineCombination_eq_weightedVSubOfPoint_vadd_of_sum_eq_one _ _ _ (sum_centroidWeights_eq_one_of_cast_card_ne_zero _ hc) (p i₁)] @@ -903,13 +903,13 @@ theorem weightedVSub_mem_vectorSpan {s : Finset ι} {w : ι → k} (h : ∑ i rcases isEmpty_or_nonempty ι with (hι | ⟨⟨i0⟩⟩) · simp [Finset.eq_empty_of_isEmpty s] · rw [vectorSpan_range_eq_span_range_vsub_right k p i0, ← Set.image_univ, - Finsupp.mem_span_image_iff_total, + Finsupp.mem_span_image_iff_linearCombination, Finset.weightedVSub_eq_weightedVSubOfPoint_of_sum_eq_zero s w p h (p i0), Finset.weightedVSubOfPoint_apply] let w' := Set.indicator (↑s) w have hwx : ∀ i, w' i ≠ 0 → i ∈ s := fun i => Set.mem_of_indicator_ne_zero use Finsupp.onFinset s w' hwx, Set.subset_univ _ - rw [Finsupp.total_apply, Finsupp.onFinset_sum hwx] + rw [Finsupp.linearCombination_apply, Finsupp.onFinset_sum hwx] · apply Finset.sum_congr rfl intro i hi simp [w', Set.indicator_apply, if_pos hi] @@ -954,7 +954,7 @@ theorem mem_vectorSpan_iff_eq_weightedVSub {v : V} {p : ι → P} : · rcases isEmpty_or_nonempty ι with (hι | ⟨⟨i0⟩⟩) swap · rw [vectorSpan_range_eq_span_range_vsub_right k p i0, ← Set.image_univ, - Finsupp.mem_span_image_iff_total] + Finsupp.mem_span_image_iff_linearCombination] rintro ⟨l, _, hv⟩ use insert i0 l.support set w := @@ -972,7 +972,7 @@ theorem mem_vectorSpan_iff_eq_weightedVSub {v : V} {p : ι → P} : have hz : w i0 • (p i0 -ᵥ p i0 : V) = 0 := (vsub_self (p i0)).symm ▸ smul_zero _ change (fun i => w i • (p i -ᵥ p i0 : V)) i0 = 0 at hz rw [Finset.weightedVSub_eq_weightedVSubOfPoint_of_sum_eq_zero _ w p hw (p i0), - Finset.weightedVSubOfPoint_apply, ← hv, Finsupp.total_apply, + Finset.weightedVSubOfPoint_apply, ← hv, Finsupp.linearCombination_apply, @Finset.sum_insert_zero _ _ l.support i0 _ _ _ hz] change (∑ i ∈ l.support, l i • _) = _ congr with i diff --git a/Mathlib/LinearAlgebra/AffineSpace/ContinuousAffineEquiv.lean b/Mathlib/LinearAlgebra/AffineSpace/ContinuousAffineEquiv.lean index 0360e2114a8d9..12ffbd6ace838 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/ContinuousAffineEquiv.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/ContinuousAffineEquiv.lean @@ -174,14 +174,12 @@ theorem apply_eq_iff_eq (e : P₁ ≃ᵃL[k] P₂) {p₁ p₂ : P₁} : e p₁ = e.toEquiv.apply_eq_iff_eq @[simp] -theorem symm_symm (e : P₁ ≃ᵃL[k] P₂) : e.symm.symm = e := by - ext x - rfl +theorem symm_symm (e : P₁ ≃ᵃL[k] P₂) : e.symm.symm = e := rfl theorem symm_symm_apply (e : P₁ ≃ᵃL[k] P₂) (x : P₁) : e.symm.symm x = e x := rfl -theorem symm_apply_eq (e : P₁ ≃ᵃL[k] P₂) {x y} : e.symm x = y ↔ x = e y := +theorem symm_apply_eq (e : P₁ ≃ᵃL[k] P₂) {x y} : e.symm x = y ↔ x = e y := e.toAffineEquiv.symm_apply_eq theorem eq_symm_apply (e : P₁ ≃ᵃL[k] P₂) {x y} : y = e.symm x ↔ e y = x := diff --git a/Mathlib/LinearAlgebra/AffineSpace/FiniteDimensional.lean b/Mathlib/LinearAlgebra/AffineSpace/FiniteDimensional.lean index f0f90fc28bd12..935dc82abfb3b 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/FiniteDimensional.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/FiniteDimensional.lean @@ -3,7 +3,6 @@ Copyright (c) 2020 Joseph Myers. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Joseph Myers -/ -import Mathlib.Init.Core import Mathlib.LinearAlgebra.AffineSpace.Basis import Mathlib.LinearAlgebra.FiniteDimensional @@ -30,14 +29,14 @@ 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. -/ @@ -157,8 +156,8 @@ theorem finrank_vectorSpan_range_le [Fintype ι] (p : ι → P) {n : ℕ} (hc : /-- The `vectorSpan` of an indexed family of `n + 1` points has dimension at most `n`. -/ lemma finrank_vectorSpan_range_add_one_le [Fintype ι] [Nonempty ι] (p : ι → P) : finrank k (vectorSpan k (Set.range p)) + 1 ≤ Fintype.card ι := - (le_tsub_iff_right $ Nat.succ_le_iff.2 Fintype.card_pos).1 $ finrank_vectorSpan_range_le _ _ - (tsub_add_cancel_of_le $ Nat.succ_le_iff.2 Fintype.card_pos).symm + (le_tsub_iff_right <| Nat.succ_le_iff.2 Fintype.card_pos).1 <| finrank_vectorSpan_range_le _ _ + (tsub_add_cancel_of_le <| Nat.succ_le_iff.2 Fintype.card_pos).symm /-- `n + 1` points are affinely independent if and only if their `vectorSpan` has dimension `n`. -/ @@ -203,7 +202,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] @@ -225,7 +224,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 _ _ @@ -242,7 +241,7 @@ lemma AffineIndependent.card_lt_card_of_affineSpan_lt_affineSpan {s t : Finset V · simp [Set.subset_empty_iff] at hst have := hs'.to_subtype have := ht'.to_set.to_subtype - have dir_lt := AffineSubspace.direction_lt_of_nonempty (k := k) hst $ hs'.to_set.affineSpan k + have dir_lt := AffineSubspace.direction_lt_of_nonempty (k := k) hst <| hs'.to_set.affineSpan k rw [direction_affineSpan, direction_affineSpan, ← @Subtype.range_coe _ (s : Set V), ← @Subtype.range_coe _ (t : Set V)] at dir_lt have finrank_lt := add_lt_add_right (Submodule.finrank_lt_finrank_of_lt dir_lt) 1 @@ -258,7 +257,7 @@ theorem AffineIndependent.vectorSpan_image_finset_eq_of_le_of_card_eq_finrank_ad (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) : 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 @@ -267,7 +266,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 @@ -372,7 +371,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) : @@ -635,7 +634,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 := @@ -670,7 +669,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] @@ -765,12 +764,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..24d2fdd76c35b 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 diff --git a/Mathlib/LinearAlgebra/AffineSpace/Matrix.lean b/Mathlib/LinearAlgebra/AffineSpace/Matrix.lean index 5ee4cb759178f..3ed1a0ba08f47 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Matrix.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Matrix.lean @@ -61,7 +61,7 @@ theorem affineIndependent_of_toMatrix_right_inv [Fintype ι] [Finite ι'] [Decid ext j change (∑ i, w₁ i • b.coord j (p i)) = ∑ i, w₂ i • b.coord j (p i) -- Porting note: Added `u` because `∘` was causing trouble - have u : (fun i => b.coord j (p i)) = b.coord j ∘ p := by simp only [(· ∘ ·)] + have u : (fun i => b.coord j (p i)) = b.coord j ∘ p := by simp only [Function.comp_def] rw [← Finset.univ.affineCombination_eq_linear_combination _ _ hw₁, ← Finset.univ.affineCombination_eq_linear_combination _ _ hw₂, u, ← Finset.univ.map_affineCombination p w₁ hw₁, ← Finset.univ.map_affineCombination p w₂ hw₂, diff --git a/Mathlib/LinearAlgebra/AffineSpace/Ordered.lean b/Mathlib/LinearAlgebra/AffineSpace/Ordered.lean index 7835a5c734a01..9f3c4c81c015f 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Ordered.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Ordered.lean @@ -4,9 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Algebra.CharP.Invertible +import Mathlib.Algebra.Order.Group.Instances import Mathlib.Algebra.Order.Invertible import Mathlib.Algebra.Order.Module.OrderedSMul -import Mathlib.Algebra.Order.Group.Instances +import Mathlib.Algebra.Order.Module.Synonym import Mathlib.LinearAlgebra.AffineSpace.Slope import Mathlib.LinearAlgebra.AffineSpace.Midpoint import Mathlib.Tactic.FieldSimp @@ -133,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 90b2803f45d8e..007a27d357368 100644 --- a/Mathlib/LinearAlgebra/Alternating/Basic.lean +++ b/Mathlib/LinearAlgebra/Alternating/Basic.lean @@ -88,7 +88,7 @@ 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 @@ -603,8 +603,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 ι) : @@ -656,10 +656,10 @@ def domDomCongrEquiv (σ : ι ≃ ι') : M [⋀^ι]→ₗ[R] N ≃+ M [⋀^ι'] invFun := domDomCongr σ.symm left_inv f := by ext - simp [Function.comp] + simp [Function.comp_def] right_inv m := by ext - simp [Function.comp] + simp [Function.comp_def] map_add' := domDomCongr_add σ section DomDomLcongr @@ -671,8 +671,8 @@ variable (S : Type*) [Semiring S] [Module S N] [SMulCommClass R S N] def domDomCongrₗ (σ : ι ≃ ι') : M [⋀^ι]→ₗ[R] N ≃ₗ[S] M [⋀^ι']→ₗ[R] N where toFun := domDomCongr σ invFun := domDomCongr σ.symm - left_inv f := by ext; simp [Function.comp] - right_inv m := by ext; simp [Function.comp] + left_inv f := by ext; simp [Function.comp_def] + right_inv m := by ext; simp [Function.comp_def] map_add' := domDomCongr_add σ map_smul' := domDomCongr_smul σ diff --git a/Mathlib/LinearAlgebra/Alternating/DomCoprod.lean b/Mathlib/LinearAlgebra/Alternating/DomCoprod.lean index deb0d98dc3cb3..847afe49e999e 100644 --- a/Mathlib/LinearAlgebra/Alternating/DomCoprod.lean +++ b/Mathlib/LinearAlgebra/Alternating/DomCoprod.lean @@ -6,6 +6,7 @@ Authors: Eric Wieser import Mathlib.LinearAlgebra.Alternating.Basic import Mathlib.LinearAlgebra.Multilinear.TensorProduct import Mathlib.GroupTheory.GroupAction.Quotient +import Mathlib.Algebra.Group.Subgroup.Finite /-! # Exterior product of alternating maps @@ -224,16 +225,16 @@ 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) fun x _ => QuotientGroup.eq (s := MonoidHom.range (Perm.sumCongrHom ιa ιb)) (a := x) (b := σ)] -- eliminate a multiplication rw [← Finset.map_univ_equiv (Equiv.mulLeft σ), Finset.filter_map, Finset.sum_map] - simp_rw [Equiv.coe_toEmbedding, Equiv.coe_mulLeft, (· ∘ ·), mul_inv_rev, inv_mul_cancel_right, - Subgroup.inv_mem_iff, MonoidHom.mem_range, Finset.univ_filter_exists, + simp_rw [Equiv.coe_toEmbedding, Equiv.coe_mulLeft, Function.comp_def, mul_inv_rev, + inv_mul_cancel_right, Subgroup.inv_mem_iff, MonoidHom.mem_range, Finset.univ_filter_exists, Finset.sum_image Perm.sumCongrHom_injective.injOn] -- now we're ready to clean up the RHS, pulling out the summation rw [domCoprod.summand_mk'', MultilinearMap.domCoprod_alternization_coe, ← Finset.sum_product', diff --git a/Mathlib/LinearAlgebra/Basis/Basic.lean b/Mathlib/LinearAlgebra/Basis/Basic.lean index bbf77e0742586..46ed8282bcd9a 100644 --- a/Mathlib/LinearAlgebra/Basis/Basic.lean +++ b/Mathlib/LinearAlgebra/Basis/Basic.lean @@ -22,7 +22,7 @@ noncomputable section universe u -open Function Set Submodule +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*} @@ -51,7 +51,7 @@ end Coord protected theorem linearIndependent : LinearIndependent R b := linearIndependent_iff.mpr fun l hl => calc - l = b.repr (Finsupp.total _ _ _ b l) := (b.repr_total l).symm + l = b.repr (Finsupp.linearCombination _ b l) := (b.repr_linearCombination l).symm _ = 0 := by rw [hl, LinearEquiv.map_zero] protected theorem ne_zero [Nontrivial R] (i) : b i ≠ 0 := @@ -125,7 +125,7 @@ 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.total_repr x, ← LinearMap.map_smul] at hcx + rw [← b.linearCombination_repr x, ← LinearMap.map_smul] at hcx have := linearIndependent_iff.mp b.linearIndependent (c • b.repr x) hcx rw [smul_eq_zero] at this exact this.resolve_right fun hr => hx (b.repr.map_eq_zero_iff.mp hr)⟩ @@ -203,17 +203,18 @@ theorem maximal [Nontrivial R] (b : Basis ι R M) : b.linearIndependent.Maximal intro x p by_contra q -- and write it in terms of the basis. - have e := b.total_repr x + have e := b.linearCombination_repr x -- This then expresses `x` as a linear combination -- of elements of `w` which are in the range of `b`, let u : ι ↪ w := ⟨fun i => ⟨b i, h ⟨i, rfl⟩⟩, fun i i' r => b.injective (by simpa only [Subtype.mk_eq_mk] using r)⟩ - simp_rw [Finsupp.total_apply] at e + simp_rw [Finsupp.linearCombination_apply] at e change ((b.repr x).sum fun (i : ι) (a : R) ↦ a • (u i : M)) = ((⟨x, p⟩ : w) : M) at e - rw [← Finsupp.sum_embDomain (f := u) (g := fun x r ↦ r • (x : M)), ← Finsupp.total_apply] at e + rw [← Finsupp.sum_embDomain (f := u) (g := fun x r ↦ r • (x : M)), + ← Finsupp.linearCombination_apply] at e -- Now we can contradict the linear independence of `hi` - refine hi.total_ne_of_not_mem_support _ ?_ e + refine hi.linearCombination_ne_of_not_mem_support _ ?_ e simp only [Finset.mem_map, Finsupp.support_embDomain] rintro ⟨j, -, W⟩ simp only [u, Embedding.coeFn_mk, Subtype.mk_eq_mk] at W @@ -227,8 +228,8 @@ variable (hli : LinearIndependent R v) (hsp : ⊤ ≤ span R (range v)) protected noncomputable def mk : Basis ι R M := .ofRepr { hli.repr.comp (LinearMap.id.codRestrict _ fun _ => hsp Submodule.mem_top) with - invFun := Finsupp.total _ _ _ v - left_inv := fun x => hli.total_repr ⟨x, _⟩ + invFun := Finsupp.linearCombination _ v + left_inv := fun x => hli.linearCombination_repr ⟨x, _⟩ right_inv := fun _ => hli.repr_eq rfl } @[simp] @@ -236,7 +237,7 @@ theorem mk_repr : (Basis.mk hli hsp).repr x = hli.repr ⟨x, hsp Submodule.mem_t rfl theorem mk_apply (i : ι) : Basis.mk hli hsp i = v i := - show Finsupp.total _ _ _ v _ = v i by simp + show Finsupp.linearCombination _ v _ = v i by simp @[simp] theorem coe_mk : ⇑(Basis.mk hli hsp) = v := @@ -279,7 +280,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))) @@ -492,28 +493,31 @@ lemma Basis.mem_center_iff {A} constructor case comm => intro y - rw [← b.total_repr y, Finsupp.total_apply, Finsupp.sum, Finset.sum_mul, Finset.mul_sum] + rw [← b.linearCombination_repr y, linearCombination_apply, sum, Finset.sum_mul, + Finset.mul_sum] simp_rw [mul_smul_comm, smul_mul_assoc, (h.1 _).eq] case left_assoc => intro c d - rw [← b.total_repr c, ← b.total_repr d, Finsupp.total_apply, Finsupp.total_apply, Finsupp.sum, - Finsupp.sum, Finset.sum_mul, Finset.mul_sum, Finset.mul_sum, Finset.mul_sum] + rw [← b.linearCombination_repr c, ← b.linearCombination_repr d, linearCombination_apply, + linearCombination_apply, sum, sum, Finset.sum_mul, Finset.mul_sum, Finset.mul_sum, + Finset.mul_sum] simp_rw [smul_mul_assoc, Finset.mul_sum, Finset.sum_mul, mul_smul_comm, Finset.mul_sum, Finset.smul_sum, smul_mul_assoc, mul_smul_comm, (h.2 _ _).1, (@SMulCommClass.smul_comm R R A)] rw [Finset.sum_comm] case mid_assoc => intro c d - rw [← b.total_repr c, ← b.total_repr d, Finsupp.total_apply, Finsupp.total_apply, Finsupp.sum, - Finsupp.sum, Finset.sum_mul, Finset.mul_sum, Finset.mul_sum, Finset.mul_sum] + rw [← b.linearCombination_repr c, ← b.linearCombination_repr d, linearCombination_apply, + linearCombination_apply, sum, sum, Finset.sum_mul, Finset.mul_sum, Finset.mul_sum, + Finset.mul_sum] simp_rw [smul_mul_assoc, Finset.sum_mul, mul_smul_comm, smul_mul_assoc, (h.2 _ _).2.1] case right_assoc => intro c d - rw [← b.total_repr c, ← b.total_repr d, Finsupp.total_apply, Finsupp.total_apply, Finsupp.sum, - Finsupp.sum, Finset.sum_mul] + rw [← b.linearCombination_repr c, ← b.linearCombination_repr d, linearCombination_apply, + linearCombination_apply, sum, Finsupp.sum, Finset.sum_mul] simp_rw [smul_mul_assoc, Finset.mul_sum, Finset.sum_mul, mul_smul_comm, Finset.mul_sum, - Finset.smul_sum, smul_mul_assoc, mul_smul_comm, Finset.sum_mul, smul_mul_assoc, - (h.2 _ _).2.2] + Finset.smul_sum, smul_mul_assoc, mul_smul_comm, Finset.sum_mul, smul_mul_assoc, + (h.2 _ _).2.2] section RestrictScalars @@ -553,7 +557,7 @@ theorem Basis.mem_span_iff_repr_mem (m : M) : refine ⟨fun hm i => ⟨(b.restrictScalars R).repr ⟨m, hm⟩ i, b.restrictScalars_repr_apply R ⟨m, hm⟩ i⟩, fun h => ?_⟩ - rw [← b.total_repr m, Finsupp.total_apply S _] + rw [← b.linearCombination_repr m, Finsupp.linearCombination_apply S _] refine sum_mem fun i _ => ?_ obtain ⟨_, h⟩ := h i simp_rw [← h, algebraMap_smul] diff --git a/Mathlib/LinearAlgebra/Basis/Bilinear.lean b/Mathlib/LinearAlgebra/Basis/Bilinear.lean index dd756b57e5821..ec749b417a941 100644 --- a/Mathlib/LinearAlgebra/Basis/Bilinear.lean +++ b/Mathlib/LinearAlgebra/Basis/Bilinear.lean @@ -41,8 +41,8 @@ Version for semi-bilinear maps, see `sum_repr_mul_repr_mul` for the bilinear ver theorem sum_repr_mul_repr_mulₛₗ {B : M →ₛₗ[ρ₁₂] N →ₛₗ[σ₁₂] P} (x y) : ((b₁.repr x).sum fun i xi => (b₂.repr y).sum fun j yj => ρ₁₂ xi • σ₁₂ yj • B (b₁ i) (b₂ j)) = B x y := by - conv_rhs => rw [← b₁.total_repr x, ← b₂.total_repr y] - simp_rw [Finsupp.total_apply, Finsupp.sum, map_sum₂, map_sum, LinearMap.map_smulₛₗ₂, + conv_rhs => rw [← b₁.linearCombination_repr x, ← b₂.linearCombination_repr y] + simp_rw [Finsupp.linearCombination_apply, Finsupp.sum, map_sum₂, map_sum, LinearMap.map_smulₛₗ₂, LinearMap.map_smulₛₗ] /-- Write out `B x y` as a sum over `B (b i) (b j)` if `b` is a basis. @@ -51,8 +51,8 @@ Version for bilinear maps, see `sum_repr_mul_repr_mulₛₗ` for the semi-biline theorem sum_repr_mul_repr_mul {B : Mₗ →ₗ[Rₗ] Nₗ →ₗ[Rₗ] Pₗ} (x y) : ((b₁'.repr x).sum fun i xi => (b₂'.repr y).sum fun j yj => xi • yj • B (b₁' i) (b₂' j)) = B x y := by - conv_rhs => rw [← b₁'.total_repr x, ← b₂'.total_repr y] - simp_rw [Finsupp.total_apply, Finsupp.sum, map_sum₂, map_sum, LinearMap.map_smul₂, + conv_rhs => rw [← b₁'.linearCombination_repr x, ← b₂'.linearCombination_repr y] + simp_rw [Finsupp.linearCombination_apply, Finsupp.sum, map_sum₂, map_sum, LinearMap.map_smul₂, LinearMap.map_smul] end AddCommMonoid diff --git a/Mathlib/LinearAlgebra/Basis/Cardinality.lean b/Mathlib/LinearAlgebra/Basis/Cardinality.lean index 74b34a45465d4..284ad5ed30aa4 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 /-! @@ -12,13 +13,15 @@ import Mathlib.SetTheory.Cardinal.Cofinality section Finite -open Basis Cardinal Set Submodule +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] [AddCommGroup 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 @@ -49,9 +52,9 @@ lemma basis_finite_of_finite_spans (w : Set M) (hw : w.Finite) (s : span R w = let bS : Set M := b '' S have h : ∀ x ∈ w, x ∈ span R bS := by intro x m - rw [← b.total_repr x, Finsupp.span_image_eq_map_total, Submodule.mem_map] + 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`, @@ -101,9 +111,9 @@ theorem union_support_maximal_linearIndependent_eq_range_basis {ι : Type w} (b apply LinearIndependent.to_subtype_range rw [linearIndependent_iff] intro l z - rw [Finsupp.total_option] at z + rw [Finsupp.linearCombination_option] at z simp only [v', Option.elim'] at z - change _ + Finsupp.total κ M R v l.some = 0 at z + change _ + Finsupp.linearCombination R v l.some = 0 at z -- We have some linear combination of `b b'` and the `v i`, which we want to show is trivial. -- We'll first show the coefficient of `b b'` is zero, -- by expressing the `v i` in the basis `b`, and using that the `v i` have no `b b'` term. @@ -113,8 +123,9 @@ theorem union_support_maximal_linearIndependent_eq_range_basis {ι : Type w} (b apply_fun fun x => b.repr x b' at z simp only [repr_self, map_smul, mul_one, Finsupp.single_eq_same, Pi.neg_apply, Finsupp.smul_single', map_neg, Finsupp.coe_neg] at z - erw [DFunLike.congr_fun (Finsupp.apply_total R (b.repr : M →ₗ[R] ι →₀ R) v l.some) b'] at z - simpa [Finsupp.total_apply, w] using z + erw [DFunLike.congr_fun (apply_linearCombination R (b.repr : M →ₗ[R] ι →₀ R) v l.some) b'] + at z + simpa [Finsupp.linearCombination_apply, w] using z -- Then all the other coefficients are zero, because `v` is linear independent. have l₁ : l.some = 0 := by rw [l₀, zero_smul, zero_add] at z @@ -152,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/Defs.lean b/Mathlib/LinearAlgebra/Basis/Defs.lean index 23deb6b640ceb..c731874f77c56 100644 --- a/Mathlib/LinearAlgebra/Basis/Defs.lean +++ b/Mathlib/LinearAlgebra/Basis/Defs.lean @@ -59,7 +59,7 @@ noncomputable section universe u -open Function Set Submodule +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*} @@ -134,36 +134,42 @@ theorem repr_self_apply (j) [Decidable (i = j)] : b.repr (b i) j = if i = j then rw [repr_self, Finsupp.single_apply] @[simp] -theorem repr_symm_apply (v) : b.repr.symm v = Finsupp.total ι M R b v := +theorem repr_symm_apply (v) : b.repr.symm v = Finsupp.linearCombination R b v := calc b.repr.symm v = b.repr.symm (v.sum Finsupp.single) := by simp _ = v.sum fun i vi => b.repr.symm (Finsupp.single i vi) := map_finsupp_sum .. - _ = Finsupp.total ι M R b v := by simp only [repr_symm_single, Finsupp.total_apply] + _ = Finsupp.linearCombination R b v := by simp only [repr_symm_single, + Finsupp.linearCombination_apply] @[simp] -theorem coe_repr_symm : ↑b.repr.symm = Finsupp.total ι M R b := +theorem coe_repr_symm : ↑b.repr.symm = Finsupp.linearCombination R b := LinearMap.ext fun v => b.repr_symm_apply v @[simp] -theorem repr_total (v) : b.repr (Finsupp.total _ _ _ b v) = v := by +theorem repr_linearCombination (v) : b.repr (Finsupp.linearCombination _ b v) = v := by rw [← b.coe_repr_symm] exact b.repr.apply_symm_apply v +@[deprecated (since := "2024-08-29")] alias repr_total := repr_linearCombination + @[simp] -theorem total_repr : Finsupp.total _ _ _ b (b.repr x) = x := by +theorem linearCombination_repr : Finsupp.linearCombination _ b (b.repr x) = x := by rw [← b.coe_repr_symm] exact b.repr.symm_apply_apply x +@[deprecated (since := "2024-08-29")] alias total_repr := linearCombination_repr + theorem repr_range : LinearMap.range (b.repr : M →ₗ[R] ι →₀ R) = Finsupp.supported R R univ := by rw [LinearEquiv.range, Finsupp.supported_univ] theorem mem_span_repr_support (m : M) : m ∈ span R (b '' (b.repr m).support) := - (Finsupp.mem_span_image_iff_total _).2 ⟨b.repr m, by simp [Finsupp.mem_supported_support]⟩ + (Finsupp.mem_span_image_iff_linearCombination _).2 + ⟨b.repr m, by simp [Finsupp.mem_supported_support]⟩ theorem repr_support_subset_of_mem_span (s : Set ι) {m : M} (hm : m ∈ span R (b '' s)) : ↑(b.repr m).support ⊆ s := by - rcases (Finsupp.mem_span_image_iff_total _).1 hm with ⟨l, hl, rfl⟩ - rwa [repr_total, ← Finsupp.mem_supported R l] + rcases (Finsupp.mem_span_image_iff_linearCombination _).1 hm with ⟨l, hl, rfl⟩ + rwa [repr_linearCombination, ← Finsupp.mem_supported R l] theorem mem_span_image {m : M} {s : Set ι} : m ∈ span R (b '' s) ↔ ↑(b.repr m).support ⊆ s := ⟨repr_support_subset_of_mem_span _ _, fun h ↦ @@ -219,7 +225,7 @@ theorem dvd_coord_smul (i : ι) (m : M) (r : R) : r ∣ b.coord i (r • m) := theorem coord_repr_symm (b : Basis ι R M) (i : ι) (f : ι →₀ R) : b.coord i (b.repr.symm f) = f i := by - simp only [repr_symm_apply, coord_apply, repr_total] + simp only [repr_symm_apply, coord_apply, repr_linearCombination] end Coord @@ -232,13 +238,13 @@ variable {M₁ : Type*} [AddCommMonoid M₁] [Module R₁ M₁] /-- Two linear maps are equal if they are equal on basis vectors. -/ theorem ext {f₁ f₂ : M →ₛₗ[σ] M₁} (h : ∀ i, f₁ (b i) = f₂ (b i)) : f₁ = f₂ := by ext x - rw [← b.total_repr x, Finsupp.total_apply, Finsupp.sum] + rw [← b.linearCombination_repr x, Finsupp.linearCombination_apply, Finsupp.sum] simp only [map_sum, LinearMap.map_smulₛₗ, h] /-- Two linear equivs are equal if they are equal on basis vectors. -/ theorem ext' {f₁ f₂ : M ≃ₛₗ[σ] M₁} (h : ∀ i, f₁ (b i) = f₂ (b i)) : f₁ = f₂ := by ext x - rw [← b.total_repr x, Finsupp.total_apply, Finsupp.sum] + rw [← b.linearCombination_repr x, Finsupp.linearCombination_apply, Finsupp.sum] simp only [map_sum, LinearEquiv.map_smulₛₗ, h] /-- Two elements are equal iff their coordinates are equal. -/ @@ -532,8 +538,8 @@ theorem mem_submodule_iff {P : Submodule R M} (b : Basis ι R P) {x : M} : x ∈ P ↔ ∃ c : ι →₀ R, x = Finsupp.sum c fun i x => x • (b i : M) := by conv_lhs => rw [← P.range_subtype, ← Submodule.map_top, ← b.span_eq, Submodule.map_span, ← Set.range_comp, - ← Finsupp.range_total] - simp [@eq_comm _ x, Function.comp, Finsupp.total_apply] + ← Finsupp.range_linearCombination] + simp [@eq_comm _ x, Function.comp, Finsupp.linearCombination_apply] section Constr @@ -551,7 +557,7 @@ you can recover an `AddEquiv` by setting `S := ℕ`. See library note [bundled maps over different rings]. -/ def constr : (ι → M') ≃ₗ[S] M →ₗ[R] M' where - toFun f := (Finsupp.total M' M' R id).comp <| Finsupp.lmapDomain R R f ∘ₗ ↑b.repr + toFun f := (Finsupp.linearCombination R id).comp <| Finsupp.lmapDomain R R f ∘ₗ ↑b.repr invFun f i := f (b i) left_inv f := by ext @@ -567,12 +573,12 @@ def constr : (ι → M') ≃ₗ[S] M →ₗ[R] M' where simp theorem constr_def (f : ι → M') : - constr (M' := M') b S f = Finsupp.total M' M' R id ∘ₗ Finsupp.lmapDomain R R f ∘ₗ ↑b.repr := + constr (M' := M') b S f = linearCombination R id ∘ₗ Finsupp.lmapDomain R R f ∘ₗ ↑b.repr := rfl theorem constr_apply (f : ι → M') (x : M) : constr (M' := M') b S f x = (b.repr x).sum fun b a => a • f b := by - simp only [constr_def, LinearMap.comp_apply, Finsupp.lmapDomain_apply, Finsupp.total_apply] + simp only [constr_def, LinearMap.comp_apply, lmapDomain_apply, linearCombination_apply] rw [Finsupp.sum_mapDomain_index] <;> simp [add_smul] @[simp] @@ -590,7 +596,7 @@ theorem constr_range {f : ι → M'} : LinearMap.range (constr (M' := M') b S f) = span R (range f) := by rw [b.constr_def S f, LinearMap.range_comp, LinearMap.range_comp, LinearEquiv.range, ← Finsupp.supported_univ, Finsupp.lmapDomain_supported, ← Set.image_univ, ← - Finsupp.span_image_eq_map_total, Set.image_id] + Finsupp.span_image_eq_map_linearCombination, Set.image_id] @[simp] theorem constr_comp (f : M' →ₗ[R] M') (v : ι → M') : @@ -704,7 +710,7 @@ a function `x : ι → R` to the linear combination `∑_i x i • v i`. -/ @[simp] theorem Basis.equivFun_symm_apply [Fintype ι] (b : Basis ι R M) (x : ι → R) : b.equivFun.symm x = ∑ i, x i • b i := by - simp [Basis.equivFun, Finsupp.total_apply, Finsupp.sum_fintype, Finsupp.equivFunOnFinite] + simp [Basis.equivFun, Finsupp.linearCombination_apply, sum_fintype, equivFunOnFinite] @[simp] theorem Basis.equivFun_apply [Finite ι] (b : Basis ι R M) (u : M) : b.equivFun u = b.repr u := diff --git a/Mathlib/LinearAlgebra/Basis/VectorSpace.lean b/Mathlib/LinearAlgebra/Basis/VectorSpace.lean index 5ffcc1cc36b43..e7a219e569dab 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) diff --git a/Mathlib/LinearAlgebra/BilinearForm/Hom.lean b/Mathlib/LinearAlgebra/BilinearForm/Hom.lean index 9e99d5b63ae90..f32f28e8aea31 100644 --- a/Mathlib/LinearAlgebra/BilinearForm/Hom.lean +++ b/Mathlib/LinearAlgebra/BilinearForm/Hom.lean @@ -347,8 +347,8 @@ theorem ext_basis (h : ∀ i j, B (b i) (b j) = F₂ (b i) (b j)) : B = F₂ := /-- Write out `B x y` as a sum over `B (b i) (b j)` if `b` is a basis. -/ theorem sum_repr_mul_repr_mul (x y : M) : ((b.repr x).sum fun i xi => (b.repr y).sum fun j yj => xi • yj • B (b i) (b j)) = B x y := by - conv_rhs => rw [← b.total_repr x, ← b.total_repr y] - simp_rw [Finsupp.total_apply, Finsupp.sum, sum_left, sum_right, smul_left, smul_right, + conv_rhs => rw [← b.linearCombination_repr x, ← b.linearCombination_repr y] + simp_rw [Finsupp.linearCombination_apply, Finsupp.sum, sum_left, sum_right, smul_left, smul_right, smul_eq_mul] end Basis diff --git a/Mathlib/LinearAlgebra/BilinearForm/Orthogonal.lean b/Mathlib/LinearAlgebra/BilinearForm/Orthogonal.lean index fb7036771789e..bff969f2c534c 100644 --- a/Mathlib/LinearAlgebra/BilinearForm/Orthogonal.lean +++ b/Mathlib/LinearAlgebra/BilinearForm/Orthogonal.lean @@ -217,7 +217,7 @@ theorem iIsOrtho.not_isOrtho_basis_self_of_nondegenerate {n : Type w} [Nontrivia intro ho refine v.ne_zero i (hB (v i) fun m => ?_) obtain ⟨vi, rfl⟩ := v.repr.symm.surjective m - rw [Basis.repr_symm_apply, Finsupp.total_apply, Finsupp.sum, sum_right] + rw [Basis.repr_symm_apply, Finsupp.linearCombination_apply, Finsupp.sum, sum_right] apply Finset.sum_eq_zero rintro j - rw [smul_right] @@ -237,7 +237,8 @@ theorem iIsOrtho.nondegenerate_iff_not_isOrtho_basis_self {n : Type w} [Nontrivi ext i rw [Finsupp.zero_apply] specialize hB (v i) - simp_rw [Basis.repr_symm_apply, Finsupp.total_apply, Finsupp.sum, sum_left, smul_left] at hB + simp_rw [Basis.repr_symm_apply, Finsupp.linearCombination_apply, Finsupp.sum, sum_left, + smul_left] at hB rw [Finset.sum_eq_single i] at hB · exact eq_zero_of_ne_zero_of_mul_right_eq_zero (ho i) hB · intro j _ hij @@ -282,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 @@ -293,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⟩ @@ -301,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 6d283deb55741..65f1bea36c373 100644 --- a/Mathlib/LinearAlgebra/BilinearForm/Properties.lean +++ b/Mathlib/LinearAlgebra/BilinearForm/Properties.lean @@ -411,12 +411,11 @@ noncomputable def dualBasis (B : BilinForm K V) (hB : B.Nondegenerate) (b : Basi theorem dualBasis_repr_apply (B : BilinForm K V) (hB : B.Nondegenerate) (b : Basis ι K V) (x i) : (B.dualBasis hB b).repr x i = B x (b i) := by - rw [dualBasis, Basis.map_repr, LinearEquiv.symm_symm, LinearEquiv.trans_apply, - Basis.dualBasis_repr] #adaptation_note - /-- Before leanprover/lean4#4814, we had a final `toDual_def` in the `rw`, - and no need for the `rfl`. I'm confused! -/ - rfl + /-- Before leanprover/lean4#4814, we did not need the `@` in front of `toDual_def` in the `rw`. + I'm confused! -/ + rw [dualBasis, Basis.map_repr, LinearEquiv.symm_symm, LinearEquiv.trans_apply, + Basis.dualBasis_repr, @toDual_def] theorem apply_dualBasis_left (B : BilinForm K V) (hB : B.Nondegenerate) (b : Basis ι K V) (i j) : B (B.dualBasis hB b i) (b j) = if j = i then 1 else 0 := by @@ -465,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 eb6892bb52914..d7ab301e16a91 100644 --- a/Mathlib/LinearAlgebra/BilinearForm/TensorProduct.lean +++ b/Mathlib/LinearAlgebra/BilinearForm/TensorProduct.lean @@ -30,8 +30,7 @@ namespace LinearMap namespace BilinMap -open LinearMap (BilinMap) -open LinearMap (BilinForm) +open LinearMap (BilinMap BilinForm) section CommSemiring variable [CommSemiring R] [CommSemiring A] diff --git a/Mathlib/LinearAlgebra/BilinearMap.lean b/Mathlib/LinearAlgebra/BilinearMap.lean index b9e49faf0456c..10c008423626e 100644 --- a/Mathlib/LinearAlgebra/BilinearMap.lean +++ b/Mathlib/LinearAlgebra/BilinearMap.lean @@ -37,16 +37,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₂} @@ -376,14 +375,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/Basic.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean index ac24ee710f6f0..8f6b4168968e9 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean @@ -185,7 +185,7 @@ theorem hom_ext {A : Type*} [Semiring A] [Algebra R A] {f g : CliffordAlgebra Q -- This proof closely follows `TensorAlgebra.induction` /-- If `C` holds for the `algebraMap` of `r : R` into `CliffordAlgebra Q`, the `ι` of `x : M`, -and is preserved under addition and muliplication, then it holds for all of `CliffordAlgebra Q`. +and is preserved under addition and multiplication, then it holds for all of `CliffordAlgebra Q`. See also the stronger `CliffordAlgebra.left_induction` and `CliffordAlgebra.right_induction`. -/ diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Contraction.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Contraction.lean index 978452899a1a5..8ef0b35b3f973 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Contraction.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Contraction.lean @@ -40,8 +40,7 @@ Within this file, we use the local notation -/ -open LinearMap (BilinMap) -open LinearMap (BilinForm) +open LinearMap (BilinMap BilinForm) universe u1 u2 u3 diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Equivs.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Equivs.lean index 64eab0f1101ed..30687d5b35594 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Equivs.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Equivs.lean @@ -358,7 +358,7 @@ variable {R M : Type*} [CommRing R] [AddCommGroup M] [Module R M] 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, - LinearMap.map_smul, smul_mul_smul, ι_sq_scalar, QuadraticMap.zero_apply, RingHom.map_zero, + LinearMap.map_smul, smul_mul_smul_comm, ι_sq_scalar, QuadraticMap.zero_apply, RingHom.map_zero, smul_zero] /-- The clifford algebra over a 1-dimensional vector space with 0 quadratic form is isomorphic to diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Even.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Even.lean index ab5a28a5dcedc..76bff36c9a4d1 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Even.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Even.lean @@ -125,7 +125,7 @@ variable {Q} namespace even.lift /-- An auxiliary submodule used to store the half-applied values of `f`. -This is the span of elements `f'` such that `∃ x m₂, ∀ m₁, f' m₁ = f m₁ m₂ * x`. -/ +This is the span of elements `f'` such that `∃ x m₂, ∀ m₁, f' m₁ = f m₁ m₂ * x`. -/ private def S : Submodule R (M →ₗ[R] A) := Submodule.span R {f' | ∃ x m₂, f' = LinearMap.lcomp R _ (f.bilin.flip m₂) (LinearMap.mulRight R x)} diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/EvenEquiv.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/EvenEquiv.lean index ff16afc3d7f70..d699e29ff8b2d 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/EvenEquiv.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/EvenEquiv.lean @@ -187,7 +187,7 @@ theorem toEven_comp_ofEven : (toEven Q).comp (ofEven Q) = AlgHom.id R _ := have h2 : -(r₂ • e0 Q * v Q m₁) = v Q m₁ * r₂ • e0 Q := by rw [mul_smul_comm, smul_mul_assoc, ← smul_neg, neg_e0_mul_v] have h3 : -algebraMap R _ (r₁ * r₂) = r₁ • e0 Q * r₂ • e0 Q := by - rw [Algebra.algebraMap_eq_smul_one, smul_mul_smul, e0_mul_e0, smul_neg] + rw [Algebra.algebraMap_eq_smul_one, smul_mul_smul_comm, e0_mul_e0, smul_neg] rw [sub_eq_add_neg, sub_eq_add_neg, h1, h2, h3] _ = ι (Q' Q) (m₁, r₁) * ι (Q' Q) (m₂, r₂) := by rw [ι_eq_v_add_smul_e0, ι_eq_v_add_smul_e0, mul_add, add_mul, add_mul, add_assoc] diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean index 4359ba5b328d0..e5f6c2be85383 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean @@ -154,7 +154,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,7 +197,7 @@ 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 + refine evenOdd_induction _ _ (motive := motive) (fun rx => ?_) add ι_mul_ι_mul x hx rintro ⟨r, rfl⟩ exact algebraMap r @@ -213,7 +213,7 @@ 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 + 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 rintro ⟨v, rfl⟩ diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Prod.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Prod.lean index fab6f0c7bfae4..e06d940aa2396 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Prod.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Prod.lean @@ -43,7 +43,7 @@ variable (f₁ : Q₁ →qᵢ Qₙ) (f₂ : Q₂ →qᵢ Qₙ) (hf : ∀ x y, Q variable (m₁ : CliffordAlgebra Q₁) (m₂ : CliffordAlgebra Q₂) include hf -/-- If `m₁` and `m₂` are both homogenous, +/-- If `m₁` and `m₂` are both homogeneous, and the quadratic spaces `Q₁` and `Q₂` map into orthogonal subspaces of `Qₙ` (for instance, when `Qₙ = Q₁.prod Q₂`), then the product of the embedding in `CliffordAlgebra Q` commutes up to a sign factor. -/ @@ -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, @@ -151,9 +151,9 @@ lemma toProd_one_tmul_ι (m₂ : M₂) : toProd Q₁ Q₂ (1 ᵍ⊗ₜ ι _ m₂ lemma toProd_comp_ofProd : (toProd Q₁ Q₂).comp (ofProd Q₁ Q₂) = AlgHom.id _ _ := by ext m <;> dsimp - · rw [ofProd_ι_mk, map_add, toProd_one_tmul_ι, toProd_ι_tmul_one, ← Prod.zero_eq_mk, + · rw [ofProd_ι_mk, map_add, toProd_one_tmul_ι, toProd_ι_tmul_one, Prod.mk_zero_zero, LinearMap.map_zero, add_zero] - · rw [ofProd_ι_mk, map_add, toProd_one_tmul_ι, toProd_ι_tmul_one, ← Prod.zero_eq_mk, + · rw [ofProd_ι_mk, map_add, toProd_one_tmul_ι, toProd_ι_tmul_one, Prod.mk_zero_zero, LinearMap.map_zero, zero_add] lemma ofProd_comp_toProd : (ofProd Q₁ Q₂).comp (toProd Q₁ Q₂) = AlgHom.id _ _ := by diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/SpinGroup.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/SpinGroup.lean new file mode 100644 index 0000000000000..06dfb81ec8f83 --- /dev/null +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/SpinGroup.lean @@ -0,0 +1,411 @@ +/- +Copyright (c) 2022 Jiale Miao. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jiale Miao, Utensil Song, Eric Wieser +-/ +import Mathlib.GroupTheory.GroupAction.ConjAct +import Mathlib.Algebra.Star.Unitary +import Mathlib.LinearAlgebra.CliffordAlgebra.Star +import Mathlib.LinearAlgebra.CliffordAlgebra.Even +import Mathlib.LinearAlgebra.CliffordAlgebra.Inversion + +/-! +# The Pin group and the Spin group + +In this file we define `lipschitzGroup`, `pinGroup` and `spinGroup` and show they form a group. + +## Main definitions + +* `lipschitzGroup`: the Lipschitz group with a quadratic form. +* `pinGroup`: the Pin group defined as the infimum of `lipschitzGroup` and `unitary`. +* `spinGroup`: the Spin group defined as the infimum of `pinGroup` and `CliffordAlgebra.even`. + +## Implementation Notes + +The definition of the Lipschitz group +$\{ x \in \mathop{\mathcal{C}\ell} | x \text{ is invertible and } x v x^{-1} ∈ V \}$ is given by: + +* [fulton2004][], Chapter 20 +* https://en.wikipedia.org/wiki/Clifford_algebra#Lipschitz_group + +But they presumably form a group only in finite dimensions. So we define `lipschitzGroup` with +closure of all the invertible elements in the form of `ι Q m`, and we show this definition is +at least as large as the other definition (See `lipschitzGroup.conjAct_smul_range_ι` and +`lipschitzGroup.involute_act_ι_mem_range_ι`). +The reverse statement presumably is true only in finite dimensions. + +Here are some discussions about the latent ambiguity of definition : +https://mathoverflow.net/q/427881/172242 and https://mathoverflow.net/q/251288/172242 + +## TODO + +Try to show the reverse statement is true in finite dimensions. +-/ + +variable {R : Type*} [CommRing R] +variable {M : Type*} [AddCommGroup M] [Module R M] +variable {Q : QuadraticForm R M} + +section Pin + +open CliffordAlgebra MulAction + +open scoped Pointwise + +/-- `lipschitzGroup` is the subgroup closure of all the invertible elements in the form of `ι Q m` +where `ι` is the canonical linear map `M →ₗ[R] CliffordAlgebra Q`. -/ +def lipschitzGroup (Q : QuadraticForm R M) : Subgroup (CliffordAlgebra Q)ˣ := + Subgroup.closure ((↑) ⁻¹' Set.range (ι Q) : Set (CliffordAlgebra Q)ˣ) + +namespace lipschitzGroup + +/-- The conjugation action by elements of the Lipschitz group keeps vectors as vectors. -/ +theorem conjAct_smul_ι_mem_range_ι {x : (CliffordAlgebra Q)ˣ} (hx : x ∈ lipschitzGroup Q) + [Invertible (2 : R)] (m : M) : + ConjAct.toConjAct x • ι Q m ∈ LinearMap.range (ι Q) := by + unfold lipschitzGroup at hx + rw [ConjAct.units_smul_def, ConjAct.ofConjAct_toConjAct] + induction hx using Subgroup.closure_induction'' generalizing m with + | mem x hx => + obtain ⟨a, ha⟩ := hx + letI := x.invertible + letI : Invertible (ι Q a) := by rwa [ha] + letI : Invertible (Q a) := invertibleOfInvertibleι Q a + simp_rw [← invOf_units x, ← ha, ι_mul_ι_mul_invOf_ι, LinearMap.mem_range_self] + | inv_mem x hx => + obtain ⟨a, ha⟩ := hx + letI := x.invertible + letI : Invertible (ι Q a) := by rwa [ha] + letI : Invertible (Q a) := invertibleOfInvertibleι Q a + letI := invertibleNeg (ι Q a) + letI := Invertible.map involute (ι Q a) + simp_rw [← invOf_units x, inv_inv, ← ha, invOf_ι_mul_ι_mul_ι, LinearMap.mem_range_self] + | one => simp_rw [inv_one, Units.val_one, one_mul, mul_one, LinearMap.mem_range_self] + | mul y z _ _ hy hz => + simp_rw [mul_inv_rev, Units.val_mul] + suffices ↑y * (↑z * ι Q m * ↑z⁻¹) * ↑y⁻¹ ∈ _ by + simpa only [mul_assoc] using this + obtain ⟨z', hz'⟩ := hz m + obtain ⟨y', hy'⟩ := hy z' + simp_rw [← hz', ← hy', LinearMap.mem_range_self] + +/-- This is another version of `lipschitzGroup.conjAct_smul_ι_mem_range_ι` which uses `involute`. -/ +theorem involute_act_ι_mem_range_ι [Invertible (2 : R)] + {x : (CliffordAlgebra Q)ˣ} (hx : x ∈ lipschitzGroup Q) (b : M) : + involute (Q := Q) ↑x * ι Q b * ↑x⁻¹ ∈ LinearMap.range (ι Q) := by + unfold lipschitzGroup at hx + induction hx using Subgroup.closure_induction'' generalizing b with + | mem x hx => + obtain ⟨a, ha⟩ := hx + letI := x.invertible + letI : Invertible (ι Q a) := by rwa [ha] + letI : Invertible (Q a) := invertibleOfInvertibleι Q a + simp_rw [← invOf_units x, ← ha, involute_ι, neg_mul, ι_mul_ι_mul_invOf_ι Q a b, ← map_neg, + LinearMap.mem_range_self] + | inv_mem x hx => + obtain ⟨a, ha⟩ := hx + letI := x.invertible + letI : Invertible (ι Q a) := by rwa [ha] + letI : Invertible (Q a) := invertibleOfInvertibleι Q a + letI := invertibleNeg (ι Q a) + letI := Invertible.map involute (ι Q a) + simp_rw [← invOf_units x, inv_inv, ← ha, map_invOf, involute_ι, invOf_neg, neg_mul, + invOf_ι_mul_ι_mul_ι, ← map_neg, LinearMap.mem_range_self] + | one => simp_rw [inv_one, Units.val_one, map_one, one_mul, mul_one, LinearMap.mem_range_self] + | mul y z _ _ hy hz => + simp_rw [mul_inv_rev, Units.val_mul, map_mul] + suffices involute (Q := Q) ↑y * (involute (Q := Q) ↑z * ι Q b * ↑z⁻¹) * ↑y⁻¹ ∈ _ by + simpa only [mul_assoc] using this + obtain ⟨z', hz'⟩ := hz b + obtain ⟨y', hy'⟩ := hy z' + simp_rw [← hz', ← hy', LinearMap.mem_range_self] + +/-- If x is in `lipschitzGroup Q`, then `(ι Q).range` is closed under twisted conjugation. +The reverse statement presumably is true only in finite dimensions.-/ +theorem conjAct_smul_range_ι {x : (CliffordAlgebra Q)ˣ} (hx : x ∈ lipschitzGroup Q) + [Invertible (2 : R)] : + ConjAct.toConjAct x • LinearMap.range (ι Q) = LinearMap.range (ι Q) := by + suffices ∀ x ∈ lipschitzGroup Q, + ConjAct.toConjAct x • LinearMap.range (ι Q) ≤ LinearMap.range (ι Q) by + apply le_antisymm + · exact this _ hx + · have := smul_mono_right (ConjAct.toConjAct x) <| this _ (inv_mem hx) + refine Eq.trans_le ?_ this + simp only [map_inv, smul_inv_smul] + intro x hx + erw [Submodule.map_le_iff_le_comap] + rintro _ ⟨m, rfl⟩ + exact conjAct_smul_ι_mem_range_ι hx _ + +theorem coe_mem_iff_mem {x : (CliffordAlgebra Q)ˣ} : + ↑x ∈ (lipschitzGroup Q).toSubmonoid.map (Units.coeHom <| CliffordAlgebra Q) ↔ + x ∈ lipschitzGroup Q := by + simp only [Submonoid.mem_map, Subgroup.mem_toSubmonoid, Units.coeHom_apply, exists_prop] + norm_cast + exact exists_eq_right + +end lipschitzGroup + +/-- `pinGroup Q` is defined as the infimum of `lipschitzGroup Q` and `unitary (CliffordAlgebra Q)`. +See `mem_iff`. -/ +def pinGroup (Q : QuadraticForm R M) : Submonoid (CliffordAlgebra Q) := + (lipschitzGroup Q).toSubmonoid.map (Units.coeHom <| CliffordAlgebra Q) ⊓ unitary _ + +namespace pinGroup + +/-- An element is in `pinGroup Q` if and only if it is in `lipschitzGroup Q` and `unitary`. -/ +theorem mem_iff {x : CliffordAlgebra Q} : + x ∈ pinGroup Q ↔ + x ∈ (lipschitzGroup Q).toSubmonoid.map (Units.coeHom <| CliffordAlgebra Q) ∧ + x ∈ unitary (CliffordAlgebra Q) := + Iff.rfl + +theorem mem_lipschitzGroup {x : CliffordAlgebra Q} (hx : x ∈ pinGroup Q) : + x ∈ (lipschitzGroup Q).toSubmonoid.map (Units.coeHom <| CliffordAlgebra Q) := + hx.1 + +theorem mem_unitary {x : CliffordAlgebra Q} (hx : x ∈ pinGroup Q) : + x ∈ unitary (CliffordAlgebra Q) := + hx.2 + +theorem units_mem_iff {x : (CliffordAlgebra Q)ˣ} : + ↑x ∈ pinGroup Q ↔ x ∈ lipschitzGroup Q ∧ ↑x ∈ unitary (CliffordAlgebra Q) := by + rw [mem_iff, lipschitzGroup.coe_mem_iff_mem] + +theorem units_mem_lipschitzGroup {x : (CliffordAlgebra Q)ˣ} (hx : ↑x ∈ pinGroup Q) : + x ∈ lipschitzGroup Q := + (units_mem_iff.1 hx).1 + +/-- The conjugation action by elements of the spin group keeps vectors as vectors. -/ +theorem conjAct_smul_ι_mem_range_ι {x : (CliffordAlgebra Q)ˣ} (hx : ↑x ∈ pinGroup Q) + [Invertible (2 : R)] (y : M) : ConjAct.toConjAct x • ι Q y ∈ LinearMap.range (ι Q) := + lipschitzGroup.conjAct_smul_ι_mem_range_ι (units_mem_lipschitzGroup hx) y + +/-- This is another version of `conjAct_smul_ι_mem_range_ι` which uses `involute`. -/ +theorem involute_act_ι_mem_range_ι {x : (CliffordAlgebra Q)ˣ} (hx : ↑x ∈ pinGroup Q) + [Invertible (2 : R)] (y : M) : involute (Q := Q) ↑x * ι Q y * ↑x⁻¹ ∈ LinearMap.range (ι Q) := + lipschitzGroup.involute_act_ι_mem_range_ι (units_mem_lipschitzGroup hx) y + +/-- If x is in `pinGroup Q`, then `(ι Q).range` is closed under twisted conjugation. The reverse +statement presumably being true only in finite dimensions.-/ +theorem conjAct_smul_range_ι {x : (CliffordAlgebra Q)ˣ} (hx : ↑x ∈ pinGroup Q) + [Invertible (2 : R)] : ConjAct.toConjAct x • LinearMap.range (ι Q) = LinearMap.range (ι Q) := + lipschitzGroup.conjAct_smul_range_ι (units_mem_lipschitzGroup hx) + +@[simp] +theorem star_mul_self_of_mem {x : CliffordAlgebra Q} (hx : x ∈ pinGroup Q) : star x * x = 1 := + hx.2.1 + +@[simp] +theorem mul_star_self_of_mem {x : CliffordAlgebra Q} (hx : x ∈ pinGroup Q) : x * star x = 1 := + hx.2.2 + +/-- See `star_mem_iff` for both directions. -/ +theorem star_mem {x : CliffordAlgebra Q} (hx : x ∈ pinGroup Q) : star x ∈ pinGroup Q := by + rw [mem_iff] at hx ⊢ + refine ⟨?_, unitary.star_mem hx.2⟩ + rcases hx with ⟨⟨y, hy₁, hy₂⟩, _hx₂, hx₃⟩ + simp only [Subgroup.coe_toSubmonoid, SetLike.mem_coe] at hy₁ + simp only [Units.coeHom_apply] at hy₂ + simp only [Submonoid.mem_map, Subgroup.mem_toSubmonoid, Units.coeHom_apply, exists_prop] + refine ⟨star y, ?_, by simp only [hy₂, Units.coe_star]⟩ + rw [← hy₂] at hx₃ + have hy₃ : y * star y = 1 := by + rw [← Units.eq_iff] + simp only [hx₃, Units.val_mul, Units.coe_star, Units.val_one] + apply_fun fun x => y⁻¹ * x at hy₃ + simp only [inv_mul_cancel_left, mul_one] at hy₃ + simp only [hy₃, hy₁, inv_mem_iff] + +/-- An element is in `pinGroup Q` if and only if `star x` is in `pinGroup Q`. +See `star_mem` for only one direction. -/ +@[simp] +theorem star_mem_iff {x : CliffordAlgebra Q} : star x ∈ pinGroup Q ↔ x ∈ pinGroup Q := by + refine ⟨?_, star_mem⟩ + intro hx + convert star_mem hx + exact (star_star x).symm + +instance : Star (pinGroup Q) where + star x := ⟨star x, star_mem x.prop⟩ + +@[simp, norm_cast] +theorem coe_star {x : pinGroup Q} : ↑(star x) = (star x : CliffordAlgebra Q) := + rfl + +theorem coe_star_mul_self (x : pinGroup Q) : (star x : CliffordAlgebra Q) * x = 1 := + star_mul_self_of_mem x.prop + +theorem coe_mul_star_self (x : pinGroup Q) : (x : CliffordAlgebra Q) * star x = 1 := + mul_star_self_of_mem x.prop + +@[simp] +theorem star_mul_self (x : pinGroup Q) : star x * x = 1 := + Subtype.ext <| coe_star_mul_self x + +@[simp] +theorem mul_star_self (x : pinGroup Q) : x * star x = 1 := + Subtype.ext <| coe_mul_star_self x + +/-- `pinGroup Q` forms a group where the inverse is `star`. -/ +instance : Group (pinGroup Q) where + inv := star + inv_mul_cancel := star_mul_self + +instance : StarMul (pinGroup Q) where + star_involutive _ := Subtype.ext <| star_involutive _ + star_mul _ _ := Subtype.ext <| star_mul _ _ + +instance : Inhabited (pinGroup Q) := + ⟨1⟩ + +theorem star_eq_inv (x : pinGroup Q) : star x = x⁻¹ := + rfl + +theorem star_eq_inv' : (star : pinGroup Q → pinGroup Q) = Inv.inv := + rfl + +/-- The elements in `pinGroup Q` embed into (CliffordAlgebra Q)ˣ. -/ +@[simps] +def toUnits : pinGroup Q →* (CliffordAlgebra Q)ˣ where + toFun x := ⟨x, ↑x⁻¹, coe_mul_star_self x, coe_star_mul_self x⟩ + map_one' := Units.ext rfl + map_mul' _x _y := Units.ext rfl + +theorem toUnits_injective : Function.Injective (toUnits : pinGroup Q → (CliffordAlgebra Q)ˣ) := + fun _x _y h => Subtype.ext <| Units.ext_iff.mp h + +end pinGroup + +end Pin + +section Spin + +open CliffordAlgebra MulAction + +open scoped Pointwise + +/-- `spinGroup Q` is defined as the infimum of `pinGroup Q` and `CliffordAlgebra.even Q`. +See `mem_iff`. -/ +def spinGroup (Q : QuadraticForm R M) : Submonoid (CliffordAlgebra Q) := + pinGroup Q ⊓ (CliffordAlgebra.even Q).toSubring.toSubmonoid + +namespace spinGroup + +/-- An element is in `spinGroup Q` if and only if it is in `pinGroup Q` and `even Q`. -/ +theorem mem_iff {x : CliffordAlgebra Q} : x ∈ spinGroup Q ↔ x ∈ pinGroup Q ∧ x ∈ even Q := + Iff.rfl + +theorem mem_pin {x : CliffordAlgebra Q} (hx : x ∈ spinGroup Q) : x ∈ pinGroup Q := + hx.1 + +theorem mem_even {x : CliffordAlgebra Q} (hx : x ∈ spinGroup Q) : x ∈ even Q := + hx.2 + +theorem units_mem_lipschitzGroup {x : (CliffordAlgebra Q)ˣ} (hx : ↑x ∈ spinGroup Q) : + x ∈ lipschitzGroup Q := + pinGroup.units_mem_lipschitzGroup (mem_pin hx) + +/-- If x is in `spinGroup Q`, then `involute x` is equal to x.-/ +theorem involute_eq {x : CliffordAlgebra Q} (hx : x ∈ spinGroup Q) : involute x = x := + involute_eq_of_mem_even (mem_even hx) + +theorem units_involute_act_eq_conjAct {x : (CliffordAlgebra Q)ˣ} (hx : ↑x ∈ spinGroup Q) (y : M) : + involute (Q := Q) ↑x * ι Q y * ↑x⁻¹ = ConjAct.toConjAct x • (ι Q y) := by + rw [involute_eq hx, @ConjAct.units_smul_def, @ConjAct.ofConjAct_toConjAct] + +/-- The conjugation action by elements of the spin group keeps vectors as vectors. -/ +theorem conjAct_smul_ι_mem_range_ι {x : (CliffordAlgebra Q)ˣ} (hx : ↑x ∈ spinGroup Q) + [Invertible (2 : R)] (y : M) : ConjAct.toConjAct x • ι Q y ∈ LinearMap.range (ι Q) := + lipschitzGroup.conjAct_smul_ι_mem_range_ι (units_mem_lipschitzGroup hx) y + +/- This is another version of `conjAct_smul_ι_mem_range_ι` which uses `involute`.-/ +theorem involute_act_ι_mem_range_ι {x : (CliffordAlgebra Q)ˣ} (hx : ↑x ∈ spinGroup Q) + [Invertible (2 : R)] (y : M) : involute (Q := Q) ↑x * ι Q y * ↑x⁻¹ ∈ LinearMap.range (ι Q) := + lipschitzGroup.involute_act_ι_mem_range_ι (units_mem_lipschitzGroup hx) y + +/- If x is in `spinGroup Q`, then `(ι Q).range` is closed under twisted conjugation. The reverse +statement presumably being true only in finite dimensions.-/ +theorem conjAct_smul_range_ι {x : (CliffordAlgebra Q)ˣ} (hx : ↑x ∈ spinGroup Q) + [Invertible (2 : R)] : ConjAct.toConjAct x • LinearMap.range (ι Q) = LinearMap.range (ι Q) := + lipschitzGroup.conjAct_smul_range_ι (units_mem_lipschitzGroup hx) + +@[simp] +theorem star_mul_self_of_mem {x : CliffordAlgebra Q} (hx : x ∈ spinGroup Q) : star x * x = 1 := + hx.1.2.1 + +@[simp] +theorem mul_star_self_of_mem {x : CliffordAlgebra Q} (hx : x ∈ spinGroup Q) : x * star x = 1 := + hx.1.2.2 + +/-- See `star_mem_iff` for both directions. -/ +theorem star_mem {x : CliffordAlgebra Q} (hx : x ∈ spinGroup Q) : star x ∈ spinGroup Q := by + rw [mem_iff] at hx ⊢ + cases' hx with hx₁ hx₂ + refine ⟨pinGroup.star_mem hx₁, ?_⟩ + dsimp only [CliffordAlgebra.even] at hx₂ ⊢ + simp only [Submodule.mem_toSubalgebra] at hx₂ ⊢ + simp only [star_def, reverse_mem_evenOdd_iff, involute_mem_evenOdd_iff, hx₂] + +/-- An element is in `spinGroup Q` if and only if `star x` is in `spinGroup Q`. +See `star_mem` for only one direction. +-/ +@[simp] +theorem star_mem_iff {x : CliffordAlgebra Q} : star x ∈ spinGroup Q ↔ x ∈ spinGroup Q := by + refine ⟨?_, star_mem⟩ + intro hx + convert star_mem hx + exact (star_star x).symm + +instance : Star (spinGroup Q) where + star x := ⟨star x, star_mem x.prop⟩ + +@[simp, norm_cast] +theorem coe_star {x : spinGroup Q} : ↑(star x) = (star x : CliffordAlgebra Q) := + rfl + +theorem coe_star_mul_self (x : spinGroup Q) : (star x : CliffordAlgebra Q) * x = 1 := + star_mul_self_of_mem x.prop + +theorem coe_mul_star_self (x : spinGroup Q) : (x : CliffordAlgebra Q) * star x = 1 := + mul_star_self_of_mem x.prop + +@[simp] +theorem star_mul_self (x : spinGroup Q) : star x * x = 1 := + Subtype.ext <| coe_star_mul_self x + +@[simp] +theorem mul_star_self (x : spinGroup Q) : x * star x = 1 := + Subtype.ext <| coe_mul_star_self x + +/-- `spinGroup Q` forms a group where the inverse is `star`. -/ +instance : Group (spinGroup Q) where + inv := star + inv_mul_cancel := star_mul_self + +instance : StarMul (spinGroup Q) where + star_involutive _ := Subtype.ext <| star_involutive _ + star_mul _ _ := Subtype.ext <| star_mul _ _ + +instance : Inhabited (spinGroup Q) := + ⟨1⟩ + +theorem star_eq_inv (x : spinGroup Q) : star x = x⁻¹ := + rfl + +theorem star_eq_inv' : (star : spinGroup Q → spinGroup Q) = Inv.inv := + rfl + +/-- The elements in `spinGroup Q` embed into (CliffordAlgebra Q)ˣ. -/ +@[simps] +def toUnits : spinGroup Q →* (CliffordAlgebra Q)ˣ where + toFun x := ⟨x, ↑x⁻¹, coe_mul_star_self x, coe_star_mul_self x⟩ + map_one' := Units.ext rfl + map_mul' _x _y := Units.ext rfl + +theorem toUnits_injective : Function.Injective (toUnits : spinGroup Q → (CliffordAlgebra Q)ˣ) := + fun _x _y h => Subtype.ext <| Units.ext_iff.mp h + +end spinGroup + +end Spin 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 c8e7dc428808d..7f631f041c8c3 100644 --- a/Mathlib/LinearAlgebra/DFinsupp.lean +++ b/Mathlib/LinearAlgebra/DFinsupp.lean @@ -299,7 +299,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 ?_ @@ -322,7 +322,7 @@ theorem mem_iSup_iff_exists_dfinsupp' (p : ι → Submodule R N) [∀ (i) (x : p (x : N) : x ∈ iSup p ↔ ∃ f : Π₀ i, p i, (f.sum fun i 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) : @@ -340,7 +340,7 @@ lemma mem_iSup_iff_exists_finsupp (p : ι → Submodule R N) (x : N) : refine ⟨fun ⟨f, hf⟩ ↦ ⟨⟨f.support, fun i ↦ (f i : N), by simp⟩, by simp, hf⟩, ?_⟩ rintro ⟨f, hf, rfl⟩ refine ⟨DFinsupp.mk f.support fun i ↦ ⟨f i, hf i⟩, Finset.sum_congr ?_ fun i hi ↦ ?_⟩ - · ext; simp + · ext; simp [mk_eq_zero] · simp [Finsupp.mem_support_iff.mp hi] theorem mem_iSup_finset_iff_exists_sum {s : Finset ι} (p : ι → Submodule R N) (a : N) : @@ -422,14 +422,15 @@ theorem independent_of_dfinsupp_sumAddHom_injective (p : ι → AddSubmonoid N) rw [← independent_map_orderIso_iff (AddSubmonoid.toNatSubmodule : AddSubmonoid N ≃o _)] exact independent_of_dfinsupp_lsum_injective _ h -/-- Combining `DFinsupp.lsum` with `LinearMap.toSpanSingleton` is the same as `Finsupp.total` -/ +/-- Combining `DFinsupp.lsum` with `LinearMap.toSpanSingleton` is the same as +`Finsupp.linearCombination` -/ theorem lsum_comp_mapRange_toSpanSingleton [∀ m : R, Decidable (m ≠ 0)] (p : ι → Submodule R N) {v : ι → N} (hv : ∀ i : ι, v i ∈ p i) : (lsum ℕ (M := fun i ↦ ↥(p i)) fun i => (p i).subtype : _ →ₗ[R] _).comp ((mapRange.linearMap fun i => LinearMap.toSpanSingleton R (↥(p i)) ⟨v i, hv i⟩ : _ →ₗ[R] _).comp (finsuppLequivDFinsupp R : (ι →₀ R) ≃ₗ[R] _).toLinearMap) = - Finsupp.total ι N R v := by + Finsupp.linearCombination R v := by ext simp diff --git a/Mathlib/LinearAlgebra/Determinant.lean b/Mathlib/LinearAlgebra/Determinant.lean index 984b62e9b92a4..dc9936ab62f2a 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') : 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 3724ba1ee3ccd..9a7b997644973 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] @@ -70,7 +70,7 @@ theorem rank_quotient_add_rank_le [Nontrivial R] (M' : Submodule R M) : refine ciSup_le fun ⟨s, hs⟩ ↦ ciSup_le fun ⟨t, ht⟩ ↦ ?_ choose f hf using Quotient.mk_surjective M' simpa [add_comm] using (LinearIndependent.sum_elim_of_quotient ht (fun (i : s) ↦ f i) - (by simpa [Function.comp, hf] using hs)).cardinal_le_rank + (by simpa [Function.comp_def, hf] using hs)).cardinal_le_rank theorem rank_quotient_le (p : Submodule R M) : Module.rank R (M ⧸ p) ≤ Module.rank R M := (mkQ p).rank_le_of_surjective (surjective_quot_mk _) @@ -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'] @@ -209,7 +209,7 @@ theorem rank_matrix'' (m n : Type u) [Finite m] [Finite n] : open Fintype -namespace FiniteDimensional +namespace Module @[simp] theorem finrank_finsupp {ι : Type v} [Fintype ι] : finrank R (ι →₀ M) = card ι * finrank R M := by @@ -234,7 +234,7 @@ theorem finrank_directSum {ι : Type v} [Fintype ι] (M : ι → Type w) [∀ i theorem finrank_matrix (m n : Type*) [Fintype m] [Fintype n] : finrank R (Matrix m n R) = card m * card n := by simp [finrank] -end FiniteDimensional +end Module end Finsupp @@ -260,13 +260,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 +294,12 @@ 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 +343,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 +352,7 @@ section SubmoduleRank section -open FiniteDimensional +open Module namespace Submodule @@ -372,7 +372,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 +386,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 @@ -402,7 +402,7 @@ section Span variable [StrongRankCondition R] theorem rank_span_le (s : Set M) : Module.rank R (span R s) ≤ #s := by - rw [Finsupp.span_eq_range_total, ← lift_strictMono.le_iff_le] + rw [Finsupp.span_eq_range_linearCombination, ← lift_strictMono.le_iff_le] refine (lift_rank_range_le _).trans ?_ rw [rank_finsupp_self] simp only [lift_lift, le_refl] @@ -413,7 +413,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) diff --git a/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean b/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean index 6b0db8a0b52de..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] @@ -180,9 +180,7 @@ theorem linearIndependent_iff_card_eq_finrank_span {ι : Type*} [Fintype ι] {b simp [f, Set.mem_image, Set.mem_range] rw [hf] at h have hx : (x : V) ∈ span K (Set.range b) := x.property - conv at hx => - arg 2 - rw [h] + simp_rw [h] at hx simpa [f, mem_map] using hx have hi : LinearMap.ker f = ⊥ := ker_subtype _ convert (linearIndependent_of_top_le_span_of_card_eq_finrank hs hc).map' _ hi @@ -249,8 +247,8 @@ theorem max_aleph0_card_le_rank_fun_nat : max ℵ₀ #K ≤ Module.rank K (ℕ contrapose! card_K exact (power_lt_aleph0 card_K <| nat_lt_aleph0 _).le obtain ⟨e⟩ := lift_mk_le'.mp (card_ιL.trans_eq (lift_uzero #ιL).symm) - have rep_e := bK.total_repr (bL ∘ e) - rw [Finsupp.total_apply, Finsupp.sum] at rep_e + have rep_e := bK.linearCombination_repr (bL ∘ e) + rw [Finsupp.linearCombination_apply, Finsupp.sum] at rep_e set c := bK.repr (bL ∘ e) set s := c.support let f i (j : s) : L := ⟨bK j i, Subfield.subset_closure ⟨(j, i), rfl⟩⟩ diff --git a/Mathlib/LinearAlgebra/Dimension/Finite.lean b/Mathlib/LinearAlgebra/Dimension/Finite.lean index 75052d2a62473..90c82db1cfcc3 100644 --- a/Mathlib/LinearAlgebra/Dimension/Finite.lean +++ b/Mathlib/LinearAlgebra/Dimension/Finite.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.Algebra.Module.Torsion import Mathlib.SetTheory.Cardinal.Cofinality @@ -26,7 +26,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) : @@ -48,7 +48,7 @@ lemma rank_eq_zero_iff : rw [← Cardinal.one_le_iff_ne_zero] have : LinearIndependent R (fun _ : Unit ↦ x) := linearIndependent_iff.mpr (fun l hl ↦ Finsupp.unique_ext <| not_not.mp fun H ↦ - hx _ H ((Finsupp.total_unique _ _ _).symm.trans hl)) + hx _ H ((Finsupp.linearCombination_unique _ _ _).symm.trans hl)) simpa using this.cardinal_lift_le_rank · intro h rw [← le_zero_iff, Module.rank_def] @@ -191,15 +191,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)) @@ -214,11 +205,11 @@ lemma exists_finset_linearIndependent_of_le_rank {n : ℕ} (hn : n ≤ Module.ra (Cardinal.bddAbove_range.{v, v} _) _ (h.trans (Module.rank_def R M)).symm have : Finite s := lt_aleph0_iff_finite.mp (hs' ▸ nat_lt_aleph0 n) cases nonempty_fintype s - exact ⟨s.toFinset, by simpa using hs', by convert hs <;> exact Set.mem_toFinset⟩ + exact ⟨s.toFinset, by simpa using hs', by convert hs using 3 <;> exact Set.mem_toFinset⟩ · obtain ⟨s, hs, hs'⟩ := exists_set_linearIndependent_of_lt_rank h have : Finite s := lt_aleph0_iff_finite.mp (hs ▸ nat_lt_aleph0 n) cases nonempty_fintype s - exact ⟨s.toFinset, by simpa using hs, by convert hs' <;> exact Set.mem_toFinset⟩ + exact ⟨s.toFinset, by simpa using hs, by convert hs' using 3 <;> exact Set.mem_toFinset⟩ lemma exists_linearIndependent_of_le_rank {n : ℕ} (hn : n ≤ Module.rank R M) : ∃ f : Fin n → M, LinearIndependent R f := @@ -363,7 +354,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,14 +365,14 @@ 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 (by rw [hn]; exact n.succ_pos) + nontrivial_of_finrank_pos (R := R) (by rw [hn]; exact n.succ_pos) end @@ -398,31 +389,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 +421,14 @@ 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 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] diff --git a/Mathlib/LinearAlgebra/Dimension/Finrank.lean b/Mathlib/LinearAlgebra/Dimension/Finrank.lean index 9bf3954c81775..69668ef8b667a 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 @@ -52,6 +52,8 @@ of `M` over `R`. 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 +94,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 883252149ac34..17254b66084e3 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 := @@ -139,8 +139,10 @@ its span. -/ theorem rank_submodule_eq_one_iff (s : Submodule K V) [Module.Free K s] : Module.rank K s = 1 ↔ ∃ v₀ ∈ s, v₀ ≠ 0 ∧ s ≤ K ∙ v₀ := by simp_rw [rank_eq_one_iff, le_span_singleton_iff] - refine ⟨fun ⟨⟨v₀, hv₀⟩, H, h⟩ ↦ ⟨v₀, hv₀, fun h' ↦ by simp [h'] at H, fun v hv ↦ ?_⟩, - fun ⟨v₀, hv₀, H, h⟩ ↦ ⟨⟨v₀, hv₀⟩, fun h' ↦ H (by simpa using h'), fun ⟨v, hv⟩ ↦ ?_⟩⟩ + refine ⟨fun ⟨⟨v₀, hv₀⟩, H, h⟩ ↦ ⟨v₀, hv₀, fun h' ↦ by + simp only [h', ne_eq] at H; exact H rfl, fun v hv ↦ ?_⟩, + fun ⟨v₀, hv₀, H, h⟩ ↦ ⟨⟨v₀, hv₀⟩, + fun h' ↦ H (by rwa [AddSubmonoid.mk_eq_zero] at h'), fun ⟨v, hv⟩ ↦ ?_⟩⟩ · obtain ⟨r, hr⟩ := h ⟨v, hv⟩ exact ⟨r, by rwa [Subtype.ext_iff, coe_smul] at hr⟩ · obtain ⟨r, hr⟩ := h v hv @@ -184,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 diff --git a/Mathlib/LinearAlgebra/Dimension/LinearMap.lean b/Mathlib/LinearAlgebra/Dimension/LinearMap.lean index 418403e43f094..ca2cb869a8ec5 100644 --- a/Mathlib/LinearAlgebra/Dimension/LinearMap.lean +++ b/Mathlib/LinearAlgebra/Dimension/LinearMap.lean @@ -34,7 +34,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 +46,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 +82,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..b6445fadfe529 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 diff --git a/Mathlib/LinearAlgebra/Dimension/RankNullity.lean b/Mathlib/LinearAlgebra/Dimension/RankNullity.lean index 39b863dc84a22..2e6cb6ba25096 100644 --- a/Mathlib/LinearAlgebra/Dimension/RankNullity.lean +++ b/Mathlib/LinearAlgebra/Dimension/RankNullity.lean @@ -104,7 +104,7 @@ theorem exists_linearIndependent_of_lt_rank [StrongRankCondition R] ← rank_quotient_add_rank (Submodule.span R s), add_comm, rank_span_set hs] exact HasLeftInverse.injective ⟨Submodule.Quotient.mk, hsec⟩ · apply LinearIndependent.union_of_quotient Submodule.subset_span hs - rwa [Function.comp, linearIndependent_image (hsec'.symm ▸ injective_id).injOn.image_of_comp, + rwa [Function.comp_def, linearIndependent_image (hsec'.symm ▸ injective_id).injOn.image_of_comp, ← image_comp, hsec', image_id] /-- Given a family of `n` linearly independent vectors in a space of dimension `> n`, one may extend @@ -136,7 +136,7 @@ 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⟩ @@ -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] diff --git a/Mathlib/LinearAlgebra/Dimension/StrongRankCondition.lean b/Mathlib/LinearAlgebra/Dimension/StrongRankCondition.lean index ea4d5b81f1804..26dc00965d15b 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 @@ -106,10 +106,10 @@ theorem Basis.le_span'' {ι : Type*} [Fintype ι] (b : Basis ι R M) {w : Set M} -- We construct a surjective linear map `(w → R) →ₗ[R] (ι → R)`, -- by expressing a linear combination in `w` as a linear combination in `ι`. fapply card_le_of_surjective' R - · exact b.repr.toLinearMap.comp (Finsupp.total w M R (↑)) + · exact b.repr.toLinearMap.comp (Finsupp.linearCombination R (↑)) · apply Surjective.comp (g := b.repr.toLinearMap) · apply LinearEquiv.surjective - rw [← LinearMap.range_eq_top, Finsupp.range_total] + rw [← LinearMap.range_eq_top, Finsupp.range_linearCombination] simpa using s /-- @@ -162,7 +162,7 @@ section StrongRankCondition variable [StrongRankCondition R] -open Submodule +open Submodule Finsupp -- An auxiliary lemma for `linearIndependent_le_span'`, -- with the additional assumption that the linearly independent family is finite. @@ -174,11 +174,12 @@ theorem linearIndependent_le_span_aux' {ι : Type*} [Fintype ι] (v : ι → M) -- and expressing that (using the axiom of choice) as a linear combination over `w`. -- We can do this linearly by constructing the map on a basis. fapply card_le_of_injective' R - · apply Finsupp.total + · apply Finsupp.linearCombination exact fun i => Span.repr R w ⟨v i, s (mem_range_self i)⟩ · intro f g h - apply_fun Finsupp.total w M R (↑) at h - simp only [Finsupp.total_total, Submodule.coe_mk, Span.finsupp_total_repr] at h + apply_fun linearCombination R ((↑) : w → M) at h + simp only [linearCombination_linearCombination, Submodule.coe_mk, + Span.finsupp_linearCombination_repr] at h rw [← sub_eq_zero, ← LinearMap.map_sub] at h exact sub_eq_zero.mp (linearIndependent_iff.mp i _ h) @@ -375,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) : @@ -391,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] @@ -401,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] @@ -414,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) @@ -435,19 +430,23 @@ 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)] + +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/Finsupp.lean b/Mathlib/LinearAlgebra/DirectSum/Finsupp.lean index 3265071dd5bad..6facf782974d3 100644 --- a/Mathlib/LinearAlgebra/DirectSum/Finsupp.lean +++ b/Mathlib/LinearAlgebra/DirectSum/Finsupp.lean @@ -205,7 +205,7 @@ lemma finsuppScalarLeft_symm_apply_single (i : ι) (n : N) : variable (R M N ι) -/-- The tensor product of `M` and `ι →₀ R` is linearly equivalent to `ι →₀ N` -/ +/-- The tensor product of `M` and `ι →₀ R` is linearly equivalent to `ι →₀ M` -/ noncomputable def finsuppScalarRight : M ⊗[R] (ι →₀ R) ≃ₗ[R] ι →₀ M := finsuppRight R M R ι ≪≫ₗ Finsupp.mapRange.linearEquiv (TensorProduct.rid R M) diff --git a/Mathlib/LinearAlgebra/Dual.lean b/Mathlib/LinearAlgebra/Dual.lean index 1a73c224e14a7..5d556906e958a 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 := @@ -280,29 +282,34 @@ theorem toDual_apply (i j : ι) : b.toDual (b i) (b j) = if i = j then 1 else 0 simp only [eq_comm] @[simp] -theorem toDual_total_left (f : ι →₀ R) (i : ι) : - b.toDual (Finsupp.total ι M R b f) (b i) = f i := by - rw [Finsupp.total_apply, Finsupp.sum, _root_.map_sum, LinearMap.sum_apply] +theorem toDual_linearCombination_left (f : ι →₀ R) (i : ι) : + b.toDual (Finsupp.linearCombination R b f) (b i) = f i := by + rw [Finsupp.linearCombination_apply, Finsupp.sum, _root_.map_sum, LinearMap.sum_apply] simp_rw [LinearMap.map_smul, LinearMap.smul_apply, toDual_apply, smul_eq_mul, mul_boole, Finset.sum_ite_eq'] split_ifs with h · rfl · rw [Finsupp.not_mem_support_iff.mp h] +@[deprecated (since := "2024-08-29")] alias toDual_total_left := toDual_linearCombination_left + @[simp] -theorem toDual_total_right (f : ι →₀ R) (i : ι) : - b.toDual (b i) (Finsupp.total ι M R b f) = f i := by - rw [Finsupp.total_apply, Finsupp.sum, _root_.map_sum] +theorem toDual_linearCombination_right (f : ι →₀ R) (i : ι) : + b.toDual (b i) (Finsupp.linearCombination R b f) = f i := by + rw [Finsupp.linearCombination_apply, Finsupp.sum, _root_.map_sum] simp_rw [LinearMap.map_smul, toDual_apply, smul_eq_mul, mul_boole, Finset.sum_ite_eq] split_ifs with h · rfl · rw [Finsupp.not_mem_support_iff.mp h] +@[deprecated (since := "2024-08-29")] alias toDual_total_right := + toDual_linearCombination_right + theorem toDual_apply_left (m : M) (i : ι) : b.toDual m (b i) = b.repr m i := by - rw [← b.toDual_total_left, b.total_repr] + rw [← b.toDual_linearCombination_left, b.linearCombination_repr] theorem toDual_apply_right (i : ι) (m : M) : b.toDual (b i) m = b.repr m i := by - rw [← b.toDual_total_right, b.total_repr] + rw [← b.toDual_linearCombination_right, b.linearCombination_repr] theorem coe_toDual_self (i : ι) : b.toDual (b i) = b.coord i := by ext @@ -335,8 +342,8 @@ theorem toDual_ker : LinearMap.ker b.toDual = ⊥ := theorem toDual_range [Finite ι] : LinearMap.range b.toDual = ⊤ := by refine eq_top_iff'.2 fun f => ?_ let lin_comb : ι →₀ R := Finsupp.equivFunOnFinite.symm fun i => f (b i) - refine ⟨Finsupp.total ι M R b lin_comb, b.ext fun i => ?_⟩ - rw [b.toDual_eq_repr _ i, repr_total b] + refine ⟨Finsupp.linearCombination R b lin_comb, b.ext fun i => ?_⟩ + rw [b.toDual_eq_repr _ i, repr_linearCombination b] rfl end CommSemiring @@ -379,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 @@ -395,17 +402,19 @@ theorem dualBasis_apply_self (i j : ι) : b.dualBasis i (b j) = convert b.toDual_apply i j using 2 rw [@eq_comm _ j i] -theorem total_dualBasis (f : ι →₀ R) (i : ι) : - Finsupp.total ι (Dual R M) R b.dualBasis f (b i) = f i := by +theorem linearCombination_dualBasis (f : ι →₀ R) (i : ι) : + Finsupp.linearCombination R b.dualBasis f (b i) = f i := by cases nonempty_fintype ι - rw [Finsupp.total_apply, Finsupp.sum_fintype, LinearMap.sum_apply] + rw [Finsupp.linearCombination_apply, Finsupp.sum_fintype, LinearMap.sum_apply] · simp_rw [LinearMap.smul_apply, smul_eq_mul, dualBasis_apply_self, mul_boole, Finset.sum_ite_eq, if_pos (Finset.mem_univ i)] · intro rw [zero_smul] +@[deprecated (since := "2024-08-29")] alias total_dualBasis := linearCombination_dualBasis + theorem dualBasis_repr (l : Dual R M) (i : ι) : b.dualBasis.repr l i = l (b i) := by - rw [← total_dualBasis b, Basis.total_repr b.dualBasis l] + rw [← linearCombination_dualBasis b, Basis.linearCombination_repr b.dualBasis l] theorem dualBasis_apply (i : ι) (m : M) : b.dualBasis i m = b.repr m i := b.toDual_apply_right i m @@ -442,24 +451,26 @@ 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 end CommRing -/-- `simp` normal form version of `total_dualBasis` -/ +/-- `simp` normal form version of `linearCombination_dualBasis` -/ @[simp] -theorem total_coord [CommRing R] [AddCommGroup M] [Module R M] [Finite ι] (b : Basis ι R M) - (f : ι →₀ R) (i : ι) : Finsupp.total ι (Dual R M) R b.coord f (b i) = f i := by +theorem linearCombination_coord [CommRing R] [AddCommGroup M] [Module R M] [Finite ι] + (b : Basis ι R M) (f : ι →₀ R) (i : ι) : Finsupp.linearCombination R b.coord f (b i) = f i := by haveI := Classical.decEq ι - rw [← coe_dualBasis, total_dualBasis] + rw [← coe_dualBasis, linearCombination_dualBasis] + +@[deprecated (since := "2024-08-29")] alias total_coord := linearCombination_coord theorem dual_rank_eq [CommRing K] [AddCommGroup V] [Module K V] [Finite ι] (b : Basis ι K V) : Cardinal.lift.{uK,uV} (Module.rank K V) = Module.rank K (Dual K V) := by @@ -473,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 @@ -531,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 @@ -569,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⟩ @@ -639,6 +651,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 @@ -662,6 +690,47 @@ 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'⟩ +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 @@ -669,7 +738,7 @@ section DualBases open Module variable {R M ι : Type*} -variable [CommSemiring R] [AddCommMonoid M] [Module R M] [DecidableEq ι] +variable [CommSemiring R] [AddCommMonoid M] [Module R M] -- Porting note: replace use_finite_instance tactic open Lean.Elab.Tactic in @@ -682,10 +751,10 @@ elab "use_finite_instance" : tactic => evalUseFiniteInstance /-- `e` and `ε` have characteristic properties of a basis and its dual -/ -- @[nolint has_nonempty_instance] Porting note (#5171): removed structure Module.DualBases (e : ι → M) (ε : ι → Dual R M) : Prop where - eval : ∀ i j : ι, ε i (e j) = if i = j then 1 else 0 + eval_same : ∀ i, ε i (e i) = 1 + eval_of_ne : Pairwise fun i j ↦ ε i (e j) = 0 protected total : ∀ {m : M}, (∀ i, ε i m = 0) → m = 0 - protected finite : ∀ m : M, { i | ε i m ≠ 0 }.Finite := by - use_finite_instance + protected finite : ∀ m : M, {i | ε i m ≠ 0}.Finite := by use_finite_instance end DualBases @@ -698,35 +767,35 @@ variable [CommRing R] [AddCommGroup M] [Module R M] variable {e : ι → M} {ε : ι → Dual R M} /-- The coefficients of `v` on the basis `e` -/ -def coeffs [DecidableEq ι] (h : DualBases e ε) (m : M) : ι →₀ R where +def coeffs (h : DualBases e ε) (m : M) : ι →₀ R where toFun i := ε i m support := (h.finite m).toFinset mem_support_toFun i := by rw [Set.Finite.mem_toFinset, Set.mem_setOf_eq] @[simp] -theorem coeffs_apply [DecidableEq ι] (h : DualBases e ε) (m : M) (i : ι) : h.coeffs m i = ε i m := +theorem coeffs_apply (h : DualBases e ε) (m : M) (i : ι) : h.coeffs m i = ε i m := rfl /-- linear combinations of elements of `e`. -This is a convenient abbreviation for `Finsupp.total _ M R e l` -/ +This is a convenient abbreviation for `Finsupp.linearCombination R e l` -/ def lc {ι} (e : ι → M) (l : ι →₀ R) : M := l.sum fun (i : ι) (a : R) => a • e i -theorem lc_def (e : ι → M) (l : ι →₀ R) : lc e l = Finsupp.total _ _ R e l := +theorem lc_def (e : ι → M) (l : ι →₀ R) : lc e l = Finsupp.linearCombination R e l := rfl open Module -variable [DecidableEq ι] (h : DualBases e ε) +variable (h : DualBases e ε) include h theorem dual_lc (l : ι →₀ R) (i : ι) : ε i (DualBases.lc e l) = l i := by rw [lc, _root_.map_finsupp_sum, Finsupp.sum_eq_single i (g := fun a b ↦ (ε i) (b • e a))] -- Porting note: cannot get at • -- simp only [h.eval, map_smul, smul_eq_mul] - · simp [h.eval, smul_eq_mul] + · simp [h.eval_same, smul_eq_mul] · intro q _ q_ne - simp [q_ne.symm, h.eval, smul_eq_mul] + simp [h.eval_of_ne q_ne.symm, smul_eq_mul] · simp @[simp] @@ -741,7 +810,7 @@ theorem lc_coeffs (m : M) : DualBases.lc e (h.coeffs m) = m := by simp [LinearMap.map_sub, h.dual_lc, sub_eq_zero] /-- `(h : DualBases e ε).basis` shows the family of vectors `e` forms a basis. -/ -@[simps] +@[simps repr_apply, simps (config := .lemmasOnly) repr_symm_apply] def basis : Basis ι R M := Basis.ofRepr { toFun := coeffs h @@ -755,30 +824,24 @@ def basis : Basis ι R M := ext i exact (ε i).map_smul c v } --- Porting note: from simpNF the LHS simplifies; it yields lc_def.symm --- probably not a useful simp lemma; nolint simpNF since it cannot see this removal -attribute [-simp, nolint simpNF] basis_repr_symm_apply - @[simp] theorem coe_basis : ⇑h.basis = e := by ext i rw [Basis.apply_eq_iff] ext j - rw [h.basis_repr_apply, coeffs_apply, h.eval, Finsupp.single_apply] - convert if_congr (eq_comm (a := j) (b := i)) rfl rfl + rcases eq_or_ne i j with rfl | hne + · simp [h.eval_same] + · simp [hne, h.eval_of_ne hne.symm] --- `convert` to get rid of a `DecidableEq` mismatch theorem mem_of_mem_span {H : Set ι} {x : M} (hmem : x ∈ Submodule.span R (e '' H)) : ∀ i : ι, ε i x ≠ 0 → i ∈ H := by intro i hi - rcases (Finsupp.mem_span_image_iff_total _).mp hmem with ⟨l, supp_l, rfl⟩ + rcases (Finsupp.mem_span_image_iff_linearCombination _).mp hmem with ⟨l, supp_l, rfl⟩ apply not_imp_comm.mp ((Finsupp.mem_supported' _ _).mp supp_l i) rwa [← lc_def, h.dual_lc] at hi -theorem coe_dualBasis [_root_.Finite ι] : ⇑h.basis.dualBasis = ε := - funext fun i => - h.basis.ext fun j => by - rw [h.basis.dualBasis_apply_self, h.coe_basis, h.eval, if_congr eq_comm rfl rfl] +theorem coe_dualBasis [DecidableEq ι] [_root_.Finite ι] : ⇑h.basis.dualBasis = ε := + funext fun i => h.basis.ext fun j => by simp end Module.DualBases @@ -1054,7 +1117,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 @@ -1076,7 +1139,7 @@ theorem dualAnnihilator_dualAnnihilator_eq (W : Subspace K V) : rw [dualCoannihilator, ← Module.mapEvalEquiv_symm_apply] at this rwa [← OrderIso.symm_apply_eq] -/-- The quotient by the dual is isomorphic to its dual annihilator. -/ +/-- The quotient by the dual is isomorphic to its dual annihilator. -/ -- Porting note (#11036): broken dot notation lean4#1910 LinearMap.range noncomputable def quotDualEquivAnnihilator (W : Subspace K V) : (Module.Dual K V ⧸ LinearMap.range W.dualLift) ≃ₗ[K] W.dualAnnihilator := @@ -1093,7 +1156,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)} : @@ -1161,12 +1224,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 [Function.funext_iff] at h + exact h _ @[simp] theorem dualCopairing_apply {W : Submodule R M} (φ : W.dualAnnihilator) (x : M) : @@ -1228,7 +1291,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 @@ -1321,7 +1384,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 : @@ -1476,7 +1538,7 @@ end Subspace section FiniteDimensional -open FiniteDimensional LinearMap +open Module LinearMap namespace LinearMap @@ -1607,7 +1669,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 @@ -1744,3 +1806,5 @@ noncomputable def dualDistribEquiv : Dual R M ⊗[R] Dual R N ≃ₗ[R] Dual R ( dualDistribEquivOfBasis (Module.Free.chooseBasis R M) (Module.Free.chooseBasis R N) end TensorProduct + +set_option linter.style.longFile 1900 diff --git a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean index adad04b9bf8f0..e2e7aa9fcb4c9 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean @@ -53,211 +53,530 @@ 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 `unifEigenspace f μ k` for a linear map `f`, a scalar `μ`, +and a number `k : ℕ∞` is the kernel of `(f - μ • id) ^ k` if `k` is a natural number, +or the union of all these kernels if `k = ∞`. -/ +def unifEigenspace (f : End R M) (μ : R) : ℕ∞ →o Submodule R M where + toFun k := ⨆ l : ℕ, ⨆ _ : l ≤ k, LinearMap.ker ((f - μ • 1) ^ l) + monotone' _ _ hkl := biSup_mono fun _ hi ↦ hi.trans hkl + +lemma mem_unifEigenspace {f : End R M} {μ : R} {k : ℕ∞} {x : M} : + x ∈ f.unifEigenspace μ k ↔ ∃ l : ℕ, l ≤ k ∧ x ∈ LinearMap.ker ((f - μ • 1) ^ l) := by + have : Nonempty {l : ℕ // l ≤ k} := ⟨⟨0, zero_le _⟩⟩ + have : Directed (ι := { i : ℕ // i ≤ k }) (· ≤ ·) fun i ↦ LinearMap.ker ((f - μ • 1) ^ (i : ℕ)) := + Monotone.directed_le fun m n h ↦ by simpa using (f - μ • 1).iterateKer.monotone h + simp_rw [unifEigenspace, OrderHom.coe_mk, LinearMap.mem_ker, iSup_subtype', + Submodule.mem_iSup_of_directed _ this, LinearMap.mem_ker, Subtype.exists, exists_prop] + +lemma unifEigenspace_directed {f : End R M} {μ : R} {k : ℕ∞} : + Directed (· ≤ ·) (fun l : {l : ℕ // l ≤ k} ↦ f.unifEigenspace μ l) := by + have aux : Monotone ((↑) : {l : ℕ // l ≤ k} → ℕ∞) := fun x y h ↦ by simpa using h + exact ((unifEigenspace f μ).monotone.comp aux).directed_le + +lemma mem_unifEigenspace_nat {f : End R M} {μ : R} {k : ℕ} {x : M} : + x ∈ f.unifEigenspace μ k ↔ x ∈ LinearMap.ker ((f - μ • 1) ^ k) := by + rw [mem_unifEigenspace] + 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_unifEigenspace_top {f : End R M} {μ : R} {x : M} : + x ∈ f.unifEigenspace μ ⊤ ↔ ∃ k : ℕ, x ∈ LinearMap.ker ((f - μ • 1) ^ k) := by + simp [mem_unifEigenspace] + +lemma unifEigenspace_nat {f : End R M} {μ : R} {k : ℕ} : + f.unifEigenspace μ k = LinearMap.ker ((f - μ • 1) ^ k) := by + ext; simp [mem_unifEigenspace_nat] + +lemma unifEigenspace_eq_iSup_unifEigenspace_nat (f : End R M) (μ : R) (k : ℕ∞) : + f.unifEigenspace μ k = ⨆ l : {l : ℕ // l ≤ k}, f.unifEigenspace μ l := by + simp_rw [unifEigenspace_nat, unifEigenspace, OrderHom.coe_mk, iSup_subtype] + +lemma unifEigenspace_top (f : End R M) (μ : R) : + f.unifEigenspace μ ⊤ = ⨆ k : ℕ, f.unifEigenspace μ k := by + rw [unifEigenspace_eq_iSup_unifEigenspace_nat, iSup_subtype] + simp only [le_top, iSup_pos, OrderHom.coe_mk] + +lemma unifEigenspace_one {f : End R M} {μ : R} : + f.unifEigenspace μ 1 = LinearMap.ker (f - μ • 1) := by + rw [← Nat.cast_one, unifEigenspace_nat, pow_one] + +@[simp] +lemma mem_unifEigenspace_one {f : End R M} {μ : R} {x : M} : + x ∈ f.unifEigenspace μ 1 ↔ f x = μ • x := by + rw [unifEigenspace_one, LinearMap.mem_ker, LinearMap.sub_apply, + sub_eq_zero, LinearMap.smul_apply, LinearMap.one_apply] + +-- `simp` can prove this using `unifEigenspace_zero` +lemma mem_unifEigenspace_zero {f : End R M} {μ : R} {x : M} : + x ∈ f.unifEigenspace μ 0 ↔ x = 0 := by + rw [← Nat.cast_zero, mem_unifEigenspace_nat, pow_zero, LinearMap.mem_ker, LinearMap.one_apply] + +@[simp] +lemma unifEigenspace_zero {f : End R M} {μ : R} : + f.unifEigenspace μ 0 = ⊥ := by + ext; apply mem_unifEigenspace_zero + +@[simp] +lemma unifEigenspace_zero_nat (f : End R M) (k : ℕ) : + f.unifEigenspace 0 k = LinearMap.ker (f ^ k) := by + ext; simp [mem_unifEigenspace_nat] + +/-- Let `M` be an `R`-module, and `f` an `R`-linear endomorphism of `M`, +and let `μ : R` and `k : ℕ∞` be given. +Then `x : M` satisfies `HasUnifEigenvector f μ k x` if +`x ∈ f.unifEigenspace μ k` and `x ≠ 0`. + +For `k = 1`, this means that `x` is an eigenvector of `f` with eigenvalue `μ`. -/ +def HasUnifEigenvector (f : End R M) (μ : R) (k : ℕ∞) (x : M) : Prop := + x ∈ f.unifEigenspace μ k ∧ x ≠ 0 + +/-- Let `M` be an `R`-module, and `f` an `R`-linear endomorphism of `M`. +Then `μ : R` and `k : ℕ∞` satisfy `HasUnifEigenvalue f μ k` if +`f.unifEigenspace μ k ≠ ⊥`. + +For `k = 1`, this means that `μ` is an eigenvalue of `f`. -/ +def HasUnifEigenvalue (f : End R M) (μ : R) (k : ℕ∞) : Prop := + f.unifEigenspace μ 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_unifEigenspace_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_unifEigenspace_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, unifEigenspace_one, ne_eq, not_iff_not] + simp [Submodule.ext_iff, LinearMap.mem_ker] + +alias ⟨_, HasUnifEigenvalue.of_mem_spectrum⟩ := hasUnifEigenvalue_iff_mem_spectrum + +lemma unifEigenspace_div (f : End K V) (a b : K) (hb : b ≠ 0) : + unifEigenspace f (a / b) 1 = LinearMap.ker (b • f - a • 1) := + calc + unifEigenspace f (a / b) 1 = unifEigenspace f (b⁻¹ * a) 1 := by rw [div_eq_mul_inv, mul_comm] + _ = LinearMap.ker (f - (b⁻¹ * a) • 1) := by rw [unifEigenspace_one] + _ = 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 unifEigenrange (f : End R M) (μ : R) (k : ℕ∞) : Submodule R M := + ⨅ l : ℕ, ⨅ (_ : l ≤ k), LinearMap.range ((f - μ • 1) ^ l) + +lemma unifEigenrange_nat {f : End R M} {μ : R} {k : ℕ} : + f.unifEigenrange μ k = LinearMap.range ((f - μ • 1) ^ k) := by + ext x + simp only [unifEigenrange, 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, unifEigenspace_zero] at h + +/-- If there exists a natural number `k` such that the kernel of `(f - μ • id) ^ k` is the +maximal generalized eigenspace, then this value is the least such `k`. If not, this value is not +meaningful. -/ +noncomputable def maxUnifEigenspaceIndex (f : End R M) (μ : R) := + monotonicSequenceLimitIndex <| (f.unifEigenspace μ).comp <| WithTop.coeOrderHom.toOrderHom + +/-- For an endomorphism of a Noetherian module, the maximal eigenspace is always of the form kernel +`(f - μ • id) ^ k` for some `k`. -/ +lemma unifEigenspace_top_eq_maxUnifEigenspaceIndex [h : IsNoetherian R M] (f : End R M) (μ : R) : + unifEigenspace f μ ⊤ = f.unifEigenspace μ (maxUnifEigenspaceIndex f μ) := by + rw [isNoetherian_iff] at h + have := WellFounded.iSup_eq_monotonicSequenceLimit h <| + (f.unifEigenspace μ).comp <| WithTop.coeOrderHom.toOrderHom + convert this using 1 + simp only [unifEigenspace, OrderHom.coe_mk, le_top, iSup_pos, OrderHom.comp_coe, + Function.comp_def] + rw [iSup_prod', iSup_subtype', ← sSup_range, ← sSup_range] + congr + aesop + +lemma unifEigenspace_le_unifEigenspace_maxUnifEigenspaceIndex [IsNoetherian R M] (f : End R M) + (μ : R) (k : ℕ∞) : + f.unifEigenspace μ k ≤ f.unifEigenspace μ (maxUnifEigenspaceIndex f μ) := by + rw [← unifEigenspace_top_eq_maxUnifEigenspaceIndex] + exact (f.unifEigenspace μ).monotone le_top + +/-- Generalized eigenspaces for exponents at least `finrank K V` are equal to each other. -/ +theorem unifEigenspace_eq_unifEigenspace_maxUnifEigenspaceIndex_of_le [IsNoetherian R M] + (f : End R M) (μ : R) {k : ℕ} (hk : maxUnifEigenspaceIndex f μ ≤ k) : + f.unifEigenspace μ k = f.unifEigenspace μ (maxUnifEigenspaceIndex f μ) := + le_antisymm + (unifEigenspace_le_unifEigenspace_maxUnifEigenspaceIndex _ _ _) + ((f.unifEigenspace μ).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.unifEigenspace _).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 [unifEigenspace_one, LinearMap.ker_eq_bot] at contra + rw [eq_bot_iff] + intro x hx + rw [mem_unifEigenspace] 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.unifEigenspace μ).monotone <| WithTop.coeOrderHom.monotone hn + · show (f.unifEigenspace μ) n ≤ (f.unifEigenspace μ) (finrank K V) + rw [unifEigenspace_nat, unifEigenspace_nat] + apply ker_pow_le_ker_pow_finrank + +/-- Every generalized eigenvector is a generalized eigenvector for exponent `finrank K V`. + (Lemma 8.11 of [axler2015]) -/ +lemma unifEigenspace_le_unifEigenspace_finrank [FiniteDimensional K V] (f : End K V) + (μ : K) (k : ℕ∞) : f.unifEigenspace μ k ≤ f.unifEigenspace μ (finrank K V) := by + calc f.unifEigenspace μ k + ≤ f.unifEigenspace μ ⊤ := (f.unifEigenspace _).monotone le_top + _ ≤ f.unifEigenspace μ (finrank K V) := by + rw [unifEigenspace_top_eq_maxUnifEigenspaceIndex] + exact (f.unifEigenspace _).monotone <| by simpa using maxUnifEigenspaceIndex_le_finrank f μ + +/-- Generalized eigenspaces for exponents at least `finrank K V` are equal to each other. -/ +theorem unifEigenspace_eq_unifEigenspace_finrank_of_le [FiniteDimensional K V] + (f : End K V) (μ : K) {k : ℕ} (hk : finrank K V ≤ k) : + f.unifEigenspace μ k = f.unifEigenspace μ (finrank K V) := + le_antisymm + (unifEigenspace_le_unifEigenspace_finrank _ _ _) + ((f.unifEigenspace μ).monotone <| by simpa using hk) + +lemma mapsTo_unifEigenspace_of_comm {f g : End R M} (h : Commute f g) (μ : R) (k : ℕ∞) : + MapsTo g (f.unifEigenspace μ k) (f.unifEigenspace μ k) := by + intro x hx + simp only [SetLike.mem_coe, mem_unifEigenspace, 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_unifEigenspace_nat (f : End R M) (μ : R) (k : ℕ) + (h : MapsTo (f - μ • (1 : End R M)) + (f.unifEigenspace μ k) (f.unifEigenspace μ k) := + mapsTo_unifEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ) μ k) : + IsNilpotent ((f - μ • 1).restrict h) := by + use k + ext ⟨x, hx⟩ + rw [mem_unifEigenspace_nat] at hx + rw [LinearMap.zero_apply, ZeroMemClass.coe_zero, ZeroMemClass.coe_eq_zero, + LinearMap.pow_restrict, LinearMap.restrict_apply] + ext + simpa + +/-- The restriction of `f - μ • 1` to the generalized `μ`-eigenspace is nilpotent. -/ +lemma isNilpotent_restrict_unifEigenspace_top [IsNoetherian R M] (f : End R M) (μ : R) + (h : MapsTo (f - μ • (1 : End R M)) + (f.unifEigenspace μ ⊤) (f.unifEigenspace μ ⊤) := + mapsTo_unifEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ) μ _) : + IsNilpotent ((f - μ • 1).restrict h) := by + apply isNilpotent_restrict_of_le + swap; apply isNilpotent_restrict_unifEigenspace_nat f μ (maxUnifEigenspaceIndex f μ) + rw [unifEigenspace_top_eq_maxUnifEigenspaceIndex] + /-- 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.unifEigenspace μ 1 + +lemma eigenspace_def {f : End R M} {μ : R} : + f.eigenspace μ = LinearMap.ker (f - μ • 1) := by + rw [eigenspace, unifEigenspace_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 := ℕ∞), unifEigenspace_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_unifEigenspace_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] + unifEigenspace_div f a b hb /-- The generalized eigenspace for a linear map `f`, a scalar `μ`, and an exponent `k ∈ ℕ` is the kernel of `(f - μ • id) ^ k`. (Def 8.10 of [axler2015]). Furthermore, a generalized eigenspace for some exponent `k` is contained in the generalized eigenspace for exponents larger than `k`. -/ def genEigenspace (f : End R M) (μ : R) : ℕ →o Submodule R M where - toFun k := 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)) + toFun k := f.unifEigenspace μ k + monotone' k l hkl := (f.unifEigenspace μ).monotone <| by simpa + +lemma genEigenspace_def (f : End R M) (μ : R) (k : ℕ) : + f.genEigenspace μ k = LinearMap.ker ((f - μ • 1) ^ k) := by + rw [genEigenspace, OrderHom.coe_mk, unifEigenspace_nat] @[simp] theorem mem_genEigenspace (f : End R M) (μ : R) (k : ℕ) (m : M) : - m ∈ f.genEigenspace μ k ↔ ((f - μ • (1 : End R M)) ^ k) m = 0 := Iff.rfl + m ∈ f.genEigenspace μ k ↔ ((f - μ • (1 : End R M)) ^ k) m = 0 := + mem_unifEigenspace_nat @[simp] theorem genEigenspace_zero (f : End R M) (k : ℕ) : - f.genEigenspace 0 k = LinearMap.ker (f ^ k) := by - simp [Module.End.genEigenspace] + f.genEigenspace 0 k = LinearMap.ker (f ^ k) := + unifEigenspace_zero_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) +abbrev genEigenrange (f : End R M) (μ : R) (k : ℕ) : Submodule R M := + unifEigenrange f μ k + +lemma genEigenrange_def {f : End R M} {μ : R} {k : ℕ} : + f.genEigenrange μ k = LinearMap.range ((f - μ • 1) ^ k) := by + rw [genEigenrange, unifEigenrange_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 := + unifEigenspace f μ ⊤ + +lemma maxGenEigenspace_def (f : End R M) (μ : R) : + f.maxGenEigenspace μ = ⨆ k, f.genEigenspace μ k := by + simp_rw [maxGenEigenspace, unifEigenspace_top, genEigenspace, OrderHom.coe_mk] theorem genEigenspace_le_maximal (f : End R M) (μ : R) (k : ℕ) : f.genEigenspace μ k ≤ f.maxGenEigenspace μ := - le_iSup _ _ + (f.unifEigenspace μ).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_unifEigenspace_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) : - maxGenEigenspace f μ = - f.genEigenspace μ (maxGenEigenspaceIndex f μ) := by - rw [isNoetherian_iff_wellFounded] at h - exact (WellFounded.iSup_eq_monotonicSequenceLimit h (f.genEigenspace μ) : _) +theorem maxGenEigenspace_eq [IsNoetherian R M] (f : End R M) (μ : R) : + maxGenEigenspace f μ = f.genEigenspace μ (maxGenEigenspaceIndex f μ) := + unifEigenspace_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.unifEigenspace _).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 _ _ + unifEigenspace_le_unifEigenspace_finrank _ _ _ @[simp] theorem iSup_genEigenspace_eq_genEigenspace_finrank [FiniteDimensional K V] (f : End K V) (μ : K) : @@ -268,7 +587,7 @@ theorem genEigenspace_le_genEigenspace_finrank [FiniteDimensional K V] (f : End 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 + unifEigenspace_eq_unifEigenspace_finrank_of_le f μ hk lemma mapsTo_genEigenspace_of_comm {f g : End R M} (h : Commute f g) (μ : R) (k : ℕ) : MapsTo g (f.genEigenspace μ k) (f.genEigenspace μ k) := by @@ -279,21 +598,43 @@ lemma mapsTo_genEigenspace_of_comm {f g : End R M} (h : Commute f g) (μ : R) (k rw [← LinearMap.comp_apply, ← LinearMap.mul_eq_comp, h.eq, LinearMap.mul_eq_comp, LinearMap.comp_apply, hx, map_zero] -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 +lemma iSup_genEigenspace_eq (f : End R M) (μ : R) : + ⨆ k, (f.genEigenspace μ) k = f.unifEigenspace μ ⊤ := by + rw [unifEigenspace_eq_iSup_unifEigenspace_nat] + ext + simp only [iSup_subtype, le_top, iSup_pos] + rfl + +lemma mapsTo_maxGenEigenspace_of_comm {f g : End R M} (h : Commute f g) (μ : R) : + MapsTo g ↑(f.maxGenEigenspace μ) ↑(f.maxGenEigenspace μ) := by + rw [maxGenEigenspace_def] simp only [MapsTo, Submodule.coe_iSup_of_chain, mem_iUnion, SetLike.mem_coe] rintro x ⟨k, hk⟩ exact ⟨k, f.mapsTo_genEigenspace_of_comm h μ k hk⟩ +lemma mapsTo_iSup_genEigenspace_of_comm {f g : End R M} (h : Commute f g) (μ : R) : + MapsTo g ↑(⨆ k, f.genEigenspace μ k) ↑(⨆ k, f.genEigenspace μ k) := by + rw [← maxGenEigenspace_def] + 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_unifEigenspace_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.unifEigenspace μ (maxUnifEigenspaceIndex f μ)) + _ (isNilpotent_restrict_unifEigenspace_nat f μ (maxUnifEigenspaceIndex f μ)) + rw [maxGenEigenspace_eq] + exact le_rfl /-- The restriction of `f - μ • 1` to the generalized `μ`-eigenspace is nilpotent. -/ lemma isNilpotent_restrict_iSup_sub_algebraMap [IsNoetherian R M] (f : End R M) (μ : R) @@ -301,42 +642,53 @@ lemma isNilpotent_restrict_iSup_sub_algebraMap [IsNoetherian R M] (f : End R M) ↑(⨆ 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 - -lemma disjoint_genEigenspace [NoZeroSMulDivisors R M] - (f : End R M) {μ₁ μ₂ : R} (hμ : μ₁ ≠ μ₂) (k l : ℕ) : - Disjoint (f.genEigenspace μ₁ k) (f.genEigenspace μ₂ l) := by + apply isNilpotent_restrict_of_le (q := f.unifEigenspace μ (maxUnifEigenspaceIndex f μ)) + _ (isNilpotent_restrict_unifEigenspace_nat f μ (maxUnifEigenspaceIndex f μ)) + apply iSup_le + intro k + apply unifEigenspace_le_unifEigenspace_maxUnifEigenspaceIndex + +lemma disjoint_unifEigenspace [NoZeroSMulDivisors R M] + (f : End R M) {μ₁ μ₂ : R} (hμ : μ₁ ≠ μ₂) (k l : ℕ∞) : + Disjoint (f.unifEigenspace μ₁ k) (f.unifEigenspace μ₂ l) := by + rw [unifEigenspace_eq_iSup_unifEigenspace_nat, unifEigenspace_eq_iSup_unifEigenspace_nat] + simp_rw [unifEigenspace_directed.disjoint_iSup_left, unifEigenspace_directed.disjoint_iSup_right] + rintro ⟨k, -⟩ ⟨l, -⟩ nontriviality M have := NoZeroSMulDivisors.isReduced R M rw [disjoint_iff] - set p := f.genEigenspace μ₁ k ⊓ f.genEigenspace μ₂ l + set p := f.unifEigenspace μ₁ k ⊓ f.unifEigenspace μ₂ l by_contra hp replace hp : Nontrivial p := Submodule.nontrivial_iff_ne_bot.mpr hp let f₁ : End R p := (f - algebraMap R (End R M) μ₁).restrict <| MapsTo.inter_inter - (mapsTo_genEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ₁) μ₁ k) - (mapsTo_genEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ₁) μ₂ l) + (mapsTo_unifEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ₁) μ₁ k) + (mapsTo_unifEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ₁) μ₂ l) let f₂ : End R p := (f - algebraMap R (End R M) μ₂).restrict <| MapsTo.inter_inter - (mapsTo_genEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ₂) μ₁ k) - (mapsTo_genEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ₂) μ₂ l) + (mapsTo_unifEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f μ₂) μ₁ k) + (mapsTo_unifEigenspace_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_unifEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f _) + apply isNilpotent_restrict_unifEigenspace_nat + apply mapsTo_unifEigenspace_of_comm (Algebra.mul_sub_algebraMap_commutes f _) + apply isNilpotent_restrict_unifEigenspace_nat have hf₁₂ : f₂ - f₁ = algebraMap R (End R p) (μ₁ - μ₂) := by ext; simp [f₁, f₂, sub_smul] rw [hf₁₂, IsNilpotent.map_iff (NoZeroSMulDivisors.algebraMap_injective R (End R p)), isNilpotent_iff_eq_zero, sub_eq_zero] at this contradiction +lemma disjoint_genEigenspace [NoZeroSMulDivisors R M] + (f : End R M) {μ₁ μ₂ : R} (hμ : μ₁ ≠ μ₂) (k l : ℕ) : + Disjoint (f.genEigenspace μ₁ k) (f.genEigenspace μ₂ l) := + disjoint_unifEigenspace f hμ k l + lemma 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μ + simpa only [iSup_genEigenspace_eq] using disjoint_unifEigenspace f hμ ⊤ ⊤ lemma injOn_genEigenspace [NoZeroSMulDivisors R M] (f : End R M) : InjOn (⨆ k, f.genEigenspace · k) {μ | ⨆ k, f.genEigenspace μ k ≠ ⊥} := by @@ -345,12 +697,14 @@ lemma injOn_genEigenspace [NoZeroSMulDivisors R M] (f : End R M) : apply hμ₂ simpa only [hμ₁₂, disjoint_self] using f.disjoint_iSup_genEigenspace contra -theorem independent_genEigenspace [NoZeroSMulDivisors R M] (f : End R M) : - CompleteLattice.Independent (fun μ ↦ ⨆ k, f.genEigenspace μ k) := by +theorem independent_maxGenEigenspace [NoZeroSMulDivisors R M] (f : End R M) : + CompleteLattice.Independent f.maxGenEigenspace := 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, + show CompleteLattice.Independent (f.maxGenEigenspace ·) + simp_rw [maxGenEigenspace_def, + CompleteLattice.independent_iff_supIndep_of_injOn f.injOn_genEigenspace, Finset.supIndep_iff_disjoint_erase] exact fun s μ _ ↦ this _ _ (s.not_mem_erase μ) intro μ₁ s @@ -384,6 +738,11 @@ theorem independent_genEigenspace [NoZeroSMulDivisors R M] (f : End R M) : simp_rw [Submodule.mem_iSup_of_chain, mem_genEigenspace] exact ⟨k, hyz⟩ +theorem independent_genEigenspace [NoZeroSMulDivisors R M] (f : End R M) : + CompleteLattice.Independent (fun μ ↦ ⨆ k, f.genEigenspace μ k) := by + simp_rw [← maxGenEigenspace_def] + 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) : @@ -396,7 +755,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]) @@ -407,7 +766,7 @@ 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`. -/ @@ -415,7 +774,7 @@ theorem genEigenspace_restrict (f : End R M) (p : Submodule R M) (k : ℕ) (μ : (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] + simp only [genEigenspace_def, OrderHom.coe_mk, ← LinearMap.ker_comp] induction' k with k ih · rw [pow_zero, pow_zero, LinearMap.one_eq_id] apply (Submodule.ker_subtype _).symm @@ -428,6 +787,50 @@ lemma _root_.Submodule.inf_genEigenspace (f : End R M) (p : Submodule R M) {k : (genEigenspace (LinearMap.restrict f hfp) μ k).map p.subtype := by rw [f.genEigenspace_restrict _ _ _ hfp, Submodule.map_comap_eq, Submodule.range_subtype] +/-- Given a family of endomorphisms `i ↦ f i`, a family of candidate eigenvalues `i ↦ μ i`, and a +submodule `p` which is invariant wrt every `f i`, the intersection of `p` with the simultaneous +maximal generalised eigenspace (taken over all `i`), is the same as the simultaneous maximal +generalised eigenspace of the `f i` restricted to `p`. -/ +lemma _root_.Submodule.inf_iInf_maxGenEigenspace_of_forall_mapsTo {ι : Type*} {μ : ι → R} + (f : ι → End R M) (p : Submodule R M) (hfp : ∀ i, MapsTo (f i) p p) : + p ⊓ ⨅ i, (f i).maxGenEigenspace (μ i) = + (⨅ i, maxGenEigenspace ((f i).restrict (hfp i)) (μ i)).map p.subtype := by + cases isEmpty_or_nonempty ι + · simp [iInf_of_isEmpty] + · simp_rw [inf_iInf, maxGenEigenspace_def, ((f _).genEigenspace _).mono.directed_le.inf_iSup_eq, + p.inf_genEigenspace _ (hfp _), ← Submodule.map_iSup, Submodule.map_iInf _ p.injective_subtype] + +/-- Given a family of endomorphisms `i ↦ f i`, a family of candidate eigenvalues `i ↦ μ i`, and a +distinguished index `i` whose maximal generalised `μ i`-eigenspace is invariant wrt every `f j`, +taking simultaneous maximal generalised eigenspaces is unaffected by first restricting to the +distinguished generalised `μ i`-eigenspace. -/ +lemma iInf_maxGenEigenspace_restrict_map_subtype_eq + {ι : Type*} {μ : ι → R} (i : ι) (f : ι → End R M) + (h : ∀ j, MapsTo (f j) ((f i).maxGenEigenspace (μ i)) ((f i).maxGenEigenspace (μ i))) : + letI p := (f i).maxGenEigenspace (μ i) + letI q (j : ι) := maxGenEigenspace ((f j).restrict (h j)) (μ j) + (⨅ j, q j).map p.subtype = ⨅ j, (f j).maxGenEigenspace (μ j) := by + have : Nonempty ι := ⟨i⟩ + set p := (f i).maxGenEigenspace (μ i) + have : ⨅ j, (f j).maxGenEigenspace (μ j) = p ⊓ ⨅ j, (f j).maxGenEigenspace (μ j) := by + refine le_antisymm ?_ inf_le_right + simpa only [le_inf_iff, le_refl, and_true] using iInf_le _ _ + rw [Submodule.map_iInf _ p.injective_subtype, this, Submodule.inf_iInf] + simp_rw [maxGenEigenspace_def, Submodule.map_iSup, + ((f _).genEigenspace _).mono.directed_le.inf_iSup_eq, p.inf_genEigenspace (f _) (h _)] + +lemma mapsTo_restrict_maxGenEigenspace_restrict_of_mapsTo + {p : Submodule R M} (f g : End R M) (hf : MapsTo f p p) (hg : MapsTo g p p) {μ₁ μ₂ : R} + (h : MapsTo f (g.maxGenEigenspace μ₁) (g.maxGenEigenspace μ₂)) : + 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) @@ -442,16 +845,18 @@ 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, OrderHom.coe_mk, unifEigenspace_nat, ← LinearMap.ker_comp]; rfl + _ = f.genEigenspace μ (finrank K V + finrank K V) := by + rw [← pow_add, genEigenspace, OrderHom.coe_mk, unifEigenspace_nat]; rfl _ = 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, unifEigenrange_nat, LinearMap.range_eq_map, + Submodule.map_inf_eq_map_inf_comap, top_inf_eq, h, + genEigenspace, OrderHom.coe_mk, unifEigenspace_nat] apply Submodule.map_comap_le /-- If an invariant subspace `p` of an endomorphism `f` is disjoint from the `μ`-eigenspace of `f`, @@ -478,11 +883,13 @@ 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, unifEigenrange_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, unifEigenrange_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 diff --git a/Mathlib/LinearAlgebra/Eigenspace/Matrix.lean b/Mathlib/LinearAlgebra/Eigenspace/Matrix.lean index a58ddeb616fdd..7ae63cc2e199b 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Matrix.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Matrix.lean @@ -22,8 +22,7 @@ section SpectrumDiagonal variable {R n M : Type*} [DecidableEq n] [Fintype n] -open Matrix -open Module.End +open Matrix Module.End section NontrivialCommRing @@ -37,7 +36,7 @@ lemma hasEigenvector_toLin_diagonal (d : n → R) (i : n) (b : Basis n R M) : /-- Standard basis vectors are eigenvectors of any associated diagonal linear operator. -/ lemma hasEigenvector_toLin'_diagonal (d : n → R) (i : n) : HasEigenvector (toLin' (diagonal d)) (d i) (Pi.basisFun R n i) := - hasEigenvector_toLin_diagonal .. + hasEigenvector_toLin_diagonal _ _ (Pi.basisFun R n) /-- Eigenvalues of a diagonal linear operator are the diagonal entries. -/ lemma hasEigenvalue_toLin_diagonal_iff (d : n → R) {μ : R} [NoZeroSMulDivisors R M] 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/Semisimple.lean b/Mathlib/LinearAlgebra/Eigenspace/Semisimple.lean index 03cddde5f1423..aefced273795c 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Semisimple.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Semisimple.lean @@ -55,7 +55,7 @@ lemma IsSemisimple.genEigenspace_eq_eigenspace lemma IsSemisimple.maxGenEigenspace_eq_eigenspace (hf : f.IsSemisimple) (μ : R) : f.maxGenEigenspace μ = f.eigenspace μ := by - simp_rw [maxGenEigenspace, ← (f.genEigenspace μ).monotone.iSup_nat_add 1, + simp_rw [maxGenEigenspace_def, ← (f.genEigenspace μ).monotone.iSup_nat_add 1, hf.genEigenspace_eq_eigenspace μ (Nat.zero_lt_succ _), ciSup_const] end Module.End diff --git a/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean b/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean index a8726197a4438..03e4ac0132b66 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean @@ -5,6 +5,7 @@ Authors: Alexander Bentkamp -/ import Mathlib.LinearAlgebra.Eigenspace.Basic import Mathlib.FieldTheory.IsAlgClosed.Spectrum +import Mathlib.LinearAlgebra.FreeModule.Finite.Matrix /-! # Triangularizable linear endomorphisms @@ -37,7 +38,7 @@ 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] @@ -52,7 +53,7 @@ theorem exists_hasEigenvalue_of_iSup_genEigenspace_eq_top [Nontrivial M] {f : En 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 + rwa [hasGenEigenvalue_iff, not_not] at hk simp [contra] -- This is Lemma 5.21 of [axler2015], although we are no longer following that proof. @@ -98,6 +99,8 @@ 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_def, Module.End.genEigenrange_def] 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 @@ -167,7 +170,8 @@ theorem inf_iSup_genEigenspace [FiniteDimensional K V] (h : ∀ x ∈ p, f x ∈ · 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 + simpa only [End.mem_genEigenspace] using + Module.End.genEigenspace_le_genEigenspace_finrank _ _ k hk 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] @@ -184,9 +188,10 @@ theorem inf_iSup_genEigenspace [FiniteDimensional K V] (h : ∀ x ∈ p, f x ∈ 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μ + rw [LinearMap.ker_noncommProd_eq_of_supIndep_ker, ← Finset.sup_eq_iSup] + · simpa only [End.genEigenspace_def] using + Finset.supIndep_iff_disjoint_erase.mp (this.supIndep' m.support) μ hμ + · simpa only [End.genEigenspace_def] using this.supIndep' (m.support.erase μ) have hg₄ : SurjOn g ↑(p ⊓ ⨆ k, f.genEigenspace μ k) ↑(p ⊓ ⨆ k, f.genEigenspace μ k) := by have : MapsTo g @@ -217,3 +222,54 @@ theorem Module.End.iSup_genEigenspace_restrict_eq_top simp_rw [Submodule.inf_genEigenspace f p h, Submodule.comap_subtype_self, ← Submodule.map_iSup, Submodule.comap_map_eq_of_injective h_inj] at this exact this.symm + +/-- Given a family of endomorphisms `i ↦ f i` which are compatible in the sense that every maximal +generalised eigenspace of `f i` is invariant wrt `f j`, if each `f i` is triangularizable, the +family is simultaneously triangularizable. -/ +lemma Module.End.iSup_iInf_maxGenEigenspace_eq_top_of_forall_mapsTo + {ι : Type*} [FiniteDimensional K V] + (f : ι → End K V) + (h : ∀ i j φ, MapsTo (f i) ((f j).maxGenEigenspace φ) ((f j).maxGenEigenspace φ)) + (h' : ∀ i, ⨆ μ, (f i).maxGenEigenspace μ = ⊤) : + ⨆ χ : ι → K, ⨅ i, (f i).maxGenEigenspace (χ i) = ⊤ := by + generalize h_dim : finrank K V = n + induction n using Nat.strongRecOn generalizing V with | ind n ih => ?_ + obtain this | ⟨i : ι, hy : ¬ ∃ φ, (f i).maxGenEigenspace φ = ⊤⟩ := + forall_or_exists_not (fun j : ι ↦ ∃ φ : K, (f j).maxGenEigenspace φ = ⊤) + · choose χ hχ using this + replace hχ : ⨅ i, (f i).maxGenEigenspace (χ i) = ⊤ := by simpa + simp_rw [eq_top_iff] at hχ ⊢ + exact le_trans hχ <| le_iSup (fun χ : ι → K ↦ ⨅ i, (f i).maxGenEigenspace (χ i)) χ + · replace hy : ∀ φ, finrank K ((f i).maxGenEigenspace φ) < n := fun φ ↦ by + simp_rw [not_exists, ← lt_top_iff_ne_top] at hy; exact h_dim ▸ Submodule.finrank_lt (hy φ) + have hi (j : ι) (φ : K) : + MapsTo (f j) ((f i).maxGenEigenspace φ) ((f i).maxGenEigenspace φ) := by + exact h j i φ + replace ih (φ : K) : + ⨆ χ : ι → K, ⨅ j, maxGenEigenspace ((f j).restrict (hi j φ)) (χ j) = ⊤ := by + apply ih _ (hy φ) + · intro j k μ + exact mapsTo_restrict_maxGenEigenspace_restrict_of_mapsTo (f j) (f k) _ _ (h j k μ) + · simp_rw [maxGenEigenspace_def] at h' ⊢ + exact fun j ↦ Module.End.iSup_genEigenspace_restrict_eq_top _ (h' j) + · rfl + replace ih (φ : K) : + ⨆ (χ : ι → K) (_ : χ i = φ), ⨅ j, maxGenEigenspace ((f j).restrict (hi j φ)) (χ j) = ⊤ := by + suffices ∀ χ : ι → K, χ i ≠ φ → ⨅ j, maxGenEigenspace ((f j).restrict (hi j φ)) (χ j) = ⊥ by + specialize ih φ; rw [iSup_split, biSup_congr this] at ih; simpa using ih + intro χ hχ + rw [eq_bot_iff, ← ((f i).maxGenEigenspace φ).ker_subtype, LinearMap.ker, + ← Submodule.map_le_iff_le_comap, ← Submodule.inf_iInf_maxGenEigenspace_of_forall_mapsTo, + ← disjoint_iff_inf_le] + simp_rw [maxGenEigenspace_def] + exact ((f i).disjoint_iSup_genEigenspace hχ.symm).mono_right (iInf_le _ i) + replace ih (φ : K) : + ⨆ (χ : ι → K) (_ : χ i = φ), ⨅ j, maxGenEigenspace (f j) (χ j) = + maxGenEigenspace (f i) φ := by + have (χ : ι → K) (hχ : χ i = φ) : ⨅ j, maxGenEigenspace (f j) (χ j) = + (⨅ j, maxGenEigenspace ((f j).restrict (hi j φ)) (χ j)).map + ((f i).maxGenEigenspace φ).subtype := by + rw [← hχ, iInf_maxGenEigenspace_restrict_map_subtype_eq] + simp_rw [biSup_congr this, ← Submodule.map_iSup, ih, Submodule.map_top, + Submodule.range_subtype] + simpa only [← ih, iSup_comm (ι := K), iSup_iSup_eq_right] using h' i diff --git a/Mathlib/LinearAlgebra/Eigenspace/Zero.lean b/Mathlib/LinearAlgebra/Eigenspace/Zero.lean index d5556a7dfff7f..30837353e1b0a 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.maxGenEigenspace_def, Module.End.genEigenspace_def] 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] @@ -191,7 +188,7 @@ lemma finrank_maxGenEigenspace (φ : Module.End K M) : generalize_proofs h' clear hx induction n with - | zero => simp only [Nat.zero_eq, pow_zero, one_apply] + | zero => simp only [pow_zero, one_apply] | succ n ih => simp only [pow_succ', LinearMap.mul_apply, ih, restrict_apply] end LinearMap diff --git a/Mathlib/LinearAlgebra/ExteriorAlgebra/Basic.lean b/Mathlib/LinearAlgebra/ExteriorAlgebra/Basic.lean index 74f30e36f4cda..cd48d0d7611d4 100644 --- a/Mathlib/LinearAlgebra/ExteriorAlgebra/Basic.lean +++ b/Mathlib/LinearAlgebra/ExteriorAlgebra/Basic.lean @@ -132,7 +132,7 @@ theorem hom_ext {f g : ExteriorAlgebra R M →ₐ[R] A} CliffordAlgebra.hom_ext h /-- If `C` holds for the `algebraMap` of `r : R` into `ExteriorAlgebra R M`, the `ι` of `x : M`, -and is preserved under addition and muliplication, then it holds for all of `ExteriorAlgebra R M`. +and is preserved under addition and multiplication, then it holds for all of `ExteriorAlgebra R M`. -/ @[elab_as_elim] theorem induction {C : ExteriorAlgebra R M → Prop} @@ -164,6 +164,9 @@ 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 isLocalRingHom_algebraMap : IsLocalRingHom (algebraMap R (ExteriorAlgebra R M)) := + isLocalRingHom_of_leftInverse _ (algebraMap_leftInverse M) + theorem isUnit_algebraMap (r : R) : IsUnit (algebraMap R (ExteriorAlgebra R M) r) ↔ IsUnit r := isUnit_map_of_leftInverse _ (algebraMap_leftInverse M) @@ -244,9 +247,10 @@ theorem ι_add_mul_swap (x y : M) : ι R x * ι R y + ι R y * ι R x = 0 := theorem ι_mul_prod_list {n : ℕ} (f : Fin n → M) (i : Fin n) : (ι R <| f i) * (List.ofFn fun i => ι R <| f i).prod = 0 := by - induction' n with n hn - · exact i.elim0 - · rw [List.ofFn_succ, List.prod_cons, ← mul_assoc] + induction n with + | zero => exact i.elim0 + | succ n hn => + rw [List.ofFn_succ, List.prod_cons, ← mul_assoc] by_cases h : i = 0 · rw [h, ι_sq_zero, zero_mul] · replace hn := @@ -298,8 +302,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) : @@ -371,7 +375,7 @@ theorem map_apply_ι (f : M →ₗ[R] N) (m : M) : map f (ι R m) = ι R (f m) : theorem map_apply_ιMulti {n : ℕ} (f : M →ₗ[R] N) (m : Fin n → M) : map f (ιMulti R n m) = ιMulti R n (f ∘ m) := by rw [ιMulti_apply, ιMulti_apply, map_list_prod] - simp only [List.map_ofFn, Function.comp, map_apply_ι] + simp only [List.map_ofFn, Function.comp_def, map_apply_ι] @[simp] theorem map_comp_ιMulti {n : ℕ} (f : M →ₗ[R] N) : diff --git a/Mathlib/LinearAlgebra/FiniteDimensional.lean b/Mathlib/LinearAlgebra/FiniteDimensional.lean index 640843d5b57d5..7b2f68f6cdcdd 100644 --- a/Mathlib/LinearAlgebra/FiniteDimensional.lean +++ b/Mathlib/LinearAlgebra/FiniteDimensional.lean @@ -27,7 +27,7 @@ variable {K : Type u} {V : Type v} namespace Submodule -open IsNoetherian FiniteDimensional +open IsNoetherian Module section DivisionRing @@ -106,10 +106,9 @@ noncomputable def LinearEquiv.quotEquivOfEquiv {p : Subspace K V} {q : Subspace /-- Given the subspaces `p q`, if `p.quotient ≃ₗ[K] q`, then `q.quotient ≃ₗ[K] p` -/ noncomputable def LinearEquiv.quotEquivOfQuotEquiv {p q : Subspace K V} (f : (V ⧸ p) ≃ₗ[K] q) : (V ⧸ q) ≃ₗ[K] p := - LinearEquiv.ofFinrankEq _ _ <| - add_right_cancel <| by - rw [Submodule.finrank_quotient_add_finrank, ← LinearEquiv.finrank_eq f, add_comm, - Submodule.finrank_quotient_add_finrank] + LinearEquiv.ofFinrankEq _ _ <| by + rw [← add_right_cancel_iff, Submodule.finrank_quotient_add_finrank, ← LinearEquiv.finrank_eq f, + add_comm, Submodule.finrank_quotient_add_finrank] end DivisionRing @@ -117,7 +116,7 @@ end FiniteDimensional namespace LinearMap -open FiniteDimensional +open Module section DivisionRing @@ -143,7 +142,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 ed9305efcd20a..f7ab907b35f9c 100644 --- a/Mathlib/LinearAlgebra/FiniteDimensional/Defs.lean +++ b/Mathlib/LinearAlgebra/FiniteDimensional/Defs.lean @@ -27,7 +27,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 +70,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 +80,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₂] @@ -145,10 +140,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 +149,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 +162,24 @@ 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] {V₂ : Type v'} [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 +191,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 +225,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 +258,6 @@ section open Finset -section - variable {L : Type*} [LinearOrderedField L] variable {W : Type v} [AddCommGroup W] [Module L W] @@ -271,16 +273,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 +326,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 +348,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 +356,7 @@ end ZeroRank namespace Submodule -open IsNoetherian FiniteDimensional +open IsNoetherian Module section DivisionRing @@ -374,8 +372,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 +421,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₂] @@ -449,10 +446,7 @@ instance finiteDimensional_finsupp {ι : Type*} [Finite ι] [FiniteDimensional K end -namespace FiniteDimensional - -section DivisionRing - +namespace Submodule variable [DivisionRing K] [AddCommGroup V] [Module K V] {V₂ : Type v'} [AddCommGroup V₂] [Module K V₂] @@ -470,33 +464,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 @@ -600,7 +590,7 @@ end LinearMap namespace LinearEquiv -open FiniteDimensional +open Module variable [DivisionRing K] [AddCommGroup V] [Module K V] variable [FiniteDimensional K V] @@ -647,14 +637,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,12 +669,14 @@ 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):) inv_zero := dif_pos rfl nnqsmul := _ + nnqsmul_def := fun q a => rfl qsmul := _ + qsmul_def := fun q a => rfl /-- 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] @@ -692,21 +684,6 @@ noncomputable def fieldOfFiniteDimensional (F K : Type*) [Field F] [h : CommRing { 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 - section DivisionRing variable [DivisionRing K] [AddCommGroup V] [Module K V] @@ -720,6 +697,7 @@ theorem finrank_span_singleton {v : V} (hv : v ≠ 0) : finrank K (K ∙ v) = 1 · exact finrank_span_le_card ({v} : Set V) · rw [Nat.succ_le_iff, finrank_pos_iff] use ⟨v, mem_span_singleton_self v⟩, 0 + apply Subtype.coe_ne_coe.mp simp [hv] /-- In a one-dimensional space, any vector is a multiple of any nonzero vector -/ diff --git a/Mathlib/LinearAlgebra/Finsupp.lean b/Mathlib/LinearAlgebra/Finsupp.lean index 209908215216b..810b8a01afebd 100644 --- a/Mathlib/LinearAlgebra/Finsupp.lean +++ b/Mathlib/LinearAlgebra/Finsupp.lean @@ -23,10 +23,10 @@ interpreted as a submodule of `α →₀ M`. We also define `LinearMap` versions linear map; * `Finsupp.restrictDom`: `Finsupp.filter` as a linear map to `Finsupp.supported s`; * `Finsupp.lsum`: `Finsupp.sum` or `Finsupp.liftAddHom` as a `LinearMap`; -* `Finsupp.total α M R (v : ι → M)`: sends `l : ι → R` to the linear combination of `v i` with - coefficients `l i`; -* `Finsupp.totalOn`: a restricted version of `Finsupp.total` with domain `Finsupp.supported R R s` - and codomain `Submodule.span R (v '' s)`; +* `Finsupp.linearCombination R (v : ι → M)`: sends `l : ι → R` to the linear combination of + `v i` with coefficients `l i`; +* `Finsupp.linearCombinationOn`: a restricted version of `Finsupp.linearCombination` with domain + `Finsupp.supported R R s` and codomain `Submodule.span R (v '' s)`; * `Finsupp.supportedEquivFinsupp`: a linear equivalence between the functions `α →₀ M` supported on `s` and the functions `s →₀ M`; * `Finsupp.lmapDomain`: a linear map version of `Finsupp.mapDomain`; @@ -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) @@ -587,75 +587,103 @@ def lcomapDomain (f : α → β) (hf : Function.Injective f) : (β →₀ M) → end LComapDomain -section Total +section LinearCombination -variable (α) (M) (R) +variable (R) variable {α' : Type*} {M' : Type*} [AddCommMonoid M'] [Module R M'] (v : α → M) {v' : α' → M'} -/-- Interprets (l : α →₀ R) as linear combination of the elements in the family (v : α → M) and +/-- Interprets (l : α →₀ R) as a linear combination of the elements in the family (v : α → M) and evaluates this linear combination. -/ -protected def total : (α →₀ R) →ₗ[R] M := +def linearCombination : (α →₀ R) →ₗ[R] M := Finsupp.lsum ℕ fun i => LinearMap.id.smulRight (v i) -variable {α M v} +@[deprecated (since := "2024-08-29")] noncomputable alias total := linearCombination + +variable {v} -theorem total_apply (l : α →₀ R) : Finsupp.total α M R v l = l.sum fun i a => a • v i := +theorem linearCombination_apply (l : α →₀ R) : linearCombination R v l = l.sum fun i a => a • v i := rfl -theorem total_apply_of_mem_supported {l : α →₀ R} {s : Finset α} - (hs : l ∈ supported R R (↑s : Set α)) : Finsupp.total α M R v l = s.sum fun i => l i • v i := +@[deprecated (since := "2024-08-29")] alias total_apply := linearCombination_apply + +theorem linearCombination_apply_of_mem_supported {l : α →₀ R} {s : Finset α} + (hs : l ∈ supported R R (↑s : Set α)) : linearCombination R v l = s.sum fun i => l i • v i := Finset.sum_subset hs fun x _ hxg => show l x • v x = 0 by rw [not_mem_support_iff.1 hxg, zero_smul] +@[deprecated (since := "2024-08-29")] alias total_apply_of_mem_supported := + linearCombination_apply_of_mem_supported + @[simp] -theorem total_single (c : R) (a : α) : Finsupp.total α M R v (single a c) = c • v a := by - simp [total_apply, sum_single_index] +theorem linearCombination_single (c : R) (a : α) : + linearCombination R v (single a c) = c • v a := by + simp [linearCombination_apply, sum_single_index] + +@[deprecated (since := "2024-08-29")] alias total_single := linearCombination_single -theorem total_zero_apply (x : α →₀ R) : (Finsupp.total α M R 0) x = 0 := by - simp [Finsupp.total_apply] +theorem linearCombination_zero_apply (x : α →₀ R) : (linearCombination R (0 : α → M)) x = 0 := by + simp [linearCombination_apply] + +@[deprecated (since := "2024-08-29")] alias total_zero_apply := linearCombination_zero_apply variable (α M) @[simp] -theorem total_zero : Finsupp.total α M R 0 = 0 := - LinearMap.ext (total_zero_apply R) +theorem linearCombination_zero : linearCombination R (0 : α → M) = 0 := + LinearMap.ext (linearCombination_zero_apply R) + +@[deprecated (since := "2024-08-29")] alias total_zero := linearCombination_zero variable {α M} -theorem apply_total (f : M →ₗ[R] M') (v) (l : α →₀ R) : - f (Finsupp.total α M R v l) = Finsupp.total α M' R (f ∘ v) l := by +theorem apply_linearCombination (f : M →ₗ[R] M') (v) (l : α →₀ R) : + f (linearCombination R v l) = linearCombination R (f ∘ v) l := by apply Finsupp.induction_linear l <;> simp (config := { contextual := true }) -theorem apply_total_id (f : M →ₗ[R] M') (l : M →₀ R) : - f (Finsupp.total M M R _root_.id l) = Finsupp.total M M' R f l := - apply_total .. +@[deprecated (since := "2024-08-29")] alias apply_total := apply_linearCombination + +theorem apply_linearCombination_id (f : M →ₗ[R] M') (l : M →₀ R) : + f (linearCombination R _root_.id l) = linearCombination R f l := + apply_linearCombination .. + +@[deprecated (since := "2024-08-29")] alias apply_total_id := apply_linearCombination_id + +theorem linearCombination_unique [Unique α] (l : α →₀ R) (v : α → M) : + linearCombination R v l = l default • v default := by + rw [← linearCombination_single, ← unique_single l] -theorem total_unique [Unique α] (l : α →₀ R) (v) : - Finsupp.total α M R v l = l default • v default := by rw [← total_single, ← unique_single l] +@[deprecated (since := "2024-08-29")] alias total_unique := linearCombination_unique -theorem total_surjective (h : Function.Surjective v) : - Function.Surjective (Finsupp.total α M R v) := by +theorem linearCombination_surjective (h : Function.Surjective v) : + Function.Surjective (linearCombination R v) := by intro x obtain ⟨y, hy⟩ := h x exact ⟨Finsupp.single y 1, by simp [hy]⟩ -theorem total_range (h : Function.Surjective v) : LinearMap.range (Finsupp.total α M R v) = ⊤ := - range_eq_top.2 <| total_surjective R h +@[deprecated (since := "2024-08-29")] alias total_surjective := linearCombination_surjective + +theorem linearCombination_range (h : Function.Surjective v) : + LinearMap.range (linearCombination R v) = ⊤ := + range_eq_top.2 <| linearCombination_surjective R h + +@[deprecated (since := "2024-08-29")] alias total_range := linearCombination_range /-- Any module is a quotient of a free module. This is stated as surjectivity of -`Finsupp.total M M R id : (M →₀ R) →ₗ[R] M`. -/ -theorem total_id_surjective (M) [AddCommMonoid M] [Module R M] : - Function.Surjective (Finsupp.total M M R _root_.id) := - total_surjective R Function.surjective_id +`Finsupp.linearCombination R id : (M →₀ R) →ₗ[R] M`. -/ +theorem linearCombination_id_surjective (M) [AddCommMonoid M] [Module R M] : + Function.Surjective (linearCombination R (id : M → M)) := + linearCombination_surjective R Function.surjective_id + +@[deprecated (since := "2024-08-29")] alias total_id_surjective := linearCombination_id_surjective -theorem range_total : LinearMap.range (Finsupp.total α M R v) = span R (range v) := by +theorem range_linearCombination : LinearMap.range (linearCombination R v) = span R (range v) := by ext x constructor · intro hx rw [LinearMap.mem_range] at hx rcases hx with ⟨l, hl⟩ rw [← hl] - rw [Finsupp.total_apply] + rw [linearCombination_apply] exact sum_mem fun i _ => Submodule.smul_mem _ _ (subset_span (mem_range_self i)) · apply span_le.2 intro x hx @@ -664,49 +692,68 @@ theorem range_total : LinearMap.range (Finsupp.total α M R v) = span R (range v use Finsupp.single i 1 simp [hi] -theorem lmapDomain_total (f : α → α') (g : M →ₗ[R] M') (h : ∀ i, g (v i) = v' (f i)) : - (Finsupp.total α' M' R v').comp (lmapDomain R R f) = g.comp (Finsupp.total α M R v) := by +@[deprecated (since := "2024-08-29")] alias range_total := range_linearCombination + +theorem lmapDomain_linearCombination (f : α → α') (g : M →ₗ[R] M') (h : ∀ i, g (v i) = v' (f i)) : + (linearCombination R v').comp (lmapDomain R R f) = g.comp (linearCombination R v) := by ext l - simp [total_apply, Finsupp.sum_mapDomain_index, add_smul, h] + simp [linearCombination_apply, Finsupp.sum_mapDomain_index, add_smul, h] + +@[deprecated (since := "2024-08-29")] alias lmapDomain_total := lmapDomain_linearCombination -theorem total_comp_lmapDomain (f : α → α') : - (Finsupp.total α' M' R v').comp (Finsupp.lmapDomain R R f) = Finsupp.total α M' R (v' ∘ f) := by +theorem linearCombination_comp_lmapDomain (f : α → α') : + (linearCombination R v').comp (Finsupp.lmapDomain R R f) = linearCombination R (v' ∘ f) := by ext simp +@[deprecated (since := "2024-08-29")] alias total_comp_lmapDomain := + linearCombination_comp_lmapDomain + @[simp] -theorem total_embDomain (f : α ↪ α') (l : α →₀ R) : - (Finsupp.total α' M' R v') (embDomain f l) = (Finsupp.total α M' R (v' ∘ f)) l := by - simp [total_apply, Finsupp.sum, support_embDomain, embDomain_apply] +theorem linearCombination_embDomain (f : α ↪ α') (l : α →₀ R) : + (linearCombination R v') (embDomain f l) = (linearCombination R (v' ∘ f)) l := by + simp [linearCombination_apply, Finsupp.sum, support_embDomain, embDomain_apply] + +@[deprecated (since := "2024-08-29")] alias total_embDomain := linearCombination_embDomain @[simp] -theorem total_mapDomain (f : α → α') (l : α →₀ R) : - (Finsupp.total α' M' R v') (mapDomain f l) = (Finsupp.total α M' R (v' ∘ f)) l := - LinearMap.congr_fun (total_comp_lmapDomain _ _) l +theorem linearCombination_mapDomain (f : α → α') (l : α →₀ R) : + (linearCombination R v') (mapDomain f l) = (linearCombination R (v' ∘ f)) l := + LinearMap.congr_fun (linearCombination_comp_lmapDomain _ _) l + +@[deprecated (since := "2024-08-29")] alias total_mapDomain := linearCombination_mapDomain @[simp] -theorem total_equivMapDomain (f : α ≃ α') (l : α →₀ R) : - (Finsupp.total α' M' R v') (equivMapDomain f l) = (Finsupp.total α M' R (v' ∘ f)) l := by - rw [equivMapDomain_eq_mapDomain, total_mapDomain] +theorem linearCombination_equivMapDomain (f : α ≃ α') (l : α →₀ R) : + (linearCombination R v') (equivMapDomain f l) = (linearCombination R (v' ∘ f)) l := by + rw [equivMapDomain_eq_mapDomain, linearCombination_mapDomain] + +@[deprecated (since := "2024-08-29")] alias total_equivMapDomain := linearCombination_equivMapDomain + +/-- A version of `Finsupp.range_linearCombination` which is useful for going in the other +direction -/ +theorem span_eq_range_linearCombination (s : Set M) : + span R s = LinearMap.range (linearCombination R ((↑) : s → M)) := by + rw [range_linearCombination, Subtype.range_coe_subtype, Set.setOf_mem_eq] -/-- A version of `Finsupp.range_total` which is useful for going in the other direction -/ -theorem span_eq_range_total (s : Set M) : span R s = LinearMap.range (Finsupp.total s M R (↑)) := by - rw [range_total, Subtype.range_coe_subtype, Set.setOf_mem_eq] +@[deprecated (since := "2024-08-29")] alias span_eq_range_total := span_eq_range_linearCombination -theorem mem_span_iff_total (s : Set M) (x : M) : - x ∈ span R s ↔ ∃ l : s →₀ R, Finsupp.total s M R (↑) l = x := - (SetLike.ext_iff.1 <| span_eq_range_total _ _) x +theorem mem_span_iff_linearCombination (s : Set M) (x : M) : + x ∈ span R s ↔ ∃ l : s →₀ R, linearCombination R (↑) l = x := + (SetLike.ext_iff.1 <| span_eq_range_linearCombination _ _) x + +@[deprecated (since := "2024-08-29")] alias mem_span_iff_total := mem_span_iff_linearCombination variable {R} theorem mem_span_range_iff_exists_finsupp {v : α → M} {x : M} : x ∈ span R (range v) ↔ ∃ c : α →₀ R, (c.sum fun i a => a • v i) = x := by - simp only [← Finsupp.range_total, LinearMap.mem_range, Finsupp.total_apply] + simp only [← Finsupp.range_linearCombination, LinearMap.mem_range, linearCombination_apply] variable (R) -theorem span_image_eq_map_total (s : Set α) : - span R (v '' s) = Submodule.map (Finsupp.total α M R v) (supported R R s) := by +theorem span_image_eq_map_linearCombination (s : Set α) : + span R (v '' s) = Submodule.map (linearCombination R v) (supported R R s) := by apply span_eq_of_le · intro x hx rw [Set.mem_image] at hx @@ -721,75 +768,99 @@ theorem span_image_eq_map_total (s : Set α) : · exact smul_mem _ _ (subset_span (Set.mem_image_of_mem _ h)) · simp [(Finsupp.mem_supported' R _).1 hz _ h] -- Porting note: `rw` is required to infer metavariables in `sum_mem`. - rw [mem_comap, total_apply] + rw [mem_comap, linearCombination_apply] refine sum_mem ?_ simp [this] -theorem mem_span_image_iff_total {s : Set α} {x : M} : - x ∈ span R (v '' s) ↔ ∃ l ∈ supported R R s, Finsupp.total α M R v l = x := by - rw [span_image_eq_map_total] +@[deprecated (since := "2024-08-29")] alias span_image_eq_map_total := + span_image_eq_map_linearCombination + +theorem mem_span_image_iff_linearCombination {s : Set α} {x : M} : + x ∈ span R (v '' s) ↔ ∃ l ∈ supported R R s, linearCombination R v l = x := by + rw [span_image_eq_map_linearCombination] simp -theorem total_option (v : Option α → M) (f : Option α →₀ R) : - Finsupp.total (Option α) M R v f = - f none • v none + Finsupp.total α M R (v ∘ Option.some) f.some := by - rw [total_apply, sum_option_index_smul, total_apply]; simp +@[deprecated (since := "2024-08-29")] alias mem_span_image_iff_total := + mem_span_image_iff_linearCombination + +theorem linearCombination_option (v : Option α → M) (f : Option α →₀ R) : + linearCombination R v f = + f none • v none + linearCombination R (v ∘ Option.some) f.some := by + rw [linearCombination_apply, sum_option_index_smul, linearCombination_apply]; simp -theorem total_total {α β : Type*} (A : α → M) (B : β → α →₀ R) (f : β →₀ R) : - Finsupp.total α M R A (Finsupp.total β (α →₀ R) R B f) = - Finsupp.total β M R (fun b => Finsupp.total α M R A (B b)) f := by +@[deprecated (since := "2024-08-29")] alias total_option := linearCombination_option + +theorem linearCombination_linearCombination {α β : Type*} (A : α → M) (B : β → α →₀ R) + (f : β →₀ R) : linearCombination R A (linearCombination R B f) = + linearCombination R (fun b => linearCombination R A (B b)) f := by classical - simp only [total_apply] + simp only [linearCombination_apply] apply induction_linear f · simp only [sum_zero_index] · intro f₁ f₂ h₁ h₂ simp [sum_add_index, h₁, h₂, add_smul] · simp [sum_single_index, sum_smul_index, smul_sum, mul_smul] +@[deprecated (since := "2024-08-29")] alias total_total := linearCombination_linearCombination + @[simp] -theorem total_fin_zero (f : Fin 0 → M) : Finsupp.total (Fin 0) M R f = 0 := by +theorem linearCombination_fin_zero (f : Fin 0 → M) : linearCombination R f = 0 := by ext i apply finZeroElim i +@[deprecated (since := "2024-08-29")] alias total_fin_zero := linearCombination_fin_zero + variable (α) (M) (v) -/-- `Finsupp.totalOn M v s` interprets `p : α →₀ R` as a linear combination of a +/-- `Finsupp.linearCombinationOn M v s` interprets `p : α →₀ R` as a linear combination of a subset of the vectors in `v`, mapping it to the span of those vectors. The subset is indicated by a set `s : Set α` of indices. -/ -protected def totalOn (s : Set α) : supported R R s →ₗ[R] span R (v '' s) := - LinearMap.codRestrict _ ((Finsupp.total _ _ _ v).comp (Submodule.subtype (supported R R s))) - fun ⟨l, hl⟩ => (mem_span_image_iff_total _).2 ⟨l, hl, rfl⟩ +def linearCombinationOn (s : Set α) : supported R R s →ₗ[R] span R (v '' s) := + LinearMap.codRestrict _ ((linearCombination _ v).comp (Submodule.subtype (supported R R s))) + fun ⟨l, hl⟩ => (mem_span_image_iff_linearCombination _).2 ⟨l, hl, rfl⟩ + +@[deprecated (since := "2024-08-29")] noncomputable alias totalOn := linearCombinationOn variable {α} {M} {v} -theorem totalOn_range (s : Set α) : LinearMap.range (Finsupp.totalOn α M R v s) = ⊤ := by - rw [Finsupp.totalOn, LinearMap.range_eq_map, LinearMap.map_codRestrict, +theorem linearCombinationOn_range (s : Set α) : + LinearMap.range (linearCombinationOn α M R v s) = ⊤ := by + rw [linearCombinationOn, LinearMap.range_eq_map, LinearMap.map_codRestrict, ← LinearMap.range_le_iff_comap, range_subtype, Submodule.map_top, LinearMap.range_comp, range_subtype] - exact (span_image_eq_map_total _ _).le + exact (span_image_eq_map_linearCombination _ _).le + +@[deprecated (since := "2024-08-29")] alias totalOn_range := linearCombinationOn_range -theorem total_comp (f : α' → α) : - Finsupp.total α' M R (v ∘ f) = (Finsupp.total α M R v).comp (lmapDomain R R f) := by +theorem linearCombination_comp (f : α' → α) : + linearCombination R (v ∘ f) = (linearCombination R v).comp (lmapDomain R R f) := by ext - simp [total_apply] + simp [linearCombination_apply] -theorem total_comapDomain (f : α → α') (l : α' →₀ R) (hf : Set.InjOn f (f ⁻¹' ↑l.support)) : - Finsupp.total α M R v (Finsupp.comapDomain f l hf) = +@[deprecated (since := "2024-08-29")] alias total_comp := linearCombination_comp + +theorem linearCombination_comapDomain (f : α → α') (l : α' →₀ R) + (hf : Set.InjOn f (f ⁻¹' ↑l.support)) : linearCombination R v (Finsupp.comapDomain f l hf) = (l.support.preimage f hf).sum fun i => l (f i) • v i := by - rw [Finsupp.total_apply]; rfl + rw [linearCombination_apply]; rfl + +@[deprecated (since := "2024-08-29")] alias total_comapDomain := linearCombination_comapDomain -theorem total_onFinset {s : Finset α} {f : α → R} (g : α → M) (hf : ∀ a, f a ≠ 0 → a ∈ s) : - Finsupp.total α M R g (Finsupp.onFinset s f hf) = Finset.sum s fun x : α => f x • g x := by +theorem linearCombination_onFinset {s : Finset α} {f : α → R} (g : α → M) + (hf : ∀ a, f a ≠ 0 → a ∈ s) : + linearCombination R g (Finsupp.onFinset s f hf) = Finset.sum s fun x : α => f x • g x := by classical - simp only [Finsupp.total_apply, Finsupp.sum, Finsupp.onFinset_apply, Finsupp.support_onFinset] + simp only [linearCombination_apply, Finsupp.sum, Finsupp.onFinset_apply, Finsupp.support_onFinset] rw [Finset.sum_filter_of_ne] intro x _ h contrapose! h simp [h] -end Total +@[deprecated (since := "2024-08-29")] alias total_onFinset := linearCombination_onFinset + +end LinearCombination /-- An equivalence of domains induces a linear equivalence of finitely supported functions. @@ -1036,13 +1107,13 @@ variable {α M : Type*} (R : Type*) [Fintype α] [Semiring R] [AddCommMonoid M] variable (S : Type*) [Semiring S] [Module S M] [SMulCommClass R S M] variable (v : α → M) -/-- `Fintype.total R S v f` is the linear combination of vectors in `v` with weights in `f`. -This variant of `Finsupp.total` is defined on fintype indexed vectors. +/-- `Fintype.linearCombination R S v f` is the linear combination of vectors in `v` with weights +in `f`. This variant of `Finsupp.linearCombination` is defined on fintype indexed vectors. This map is linear in `v` if `R` is commutative, and always linear in `f`. See note [bundled maps over different rings] for why separate `R` and `S` semirings are used. -/ -protected def Fintype.total : (α → M) →ₗ[S] (α → R) →ₗ[R] M where +protected def Fintype.linearCombination : (α → M) →ₗ[S] (α → R) →ₗ[R] M where toFun v := { toFun := fun f => ∑ i, f i • v i map_add' := fun f g => by simp_rw [← Finset.sum_add_distrib, ← add_smul]; rfl @@ -1050,39 +1121,55 @@ protected def Fintype.total : (α → M) →ₗ[S] (α → R) →ₗ[R] M where map_add' u v := by ext; simp [Finset.sum_add_distrib, Pi.add_apply, smul_add] map_smul' r v := by ext; simp [Finset.smul_sum, smul_comm] +@[deprecated (since := "2024-08-29")] alias Fintype.total := Fintype.linearCombination + variable {S} -theorem Fintype.total_apply (f) : Fintype.total R S v f = ∑ i, f i • v i := +theorem Fintype.linearCombination_apply (f) : Fintype.linearCombination R S v f = ∑ i, f i • v i := rfl +@[deprecated (since := "2024-08-29")] alias Fintype.total_apply := Fintype.linearCombination_apply + @[simp] -theorem Fintype.total_apply_single [DecidableEq α] (i : α) (r : R) : - Fintype.total R S v (Pi.single i r) = r • v i := by - simp_rw [Fintype.total_apply, Pi.single_apply, ite_smul, zero_smul] +theorem Fintype.linearCombination_apply_single [DecidableEq α] (i : α) (r : R) : + Fintype.linearCombination R S v (Pi.single i r) = r • v i := by + simp_rw [Fintype.linearCombination_apply, Pi.single_apply, ite_smul, zero_smul] rw [Finset.sum_ite_eq', if_pos (Finset.mem_univ _)] +@[deprecated (since := "2024-08-29")] alias Fintype.total_apply_single := + Fintype.linearCombination_apply_single + variable (S) -theorem Finsupp.total_eq_fintype_total_apply (x : α → R) : Finsupp.total α M R v - ((Finsupp.linearEquivFunOnFinite R R α).symm x) = Fintype.total R S v x := by +theorem Finsupp.linearCombination_eq_fintype_linearCombination_apply (x : α → R) : + linearCombination R v ((Finsupp.linearEquivFunOnFinite R R α).symm x) = + Fintype.linearCombination R S v x := by apply Finset.sum_subset · exact Finset.subset_univ _ · intro x _ hx rw [Finsupp.not_mem_support_iff.mp hx] exact zero_smul _ _ -theorem Finsupp.total_eq_fintype_total : - (Finsupp.total α M R v).comp (Finsupp.linearEquivFunOnFinite R R α).symm.toLinearMap = - Fintype.total R S v := - LinearMap.ext <| Finsupp.total_eq_fintype_total_apply R S v +@[deprecated (since := "2024-08-29")] alias Finsupp.total_eq_fintype_total_apply := + Finsupp.linearCombination_eq_fintype_linearCombination_apply + +theorem Finsupp.linearCombination_eq_fintype_linearCombination : + (linearCombination R v).comp (Finsupp.linearEquivFunOnFinite R R α).symm.toLinearMap = + Fintype.linearCombination R S v := + LinearMap.ext <| linearCombination_eq_fintype_linearCombination_apply R S v + +@[deprecated (since := "2024-08-29")] alias Finsupp.total_eq_fintype_total := + Finsupp.linearCombination_eq_fintype_linearCombination variable {S} @[simp] -theorem Fintype.range_total : - LinearMap.range (Fintype.total R S v) = Submodule.span R (Set.range v) := by - rw [← Finsupp.total_eq_fintype_total, LinearMap.range_comp, LinearEquiv.range, - Submodule.map_top, Finsupp.range_total] +theorem Fintype.range_linearCombination : + LinearMap.range (Fintype.linearCombination R S v) = Submodule.span R (Set.range v) := by + rw [← Finsupp.linearCombination_eq_fintype_linearCombination, LinearMap.range_comp, + LinearEquiv.range, Submodule.map_top, Finsupp.range_linearCombination] + +@[deprecated (since := "2024-08-29")] alias Fintype.range_total := Fintype.range_linearCombination section SpanRange @@ -1112,32 +1199,40 @@ end Fintype variable {R : Type*} {M : Type*} {N : Type*} variable [Semiring R] [AddCommMonoid M] [Module R M] [AddCommMonoid N] [Module R N] +open Finsupp + section variable (R) /-- Pick some representation of `x : span R w` as a linear combination in `w`, -using the axiom of choice. + ((Finsupp.mem_span_iff_linearCombination _ _ _).mp x.2).choose -/ irreducible_def Span.repr (w : Set M) (x : span R w) : w →₀ R := - ((Finsupp.mem_span_iff_total _ _ _).mp x.2).choose + ((Finsupp.mem_span_iff_linearCombination _ _ _).mp x.2).choose @[simp] -theorem Span.finsupp_total_repr {w : Set M} (x : span R w) : - Finsupp.total w M R (↑) (Span.repr R w x) = x := by +theorem Span.finsupp_linearCombination_repr {w : Set M} (x : span R w) : + Finsupp.linearCombination R ((↑) : w → M) (Span.repr R w x) = x := by rw [Span.repr_def] - exact ((Finsupp.mem_span_iff_total _ _ _).mp x.2).choose_spec + exact ((Finsupp.mem_span_iff_linearCombination _ _ _).mp x.2).choose_spec +@[deprecated (since := "2024-08-29")] alias Span.finsupp_total_repr := + Span.finsupp_linearCombination_repr end protected theorem Submodule.finsupp_sum_mem {ι β : Type*} [Zero β] (S : Submodule R M) (f : ι →₀ β) (g : ι → β → M) (h : ∀ c, f c ≠ 0 → g c (f c) ∈ S) : f.sum g ∈ S := AddSubmonoidClass.finsupp_sum_mem S f g h -theorem LinearMap.map_finsupp_total (f : M →ₗ[R] N) {ι : Type*} {g : ι → M} (l : ι →₀ R) : - f (Finsupp.total ι M R g l) = Finsupp.total ι N R (f ∘ g) l := by +theorem LinearMap.map_finsupp_linearCombination (f : M →ₗ[R] N) {ι : Type*} {g : ι → M} + (l : ι →₀ R) : f (linearCombination R g l) = linearCombination R (f ∘ g) l := by -- Porting note: `(· ∘ ·)` is required. - simp only [Finsupp.total_apply, Finsupp.total_apply, Finsupp.sum, map_sum, map_smul, (· ∘ ·)] + simp only [linearCombination_apply, linearCombination_apply, Finsupp.sum, map_sum, map_smul, + (· ∘ ·)] + +@[deprecated (since := "2024-08-29")] alias LinearMap.map_finsupp_total := + LinearMap.map_finsupp_linearCombination theorem Submodule.exists_finset_of_mem_iSup {ι : Sort _} (p : ι → Submodule R M) {m : M} (hm : m ∈ ⨆ i, p i) : ∃ s : Finset ι, m ∈ ⨆ i ∈ s, p i := by @@ -1168,9 +1263,9 @@ theorem mem_span_finset {s : Finset M} {x : M} : x ∈ span R (↑s : Set M) ↔ ∃ f : M → R, ∑ i ∈ s, f i • i = x := ⟨fun hx => let ⟨v, hvs, hvx⟩ := - (Finsupp.mem_span_image_iff_total _).1 + (Finsupp.mem_span_image_iff_linearCombination _).1 (show x ∈ span R (_root_.id '' (↑s : Set M)) by rwa [Set.image_id]) - ⟨v, hvx ▸ (Finsupp.total_apply_of_mem_supported _ hvs).symm⟩, + ⟨v, hvx ▸ (linearCombination_apply_of_mem_supported _ hvs).symm⟩, fun ⟨f, hf⟩ => hf ▸ sum_mem fun i 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 @@ -1180,7 +1275,7 @@ theorem mem_span_set {m : M} {s : Set M} : m ∈ Submodule.span R s ↔ ∃ c : M →₀ R, (c.support : Set M) ⊆ s ∧ (c.sum fun mi r => r • mi) = m := by conv_lhs => rw [← Set.image_id s] - exact Finsupp.mem_span_image_iff_total R (v := _root_.id (α := M)) + exact Finsupp.mem_span_image_iff_linearCombination R (v := _root_.id (α := M)) /-- 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`. 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/FreeAlgebra.lean b/Mathlib/LinearAlgebra/FreeAlgebra.lean index 5b221a8d639dd..6853792914e06 100644 --- a/Mathlib/LinearAlgebra/FreeAlgebra.lean +++ b/Mathlib/LinearAlgebra/FreeAlgebra.lean @@ -5,6 +5,7 @@ Authors: Eric Wieser -/ import Mathlib.LinearAlgebra.Basis.Cardinality import Mathlib.Algebra.FreeAlgebra +import Mathlib.LinearAlgebra.FreeModule.Basic import Mathlib.LinearAlgebra.FinsuppVectorSpace import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition import Mathlib.LinearAlgebra.Dimension.StrongRankCondition diff --git a/Mathlib/LinearAlgebra/FreeModule/Basic.lean b/Mathlib/LinearAlgebra/FreeModule/Basic.lean index d93fc0610a6b4..ae0a984945266 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Basic.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Basic.lean @@ -13,7 +13,8 @@ import Mathlib.LinearAlgebra.TensorProduct.Basis We introduce a class `Module.Free R M`, for `R` a `Semiring` and `M` an `R`-module and we provide several basic instances for this class. -Use `Finsupp.total_id_surjective` to prove that any module is the quotient of a free module. +Use `Finsupp.linearCombination_id_surjective` to prove that any module is the quotient of a free +module. ## Main definition diff --git a/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean b/Mathlib/LinearAlgebra/FreeModule/Finite/Basic.lean index b79eba46aca11..fd4961dd7d2fc 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] [AddCommGroup 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,17 @@ 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 ι₂] : +instance Module.Finite.matrix {R : Type u} [Semiring R] + {ι₁ ι₂ : Type*} [_root_.Finite ι₁] [_root_.Finite ι₂] : Module.Finite R (Matrix ι₁ ι₂ R) := by cases nonempty_fintype ι₁ cases nonempty_fintype ι₂ exact Module.Finite.of_basis (Pi.basis fun _ => Pi.basisFun R _) - -end CommRing - -end Module.Free diff --git a/Mathlib/LinearAlgebra/FreeModule/Finite/Matrix.lean b/Mathlib/LinearAlgebra/FreeModule/Finite/Matrix.lean index 7be847207c3de..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,25 +46,28 @@ 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 Module.finrank_linear_map' := Module.finrank_linearMap_self + end Ring section AlgHom @@ -81,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..054d145f3347d 100644 --- a/Mathlib/LinearAlgebra/FreeModule/IdealQuotient.lean +++ b/Mathlib/LinearAlgebra/FreeModule/IdealQuotient.lean @@ -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..5332fcc328e26 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Norm.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Norm.lean @@ -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 4d837a3b56384..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. @@ -369,9 +369,8 @@ noncomputable def Module.basisOfFiniteTypeTorsionFree [Fintype ι] {s : ι → M apply this intro i calc - (∏ j, a j) • s i = (∏ j ∈ {i}ᶜ, a j) • a i • s i := by - rw [Fintype.prod_eq_prod_compl_mul i, mul_smul] - _ ∈ N := N.smul_mem _ (ha' i) + (∏ j ∈ {i}ᶜ, a j) • a i • s i ∈ N := N.smul_mem _ (ha' i) + _ = (∏ j, a j) • s i := by rw [Fintype.prod_eq_prod_compl_mul i, mul_smul] -- Since a submodule of a free `R`-module is free, we get that `A • M` is free obtain ⟨n, b : Basis (Fin n) R (LinearMap.range φ)⟩ := Submodule.basisOfPidOfLE this sI_basis 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..1a9f732fb0a95 100644 --- a/Mathlib/LinearAlgebra/InvariantBasisNumber.lean +++ b/Mathlib/LinearAlgebra/InvariantBasisNumber.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.RingTheory.OrzechProperty import Mathlib.RingTheory.Ideal.Quotient @@ -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..54a39b6372052 100644 --- a/Mathlib/LinearAlgebra/Isomorphisms.lean +++ b/Mathlib/LinearAlgebra/Isomorphisms.lean @@ -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. @@ -122,7 +122,7 @@ theorem quotientInfEquivSupQuotient_symm_apply_eq_zero_iff {p p' : Submodule R M (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] + rw [_root_.map_zero, Quotient.mk_eq_zero, mem_comap, Submodule.coe_subtype] 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) diff --git a/Mathlib/LinearAlgebra/JordanChevalley.lean b/Mathlib/LinearAlgebra/JordanChevalley.lean index 76d5f6488464f..b526d14e3ebcd 100644 --- a/Mathlib/LinearAlgebra/JordanChevalley.lean +++ b/Mathlib/LinearAlgebra/JordanChevalley.lean @@ -5,6 +5,7 @@ Authors: Oliver Nash -/ import Mathlib.Dynamics.Newton import Mathlib.LinearAlgebra.Semisimple +import Mathlib.LinearAlgebra.FreeModule.Finite.Matrix /-! # Jordan-Chevalley-Dunford decomposition diff --git a/Mathlib/LinearAlgebra/Lagrange.lean b/Mathlib/LinearAlgebra/Lagrange.lean index d3e6374765d4c..ab7d725e81277 100644 --- a/Mathlib/LinearAlgebra/Lagrange.lean +++ b/Mathlib/LinearAlgebra/Lagrange.lean @@ -145,7 +145,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 @@ -504,8 +504,9 @@ theorem nodal_eq_mul_nodal_erase [DecidableEq ι] {i : ι} (hi : i ∈ s) : nodal s v = (X - C (v i)) * nodal (s.erase i) v := by simp_rw [nodal, Finset.mul_prod_erase _ (fun x => X - C (v x)) hi] -theorem X_sub_C_dvd_nodal (v : ι → R) {i : ι} (hi : i ∈ s) : X - C (v i) ∣ nodal s v := - ⟨_, by classical exact nodal_eq_mul_nodal_erase hi⟩ +theorem X_sub_C_dvd_nodal (v : ι → R) {i : ι} (hi : i ∈ s) : X - C (v i) ∣ nodal s v := by + classical + exact ⟨nodal (s.erase i) v, nodal_eq_mul_nodal_erase hi⟩ theorem nodal_insert_eq_nodal [DecidableEq ι] {i : ι} (hi : i ∉ s) : nodal (insert i s) v = (X - C (v i)) * nodal s v := by diff --git a/Mathlib/LinearAlgebra/LinearDisjoint.lean b/Mathlib/LinearAlgebra/LinearDisjoint.lean index 725d409379f59..f290e4e777d86 100644 --- a/Mathlib/LinearAlgebra/LinearDisjoint.lean +++ b/Mathlib/LinearAlgebra/LinearDisjoint.lean @@ -208,15 +208,15 @@ theorem of_basis_right' {ι : Type*} (n : Basis ι R N) /-- If `{ m_i }` is an `R`-basis of `M`, if `{ n_i }` is an `R`-basis of `N`, such that the family `{ m_i * n_j }` in `S` is `R`-linearly independent -(in this result it is stated as the relevant `Finsupp.total` is injective), +(in this result it is stated as the relevant `Finsupp.linearCombination` is injective), then `M` and `N` are linearly disjoint. -/ theorem of_basis_mul' {κ ι : Type*} (m : Basis κ R M) (n : Basis ι R N) - (H : Function.Injective (Finsupp.total (κ × ι) S R fun i ↦ m i.1 * n i.2)) : + (H : Function.Injective (Finsupp.linearCombination R fun i : κ × ι ↦ (m i.1 * n i.2 : S))) : M.LinearDisjoint N := by let i0 := (finsuppTensorFinsupp' R κ ι).symm let i1 := TensorProduct.congr m.repr n.repr let i := mulMap M N ∘ₗ (i0.trans i1.symm).toLinearMap - have : i = Finsupp.total (κ × ι) S R fun i ↦ m i.1 * n i.2 := by + have : i = Finsupp.linearCombination R fun i : κ × ι ↦ (m i.1 * n i.2 : S) := by ext x simp [i, i0, i1, finsuppTensorFinsupp'_symm_single_eq_single_one_tmul] simp_rw [← this, i, LinearMap.coe_comp, LinearEquiv.coe_coe, EquivLike.injective_comp] at H @@ -311,7 +311,7 @@ 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] + ← Function.comp_assoc, EquivLike.injective_comp] rw [LinearIndependent, LinearMap.ker_eq_bot] at hm exact H.injective.comp (Module.Flat.rTensor_preserves_injective_linearMap (M := N) _ hm) @@ -332,7 +332,7 @@ 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] + ← Function.comp_assoc, EquivLike.injective_comp] rw [LinearIndependent, LinearMap.ker_eq_bot] at hn exact H.injective.comp (Module.Flat.lTensor_preserves_injective_linearMap (M := M) _ hn) @@ -354,13 +354,13 @@ theorem linearIndependent_mul_of_flat_left (H : M.LinearDisjoint N) [Module.Flat (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 ⊢ let i0 := (finsuppTensorFinsupp' R κ ι).symm - let i1 := LinearMap.rTensor (ι →₀ R) (Finsupp.total κ M R m) - let i2 := LinearMap.lTensor M (Finsupp.total ι N R n) + let i1 := LinearMap.rTensor (ι →₀ R) (Finsupp.linearCombination R m) + let i2 := LinearMap.lTensor M (Finsupp.linearCombination R n) let i := mulMap M N ∘ₗ i2 ∘ₗ i1 ∘ₗ i0.toLinearMap have h1 : Function.Injective i1 := Module.Flat.rTensor_preserves_injective_linearMap _ hm have h2 : Function.Injective i2 := Module.Flat.lTensor_preserves_injective_linearMap _ hn have h : Function.Injective i := H.injective.comp h2 |>.comp h1 |>.comp i0.injective - have : i = Finsupp.total (κ × ι) S R fun i ↦ (m i.1).1 * (n i.2).1 := by + have : i = Finsupp.linearCombination R fun i ↦ (m i.1).1 * (n i.2).1 := by ext x simp [i, i0, i1, i2, finsuppTensorFinsupp'_symm_single_eq_single_one_tmul] rwa [this] at h @@ -375,13 +375,13 @@ theorem linearIndependent_mul_of_flat_right (H : M.LinearDisjoint N) [Module.Fla (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 ⊢ let i0 := (finsuppTensorFinsupp' R κ ι).symm - let i1 := LinearMap.lTensor (κ →₀ R) (Finsupp.total ι N R n) - let i2 := LinearMap.rTensor N (Finsupp.total κ M R m) + let i1 := LinearMap.lTensor (κ →₀ R) (Finsupp.linearCombination R n) + let i2 := LinearMap.rTensor N (Finsupp.linearCombination R m) let i := mulMap M N ∘ₗ i2 ∘ₗ i1 ∘ₗ i0.toLinearMap have h1 : Function.Injective i1 := Module.Flat.lTensor_preserves_injective_linearMap _ hn have h2 : Function.Injective i2 := Module.Flat.rTensor_preserves_injective_linearMap _ hm have h : Function.Injective i := H.injective.comp h2 |>.comp h1 |>.comp i0.injective - have : i = Finsupp.total (κ × ι) S R fun i ↦ (m i.1).1 * (n i.2).1 := by + have : i = Finsupp.linearCombination R fun i ↦ (m i.1).1 * (n i.2).1 := by ext x simp [i, i0, i1, i2, finsuppTensorFinsupp'_symm_single_eq_single_one_tmul] rwa [this] at h @@ -477,8 +477,8 @@ theorem not_linearIndependent_pair_of_commute_of_flat_left [Module.Flat R M] have hm : mulRightMap M n m = 0 := by simp [m, n, show _ * _ = _ * _ from hc] rw [← LinearMap.mem_ker, H.linearIndependent_right_of_flat hn, mem_bot] at hm simp only [Fin.isValue, sub_eq_zero, Finsupp.single_eq_single_iff, zero_ne_one, Subtype.mk.injEq, - SetLike.coe_eq_coe, false_and, AddSubmonoid.mk_eq_zero, ZeroMemClass.coe_eq_zero, - false_or, m] at hm + SetLike.coe_eq_coe, false_and, false_or, m] at hm + repeat rw [AddSubmonoid.mk_eq_zero, ZeroMemClass.coe_eq_zero] at hm exact h.ne_zero 0 hm.2 /-- If `M` and `N` are linearly disjoint, if `N` is flat, then any two commutative @@ -493,8 +493,8 @@ theorem not_linearIndependent_pair_of_commute_of_flat_right [Module.Flat R N] have hn : mulLeftMap N m n = 0 := by simp [m, n, show _ * _ = _ * _ from hc] rw [← LinearMap.mem_ker, H.linearIndependent_left_of_flat hm, mem_bot] at hn simp only [Fin.isValue, sub_eq_zero, Finsupp.single_eq_single_iff, zero_ne_one, Subtype.mk.injEq, - SetLike.coe_eq_coe, false_and, AddSubmonoid.mk_eq_zero, ZeroMemClass.coe_eq_zero, - false_or, n] at hn + SetLike.coe_eq_coe, false_and, false_or, n] at hn + repeat rw [AddSubmonoid.mk_eq_zero, ZeroMemClass.coe_eq_zero] at hn exact h.ne_zero 0 hn.2 /-- If `M` and `N` are linearly disjoint, if one of `M` and `N` is flat, then any two commutative @@ -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 e6a3d680dc9fc..9ce4ca2f473b7 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,11 +22,11 @@ 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.total ι M R v) = ⊥`. Here `Finsupp.total` 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.total ι M R v` and some versions with explicitly written -linear combinations. +We define `LinearIndependent R v` as `ker (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 +some versions with explicitly written linear combinations. ## Main definitions All definitions are given for families of vectors, i.e. `v : ι → M` where `M` is the module or @@ -97,7 +98,7 @@ variable (R) (v) /-- `LinearIndependent R v` states the family of vectors `v` is linearly independent over `R`. -/ def LinearIndependent : Prop := - LinearMap.ker (Finsupp.total ι M R v) = ⊥ + LinearMap.ker (Finsupp.linearCombination R v) = ⊥ open Lean PrettyPrinter.Delaborator SubExpr in /-- Delaborator for `LinearIndependent` that suggests pretty printing with type hints @@ -122,7 +123,7 @@ def delabLinearIndependent : Delab := variable {R} {v} theorem linearIndependent_iff : - LinearIndependent R v ↔ ∀ l, Finsupp.total ι M R v l = 0 → l = 0 := by + LinearIndependent R v ↔ ∀ l, Finsupp.linearCombination R v l = 0 → l = 0 := by simp [LinearIndependent, LinearMap.ker_eq_bot'] theorem linearIndependent_iff' : @@ -132,7 +133,7 @@ theorem linearIndependent_iff' : ⟨fun hf s g hg i his => have h := hf (∑ i ∈ s, Finsupp.single i (g i)) <| by - simpa only [map_sum, Finsupp.total_single] using hg + simpa only [map_sum, Finsupp.linearCombination_single] using hg calc g i = (Finsupp.lapply i : (ι →₀ R) →ₗ[R] R) (Finsupp.single i (g i)) := by { rw [Finsupp.lapply_apply, Finsupp.single_eq_same] } @@ -220,7 +221,7 @@ lemma LinearIndependent.pair_iff {x y : M} : linearly independent family. -/ theorem LinearIndependent.comp (h : LinearIndependent R v) (f : ι' → ι) (hf : Injective f) : LinearIndependent R (v ∘ f) := by - rw [linearIndependent_iff, Finsupp.total_comp] + 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 @@ -244,24 +245,24 @@ disjoint with the submodule spanned by the vectors of `v`, then `f ∘ v` is a l family of vectors. See also `LinearIndependent.map'` for a special case assuming `ker f = ⊥`. -/ theorem LinearIndependent.map (hv : LinearIndependent R v) {f : M →ₗ[R] M'} (hf_inj : Disjoint (span R (range v)) (LinearMap.ker f)) : LinearIndependent R (f ∘ v) := by - rw [disjoint_iff_inf_le, ← Set.image_univ, Finsupp.span_image_eq_map_total, + 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 [hv, le_bot_iff] at hf_inj haveI : Inhabited M := ⟨0⟩ - rw [Finsupp.total_comp, Finsupp.lmapDomain_total _ _ f, LinearMap.ker_comp, - hf_inj] + rw [Finsupp.linearCombination_comp, Finsupp.lmapDomain_linearCombination _ _ f, + LinearMap.ker_comp, hf_inj] exact fun _ => rfl -/-- If `v` is an injective family of vectors such that `f ∘ v` is linearly independent, then `v` +/-- If `v` is an injective family of vectors such that `f ∘ v` is linearly independent, then `v` spans a submodule disjoint from the kernel of `f` -/ 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.total_comp, Finsupp.lmapDomain_total R _ f (fun _ ↦ rfl), - LinearMap.ker_comp] at hv - rw [disjoint_iff_inf_le, ← Set.image_univ, Finsupp.span_image_eq_map_total, + rw [LinearIndependent, 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] /-- An injective linear map sends linearly independent families of vectors to linearly independent @@ -406,13 +407,13 @@ section Subtype theorem linearIndependent_comp_subtype {s : Set ι} : LinearIndependent R (v ∘ (↑) : s → M) ↔ - ∀ l ∈ Finsupp.supported R R s, (Finsupp.total ι M R v) l = 0 → l = 0 := by - simp only [linearIndependent_iff, (· ∘ ·), Finsupp.mem_supported, Finsupp.total_apply, + ∀ l ∈ Finsupp.supported R R s, (Finsupp.linearCombination R v) l = 0 → l = 0 := by + simp only [linearIndependent_iff, (· ∘ ·), Finsupp.mem_supported, Finsupp.linearCombination_apply, 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 @@ -423,10 +424,10 @@ theorem linearIndependent_comp_subtype {s : Set ι} : theorem linearDependent_comp_subtype' {s : Set ι} : ¬LinearIndependent R (v ∘ (↑) : s → M) ↔ - ∃ f : ι →₀ R, f ∈ Finsupp.supported R R s ∧ Finsupp.total ι M R v f = 0 ∧ f ≠ 0 := by + ∃ f : ι →₀ R, f ∈ Finsupp.supported R R s ∧ Finsupp.linearCombination R v f = 0 ∧ f ≠ 0 := by simp [linearIndependent_comp_subtype, and_left_comm] -/-- A version of `linearDependent_comp_subtype'` with `Finsupp.total` unfolded. -/ +/-- A version of `linearDependent_comp_subtype'` with `Finsupp.linearCombination` unfolded. -/ theorem linearDependent_comp_subtype {s : Set ι} : ¬LinearIndependent R (v ∘ (↑) : s → M) ↔ ∃ f : ι →₀ R, f ∈ Finsupp.supported R R s ∧ ∑ i ∈ f.support, f i • v i = 0 ∧ f ≠ 0 := @@ -434,25 +435,28 @@ theorem linearDependent_comp_subtype {s : Set ι} : theorem linearIndependent_subtype {s : Set M} : LinearIndependent R (fun x => x : s → M) ↔ - ∀ l ∈ Finsupp.supported R R s, (Finsupp.total M M R id) l = 0 → l = 0 := by + ∀ l ∈ Finsupp.supported R R s, (Finsupp.linearCombination R id) l = 0 → l = 0 := by apply linearIndependent_comp_subtype (v := id) theorem linearIndependent_comp_subtype_disjoint {s : Set ι} : LinearIndependent R (v ∘ (↑) : s → M) ↔ - Disjoint (Finsupp.supported R R s) (LinearMap.ker <| Finsupp.total ι M R v) := by + Disjoint (Finsupp.supported R R s) (LinearMap.ker <| Finsupp.linearCombination R v) := by rw [linearIndependent_comp_subtype, LinearMap.disjoint_ker] theorem linearIndependent_subtype_disjoint {s : Set M} : LinearIndependent R (fun x => x : s → M) ↔ - Disjoint (Finsupp.supported R R s) (LinearMap.ker <| Finsupp.total M M R id) := by + Disjoint (Finsupp.supported R R s) (LinearMap.ker <| Finsupp.linearCombination R id) := by apply linearIndependent_comp_subtype_disjoint (v := id) -theorem linearIndependent_iff_totalOn {s : Set M} : +theorem linearIndependent_iff_linearCombinationOn {s : Set M} : LinearIndependent R (fun x => x : s → M) ↔ - (LinearMap.ker <| Finsupp.totalOn M M R id s) = ⊥ := by - rw [Finsupp.totalOn, LinearMap.ker, LinearMap.comap_codRestrict, Submodule.map_bot, comap_bot, - LinearMap.ker_comp, linearIndependent_subtype_disjoint, disjoint_iff_inf_le, ← - map_comap_subtype, map_le_iff_le_comap, comap_bot, ker_subtype, le_bot_iff] + (LinearMap.ker <| Finsupp.linearCombinationOn M M R id s) = ⊥ := by + rw [Finsupp.linearCombinationOn, LinearMap.ker, LinearMap.comap_codRestrict, Submodule.map_bot, + comap_bot, LinearMap.ker_comp, linearIndependent_subtype_disjoint, disjoint_iff_inf_le, + ← map_comap_subtype, map_le_iff_le_comap, comap_bot, ker_subtype, le_bot_iff] + +@[deprecated (since := "2024-08-29")] alias linearIndependent_iff_totalOn := + linearIndependent_iff_linearCombinationOn theorem LinearIndependent.restrict_of_comp_subtype {s : Set ι} (hs : LinearIndependent R (v ∘ (↑) : s → M)) : LinearIndependent R (s.restrict v) := @@ -515,18 +519,26 @@ 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_total : - LinearIndependent R v ↔ Function.Injective (Finsupp.total ι M R v) := +theorem linearIndependent_iff_injective_linearCombination : + LinearIndependent R v ↔ Function.Injective (Finsupp.linearCombination R v) := linearIndependent_iff.trans - (injective_iff_map_eq_zero (Finsupp.total ι M R v).toAddMonoidHom).symm + (injective_iff_map_eq_zero (Finsupp.linearCombination R v).toAddMonoidHom).symm + +@[deprecated (since := "2024-08-29")] alias linearIndependent_iff_injective_total := + linearIndependent_iff_injective_linearCombination + +alias ⟨LinearIndependent.injective_linearCombination, _⟩ := -alias ⟨LinearIndependent.injective_total, _⟩ := linearIndependent_iff_injective_total + 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.total ι M R v l = 0 := by - simp_rw [l, LinearMap.map_sub, Finsupp.total_apply] + 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 @@ -580,15 +592,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]) @@ -606,8 +616,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 @@ -657,8 +666,8 @@ theorem LinearIndependent.eq_of_smul_apply_eq_smul_apply {M : Type*} [AddCommGro {v : ι → M} (li : LinearIndependent R v) (c d : R) (i j : ι) (hc : c ≠ 0) (h : c • v i = d • v j) : i = j := by let l : ι →₀ R := Finsupp.single i c - Finsupp.single j d - have h_total : Finsupp.total ι M R v l = 0 := by - simp_rw [l, LinearMap.map_sub, Finsupp.total_apply] + have h_total : Finsupp.linearCombination R v l = 0 := by + simp_rw [l, LinearMap.map_sub, Finsupp.linearCombination_apply] simp [h] have h_single_eq : Finsupp.single i c = Finsupp.single j d := by rw [linearIndependent_iff] at li @@ -673,9 +682,9 @@ section Subtype theorem LinearIndependent.disjoint_span_image (hv : LinearIndependent R v) {s t : Set ι} (hs : Disjoint s t) : Disjoint (Submodule.span R <| v '' s) (Submodule.span R <| v '' t) := by - simp only [disjoint_def, Finsupp.mem_span_image_iff_total] + simp only [disjoint_def, Finsupp.mem_span_image_iff_linearCombination] rintro _ ⟨l₁, hl₁, rfl⟩ ⟨l₂, hl₂, H⟩ - rw [hv.injective_total.eq_iff] at H; subst l₂ + rw [hv.injective_linearCombination.eq_iff] at H; subst l₂ have : l₁ = 0 := Submodule.disjoint_def.mp (Finsupp.disjoint_supported_supported hs) _ hl₁ hl₂ simp [this] @@ -689,16 +698,20 @@ theorem LinearIndependent.not_mem_span_image [Nontrivial R] (hv : LinearIndepend refine disjoint_def.1 (hv.disjoint_span_image ?_) (v x) h' w simpa using h -theorem LinearIndependent.total_ne_of_not_mem_support [Nontrivial R] (hv : LinearIndependent R v) - {x : ι} (f : ι →₀ R) (h : x ∉ f.support) : Finsupp.total ι M R v f ≠ v x := by +theorem LinearIndependent.linearCombination_ne_of_not_mem_support [Nontrivial R] + (hv : LinearIndependent R v) {x : ι} (f : ι →₀ R) (h : x ∉ f.support) : + Finsupp.linearCombination R v f ≠ v x := by replace h : x ∉ (f.support : Set ι) := h have p := hv.not_mem_span_image h intro w rw [← w] at p - rw [Finsupp.span_image_eq_map_total] at p + rw [Finsupp.span_image_eq_map_linearCombination] at p simp only [not_exists, not_and, mem_map] at p -- Porting note: `mem_map` isn't currently triggered exact p f (f.mem_supported_support R) rfl +@[deprecated (since := "2024-08-29")] alias LinearIndependent.total_ne_of_not_mem_support := + LinearIndependent.linearCombination_ne_of_not_mem_support + theorem linearIndependent_sum {v : ι ⊕ ι' → M} : LinearIndependent R v ↔ LinearIndependent R (v ∘ Sum.inl) ∧ @@ -801,41 +814,54 @@ variable (hv : LinearIndependent R v) /-- Canonical isomorphism between linear combinations and the span of linearly independent vectors. -/ @[simps (config := { rhsMd := default }) symm_apply] -def LinearIndependent.totalEquiv (hv : LinearIndependent R v) : +def LinearIndependent.linearCombinationEquiv (hv : LinearIndependent R v) : (ι →₀ R) ≃ₗ[R] span R (range v) := by - apply LinearEquiv.ofBijective (LinearMap.codRestrict (span R (range v)) (Finsupp.total ι M R v) _) + apply LinearEquiv.ofBijective (LinearMap.codRestrict (span R (range v)) + (Finsupp.linearCombination R v) _) constructor · rw [← LinearMap.ker_eq_bot, LinearMap.ker_codRestrict] · apply hv · intro l - rw [← Finsupp.range_total] + rw [← Finsupp.range_linearCombination] rw [LinearMap.mem_range] apply mem_range_self l · rw [← LinearMap.range_eq_top, LinearMap.range_eq_map, LinearMap.map_codRestrict, ← LinearMap.range_le_iff_comap, range_subtype, Submodule.map_top] - rw [Finsupp.range_total] + rw [Finsupp.range_linearCombination] + +@[deprecated (since := "2024-08-29")] noncomputable alias LinearIndependent.totalEquiv := + LinearIndependent.linearCombinationEquiv -- Porting note: The original theorem generated by `simps` was -- different from the theorem on Lean 3, and not simp-normal form. @[simp] -theorem LinearIndependent.totalEquiv_apply_coe (hv : LinearIndependent R v) (l : ι →₀ R) : - hv.totalEquiv l = Finsupp.total ι M R v l := rfl +theorem LinearIndependent.linearCombinationEquiv_apply_coe (hv : LinearIndependent R v) + (l : ι →₀ R) : hv.linearCombinationEquiv l = Finsupp.linearCombination R v l := rfl +@[deprecated (since := "2024-08-29")] alias LinearIndependent.totalEquiv_apply_coe := + LinearIndependent.linearCombinationEquiv_apply_coe /-- Linear combination representing a vector in the span of linearly independent vectors. Given a family of linearly independent vectors, we can represent any vector in their span as a linear combination of these vectors. These are provided by this linear map. -It is simply one direction of `LinearIndependent.total_equiv`. -/ +It is simply one direction of `LinearIndependent.linearCombinationEquiv`. -/ def LinearIndependent.repr (hv : LinearIndependent R v) : span R (range v) →ₗ[R] ι →₀ R := - hv.totalEquiv.symm + hv.linearCombinationEquiv.symm @[simp] -theorem LinearIndependent.total_repr (x) : Finsupp.total ι M R v (hv.repr x) = x := - Subtype.ext_iff.1 (LinearEquiv.apply_symm_apply hv.totalEquiv x) +theorem LinearIndependent.linearCombination_repr (x) : + Finsupp.linearCombination R v (hv.repr x) = x := + Subtype.ext_iff.1 (LinearEquiv.apply_symm_apply hv.linearCombinationEquiv x) + +@[deprecated (since := "2024-08-29")] alias LinearIndependent.total_repr := + LinearIndependent.linearCombination_repr -theorem LinearIndependent.total_comp_repr : - (Finsupp.total ι M R v).comp hv.repr = Submodule.subtype _ := - LinearMap.ext <| hv.total_repr +theorem LinearIndependent.linearCombination_comp_repr : + (Finsupp.linearCombination R v).comp hv.repr = Submodule.subtype _ := + LinearMap.ext <| hv.linearCombination_repr + +@[deprecated (since := "2024-08-29")] alias LinearIndependent.total_comp_repr := + LinearIndependent.linearCombination_comp_repr theorem LinearIndependent.repr_ker : LinearMap.ker hv.repr = ⊥ := by rw [LinearIndependent.repr, LinearEquiv.ker] @@ -844,22 +870,22 @@ theorem LinearIndependent.repr_range : LinearMap.range hv.repr = ⊤ := by rw [LinearIndependent.repr, LinearEquiv.range] theorem LinearIndependent.repr_eq {l : ι →₀ R} {x : span R (range v)} - (eq : Finsupp.total ι M R v l = ↑x) : hv.repr x = l := by + (eq : Finsupp.linearCombination R v l = ↑x) : hv.repr x = l := by have : - ↑((LinearIndependent.totalEquiv hv : (ι →₀ R) →ₗ[R] span R (range v)) l) = - Finsupp.total ι M R v l := + ↑((LinearIndependent.linearCombinationEquiv hv : (ι →₀ R) →ₗ[R] span R (range v)) l) = + Finsupp.linearCombination R v l := rfl - have : (LinearIndependent.totalEquiv hv : (ι →₀ R) →ₗ[R] span R (range v)) l = x := by + have : (LinearIndependent.linearCombinationEquiv hv : (ι →₀ R) →ₗ[R] span R (range v)) l = x := by rw [eq] at this exact Subtype.ext_iff.2 this - rw [← LinearEquiv.symm_apply_apply hv.totalEquiv l] + rw [← LinearEquiv.symm_apply_apply hv.linearCombinationEquiv l] rw [← this] rfl theorem LinearIndependent.repr_eq_single (i) (x : span R (range v)) (hx : ↑x = v i) : hv.repr x = Finsupp.single i 1 := by apply hv.repr_eq - simp [Finsupp.total_single, hx] + simp [Finsupp.linearCombination_single, hx] theorem LinearIndependent.span_repr_eq [Nontrivial R] (x) : Span.repr R (Set.range v) x = @@ -867,17 +893,18 @@ theorem LinearIndependent.span_repr_eq [Nontrivial R] (x) : have p : (Span.repr R (Set.range v) x).equivMapDomain (Equiv.ofInjective _ hv.injective).symm = hv.repr x := by - apply (LinearIndependent.totalEquiv hv).injective + apply (LinearIndependent.linearCombinationEquiv hv).injective ext - simp only [LinearIndependent.totalEquiv_apply_coe, Equiv.self_comp_ofInjective_symm, - LinearIndependent.total_repr, Finsupp.total_equivMapDomain, Span.finsupp_total_repr] + simp only [LinearIndependent.linearCombinationEquiv_apply_coe, Equiv.self_comp_ofInjective_symm, + LinearIndependent.linearCombination_repr, Finsupp.linearCombination_equivMapDomain, + Span.finsupp_linearCombination_repr] ext ⟨_, ⟨i, rfl⟩⟩ simp [← p] theorem linearIndependent_iff_not_smul_mem_span : LinearIndependent R v ↔ ∀ (i : ι) (a : R), a • v i ∈ span R (v '' (univ \ {i})) → a = 0 := ⟨fun hv i a ha => by - rw [Finsupp.span_image_eq_map_total, mem_map] at ha + rw [Finsupp.span_image_eq_map_linearCombination, mem_map] at ha rcases ha with ⟨l, hl, e⟩ rw [sub_eq_zero.1 (linearIndependent_iff.1 hv (l - Finsupp.single i a) (by simp [e]))] at hl by_contra hn @@ -886,7 +913,7 @@ theorem linearIndependent_iff_not_smul_mem_span : ext i; simp only [Finsupp.zero_apply] by_contra hn refine hn (H i _ ?_) - refine (Finsupp.mem_span_image_iff_total R).2 ⟨Finsupp.single i (l i) - l, ?_, ?_⟩ + refine (Finsupp.mem_span_image_iff_linearCombination R).2 ⟨Finsupp.single i (l i) - l, ?_, ?_⟩ · rw [Finsupp.mem_supported'] intro j hj have hij : j = i := @@ -979,13 +1006,14 @@ theorem surjective_of_linearIndependent_of_span [Nontrivial R] (hv : LinearIndep intro i let repr : (span R (range (v ∘ f)) : Type _) → ι' →₀ R := (hv.comp f f.injective).repr let l := (repr ⟨v i, hss (mem_range_self i)⟩).mapDomain f - have h_total_l : Finsupp.total ι M R v l = v i := by + have h_total_l : Finsupp.linearCombination R v l = v i := by dsimp only [l] - rw [Finsupp.total_mapDomain] - rw [(hv.comp f f.injective).total_repr] + rw [Finsupp.linearCombination_mapDomain] + rw [(hv.comp f f.injective).linearCombination_repr] -- Porting note: `rfl` isn't necessary. - have h_total_eq : (Finsupp.total ι M R v) l = (Finsupp.total ι M R v) (Finsupp.single i 1) := by - rw [h_total_l, Finsupp.total_single, one_smul] + 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 dsimp only [l] at l_eq rw [← Finsupp.embDomain_eq_mapDomain] at l_eq @@ -1000,7 +1028,7 @@ theorem eq_of_linearIndependent_of_span_subtype [Nontrivial R] {s t : Set M} ⟨fun x => ⟨x.1, h x.2⟩, fun a b hab => Subtype.coe_injective (Subtype.mk.inj hab)⟩ have h_surj : Surjective f := by apply surjective_of_linearIndependent_of_span hs f _ - convert hst <;> simp [f, comp] + convert hst <;> simp [f, comp_def] show s = t apply Subset.antisymm _ h intro x hx @@ -1082,11 +1110,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 @@ -1164,7 +1191,7 @@ variable {v : ι → M} {s t : Set M} {x y z : M} theorem linearIndependent_unique_iff (v : ι → M) [Unique ι] : LinearIndependent R v ↔ v default ≠ 0 := by - simp only [linearIndependent_iff, Finsupp.total_unique, smul_eq_zero] + simp only [linearIndependent_iff, Finsupp.linearCombination_unique, smul_eq_zero] refine ⟨fun h hv => ?_, fun hv l hl => Finsupp.unique_ext <| hl.resolve_right hv⟩ have := h (Finsupp.single default 1) (Or.inr hv) exact one_ne_zero (Finsupp.single_eq_zero.1 this) @@ -1202,7 +1229,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 @@ -1225,7 +1252,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⟩⟩ @@ -1250,7 +1277,7 @@ theorem linearIndependent_insert' {ι} {s : Set ι} {a : ι} {f : ι → V} (has linearIndependent_option] -- Porting note: `simp [(· ∘ ·), range_comp f]` → `simp [(· ∘ ·)]; erw [range_comp f ..]; simp` -- https://github.com/leanprover-community/mathlib4/issues/5164 - simp only [(· ∘ ·)] + simp only [Function.comp_def] erw [range_comp f ((↑) : s → ι)] simp @@ -1276,8 +1303,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) ↔ @@ -1374,6 +1401,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..bae8ae629f0f7 100644 --- a/Mathlib/LinearAlgebra/LinearPMap.lean +++ b/Mathlib/LinearAlgebra/LinearPMap.lean @@ -847,7 +847,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/Adjugate.lean b/Mathlib/LinearAlgebra/Matrix/Adjugate.lean index 86afb594ac8cb..ef3a1b2ec6823 100644 --- a/Mathlib/LinearAlgebra/Matrix/Adjugate.lean +++ b/Mathlib/LinearAlgebra/Matrix/Adjugate.lean @@ -158,7 +158,7 @@ theorem cramer_submatrix_equiv (A : Matrix m m α) (e : n ≃ m) (b : n → α) cramer (A.submatrix e e) b = cramer A (b ∘ e.symm) ∘ e := by ext i simp_rw [Function.comp_apply, cramer_apply, updateColumn_submatrix_equiv, - det_submatrix_equiv_self e, Function.comp] + det_submatrix_equiv_self e, Function.comp_def] theorem cramer_reindex (e : m ≃ n) (A : Matrix m m α) (b : n → α) : cramer (reindex e e A) b = cramer A (b ∘ e) ∘ e.symm := @@ -256,7 +256,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 +495,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..f6e6c15a38732 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 diff --git a/Mathlib/LinearAlgebra/Matrix/Block.lean b/Mathlib/LinearAlgebra/Matrix/Block.lean index c998bad25a879..8432d56b10b42 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) := diff --git a/Mathlib/LinearAlgebra/Matrix/Charpoly/Basic.lean b/Mathlib/LinearAlgebra/Matrix/Charpoly/Basic.lean index cffadee4baad5..83b4e6ed3bec2 100644 --- a/Mathlib/LinearAlgebra/Matrix/Charpoly/Basic.lean +++ b/Mathlib/LinearAlgebra/Matrix/Charpoly/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.LinearAlgebra.Matrix.Adjugate import Mathlib.RingTheory.PolynomialAlgebra diff --git a/Mathlib/LinearAlgebra/Matrix/Charpoly/Coeff.lean b/Mathlib/LinearAlgebra/Matrix/Charpoly/Coeff.lean index 3b0529e1973d4..4a0d9f53997f4 100644 --- a/Mathlib/LinearAlgebra/Matrix/Charpoly/Coeff.lean +++ b/Mathlib/LinearAlgebra/Matrix/Charpoly/Coeff.lean @@ -150,7 +150,7 @@ theorem matPolyEquiv_symm_map_eval (M : (Matrix n n R)[X]) (r : R) : DFunLike.congr_fun this M ext : 1 · ext M : 1 - simp [Function.comp] + simp [Function.comp_def] · simp [smul_eq_diagonal_mul] theorem matPolyEquiv_eval_eq_map (M : Matrix n n R[X]) (r : R) : @@ -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] @@ -298,7 +298,6 @@ end Ideal section reverse -open Polynomial open LaurentPolynomial hiding C /-- The reverse of the characteristic polynomial of a matrix. @@ -327,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 45a4644bc6fc5..73a35fa98fa85 100644 --- a/Mathlib/LinearAlgebra/Matrix/Charpoly/LinearMap.lean +++ b/Mathlib/LinearAlgebra/Matrix/Charpoly/LinearMap.lean @@ -28,41 +28,41 @@ variable (b : ι → M) open Polynomial Matrix /-- The composition of a matrix (as an endomorphism of `ι → R`) with the projection -`(ι → R) →ₗ[R] M`. -/ +`(ι → R) →ₗ[R] M`. -/ def PiToModule.fromMatrix [DecidableEq ι] : Matrix ι ι R →ₗ[R] (ι → R) →ₗ[R] M := - (LinearMap.llcomp R _ _ _ (Fintype.total R R b)).comp algEquivMatrix'.symm.toLinearMap + (LinearMap.llcomp R _ _ _ (Fintype.linearCombination R R b)).comp algEquivMatrix'.symm.toLinearMap theorem PiToModule.fromMatrix_apply [DecidableEq ι] (A : Matrix ι ι R) (w : ι → R) : - PiToModule.fromMatrix R b A w = Fintype.total R R b (A *ᵥ w) := + PiToModule.fromMatrix R b A w = Fintype.linearCombination R R b (A *ᵥ w) := rfl theorem PiToModule.fromMatrix_apply_single_one [DecidableEq ι] (A : Matrix ι ι R) (j : ι) : PiToModule.fromMatrix R b A (Pi.single j 1) = ∑ i : ι, A i j • b i := by - rw [PiToModule.fromMatrix_apply, Fintype.total_apply, Matrix.mulVec_single] + rw [PiToModule.fromMatrix_apply, Fintype.linearCombination_apply, Matrix.mulVec_single] simp_rw [mul_one] /-- The endomorphisms of `M` acts on `(ι → R) →ₗ[R] M`, and takes the projection to a `(ι → R) →ₗ[R] M`. -/ def PiToModule.fromEnd : Module.End R M →ₗ[R] (ι → R) →ₗ[R] M := - LinearMap.lcomp _ _ (Fintype.total R R b) + LinearMap.lcomp _ _ (Fintype.linearCombination R R b) theorem PiToModule.fromEnd_apply (f : Module.End R M) (w : ι → R) : - PiToModule.fromEnd R b f w = f (Fintype.total R R b w) := + PiToModule.fromEnd R b f w = f (Fintype.linearCombination R R b w) := rfl theorem PiToModule.fromEnd_apply_single_one [DecidableEq ι] (f : Module.End R M) (i : ι) : PiToModule.fromEnd R b f (Pi.single i 1) = f (b i) := by rw [PiToModule.fromEnd_apply] congr - convert Fintype.total_apply_single (S := R) R b i (1 : R) + convert Fintype.linearCombination_apply_single (S := R) R b i (1 : R) rw [one_smul] theorem PiToModule.fromEnd_injective (hb : Submodule.span R (Set.range b) = ⊤) : Function.Injective (PiToModule.fromEnd R b) := by intro x y e ext m - obtain ⟨m, rfl⟩ : m ∈ LinearMap.range (Fintype.total R R b) := by - rw [(Fintype.range_total R b).trans hb] + obtain ⟨m, rfl⟩ : m ∈ LinearMap.range (Fintype.linearCombination R R b) := by + rw [(Fintype.range_linearCombination R b).trans hb] exact Submodule.mem_top exact (LinearMap.congr_fun e m : _) @@ -71,18 +71,19 @@ section variable {R} [DecidableEq ι] /-- We say that a matrix represents an endomorphism of `M` if the matrix acting on `ι → R` is -equal to `f` via the projection `(ι → R) →ₗ[R] M` given by a fixed (spanning) set. -/ +equal to `f` via the projection `(ι → R) →ₗ[R] M` given by a fixed (spanning) set. -/ def Matrix.Represents (A : Matrix ι ι R) (f : Module.End R M) : Prop := PiToModule.fromMatrix R b A = PiToModule.fromEnd R b f variable {b} theorem Matrix.Represents.congr_fun {A : Matrix ι ι R} {f : Module.End R M} (h : A.Represents b f) - (x) : Fintype.total R R b (A *ᵥ x) = f (Fintype.total R R b x) := + (x) : Fintype.linearCombination R R b (A *ᵥ x) = f (Fintype.linearCombination R R b x) := LinearMap.congr_fun h x theorem Matrix.represents_iff {A : Matrix ι ι R} {f : Module.End R M} : - A.Represents b f ↔ ∀ x, Fintype.total R R b (A *ᵥ x) = f (Fintype.total R R b x) := + A.Represents b f ↔ + ∀ x, Fintype.linearCombination R R b (A *ᵥ x) = f (Fintype.linearCombination R R b x) := ⟨fun e x => e.congr_fun x, fun H => LinearMap.ext fun x => H x⟩ theorem Matrix.represents_iff' {A : Matrix ι ι R} {f : Module.End R M} : diff --git a/Mathlib/LinearAlgebra/Matrix/Charpoly/Univ.lean b/Mathlib/LinearAlgebra/Matrix/Charpoly/Univ.lean index 060c707fa9548..4f8c88911dcd1 100644 --- a/Mathlib/LinearAlgebra/Matrix/Charpoly/Univ.lean +++ b/Mathlib/LinearAlgebra/Matrix/Charpoly/Univ.lean @@ -17,7 +17,7 @@ and hence has coefficients that are multivariate polynomials. It is universal in the sense that one obtains the characteristic polynomial of a matrix `M` by evaluating the coefficients of `univ` at the entries of `M`. -We use it to show that the coeffients of the characteristic polynomial +We use it to show that the coefficients of the characteristic polynomial of a matrix are homogeneous polynomials in the matrix entries. ## Main results diff --git a/Mathlib/LinearAlgebra/Matrix/Determinant/Basic.lean b/Mathlib/LinearAlgebra/Matrix/Determinant/Basic.lean index bed32a8a62a86..c33327a8858ae 100644 --- a/Mathlib/LinearAlgebra/Matrix/Determinant/Basic.lean +++ b/Mathlib/LinearAlgebra/Matrix/Determinant/Basic.lean @@ -136,7 +136,7 @@ theorem det_mul (M N : Matrix n n R) : det (M * N) = det M * det N := ∑ σ : 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) + det_mul_aux <| by 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 +183,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. -/ @@ -747,7 +747,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] @@ -760,10 +760,10 @@ theorem det_fin_three (A : Matrix (Fin 3) (Fin 3) R) : A 0 0 * A 1 1 * A 2 2 - A 0 0 * A 1 2 * A 2 1 - A 0 1 * A 1 0 * A 2 2 + A 0 1 * A 1 2 * A 2 0 + A 0 2 * A 1 0 * A 2 1 - A 0 2 * A 1 1 * A 2 0 := by - simp only [det_succ_row_zero, Nat.odd_iff_not_even, submatrix_apply, Fin.succ_zero_eq_one, + 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/DotProduct.lean b/Mathlib/LinearAlgebra/Matrix/DotProduct.lean index a549bac8773ce..d943a52a81685 100644 --- a/Mathlib/LinearAlgebra/Matrix/DotProduct.lean +++ b/Mathlib/LinearAlgebra/Matrix/DotProduct.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Patrick Massot, Casper Putz, Anne Baanen -/ import Mathlib.Algebra.Ring.Regular -import Mathlib.Algebra.Star.Order +import Mathlib.Algebra.Order.Star.Basic import Mathlib.Data.Matrix.Basic import Mathlib.LinearAlgebra.StdBasis import Mathlib.Algebra.Order.BigOperators.Group.Finset diff --git a/Mathlib/LinearAlgebra/Matrix/GeneralLinearGroup/Card.lean b/Mathlib/LinearAlgebra/Matrix/GeneralLinearGroup/Card.lean index 2e1d5ed83ed2b..d7867798bc310 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,8 +38,8 @@ 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.total_fin_zero, ker_zero, card_ofSubsingleton, - Finset.univ_eq_empty, Finset.prod_empty] + | zero => simp only [LinearIndependent, 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 }) : card ((Submodule.span K (Set.range (s : Fin k → V)))ᶜ : Set (V)) = @@ -64,7 +64,7 @@ local notation "q" => Fintype.card 𝔽 variable (n : ℕ) /-- Equivalence between `GL n F` and `n` vectors of length `n` that are linearly independent. Given -by sending a matrix to its coloumns. -/ +by sending a matrix to its columns. -/ noncomputable def equiv_GL_linearindependent (hn : 0 < n) : GL (Fin n) 𝔽 ≃ { s : Fin n → Fin n → 𝔽 // LinearIndependent 𝔽 s } where toFun M := ⟨transpose M, by @@ -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 301e6932dcf83..5ae49bf1b77c9 100644 --- a/Mathlib/LinearAlgebra/Matrix/GeneralLinearGroup/Defs.lean +++ b/Mathlib/LinearAlgebra/Matrix/GeneralLinearGroup/Defs.lean @@ -37,7 +37,7 @@ open LinearMap attribute [-instance] SpecialLinearGroup.instCoeFun /-- `GL n R` is the group of `n` by `n` `R`-matrices with unit determinant. -Defined as a subtype of matrices-/ +Defined as a subtype of matrices -/ abbrev GeneralLinearGroup (n : Type u) (R : Type v) [DecidableEq n] [Fintype n] [CommRing R] : Type _ := (Matrix n n R)ˣ @@ -69,7 +69,7 @@ def det : GL n R →* Rˣ where map_one' := Units.ext det_one map_mul' A B := Units.ext <| det_mul _ _ -/-- The `GL n R` and `Matrix.GeneralLinearGroup R n` groups are multiplicatively equivalent-/ +/-- The `GL n R` and `Matrix.GeneralLinearGroup R n` groups are multiplicatively equivalent -/ def toLin : GL n R ≃* LinearMap.GeneralLinearGroup R (n → R) := Units.mapEquiv toLinAlgEquiv'.toMulEquiv @@ -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/HermitianFunctionalCalculus.lean b/Mathlib/LinearAlgebra/Matrix/HermitianFunctionalCalculus.lean index aedad97e0580a..ff884d2e289ad 100644 --- a/Mathlib/LinearAlgebra/Matrix/HermitianFunctionalCalculus.lean +++ b/Mathlib/LinearAlgebra/Matrix/HermitianFunctionalCalculus.lean @@ -7,7 +7,7 @@ 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 /-! # Continuous Functional Calculus for Hermitian Matrices @@ -76,7 +76,7 @@ noncomputable def cfcAux : C(spectrum ℝ A, ℝ) →⋆ₐ[ℝ] (Matrix n n congr! with i simp commutes' r := by - simp only [Function.comp, algebraMap_apply, smul_eq_mul, mul_one] + simp only [Function.comp_def, algebraMap_apply, smul_eq_mul, mul_one] rw [← mul_one (algebraMap _ _ _), ← unitary.coe_mul_star_self hA.eigenvectorUnitary, ← Algebra.left_comm, unitary.coe_star, mul_assoc] congr! @@ -134,7 +134,7 @@ instance instContinuousFunctionalCalculus : simp only [isSelfAdjoint_iff, cfcAux_apply, mul_assoc, star_mul, star_star] rw [star_eq_conjTranspose, diagonal_conjTranspose] congr! - simp [Pi.star_def, Function.comp] + simp [Pi.star_def, Function.comp_def] predicate_zero := .zero _ instance instUniqueContinuousFunctionalCalculus : @@ -157,7 +157,8 @@ lemma cfc_eq (f : ℝ → ℝ) : cfc f A = hA.cfc f := by have := cfcHom_eq_of_continuous_of_map_id hA' hA.cfcAux hA.closedEmbedding_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, Set.restrict_apply, IsHermitian.cfc] + simp only [cfcAux_apply, ContinuousMap.coe_mk, Function.comp_def, Set.restrict_apply, + IsHermitian.cfc] end IsHermitian end Matrix 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/LDL.lean b/Mathlib/LinearAlgebra/Matrix/LDL.lean index 46bbe801bd60b..277c2bddd5c89 100644 --- a/Mathlib/LinearAlgebra/Matrix/LDL.lean +++ b/Mathlib/LinearAlgebra/Matrix/LDL.lean @@ -107,7 +107,7 @@ noncomputable def LDL.lower := (LDL.lowerInv hS)⁻¹ /-- **LDL decomposition**: any positive definite matrix `S` can be -decomposed as `S = LDLᴴ` where `L` is a lower-triangular matrix and `D` is a diagonal matrix. -/ +decomposed as `S = LDLᴴ` where `L` is a lower-triangular matrix and `D` is a diagonal matrix. -/ theorem LDL.lower_conj_diag : LDL.lower hS * LDL.diag hS * (LDL.lower hS)ᴴ = S := by rw [LDL.lower, conjTranspose_nonsing_inv, Matrix.mul_assoc, Matrix.inv_mul_eq_iff_eq_mul_of_invertible (LDL.lowerInv hS), 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 5aee7b5572d59..9343bc8070623 100644 --- a/Mathlib/LinearAlgebra/Matrix/PosDef.lean +++ b/Mathlib/LinearAlgebra/Matrix/PosDef.lean @@ -18,7 +18,7 @@ of quadratic forms. Most results require `𝕜 = ℝ` or `ℂ`. * `Matrix.PosSemidef` : a matrix `M : Matrix n n 𝕜` is positive semidefinite if it is hermitian and `xᴴMx` is nonnegative for all `x`. -## Main results +## Main results * `Matrix.posSemidef_iff_eq_transpose_mul_self` : a matrix `M : Matrix n n 𝕜` is positive semidefinite iff it has the form `Bᴴ * B` for some `B`. @@ -263,7 +263,7 @@ theorem posSemidef_submatrix_equiv {M : Matrix n n R} (e : m ≃ n) : (M.submatrix e e).PosSemidef ↔ M.PosSemidef := ⟨fun h => by simpa using h.submatrix e.symm, fun h => h.submatrix _⟩ -/-- The conjugate transpose of a matrix mulitplied by the matrix is positive semidefinite -/ +/-- The conjugate transpose of a matrix multiplied by the matrix is positive semidefinite -/ theorem posSemidef_conjTranspose_mul_self [StarOrderedRing R] (A : Matrix m n R) : PosSemidef (Aᴴ * A) := by refine ⟨isHermitian_transpose_mul_self _, fun x => ?_⟩ @@ -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/SchurComplement.lean b/Mathlib/LinearAlgebra/Matrix/SchurComplement.lean index 03ef3530c8616..3c18c28e836bd 100644 --- a/Mathlib/LinearAlgebra/Matrix/SchurComplement.lean +++ b/Mathlib/LinearAlgebra/Matrix/SchurComplement.lean @@ -27,8 +27,8 @@ Compare with `Matrix.invertibleOfFromBlocks₁₁Invertible`. block triangular matrix. * `Matrix.det_one_add_mul_comm`: the **Weinstein–Aronszajn identity**. * `Matrix.PosSemidef.fromBlocks₁₁` and `Matrix.PosSemidef.fromBlocks₂₂`: If a matrix `A` is - positive definite, then `[A B; Bᴴ D]` is postive semidefinite if and only if `D - Bᴴ A⁻¹ B` is - postive semidefinite. + positive definite, then `[A B; Bᴴ D]` is positive semidefinite if and only if `D - Bᴴ A⁻¹ B` is + positive semidefinite. -/ @@ -53,8 +53,8 @@ theorem fromBlocks_eq_of_invertible₁₁ (A : Matrix m m α) (B : Matrix m n α fromBlocks 1 0 (C * ⅟ A) 1 * fromBlocks A 0 0 (D - C * ⅟ A * B) * fromBlocks 1 (⅟ A * B) 0 1 := by simp only [fromBlocks_multiply, Matrix.mul_zero, Matrix.zero_mul, add_zero, zero_add, - Matrix.one_mul, Matrix.mul_one, invOf_mul_self, Matrix.mul_invOf_self_assoc, - Matrix.mul_invOf_mul_self_cancel, Matrix.mul_assoc, add_sub_cancel] + Matrix.one_mul, Matrix.mul_one, invOf_mul_self, Matrix.mul_invOf_cancel_left, + Matrix.invOf_mul_cancel_right, Matrix.mul_assoc, add_sub_cancel] /-- LDU decomposition of a block matrix with an invertible bottom-right corner, using the Schur complement. -/ @@ -78,7 +78,7 @@ def fromBlocksZero₂₁Invertible (A : Matrix m m α) (B : Matrix m n α) (D : [Invertible A] [Invertible D] : Invertible (fromBlocks A B 0 D) := invertibleOfLeftInverse _ (fromBlocks (⅟ A) (-(⅟ A * B * ⅟ D)) 0 (⅟ D)) <| by simp_rw [fromBlocks_multiply, Matrix.mul_zero, Matrix.zero_mul, zero_add, add_zero, - Matrix.neg_mul, invOf_mul_self, Matrix.mul_invOf_mul_self_cancel, add_neg_cancel, + Matrix.neg_mul, invOf_mul_self, Matrix.invOf_mul_cancel_right, add_neg_cancel, fromBlocks_one] /-- A lower-block-triangular matrix is invertible if its diagonal is. -/ @@ -88,7 +88,7 @@ def fromBlocksZero₁₂Invertible (A : Matrix m m α) (C : Matrix n m α) (D : (fromBlocks (⅟ A) 0 (-(⅟ D * C * ⅟ A)) (⅟ D)) <| by -- a symmetry argument is more work than just copying the proof simp_rw [fromBlocks_multiply, Matrix.mul_zero, Matrix.zero_mul, zero_add, add_zero, - Matrix.neg_mul, invOf_mul_self, Matrix.mul_invOf_mul_self_cancel, neg_add_cancel, + Matrix.neg_mul, invOf_mul_self, Matrix.invOf_mul_cancel_right, neg_add_cancel, fromBlocks_one] theorem invOf_fromBlocks_zero₂₁_eq (A : Matrix m m α) (B : Matrix m n α) (D : Matrix n n α) @@ -224,7 +224,7 @@ end Triangular section Block -/-! #### General 2×2 block matrices-/ +/-! #### General 2×2 block matrices -/ /-- A block matrix is invertible if the bottom right corner and the corresponding schur complement diff --git a/Mathlib/LinearAlgebra/Matrix/SesquilinearForm.lean b/Mathlib/LinearAlgebra/Matrix/SesquilinearForm.lean index 44fdd5263d583..8e620f838f3f0 100644 --- a/Mathlib/LinearAlgebra/Matrix/SesquilinearForm.lean +++ b/Mathlib/LinearAlgebra/Matrix/SesquilinearForm.lean @@ -485,7 +485,7 @@ end end ToMatrix -/-! ### Adjoint pairs-/ +/-! ### Adjoint pairs -/ section MatrixAdjoints @@ -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] @@ -623,7 +622,7 @@ end MatrixAdjoints namespace LinearMap -/-! ### Nondegenerate bilinear forms-/ +/-! ### Nondegenerate bilinear forms -/ section Det diff --git a/Mathlib/LinearAlgebra/Matrix/SpecialLinearGroup.lean b/Mathlib/LinearAlgebra/Matrix/SpecialLinearGroup.lean index bf7e0f5c040f9..261b976d62a38 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⟩ @@ -285,7 +288,7 @@ def center_equiv_rootsOfUnity' (i : n) : map_mul' A B := by dsimp ext - simp only [Submonoid.coe_mul, coe_mul, rootsOfUnity.val_mkOfPowEq_coe, Units.val_mul] + simp only [rootsOfUnity.val_mkOfPowEq_coe, Subgroup.coe_mul, Units.val_mul] rw [← scalar_eq_coe_self_center A i, ← scalar_eq_coe_self_center B i] simp diff --git a/Mathlib/LinearAlgebra/Matrix/Spectrum.lean b/Mathlib/LinearAlgebra/Matrix/Spectrum.lean index d69134ff4820b..e20e0a672cfc3 100644 --- a/Mathlib/LinearAlgebra/Matrix/Spectrum.lean +++ b/Mathlib/LinearAlgebra/Matrix/Spectrum.lean @@ -17,7 +17,7 @@ the spectral theorem for linear maps (`LinearMap.IsSymmetric.eigenvectorBasis_ap ## Tags -spectral theorem, diagonalization theorem-/ +spectral theorem, diagonalization theorem -/ namespace Matrix diff --git a/Mathlib/LinearAlgebra/Matrix/ToLin.lean b/Mathlib/LinearAlgebra/Matrix/ToLin.lean index f7a4aba7c8c89..803a75b7be149 100644 --- a/Mathlib/LinearAlgebra/Matrix/ToLin.lean +++ b/Mathlib/LinearAlgebra/Matrix/ToLin.lean @@ -942,7 +942,7 @@ If `M₁` and `M₂` are modules with basis `b₁` and `b₂` respectively index by finite types `ι₁` and `ι₂`, then `Basis.linearMap b₁ b₂` is the basis of `M₁ →ₗ[R] M₂` indexed by `ι₂ × ι₁` where `(i, j)` indexes the linear map that sends `b j` to `b i` -and sends all other basis vectors to `0`. -/ +and sends all other basis vectors to `0`. -/ @[simps! (config := .lemmasOnly) repr_apply repr_symm_apply] noncomputable def linearMap (b₁ : Basis ι₁ R M₁) (b₂ : Basis ι₂ R M₂) : @@ -968,7 +968,7 @@ induced by a basis of the module. If `M` is a module with basis `b` indexed by a finite type `ι`, then `Basis.end b` is the basis of `Module.End R M` indexed by `ι × ι` where `(i, j)` indexes the linear map that sends `b j` to `b i` -and sends all other basis vectors to `0`. -/ +and sends all other basis vectors to `0`. -/ @[simps! (config := .lemmasOnly) repr_apply repr_symm_apply] noncomputable abbrev _root_.Basis.end (b : Basis ι R M) : Basis (ι × ι) R (Module.End R M) := diff --git a/Mathlib/LinearAlgebra/Matrix/Trace.lean b/Mathlib/LinearAlgebra/Matrix/Trace.lean index 1e018cf22f592..40da0be3f44c0 100644 --- a/Mathlib/LinearAlgebra/Matrix/Trace.lean +++ b/Mathlib/LinearAlgebra/Matrix/Trace.lean @@ -109,7 +109,7 @@ theorem _root_.AddMonoidHom.map_trace [AddCommMonoid S] (f : R →+ S) (A : Matr 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 +175,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 1e06f78ec9172..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] @@ -351,7 +351,7 @@ theorem listTransvecCol_get (i : Fin (listTransvecCol M).length) : (listTransvecCol M).get i = letI i' := Fin.cast (length_listTransvecCol M) i transvection (inl i') (inr unit) <| -M (inl i') (inr unit) / M (inr unit) (inr unit) := - listTransvecCol_getElem .. + listTransvecCol_getElem _ i.isLt @[simp] theorem length_listTransvecRow : (listTransvecRow M).length = r := by simp [listTransvecRow] @@ -367,7 +367,7 @@ theorem listTransvecRow_get (i : Fin (listTransvecRow M).length) : (listTransvecRow M).get i = letI i' := Fin.cast (length_listTransvecRow M) i transvection (inr unit) (inl i') <| -M (inr unit) (inl i') / M (inr unit) (inr unit) := - listTransvecRow_getElem .. + listTransvecRow_getElem _ i.isLt /-- Multiplying by some of the matrices in `listTransvecCol M` does not change the last row. -/ theorem listTransvecCol_mul_last_row_drop (i : Fin r ⊕ Unit) {k : ℕ} (hk : k ≤ r) : @@ -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, @@ -447,7 +447,7 @@ theorem mul_listTransvecRow_last_col_take (i : Fin r ⊕ Unit) {k : ℕ} (hk : k simp only [List.take_succ, ← Matrix.mul_assoc, this, List.prod_append, Matrix.mul_one, List.prod_cons, List.prod_nil, Option.toList_some] rw [mul_transvection_apply_of_ne, IH hkr.le] - simp only [Ne, not_false_iff] + simp only [Ne, not_false_iff, reduceCtorEq] /-- Multiplying by all the matrices in `listTransvecRow M` does not change the last column. -/ theorem mul_listTransvecRow_last_col (i : Fin r ⊕ Unit) : @@ -471,7 +471,7 @@ theorem mul_listTransvecRow_last_row (hM : M (inr unit) (inr unit) ≠ 0) (i : F simpa only [this, ite_eq_right_iff] using H r le_rfl intro k hk induction' k with n IH - · simp only [if_true, Matrix.mul_one, List.take_zero, zero_le', List.prod_nil, Nat.zero_eq] + · simp only [if_true, Matrix.mul_one, List.take_zero, zero_le', List.prod_nil] · have hnr : n < r := hk let n' : Fin r := ⟨n, hnr⟩ have A : @@ -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. -/ @@ -549,8 +549,8 @@ theorem exists_isTwoBlockDiagonal_of_ne_zero (hM : M (inr unit) (inr unit) ≠ 0 List.ofFn fun i : Fin r => ⟨inr unit, inl i, by simp, -M (inr unit) (inl i) / M (inr unit) (inr unit)⟩ refine ⟨L, L', ?_⟩ - have A : L.map toMatrix = listTransvecCol M := by simp [L, listTransvecCol, (· ∘ ·)] - have B : L'.map toMatrix = listTransvecRow M := by simp [L', listTransvecRow, (· ∘ ·)] + have A : L.map toMatrix = listTransvecCol M := by simp [L, listTransvecCol, Function.comp_def] + have B : L'.map toMatrix = listTransvecRow M := by simp [L', listTransvecRow, Function.comp_def] rw [A, B] exact isTwoBlockDiagonal_listTransvecCol_mul_mul_listTransvecRow M hM diff --git a/Mathlib/LinearAlgebra/Matrix/ZPow.lean b/Mathlib/LinearAlgebra/Matrix/ZPow.lean index 5523292767d36..dd11fe3101db7 100644 --- a/Mathlib/LinearAlgebra/Matrix/ZPow.lean +++ b/Mathlib/LinearAlgebra/Matrix/ZPow.lean @@ -110,12 +110,14 @@ theorem _root_.IsUnit.det_zpow {A : M} (h : IsUnit A.det) (n : ℤ) : IsUnit (A · simpa using h.pow n.succ theorem isUnit_det_zpow_iff {A : M} {z : ℤ} : IsUnit (A ^ z).det ↔ IsUnit A.det ∨ z = 0 := by - induction' z using Int.induction_on with z _ z _ - · simp - · rw [← Int.ofNat_succ, zpow_natCast, det_pow, isUnit_pow_succ_iff, ← Int.ofNat_zero, + induction z using Int.induction_on with + | hz => simp + | hp z => + rw [← Int.ofNat_succ, zpow_natCast, det_pow, isUnit_pow_succ_iff, ← Int.ofNat_zero, Int.ofNat_inj] simp - · rw [← neg_add', ← Int.ofNat_succ, zpow_neg_natCast, isUnit_nonsing_inv_det_iff, det_pow, + | hn z => + rw [← neg_add', ← Int.ofNat_succ, zpow_neg_natCast, isUnit_nonsing_inv_det_iff, det_pow, isUnit_pow_succ_iff, neg_eq_zero, ← Int.ofNat_zero, Int.ofNat_inj] simp @@ -216,7 +218,7 @@ theorem zpow_add_one_of_ne_neg_one {A : M} : ∀ n : ℤ, n ≠ -1 → A ^ (n + rcases nonsing_inv_cancel_or_zero A with (⟨h, _⟩ | h) · apply zpow_add_one (isUnit_det_of_left_inverse h) · show A ^ (-((n + 1 : ℕ) : ℤ)) = A ^ (-((n + 2 : ℕ) : ℤ)) * A - simp_rw [zpow_neg_natCast, ← inv_pow', h, zero_pow $ Nat.succ_ne_zero _, zero_mul] + simp_rw [zpow_neg_natCast, ← inv_pow', h, zero_pow <| Nat.succ_ne_zero _, zero_mul] theorem zpow_mul (A : M) (h : IsUnit A.det) : ∀ m n : ℤ, A ^ (m * n) = (A ^ m) ^ n | (m : ℕ), (n : ℕ) => by rw [zpow_natCast, zpow_natCast, ← pow_mul, ← zpow_natCast, Int.ofNat_mul] diff --git a/Mathlib/LinearAlgebra/Multilinear/Basic.lean b/Mathlib/LinearAlgebra/Multilinear/Basic.lean index 9e188e11220cf..25022902c14a5 100644 --- a/Mathlib/LinearAlgebra/Multilinear/Basic.lean +++ b/Mathlib/LinearAlgebra/Multilinear/Basic.lean @@ -109,7 +109,7 @@ variable [Semiring R] [∀ i, AddCommMonoid (M i)] [∀ i, AddCommMonoid (M₁ i -- 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) @@ -453,14 +453,9 @@ theorem map_sum_finset_aux [DecidableEq ι] [Fintype ι] {n : ℕ} (h : (∑ 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 @@ -522,7 +517,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 => @@ -797,7 +792,7 @@ theorem compMultilinearMap_apply (g : M₂ →ₗ[R] M₃) (f : MultilinearMap R @[simp] theorem subtype_compMultilinearMap_codRestrict (f : MultilinearMap R M₁ M₂) (p : Submodule R M₂) (h) : p.subtype.compMultilinearMap (f.codRestrict p h) = f := - MultilinearMap.ext fun _ => rfl + rfl /-- The multilinear version of `LinearMap.comp_codRestrict` -/ @[simp] @@ -805,7 +800,7 @@ theorem compMultilinearMap_codRestrict (g : M₂ →ₗ[R] M₃) (f : Multilinea (p : Submodule R M₃) (h) : (g.codRestrict p h).compMultilinearMap f = (g.compMultilinearMap f).codRestrict p fun v => h (f v) := - MultilinearMap.ext fun _ => rfl + rfl variable {ι₁ ι₂ : Type*} @@ -1432,25 +1427,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 +1533,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 @@ -1771,3 +1757,5 @@ def range [Nonempty ι] (f : MultilinearMap R M₁ M₂) : SubMulAction R M₂ : end Submodule end MultilinearMap + +set_option linter.style.longFile 1900 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/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 74a47d2060113..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 @@ -49,6 +49,10 @@ instance instFunLike : FunLike (PerfectPairing R M N) M (N →ₗ[R] R) where coe f := f.toLin coe_injective' x y h := by cases x; cases y; simpa using h +@[simp] +lemma toLin_apply (p : PerfectPairing R M N) {x : M} : p.toLin x = p x := by + rfl + variable (p : PerfectPairing R M N) /-- Given a perfect pairing between `M` and `N`, we may interchange the roles of `M` and `N`. -/ @@ -57,7 +61,13 @@ protected def flip : PerfectPairing R N M where bijectiveLeft := p.bijectiveRight bijectiveRight := p.bijectiveLeft -@[simp] lemma flip_flip : p.flip.flip = p := rfl +@[simp] +lemma flip_apply_apply {x : M} {y : N} : p.flip y x = p x y := + rfl + +@[simp] +lemma flip_flip : p.flip.flip = p := + rfl /-- The linear equivalence from `M` to `Dual R N` induced by a perfect pairing. -/ noncomputable def toDualLeft : M ≃ₗ[R] Dual R N := @@ -130,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 d1342d034d19e..18abf808fda35 100644 --- a/Mathlib/LinearAlgebra/Pi.lean +++ b/Mathlib/LinearAlgebra/Pi.lean @@ -4,12 +4,12 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro, Kevin Buzzard, Yury Kudryashov, Eric Wieser -/ import Mathlib.Algebra.Group.Fin.Tuple +import Mathlib.Algebra.BigOperators.GroupWithZero.Action import Mathlib.Algebra.BigOperators.Pi import Mathlib.Algebra.Module.Prod import Mathlib.Algebra.Module.Submodule.Ker import Mathlib.Algebra.Module.Submodule.Range import Mathlib.Algebra.Module.Equiv.Basic -import Mathlib.GroupTheory.GroupAction.BigOperators import Mathlib.Logic.Equiv.Fin /-! diff --git a/Mathlib/LinearAlgebra/PiTensorProduct.lean b/Mathlib/LinearAlgebra/PiTensorProduct.lean index 1175a41ee25f1..79f7de870e7fd 100644 --- a/Mathlib/LinearAlgebra/PiTensorProduct.lean +++ b/Mathlib/LinearAlgebra/PiTensorProduct.lean @@ -313,7 +313,7 @@ def lifts (x : ⨂[R] i, s i) : Set (FreeAddMonoid (R × Π i, s i)) := {p | AddCon.toQuotient (c := addConGen (PiTensorProduct.Eqv R s)) p = x} /-- An element `p` of `FreeAddMonoid (R × Π i, s i)` lifts an element `x` of `⨂[R] i, s i` -if and only if `x` is equal to to the sum of `a • ⨂ₜ[R] i, m i` over all the entries +if and only if `x` is equal to the sum of `a • ⨂ₜ[R] i, m i` over all the entries `(a, m)` of `p`. -/ lemma mem_lifts_iff (x : ⨂[R] i, s i) (p : FreeAddMonoid (R × Π i, s i)) : @@ -411,7 +411,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 f20dd2b8bdbdf..5c0e7970a2362 100644 --- a/Mathlib/LinearAlgebra/Prod.lean +++ b/Mathlib/LinearAlgebra/Prod.lean @@ -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 @@ -525,10 +525,9 @@ def fstEquiv : Submodule.fst R M M₂ ≃ₗ[R] M where -- Porting note: proofs were `tidy` or `simp` toFun x := x.1.1 invFun m := ⟨⟨m, 0⟩, by simp only [fst, comap_bot, mem_ker, snd_apply]⟩ - map_add' := by simp only [AddSubmonoid.coe_add, coe_toAddSubmonoid, Prod.fst_add, Subtype.forall, - implies_true, Prod.forall, forall_const] + map_add' := by simp only [coe_add, Prod.fst_add, implies_true] map_smul' := by simp only [SetLike.val_smul, Prod.smul_fst, RingHom.id_apply, Subtype.forall, - implies_true, Prod.forall, forall_const] + implies_true] left_inv := by rintro ⟨⟨x, y⟩, hy⟩ simp only [fst, comap_bot, mem_ker, snd_apply] at hy @@ -557,10 +556,9 @@ def sndEquiv : Submodule.snd R M M₂ ≃ₗ[R] M₂ where -- Porting note: proofs were `tidy` or `simp` toFun x := x.1.2 invFun n := ⟨⟨0, n⟩, by simp only [snd, comap_bot, mem_ker, fst_apply]⟩ - map_add' := by simp only [AddSubmonoid.coe_add, coe_toAddSubmonoid, Prod.snd_add, Subtype.forall, - implies_true, Prod.forall, forall_const] + map_add' := by simp only [coe_add, Prod.snd_add, implies_true] map_smul' := by simp only [SetLike.val_smul, Prod.smul_snd, RingHom.id_apply, Subtype.forall, - implies_true, Prod.forall, forall_const] + implies_true] left_inv := by rintro ⟨⟨x, y⟩, hx⟩ simp only [snd, comap_bot, mem_ker, fst_apply] at hx @@ -865,16 +863,16 @@ 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] @[deprecated (since := "2024-06-05")] theorem tailing_sup_tunnel_succ_le_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : - tailing f i n ⊔ (OrderDual.ofDual (α := Submodule R M) $ tunnel f i (n + 1)) ≤ + 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..da597346dcca3 100644 --- a/Mathlib/LinearAlgebra/Projection.lean +++ b/Mathlib/LinearAlgebra/Projection.lean @@ -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..94d4e7925bb43 100644 --- a/Mathlib/LinearAlgebra/Projectivization/Basic.lean +++ b/Mathlib/LinearAlgebra/Projectivization/Basic.lean @@ -78,7 +78,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/QuadraticForm/Basic.lean b/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean index f3758444777a0..fe2fe2b66dfe2 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/Basic.lean @@ -63,7 +63,7 @@ substantial refactors from the current version, such that $Q(rm) = rQ(m)r^*$ for suitable conjugation $r^*$. The [Zulip thread](https://leanprover.zulipchat.com/#narrow/stream/116395-maths/topic/Quadratic.20Maps/near/395529867) -has some further discusion. +has some further discussion. ## References @@ -75,14 +75,12 @@ has some further discusion. quadratic map, homogeneous polynomial, quadratic polynomial -/ - universe u v w variable {S T : Type*} variable {R : Type*} {M N P A : Type*} -open LinearMap (BilinMap) -open LinearMap (BilinForm) +open LinearMap (BilinMap BilinForm) section Polar @@ -147,7 +145,6 @@ section QuadraticForm variable (R : Type u) (M : Type v) [CommSemiring R] [AddCommMonoid M] [Module R M] -variable (R M) in /-- A quadratic form on a module. -/ abbrev QuadraticForm : Type _ := QuadraticMap R M R @@ -643,7 +640,7 @@ end QuadraticMap Over a commutative ring with an inverse of 2, the theory of quadratic maps is basically identical to that of symmetric bilinear maps. The map from quadratic -maps to bilinear maps giving this identification is called the <`associated` +maps to bilinear maps giving this identification is called the `QuadraticMap.associated` quadratic map. -/ @@ -857,15 +854,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 @@ -1183,7 +1180,7 @@ theorem exists_bilinForm_self_ne_zero [htwo : Invertible (2 : R)] {B : BilinForm obtain ⟨x, hx⟩ := QuadraticMap.exists_quadraticForm_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] @@ -1197,7 +1194,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₂ @@ -1291,8 +1288,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 0c19cad735241..c2c99925d7bb1 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/Basis.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/Basis.lean @@ -35,8 +35,8 @@ theorem toBilin_apply (Q : QuadraticMap R M N) (bm : Basis ι R M) (i j : ι) : theorem toQuadraticMap_toBilin (Q : QuadraticMap R M N) (bm : Basis ι R M) : (Q.toBilin bm).toQuadraticMap = Q := by ext x - rw [← bm.total_repr x, LinearMap.BilinMap.toQuadraticMap_apply, Finsupp.total_apply, - Finsupp.sum] + rw [← bm.linearCombination_repr x, LinearMap.BilinMap.toQuadraticMap_apply, + Finsupp.linearCombination_apply, Finsupp.sum] simp_rw [LinearMap.map_sum₂, map_sum, LinearMap.map_smul₂, _root_.map_smul, toBilin_apply, smul_ite, smul_zero, ← Finset.sum_product', ← Finset.diag_union_offDiag, Finset.sum_union (Finset.disjoint_diag_offDiag _), Finset.sum_diag, if_true] 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/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/QuadraticModuleCat.lean b/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat.lean index a86dc75313b8c..c0d2eb6ac8a7a 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat.lean @@ -16,7 +16,7 @@ universe v u variable (R : Type u) [CommRing R] -/-- The category of quadratic modules; modules with an associated quadratic form-/ +/-- The category of quadratic modules; modules with an associated quadratic form -/ structure QuadraticModuleCat extends ModuleCat.{v} R where /-- The quadratic form associated with the module. -/ form : QuadraticForm R carrier @@ -25,8 +25,7 @@ variable {R} namespace QuadraticModuleCat -open QuadraticForm -open QuadraticMap +open QuadraticForm QuadraticMap instance : CoeSort (QuadraticModuleCat.{v} R) (Type v) := ⟨(·.carrier)⟩ @@ -44,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 diff --git a/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat/Monoidal.lean b/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat/Monoidal.lean index 0a4c42c63fd3c..f7b52334b7167 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat/Monoidal.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat/Monoidal.lean @@ -35,8 +35,7 @@ variable {R : Type u} [CommRing R] [Invertible (2 : R)] namespace QuadraticModuleCat -open QuadraticMap -open QuadraticForm +open QuadraticMap QuadraticForm namespace instMonoidalCategory @@ -87,22 +86,22 @@ noncomputable instance instMonoidalCategory : MonoidalCategory (QuadraticModuleC εIso := Iso.refl _ leftUnitor_eq := fun X => by simp only [forget₂_obj, forget₂_map, Iso.refl_symm, Iso.trans_assoc, Iso.trans_hom, - Iso.refl_hom, tensorIso_hom, MonoidalCategory.tensorHom_id] + Iso.refl_hom, MonoidalCategory.tensorIso_hom, MonoidalCategory.tensorHom_id] dsimp only [toModuleCat_tensor, ModuleCat.of_coe] erw [MonoidalCategory.id_whiskerRight] simp rfl rightUnitor_eq := fun X => by simp only [forget₂_obj, forget₂_map, Iso.refl_symm, Iso.trans_assoc, Iso.trans_hom, - Iso.refl_hom, tensorIso_hom, MonoidalCategory.id_tensorHom] + Iso.refl_hom, MonoidalCategory.tensorIso_hom, MonoidalCategory.id_tensorHom] dsimp only [toModuleCat_tensor, ModuleCat.of_coe] erw [MonoidalCategory.whiskerLeft_id] simp rfl associator_eq := fun X Y Z => by dsimp only [forget₂_obj, forget₂_map_associator_hom] - simp only [eqToIso_refl, Iso.refl_trans, Iso.refl_symm, Iso.trans_hom, tensorIso_hom, - Iso.refl_hom, MonoidalCategory.tensor_id] + simp only [eqToIso_refl, Iso.refl_trans, Iso.refl_symm, Iso.trans_hom, + MonoidalCategory.tensorIso_hom, Iso.refl_hom, MonoidalCategory.tensor_id] dsimp only [toModuleCat_tensor, ModuleCat.of_coe] rw [Category.id_comp, Category.id_comp, Category.comp_id, MonoidalCategory.tensor_id, Category.id_comp] } diff --git a/Mathlib/LinearAlgebra/QuadraticForm/Real.lean b/Mathlib/LinearAlgebra/QuadraticForm/Real.lean index 7ec3a6f4947d8..b9fe9bdf90ae3 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/Real.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/Real.lean @@ -53,7 +53,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 +63,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 +72,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 +81,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 f4bca4eca0457..1d4c4ee3c081a 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/TensorProduct.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/TensorProduct.lean @@ -20,10 +20,8 @@ universe uR uA uM₁ uM₂ variable {R : Type uR} {A : Type uA} {M₁ : Type uM₁} {M₂ : Type uM₂} -open TensorProduct -open LinearMap (BilinMap) -open LinearMap (BilinForm) -open QuadraticMap +open LinearMap (BilinMap BilinForm) +open TensorProduct QuadraticMap namespace QuadraticForm diff --git a/Mathlib/LinearAlgebra/Quotient.lean b/Mathlib/LinearAlgebra/Quotient.lean index f19649d0da829..ece10805d5505 100644 --- a/Mathlib/LinearAlgebra/Quotient.lean +++ b/Mathlib/LinearAlgebra/Quotient.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.GroupTheory.QuotientGroup import Mathlib.LinearAlgebra.Span +import Mathlib.LinearAlgebra.Pi import Mathlib.Algebra.Module.Equiv.Basic +import Mathlib.GroupTheory.QuotientGroup.Basic +import Mathlib.SetTheory.Cardinal.Finite /-! # Quotients by submodules @@ -32,13 +34,15 @@ 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 := +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)⟩ @@ -67,7 +71,7 @@ protected theorem eq' {x y : M} : (mk x : M ⧸ p) = (mk : M → M ⧸ p) y ↔ 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) + (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. @@ -281,9 +285,14 @@ def mkQ : M →ₗ[R] M ⧸ p where 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 +theorem mkQ_surjective : Function.Surjective p.mkQ := by rintro ⟨x⟩; exact ⟨x, rfl⟩ +theorem strictMono_comap_prod_map : + StrictMono fun m : Submodule R M ↦ (m.comap p.subtype, m.map p.mkQ) := + fun m₁ m₂ ↦ QuotientAddGroup.strictMono_comap_prod_map + p.toAddSubgroup (a := m₁.toAddSubgroup) (b := m₂.toAddSubgroup) + end variable {R₂ M₂ : Type*} [Ring R₂] [AddCommGroup M₂] [Module R₂ M₂] {τ₁₂ : R →+* R₂} @@ -309,6 +318,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₂ := diff --git a/Mathlib/LinearAlgebra/Ray.lean b/Mathlib/LinearAlgebra/Ray.lean index 04a2786fe4bde..547a7c8540f4b 100644 --- a/Mathlib/LinearAlgebra/Ray.lean +++ b/Mathlib/LinearAlgebra/Ray.lean @@ -3,10 +3,10 @@ Copyright (c) 2021 Joseph Myers. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Joseph Myers -/ -import Mathlib.Algebra.Group.Subgroup.Actions import Mathlib.Algebra.Order.Module.Algebra import Mathlib.LinearAlgebra.LinearIndependent import Mathlib.Algebra.Ring.Subring.Units +import Mathlib.Tactic.Positivity /-! # Rays in modules @@ -106,8 +106,8 @@ lemma sameRay_nonneg_smul_right (v : M) (h : 0 ≤ a) : SameRay R v (a • v) := obtain h | h := (algebraMap_nonneg R h).eq_or_gt · 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] + · refine Or.inr <| Or.inr ⟨algebraMap S R a, 1, h, by nontriviality R; exact zero_lt_one, ?_⟩ + 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 := @@ -171,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) := @@ -467,7 +466,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 := @@ -485,7 +484,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 := @@ -532,11 +531,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 e6bde244d8722..d807bcfeec42e 100644 --- a/Mathlib/LinearAlgebra/Reflection.lean +++ b/Mathlib/LinearAlgebra/Reflection.lean @@ -40,7 +40,7 @@ should connect (or unify) these definitions with `Module.reflecton` defined here -/ -open Set Function Pointwise +open Function Set open Module hiding Finite open Submodule (span) @@ -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) = @@ -161,13 +161,19 @@ lemma Dual.eq_of_preReflection_mapsTo' [CharZero R] [NoZeroSMulDivisors R M] set Φ' : Set (span R Φ) := range (inclusion <| Submodule.subset_span (R := R) (s := Φ)) rw [← finite_coe_iff] at hΦ₁ have hΦ'₁ : Φ'.Finite := finite_range (inclusion Submodule.subset_span) - have hΦ'₂ : span R Φ' = ⊤ := by simp [Φ'] + have hΦ'₂ : span R Φ' = ⊤ := by + simp only [Φ'] + rw [range_inclusion] + simp let x' : span R Φ := ⟨x, hx'⟩ have hx' : x' ≠ 0 := Subtype.coe_ne_coe.1 hx have this : ∀ {F : Dual R M}, MapsTo (preReflection x F) Φ Φ → MapsTo (preReflection x' ((span R Φ).subtype.dualMap F)) Φ' Φ' := by intro F hF ⟨y, hy⟩ hy' - simp only [Φ', range_inclusion, SetLike.coe_sort_coe, mem_setOf_eq] at hy' ⊢ + simp only [Φ'] at hy' ⊢ + rw [range_inclusion] at hy' + simp only [SetLike.coe_sort_coe, mem_setOf_eq] at hy' ⊢ + rw [range_inclusion] exact hF hy' exact eq_of_preReflection_mapsTo hx' hΦ'₁ hΦ'₂ hf₁ (this hf₂) hg₁ (this hg₂) diff --git a/Mathlib/LinearAlgebra/RootSystem/Basic.lean b/Mathlib/LinearAlgebra/RootSystem/Basic.lean index 4b4ba33c9fa5a..4aba11c944d5e 100644 --- a/Mathlib/LinearAlgebra/RootSystem/Basic.lean +++ b/Mathlib/LinearAlgebra/RootSystem/Basic.lean @@ -17,7 +17,7 @@ This file contains basic results for root systems and root data. * `RootSystem.ext`: In characteristic zero if there is no torsion, a root system is determined entirely by its roots. * `RootPairing.mk'`: In characteristic zero if there is no torsion, to check that two finite - familes of of roots and coroots form a root pairing, it is sufficient to check that they are + families of roots and coroots form a root pairing, it is sufficient to check that they are stable under reflections. * `RootSystem.mk'`: In characteristic zero if there is no torsion, to check that a finite family of roots form a root system, we do not need to check that the coroots are stable under reflections @@ -48,7 +48,7 @@ variable (p : PerfectPairing R M N) (root : ι ↪ M) (coroot : ι ↪ N) (i j : include h private theorem exist_eq_reflection_of_mapsTo : - ∃ k, root k = (preReflection (root i) (p.toLin.flip (coroot i))) (root j) := + ∃ k, root k = (preReflection (root i) (p.flip (coroot i))) (root j) := h i (mem_range_self j) variable (hp : ∀ i, p.toLin (root i) (coroot i) = 2) @@ -112,7 +112,7 @@ Formally, the point is that the hypothesis `hc` depends only on the range of the @[ext] protected lemma ext [CharZero R] [NoZeroSMulDivisors R M] {P₁ P₂ : RootPairing ι R M N} - (he : P₁.toLin = P₂.toLin) + (he : P₁.toPerfectPairing = P₂.toPerfectPairing) (hr : P₁.root = P₂.root) (hc : range P₁.coroot = range P₂.coroot) : P₁ = P₂ := by @@ -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 @@ -139,49 +139,50 @@ private lemma coroot_eq_coreflection_of_root_eq' [CharZero R] [NoZeroSMulDivisor (p : PerfectPairing R M N) (root : ι ↪ M) (coroot : ι ↪ N) - (hp : ∀ i, p.toLin (root i) (coroot i) = 2) - (hr : ∀ i, MapsTo (preReflection (root i) (p.toLin.flip (coroot i))) (range root) (range root)) - (hc : ∀ i, MapsTo (preReflection (coroot i) (p.toLin (root i))) (range coroot) (range coroot)) - {i j k : ι} (hk : root k = preReflection (root i) (p.toLin.flip (coroot i)) (root j)) : - coroot k = preReflection (coroot i) (p.toLin (root i)) (coroot j) := by + (hp : ∀ i, p (root i) (coroot i) = 2) + (hr : ∀ i, MapsTo (preReflection (root i) (p.flip (coroot i))) (range root) (range root)) + (hc : ∀ i, MapsTo (preReflection (coroot i) (p (root i))) (range coroot) (range coroot)) + {i j k : ι} (hk : root k = preReflection (root i) (p.flip (coroot i)) (root j)) : + coroot k = preReflection (coroot i) (p (root i)) (coroot j) := by set α := root i set β := root j set α' := coroot i set β' := coroot j - set sα := preReflection α (p.toLin.flip α') - set sβ := preReflection β (p.toLin.flip β') - let sα' := preReflection α' (p.toLin α) - have hij : preReflection (sα β) (p.toLin.flip (sα' β')) = sα ∘ₗ sβ ∘ₗ sα := by + set sα := preReflection α (p.flip α') + set sβ := preReflection β (p.flip β') + let sα' := preReflection α' (p α) + have hij : preReflection (sα β) (p.flip (sα' β')) = sα ∘ₗ sβ ∘ₗ sα := by ext - have hpi : (p.toLin.flip (coroot i)) (root i) = 2 := by rw [LinearMap.flip_apply, hp i] - simp [α, β, α', β', sα, sβ, sα', ← preReflection_preReflection β (p.toLin.flip β') hpi, + have hpi : (p.flip (coroot i)) (root i) = 2 := by rw [PerfectPairing.flip_apply_apply, hp i] + simp [α, β, α', β', sα, sβ, sα', ← preReflection_preReflection β (p.flip β') hpi, preReflection_apply] - have hk₀ : root k ≠ 0 := fun h ↦ by simpa [h] using hp k + have hk₀ : root k ≠ 0 := fun h ↦ by simpa [h, ← PerfectPairing.toLin_apply] using hp k obtain ⟨l, hl⟩ := hc i (mem_range_self j) rw [← hl] - have hkl : (p.toLin.flip (coroot l)) (root k) = 2 := by - simp [hl, hk, preReflection_apply, mul_sub, mul_two, β', α, α', β, sα, hp i, hp j] - rw [mul_comm (p.toLin (root i) (coroot j))] + have hkl : (p.flip (coroot l)) (root k) = 2 := by + simp only [hl, preReflection_apply, hk, PerfectPairing.flip_apply_apply, map_sub, hp j, + map_smul, smul_eq_mul, hp i, mul_sub, sα, α, α', β, mul_two, mul_add] + rw [mul_comm (p (root i) (coroot j))] abel - suffices p.toLin.flip (coroot k) = p.toLin.flip (coroot l) from p.bijectiveRight.injective this + suffices p.flip (coroot k) = p.flip (coroot l) from p.bijectiveRight.injective this have _i : NoZeroSMulDivisors ℤ M := NoZeroSMulDivisors.int_of_charZero R M have := injOn_dualMap_subtype_span_range_range (finite_range root) - (c := p.toLin.flip ∘ coroot) hp hr + (c := p.flip ∘ coroot) hp hr apply this (mem_range_self k) (mem_range_self l) refine Dual.eq_of_preReflection_mapsTo' hk₀ (finite_range root) (Submodule.subset_span <| mem_range_self k) (hp k) (hr k) hkl ?_ rw [comp_apply, hl, hk, hij] exact (hr i).comp <| (hr j).comp (hr i) -/-- In characteristic zero if there is no torsion, to check that two finite familes of of roots and +/-- In characteristic zero if there is no torsion, to check that two finite families of roots and coroots form a root pairing, it is sufficient to check that they are stable under reflections. -/ def mk' [Finite ι] [CharZero R] [NoZeroSMulDivisors R M] (p : PerfectPairing R M N) (root : ι ↪ M) (coroot : ι ↪ N) - (hp : ∀ i, p.toLin (root i) (coroot i) = 2) - (hr : ∀ i, MapsTo (preReflection (root i) (p.toLin.flip (coroot i))) (range root) (range root)) - (hc : ∀ i, MapsTo (preReflection (coroot i) (p.toLin (root i))) (range coroot) (range coroot)) : + (hp : ∀ i, p (root i) (coroot i) = 2) + (hr : ∀ i, MapsTo (preReflection (root i) (p.flip (coroot i))) (range root) (range root)) + (hc : ∀ i, MapsTo (preReflection (coroot i) (p (root i))) (range coroot) (range coroot)) : RootPairing ι R M N where toPerfectPairing := p root := root @@ -190,7 +191,7 @@ def mk' [Finite ι] [CharZero R] [NoZeroSMulDivisors R M] reflection_perm i := RootPairing.equiv_of_mapsTo p root coroot i hr hp reflection_perm_root i j := by rw [equiv_of_mapsTo_apply, (exist_eq_reflection_of_mapsTo p root coroot i j hr).choose_spec, - preReflection_apply, LinearMap.flip_apply] + preReflection_apply, PerfectPairing.flip_apply_apply] reflection_perm_coroot i j := by refine (coroot_eq_coreflection_of_root_eq' p root coroot hp hr hc ?_).symm rw [equiv_of_mapsTo_apply, (exist_eq_reflection_of_mapsTo p root coroot i j hr).choose_spec] @@ -208,11 +209,11 @@ its roots. -/ @[ext] protected lemma ext [CharZero R] [NoZeroSMulDivisors R M] {P₁ P₂ : RootSystem ι R M N} - (he : P₁.toLin = P₂.toLin) + (he : P₁.toPerfectPairing = P₂.toPerfectPairing) (hr : P₁.root = P₂.root) : P₁ = P₂ := by - suffices ∀ P₁ P₂ : RootSystem ι R M N, P₁.toLin = P₂.toLin → P₁.root = P₂.root → - range P₁.coroot ⊆ range P₂.coroot by + suffices ∀ P₁ P₂ : RootSystem ι R M N, P₁.toPerfectPairing = P₂.toPerfectPairing → + P₁.root = P₂.root → range P₁.coroot ⊆ range P₂.coroot by have h₁ := this P₁ P₂ he hr have h₂ := this P₂ P₁ he.symm hr.symm cases' P₁ with P₁ @@ -233,28 +234,28 @@ private lemma coroot_eq_coreflection_of_root_eq_of_span_eq_top [CharZero R] [NoZ (p : PerfectPairing R M N) (root : ι ↪ M) (coroot : ι ↪ N) - (hp : ∀ i, p.toLin (root i) (coroot i) = 2) - (hs : ∀ i, MapsTo (preReflection (root i) (p.toLin.flip (coroot i))) (range root) (range root)) + (hp : ∀ i, p (root i) (coroot i) = 2) + (hs : ∀ i, MapsTo (preReflection (root i) (p.flip (coroot i))) (range root) (range root)) (hsp : span R (range root) = ⊤) - {i j k : ι} (hk : root k = preReflection (root i) (p.toLin.flip (coroot i)) (root j)) : - coroot k = preReflection (coroot i) (p.toLin (root i)) (coroot j) := by + {i j k : ι} (hk : root k = preReflection (root i) (p.flip (coroot i)) (root j)) : + coroot k = preReflection (coroot i) (p (root i)) (coroot j) := by set α := root i set β := root j set α' := coroot i set β' := coroot j - set sα := preReflection α (p.toLin.flip α') - set sβ := preReflection β (p.toLin.flip β') - let sα' := preReflection α' (p.toLin α) + set sα := preReflection α (p.flip α') + set sβ := preReflection β (p.flip β') + let sα' := preReflection α' (p α) have hij : preReflection (sα β) (p.toLin.flip (sα' β')) = sα ∘ₗ sβ ∘ₗ sα := by ext - have hpi : (p.toLin.flip (coroot i)) (root i) = 2 := by rw [LinearMap.flip_apply, hp i] - simp [α, β, α', β', sα, sβ, sα', ← preReflection_preReflection β (p.toLin.flip β') hpi, + have hpi : (p.flip (coroot i)) (root i) = 2 := by rw [PerfectPairing.flip_apply_apply, hp i] + simp [α, β, α', β', sα, sβ, sα', ← preReflection_preReflection β (p.flip β') hpi, preReflection_apply] -- v4.7.0-rc1 issues - have hk₀ : root k ≠ 0 := fun h ↦ by simpa [h] using hp k + 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, - mul_comm (p.toLin α β')] + · 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] exact (hs i).comp <| (hs j).comp (hs i) diff --git a/Mathlib/LinearAlgebra/RootSystem/Defs.lean b/Mathlib/LinearAlgebra/RootSystem/Defs.lean index 8ce5eed7055ed..eac40333d52fc 100644 --- a/Mathlib/LinearAlgebra/RootSystem/Defs.lean +++ b/Mathlib/LinearAlgebra/RootSystem/Defs.lean @@ -16,25 +16,24 @@ This file contains basic definitions for root systems and root data. * `RootPairing`: Given two perfectly-paired `R`-modules `M` and `N` (over some commutative ring `R`) a root pairing with indexing set `ι` is the data of an `ι`-indexed subset of `M` ("the roots") an `ι`-indexed subset of `N` ("the coroots"), and an `ι`-indexed set of - permutations of `ι` such that each root-coroot pair - evaluates to `2`, and the permutation attached to each element of `ι` is compatible with the - reflections on the corresponding roots and coroots. + permutations of `ι` such that each root-coroot pair evaluates to `2`, and the permutation + attached to each element of `ι` is compatible with the reflections on the corresponding roots and + coroots. * `RootDatum`: A root datum is a root pairing for which the roots and coroots take values in finitely-generated free Abelian groups. * `RootSystem`: A root system is a root pairing for which the roots span their ambient module. * `RootPairing.IsCrystallographic`: A root pairing is said to be crystallographic if the pairing between a root and coroot is always an integer. - * `RootPairing.IsReduced`: A root pairing is said to be reduced if it never contains the double of - a root. + * `RootPairing.IsReduced`: A root pairing is said to be reduced if two linearly dependent roots are + always related by a sign. + * `RootPairing.weylGroup`: The group of linear isomorphisms on `M` generated by reflections. + * `RootPairing.weylGroupToPerm`: The permutation representation of the Weyl group on `ι`. ## TODO -* Put more API theorems in the Defs file. -* Introduce the Weyl Group, and its action on the indexing set. -* Base change of root pairings (may need flatness). -* 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. + * Base change of root pairings (may need flatness; perhaps should go in a different file). + * Crystallographic root systems are isomorphic to base changes of root systems over `ℤ`: Take + `M₀` and `N₀` to be the `ℤ`-span of roots and coroots. ## Implementation details @@ -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. -/ @@ -97,9 +95,9 @@ structure RootPairing extends PerfectPairing R M N := /-- A parametrized family of permutations, induced by reflection. -/ reflection_perm : ι → (ι ≃ ι) reflection_perm_root : ∀ i j, - root j - toLin (root j) (coroot i) • root i = root (reflection_perm i j) + root j - toPerfectPairing (root j) (coroot i) • root i = root (reflection_perm i j) reflection_perm_coroot : ∀ i j, - coroot j - toLin (root i) (coroot j) • coroot i = coroot (reflection_perm i j) + coroot j - toPerfectPairing (root i) (coroot j) • coroot i = coroot (reflection_perm i j) /-- A root datum is a root pairing with coefficients in the integers and for which the root and coroot spaces are finitely-generated free Abelian groups. @@ -112,20 +110,26 @@ 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 + namespace RootPairing 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 +@[simp] +lemma toLin_toPerfectPairing (x : M) (y : N) : P.toLin x y = P.toPerfectPairing x y := + rfl + /-- If we interchange the roles of `M` and `N`, we still have a root pairing. -/ protected def flip : RootPairing ι R N M := { P.toPerfectPairing.flip with @@ -140,11 +144,25 @@ 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.toLin (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.toLin (P.root i) (P.coroot j) = P.pairing i j := +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 @@ -172,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.toLin x (P.coroot i)) • P.root i := + P.reflection i x = x - (P.coroot' i x) • P.root i := rfl lemma reflection_apply_root : @@ -189,6 +207,40 @@ lemma reflection_same (x : M) : P.reflection i (P.reflection i x) = x := Module.involutive_reflection (P.coroot_root_two i) x +@[simp] +lemma reflection_inv : + (P.reflection i)⁻¹ = P.reflection i := + rfl + +@[simp] +lemma reflection_sq : + P.reflection i ^ 2 = 1 := + mul_eq_one_iff_eq_inv.mpr rfl + +@[simp] +lemma reflection_perm_sq : + P.reflection_perm i ^ 2 = 1 := by + ext j + apply P.root.injective + simp only [sq, Equiv.Perm.mul_apply, root_reflection_perm, reflection_same, Equiv.Perm.one_apply] + +@[simp] +lemma reflection_perm_inv : + (P.reflection_perm i)⁻¹ = P.reflection_perm i := + (mul_eq_one_iff_eq_inv.mp <| P.reflection_perm_sq i).symm + +@[simp] +lemma reflection_perm_self : P.reflection_perm i (P.reflection_perm i j) = j := by + apply P.root.injective + simp only [root_reflection_perm, reflection_same] + +lemma reflection_perm_involutive : Involutive (P.reflection_perm i) := + involutive_iff_iter_2_eq_id.mpr (by ext; simp) + +@[simp] +lemma reflection_perm_symm : (P.reflection_perm i).symm = P.reflection_perm i := + Involutive.symm_eq_self_of_involutive (P.reflection_perm i) <| P.reflection_perm_involutive i + lemma bijOn_reflection_root : BijOn (P.reflection i) (range P.root) (range P.root) := Module.bijOn_reflection_of_mapsTo _ <| P.mapsTo_reflection_root i @@ -213,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.toLin (P.root i) f) • P.coroot i := + P.coreflection i f = f - (P.root' i) f • P.coroot i := rfl lemma coreflection_apply_coroot : @@ -230,6 +282,16 @@ lemma coreflection_same (x : N) : P.coreflection i (P.coreflection i x) = x := Module.involutive_reflection (P.flip.coroot_root_two i) x +@[simp] +lemma coreflection_inv : + (P.coreflection i)⁻¹ = P.coreflection i := + rfl + +@[simp] +lemma coreflection_sq : + P.coreflection i ^ 2 = 1 := + mul_eq_one_iff_eq_inv.mpr rfl + lemma bijOn_coreflection_coroot : BijOn (P.coreflection i) (range P.coroot) (range P.coroot) := bijOn_reflection_root P.flip i @@ -245,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.toLin 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)) : @@ -253,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.toLin (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 @@ -280,6 +374,150 @@ lemma isReduced_iff : P.IsReduced ↔ ∀ i j : ι, i ≠ j → · exact Or.inl (congrArg P.root h') · exact Or.inr (h i j h' hLin) +/-- The `Weyl group` of a root pairing is the group of automorphisms of the weight space generated +by reflections in roots. -/ +def weylGroup : Subgroup (M ≃ₗ[R] M) := + Subgroup.closure (range P.reflection) + +lemma reflection_mem_weylGroup : P.reflection i ∈ P.weylGroup := + Subgroup.subset_closure <| mem_range_self i + +lemma mem_range_root_of_mem_range_reflection_of_mem_range_root + {r : M ≃ₗ[R] M} {α : M} (hr : r ∈ range P.reflection) (hα : α ∈ range P.root) : + r • α ∈ range P.root := by + obtain ⟨i, rfl⟩ := hr + obtain ⟨j, rfl⟩ := hα + exact ⟨P.reflection_perm i j, P.root_reflection_perm i j⟩ + +lemma mem_range_coroot_of_mem_range_coreflection_of_mem_range_coroot + {r : N ≃ₗ[R] N} {α : N} (hr : r ∈ range P.coreflection) (hα : α ∈ range P.coroot) : + r • α ∈ range P.coroot := by + obtain ⟨i, rfl⟩ := hr + obtain ⟨j, rfl⟩ := hα + exact ⟨P.reflection_perm i j, P.coroot_reflection_perm i j⟩ + +lemma exists_root_eq_smul_of_mem_weylGroup {w : M ≃ₗ[R] M} (hw : w ∈ P.weylGroup) (i : ι) : + ∃ j, P.root j = w • P.root i := + Subgroup.smul_mem_of_mem_closure_of_mem (by simp) + (fun _ h _ ↦ P.mem_range_root_of_mem_range_reflection_of_mem_range_root h) hw (mem_range_self i) + +/-- The permutation representation of the Weyl group induced by `reflection_perm`. -/ +def weylGroupToPerm : P.weylGroup →* Equiv.Perm ι where + toFun w := + { toFun := fun i => (P.exists_root_eq_smul_of_mem_weylGroup w.2 i).choose + invFun := fun i => (P.exists_root_eq_smul_of_mem_weylGroup w⁻¹.2 i).choose + left_inv := fun i => by + obtain ⟨w, hw⟩ := w + apply P.root.injective + rw [(P.exists_root_eq_smul_of_mem_weylGroup ((Subgroup.inv_mem_iff P.weylGroup).mpr hw) + ((P.exists_root_eq_smul_of_mem_weylGroup hw i).choose)).choose_spec, + (P.exists_root_eq_smul_of_mem_weylGroup hw i).choose_spec, inv_smul_smul] + right_inv := fun i => by + obtain ⟨w, hw⟩ := w + have hw' : w⁻¹ ∈ P.weylGroup := (Subgroup.inv_mem_iff P.weylGroup).mpr hw + apply P.root.injective + rw [(P.exists_root_eq_smul_of_mem_weylGroup hw + ((P.exists_root_eq_smul_of_mem_weylGroup hw' i).choose)).choose_spec, + (P.exists_root_eq_smul_of_mem_weylGroup hw' i).choose_spec, smul_inv_smul] } + map_one' := by ext; simp + map_mul' x y := by + obtain ⟨x, hx⟩ := x + obtain ⟨y, hy⟩ := y + ext i + apply P.root.injective + simp only [Equiv.coe_fn_mk, Equiv.Perm.coe_mul, comp_apply] + rw [(P.exists_root_eq_smul_of_mem_weylGroup (mul_mem hx hy) i).choose_spec, + (P.exists_root_eq_smul_of_mem_weylGroup hx + ((P.exists_root_eq_smul_of_mem_weylGroup hy i).choose)).choose_spec, + (P.exists_root_eq_smul_of_mem_weylGroup hy i).choose_spec, mul_smul] + +@[simp] +lemma weylGroupToPerm_apply_reflection : + P.weylGroupToPerm ⟨P.reflection i, P.reflection_mem_weylGroup i⟩ = P.reflection_perm i := by + ext j + apply P.root.injective + rw [weylGroupToPerm, MonoidHom.coe_mk, OneHom.coe_mk, Equiv.coe_fn_mk, root_reflection_perm, + (P.exists_root_eq_smul_of_mem_weylGroup (P.reflection_mem_weylGroup i) j).choose_spec, + LinearEquiv.smul_def] + +@[simp] +lemma range_weylGroupToPerm : + P.weylGroupToPerm.range = Subgroup.closure (range P.reflection_perm) := by + refine (Subgroup.closure_eq_of_le _ ?_ ?_).symm + · rintro - ⟨i, rfl⟩ + simpa only [← weylGroupToPerm_apply_reflection] using mem_range_self _ + · rintro - ⟨⟨w, hw⟩, rfl⟩ + induction hw using Subgroup.closure_induction'' with + | one => + change P.weylGroupToPerm 1 ∈ _ + simpa only [map_one] using Subgroup.one_mem _ + | mem w' hw' => + obtain ⟨i, rfl⟩ := hw' + simpa only [weylGroupToPerm_apply_reflection] using Subgroup.subset_closure (mem_range_self i) + | inv_mem w' hw' => + obtain ⟨i, rfl⟩ := hw' + simpa only [reflection_inv, weylGroupToPerm_apply_reflection] using + Subgroup.subset_closure (mem_range_self i) + | mul w₁ w₂ hw₁ hw₂ h₁ h₂ => + simpa only [← Submonoid.mk_mul_mk _ w₁ w₂ hw₁ hw₂, map_mul] using Subgroup.mul_mem _ h₁ h₂ + +lemma pairing_smul_root_eq (k : ι) (hij : P.reflection_perm i = P.reflection_perm j) : + P.pairing k i • P.root i = P.pairing k j • P.root j := by + have h : P.reflection i (P.root k) = P.reflection j (P.root k) := by + simp only [← root_reflection_perm, hij] + simpa only [reflection_apply_root, sub_right_inj] using h + +lemma pairing_smul_coroot_eq (k : ι) (hij : P.reflection_perm i = P.reflection_perm j) : + P.pairing i k • P.coroot i = P.pairing j k • P.coroot j := by + have h : P.coreflection i (P.coroot k) = P.coreflection j (P.coroot k) := by + simp only [← coroot_reflection_perm, hij] + simpa only [coreflection_apply_coroot, sub_right_inj] using h + +lemma two_nsmul_reflection_eq_of_perm_eq (hij : P.reflection_perm i = P.reflection_perm j) : + 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, 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) := ?_ + _ = P.toLin x (P.pairing i j • P.coroot i) • (P.root j) := ?_ + _ = P.toLin x ((2 : R) • P.coroot j) • (P.root j) := ?_ + _ = 2 • P.toLin x (P.coroot j) • P.root j := ?_ + · rw [smul_comm, ← Nat.cast_smul_eq_nsmul R, Nat.cast_ofNat] + · rw [P.pairing_smul_root_eq j i i hij.symm, pairing_same] + · rw [← smul_comm, ← smul_assoc, map_smul] + · rw [← P.pairing_smul_coroot_eq j i j hij.symm, pairing_same] + · rw [map_smul, smul_assoc, ← Nat.cast_smul_eq_nsmul R, Nat.cast_ofNat] + +lemma reflection_perm_eq_reflection_perm_iff_of_isSMulRegular (h2 : IsSMulRegular M 2) : + P.reflection_perm i = P.reflection_perm j ↔ P.reflection i = P.reflection j := by + refine ⟨fun h ↦ ?_, fun h ↦ Equiv.ext fun k ↦ P.root.injective <| by simp [h]⟩ + suffices ⇑(P.reflection i) = ⇑(P.reflection j) from DFunLike.coe_injective this + replace h2 : IsSMulRegular (M → M) 2 := IsSMulRegular.pi fun _ ↦ h2 + exact h2 <| P.two_nsmul_reflection_eq_of_perm_eq i j h + +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 + | mem x hx => + obtain ⟨k, rfl⟩ := hx + simp only [← root_reflection_perm, h] + | zero => simp + | add x _ y _ hx hy => simp [hx, hy] + | smul t x _ hx => simp [hx] + · ext k + apply P.root.injective + simp [h (P.root k) (Submodule.subset_span <| mem_range_self k)] + +lemma _root_.RootSystem.reflection_perm_eq_reflection_perm_iff (P : RootSystem ι R M N) (i j : ι) : + P.reflection_perm i = P.reflection_perm j ↔ P.reflection i = P.reflection j := by + refine ⟨fun h ↦ ?_, fun h ↦ Equiv.ext fun k ↦ P.root.injective <| by simp [h]⟩ + ext x + exact (P.reflection_perm_eq_reflection_perm_iff_of_span i j).mp h x <| by simp + /-- The Coxeter Weight of a pair gives the weight of an edge in a Coxeter diagram, when it is finite. It is `4 cos² θ`, where `θ` describes the dihedral angle between hyperplanes. -/ def coxeterWeight : R := pairing P i j * pairing P j i @@ -294,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, 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 new file mode 100644 index 0000000000000..5d58b28dabbf4 --- /dev/null +++ b/Mathlib/LinearAlgebra/RootSystem/Hom.lean @@ -0,0 +1,125 @@ +/- +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 + +/-! +# Morphisms of root pairings +This file defines morphisms of root pairings, following the definition of morphisms of root data +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 + spaces, and a bijection on the set that indexes roots and coroots. + * `Hom.id`: The identity morphism. + * `Hom.comp`: The composite of two morphisms. + +## TODO + + * Special types of morphisms: Isogenies, weight/coweight space embeddings + * Weyl group reimplementation? + +-/ + +open Set Function + +noncomputable section + +variable {ι R M N : Type*} [CommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] + +namespace RootPairing + +/-- A morphism of root pairings is a pair of mutually transposed maps of weight and coweight spaces +that preserves roots and coroots. We make the map of indexing sets explicit. -/ +@[ext] +structure Hom {ι₂ M₂ N₂ : Type*} + [AddCommGroup M₂] [Module R M₂] [AddCommGroup N₂] [Module R N₂] + (P : RootPairing ι R M N) (Q : RootPairing ι₂ R M₂ N₂) where + /-- A linear map on weight space. -/ + weightMap : M →ₗ[R] M₂ + /-- A contravariant linear map on coweight space. -/ + coweightMap : N₂ →ₗ[R] N + /-- A bijection on index sets. -/ + indexEquiv : ι ≃ ι₂ + weight_coweight_transpose : weightMap.dualMap ∘ₗ Q.toDualRight = P.toDualRight ∘ₗ coweightMap + root_weightMap : weightMap ∘ P.root = Q.root ∘ indexEquiv + coroot_coweightMap : coweightMap ∘ Q.coroot = P.coroot ∘ indexEquiv.symm + +/-- The identity morphism of a root pairing. -/ +@[simps!] +def Hom.id (P : RootPairing ι R M N) : Hom P P where + weightMap := LinearMap.id + coweightMap := LinearMap.id + indexEquiv := Equiv.refl ι + weight_coweight_transpose := by simp + root_weightMap := by simp + coroot_coweightMap := by simp + +/-- Composition of morphisms -/ +@[simps!] +def Hom.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 + weightMap := g.weightMap ∘ₗ f.weightMap + coweightMap := f.coweightMap ∘ₗ g.coweightMap + indexEquiv := f.indexEquiv.trans g.indexEquiv + weight_coweight_transpose := by + ext φ x + rw [← LinearMap.dualMap_comp_dualMap, ← LinearMap.comp_assoc _ f.coweightMap, + ← f.weight_coweight_transpose, LinearMap.comp_assoc g.coweightMap, + ← g.weight_coweight_transpose, ← LinearMap.comp_assoc] + 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] + 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] + simp + +@[simp] +lemma Hom.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 + ext x <;> simp + +@[simp] +lemma Hom.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 + ext x <;> simp + +@[simp] +lemma Hom.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 + ext <;> simp + +/-- The endomorphism of a root pairing given by a reflection. -/ +@[simps!] +def Hom.reflection (P : RootPairing ι R M N) (i : ι) : Hom P P where + weightMap := P.reflection i + coweightMap := P.coreflection i + indexEquiv := P.reflection_perm i + weight_coweight_transpose := by + ext f x + simp only [LinearMap.coe_comp, LinearEquiv.coe_coe, comp_apply, + PerfectPairing.toDualRight_apply, LinearMap.dualMap_apply, PerfectPairing.flip_apply_apply, + LinearEquiv.comp_coe, LinearEquiv.trans_apply] + rw [RootPairing.reflection_apply, RootPairing.coreflection_apply] + 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 + +end RootPairing diff --git a/Mathlib/LinearAlgebra/RootSystem/OfBilinear.lean b/Mathlib/LinearAlgebra/RootSystem/OfBilinear.lean new file mode 100644 index 0000000000000..b339fa3a131cc --- /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 N : Type*} [CommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] + +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/RootPairingCat.lean b/Mathlib/LinearAlgebra/RootSystem/RootPairingCat.lean new file mode 100644 index 0000000000000..662e12e5e940c --- /dev/null +++ b/Mathlib/LinearAlgebra/RootSystem/RootPairingCat.lean @@ -0,0 +1,61 @@ +/- +Copyright (c) 2024 Scott Carnahan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Scott Carnahan +-/ +import Mathlib.LinearAlgebra.RootSystem.Hom +import Mathlib.CategoryTheory.Category.Basic + +/-! +# The category of root pairings +This file defines the category of root pairings, following the definition of category of root data +given in SGA III Exp. 21 Section 6. + +## Main definitions: + * `RootPairingCat`: Objects are root pairings. + +## TODO + + * Forgetful functors + * Functions passing between module maps and root pairing homs + +## Implementation details + +This is mostly copied from `ModuleCat`. + +-/ + +open Set Function CategoryTheory + +noncomputable section + +universe v u + +variable {R : Type u} [CommRing R] + +/-- Objects in the category of root pairings. -/ +structure RootPairingCat (R : Type u) [CommRing R] where + /-- The weight space of a root pairing. -/ + weight : Type v + [weightIsAddCommGroup : AddCommGroup weight] + [weightIsModule : Module R weight] + /-- The coweight space of a root pairing. -/ + coweight : Type v + [coweightIsAddCommGroup : AddCommGroup coweight] + [coweightIsModule : Module R coweight] + /-- The set that indexes roots and coroots. -/ + index : Type v + /-- The root pairing structure. -/ + pairing : RootPairing index R weight coweight + +attribute [instance] RootPairingCat.weightIsAddCommGroup RootPairingCat.weightIsModule +attribute [instance] RootPairingCat.coweightIsAddCommGroup RootPairingCat.coweightIsModule + +namespace RootPairingCat + +instance category : Category.{v, max (v+1) u} (RootPairingCat.{v} R) where + Hom P Q := RootPairing.Hom P.pairing Q.pairing + id P := RootPairing.Hom.id P.pairing + comp f g := RootPairing.Hom.comp g f + +end RootPairingCat 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/Semisimple.lean b/Mathlib/LinearAlgebra/Semisimple.lean index ea02d0bd4374e..3aeb94be63ed6 100644 --- a/Mathlib/LinearAlgebra/Semisimple.lean +++ b/Mathlib/LinearAlgebra/Semisimple.lean @@ -80,7 +80,7 @@ lemma eq_zero_of_isNilpotent_isSemisimple (hn : IsNilpotent f) (hs : f.IsSemisim 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⟩ @[simp] lemma isSemisimple_sub_algebraMap_iff {μ : R} : @@ -145,7 +145,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 +174,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 +187,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 f97b86492d2e9..99617d933657d 100644 --- a/Mathlib/LinearAlgebra/SesquilinearForm.lean +++ b/Mathlib/LinearAlgebra/SesquilinearForm.lean @@ -458,9 +458,40 @@ 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-/ +/-! ### Self-adjoint pairs -/ section SelfadjointPair @@ -704,7 +735,7 @@ theorem IsOrthoᵢ.not_isOrtho_basis_self_of_separatingLeft [Nontrivial R] intro ho refine v.ne_zero i (hB (v i) fun m ↦ ?_) obtain ⟨vi, rfl⟩ := v.repr.symm.surjective m - rw [Basis.repr_symm_apply, Finsupp.total_apply, Finsupp.sum, map_sum] + rw [Basis.repr_symm_apply, Finsupp.linearCombination_apply, Finsupp.sum, map_sum] apply Finset.sum_eq_zero rintro j - rw [map_smulₛₗ] @@ -733,7 +764,8 @@ theorem IsOrthoᵢ.separatingLeft_of_not_isOrtho_basis_self [NoZeroSMulDivisors ext i rw [Finsupp.zero_apply] specialize hB (v i) - simp_rw [Basis.repr_symm_apply, Finsupp.total_apply, Finsupp.sum, map_sum₂, map_smulₛₗ₂] at hB + simp_rw [Basis.repr_symm_apply, Finsupp.linearCombination_apply, Finsupp.sum, map_sum₂, + map_smulₛₗ₂] at hB rw [Finset.sum_eq_single i] at hB · exact (smul_eq_zero.mp hB).elim _root_.id (h i).elim · intro j _hj hij diff --git a/Mathlib/LinearAlgebra/Span.lean b/Mathlib/LinearAlgebra/Span.lean index 9e71038dfec4b..460f7003ad94b 100644 --- a/Mathlib/LinearAlgebra/Span.lean +++ b/Mathlib/LinearAlgebra/Span.lean @@ -74,7 +74,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 @@ -362,8 +362,9 @@ theorem coe_iSup_of_chain (a : ℕ →o Submodule R M) : (↑(⨆ k, a k) : Set /-- We can regard `coe_iSup_of_chain` as the statement that `(↑) : (Submodule R M) → Set M` is Scott continuous for the ω-complete partial order induced by the complete lattice structures. -/ theorem coe_scott_continuous : - OmegaCompletePartialOrder.Continuous' ((↑) : Submodule R M → Set M) := - ⟨SetLike.coe_mono, coe_iSup_of_chain⟩ + OmegaCompletePartialOrder.ωScottContinuous ((↑) : Submodule R M → Set M) := + OmegaCompletePartialOrder.ωScottContinuous.of_monotone_map_ωSup + ⟨SetLike.coe_mono, coe_iSup_of_chain⟩ @[simp] theorem mem_iSup_of_chain (a : ℕ →o Submodule R M) (m : M) : (m ∈ ⨆ k, a k) ↔ ∃ k, m ∈ a k := @@ -744,7 +745,7 @@ theorem span_prod_le (s : Set M) (t : Set M') : span R (s ×ˢ t) ≤ prod (span theorem prod_top : (prod ⊤ ⊤ : Submodule R (M × M')) = ⊤ := by ext; simp @[simp] -theorem prod_bot : (prod ⊥ ⊥ : Submodule R (M × M')) = ⊥ := by ext ⟨x, y⟩; simp [Prod.zero_eq_mk] +theorem prod_bot : (prod ⊥ ⊥ : Submodule R (M × M')) = ⊥ := by ext ⟨x, y⟩; simp theorem prod_mono {p p' : Submodule R M} {q q' : Submodule R M'} : p ≤ p' → q ≤ q' → prod p q ≤ prod p' q' := diff --git a/Mathlib/LinearAlgebra/TensorAlgebra/Basic.lean b/Mathlib/LinearAlgebra/TensorAlgebra/Basic.lean index bfa9c8e59147a..9355d09c2992a 100644 --- a/Mathlib/LinearAlgebra/TensorAlgebra/Basic.lean +++ b/Mathlib/LinearAlgebra/TensorAlgebra/Basic.lean @@ -177,7 +177,7 @@ theorem hom_ext {A : Type*} [Semiring A] [Algebra R A] {f g : TensorAlgebra R M -- This proof closely follows `FreeAlgebra.induction` /-- If `C` holds for the `algebraMap` of `r : R` into `TensorAlgebra R M`, the `ι` of `x : M`, -and is preserved under addition and muliplication, then it holds for all of `TensorAlgebra R M`. +and is preserved under addition and multiplication, then it holds for all of `TensorAlgebra R M`. -/ @[elab_as_elim] theorem induction {C : TensorAlgebra R M → Prop} diff --git a/Mathlib/LinearAlgebra/TensorAlgebra/Basis.lean b/Mathlib/LinearAlgebra/TensorAlgebra/Basis.lean index 197e95b75cf05..24e2067ed86e6 100644 --- a/Mathlib/LinearAlgebra/TensorAlgebra/Basis.lean +++ b/Mathlib/LinearAlgebra/TensorAlgebra/Basis.lean @@ -35,7 +35,7 @@ with its index. -/ noncomputable def equivFreeAlgebra (b : Basis κ R M) : TensorAlgebra R M ≃ₐ[R] FreeAlgebra R κ := AlgEquiv.ofAlgHom - (TensorAlgebra.lift _ (Finsupp.total _ _ _ (FreeAlgebra.ι _) ∘ₗ b.repr.toLinearMap)) + (TensorAlgebra.lift _ (Finsupp.linearCombination _ (FreeAlgebra.ι _) ∘ₗ b.repr.toLinearMap)) (FreeAlgebra.lift _ (ι R ∘ b)) (by ext; simp) (hom_ext <| b.ext fun i => by simp) diff --git a/Mathlib/LinearAlgebra/TensorAlgebra/ToTensorPower.lean b/Mathlib/LinearAlgebra/TensorAlgebra/ToTensorPower.lean index bb0ee53dd453c..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) : @@ -128,18 +128,18 @@ theorem _root_.TensorPower.list_prod_gradedMonoid_mk_single (n : ℕ) (x : Fin n rfl · intro n x₀ x ih rw [List.finRange_succ_eq_map, List.map_cons, List.prod_cons, List.map_map] - simp_rw [Function.comp, Fin.cons_zero, Fin.cons_succ] + simp_rw [Function.comp_def, Fin.cons_zero, Fin.cons_succ] rw [ih, GradedMonoid.mk_mul_mk, TensorPower.tprod_mul_tprod] refine TensorPower.gradedMonoid_eq_of_cast (add_comm _ _) ?_ dsimp only [GradedMonoid.mk] rw [TensorPower.cast_tprod] - simp_rw [Fin.append_left_eq_cons, Function.comp] + simp_rw [Fin.append_left_eq_cons, Function.comp_def] congr 1 with i theorem toDirectSum_tensorPower_tprod {n} (x : Fin n → M) : toDirectSum (tprod R M n x) = DirectSum.of _ n (PiTensorProduct.tprod R x) := by rw [tprod_apply, map_list_prod, List.map_ofFn] - simp_rw [Function.comp, toDirectSum_ι] + simp_rw [Function.comp_def, toDirectSum_ι] rw [DirectSum.list_prod_ofFn_of_eq_dProd] apply DirectSum.of_eq_of_gradedMonoid_eq rw [GradedMonoid.mk_list_dProd] diff --git a/Mathlib/LinearAlgebra/TensorPower.lean b/Mathlib/LinearAlgebra/TensorPower.lean index 0e0eed359fc0c..b05bd64ae042d 100644 --- a/Mathlib/LinearAlgebra/TensorPower.lean +++ b/Mathlib/LinearAlgebra/TensorPower.lean @@ -31,7 +31,7 @@ suppress_compilation open scoped TensorProduct -/-- Homogenous tensor powers $M^{\otimes n}$. `⨂[R]^n M` is a shorthand for +/-- Homogeneous tensor powers $M^{\otimes n}$. `⨂[R]^n M` is a shorthand for `⨂[R] (i : Fin n), M`. -/ abbrev TensorPower (R : Type*) (n : ℕ) (M : Type*) [CommSemiring R] [AddCommMonoid M] [Module R M] : Type _ := diff --git a/Mathlib/LinearAlgebra/TensorProduct/Basic.lean b/Mathlib/LinearAlgebra/TensorProduct/Basic.lean index 8cc95132b62e1..98e1a776a8717 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Basic.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Basic.lean @@ -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 @@ -526,6 +526,13 @@ theorem ext' {g h : M ⊗[R] N →ₗ[R] P} (H : ∀ x y, g (x ⊗ₜ y) = h (x TensorProduct.induction_on z (by simp_rw [LinearMap.map_zero]) H fun x y ihx ihy => by rw [g.map_add, h.map_add, ihx, ihy] +theorem ext₃ {g h : (M ⊗[R] N) ⊗[R] P →ₗ[R] Q} + (H : ∀ x y z, g (x ⊗ₜ y ⊗ₜ z) = h (x ⊗ₜ y ⊗ₜ z)) : g = h := + ext' fun x => TensorProduct.induction_on x + (fun x => by simp only [zero_tmul, map_zero]) + (fun x y => H x y) + (fun x y ihx ihy z => by rw [add_tmul, g.map_add, h.map_add, ihx, ihy]) + theorem lift.unique {g : M ⊗[R] N →ₗ[R] P} (H : ∀ x y, g (x ⊗ₜ y) = f x y) : g = lift f := ext' fun m n => by rw [H, lift.tmul] @@ -669,7 +676,7 @@ theorem comm_tmul (m : M) (n : N) : (TensorProduct.comm R M N) (m ⊗ₜ n) = n theorem comm_symm_tmul (m : M) (n : N) : (TensorProduct.comm R M N).symm (n ⊗ₜ m) = m ⊗ₜ n := rfl -lemma lift_comp_comm_eq (f : M →ₗ[R] N →ₗ[R] P) : +lemma lift_comp_comm_eq (f : M →ₗ[R] N →ₗ[R] P) : lift f ∘ₗ TensorProduct.comm R N M = lift f.flip := ext rfl end @@ -827,19 +834,19 @@ theorem map_id : map (id : M →ₗ[R] M) (id : N →ₗ[R] N) = .id := by simp only [mk_apply, id_coe, compr₂_apply, _root_.id, map_tmul] @[simp] -theorem map_one : map (1 : M →ₗ[R] M) (1 : N →ₗ[R] N) = 1 := +protected theorem map_one : map (1 : M →ₗ[R] M) (1 : N →ₗ[R] N) = 1 := map_id -theorem map_mul (f₁ f₂ : M →ₗ[R] M) (g₁ g₂ : N →ₗ[R] N) : +protected theorem map_mul (f₁ f₂ : M →ₗ[R] M) (g₁ g₂ : N →ₗ[R] N) : map (f₁ * f₂) (g₁ * g₂) = map f₁ g₁ * map f₂ g₂ := map_comp f₁ f₂ g₁ g₂ @[simp] protected theorem map_pow (f : M →ₗ[R] M) (g : N →ₗ[R] N) (n : ℕ) : map f g ^ n = map (f ^ n) (g ^ n) := by - induction' n with n ih - · simp only [Nat.zero_eq, pow_zero, map_one] - · simp only [pow_succ', ih, map_mul] + induction n with + | zero => simp only [pow_zero, TensorProduct.map_one] + | succ n ih => simp only [pow_succ', ih, TensorProduct.map_mul] theorem map_add_left (f₁ f₂ : M →ₗ[R] P) (g : N →ₗ[R] Q) : map (f₁ + f₂) g = map f₁ g + map f₂ g := by diff --git a/Mathlib/LinearAlgebra/TensorProduct/Graded/External.lean b/Mathlib/LinearAlgebra/TensorProduct/Graded/External.lean index 64465d3ce42e3..e9896dd5d9c21 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Graded/External.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Graded/External.lean @@ -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 b66de04b692fd..2560f546b9ab3 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Graded/Internal.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Graded/Internal.lean @@ -5,7 +5,6 @@ Authors: Eric Wieser -/ import Mathlib.LinearAlgebra.TensorProduct.Graded.External import Mathlib.RingTheory.GradedAlgebra.Basic -import Mathlib.GroupTheory.GroupAction.Ring /-! # Graded tensor products over graded algebras @@ -150,7 +149,7 @@ theorem mulHom_apply (x y : 𝒜 ᵍ⊗[R] ℬ) : = (auxEquiv R 𝒜 ℬ).symm (gradedMul R (𝒜 ·) (ℬ ·) (auxEquiv R 𝒜 ℬ x) (auxEquiv R 𝒜 ℬ y)) := rfl -/-- The multipication on the graded tensor product. +/-- The multiplication on the graded tensor product. See `GradedTensorProduct.coe_mul_coe` for a characterization on pure tensors. -/ instance : Mul (𝒜 ᵍ⊗[R] ℬ) where mul x y := mulHom 𝒜 ℬ x y @@ -179,17 +178,16 @@ instance instRing : Ring (𝒜 ᵍ⊗[R] ℬ) where mul_zero x := by simp_rw [mul_def, map_zero] zero_mul x := by simp_rw [mul_def, LinearMap.map_zero₂] -/-- The characterization of this multiplication on partially homogenous elements. -/ +/-- The characterization of this multiplication on partially homogeneous elements. -/ theorem tmul_coe_mul_coe_tmul {j₁ i₂ : ι} (a₁ : A) (b₁ : ℬ j₁) (a₂ : 𝒜 i₂) (b₂ : B) : (a₁ ᵍ⊗ₜ[R] (b₁ : B) * (a₂ : A) ᵍ⊗ₜ[R] b₂ : 𝒜 ᵍ⊗[R] ℬ) = (-1 : ℤˣ)^(j₁ * i₂) • ((a₁ * a₂ : A) ᵍ⊗ₜ (b₁ * b₂ : B)) := by dsimp only [mul_def, mulHom_apply, of_symm_of] dsimp [auxEquiv, tmul] - erw [decompose_coe, decompose_coe] + rw [decompose_coe, decompose_coe] simp_rw [← lof_eq_of R] rw [tmul_of_gradedMul_of_tmul] simp_rw [lof_eq_of R] - rw [LinearEquiv.symm_symm] -- Note: #8386 had to specialize `map_smul` to `LinearEquiv.map_smul` rw [@Units.smul_def _ _ (_) (_), ← Int.cast_smul_eq_zsmul R, LinearEquiv.map_smul, map_smul, Int.cast_smul_eq_zsmul R, ← @Units.smul_def _ _ (_) (_)] @@ -222,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] @@ -296,7 +294,7 @@ lemma algebraMap_def' (r : R) : algebraMap R (𝒜 ᵍ⊗[R] ℬ) r = 1 ᵍ⊗ variable {C} [Ring C] [Algebra R C] /-- The forwards direction of the universal property; an algebra morphism out of the graded tensor -product can be assembed from maps on each component that (anti)commute on pure elements of the +product can be assembled from maps on each component that (anti)commute on pure elements of the corresponding graded algebras. -/ def lift (f : A →ₐ[R] C) (g : B →ₐ[R] C) (h_anti_commutes : ∀ ⦃i j⦄ (a : 𝒜 i) (b : ℬ j), f a * g b = (-1 : ℤˣ)^(j * i) • (g b * f a)) : @@ -307,7 +305,7 @@ def lift (f : A →ₐ[R] C) (g : B →ₐ[R] C) ∘ₗ ((of R 𝒜 ℬ).symm : 𝒜 ᵍ⊗[R] ℬ →ₗ[R] A ⊗[R] B)) (by dsimp [Algebra.TensorProduct.one_def] - simp only [_root_.map_one, mul_one]) + simp only [map_one, mul_one]) (by rw [LinearMap.map_mul_iff] ext a₁ : 3 @@ -320,7 +318,7 @@ def lift (f : A →ₐ[R] C) (g : B →ₐ[R] C) rw [@Units.smul_def _ _ (_) (_), ← Int.cast_smul_eq_zsmul R, map_smul, map_smul, map_smul] rw [Int.cast_smul_eq_zsmul R, ← @Units.smul_def _ _ (_) (_)] rw [of_symm_of, map_tmul, LinearMap.mul'_apply] - simp_rw [AlgHom.toLinearMap_apply, _root_.map_mul] + simp_rw [AlgHom.toLinearMap_apply, map_mul] simp_rw [mul_assoc (f a₁), ← mul_assoc _ _ (g b₂), h_anti_commutes, mul_smul_comm, smul_mul_assoc, smul_smul, Int.units_mul_self, one_smul]) @@ -340,14 +338,14 @@ def liftEquiv : toFun fg := lift 𝒜 ℬ _ _ fg.prop invFun F := ⟨(F.comp (includeLeft 𝒜 ℬ), F.comp (includeRight 𝒜 ℬ)), fun i j a b => by dsimp - rw [← _root_.map_mul, ← _root_.map_mul F, tmul_coe_mul_coe_tmul, one_mul, mul_one, - AlgHom.map_smul_of_tower, tmul_one_mul_one_tmul, smul_smul, Int.units_mul_self, one_smul]⟩ - left_inv fg := by ext <;> (dsimp; simp only [_root_.map_one, mul_one, one_mul]) + rw [← map_mul, ← map_mul F, tmul_coe_mul_coe_tmul, one_mul, mul_one, AlgHom.map_smul_of_tower, + tmul_one_mul_one_tmul, smul_smul, Int.units_mul_self, one_smul]⟩ + left_inv fg := by ext <;> (dsimp; simp only [map_one, mul_one, one_mul]) right_inv F := by apply AlgHom.toLinearMap_injective ext dsimp - rw [← _root_.map_mul, tmul_one_mul_one_tmul] + rw [← map_mul, tmul_one_mul_one_tmul] /-- Two algebra morphism from the graded tensor product agree if their compositions with the left and right inclusions agree. -/ diff --git a/Mathlib/LinearAlgebra/TensorProduct/RightExactness.lean b/Mathlib/LinearAlgebra/TensorProduct/RightExactness.lean index 3cdcdf07810e4..14d7396e79842 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/RightExactness.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/RightExactness.lean @@ -6,6 +6,7 @@ Authors: Antoine Chambert-Loir import Mathlib.Algebra.Exact import Mathlib.RingTheory.TensorProduct.Basic +import Mathlib.RingTheory.Ideal.Quotient /-! # Right-exactness properties of tensor product @@ -170,14 +171,15 @@ variable {f : M →ₗ[R] N} {g : N →ₗ[R] P} (hfg : Exact f g) (hg : Function.Surjective g) /-- The direct map in `lTensor.equiv` -/ -noncomputable def lTensor.toFun : +noncomputable def lTensor.toFun (hfg : Exact f g) : Q ⊗[R] N ⧸ LinearMap.range (lTensor Q f) →ₗ[R] Q ⊗[R] P := Submodule.liftQ _ (lTensor Q g) <| by rw [LinearMap.range_le_iff_comap, ← LinearMap.ker_comp, ← lTensor_comp, hfg.linearMap_comp_eq_zero, lTensor_zero, ker_zero] /-- The inverse map in `lTensor.equiv_of_rightInverse` (computably, given a right inverse)-/ -noncomputable def lTensor.inverse_of_rightInverse {h : P → N} (hgh : Function.RightInverse h g) : +noncomputable def lTensor.inverse_of_rightInverse {h : P → N} (hfg : Exact f g) + (hgh : Function.RightInverse h g) : Q ⊗[R] P →ₗ[R] Q ⊗[R] N ⧸ LinearMap.range (lTensor Q f) := TensorProduct.lift <| LinearMap.flip <| { toFun := fun p ↦ Submodule.mkQ _ ∘ₗ ((TensorProduct.mk R _ _).flip (h p)) @@ -276,14 +278,15 @@ lemma lTensor_mkQ (N : Submodule R M) : exact lTensor_exact Q (LinearMap.exact_subtype_mkQ N) (Submodule.mkQ_surjective N) /-- The direct map in `rTensor.equiv` -/ -noncomputable def rTensor.toFun : +noncomputable def rTensor.toFun (hfg : Exact f g) : N ⊗[R] Q ⧸ range (rTensor Q f) →ₗ[R] P ⊗[R] Q := Submodule.liftQ _ (rTensor Q g) <| by rw [range_le_iff_comap, ← ker_comp, ← rTensor_comp, hfg.linearMap_comp_eq_zero, rTensor_zero, ker_zero] /-- The inverse map in `rTensor.equiv_of_rightInverse` (computably, given a right inverse) -/ -noncomputable def rTensor.inverse_of_rightInverse {h : P → N} (hgh : Function.RightInverse h g) : +noncomputable def rTensor.inverse_of_rightInverse {h : P → N} (hfg : Exact f g) + (hgh : Function.RightInverse h g) : P ⊗[R] Q →ₗ[R] N ⊗[R] Q ⧸ LinearMap.range (rTensor Q f) := TensorProduct.lift { toFun := fun p ↦ Submodule.mkQ _ ∘ₗ TensorProduct.mk R _ _ (h p) @@ -544,7 +547,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 @@ -563,7 +566,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] @@ -612,7 +615,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 @@ -631,7 +634,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 5e2c363f1116d..83b52e58279fd 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Subalgebra.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Subalgebra.lean @@ -3,9 +3,10 @@ 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.Dimension.Constructions +import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition import Mathlib.LinearAlgebra.TensorProduct.Submodule import Mathlib.RingTheory.TensorProduct.Basic -import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition /-! @@ -35,7 +36,7 @@ mainly used in the definition of linearly disjointness. open scoped TensorProduct -open FiniteDimensional +open Module noncomputable section @@ -193,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 @@ -205,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 eb444a275be7e..838f15025ec00 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Submodule.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Submodule.lean @@ -234,13 +234,13 @@ theorem comm_trans_rTensorOne : variable {M} in theorem mulLeftMap_eq_mulMap_comp {ι : Type*} [DecidableEq ι] (m : ι → M) : - mulLeftMap N m = mulMap M N ∘ₗ LinearMap.rTensor N (Finsupp.total ι M R m) ∘ₗ + mulLeftMap N m = mulMap M N ∘ₗ LinearMap.rTensor N (Finsupp.linearCombination R m) ∘ₗ (TensorProduct.finsuppScalarLeft R N ι).symm.toLinearMap := by ext; simp variable {N} in theorem mulRightMap_eq_mulMap_comp {ι : Type*} [DecidableEq ι] (n : ι → N) : - mulRightMap M n = mulMap M N ∘ₗ LinearMap.lTensor M (Finsupp.total ι N R n) ∘ₗ + mulRightMap M n = mulMap M N ∘ₗ LinearMap.lTensor M (Finsupp.linearCombination R n) ∘ₗ (TensorProduct.finsuppScalarRight R M ι).symm.toLinearMap := by ext; simp diff --git a/Mathlib/LinearAlgebra/TensorProduct/Tower.lean b/Mathlib/LinearAlgebra/TensorProduct/Tower.lean index da36cbf10939d..5ed4fbb0c5ba5 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 diff --git a/Mathlib/LinearAlgebra/TensorProduct/Vanishing.lean b/Mathlib/LinearAlgebra/TensorProduct/Vanishing.lean index 968e2a986f444..8a6dcf8f11f00 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Vanishing.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Vanishing.lean @@ -60,7 +60,7 @@ variable (R : Type u) [CommRing R] variable {M : Type u} [AddCommGroup M] [Module R M] variable {N : Type u} [AddCommGroup N] [Module R N] -open DirectSum LinearMap Function Submodule +open DirectSum LinearMap Function Submodule Finsupp namespace TensorProduct @@ -102,7 +102,7 @@ vanishes, then it vanishes trivially. -/ theorem vanishesTrivially_of_sum_tmul_eq_zero (hm : Submodule.span R (Set.range m) = ⊤) (hmn : ∑ i, m i ⊗ₜ n i = (0 : M ⊗[R] N)) : VanishesTrivially R m n := by -- Define a map $G \colon R^\iota \to M$ whose matrix entries are the $m_i$. It is surjective. - set G : (ι →₀ R) →ₗ[R] M := Finsupp.total ι M R m with hG + set G : (ι →₀ R) →ₗ[R] M := Finsupp.linearCombination R m with hG have G_basis_eq (i : ι) : G (Finsupp.single i 1) = m i := by simp [hG, toModule_lof] have G_surjective : Surjective G := by apply LinearMap.range_eq_top.mp @@ -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 _ @@ -154,7 +154,7 @@ theorem vanishesTrivially_of_sum_tmul_eq_zero (hm : Submodule.span R (Set.range · next h'x => rw [h'x, zero_smul] · rfl · rintro ⟨⟨⟨k, hk⟩, _⟩, _⟩ - simpa only [hG, Finsupp.total_apply, zero_smul, implies_true, Finsupp.sum_fintype] using + simpa only [hG, linearCombination_apply, zero_smul, implies_true, Finsupp.sum_fintype] using mem_ker.mp hk /-- **Equational criterion for vanishing** @@ -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 9bbcd7e816372..81598681a3b50 100644 --- a/Mathlib/LinearAlgebra/Trace.lean +++ b/Mathlib/LinearAlgebra/Trace.lean @@ -16,21 +16,16 @@ See also `LinearAlgebra/Matrix/Trace.lean` for the trace of a matrix. ## Tags linear_map, trace, diagonal - -/ - noncomputable section universe u v w namespace LinearMap -open Matrix - -open FiniteDimensional - -open TensorProduct +open scoped Matrix +open Module TensorProduct section @@ -64,16 +59,16 @@ theorem traceAux_eq : traceAux R b = traceAux R c := rw [LinearMap.toMatrix_comp _ b, LinearMap.toMatrix_comp _ c] _ = Matrix.trace (LinearMap.toMatrix c c f) := by rw [LinearMap.comp_id, LinearMap.comp_id] -open scoped Classical - variable (M) +open Classical in /-- Trace of an endomorphism independent of basis. -/ def trace : (M →ₗ[R] M) →ₗ[R] R := if H : ∃ s : Finset M, Nonempty (Basis s R M) then traceAux R H.choose_spec.some else 0 variable {M} +open Classical in /-- Auxiliary lemma for `trace_eq_matrix_trace`. -/ theorem trace_eq_matrix_trace_of_finset {s : Finset M} (b : Basis s R M) (f : M →ₗ[R] M) : trace R M f = Matrix.trace (LinearMap.toMatrix b b f) := by @@ -84,15 +79,17 @@ theorem trace_eq_matrix_trace_of_finset {s : Finset M} (b : Basis s R M) (f : M theorem trace_eq_matrix_trace (f : M →ₗ[R] M) : trace R M f = Matrix.trace (LinearMap.toMatrix b b f) := by + classical rw [trace_eq_matrix_trace_of_finset R b.reindexFinsetRange, ← traceAux_def, ← traceAux_def, traceAux_eq R b b.reindexFinsetRange] -theorem trace_mul_comm (f g : M →ₗ[R] M) : trace R M (f * g) = trace R M (g * f) := - if H : ∃ s : Finset M, Nonempty (Basis s R M) then by - let ⟨s, ⟨b⟩⟩ := H +theorem trace_mul_comm (f g : M →ₗ[R] M) : trace R M (f * g) = trace R M (g * f) := by + classical + by_cases H : ∃ s : Finset M, Nonempty (Basis s R M) + · let ⟨s, ⟨b⟩⟩ := H simp_rw [trace_eq_matrix_trace R b, LinearMap.toMatrix_mul] apply Matrix.trace_mul_comm - else by rw [trace, dif_neg H, LinearMap.zero_apply, LinearMap.zero_apply] + · rw [trace, dif_neg H, LinearMap.zero_apply, LinearMap.zero_apply] lemma trace_mul_cycle (f g h : M →ₗ[R] M) : trace R M (f * g * h) = trace R M (h * f * g) := by 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 88fe378a09004..b4258e60f795c 100644 --- a/Mathlib/Logic/Basic.lean +++ b/Mathlib/Logic/Basic.lean @@ -3,7 +3,6 @@ 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 -/ -import Mathlib.Init.Algebra.Classes import Mathlib.Tactic.Attr.Register import Mathlib.Tactic.Basic import Batteries.Logic @@ -11,6 +10,7 @@ import Batteries.Util.LibraryNote import Batteries.Tactic.Lint.Basic import Mathlib.Data.Nat.Notation import Mathlib.Data.Int.Notation +import Mathlib.Order.Defs /-! # Basic logic properties @@ -37,7 +37,9 @@ 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 [simp] cast_eq cast_heq imp_false +-- 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 if it is applied to a large term, so it can be used for elision, @@ -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'] @@ -413,26 +420,29 @@ theorem eqRec_heq' {α : Sort*} {a' : α} {motive : (a : α) → a' = a → Sort HEq (@Eq.rec α a' motive p a t) p := by subst t; rfl -set_option autoImplicit true in -theorem rec_heq_of_heq {C : α → Sort*} {x : C a} {y : β} (e : a = b) (h : HEq x y) : - HEq (e ▸ x) y := by subst e; exact h +theorem rec_heq_of_heq {α β : Sort _} {a b : α} {C : α → Sort*} {x : C a} {y : β} + (e : a = b) (h : HEq x y) : HEq (e ▸ x) y := by subst e; exact h -set_option autoImplicit true in -theorem rec_heq_iff_heq {C : α → Sort*} {x : C a} {y : β} {e : a = b} : +theorem rec_heq_iff_heq {α β : Sort _} {a b : α} {C : α → Sort*} {x : C a} {y : β} {e : a = b} : HEq (e ▸ x) y ↔ HEq x y := by subst e; rfl -set_option autoImplicit true in -theorem heq_rec_iff_heq {C : α → Sort*} {x : β} {y : C a} {e : a = b} : +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 @@ -458,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⟩ @@ -508,15 +518,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] @@ -527,12 +528,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⟩ @@ -611,10 +606,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 @@ -631,9 +622,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 @@ -672,29 +660,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 -/ @@ -705,7 +670,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 @@ -718,7 +683,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 @@ -747,12 +711,37 @@ def choice_of_byContradiction' {α : Sort*} (contra : ¬(α → False) → α) : lemma choose_eq' (a : α) : @Exists.choose _ (a = ·) ⟨a, rfl⟩ = a := (@choose_spec _ (a = ·) _).symm +alias axiom_of_choice := axiomOfChoice -- TODO: remove? rename in core? +alias by_cases := byCases -- TODO: remove? rename in core? +alias by_contradiction := byContradiction -- TODO: remove? rename in core? + +-- The remaining theorems in this section were ported from Lean 3, +-- but are currently unused in Mathlib, so have been deprecated. +-- If any are being used downstream, please remove the deprecation. + +alias prop_complete := propComplete -- TODO: remove? rename in core? + +@[elab_as_elim, deprecated (since := "2024-07-27")] theorem cases_true_false (p : Prop → Prop) + (h1 : p True) (h2 : p False) (a : Prop) : p a := + Or.elim (prop_complete a) (fun ht : a = True ↦ ht.symm ▸ h1) fun hf : a = False ↦ hf.symm ▸ h2 + +@[deprecated (since := "2024-07-27")] +theorem eq_false_or_eq_true (a : Prop) : a = False ∨ a = True := (prop_complete a).symm + +set_option linter.deprecated false in +@[deprecated (since := "2024-07-27")] +theorem cases_on (a : Prop) {p : Prop → Prop} (h1 : p True) (h2 : p False) : p a := + @cases_true_false p h1 h2 a + +set_option linter.deprecated false in +@[deprecated (since := "2024-07-27")] +theorem cases {p : Prop → Prop} (h1 : p True) (h2 : p False) (a) : p a := cases_on a h1 h2 + 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) @@ -760,7 +749,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⟩⟩ @@ -802,8 +791,6 @@ theorem exists_mem_of_exists (H : ∀ x, p x) : (∃ x, q x) → ∃ (x : _) (_ theorem exists_of_exists_mem : (∃ (x : _) (_ : p x), q x) → ∃ x, q x | ⟨x, _, hq⟩ => ⟨x, hq⟩ -theorem exists₂_imp : (∃ x h, P x h) → b ↔ ∀ x h, P x h → b := by simp - @[deprecated (since := "2024-03-23")] alias bex_of_exists := exists_mem_of_exists @[deprecated (since := "2024-03-23")] alias exists_of_bex := exists_of_exists_mem @[deprecated (since := "2024-03-23")] alias bex_imp := exists₂_imp @@ -937,6 +924,9 @@ variable [Decidable Q] theorem ite_and : ite (P ∧ Q) a b = ite P (ite Q a b) b := by by_cases hp : P <;> by_cases hq : Q <;> simp [hp, hq] +theorem ite_or : ite (P ∨ Q) a b = ite P a (ite Q a b) := by + by_cases hp : P <;> by_cases hq : Q <;> simp [hp, hq] + theorem dite_dite_comm {B : Q → α} {C : ¬P → ¬Q → α} (h : P → ¬Q) : (if p : P then A p else if q : Q then B q else C p q) = if q : Q then B q else if p : P then A p else C p q := @@ -968,13 +958,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 4869749bcd209..cf0e64c97bd1d 100644 --- a/Mathlib/Logic/Denumerable.lean +++ b/Mathlib/Logic/Denumerable.lean @@ -184,22 +184,19 @@ open Function Encodable /-! ### Subsets of `ℕ` -/ - variable {s : Set ℕ} [Infinite s] section Classical -open scoped Classical - -theorem exists_succ (x : s) : ∃ n, (x : ℕ) + n + 1 ∈ s := - _root_.by_contradiction fun h => - have : ∀ (a : ℕ) (_ : a ∈ s), a < x + 1 := fun a ha => - lt_of_not_ge fun hax => h ⟨a - (x + 1), by rwa [add_right_comm, Nat.add_sub_cancel' hax]⟩ - Fintype.false - ⟨(((Multiset.range (succ x)).filter (· ∈ s)).pmap - (fun (y : ℕ) (hy : y ∈ s) => Subtype.mk y hy) - (by simp [-Multiset.range_succ])).toFinset, - by simpa [Subtype.ext_iff_val, Multiset.mem_filter, -Multiset.range_succ] ⟩ +theorem exists_succ (x : s) : ∃ n, (x : ℕ) + n + 1 ∈ s := by + by_contra h + have : ∀ (a : ℕ) (_ : a ∈ s), a < x + 1 := fun a ha => + lt_of_not_ge fun hax => h ⟨a - (x + 1), by rwa [add_right_comm, Nat.add_sub_cancel' hax]⟩ + classical + exact Fintype.false + ⟨(((Multiset.range (succ x)).filter (· ∈ s)).pmap + (fun (y : ℕ) (hy : y ∈ s) => Subtype.mk y hy) (by simp [-Multiset.range_succ])).toFinset, + by simpa [Subtype.ext_iff_val, Multiset.mem_filter, -Multiset.range_succ] ⟩ end Classical @@ -297,7 +294,7 @@ private theorem right_inverse_aux : ∀ n, toFunAux (ofNat s n) = n 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 0f91bfa54fc08..c52ae8f8e8e1d 100644 --- a/Mathlib/Logic/Embedding/Basic.lean +++ b/Mathlib/Logic/Embedding/Basic.lean @@ -85,9 +85,6 @@ instance Equiv.coeEmbedding : Coe (α ≃ β) (α ↪ β) := @[instance] abbrev Equiv.Perm.coeEmbedding : Coe (Equiv.Perm α) (α ↪ α) := Equiv.coeEmbedding --- Porting note : `theorem Equiv.coe_eq_to_embedding : ↑f = f.toEmbedding` is a --- syntactic tautology in Lean 4 - end Equiv namespace Function diff --git a/Mathlib/Logic/Embedding/Set.lean b/Mathlib/Logic/Embedding/Set.lean index bff9f99b31ff2..0c0ce8045a169 100644 --- a/Mathlib/Logic/Embedding/Set.lean +++ b/Mathlib/Logic/Embedding/Set.lean @@ -90,7 +90,7 @@ variable {α : Type*} subtypes `{x // p x} ⊕ {x // q x}` such that `¬ p x` is sent to the right, when `Disjoint p q`. -See also `Equiv.sumCompl`, for when `IsCompl p q`. -/ +See also `Equiv.sumCompl`, for when `IsCompl p q`. -/ @[simps apply] def subtypeOrEquiv (p q : α → Prop) [DecidablePred p] (h : Disjoint p q) : { x // p x ∨ q x } ≃ { x // p x } ⊕ { x // q x } where diff --git a/Mathlib/Logic/Encodable/Basic.lean b/Mathlib/Logic/Encodable/Basic.lean index d6cac938c8892..60412ec201292 100644 --- a/Mathlib/Logic/Encodable/Basic.lean +++ b/Mathlib/Logic/Encodable/Basic.lean @@ -47,7 +47,7 @@ class Encodable (α : Type*) where --explicitly in Lean4 /-- Decoding from ℕ to Option α-/ decode : ℕ → Option α - /-- Invariant relationship between encoding and decoding-/ + /-- Invariant relationship between encoding and decoding -/ encodek : ∀ a, decode (encode a) = some a attribute [simp] Encodable.encodek diff --git a/Mathlib/Logic/Encodable/Lattice.lean b/Mathlib/Logic/Encodable/Lattice.lean index d5457863486ba..039681749b576 100644 --- a/Mathlib/Logic/Encodable/Lattice.lean +++ b/Mathlib/Logic/Encodable/Lattice.lean @@ -33,13 +33,12 @@ 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 | none => by - simp only [Option.mem_def, iUnion_of_empty, iUnion_empty] + simp only [Option.mem_def, iUnion_of_empty, iUnion_empty, reduceCtorEq] apply H0 | some b => by convert H1 b 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 d87713b0db049..198c48db494a9 100644 --- a/Mathlib/Logic/Equiv/Basic.lean +++ b/Mathlib/Logic/Equiv/Basic.lean @@ -9,7 +9,7 @@ import Mathlib.Data.Prod.Basic import Mathlib.Data.Sigma.Basic import Mathlib.Data.Subtype import Mathlib.Data.Sum.Basic -import Mathlib.Init.Data.Sigma.Basic +import Mathlib.Init.Algebra.Classes import Mathlib.Logic.Equiv.Defs import Mathlib.Logic.Function.Conjugate import Mathlib.Tactic.Coe @@ -39,7 +39,7 @@ In this file we continue the work on equivalences begun in `Logic/Equiv/Defs.lea `eb : β₁ ≃ β₂` using `Prod.map`. More definitions of this kind can be found in other files. - E.g., `Data/Equiv/TransferInstance.lean` does it for many algebraic type classes like + E.g., `Logic/Equiv/TransferInstance.lean` does it for many algebraic type classes like `Group`, `Module`, etc. ## Tags @@ -47,17 +47,18 @@ In this file we continue the work on equivalences begun in `Logic/Equiv/Defs.lea equivalence, congruence, bijective map -/ -set_option autoImplicit true - -universe u +universe u v w z open Function +-- Unless required to be `Type*`, all variables in this file are `Sort*` +variable {α α₁ α₂ β β₁ β₂ γ δ : Sort*} + namespace Equiv /-- `PProd α β` is equivalent to `α × β` -/ @[simps apply symm_apply] -def pprodEquivProd : PProd α β ≃ α × β where +def pprodEquivProd {α β} : PProd α β ≃ α × β where toFun x := (x.1, x.2) invFun x := ⟨x.1, x.2⟩ left_inv := fun _ => rfl @@ -75,13 +76,13 @@ def pprodCongr (e₁ : α ≃ β) (e₂ : γ ≃ δ) : PProd α γ ≃ PProd β /-- Combine two equivalences using `PProd` in the domain and `Prod` in the codomain. -/ @[simps! apply symm_apply] -def pprodProd (ea : α₁ ≃ α₂) (eb : β₁ ≃ β₂) : +def pprodProd {α₂ β₂} (ea : α₁ ≃ α₂) (eb : β₁ ≃ β₂) : PProd α₁ β₁ ≃ α₂ × β₂ := (ea.pprodCongr eb).trans pprodEquivProd /-- Combine two equivalences using `PProd` in the codomain and `Prod` in the domain. -/ @[simps! apply symm_apply] -def prodPProd (ea : α₁ ≃ α₂) (eb : β₁ ≃ β₂) : +def prodPProd {α₁ β₁} (ea : α₁ ≃ α₂) (eb : β₁ ≃ β₂) : α₁ × β₁ ≃ PProd α₂ β₂ := (ea.symm.pprodProd eb.symm).symm @@ -94,11 +95,11 @@ def pprodEquivProdPLift : PProd α β ≃ PLift α × PLift β := `Prod.map` as an equivalence. -/ -- Porting note: in Lean 3 there was also a @[congr] tag @[simps (config := .asFn) apply] -def prodCongr (e₁ : α₁ ≃ α₂) (e₂ : β₁ ≃ β₂) : α₁ × β₁ ≃ α₂ × β₂ := +def prodCongr {α₁ α₂ β₁ β₂} (e₁ : α₁ ≃ α₂) (e₂ : β₁ ≃ β₂) : α₁ × β₁ ≃ α₂ × β₂ := ⟨Prod.map e₁ e₂, Prod.map e₁.symm e₂.symm, fun ⟨a, b⟩ => by simp, fun ⟨a, b⟩ => by simp⟩ @[simp] -theorem prodCongr_symm (e₁ : α₁ ≃ α₂) (e₂ : β₁ ≃ β₂) : +theorem prodCongr_symm {α₁ α₂ β₁ β₂} (e₁ : α₁ ≃ α₂) (e₂ : β₁ ≃ β₂) : (prodCongr e₁ e₂).symm = prodCongr e₁.symm e₂.symm := rfl @@ -112,7 +113,7 @@ theorem coe_prodComm (α β) : (⇑(prodComm α β) : α × β → β × α) = P rfl @[simp] -theorem prodComm_apply (x : α × β) : prodComm α β x = x.swap := +theorem prodComm_apply {α β} (x : α × β) : prodComm α β x = x.swap := rfl @[simp] @@ -127,14 +128,14 @@ def prodAssoc (α β γ) : (α × β) × γ ≃ α × β × γ := /-- Four-way commutativity of `prod`. The name matches `mul_mul_mul_comm`. -/ @[simps apply] -def prodProdProdComm (α β γ δ : Type*) : (α × β) × γ × δ ≃ (α × γ) × β × δ where +def prodProdProdComm (α β γ δ) : (α × β) × γ × δ ≃ (α × γ) × β × δ where toFun abcd := ((abcd.1.1, abcd.2.1), (abcd.1.2, abcd.2.2)) invFun acbd := ((acbd.1.1, acbd.2.1), (acbd.1.2, acbd.2.2)) left_inv := fun ⟨⟨_a, _b⟩, ⟨_c, _d⟩⟩ => rfl right_inv := fun ⟨⟨_a, _c⟩, ⟨_b, _d⟩⟩ => rfl @[simp] -theorem prodProdProdComm_symm (α β γ δ : Type*) : +theorem prodProdProdComm_symm (α β γ δ) : (prodProdProdComm α β γ δ).symm = prodProdProdComm α γ β δ := rfl @@ -170,15 +171,14 @@ def prodUnique (α β) [Unique β] : α × β ≃ α := ((Equiv.refl α).prodCongr <| equivPUnit.{_,1} β).trans <| prodPUnit α @[simp] -theorem coe_prodUnique [Unique β] : (⇑(prodUnique α β) : α × β → α) = Prod.fst := +theorem coe_prodUnique {α β} [Unique β] : (⇑(prodUnique α β) : α × β → α) = Prod.fst := rfl -theorem prodUnique_apply [Unique β] (x : α × β) : prodUnique α β x = x.1 := +theorem prodUnique_apply {α β} [Unique β] (x : α × β) : prodUnique α β x = x.1 := rfl @[simp] -theorem prodUnique_symm_apply [Unique β] (x : α) : - (prodUnique α β).symm x = (x, default) := +theorem prodUnique_symm_apply {α β} [Unique β] (x : α) : (prodUnique α β).symm x = (x, default) := rfl /-- Any `Unique` type is a left identity for type product up to equivalence. -/ @@ -186,14 +186,14 @@ def uniqueProd (α β) [Unique β] : β × α ≃ α := ((equivPUnit.{_,1} β).prodCongr <| Equiv.refl α).trans <| punitProd α @[simp] -theorem coe_uniqueProd [Unique β] : (⇑(uniqueProd α β) : β × α → α) = Prod.snd := +theorem coe_uniqueProd {α β} [Unique β] : (⇑(uniqueProd α β) : β × α → α) = Prod.snd := rfl -theorem uniqueProd_apply [Unique β] (x : β × α) : uniqueProd α β x = x.2 := +theorem uniqueProd_apply {α β} [Unique β] (x : β × α) : uniqueProd α β x = x.2 := rfl @[simp] -theorem uniqueProd_symm_apply [Unique β] (x : α) : +theorem uniqueProd_symm_apply {α β} [Unique β] (x : α) : (uniqueProd α β).symm x = (default, x) := rfl @@ -203,16 +203,16 @@ def sigmaUnique (α) (β : α → Type*) [∀ a, Unique (β a)] : (a : α) × ( (Equiv.sigmaCongrRight fun a ↦ equivPUnit.{_,1} (β a)).trans <| sigmaPUnit α @[simp] -theorem coe_sigmaUnique {β : α → Type*} [∀ a, Unique (β a)] : +theorem coe_sigmaUnique {α} {β : α → Type*} [∀ a, Unique (β a)] : (⇑(sigmaUnique α β) : (a : α) × (β a) → α) = Sigma.fst := rfl -theorem sigmaUnique_apply {β : α → Type*} [∀ a, Unique (β a)] (x : (a : α) × β a) : +theorem sigmaUnique_apply {α} {β : α → Type*} [∀ a, Unique (β a)] (x : (a : α) × β a) : sigmaUnique α β x = x.1 := rfl @[simp] -theorem sigmaUnique_symm_apply {β : α → Type*} [∀ a, Unique (β a)] (x : α) : +theorem sigmaUnique_symm_apply {α} {β : α → Type*} [∀ a, Unique (β a)] (x : α) : (sigmaUnique α β).symm x = ⟨x, default⟩ := rfl @@ -247,7 +247,7 @@ def psumEquivSum (α β) : α ⊕' β ≃ α ⊕ β where /-- If `α ≃ α'` and `β ≃ β'`, then `α ⊕ β ≃ α' ⊕ β'`. This is `Sum.map` as an equivalence. -/ @[simps apply] -def sumCongr (ea : α₁ ≃ α₂) (eb : β₁ ≃ β₂) : α₁ ⊕ β₁ ≃ α₂ ⊕ β₂ := +def sumCongr {α₁ α₂ β₁ β₂} (ea : α₁ ≃ α₂) (eb : β₁ ≃ β₂) : α₁ ⊕ β₁ ≃ α₂ ⊕ β₂ := ⟨Sum.map ea eb, Sum.map ea.symm eb.symm, fun x => by simp, fun x => by simp⟩ /-- If `α ≃ α'` and `β ≃ β'`, then `α ⊕' β ≃ α' ⊕' β'`. -/ @@ -258,33 +258,35 @@ def psumCongr (e₁ : α ≃ β) (e₂ : γ ≃ δ) : α ⊕' γ ≃ β ⊕' δ right_inv := by rintro (x | x) <;> simp /-- Combine two `Equiv`s using `PSum` in the domain and `Sum` in the codomain. -/ -def psumSum (ea : α₁ ≃ α₂) (eb : β₁ ≃ β₂) : +def psumSum {α₂ β₂} (ea : α₁ ≃ α₂) (eb : β₁ ≃ β₂) : α₁ ⊕' β₁ ≃ α₂ ⊕ β₂ := (ea.psumCongr eb).trans (psumEquivSum _ _) /-- Combine two `Equiv`s using `Sum` in the domain and `PSum` in the codomain. -/ -def sumPSum (ea : α₁ ≃ α₂) (eb : β₁ ≃ β₂) : +def sumPSum {α₁ β₁} (ea : α₁ ≃ α₂) (eb : β₁ ≃ β₂) : α₁ ⊕ β₁ ≃ α₂ ⊕' β₂ := (ea.symm.psumSum eb.symm).symm @[simp] -theorem sumCongr_trans (e : α₁ ≃ β₁) (f : α₂ ≃ β₂) (g : β₁ ≃ γ₁) (h : β₂ ≃ γ₂) : +theorem sumCongr_trans {α₁ α₂ β₁ β₂ γ₁ γ₂} (e : α₁ ≃ β₁) (f : α₂ ≃ β₂) (g : β₁ ≃ γ₁) (h : β₂ ≃ γ₂) : (Equiv.sumCongr e f).trans (Equiv.sumCongr g h) = Equiv.sumCongr (e.trans g) (f.trans h) := by ext i cases i <;> rfl @[simp] -theorem sumCongr_symm (e : α ≃ β) (f : γ ≃ δ) : +theorem sumCongr_symm {α β γ δ} (e : α ≃ β) (f : γ ≃ δ) : (Equiv.sumCongr e f).symm = Equiv.sumCongr e.symm f.symm := rfl @[simp] -theorem sumCongr_refl : Equiv.sumCongr (Equiv.refl α) (Equiv.refl β) = Equiv.refl (α ⊕ β) := by +theorem sumCongr_refl {α β} : + Equiv.sumCongr (Equiv.refl α) (Equiv.refl β) = Equiv.refl (α ⊕ β) := by ext i cases i <;> rfl /-- A subtype of a sum is equivalent to a sum of subtypes. -/ -def subtypeSum {p : α ⊕ β → Prop} : {c // p c} ≃ {a // p (Sum.inl a)} ⊕ {b // p (Sum.inr b)} where +def subtypeSum {α β} {p : α ⊕ β → Prop} : + {c // p c} ≃ {a // p (Sum.inl a)} ⊕ {b // p (Sum.inr b)} where toFun c := match h : c.1 with | Sum.inl a => Sum.inl ⟨a, h ▸ c.2⟩ | Sum.inr b => Sum.inr ⟨b, h ▸ c.2⟩ @@ -297,25 +299,25 @@ def subtypeSum {p : α ⊕ β → Prop} : {c // p c} ≃ {a // p (Sum.inl a)} namespace Perm /-- Combine a permutation of `α` and of `β` into a permutation of `α ⊕ β`. -/ -abbrev sumCongr (ea : Equiv.Perm α) (eb : Equiv.Perm β) : Equiv.Perm (α ⊕ β) := +abbrev sumCongr {α β} (ea : Equiv.Perm α) (eb : Equiv.Perm β) : Equiv.Perm (α ⊕ β) := Equiv.sumCongr ea eb @[simp] -theorem sumCongr_apply (ea : Equiv.Perm α) (eb : Equiv.Perm β) (x : α ⊕ β) : +theorem sumCongr_apply {α β} (ea : Equiv.Perm α) (eb : Equiv.Perm β) (x : α ⊕ β) : sumCongr ea eb x = Sum.map (⇑ea) (⇑eb) x := Equiv.sumCongr_apply ea eb x -- Porting note: it seems the general theorem about `Equiv` is now applied, so there's no need -- to have this version also have `@[simp]`. Similarly for below. -theorem sumCongr_trans (e : Equiv.Perm α) (f : Equiv.Perm β) (g : Equiv.Perm α) +theorem sumCongr_trans {α β} (e : Equiv.Perm α) (f : Equiv.Perm β) (g : Equiv.Perm α) (h : Equiv.Perm β) : (sumCongr e f).trans (sumCongr g h) = sumCongr (e.trans g) (f.trans h) := Equiv.sumCongr_trans e f g h -theorem sumCongr_symm (e : Equiv.Perm α) (f : Equiv.Perm β) : +theorem sumCongr_symm {α β} (e : Equiv.Perm α) (f : Equiv.Perm β) : (sumCongr e f).symm = sumCongr e.symm f.symm := Equiv.sumCongr_symm e f -theorem sumCongr_refl : sumCongr (Equiv.refl α) (Equiv.refl β) = Equiv.refl (α ⊕ β) := +theorem sumCongr_refl {α β} : sumCongr (Equiv.refl α) (Equiv.refl β) = Equiv.refl (α ⊕ β) := Equiv.sumCongr_refl end Perm @@ -342,15 +344,15 @@ def sumAssoc (α β γ) : (α ⊕ β) ⊕ γ ≃ α ⊕ (β ⊕ γ) := rintro (_ | ⟨_ | _⟩) <;> rfl⟩ @[simp] -theorem sumAssoc_apply_inl_inl (a) : sumAssoc α β γ (inl (inl a)) = inl a := +theorem sumAssoc_apply_inl_inl {α β γ} (a) : sumAssoc α β γ (inl (inl a)) = inl a := rfl @[simp] -theorem sumAssoc_apply_inl_inr (b) : sumAssoc α β γ (inl (inr b)) = inr (inl b) := +theorem sumAssoc_apply_inl_inr {α β γ} (b) : sumAssoc α β γ (inl (inr b)) = inr (inl b) := rfl @[simp] -theorem sumAssoc_apply_inr (c) : sumAssoc α β γ (inr c) = inr (inr c) := +theorem sumAssoc_apply_inr {α β γ} (c) : sumAssoc α β γ (inr c) = inr (inr c) := rfl @[simp] @@ -366,6 +368,26 @@ theorem sumAssoc_symm_apply_inr_inl {α β γ} (b) : theorem sumAssoc_symm_apply_inr_inr {α β γ} (c) : (sumAssoc α β γ).symm (inr (inr c)) = inr c := rfl +/-- Four-way commutativity of `sum`. The name matches `add_add_add_comm`. -/ +@[simps apply] +def sumSumSumComm (α β γ δ) : (α ⊕ β) ⊕ γ ⊕ δ ≃ (α ⊕ γ) ⊕ β ⊕ δ where + toFun := + (sumAssoc (α ⊕ γ) β δ) ∘ (Sum.map (sumAssoc α γ β).symm (@id δ)) + ∘ (Sum.map (Sum.map (@id α) (sumComm β γ)) (@id δ)) + ∘ (Sum.map (sumAssoc α β γ) (@id δ)) + ∘ (sumAssoc (α ⊕ β) γ δ).symm + invFun := + (sumAssoc (α ⊕ β) γ δ) ∘ (Sum.map (sumAssoc α β γ).symm (@id δ)) + ∘ (Sum.map (Sum.map (@id α) (sumComm β γ).symm) (@id δ)) + ∘ (Sum.map (sumAssoc α γ β) (@id δ)) + ∘ (sumAssoc (α ⊕ γ) β δ).symm + left_inv x := by rcases x with ((a | b) | (c | d)) <;> simp + right_inv x := by rcases x with ((a | c) | (b | d)) <;> simp + +@[simp] +theorem sumSumSumComm_symm (α β γ δ) : (sumSumSumComm α β γ δ).symm = sumSumSumComm α γ β δ := + rfl + /-- Sum with `IsEmpty` is equivalent to the original type. -/ @[simps symm_apply] def sumEmpty (α β) [IsEmpty β] : α ⊕ β ≃ α where @@ -378,7 +400,7 @@ def sumEmpty (α β) [IsEmpty β] : α ⊕ β ≃ α where right_inv _ := rfl @[simp] -theorem sumEmpty_apply_inl [IsEmpty β] (a : α) : sumEmpty α β (Sum.inl a) = a := +theorem sumEmpty_apply_inl {α β} [IsEmpty β] (a : α) : sumEmpty α β (Sum.inl a) = a := rfl /-- The sum of `IsEmpty` with any type is equivalent to that type. -/ @@ -387,7 +409,7 @@ def emptySum (α β) [IsEmpty α] : α ⊕ β ≃ β := (sumComm _ _).trans <| sumEmpty _ _ @[simp] -theorem emptySum_apply_inr [IsEmpty α] (b : β) : emptySum α β (Sum.inr b) = b := +theorem emptySum_apply_inr {α β} [IsEmpty α] (b : β) : emptySum α β (Sum.inr b) = b := rfl /-- `Option α` is equivalent to `α ⊕ PUnit` -/ @@ -397,23 +419,23 @@ def optionEquivSumPUnit (α) : Option α ≃ α ⊕ PUnit := fun s => by rcases s with (_ | ⟨⟨⟩⟩) <;> rfl⟩ @[simp] -theorem optionEquivSumPUnit_none : optionEquivSumPUnit α none = Sum.inr PUnit.unit := +theorem optionEquivSumPUnit_none {α} : optionEquivSumPUnit α none = Sum.inr PUnit.unit := rfl @[simp] -theorem optionEquivSumPUnit_some (a) : optionEquivSumPUnit α (some a) = Sum.inl a := +theorem optionEquivSumPUnit_some {α} (a) : optionEquivSumPUnit α (some a) = Sum.inl a := rfl @[simp] -theorem optionEquivSumPUnit_coe (a : α) : optionEquivSumPUnit α a = Sum.inl a := +theorem optionEquivSumPUnit_coe {α} (a : α) : optionEquivSumPUnit α a = Sum.inl a := rfl @[simp] -theorem optionEquivSumPUnit_symm_inl (a) : (optionEquivSumPUnit α).symm (Sum.inl a) = a := +theorem optionEquivSumPUnit_symm_inl {α} (a) : (optionEquivSumPUnit α).symm (Sum.inl a) = a := rfl @[simp] -theorem optionEquivSumPUnit_symm_inr (a) : (optionEquivSumPUnit α).symm (Sum.inr a) = none := +theorem optionEquivSumPUnit_symm_inr {α} (a) : (optionEquivSumPUnit α).symm (Sum.inr a) = none := rfl /-- The set of `x : Option α` such that `isSome x` is equivalent to `α`. -/ @@ -427,7 +449,7 @@ def optionIsSomeEquiv (α) : { x : Option α // x.isSome } ≃ α where /-- The product over `Option α` of `β a` is the binary product of the product over `α` of `β (some α)` and `β none` -/ @[simps] -def piOptionEquivProd {β : Option α → Type*} : +def piOptionEquivProd {α} {β : Option α → Type*} : (∀ a : Option α, β a) ≃ β none × ∀ a : α, β (some a) where toFun f := (f none, fun a => f (some a)) invFun x a := Option.casesOn a x.fst x.snd @@ -438,7 +460,7 @@ def piOptionEquivProd {β : Option α → Type*} : `β` to be types from the same universe, so it cannot be used directly to transfer theorems about sigma types to theorems about sum types. In many cases one can use `ULift` to work around this difficulty. -/ -def sumEquivSigmaBool (α β : Type u) : α ⊕ β ≃ Σ b : Bool, b.casesOn α β := +def sumEquivSigmaBool (α β) : α ⊕ β ≃ Σ b : Bool, b.casesOn α β := ⟨fun s => s.elim (fun x => ⟨false, x⟩) fun x => ⟨true, x⟩, fun s => match s with | ⟨false, a⟩ => inl a @@ -473,7 +495,7 @@ the sum of the two subtypes `{a // p a}` and its complement `{a // ¬ p a}` is naturally equivalent to `α`. See `subtypeOrEquiv` for sum types over subtypes `{x // p x}` and `{x // q x}` -that are not necessarily `IsCompl p q`. -/ +that are not necessarily `IsCompl p q`. -/ def sumCompl {α : Type*} (p : α → Prop) [DecidablePred p] : { a // p a } ⊕ { a // ¬p a } ≃ α where toFun := Sum.elim Subtype.val Subtype.val @@ -487,32 +509,32 @@ def sumCompl {α : Type*} (p : α → Prop) [DecidablePred p] : split_ifs <;> rfl @[simp] -theorem sumCompl_apply_inl (p : α → Prop) [DecidablePred p] (x : { a // p a }) : +theorem sumCompl_apply_inl {α} (p : α → Prop) [DecidablePred p] (x : { a // p a }) : sumCompl p (Sum.inl x) = x := rfl @[simp] -theorem sumCompl_apply_inr (p : α → Prop) [DecidablePred p] (x : { a // ¬p a }) : +theorem sumCompl_apply_inr {α} (p : α → Prop) [DecidablePred p] (x : { a // ¬p a }) : sumCompl p (Sum.inr x) = x := rfl @[simp] -theorem sumCompl_apply_symm_of_pos (p : α → Prop) [DecidablePred p] (a : α) (h : p a) : +theorem sumCompl_apply_symm_of_pos {α} (p : α → Prop) [DecidablePred p] (a : α) (h : p a) : (sumCompl p).symm a = Sum.inl ⟨a, h⟩ := dif_pos h @[simp] -theorem sumCompl_apply_symm_of_neg (p : α → Prop) [DecidablePred p] (a : α) (h : ¬p a) : +theorem sumCompl_apply_symm_of_neg {α} (p : α → Prop) [DecidablePred p] (a : α) (h : ¬p a) : (sumCompl p).symm a = Sum.inr ⟨a, h⟩ := dif_neg h /-- Combines an `Equiv` between two subtypes with an `Equiv` between their complements to form a permutation. -/ -def subtypeCongr {p q : α → Prop} [DecidablePred p] [DecidablePred q] +def subtypeCongr {α} {p q : α → Prop} [DecidablePred p] [DecidablePred q] (e : { x // p x } ≃ { x // q x }) (f : { x // ¬p x } ≃ { x // ¬q x }) : Perm α := (sumCompl p).symm.trans ((sumCongr e f).trans (sumCompl q)) -variable {p : ε → Prop} [DecidablePred p] +variable {ε : Type*} {p : ε → Prop} [DecidablePred p] variable (ep ep' : Perm { a // p a }) (en en' : Perm { a // ¬p a }) /-- Combining permutations on `ε` that permute only inside or outside the subtype @@ -607,7 +629,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`. @@ -624,7 +646,7 @@ theorem piComm_symm {φ : α → β → Sort*} : (piComm φ).symm = (piComm <| s to the type of dependent functions of two arguments (i.e., functions to the space of functions). This is `Sigma.curry` and `Sigma.uncurry` together as an equiv. -/ -def piCurry {β : α → Type*} (γ : ∀ a, β a → Type*) : +def piCurry {α} {β : α → Type*} (γ : ∀ a, β a → Type*) : (∀ x : Σ i, β i, γ x.1 x.2) ≃ ∀ a b, γ a b where toFun := Sigma.curry invFun := Sigma.uncurry @@ -632,12 +654,12 @@ def piCurry {β : α → Type*} (γ : ∀ a, β a → Type*) : right_inv := Sigma.curry_uncurry -- `simps` overapplies these but `simps (config := .asFn)` under-applies them -@[simp] theorem piCurry_apply {β : α → Type*} (γ : ∀ a, β a → Type*) +@[simp] theorem piCurry_apply {α} {β : α → Type*} (γ : ∀ a, β a → Type*) (f : ∀ x : Σ i, β i, γ x.1 x.2) : piCurry γ f = Sigma.curry f := rfl -@[simp] theorem piCurry_symm_apply {β : α → Type*} (γ : ∀ a, β a → Type*) (f : ∀ a b, γ a b) : +@[simp] theorem piCurry_symm_apply {α} {β : α → Type*} (γ : ∀ a, β a → Type*) (f : ∀ a b, γ a b) : (piCurry γ).symm f = Sigma.uncurry f := rfl @@ -645,7 +667,7 @@ end section prodCongr -variable (e : α₁ → β₁ ≃ β₂) +variable {α₁ α₂ β₁ β₂ : Type*} (e : α₁ → β₁ ≃ β₂) /-- A family of equivalences `∀ (a : α₁), β₁ ≃ β₂` generates an equivalence between `β₁ × α₁` and `β₂ × α₁`. -/ @@ -717,7 +739,8 @@ theorem sigmaEquivProd_sigmaCongrRight : -- See also `Equiv.ofPreimageEquiv`. /-- A family of equivalences between fibers gives an equivalence between domains. -/ @[simps!] -def ofFiberEquiv {f : α → γ} {g : β → γ} (e : ∀ c, { a // f a = c } ≃ { b // g b = c }) : α ≃ β := +def ofFiberEquiv {α β γ} {f : α → γ} {g : β → γ} + (e : ∀ c, { a // f a = c } ≃ { b // g b = c }) : α ≃ β := (sigmaFiberEquiv f).symm.trans <| (Equiv.sigmaCongrRight e).trans (sigmaFiberEquiv g) theorem ofFiberEquiv_map {α β γ} {f : α → γ} {g : β → γ} @@ -742,7 +765,7 @@ end prodCongr namespace Perm -variable [DecidableEq α₁] (a : α₁) (e : Perm β₁) +variable {α₁ β₁ : Type*} [DecidableEq α₁] (a : α₁) (e : Perm β₁) /-- `prodExtendRight a e` extends `e : Perm β` to `Perm (α × β)` by sending `(a, b)` to `(a, e b)` and keeping the other `(a', b)` fixed. -/ @@ -802,7 +825,8 @@ open Sum /-- The type of dependent functions on a sum type `ι ⊕ ι'` is equivalent to the type of pairs of functions on `ι` and on `ι'`. This is a dependent version of `Equiv.sumArrowEquivProdArrow`. -/ @[simps] -def sumPiEquivProdPi (π : ι ⊕ ι' → Type*) : (∀ i, π i) ≃ (∀ i, π (inl i)) × ∀ i', π (inr i') where +def sumPiEquivProdPi {ι ι'} (π : ι ⊕ ι' → Type*) : + (∀ i, π i) ≃ (∀ i, π (inl i)) × ∀ i', π (inr i') where 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 @@ -811,7 +835,7 @@ def sumPiEquivProdPi (π : ι ⊕ ι' → Type*) : (∀ i, π i) ≃ (∀ i, π /-- The equivalence between a product of two dependent functions types and a single dependent function type. Basically a symmetric version of `Equiv.sumPiEquivProdPi`. -/ @[simps!] -def prodPiEquivSumPi (π : ι → Type u) (π' : ι' → Type u) : +def prodPiEquivSumPi {ι ι'} (π : ι → Type u) (π' : ι' → Type u) : ((∀ i, π i) × ∀ i', π' i') ≃ ∀ i, Sum.elim π π' i := sumPiEquivProdPi (Sum.elim π π') |>.symm @@ -823,22 +847,22 @@ def sumArrowEquivProdArrow (α β γ : Type*) : (α ⊕ β → γ) ≃ (α → rfl⟩ @[simp] -theorem sumArrowEquivProdArrow_apply_fst (f : α ⊕ β → γ) (a : α) : +theorem sumArrowEquivProdArrow_apply_fst {α β γ} (f : α ⊕ β → γ) (a : α) : (sumArrowEquivProdArrow α β γ f).1 a = f (inl a) := rfl @[simp] -theorem sumArrowEquivProdArrow_apply_snd (f : α ⊕ β → γ) (b : β) : +theorem sumArrowEquivProdArrow_apply_snd {α β γ} (f : α ⊕ β → γ) (b : β) : (sumArrowEquivProdArrow α β γ f).2 b = f (inr b) := rfl @[simp] -theorem sumArrowEquivProdArrow_symm_apply_inl (f : α → γ) (g : β → γ) (a : α) : +theorem sumArrowEquivProdArrow_symm_apply_inl {α β γ} (f : α → γ) (g : β → γ) (a : α) : ((sumArrowEquivProdArrow α β γ).symm (f, g)) (inl a) = f a := rfl @[simp] -theorem sumArrowEquivProdArrow_symm_apply_inr (f : α → γ) (g : β → γ) (b : β) : +theorem sumArrowEquivProdArrow_symm_apply_inr {α β γ} (f : α → γ) (g : β → γ) (b : β) : ((sumArrowEquivProdArrow α β γ).symm (f, g)) (inr b) = g b := rfl @@ -849,55 +873,55 @@ def sumProdDistrib (α β γ) : (α ⊕ β) × γ ≃ α × γ ⊕ β × γ := rintro ⟨_ | _, _⟩ <;> rfl, by rintro (⟨_, _⟩ | ⟨_, _⟩) <;> rfl⟩ @[simp] -theorem sumProdDistrib_apply_left (a : α) (c : γ) : +theorem sumProdDistrib_apply_left {α β γ} (a : α) (c : γ) : sumProdDistrib α β γ (Sum.inl a, c) = Sum.inl (a, c) := rfl @[simp] -theorem sumProdDistrib_apply_right (b : β) (c : γ) : +theorem sumProdDistrib_apply_right {α β γ} (b : β) (c : γ) : sumProdDistrib α β γ (Sum.inr b, c) = Sum.inr (b, c) := rfl @[simp] -theorem sumProdDistrib_symm_apply_left (a : α × γ) : +theorem sumProdDistrib_symm_apply_left {α β γ} (a : α × γ) : (sumProdDistrib α β γ).symm (inl a) = (inl a.1, a.2) := rfl @[simp] -theorem sumProdDistrib_symm_apply_right (b : β × γ) : +theorem sumProdDistrib_symm_apply_right {α β γ} (b : β × γ) : (sumProdDistrib α β γ).symm (inr b) = (inr b.1, b.2) := rfl /-- Type product is left distributive with respect to type sum up to an equivalence. -/ -def prodSumDistrib (α β γ : Type*) : α × (β ⊕ γ) ≃ (α × β) ⊕ (α × γ) := +def prodSumDistrib (α β γ) : α × (β ⊕ γ) ≃ (α × β) ⊕ (α × γ) := calc α × (β ⊕ γ) ≃ (β ⊕ γ) × α := prodComm _ _ _ ≃ (β × α) ⊕ (γ × α) := sumProdDistrib _ _ _ _ ≃ (α × β) ⊕ (α × γ) := sumCongr (prodComm _ _) (prodComm _ _) @[simp] -theorem prodSumDistrib_apply_left (a : α) (b : β) : +theorem prodSumDistrib_apply_left {α β γ} (a : α) (b : β) : prodSumDistrib α β γ (a, Sum.inl b) = Sum.inl (a, b) := rfl @[simp] -theorem prodSumDistrib_apply_right (a : α) (c : γ) : +theorem prodSumDistrib_apply_right {α β γ} (a : α) (c : γ) : prodSumDistrib α β γ (a, Sum.inr c) = Sum.inr (a, c) := rfl @[simp] -theorem prodSumDistrib_symm_apply_left (a : α × β) : +theorem prodSumDistrib_symm_apply_left {α β γ} (a : α × β) : (prodSumDistrib α β γ).symm (inl a) = (a.1, inl a.2) := rfl @[simp] -theorem prodSumDistrib_symm_apply_right (a : α × γ) : +theorem prodSumDistrib_symm_apply_right {α β γ} (a : α × γ) : (prodSumDistrib α β γ).symm (inr a) = (a.1, inr a.2) := rfl /-- An indexed sum of disjoint sums of types is equivalent to the sum of the indexed sums. -/ @[simps] -def sigmaSumDistrib (α β : ι → Type*) : +def sigmaSumDistrib {ι} (α β : ι → Type*) : (Σ i, α i ⊕ β i) ≃ (Σ i, α i) ⊕ (Σ i, β i) := ⟨fun p => p.2.map (Sigma.mk p.1) (Sigma.mk p.1), Sum.elim (Sigma.map id fun _ => Sum.inl) (Sigma.map id fun _ => Sum.inr), fun p => by @@ -905,7 +929,8 @@ def sigmaSumDistrib (α β : ι → Type*) : /-- The product of an indexed sum of types (formally, a `Sigma`-type `Σ i, α i`) by a type `β` is equivalent to the sum of products `Σ i, (α i × β)`. -/ -def sigmaProdDistrib (α : ι → Type*) (β : Type*) : (Σ i, α i) × β ≃ Σ i, α i × β := +@[simps apply symm_apply] +def sigmaProdDistrib {ι} (α : ι → Type*) (β) : (Σ i, α i) × β ≃ Σ i, α i × β := ⟨fun p => ⟨p.1.1, (p.1.2, p.2)⟩, fun p => (⟨p.1, p.2.1⟩, p.2.2), fun p => by rcases p with ⟨⟨_, _⟩, _⟩ rfl, fun p => by @@ -964,7 +989,7 @@ def intEquivNatSumNat : ℤ ≃ ℕ ⊕ ℕ where end /-- An equivalence between `α` and `β` generates an equivalence between `List α` and `List β`. -/ -def listEquivOfEquiv (e : α ≃ β) : List α ≃ List β where +def listEquivOfEquiv {α β} (e : α ≃ β) : List α ≃ List β where toFun := List.map e invFun := List.map e.symm left_inv l := by rw [List.map_map, e.symm_comp_self, List.map_id] @@ -998,7 +1023,7 @@ def subtypeEquiv {p : α → Prop} {q : β → Prop} (e : α ≃ β) (h : ∀ a, left_inv a := Subtype.ext <| by simp right_inv b := Subtype.ext <| by simp -lemma coe_subtypeEquiv_eq_map {X Y : Type*} {p : X → Prop} {q : Y → Prop} (e : X ≃ Y) +lemma coe_subtypeEquiv_eq_map {X Y} {p : X → Prop} {q : Y → Prop} (e : X ≃ Y) (h : ∀ x, p x ↔ q (e x)) : ⇑(e.subtypeEquiv h) = Subtype.map e (h · |>.mp) := rfl @@ -1077,25 +1102,25 @@ def subtypeSubtypeEquivSubtypeInter {α : Type u} (p q : α → Prop) : /-- If the outer subtype has more restrictive predicate than the inner one, then we can drop the latter. -/ @[simps!] -def subtypeSubtypeEquivSubtype {p q : α → Prop} (h : ∀ {x}, q x → p x) : +def subtypeSubtypeEquivSubtype {α} {p q : α → Prop} (h : ∀ {x}, q x → p x) : { x : Subtype p // q x.1 } ≃ Subtype q := (subtypeSubtypeEquivSubtypeInter p _).trans <| subtypeEquivRight fun _ => and_iff_right_of_imp h /-- If a proposition holds for all elements, then the subtype is equivalent to the original type. -/ @[simps apply symm_apply] -def subtypeUnivEquiv {p : α → Prop} (h : ∀ x, p x) : Subtype p ≃ α := +def subtypeUnivEquiv {α} {p : α → Prop} (h : ∀ x, p x) : Subtype p ≃ α := ⟨fun x => x, fun x => ⟨x, h x⟩, fun _ => Subtype.eq rfl, fun _ => rfl⟩ /-- A subtype of a sigma-type is a sigma-type over a subtype. -/ -def subtypeSigmaEquiv (p : α → Type v) (q : α → Prop) : { y : Sigma p // q y.1 } ≃ Σ x : +def subtypeSigmaEquiv {α} (p : α → Type v) (q : α → Prop) : { y : Sigma p // q y.1 } ≃ Σ x : Subtype q, p x.1 := ⟨fun x => ⟨⟨x.1.1, x.2⟩, x.1.2⟩, fun x => ⟨⟨x.1.1, x.2⟩, x.1.2⟩, fun _ => rfl, fun _ => rfl⟩ /-- A sigma type over a subtype is equivalent to the sigma set over the original type, if the fiber is empty outside of the subset -/ -def sigmaSubtypeEquivOfSubset (p : α → Type v) (q : α → Prop) (h : ∀ x, p x → q x) : +def sigmaSubtypeEquivOfSubset {α} (p : α → Type v) (q : α → Prop) (h : ∀ x, p x → q x) : (Σ x : Subtype q, p x) ≃ Σ x : α, p x := (subtypeSigmaEquiv p q).symm.trans <| subtypeUnivEquiv fun x => h x.1 x.2 @@ -1125,7 +1150,7 @@ def sigmaSubtypeFiberEquivSubtype {α β : Type*} (f : α → β) {p : α → Pr /-- A sigma type over an `Option` is equivalent to the sigma set over the original type, if the fiber is empty at none. -/ -def sigmaOptionEquivOfSome (p : Option α → Type v) (h : p none → False) : +def sigmaOptionEquivOfSome {α} (p : Option α → Type v) (h : p none → False) : (Σ x : Option α, p x) ≃ Σ x : α, p (some x) := haveI h' : ∀ x, p x → x.isSome := by intro x @@ -1164,7 +1189,7 @@ def subtypePiEquivPi {β : α → Sort v} {p : ∀ a, β a → Prop} : /-- A subtype of a product defined by componentwise conditions is equivalent to a product of subtypes. -/ -def subtypeProdEquivProd {p : α → Prop} {q : β → Prop} : +def subtypeProdEquivProd {α β} {p : α → Prop} {q : β → Prop} : { c : α × β // p c.1 ∧ q c.2 } ≃ { a // p a } × { b // q b } where toFun := fun x => ⟨⟨x.1.1, x.2.1⟩, ⟨x.1.2, x.2.2⟩⟩ invFun := fun x => ⟨⟨x.1.1, x.2.1⟩, ⟨x.1.2, x.2.2⟩⟩ @@ -1173,14 +1198,15 @@ def subtypeProdEquivProd {p : α → Prop} {q : β → Prop} : /-- A subtype of a `Prod` that depends only on the first component is equivalent to the corresponding subtype of the first type times the second type. -/ -def prodSubtypeFstEquivSubtypeProd {p : α → Prop} : {s : α × β // p s.1} ≃ {a // p a} × β where +def prodSubtypeFstEquivSubtypeProd {α β} {p : α → Prop} : + {s : α × β // p s.1} ≃ {a // p a} × β where toFun x := ⟨⟨x.1.1, x.2⟩, x.1.2⟩ invFun x := ⟨⟨x.1.1, x.2⟩, x.1.2⟩ left_inv _ := rfl right_inv _ := rfl /-- A subtype of a `Prod` is equivalent to a sigma type whose fibers are subtypes. -/ -def subtypeProdEquivSigmaSubtype (p : α → β → Prop) : +def subtypeProdEquivSigmaSubtype {α β} (p : α → β → Prop) : { x : α × β // p x.1 x.2 } ≃ Σa, { b : β // p a b } where toFun x := ⟨x.1.1, x.1.2, x.property⟩ invFun x := ⟨⟨x.1, x.2⟩, x.2.property⟩ @@ -1233,7 +1259,7 @@ end section subtypeEquivCodomain -variable [DecidableEq X] {x : X} +variable {X Y : Sort*} [DecidableEq X] {x : X} /-- The type of all functions `X → Y` with prescribed values for all `x' ≠ x` is equivalent to the codomain `Y`. -/ @@ -1346,14 +1372,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 @@ -1533,6 +1559,9 @@ theorem toPerm_symm {f : α → α} (h : Involutive f) : (h.toPerm f).symm = h.t theorem toPerm_involutive {f : α → α} (h : Involutive f) : Involutive (h.toPerm f) := h +theorem symm_eq_self_of_involutive (f : Equiv.Perm α) (h : Involutive f) : f.symm = f := + DFunLike.coe_injective (h.leftInverse_iff.mp f.left_inv) + end Function.Involutive theorem PLift.eq_up_iff_down_eq {x : PLift α} {y : α} : x = PLift.up y ↔ x.down = y := @@ -1551,11 +1580,9 @@ namespace Equiv section -variable (P : α → Sort w) (e : α ≃ β) - /-- Transport dependent functions through an equivalence of the base space. -/ -@[simps] +@[simps apply, simps (config := .lemmasOnly) symm_apply] def piCongrLeft' (P : α → Sort*) (e : α ≃ β) : (∀ a, P a) ≃ ∀ b, P (e.symm b) where toFun f x := f (e.symm x) invFun f x := (e.symm_apply_apply x).ndrec (f (e x)) @@ -1579,13 +1606,11 @@ theorem piCongrLeft'_symm (P : Sort*) (e : α ≃ β) : LHS would have type `P a` while the RHS would have type `P (e.symm (e a))`. This lemma is a way around it in the case where `a` is of the form `e.symm b`, so we can use `g b` instead of `g (e (e.symm b))`. -/ +@[simp] lemma piCongrLeft'_symm_apply_apply (P : α → Sort*) (e : α ≃ β) (g : ∀ b, P (e.symm b)) (b : β) : (piCongrLeft' P e).symm g (e.symm b) = g b := by - change Eq.ndrec _ _ = _ - generalize_proofs hZa - revert hZa - rw [e.apply_symm_apply b] - simp + rw [piCongrLeft'_symm_apply, ← heq_iff_eq, rec_heq_iff_heq] + exact congr_arg_heq _ (e.apply_symm_apply _) end @@ -1627,13 +1652,13 @@ lemma piCongrLeft_apply_eq_cast {P : β → Sort v} {e : α ≃ β} piCongrLeft P e f b = cast (congr_arg P (e.apply_symm_apply b)) (f (e.symm b)) := Eq.rec_eq_cast _ _ -theorem piCongrLeft_sum_inl (π : ι'' → Type*) (e : ι ⊕ ι' ≃ ι'') (f : ∀ i, π (e (inl i))) +theorem piCongrLeft_sum_inl {ι ι' ι''} (π : ι'' → Type*) (e : ι ⊕ ι' ≃ ι'') (f : ∀ i, π (e (inl i))) (g : ∀ i, π (e (inr i))) (i : ι) : piCongrLeft π e (sumPiEquivProdPi (fun x => π (e x)) |>.symm (f, g)) (e (inl i)) = f i := by simp_rw [piCongrLeft_apply_eq_cast, sumPiEquivProdPi_symm_apply, sum_rec_congr _ _ _ (e.symm_apply_apply (inl i)), cast_cast, cast_eq] -theorem piCongrLeft_sum_inr (π : ι'' → Type*) (e : ι ⊕ ι' ≃ ι'') (f : ∀ i, π (e (inl i))) +theorem piCongrLeft_sum_inr {ι ι' ι''} (π : ι'' → Type*) (e : ι ⊕ ι' ≃ ι'') (f : ∀ i, π (e (inl i))) (g : ∀ i, π (e (inr i))) (j : ι') : piCongrLeft π e (sumPiEquivProdPi (fun x => π (e x)) |>.symm (f, g)) (e (inr j)) = g j := by simp_rw [piCongrLeft_apply_eq_cast, sumPiEquivProdPi_symm_apply, @@ -1663,7 +1688,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 @@ -1707,9 +1732,13 @@ instance [Std.Associative f] : Std.Associative (e.arrowCongr (e.arrowCongr e) f) instance [Std.IdempotentOp f] : Std.IdempotentOp (e.arrowCongr (e.arrowCongr e) f) := (e.semiconj₂_conj f).isIdempotent_right e.surjective +set_option linter.deprecated false in +@[deprecated (since := "2024-09-11")] instance [IsLeftCancel α₁ f] : IsLeftCancel β₁ (e.arrowCongr (e.arrowCongr e) f) := ⟨e.surjective.forall₃.2 fun x y z => by simpa using @IsLeftCancel.left_cancel _ f _ x y z⟩ +set_option linter.deprecated false in +@[deprecated (since := "2024-09-11")] instance [IsRightCancel α₁ f] : IsRightCancel β₁ (e.arrowCongr (e.arrowCongr e) f) := ⟨e.surjective.forall₃.2 fun x y z => by simpa using @IsRightCancel.right_cancel _ f _ x y z⟩ @@ -1718,7 +1747,7 @@ end BinaryOp section ULift @[simp] -theorem ulift_symm_down (x : α) : (Equiv.ulift.{u, v}.symm x).down = x := +theorem ulift_symm_down {α} (x : α) : (Equiv.ulift.{u, v}.symm x).down = x := rfl end ULift @@ -1742,7 +1771,7 @@ theorem Function.Injective.swap_comp funext fun _ => hf.swap_apply _ _ _ /-- If `α` is a subsingleton, then it is equivalent to `α × α`. -/ -def subsingletonProdSelfEquiv [Subsingleton α] : α × α ≃ α where +def subsingletonProdSelfEquiv {α} [Subsingleton α] : α × α ≃ α where toFun p := p.1 invFun a := (a, a) left_inv _ := Subsingleton.elim _ _ @@ -1773,6 +1802,8 @@ def uniqueEquivEquivUnique (α : Sort u) (β : Sort v) [Unique β] : Unique α namespace Function +variable {α' : Sort*} + theorem update_comp_equiv [DecidableEq α'] [DecidableEq α] (f : α → β) (g : α' ≃ α) (a : α) (v : β) : update f a v ∘ g = update (f ∘ g) (g.symm a) v := by @@ -1804,3 +1835,5 @@ theorem piCongrLeft'_symm_update [DecidableEq α] [DecidableEq β] (P : α → S simp [(e.piCongrLeft' P).symm_apply_eq, piCongrLeft'_update] end Function + +set_option linter.style.longFile 2000 diff --git a/Mathlib/Logic/Equiv/Defs.lean b/Mathlib/Logic/Equiv/Defs.lean index b42323a8b7ae0..79b92f29b0e1b 100644 --- a/Mathlib/Logic/Equiv/Defs.lean +++ b/Mathlib/Logic/Equiv/Defs.lean @@ -259,9 +259,7 @@ theorem Perm.coe_subsingleton {α : Type*} [Subsingleton α] (e : Perm α) : (e @[simp] theorem symm_trans_apply (f : α ≃ β) (g : β ≃ γ) (a : γ) : (f.trans g).symm a = f.symm (g.symm a) := rfl --- The `simp` attribute is needed to make this a `dsimp` lemma. --- `simp` will always rewrite with `Equiv.symm_symm` before this has a chance to fire. -@[simp, nolint simpNF] theorem symm_symm_apply (f : α ≃ β) (b : α) : f.symm.symm b = f b := rfl +theorem symm_symm_apply (f : α ≃ β) (b : α) : f.symm.symm b = f b := rfl theorem apply_eq_iff_eq (f : α ≃ β) {x y : α} : f x = f y ↔ x = y := EquivLike.apply_eq_iff_eq f @@ -288,7 +286,7 @@ theorem symm_apply_eq {α β} (e : α ≃ β) {x y} : e.symm x = y ↔ x = e y : theorem eq_symm_apply {α β} (e : α ≃ β) {x y} : y = e.symm x ↔ e y = x := (eq_comm.trans e.symm_apply_eq).trans eq_comm -@[simp] theorem symm_symm (e : α ≃ β) : e.symm.symm = e := by cases e; rfl +@[simp] theorem symm_symm (e : α ≃ β) : e.symm.symm = e := rfl theorem symm_bijective : Function.Bijective (Equiv.symm : (α ≃ β) → β ≃ α) := Function.bijective_iff_has_inverse.mpr ⟨_, symm_symm, symm_symm⟩ @@ -496,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⟩ @@ -613,7 +628,7 @@ theorem sigmaCongrRight_symm {α} {β₁ β₂ : α → Type*} (F : ∀ a, β₁ theorem sigmaCongrRight_refl {α} {β : α → Type*} : (sigmaCongrRight fun a => Equiv.refl (β a)) = Equiv.refl (Σ a, β a) := rfl -/-- A `PSigma` with `Prop` fibers is equivalent to the subtype. -/ +/-- A `PSigma` with `Prop` fibers is equivalent to the subtype. -/ def psigmaEquivSubtype {α : Type v} (P : α → Prop) : (Σ' i, P i) ≃ Subtype P where toFun x := ⟨x.1, x.2⟩ invFun x := ⟨x.1, x.2⟩ @@ -721,13 +736,13 @@ protected lemma exists_congr_left : (∃ a, p a) ↔ ∃ b, p (e.symm b) := e.symm.exists_congr_right.symm protected lemma exists_congr (h : ∀ a, p a ↔ q (e a)) : (∃ a, p a) ↔ ∃ b, q b := - e.exists_congr_left.trans $ by simp [h] + e.exists_congr_left.trans <| by simp [h] protected lemma exists_congr' (h : ∀ b, p (e.symm b) ↔ q b) : (∃ a, p a) ↔ ∃ b, q b := - e.exists_congr_left.trans $ by simp [h] + e.exists_congr_left.trans <| by simp [h] protected lemma existsUnique_congr_right : (∃! a, q (e a)) ↔ ∃! b, q b := - e.exists_congr $ by simpa using fun _ _ ↦ e.forall_congr (by simp) + e.exists_congr <| by simpa using fun _ _ ↦ e.forall_congr (by simp) protected lemma existsUnique_congr_left : (∃! a, p a) ↔ ∃! b, p (e.symm b) := e.symm.existsUnique_congr_right.symm @@ -739,12 +754,12 @@ alias exists_unique_congr_left := Equiv.existsUnique_congr_right alias exists_unique_congr_left' := Equiv.existsUnique_congr_left protected lemma existsUnique_congr (h : ∀ a, p a ↔ q (e a)) : (∃! a, p a) ↔ ∃! b, q b := - e.existsUnique_congr_left.trans $ by simp [h] + e.existsUnique_congr_left.trans <| by simp [h] @[deprecated (since := "2024-06-11")] alias exists_unique_congr := Equiv.existsUnique_congr protected lemma existsUnique_congr' (h : ∀ b, p (e.symm b) ↔ q b) : (∃! a, p a) ↔ ∃! b, q b := - e.existsUnique_congr_left.trans $ by simp [h] + e.existsUnique_congr_left.trans <| by simp [h] -- We next build some higher arity versions of `Equiv.forall_congr`. -- Although they appear to just be repeated applications of `Equiv.forall_congr`, @@ -756,7 +771,7 @@ protected lemma existsUnique_congr' (h : ∀ b, p (e.symm b) ↔ q b) : (∃! a, protected theorem forall₂_congr {α₁ α₂ β₁ β₂ : Sort*} {p : α₁ → β₁ → Prop} {q : α₂ → β₂ → Prop} (eα : α₁ ≃ α₂) (eβ : β₁ ≃ β₂) (h : ∀ {x y}, p x y ↔ q (eα x) (eβ y)) : (∀ x y, p x y) ↔ ∀ x y, q x y := - eα.forall_congr fun _ ↦ eβ.forall_congr $ @h _ + eα.forall_congr fun _ ↦ eβ.forall_congr <| @h _ protected theorem forall₂_congr' {α₁ α₂ β₁ β₂ : Sort*} {p : α₁ → β₁ → Prop} {q : α₂ → β₂ → Prop} (eα : α₁ ≃ α₂) (eβ : β₁ ≃ β₂) (h : ∀ {x y}, p (eα.symm x) (eβ.symm y) ↔ q x y) : @@ -766,7 +781,7 @@ protected theorem forall₃_congr {α₁ α₂ β₁ β₂ γ₁ γ₂ : Sort*} {p : α₁ → β₁ → γ₁ → Prop} {q : α₂ → β₂ → γ₂ → Prop} (eα : α₁ ≃ α₂) (eβ : β₁ ≃ β₂) (eγ : γ₁ ≃ γ₂) (h : ∀ {x y z}, p x y z ↔ q (eα x) (eβ y) (eγ z)) : (∀ x y z, p x y z) ↔ ∀ x y z, q x y z := - Equiv.forall₂_congr _ _ <| Equiv.forall_congr _ $ @h _ _ + Equiv.forall₂_congr _ _ <| Equiv.forall_congr _ <| @h _ _ protected theorem forall₃_congr' {α₁ α₂ β₁ β₂ γ₁ γ₂ : Sort*} {p : α₁ → β₁ → γ₁ → Prop} {q : α₂ → β₂ → γ₂ → Prop} @@ -829,17 +844,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/Embedding.lean b/Mathlib/Logic/Equiv/Embedding.lean index 5d383980cd4ea..10d04e64a9425 100644 --- a/Mathlib/Logic/Equiv/Embedding.lean +++ b/Mathlib/Logic/Equiv/Embedding.lean @@ -26,7 +26,7 @@ def sumEmbeddingEquivProdEmbeddingDisjoint {α β γ : Type*} : rintro _ ⟨a, h⟩ ⟨b, rfl⟩ simp only [trans_apply, inl_apply, inr_apply] at h have : Sum.inl a = Sum.inr b := f.injective h - simp only at this⟩ + simp only [reduceCtorEq] at this⟩ invFun := fun ⟨⟨f, g⟩, disj⟩ => ⟨fun x => match x with diff --git a/Mathlib/Logic/Equiv/Fin.lean b/Mathlib/Logic/Equiv/Fin.lean index 179b1141b3244..3453d19eac020 100644 --- a/Mathlib/Logic/Equiv/Fin.lean +++ b/Mathlib/Logic/Equiv/Fin.lean @@ -37,6 +37,59 @@ def finTwoEquiv : Fin 2 ≃ Bool where left_inv := Fin.forall_fin_two.2 <| by simp right_inv := Bool.forall_bool.2 <| by simp +/-! +### Tuples + +This section defines a bunch of equivalences between `n + 1`-tuples and products of `n`-tuples with +an entry. +-/ + +namespace Fin + +/-- Equivalence between tuples of length `n + 1` and pairs of an element and a tuple of length `n` +given by separating out the first element of the tuple. + +This is `Fin.cons` as an `Equiv`. -/ +@[simps] +def consEquiv (α : Fin (n + 1) → Type*) : α 0 × (∀ i, α (succ i)) ≃ ∀ i, α i where + toFun f := cons f.1 f.2 + invFun f := (f 0, tail f) + left_inv f := by simp + right_inv f := by simp + +/-- Equivalence between tuples of length `n + 1` and pairs of an element and a tuple of length `n` +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 _ + invFun f := ⟨f _, Fin.init f⟩ + left_inv f := by simp + right_inv f := by simp + +/-- Equivalence between tuples of length `n + 1` and pairs of an element and a tuple of length `n` +given by separating out the `p`-th element of the tuple. + +This is `Fin.insertNth` as an `Equiv`. -/ +@[simps] +def insertNthEquiv (α : Fin (n + 1) → Type u) (p : Fin (n + 1)) : + α p × (∀ i, α (p.succAbove i)) ≃ ∀ i, α i where + toFun f := insertNth p f.1 f.2 + invFun f := (f p, removeNth p f) + left_inv f := by ext <;> simp + right_inv f := by simp + +@[simp] lemma insertNthEquiv_zero (α : Fin (n + 1) → Type*) : insertNthEquiv α 0 = consEquiv α := + Equiv.symm_bijective.injective <| by ext <;> rfl + +/-- Note this lemma can only be written about non-dependent tuples as `insertNth (last n) = snoc` is +not a definitional equality. -/ +@[simp] lemma insertNthEquiv_last (n : ℕ) (α : Type*) : + insertNthEquiv (fun _ ↦ α) (last n) = snocEquiv (fun _ ↦ α) := by ext; simp + +end Fin + /-- `Π i : Fin 2, α i` is equivalent to `α 0 × α 1`. See also `finTwoArrowEquiv` for a non-dependent version and `prodEquivPiFinTwo` for a version with inputs `α β : Type u`. -/ @[simps (config := .asFn)] @@ -46,6 +99,12 @@ def piFinTwoEquiv (α : Fin 2 → Type u) : (∀ i, α i) ≃ α 0 × α 1 where left_inv _ := funext <| Fin.forall_fin_two.2 ⟨rfl, rfl⟩ right_inv := fun _ => rfl +/-! +### Miscellaneous + +This is currently not very sorted. PRs welcome! +-/ + theorem Fin.preimage_apply_01_prod {α : Fin 2 → Type u} (s : Set (α 0)) (t : Set (α 1)) : (fun f : ∀ i, α i => (f 0, f 1)) ⁻¹' s ×ˢ t = Set.pi Set.univ (Fin.cons s <| Fin.cons t finZeroElim) := by @@ -202,7 +261,7 @@ theorem finSuccEquivLast_symm_some (i : Fin n) : finSuccEquiv'_symm_none _ /-- Equivalence between `Π j : Fin (n + 1), α j` and `α i × Π j : Fin n, α (Fin.succAbove i j)`. -/ -@[simps (config := .asFn)] +@[simps (config := .asFn), deprecated Fin.insertNthEquiv (since := "2024-07-12")] def Equiv.piFinSuccAbove (α : Fin (n + 1) → Type u) (i : Fin (n + 1)) : (∀ j, α j) ≃ α i × ∀ j, α (i.succAbove j) where toFun f := (f i, i.removeNth f) @@ -211,9 +270,9 @@ def Equiv.piFinSuccAbove (α : Fin (n + 1) → Type u) (i : Fin (n + 1)) : right_inv f := by simp /-- Equivalence between `Fin (n + 1) → β` and `β × (Fin n → β)`. -/ -@[simps! (config := .asFn)] +@[simps! (config := .asFn), deprecated Fin.consEquiv (since := "2024-07-12")] def Equiv.piFinSucc (n : ℕ) (β : Type u) : (Fin (n + 1) → β) ≃ β × (Fin n → β) := - Equiv.piFinSuccAbove (fun _ => β) 0 + (Fin.insertNthEquiv (fun _ => β) 0).symm /-- An embedding `e : Fin (n+1) ↪ ι` corresponds to an embedding `f : Fin n ↪ ι` (corresponding the last `n` coordinates of `e`) together with a value not taken by `f` (corresponding to `e 0`). -/ @@ -236,9 +295,9 @@ def Equiv.embeddingFinSucc (n : ℕ) (ι : Type*) : /-- Equivalence between `Fin (n + 1) → β` and `β × (Fin n → β)` which separates out the last element of the tuple. -/ -@[simps! (config := .asFn)] +@[simps! (config := .asFn), deprecated Fin.snocEquiv (since := "2024-07-12")] def Equiv.piFinCastSucc (n : ℕ) (β : Type u) : (Fin (n + 1) → β) ≃ β × (Fin n → β) := - Equiv.piFinSuccAbove (fun _ => β) (.last _) + (Fin.insertNthEquiv (fun _ => β) (.last _)).symm /-- Equivalence between `Fin m ⊕ Fin n` and `Fin (m + n)` -/ def finSumFinEquiv : Fin m ⊕ Fin n ≃ Fin (m + n) where @@ -411,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 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 dd286968a4960..7a050c68661b5 100644 --- a/Mathlib/Logic/Equiv/List.lean +++ b/Mathlib/Logic/Equiv/List.lean @@ -14,7 +14,6 @@ This file defines some additional constructive equivalences using `Encodable` an function on `ℕ`. -/ - open Mathlib (Vector) open Nat List @@ -118,7 +117,7 @@ def encodableOfList [DecidableEq α] (l : List α) (H : ∀ x, x ∈ l) : Encoda /-- A finite type is encodable. Because the encoding is not unique, we wrap it in `Trunc` to preserve computability. -/ def _root_.Fintype.truncEncodable (α : Type*) [DecidableEq α] [Fintype α] : Trunc (Encodable α) := - @Quot.recOnSubsingleton' _ _ (fun s : Multiset α => (∀ x : α, x ∈ s) → Trunc (Encodable α)) _ + @Quot.recOnSubsingleton _ _ (fun s : Multiset α => (∀ x : α, x ∈ s) → Trunc (Encodable α)) _ Finset.univ.1 (fun l H => Trunc.mk <| encodableOfList l H) Finset.mem_univ /-- A noncomputable way to arbitrarily choose an ordering on a finite type. @@ -290,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 @@ -345,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 33a5a78ec5165..9c0c3d02003ee 100644 --- a/Mathlib/Logic/Equiv/Option.lean +++ b/Mathlib/Logic/Equiv/Option.lean @@ -7,7 +7,6 @@ import Mathlib.Control.EquivFunctor import Mathlib.Data.Option.Basic import Mathlib.Data.Subtype import Mathlib.Logic.Equiv.Defs -import Mathlib.Tactic.Cases /-! # Equivalences for `Option α` @@ -125,13 +124,13 @@ theorem option_symm_apply_none_iff : e.symm none = none ↔ e none = none := ⟨fun h => by simpa using (congr_arg e h).symm, fun h => by simpa using (congr_arg e.symm h).symm⟩ theorem some_removeNone_iff {x : α} : some (removeNone e x) = e none ↔ e.symm none = some x := by - cases' h : e (some x) with a + rcases h : e (some x) with a | a · rw [removeNone_none _ h] simpa using (congr_arg e.symm h).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] + 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 60d671cc71a1e..9dd50be972f0c 100644 --- a/Mathlib/Logic/Equiv/PartialEquiv.lean +++ b/Mathlib/Logic/Equiv/PartialEquiv.lean @@ -289,9 +289,7 @@ theorem symm_target : e.symm.target = e.source := rfl @[simp, mfld_simps] -theorem symm_symm : e.symm.symm = e := by - cases e - rfl +theorem symm_symm : e.symm.symm = e := rfl theorem symm_bijective : Function.Bijective (PartialEquiv.symm : PartialEquiv α β → PartialEquiv β α) := @@ -318,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 @@ -721,7 +719,7 @@ theorem EqOnSource.restr {e e' : PartialEquiv α β} (he : e ≈ e') (s : Set α theorem EqOnSource.source_inter_preimage_eq {e e' : PartialEquiv α β} (he : e ≈ e') (s : Set β) : e.source ∩ e ⁻¹' s = e'.source ∩ e' ⁻¹' s := by rw [he.eqOn.inter_preimage_eq, source_eq he] -/-- Composition of a partial equivlance and its inverse is equivalent to +/-- Composition of a partial equivalence and its inverse is equivalent to the restriction of the identity to the source. -/ theorem self_trans_symm : e.trans e.symm ≈ ofSet e.source := by have A : (e.trans e.symm).source = e.source := by mfld_set_tac @@ -845,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) diff --git a/Mathlib/Logic/Equiv/Set.lean b/Mathlib/Logic/Equiv/Set.lean index 9976bc2e53085..660731bfc4b8a 100644 --- a/Mathlib/Logic/Equiv/Set.lean +++ b/Mathlib/Logic/Equiv/Set.lean @@ -239,6 +239,9 @@ TODO: this is the same as `Equiv.setCongr`! -/ protected def ofEq {α : Type u} {s t : Set α} (h : s = t) : s ≃ t := Equiv.setCongr h +lemma Equiv.strictMono_setCongr {α : Type*} [PartialOrder α] {S T : Set α} (h : S = T) : + StrictMono (setCongr h) := fun _ _ ↦ id + /-- If `a ∉ s`, then `insert a s` is equivalent to `s ⊕ PUnit`. -/ protected def insert {α} {s : Set.{u} α} [DecidablePred (· ∈ s)] {a : α} (H : a ∉ s) : (insert a s : Set α) ≃ s ⊕ PUnit.{u + 1} := @@ -298,13 +301,13 @@ theorem sumCompl_symm_apply_of_not_mem {α : Type u} {s : Set α} [DecidablePred @[simp] theorem sumCompl_symm_apply {α : Type*} {s : Set α} [DecidablePred (· ∈ s)] {x : s} : - (Equiv.Set.sumCompl s).symm x = Sum.inl x := by - cases' x with x hx; exact Set.sumCompl_symm_apply_of_mem hx + (Equiv.Set.sumCompl s).symm x = Sum.inl x := + Set.sumCompl_symm_apply_of_mem x.2 @[simp] theorem sumCompl_symm_apply_compl {α : Type*} {s : Set α} [DecidablePred (· ∈ s)] - {x : (sᶜ : Set α)} : (Equiv.Set.sumCompl s).symm x = Sum.inr x := by - cases' x with x hx; exact Set.sumCompl_symm_apply_of_not_mem hx + {x : (sᶜ : Set α)} : (Equiv.Set.sumCompl s).symm x = Sum.inr x := + Set.sumCompl_symm_apply_of_not_mem x.2 /-- `sumDiffSubset s t` is the natural equivalence between `s ⊕ (t \ s)` and `t`, where `s` and `t` are two sets. -/ @@ -328,14 +331,12 @@ theorem sumDiffSubset_apply_inr {α} {s t : Set α} (h : s ⊆ t) [DecidablePred theorem sumDiffSubset_symm_apply_of_mem {α} {s t : Set α} (h : s ⊆ t) [DecidablePred (· ∈ s)] {x : t} (hx : x.1 ∈ s) : (Equiv.Set.sumDiffSubset h).symm x = Sum.inl ⟨x, hx⟩ := by apply (Equiv.Set.sumDiffSubset h).injective - simp only [apply_symm_apply, sumDiffSubset_apply_inl] - exact Subtype.eq rfl + simp only [apply_symm_apply, sumDiffSubset_apply_inl, Set.inclusion_mk] theorem sumDiffSubset_symm_apply_of_not_mem {α} {s t : Set α} (h : s ⊆ t) [DecidablePred (· ∈ s)] {x : t} (hx : x.1 ∉ s) : (Equiv.Set.sumDiffSubset h).symm x = Sum.inr ⟨x, ⟨x.2, hx⟩⟩ := by apply (Equiv.Set.sumDiffSubset h).injective - simp only [apply_symm_apply, sumDiffSubset_apply_inr] - exact Subtype.eq rfl + simp only [apply_symm_apply, sumDiffSubset_apply_inr, Set.inclusion_mk] /-- If `s` is a set with decidable membership, then the sum of `s ∪ t` and `s ∩ t` is equivalent to `s ⊕ t`. -/ diff --git a/Mathlib/Logic/Equiv/TransferInstance.lean b/Mathlib/Logic/Equiv/TransferInstance.lean index 4c39c97683377..f4afabe33c38e 100644 --- a/Mathlib/Logic/Equiv/TransferInstance.lean +++ b/Mathlib/Logic/Equiv/TransferInstance.lean @@ -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 23b06d62b1a9b..1af46bf00e7fa 100644 --- a/Mathlib/Logic/Function/Basic.lean +++ b/Mathlib/Logic/Function/Basic.lean @@ -3,9 +3,10 @@ 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.Logic.Nonempty -import Mathlib.Init.Set +import Mathlib.Data.Set.Defs import Mathlib.Logic.Basic +import Mathlib.Logic.ExistsUnique +import Mathlib.Logic.Nonempty import Batteries.Tactic.Init /-! @@ -117,10 +118,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 _ _ @@ -328,7 +334,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 @@ -358,7 +364,7 @@ end section InvFun -variable {α β : Sort*} [Nonempty α] {f : α → β} {a : α} {b : β} +variable {α β : Sort*} [Nonempty α] {f : α → β} {b : β} attribute [local instance] Classical.propDecidable @@ -441,10 +447,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) : @@ -456,7 +474,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. -/ @@ -652,6 +670,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 @@ -667,7 +689,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 @@ -763,6 +785,10 @@ theorem comp_self : f ∘ f = id := protected theorem leftInverse : LeftInverse f f := h +theorem leftInverse_iff {g : α → α} : + g.LeftInverse f ↔ g = f := + ⟨fun hg ↦ funext fun x ↦ by rw [← h x, hg, h], fun he ↦ he ▸ h.leftInverse⟩ + protected theorem rightInverse : RightInverse f f := h protected theorem injective : Injective f := h.leftInverse.injective @@ -927,7 +953,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 : α) : @@ -945,12 +971,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 202f3bf2502f2..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 φ = χ @@ -64,3 +64,5 @@ lemma comp_apply {M N P : Type*} rw [← h.comp_eq, Function.comp_apply] end CompTriple + +end CompTriple 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 57c703c66bfff..ab1505baf76fa 100644 --- a/Mathlib/Logic/Function/Defs.lean +++ b/Mathlib/Logic/Function/Defs.lean @@ -88,12 +88,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 - -@[simp] theorem const_comp {γ : Sort*} (f : α → β) (c : γ) : const β c ∘ f = const α c := rfl - -@[simp] theorem comp_const (f : β → φ) (b : β) : f ∘ const α b = const α (f b) := rfl +@[deprecated (since := "2024-09-24")] alias comp.assoc := comp_assoc @[deprecated (since := "2024-01-14")] alias comp_const_right := comp_const @@ -206,3 +203,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 a504860f1408a..52ef094f4d92b 100644 --- a/Mathlib/Logic/Godel/GodelBetaFunction.lean +++ b/Mathlib/Logic/Godel/GodelBetaFunction.lean @@ -13,7 +13,7 @@ import Mathlib.Data.Nat.Pairing # Gödel's Beta Function Lemma This file proves Gödel's Beta Function Lemma, used to prove the First Incompleteness Theorem. It -permits quantification over finite sequences of natural numbers in formal theories of arithmetic. +permits quantification over finite sequences of natural numbers in formal theories of arithmetic. This Beta Function has no connection with the unrelated Beta Function defined in analysis. Note that `Nat.beta` and `Nat.unbeta` provide similar functionality to `Encodable.encodeList` and `Encodable.decodeList`. We define these separately, because it is easier to prove that `Nat.beta` @@ -46,7 +46,7 @@ lemma coprime_mul_succ {n m a} (h : n ≤ m) (ha : m - n ∣ a) : Coprime (n * a Nat.coprime_of_dvd fun p pp hn hm => by have : p ∣ (m - n) * a := by simpa [Nat.succ_sub_succ, ← Nat.mul_sub_right_distrib] using - Nat.dvd_sub (Nat.succ_le_succ $ Nat.mul_le_mul_right a h) hm hn + Nat.dvd_sub (Nat.succ_le_succ <| Nat.mul_le_mul_right a h) hm hn have : p ∣ a := by rcases (Nat.Prime.dvd_mul pp).mp this with (hp | hp) · exact Nat.dvd_trans hp ha @@ -62,7 +62,7 @@ private def coprimes (a : Fin m → ℕ) : Fin m → ℕ := fun i => (i + 1) * ( lemma coprimes_lt (a : Fin m → ℕ) (i) : a i < coprimes a i := by have h₁ : a i < supOfSeq a := - Nat.lt_add_one_iff.mpr (le_max_of_le_right $ Finset.le_sup (by simp)) + Nat.lt_add_one_iff.mpr (le_max_of_le_right <| Finset.le_sup (by simp)) have h₂ : supOfSeq a ≤ (i + 1) * (supOfSeq a)! + 1 := le_trans (self_le_factorial _) (le_trans (Nat.le_mul_of_pos_left (supOfSeq a)! (succ_pos i)) (le_add_right _ _)) @@ -75,9 +75,8 @@ private lemma pairwise_coprime_coprimes (a : Fin m → ℕ) : Pairwise (Coprime unfold Function.onFun coprimes 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.succ_le_succ <| le_of_lt 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/IsEmpty.lean b/Mathlib/Logic/IsEmpty.lean index a7c0a41156632..b46a933890f1c 100644 --- a/Mathlib/Logic/IsEmpty.lean +++ b/Mathlib/Logic/IsEmpty.lean @@ -138,7 +138,7 @@ theorem not_isEmpty_iff : ¬IsEmpty α ↔ Nonempty α := @[simp] theorem isEmpty_Prop {p : Prop} : IsEmpty p ↔ ¬p := by - simp only [← not_nonempty_iff, nonempty_Prop] + simp only [← not_nonempty_iff, nonempty_prop] @[simp] theorem isEmpty_pi {π : α → Sort*} : IsEmpty (∀ a, π a) ↔ ∃ a, IsEmpty (π a) := by 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 67d8bd928a527..1c8198b9475d3 100644 --- a/Mathlib/Logic/Nonempty.lean +++ b/Mathlib/Logic/Nonempty.lean @@ -32,9 +32,7 @@ theorem Nonempty.exists {α} {p : Nonempty α → Prop} : (∃ h : Nonempty α, theorem exists_true_iff_nonempty {α : Sort*} : (∃ _ : α, True) ↔ Nonempty α := Iff.intro (fun ⟨a, _⟩ ↦ ⟨a⟩) fun ⟨a⟩ ↦ ⟨a, trivial⟩ -@[simp] -theorem nonempty_Prop {p : Prop} : Nonempty p ↔ p := - Iff.intro (fun ⟨h⟩ ↦ h) fun h ↦ ⟨h⟩ +@[deprecated (since := "2024-08-30")] alias nonempty_Prop := nonempty_prop theorem Nonempty.imp {α} {p : Prop} : (Nonempty α → p) ↔ (α → p) := Nonempty.forall @@ -101,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/Basic.lean b/Mathlib/Logic/Nontrivial/Basic.lean index fb49821633797..ee2fcbb4f7759 100644 --- a/Mathlib/Logic/Nontrivial/Basic.lean +++ b/Mathlib/Logic/Nontrivial/Basic.lean @@ -16,11 +16,8 @@ import Mathlib.Tactic.Attr.Register Results about `Nontrivial`. -/ - variable {α : Type*} {β : Type*} -open scoped Classical - -- `x` and `y` are explicit here, as they are often needed to guide typechecking of `h`. theorem nontrivial_of_lt [Preorder α] (x y : α) (h : x < y) : Nontrivial α := ⟨⟨x, y, ne_of_lt h⟩⟩ @@ -36,6 +33,7 @@ theorem Subtype.nontrivial_iff_exists_ne (p : α → Prop) (x : Subtype p) : Nontrivial (Subtype p) ↔ ∃ (y : α) (_ : p y), y ≠ x := by simp only [_root_.nontrivial_iff_exists_ne x, Subtype.exists, Ne, Subtype.ext_iff] +open Classical in /-- An inhabited type is either nontrivial, or has a unique element. -/ noncomputable def nontrivialPSumUnique (α : Type*) [Inhabited α] : Nontrivial α ⊕' Unique α := @@ -76,6 +74,7 @@ namespace Pi variable {I : Type*} {f : I → Type*} +open Classical in /-- A pi type is nontrivial if it's nonempty everywhere and nontrivial somewhere. -/ theorem nontrivial_at (i' : I) [inst : ∀ i, Nonempty (f i)] [Nontrivial (f i')] : Nontrivial (∀ i : I, f i) := by diff --git a/Mathlib/Logic/Nontrivial/Defs.lean b/Mathlib/Logic/Nontrivial/Defs.lean index a0173e706b52d..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 @@ -19,11 +18,8 @@ We introduce a typeclass `Nontrivial` formalizing this property. Basic results about nontrivial types are in `Mathlib.Logic.Nontrivial.Basic`. -/ - variable {α : Type*} {β : Type*} -open scoped Classical - /-- Predicate typeclass for expressing that a type is not reduced to a single element. In rings, this is equivalent to `0 ≠ 1`. In vector spaces, this is equivalent to positive dimension. -/ class Nontrivial (α : Type*) : Prop where @@ -44,6 +40,7 @@ protected theorem Decidable.exists_ne [Nontrivial α] [DecidableEq α] (x : α) exact ⟨y', h.symm⟩ · exact ⟨y, Ne.symm hx⟩ +open Classical in theorem exists_ne [Nontrivial α] (x : α) : ∃ y, y ≠ x := Decidable.exists_ne x -- `x` and `y` are explicit here, as they are often needed to guide typechecking of `h`. diff --git a/Mathlib/Logic/OpClass.lean b/Mathlib/Logic/OpClass.lean new file mode 100644 index 0000000000000..2f65fe0b3d85e --- /dev/null +++ b/Mathlib/Logic/OpClass.lean @@ -0,0 +1,60 @@ +/- +Copyright (c) 2014 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Leonardo de Moura +-/ + +/-! +# 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 587b569ca7820..13ae772203bbe 100644 --- a/Mathlib/Logic/Pairwise.lean +++ b/Mathlib/Logic/Pairwise.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl -/ import Mathlib.Logic.Function.Basic -import Mathlib.Init.Set +import Mathlib.Data.Set.Defs import Mathlib.Tactic.Common /-! @@ -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 9f30f820360f2..2a90c042f467f 100644 --- a/Mathlib/Logic/Relation.lean +++ b/Mathlib/Logic/Relation.lean @@ -5,8 +5,6 @@ Authors: Johannes Hölzl -/ import Mathlib.Logic.Function.Basic import Mathlib.Logic.Relator -import Mathlib.Init.Data.Quot -import Mathlib.Tactic.Cases import Mathlib.Tactic.Use import Mathlib.Tactic.MkIffOfInductiveProp import Mathlib.Tactic.SimpRw @@ -14,8 +12,8 @@ import Mathlib.Tactic.SimpRw /-! # Relation closures -This file defines the reflexive, transitive, and reflexive transitive closures of relations. -It also proves some basic results on definitions such as `EqvGen`. +This file defines the reflexive, transitive, reflexive transitive and equivalence closures +of relations and proves some basic results on them. Note that this is about unbundled relations, that is terms of types of the form `α → β → Prop`. For the bundled version, see `Rel`. @@ -32,6 +30,8 @@ the bundled version, see `Rel`. the reflexive closure of the transitive closure, or the transitive closure of the reflexive closure. In terms of rewriting systems, this means that `a` can be rewritten to `b` in a number of rewrites. +* `Relation.EqvGen`: Equivalence closure. `EqvGen r` relates everything `ReflTransGen r` relates, + plus for all related pairs it relates them in the opposite order. * `Relation.Comp`: Relation composition. We provide notation `∘r`. For `r : α → β → Prop` and `s : β → γ → Prop`, `r ∘r s`relates `a : α` and `c : γ` iff there exists `b : β` that's related to both. @@ -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 @@ -167,7 +167,7 @@ variable {rα rβ} /-- If `f : α → β` is a fibration between relations `rα` and `rβ`, and `a : α` is accessible under `rα`, then `f a` is accessible under `rβ`. -/ theorem _root_.Acc.of_fibration (fib : Fibration rα rβ f) {a} (ha : Acc rα a) : Acc rβ (f a) := by - induction' ha with a _ ih + induction ha with | intro a _ ih => ?_ refine Acc.intro (f a) fun b hr ↦ ?_ obtain ⟨a', hr', rfl⟩ := fib hr exact ih a' hr' @@ -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] @@ -229,9 +229,16 @@ inductive ReflGen (r : α → α → Prop) (a : α) : α → Prop | refl : ReflGen r a a | single {b} : r a b → ReflGen r a b -attribute [mk_iff] TransGen - +variable (r) in +/-- `EqvGen r`: equivalence closure of `r`. -/ +@[mk_iff] +inductive EqvGen : α → α → Prop + | rel x y : r x y → EqvGen x y + | refl x : EqvGen x x + | symm x y : EqvGen x y → EqvGen y x + | trans x y z : EqvGen x y → EqvGen y z → EqvGen x z +attribute [mk_iff] TransGen attribute [refl] ReflGen.refl namespace ReflGen @@ -267,9 +274,9 @@ theorem head (hab : r a b) (hbc : ReflTransGen r b c) : ReflTransGen r a c := by theorem symmetric (h : Symmetric r) : Symmetric (ReflTransGen r) := by intro x y h - induction' h with z w _ b c - · rfl - · apply Relation.ReflTransGen.head (h b) c + induction h with + | refl => rfl + | tail _ b c => apply Relation.ReflTransGen.head (h b) c theorem cases_tail : ReflTransGen r a b → b = a ∨ ∃ c, ReflTransGen r a c ∧ r c b := (cases_tail_iff r a b).1 @@ -309,9 +316,10 @@ theorem cases_head_iff : ReflTransGen r a b ↔ a = b ∨ ∃ c, r a c ∧ ReflT theorem total_of_right_unique (U : Relator.RightUnique r) (ab : ReflTransGen r a b) (ac : ReflTransGen r a c) : ReflTransGen r b c ∨ ReflTransGen r c b := by - induction' ab with b d _ bd IH - · exact Or.inl ac - · rcases IH with (IH | IH) + induction ab with + | refl => exact Or.inl ac + | tail _ bd IH => + rcases IH with (IH | IH) · rcases cases_head IH with (rfl | ⟨e, be, ec⟩) · exact Or.inr (single bd) · cases U bd be @@ -323,10 +331,9 @@ end ReflTransGen namespace TransGen theorem to_reflTransGen {a b} (h : TransGen r a b) : ReflTransGen r a b := by - induction' h with b h b c _ bc ab - · exact ReflTransGen.single h - · exact ReflTransGen.tail ab bc --- Porting note: in Lean 3 this function was called `to_refl` which seems wrong. + induction h with + | single h => exact ReflTransGen.single h + | tail _ bc ab => exact ReflTransGen.tail ab bc theorem trans_left (hab : TransGen r a b) (hbc : ReflTransGen r b c) : TransGen r a c := by induction hbc with @@ -336,9 +343,7 @@ theorem trans_left (hab : TransGen r a b) (hbc : ReflTransGen r b c) : TransGen instance : Trans (TransGen r) (ReflTransGen r) (TransGen r) := ⟨trans_left⟩ -@[trans] -theorem trans (hab : TransGen r a b) (hbc : TransGen r b c) : TransGen r a c := - trans_left hab hbc.to_reflTransGen +attribute [trans] trans instance : Trans (TransGen r) (TransGen r) (TransGen r) := ⟨trans⟩ @@ -384,9 +389,9 @@ instance : Trans (ReflTransGen r) (TransGen r) (TransGen r) := theorem tail'_iff : TransGen r a c ↔ ∃ b, ReflTransGen r a b ∧ r b c := by refine ⟨fun h ↦ ?_, fun ⟨b, hab, hbc⟩ ↦ tail' hab hbc⟩ - cases' h with _ hac b _ hab hbc - · exact ⟨_, by rfl, hac⟩ - · exact ⟨_, hab.to_reflTransGen, hbc⟩ + cases h with + | single hac => exact ⟨_, by rfl, hac⟩ + | tail hab hbc => exact ⟨_, hab.to_reflTransGen, hbc⟩ theorem head'_iff : TransGen r a c ↔ ∃ b, r a b ∧ ReflTransGen r b c := by refine ⟨fun h ↦ ?_, fun ⟨b, hab, hbc⟩ ↦ head' hab hbc⟩ @@ -458,9 +463,9 @@ lemma transGen_minimal {r' : α → α → Prop} (hr' : Transitive r') (h : ∀ simpa [transGen_eq_self hr'] using TransGen.mono h hxy theorem TransGen.swap (h : TransGen r b a) : TransGen (swap r) a b := by - induction' h with b h b c _ hbc ih - · exact TransGen.single h - · exact ih.head hbc + induction h with + | single h => exact TransGen.single h + | tail _ hbc ih => exact ih.head hbc theorem transGen_swap : TransGen (swap r) a b ↔ TransGen r b a := ⟨TransGen.swap, TransGen.swap⟩ @@ -476,9 +481,9 @@ theorem reflTransGen_iff_eq (h : ∀ b, ¬r a b) : ReflTransGen r a b ↔ b = a theorem reflTransGen_iff_eq_or_transGen : ReflTransGen r a b ↔ b = a ∨ TransGen r a b := by refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ - · cases' h with c _ hac hcb - · exact Or.inl rfl - · exact Or.inr (TransGen.tail' hac hcb) + · cases h with + | refl => exact Or.inl rfl + | tail hac hcb => exact Or.inr (TransGen.tail' hac hcb) · rcases h with (rfl | h) · rfl · exact h.to_reflTransGen @@ -494,9 +499,9 @@ theorem ReflTransGen.mono {p : α → α → Prop} : (∀ a b, r a b → p a b) theorem reflTransGen_eq_self (refl : Reflexive r) (trans : Transitive r) : ReflTransGen r = r := funext fun a ↦ funext fun b ↦ propext <| ⟨fun h ↦ by - induction' h with b c _ h₂ IH - · apply refl - · exact trans IH h₂, single⟩ + induction h with + | refl => apply refl + | tail _ h₂ IH => exact trans IH h₂, single⟩ lemma reflTransGen_minimal {r' : α → α → Prop} (hr₁ : Reflexive r') (hr₂ : Transitive r') (h : ∀ x y, r x y → r' x y) {x y : α} (hxy : ReflTransGen r x y) : r' x y := by @@ -525,9 +530,9 @@ theorem reflTransGen_closed {p : α → α → Prop} : ReflTransGen.lift' id theorem ReflTransGen.swap (h : ReflTransGen r b a) : ReflTransGen (swap r) a b := by - induction' h with b c _ hbc ih - · rfl - · exact ih.head hbc + induction h with + | refl => rfl + | tail _ hbc ih => exact ih.head hbc theorem reflTransGen_swap : ReflTransGen (swap r) a b ↔ ReflTransGen r b a := ⟨ReflTransGen.swap, ReflTransGen.swap⟩ @@ -561,6 +566,34 @@ lemma reflTransGen_eq_reflGen (hr : Transitive r) : end ReflTransGen +namespace EqvGen + +variable (r) + +theorem is_equivalence : Equivalence (@EqvGen α r) := + Equivalence.mk EqvGen.refl (EqvGen.symm _ _) (EqvGen.trans _ _ _) + +/-- `EqvGen.setoid r` is the setoid generated by a relation `r`. + +The motivation for this definition is that `Quot r` behaves like `Quotient (EqvGen.setoid r)`, +see for example `Quot.eqvGen_exact` and `Quot.eqvGen_sound`. -/ +def setoid : Setoid α := + Setoid.mk _ (EqvGen.is_equivalence r) + +theorem mono {r p : α → α → Prop} (hrp : ∀ a b, r a b → p a b) (h : EqvGen r a b) : + EqvGen p a b := by + induction h with + | rel a b h => exact EqvGen.rel _ _ (hrp _ _ h) + | refl => exact EqvGen.refl _ + | symm a b _ ih => exact EqvGen.symm _ _ ih + | trans a b c _ _ hab hbc => exact EqvGen.trans _ _ _ hab hbc + +@[deprecated (since := "2024-09-01")] alias _root_.EqvGen.is_equivalence := is_equivalence +@[deprecated (since := "2024-09-01")] alias _root_.EqvGen.Setoid := setoid +@[deprecated (since := "2024-09-01")] alias _root_.EqvGen.mono := mono + +end EqvGen + /-- The join of a relation on a single type is a new relation for which pairs of terms are related if there is a third term they are both related to. For example, if `r` is a relation representing rewrites @@ -587,14 +620,15 @@ theorem church_rosser (h : ∀ a b c, r a b → r a c → ∃ d, ReflGen r b d | refl => exact ⟨e, refl, ReflGen.single hde⟩ | @tail f b _ hfb ih => rcases ih with ⟨a, hea, hfa⟩ - cases' hfa with _ hfa - · exact ⟨b, hea.tail hfb, ReflGen.refl⟩ - · rcases h _ _ _ hfb hfa with ⟨c, hbc, hac⟩ + cases hfa with + | refl => exact ⟨b, hea.tail hfb, ReflGen.refl⟩ + | single hfa => + rcases h _ _ _ hfb hfa with ⟨c, hbc, hac⟩ exact ⟨c, hea.trans hac, hbc⟩ rcases this with ⟨a, hea, hba⟩ - cases' hba with _ hba - · exact ⟨b, hea, hcb⟩ - · exact ⟨a, hea, hcb.tail hba⟩ + cases hba with + | refl => exact ⟨b, hea, hcb⟩ + | single hba => exact ⟨a, hea, hcb.tail hba⟩ theorem join_of_single (h : Reflexive r) (hab : r a b) : Join r a b := @@ -625,9 +659,9 @@ theorem join_of_equivalence {r' : α → α → Prop} (hr : Equivalence r) (h : theorem reflTransGen_of_transitive_reflexive {r' : α → α → Prop} (hr : Reflexive r) (ht : Transitive r) (h : ∀ a b, r' a b → r a b) (h' : ReflTransGen r' a b) : r a b := by - induction' h' with b c _ hbc ih - · exact hr _ - · exact ht ih (h _ _ hbc) + induction h' with + | refl => exact hr _ + | tail _ hbc ih => exact ht ih (h _ _ hbc) theorem reflTransGen_of_equivalence {r' : α → α → Prop} (hr : Equivalence r) : (∀ a b, r' a b → r a b) → ReflTransGen r' a b → r a b := @@ -639,8 +673,31 @@ end Relation section EqvGen +open Relation + variable {r : α → α → Prop} {a b : α} +theorem Quot.eqvGen_exact (H : Quot.mk r a = Quot.mk r b) : EqvGen r a b := + @Quotient.exact _ (EqvGen.setoid r) a b (congrArg + (Quot.lift (Quotient.mk (EqvGen.setoid r)) (fun x y h ↦ Quot.sound (EqvGen.rel x y h))) H) + +theorem Quot.eqvGen_sound (H : EqvGen r a b) : Quot.mk r a = Quot.mk r b := + EqvGen.rec + (fun _ _ h ↦ Quot.sound h) + (fun _ ↦ rfl) + (fun _ _ _ IH ↦ Eq.symm IH) + (fun _ _ _ _ _ IH₁ IH₂ ↦ Eq.trans IH₁ IH₂) + H + +instance Quotient.decidableEq {α : Sort*} {s : Setoid α} [d : ∀ a b : α, Decidable (a ≈ b)] : + DecidableEq (Quotient s) := + fun q₁ q₂ : Quotient s ↦ + Quotient.recOnSubsingleton₂ q₁ q₂ + (fun a₁ a₂ ↦ + match (d a₁ a₂) with + | (isTrue h₁) => isTrue (Quotient.sound h₁) + | (isFalse h₂) => isFalse (fun h ↦ absurd (Quotient.exact h) h₂)) + theorem Equivalence.eqvGen_iff (h : Equivalence r) : EqvGen r a b ↔ r a b := Iff.intro (by @@ -655,12 +712,7 @@ theorem Equivalence.eqvGen_iff (h : Equivalence r) : EqvGen r a b ↔ r a b := theorem Equivalence.eqvGen_eq (h : Equivalence r) : EqvGen r = r := funext fun _ ↦ funext fun _ ↦ propext <| h.eqvGen_iff -theorem EqvGen.mono {r p : α → α → Prop} (hrp : ∀ a b, r a b → p a b) (h : EqvGen r a b) : - EqvGen p a b := by - induction h with - | rel a b h => exact EqvGen.rel _ _ (hrp _ _ h) - | refl => exact EqvGen.refl _ - | symm a b _ ih => exact EqvGen.symm _ _ ih - | trans a b c _ _ hab hbc => exact EqvGen.trans _ _ _ hab hbc +@[deprecated (since := "2024-08-29")] alias Quot.exact := Quot.eqvGen_exact +@[deprecated (since := "2024-08-29")] alias Quot.EqvGen_sound := Quot.eqvGen_sound end EqvGen 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 db322f081308c..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,8 +16,10 @@ universe u w v v' section -open scoped Classical +-- 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 6a6f1cf0785a9..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 @@ -88,8 +88,6 @@ theorem small_type : Small.{max (u + 1) v} (Type u) := section -open scoped Classical - theorem small_congr {α : Type*} {β : Type*} (e : α ≃ β) : Small.{w} α ↔ Small.{w} β := ⟨fun h => @small_map _ _ h e.symm, fun h => @small_map _ _ h e⟩ diff --git a/Mathlib/Logic/Small/Group.lean b/Mathlib/Logic/Small/Group.lean index fa16ff5f09481..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 @@ -14,161 +14,102 @@ noncomputable section variable {α : Type*} --- FIXME: here and below, why doesn't `to_additive` work? --- We're waiting on the fix for https://github.com/leanprover/lean4/issues/2077 to arrive. +-- TODO: noncomputable has to be specified explicitly. #1074 (item 8) +@[to_additive] +noncomputable instance [One α] [Small α] : One (Shrink α) := (equivShrink _).symm.one -instance [Zero α] [Small α] : Zero (Shrink α) := (equivShrink _).symm.zero - -@[to_additive existing] -instance [One α] [Small α] : One (Shrink α) := (equivShrink _).symm.one - -@[simp] -lemma equivShrink_symm_zero [Zero α] [Small α] : (equivShrink α).symm 0 = 0 := - (equivShrink α).symm_apply_apply 0 - -@[to_additive existing (attr := simp)] +@[to_additive (attr := simp)] lemma equivShrink_symm_one [One α] [Small α] : (equivShrink α).symm 1 = 1 := (equivShrink α).symm_apply_apply 1 -instance [Add α] [Small α] : Add (Shrink α) := (equivShrink _).symm.add - -@[to_additive existing] -instance [Mul α] [Small α] : Mul (Shrink α) := (equivShrink _).symm.mul +-- TODO: noncomputable has to be specified explicitly. #1074 (item 8) +@[to_additive] +noncomputable instance [Mul α] [Small α] : Mul (Shrink α) := (equivShrink _).symm.mul -@[simp] -lemma equivShrink_symm_add [Add α] [Small α] (x y : Shrink α) : - (equivShrink α).symm (x + y) = (equivShrink α).symm x + (equivShrink α).symm y := by - rw [Equiv.add_def] - simp - -@[simp] -lemma equivShrink_add [Add α] [Small α] (x y : α) : - equivShrink α (x + y) = equivShrink α x + equivShrink α y := by - rw [Equiv.add_def] - simp - -@[to_additive existing (attr := simp)] +@[to_additive (attr := simp)] lemma equivShrink_symm_mul [Mul α] [Small α] (x y : Shrink α) : (equivShrink α).symm (x * y) = (equivShrink α).symm x * (equivShrink α).symm y := by rw [Equiv.mul_def] simp -@[to_additive existing (attr := simp)] +@[to_additive (attr := simp)] lemma equivShrink_mul [Mul α] [Small α] (x y : α) : equivShrink α (x * y) = equivShrink α x * equivShrink α y := by rw [Equiv.mul_def] simp -instance [Sub α] [Small α] : Sub (Shrink α) := (equivShrink _).symm.sub - -@[to_additive existing] -instance [Div α] [Small α] : Div (Shrink α) := (equivShrink _).symm.div - -@[simp] -lemma equivShrink_symm_sub [Sub α] [Small α] (x y : Shrink α) : - (equivShrink α).symm (x - y) = (equivShrink α).symm x - (equivShrink α).symm y := by - rw [Equiv.sub_def] - simp - -@[simp] -lemma equivShrink_sub [Sub α] [Small α] (x y : α) : - equivShrink α (x - y) = equivShrink α x - equivShrink α y := by - rw [Equiv.sub_def] - simp +-- TODO: noncomputable has to be specified explicitly. #1074 (item 8) +@[to_additive] +noncomputable instance [Div α] [Small α] : Div (Shrink α) := (equivShrink _).symm.div -@[to_additive existing (attr := simp)] +@[to_additive (attr := simp)] lemma equivShrink_symm_div [Div α] [Small α] (x y : Shrink α) : (equivShrink α).symm (x / y) = (equivShrink α).symm x / (equivShrink α).symm y := by rw [Equiv.div_def] simp -@[to_additive existing (attr := simp)] +@[to_additive (attr := simp)] lemma equivShrink_div [Div α] [Small α] (x y : α) : equivShrink α (x / y) = equivShrink α x / equivShrink α y := by rw [Equiv.div_def] simp -instance [Neg α] [Small α] : Neg (Shrink α) := (equivShrink _).symm.Neg +-- TODO: noncomputable has to be specified explicitly. #1074 (item 8) +@[to_additive] +noncomputable instance [Inv α] [Small α] : Inv (Shrink α) := (equivShrink _).symm.Inv -@[to_additive existing] -instance [Inv α] [Small α] : Inv (Shrink α) := (equivShrink _).symm.Inv - -@[simp] -lemma equivShrink_symm_neg [Neg α] [Small α] (x : Shrink α) : - (equivShrink α).symm (-x) = -(equivShrink α).symm x := by - rw [Equiv.neg_def] - simp - -@[simp] -lemma equivShrink_neg [Neg α] [Small α] (x : α) : - equivShrink α (-x) = -equivShrink α x := by - rw [Equiv.neg_def] - simp - -@[to_additive existing (attr := simp)] +@[to_additive (attr := simp)] lemma equivShrink_symm_inv [Inv α] [Small α] (x : Shrink α) : (equivShrink α).symm x⁻¹ = ((equivShrink α).symm x)⁻¹ := by rw [Equiv.inv_def] simp -@[to_additive existing (attr := simp)] +@[to_additive (attr := simp)] lemma equivShrink_inv [Inv α] [Small α] (x : α) : equivShrink α x⁻¹ = (equivShrink α x)⁻¹ := by rw [Equiv.inv_def] simp -instance [AddSemigroup α] [Small α] : AddSemigroup (Shrink α) := (equivShrink _).symm.addSemigroup - -@[to_additive existing] -instance [Semigroup α] [Small α] : Semigroup (Shrink α) := (equivShrink _).symm.semigroup +-- TODO: noncomputable has to be specified explicitly. #1074 (item 8) +@[to_additive] +noncomputable instance [Semigroup α] [Small α] : Semigroup (Shrink α) := + (equivShrink _).symm.semigroup instance [SemigroupWithZero α] [Small α] : SemigroupWithZero (Shrink α) := (equivShrink _).symm.semigroupWithZero -instance [AddCommSemigroup α] [Small α] : AddCommSemigroup (Shrink α) := - (equivShrink _).symm.addCommSemigroup - -@[to_additive existing] -instance [CommSemigroup α] [Small α] : CommSemigroup (Shrink α) := +-- TODO: noncomputable has to be specified explicitly. #1074 (item 8) +@[to_additive] +noncomputable instance [CommSemigroup α] [Small α] : CommSemigroup (Shrink α) := (equivShrink _).symm.commSemigroup instance [MulZeroClass α] [Small α] : MulZeroClass (Shrink α) := (equivShrink _).symm.mulZeroClass -instance [AddZeroClass α] [Small α] : AddZeroClass (Shrink α) := - (equivShrink _).symm.addZeroClass - -@[to_additive existing] -instance [MulOneClass α] [Small α] : MulOneClass (Shrink α) := +-- TODO: noncomputable has to be specified explicitly. #1074 (item 8) +@[to_additive] +noncomputable instance [MulOneClass α] [Small α] : MulOneClass (Shrink α) := (equivShrink _).symm.mulOneClass instance [MulZeroOneClass α] [Small α] : MulZeroOneClass (Shrink α) := (equivShrink _).symm.mulZeroOneClass -instance [AddMonoid α] [Small α] : AddMonoid (Shrink α) := - (equivShrink _).symm.addMonoid - -@[to_additive existing] -instance [Monoid α] [Small α] : Monoid (Shrink α) := +-- TODO: noncomputable has to be specified explicitly. #1074 (item 8) +@[to_additive] +noncomputable instance [Monoid α] [Small α] : Monoid (Shrink α) := (equivShrink _).symm.monoid -instance [AddCommMonoid α] [Small α] : AddCommMonoid (Shrink α) := - (equivShrink _).symm.addCommMonoid - -@[to_additive existing] -instance [CommMonoid α] [Small α] : CommMonoid (Shrink α) := +-- TODO: noncomputable has to be specified explicitly. #1074 (item 8) +@[to_additive] +noncomputable instance [CommMonoid α] [Small α] : CommMonoid (Shrink α) := (equivShrink _).symm.commMonoid -instance [AddGroup α] [Small α] : AddGroup (Shrink α) := - (equivShrink _).symm.addGroup - -@[to_additive existing] -instance [Group α] [Small α] : Group (Shrink α) := +-- TODO: noncomputable has to be specified explicitly. #1074 (item 8) +@[to_additive] +noncomputable instance [Group α] [Small α] : Group (Shrink α) := (equivShrink _).symm.group -instance [AddCommGroup α] [Small α] : AddCommGroup (Shrink α) := - (equivShrink _).symm.addCommGroup - -@[to_additive existing] -instance [CommGroup α] [Small α] : CommGroup (Shrink α) := +-- TODO: noncomputable has to be specified explicitly. #1074 (item 8) +@[to_additive] +noncomputable instance [CommGroup α] [Small α] : CommGroup (Shrink α) := (equivShrink _).symm.commGroup 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..678d68e2ff016 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 /-! @@ -248,7 +247,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/Constructions/BorelSpace/Basic.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean index 74681e526e72b..b7ac515ab27d0 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Basic.lean @@ -55,14 +55,6 @@ theorem borel_anti : Antitone (@borel α) := fun _ _ h => theorem borel_eq_top_of_discrete [TopologicalSpace α] [DiscreteTopology α] : borel α = ⊤ := top_le_iff.1 fun s _ => GenerateMeasurable.basic s (isOpen_discrete s) -theorem borel_eq_top_of_countable [TopologicalSpace α] [T1Space α] [Countable α] : borel α = ⊤ := by - refine top_le_iff.1 fun s _ => biUnion_of_singleton s ▸ ?_ - apply MeasurableSet.biUnion s.to_countable - intro x _ - apply MeasurableSet.of_compl - apply GenerateMeasurable.basic - exact isClosed_singleton.isOpen_compl - theorem borel_eq_generateFrom_of_subbasis {s : Set (Set α)} [t : TopologicalSpace α] [SecondCountableTopology α] (hs : t = .generateFrom s) : borel α = .generateFrom s := le_antisymm @@ -157,7 +149,7 @@ def borelToRefl (e : Expr) (i : FVarId) : TacticM Unit := do `‹TopologicalSpace {e}› := {et}\n\ depends on\n\ {Expr.fvar i} : MeasurableSpace {e}`\n\ - so `borelize` isn't avaliable" + so `borelize` isn't available" evalTactic <| ← `(tactic| refine_lift letI : MeasurableSpace $te := borel $te @@ -267,6 +259,9 @@ theorem IsClosed.nullMeasurableSet {μ} (h : IsClosed s) : NullMeasurableSet s theorem IsCompact.measurableSet [T2Space α] (h : IsCompact s) : MeasurableSet s := h.isClosed.measurableSet +theorem IsCompact.nullMeasurableSet [T2Space α] {μ} (h : IsCompact s) : NullMeasurableSet s μ := + h.isClosed.nullMeasurableSet + /-- If two points are topologically inseparable, then they can't be separated by a Borel measurable set. -/ theorem Inseparable.mem_measurableSet_iff {x y : γ} (h : Inseparable x y) {s : Set γ} @@ -286,7 +281,7 @@ the measure of the closure of a compact set `K` is equal to the measure of `K`. See also `MeasureTheory.Measure.OuterRegular.measure_closure_eq_of_isCompact` for a version that assumes `μ` to be outer regular -but does not assume the `σ`-algebra to be Borel. -/ +but does not assume the `σ`-algebra to be Borel. -/ theorem IsCompact.measure_closure [R1Space γ] {K : Set γ} (hK : IsCompact K) (μ : Measure γ) : μ (closure K) = μ K := by refine le_antisymm ?_ (measure_mono subset_closure) @@ -339,6 +334,12 @@ instance (priority := 100) OpensMeasurableSpace.separatesPoints [T0Space α] : rw [inseparable_iff_forall_open] exact fun s hs => hxy _ hs.measurableSet +theorem borel_eq_top_of_countable {α : Type*} [TopologicalSpace α] [T0Space α] [Countable α] : + borel α = ⊤ := by + refine top_unique fun s _ ↦ ?_ + borelize α + exact .of_discrete + -- see Note [lower instance priority] instance (priority := 100) OpensMeasurableSpace.toMeasurableSingletonClass [T1Space α] : MeasurableSingletonClass α := @@ -501,9 +502,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] @@ -624,7 +624,7 @@ instance _root_.ULift.instBorelSpace : BorelSpace (ULift α) := instance DiscreteMeasurableSpace.toBorelSpace {α : Type*} [TopologicalSpace α] [DiscreteTopology α] [MeasurableSpace α] [DiscreteMeasurableSpace α] : BorelSpace α := by - constructor; ext; simp [MeasurableSpace.measurableSet_generateFrom, measurableSet_discrete] + constructor; ext; simp [MeasurableSpace.measurableSet_generateFrom, MeasurableSet.of_discrete] protected theorem Embedding.measurableEmbedding {f : α → β} (h₁ : Embedding f) (h₂ : MeasurableSet (range f)) : MeasurableEmbedding f := diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Metric.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Metric.lean index c18fa56992e55..2a7e7bc08abc6 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Metric.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Metric.lean @@ -128,7 +128,7 @@ theorem tendsto_measure_cthickening {μ : Measure α} {s : Set α} have A : Tendsto (fun r => μ (cthickening r s)) (𝓝[Ioi 0] 0) (𝓝 (μ (closure s))) := by rw [closure_eq_iInter_cthickening] exact - tendsto_measure_biInter_gt (fun r _ => isClosed_cthickening.measurableSet) + tendsto_measure_biInter_gt (fun r _ => isClosed_cthickening.nullMeasurableSet) (fun i j _ ij => cthickening_mono ij _) hs have B : Tendsto (fun r => μ (cthickening r s)) (𝓝[Iic 0] 0) (𝓝 (μ (closure s))) := by apply Tendsto.congr' _ tendsto_const_nhds @@ -151,7 +151,7 @@ theorem tendsto_measure_thickening {μ : Measure α} {s : Set α} (hs : ∃ R > 0, μ (thickening R s) ≠ ∞) : Tendsto (fun r => μ (thickening r s)) (𝓝[>] 0) (𝓝 (μ (closure s))) := by rw [closure_eq_iInter_thickening] - exact tendsto_measure_biInter_gt (fun r _ => isOpen_thickening.measurableSet) + exact tendsto_measure_biInter_gt (fun r _ => isOpen_thickening.nullMeasurableSet) (fun i j _ ij => thickening_mono ij _) hs /-- If a closed set has a thickening with finite measure, then the measure of its @@ -196,7 +196,7 @@ theorem exists_borelSpace_of_countablyGenerated_of_separatesPoints (α : Type*) ∃ τ : 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.toHomeomorphOfInducing <| inducing_induced _ exact ⟨inferInstance, F.secondCountableTopology, F.symm.t4Space, MeasurableEmbedding.borelSpace f.measurableEmbedding F.inducing⟩ diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Metrizable.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Metrizable.lean index dd5807aa62123..99fb114ff5bf1 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Metrizable.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Metrizable.lean @@ -105,7 +105,7 @@ theorem measurable_limit_of_tendsto_metrizable_ae {ι} [Countable ι] [Nonempty classical inhabit ι rcases eq_or_neBot L with (rfl | hL) - · exact ⟨(hf default).mk _, (hf default).measurable_mk, eventually_of_forall fun x => tendsto_bot⟩ + · exact ⟨(hf default).mk _, (hf default).measurable_mk, Eventually.of_forall fun x => tendsto_bot⟩ let p : α → (ι → β) → Prop := fun x f' => ∃ l : β, Tendsto (fun n => f' n) L (𝓝 l) have hp_mem : ∀ x ∈ aeSeqSet hf p, p x fun n => f n x := fun x hx => aeSeq.fun_prop_of_mem_aeSeqSet hf hx diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Order.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Order.lean index d848798cf7bd9..4bd14a8a98d53 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Order.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Order.lean @@ -99,20 +99,29 @@ variable [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 _ @@ -281,7 +305,7 @@ theorem Dense.borel_eq_generateFrom_Ico_mem {α : Type*} [TopologicalSpace α] [ 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 _ @@ -307,7 +331,7 @@ theorem Dense.borel_eq_generateFrom_Ioc_mem {α : Type*} [TopologicalSpace α] [ 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,11 +422,11 @@ 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, - measure_diff (Iic_subset_Iic.2 hlt.le) measurableSet_Iic, 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. -/ @@ -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,13 +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 [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)) : @@ -924,8 +943,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 9e03eae8ea344..f15add556e5f0 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Real.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Real.lean @@ -480,7 +480,7 @@ 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 @@ -505,7 +505,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) + 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..3ef19d096a73e 100644 --- a/Mathlib/MeasureTheory/Constructions/Cylinders.lean +++ b/Mathlib/MeasureTheory/Constructions/Cylinders.lean @@ -150,11 +150,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 +178,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 +186,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 +198,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 +217,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 +225,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 +272,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 +308,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,7 +357,7 @@ 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 diff --git a/Mathlib/MeasureTheory/Constructions/EventuallyMeasurable.lean b/Mathlib/MeasureTheory/Constructions/EventuallyMeasurable.lean index 38354c1a4bf18..c26b40b3beb7d 100644 --- a/Mathlib/MeasureTheory/Constructions/EventuallyMeasurable.lean +++ b/Mathlib/MeasureTheory/Constructions/EventuallyMeasurable.lean @@ -33,11 +33,11 @@ TODO: Implement the latter. open Filter Set MeasurableSpace -variable {α : Type*} (m : MeasurableSpace α) (l : Filter α) [CountableInterFilter l] {s t : Set α} +variable {α : Type*} (m : MeasurableSpace α) {s t : Set α} /-- The `MeasurableSpace` of sets which are measurable with respect to a given σ-algebra `m` on `α`, modulo a given σ-filter `l` on `α`. -/ -def EventuallyMeasurableSpace : MeasurableSpace α where +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⟩ @@ -48,9 +48,11 @@ def EventuallyMeasurableSpace : MeasurableSpace α where /-- We say a set `s` is an `EventuallyMeasurableSet` with respect to a given σ-algebra `m` and σ-filter `l` if it differs from a set in `m` by a set in the dual ideal of `l`. -/ -def EventuallyMeasurableSet (s : Set α) : Prop := @MeasurableSet _ (EventuallyMeasurableSpace m l) s +def EventuallyMeasurableSet (l : Filter α) [CountableInterFilter l] (s : Set α) : Prop := + @MeasurableSet _ (EventuallyMeasurableSpace m l) s -variable {l m} +variable {l : Filter α} [CountableInterFilter l] +variable {m} theorem MeasurableSet.eventuallyMeasurableSet (hs : MeasurableSet s) : EventuallyMeasurableSet m l s := @@ -75,7 +77,7 @@ namespace EventuallyMeasurableSpace instance measurableSingleton [MeasurableSingletonClass α] : @MeasurableSingletonClass α (EventuallyMeasurableSpace m l) := - @MeasurableSingletonClass.mk _ (_) $ fun x => (MeasurableSet.singleton x).eventuallyMeasurableSet + @MeasurableSingletonClass.mk _ (_) <| fun x => (MeasurableSet.singleton x).eventuallyMeasurableSet end EventuallyMeasurableSpace diff --git a/Mathlib/MeasureTheory/Constructions/HaarToSphere.lean b/Mathlib/MeasureTheory/Constructions/HaarToSphere.lean index 97bd8507cbce3..2b64a512ceb6e 100644 --- a/Mathlib/MeasureTheory/Constructions/HaarToSphere.lean +++ b/Mathlib/MeasureTheory/Constructions/HaarToSphere.lean @@ -3,7 +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 -/ -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 @@ -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 @@ -74,8 +74,8 @@ theorem toSphere_apply_univ : μ.toSphere univ = dim E * μ (ball 0 1) := by instance : IsFiniteMeasure μ.toSphere where measure_univ_lt_top := by rw [toSphere_apply_univ'] - exact ENNReal.mul_lt_top (ENNReal.natCast_ne_top _) <| - ne_top_of_le_ne_top measure_ball_lt_top.ne <| measure_mono diff_subset + exact ENNReal.mul_lt_top (ENNReal.natCast_lt_top _) <| + measure_ball_lt_top.trans_le' <| measure_mono diff_subset /-- The measure on `(0, +∞)` that has density `(· ^ n)` with respect to the Lebesgue measure. -/ def volumeIoiPow (n : ℕ) : Measure (Ioi (0 : ℝ)) := @@ -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, diff --git a/Mathlib/MeasureTheory/Constructions/Pi.lean b/Mathlib/MeasureTheory/Constructions/Pi.lean index 3482a2535938d..300e10ce1b53a 100644 --- a/Mathlib/MeasureTheory/Constructions/Pi.lean +++ b/Mathlib/MeasureTheory/Constructions/Pi.lean @@ -211,8 +211,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 := @@ -325,7 +324,7 @@ def FiniteSpanningSetsIn.pi {C : ∀ i, Set (Set (α i))} _ = ∏ i, μ i (toMeasurable (μ i) ((hμ i).set (e n i))) := (pi_pi_aux μ _ fun i => measurableSet_toMeasurable _ _) _ = ∏ i, μ i ((hμ i).set (e n i)) := by simp only [measure_toMeasurable] - _ < ∞ := ENNReal.prod_lt_top fun i _ => ((hμ i).finite _).ne + _ < ∞ := ENNReal.prod_lt_top fun i _ => (hμ i).finite _ · simp_rw [(surjective_decode_iget (ι → ℕ)).iUnion_comp fun x => Set.pi univ fun i => (hμ i).set (x i), iUnion_univ_pi fun i => (hμ i).set, (hμ _).spanning, Set.pi_univ] @@ -385,7 +384,7 @@ instance {α : ι → Type*} [∀ i, MeasureSpace (α i)] [∀ i, SigmaFinite (v instance pi.instIsFiniteMeasure [∀ i, IsFiniteMeasure (μ i)] : IsFiniteMeasure (Measure.pi μ) := - ⟨Measure.pi_univ μ ▸ ENNReal.prod_lt_top (fun i _ ↦ measure_ne_top (μ i) _)⟩ + ⟨Measure.pi_univ μ ▸ ENNReal.prod_lt_top (fun i _ ↦ measure_lt_top (μ i) _)⟩ instance {α : ι → Type*} [∀ i, MeasureSpace (α i)] [∀ i, IsFiniteMeasure (volume : Measure (α i))] : IsFiniteMeasure (volume : Measure (∀ i, α i)) := @@ -570,7 +569,7 @@ instance pi.isLocallyFiniteMeasure choose s hxs ho hμ using fun i => (μ i).exists_isOpen_measure_lt_top (x i) refine ⟨pi univ s, set_pi_mem_nhds finite_univ fun i _ => IsOpen.mem_nhds (ho i) (hxs i), ?_⟩ rw [pi_pi] - exact ENNReal.prod_lt_top fun i _ => (hμ i).ne + exact ENNReal.prod_lt_top fun i _ => hμ i instance {X : ι → Type*} [∀ i, TopologicalSpace (X i)] [∀ i, MeasureSpace (X i)] [∀ i, SigmaFinite (volume : Measure (X i))] @@ -648,7 +647,7 @@ instance pi.isFiniteMeasureOnCompacts [∀ i, TopologicalSpace (α i)] exact lt_of_le_of_lt (measure_mono (univ.subset_pi_eval_image K)) this rw [Measure.pi_pi] refine WithTop.prod_lt_top ?_ - exact fun i _ => ne_of_lt (IsCompact.measure_lt_top (IsCompact.image hK (continuous_apply i))) + exact fun i _ => IsCompact.measure_lt_top (IsCompact.image hK (continuous_apply i)) instance {X : ι → Type*} [∀ i, MeasureSpace (X i)] [∀ i, TopologicalSpace (X i)] [∀ i, SigmaFinite (volume : Measure (X i))] diff --git a/Mathlib/MeasureTheory/Constructions/Polish/Basic.lean b/Mathlib/MeasureTheory/Constructions/Polish/Basic.lean index be0467e7351a6..89db09097d3cb 100644 --- a/Mathlib/MeasureTheory/Constructions/Polish/Basic.lean +++ b/Mathlib/MeasureTheory/Constructions/Polish/Basic.lean @@ -343,7 +343,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] @@ -561,7 +561,7 @@ theorem measurableSet_preimage_iff_preimage_val {f : X → Z} [CountablySeparate /-- If `f : X → Z` is a Borel measurable map from a standard Borel space to a countably separated measurable space and the range of `f` is measurable, then the preimage of a set `s` is measurable -if and only if the intesection with `Set.range f` is measurable. -/ +if and only if the intersection with `Set.range f` is measurable. -/ theorem measurableSet_preimage_iff_inter_range {f : X → Z} [CountablySeparated (range f)] (hf : Measurable f) (hr : MeasurableSet (range f)) {s : Set Z} : MeasurableSet (f ⁻¹' s) ↔ MeasurableSet (s ∩ range f) := by @@ -985,7 +985,7 @@ noncomputable def measurableEquivNatBoolOfNotCountable (h : ¬Countable α) : α apply Nonempty.some letI := upgradeStandardBorel α obtain ⟨f, -, fcts, finj⟩ := - isClosed_univ.exists_nat_bool_injection_of_not_countable + isClosed_univ.exists_nat_bool_injection_of_not_countable (α := α) (by rwa [← countable_coe_iff, (Equiv.Set.univ _).countable_iff]) obtain ⟨g, gmeas, ginj⟩ := MeasurableSpace.measurable_injection_nat_bool_of_countablySeparated α diff --git a/Mathlib/MeasureTheory/Constructions/Polish/EmbeddingReal.lean b/Mathlib/MeasureTheory/Constructions/Polish/EmbeddingReal.lean index f6436e70180fc..67a330bbb5bb7 100644 --- a/Mathlib/MeasureTheory/Constructions/Polish/EmbeddingReal.lean +++ b/Mathlib/MeasureTheory/Constructions/Polish/EmbeddingReal.lean @@ -63,4 +63,9 @@ lemma measurableEmbedding_embeddingReal (Ω : Type*) [MeasurableSpace Ω] [Stand MeasurableEmbedding (embeddingReal Ω) := (exists_measurableEmbedding_real Ω).choose_spec +@[fun_prop] +lemma measurable_embeddingReal (Ω : Type*) [MeasurableSpace Ω] [StandardBorelSpace Ω] : + Measurable (embeddingReal Ω) := + (measurableEmbedding_embeddingReal Ω).measurable + end MeasureTheory diff --git a/Mathlib/MeasureTheory/Constructions/Prod/Basic.lean b/Mathlib/MeasureTheory/Constructions/Prod/Basic.lean index e219a86ee54da..a8e405fc234e1 100644 --- a/Mathlib/MeasureTheory/Constructions/Prod/Basic.lean +++ b/Mathlib/MeasureTheory/Constructions/Prod/Basic.lean @@ -383,7 +383,7 @@ instance prod.instIsFiniteMeasure {α β : Type*} {mα : MeasurableSpace α} {m IsFiniteMeasure (μ.prod ν) := by constructor rw [← univ_prod_univ, prod_prod] - exact mul_lt_top (measure_lt_top _ _).ne (measure_lt_top _ _).ne + exact mul_lt_top (measure_lt_top _ _) (measure_lt_top _ _) instance {α β : Type*} [MeasureSpace α] [MeasureSpace β] [IsFiniteMeasure (volume : Measure α)] [IsFiniteMeasure (volume : Measure β)] : IsFiniteMeasure (volume : Measure (α × β)) := @@ -412,7 +412,7 @@ instance prod.instIsFiniteMeasureOnCompacts {α β : Type*} [TopologicalSpace α exact ⟨⟨y, hxy⟩, ⟨x, hxy⟩⟩ apply lt_of_le_of_lt (measure_mono this) rw [hL, prod_prod] - exact mul_lt_top (hK.image continuous_fst).measure_ne_top (hK.image continuous_snd).measure_ne_top + exact mul_lt_top (hK.image continuous_fst).measure_lt_top (hK.image continuous_snd).measure_lt_top instance {X Y : Type*} [TopologicalSpace X] [MeasureSpace X] [IsFiniteMeasureOnCompacts (volume : Measure X)] @@ -449,9 +449,9 @@ theorem measure_ae_null_of_prod_null {s : Set (α × β)} (h : μ.prod ν s = 0) rw [measure_prod_null mt] at ht rw [eventuallyLE_antisymm_iff] exact - ⟨EventuallyLE.trans_eq (eventually_of_forall fun x => (measure_mono (preimage_mono hst) : _)) + ⟨EventuallyLE.trans_eq (Eventually.of_forall fun x => (measure_mono (preimage_mono hst) : _)) ht, - eventually_of_forall fun x => zero_le _⟩ + Eventually.of_forall fun x => zero_le _⟩ theorem AbsolutelyContinuous.prod [SFinite ν'] (h1 : μ ≪ μ') (h2 : ν ≪ ν') : μ.prod ν ≪ μ'.prod ν' := by @@ -520,7 +520,7 @@ lemma _root_.MeasureTheory.NullMeasurableSet.right_of_prod {s : Set α} {t : Set /-- If `Prod.snd ⁻¹' t` is a null measurable set and `μ ≠ 0`, then `t` is a null measurable set. -/ lemma _root_.MeasureTheory.NullMeasurableSet.of_preimage_snd [NeZero μ] {t : Set β} (h : NullMeasurableSet (Prod.snd ⁻¹' t) (μ.prod ν)) : NullMeasurableSet t ν := - .right_of_prod (by rwa [univ_prod]) (NeZero.ne _) + .right_of_prod (by rwa [univ_prod]) (NeZero.ne (μ univ)) /-- `Prod.snd ⁻¹' t` is null measurable w.r.t. `μ.prod ν` iff `t` is null measurable w.r.t. `ν` provided that `μ ≠ 0`. -/ @@ -541,7 +541,7 @@ noncomputable def FiniteSpanningSetsIn.prod {ν : Measure β} {C : Set (Set α)} ⟨fun n => hμ.set n.unpair.1 ×ˢ hν.set n.unpair.2, fun n => mem_image2_of_mem (hμ.set_mem _) (hν.set_mem _), fun n => ?_, ?_⟩ · rw [prod_prod] - exact mul_lt_top (hμ.finite _).ne (hν.finite _).ne + exact mul_lt_top (hμ.finite _) (hν.finite _) · simp_rw [iUnion_unpair_prod, hμ.spanning, hν.spanning, univ_prod_univ] lemma prod_sum_left {ι : Type*} (m : ι → Measure α) (μ : Measure β) [SFinite μ] : @@ -657,7 +657,7 @@ lemma _root_.MeasureTheory.NullMeasurableSet.left_of_prod {s : Set α} {t : Set /-- If `Prod.fst ⁻¹' s` is a null measurable set and `ν ≠ 0`, then `s` is a null measurable set. -/ lemma _root_.MeasureTheory.NullMeasurableSet.of_preimage_fst [NeZero ν] {s : Set α} (h : NullMeasurableSet (Prod.fst ⁻¹' s) (μ.prod ν)) : NullMeasurableSet s μ := - .left_of_prod (by rwa [prod_univ]) (NeZero.ne _) + .left_of_prod (by rwa [prod_univ]) (NeZero.ne (ν univ)) /-- `Prod.fst ⁻¹' s` is null measurable w.r.t. `μ.prod ν` iff `s` is null measurable w.r.t. `μ` provided that `ν ≠ 0`. -/ @@ -1012,6 +1012,9 @@ theorem fst_map_prod_mk {X : α → β} {Y : α → γ} {μ : Measure α} (hY : Measurable Y) : (μ.map fun a => (X a, Y a)).fst = μ.map X := fst_map_prod_mk₀ hY.aemeasurable +@[gcongr] +theorem fst_mono {μ : Measure (α × β)} (h : ρ ≤ μ) : ρ.fst ≤ μ.fst := map_mono h measurable_fst + /-- Marginal measure on `β` obtained from a measure on `ρ` `α × β`, defined by `ρ.map Prod.snd`. -/ noncomputable def snd (ρ : Measure (α × β)) : Measure β := ρ.map Prod.snd @@ -1056,6 +1059,9 @@ theorem snd_map_prod_mk {X : α → β} {Y : α → γ} {μ : Measure α} (hX : (μ.map fun a => (X a, Y a)).snd = μ.map Y := snd_map_prod_mk₀ hX.aemeasurable +@[gcongr] +theorem snd_mono {μ : Measure (α × β)} (h : ρ ≤ μ) : ρ.snd ≤ μ.snd := map_mono h measurable_snd + @[simp] lemma fst_map_swap : (ρ.map Prod.swap).fst = ρ.snd := by rw [Measure.fst, Measure.map_map measurable_fst measurable_swap] rfl diff --git a/Mathlib/MeasureTheory/Constructions/Prod/Integral.lean b/Mathlib/MeasureTheory/Constructions/Prod/Integral.lean index 18a596110f89b..25d335405cc0f 100644 --- a/Mathlib/MeasureTheory/Constructions/Prod/Integral.lean +++ b/Mathlib/MeasureTheory/Constructions/Prod/Integral.lean @@ -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 @@ -104,12 +104,12 @@ theorem MeasureTheory.StronglyMeasurable.integral_prod_right [SFinite ν] ⦃f : refine tendsto_integral_of_dominated_convergence (fun y => ‖f x y‖ + ‖f x y‖) (fun n => (s' n x).aestronglyMeasurable) (hfx.norm.add hfx.norm) ?_ ?_ - · refine fun n => eventually_of_forall fun y => + · refine fun n => Eventually.of_forall fun y => SimpleFunc.norm_approxOn_zero_le ?_ ?_ (x, y) n -- Porting note: Lean 3 solved the following two subgoals on its own · exact hf.measurable · simp - · refine eventually_of_forall fun y => SimpleFunc.tendsto_approxOn ?_ ?_ ?_ + · refine Eventually.of_forall fun y => SimpleFunc.tendsto_approxOn ?_ ?_ ?_ -- Porting note: Lean 3 solved the following two subgoals on its own · exact hf.measurable.of_uncurry_left · simp @@ -287,7 +287,7 @@ theorem Integrable.prod_smul {𝕜 : Type*} [NontriviallyNormedField 𝕜] [Norm Integrable (fun z : α × β => f z.1 • g z.2) (μ.prod ν) := by refine (integrable_prod_iff ?_).2 ⟨?_, ?_⟩ · exact hf.1.fst.smul hg.1.snd - · exact eventually_of_forall fun x => hg.smul (f x) + · exact Eventually.of_forall fun x => hg.smul (f x) · simpa only [norm_smul, integral_mul_left] using hf.norm.mul_const _ theorem Integrable.prod_mul {L : Type*} [RCLike L] {f : α → L} {g : β → L} (hf : Integrable f μ) @@ -301,11 +301,11 @@ variable [NormedSpace ℝ E] theorem Integrable.integral_prod_left ⦃f : α × β → E⦄ (hf : Integrable f (μ.prod ν)) : Integrable (fun x => ∫ y, f (x, y) ∂ν) μ := Integrable.mono hf.integral_norm_prod_left hf.aestronglyMeasurable.integral_prod_right' <| - eventually_of_forall fun x => + Eventually.of_forall fun x => (norm_integral_le_integral_norm _).trans_eq <| (norm_of_nonneg <| integral_nonneg_of_ae <| - eventually_of_forall fun y => (norm_nonneg (f (x, y)) : _)).symm + Eventually.of_forall fun y => (norm_nonneg (f (x, y)) : _)).symm theorem Integrable.integral_prod_right [SFinite μ] ⦃f : α × β → E⦄ (hf : Integrable f (μ.prod ν)) : Integrable (fun y => ∫ x, f (x, y) ∂μ) ν := @@ -388,7 +388,7 @@ theorem continuous_integral_integral : rw [continuous_iff_continuousAt]; intro g refine tendsto_integral_of_L1 _ (L1.integrable_coeFn g).integral_prod_left - (eventually_of_forall fun h => (L1.integrable_coeFn h).integral_prod_left) ?_ + (Eventually.of_forall fun h => (L1.integrable_coeFn h).integral_prod_left) ?_ simp_rw [← lintegral_fn_integral_sub (fun x => (‖x‖₊ : ℝ≥0∞)) (L1.integrable_coeFn _) (L1.integrable_coeFn g)] @@ -422,7 +422,7 @@ theorem integral_prod (f : α × β → E) (hf : Integrable f (μ.prod ν)) : revert f apply Integrable.induction · intro c s hs h2s - simp_rw [integral_indicator hs, ← indicator_comp_right, Function.comp, + simp_rw [integral_indicator hs, ← indicator_comp_right, Function.comp_def, 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)] @@ -535,7 +535,7 @@ lemma integral_integral_swap_of_hasCompactSupport apply (integrableOn_iff_integrable_of_support_subset (subset_tsupport f.uncurry)).mp refine ⟨(h'f.stronglyMeasurable_of_prod hf).aestronglyMeasurable, ?_⟩ obtain ⟨C, hC⟩ : ∃ C, ∀ p, ‖f.uncurry p‖ ≤ C := hf.bounded_above_of_compact_support h'f - exact hasFiniteIntegral_of_bounded (C := C) (eventually_of_forall hC) + exact hasFiniteIntegral_of_bounded (C := C) (Eventually.of_forall hC) _ = ∫ y, (∫ x in U, f x y ∂μ) ∂ν := by apply setIntegral_eq_integral_of_forall_compl_eq_zero (fun y hy ↦ ?_) have : ∀ x, f x y = 0 := by 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/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 46af5641e5aa1..91cc3db5e2be0 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, @@ -319,7 +319,7 @@ theorem mem_iUnionUpTo_lastStep (x : β) : p.c x ∈ p.iUnionUpTo p.lastStep := rcases A y with (Hy | Hy) · exact hy1 Hy · rw [← div_eq_inv_mul] at hy2 - have := (div_le_iff' (_root_.zero_lt_one.trans p.one_lt_tau)).1 hy2.le + have := (div_le_iff₀' (_root_.zero_lt_one.trans p.one_lt_tau)).1 hy2.le exact lt_irrefl _ (Hy.trans_le this) /-- If there are no configurations of satellites with `N+1` points, one never uses more than `N` @@ -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⟩ : @@ -621,9 +621,9 @@ theorem exist_finset_disjoint_balls_large_measure (μ : Measure α) [IsFiniteMea rw [← diff_inter_self_eq_diff, measure_diff_le_iff_le_add _ inter_subset_right (measure_lt_top μ _).ne] swap - · apply MeasurableSet.inter _ omeas - haveI : Encodable (u i) := (u_count i).toEncodable - exact MeasurableSet.iUnion fun b => MeasurableSet.iUnion fun _ => measurableSet_closedBall + · exact .inter + (w.nullMeasurableSet_biUnion fun _ _ ↦ measurableSet_closedBall.nullMeasurableSet) + omeas.nullMeasurableSet calc μ o = 1 / (N + 1) * μ s + N / (N + 1) * μ s := by rw [μo, ← add_mul, ENNReal.div_add_div_same, add_comm, ENNReal.div_self, one_mul] <;> simp @@ -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⟩ @@ -743,7 +743,7 @@ theorem exists_disjoint_closedBall_covering_ae_of_finiteMeasure_aux (μ : Measur have Pu : ∀ n, P (u n) := by intro n induction' n with n IH - · simp only [P, u, Prod.forall, id, Function.iterate_zero, Nat.zero_eq] + · simp only [P, u, Prod.forall, id, Function.iterate_zero] simp only [Finset.not_mem_empty, IsEmpty.forall_iff, Finset.coe_empty, forall₂_true_iff, and_self_iff, pairwiseDisjoint_empty] · rw [u_succ] @@ -768,7 +768,7 @@ theorem exists_disjoint_closedBall_covering_ae_of_finiteMeasure_aux (μ : Measur intro n induction' n with n IH · simp only [u, le_refl, diff_empty, one_mul, iUnion_false, iUnion_empty, pow_zero, - Nat.zero_eq, Function.iterate_zero, id, Finset.not_mem_empty] + Function.iterate_zero, id, Finset.not_mem_empty] calc μ (s \ ⋃ (p : α × ℝ) (_ : p ∈ u n.succ), closedBall p.fst p.snd) ≤ N / (N + 1) * μ (s \ ⋃ (p : α × ℝ) (_ : p ∈ u n), closedBall p.fst p.snd) := by @@ -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) @@ -808,7 +808,7 @@ theorem exists_disjoint_closedBall_covering_ae_aux (μ : Measure α) [SFinite μ t.PairwiseDisjoint fun p => closedBall p.1 p.2 := by /- This is deduced from the finite measure case, by using a finite measure with respect to which the initial sigma-finite measure is absolutely continuous. -/ - rcases exists_absolutelyContinuous_isFiniteMeasure μ with ⟨ν, hν, hμν⟩ + rcases exists_isFiniteMeasure_absolutelyContinuous μ with ⟨ν, hν, hμν, -⟩ rcases exists_disjoint_closedBall_covering_ae_of_finiteMeasure_aux ν f s hf with ⟨t, t_count, ts, tr, tν, tdisj⟩ exact ⟨t, t_count, ts, tr, hμν tν, tdisj⟩ @@ -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 diff --git a/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean b/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean index 9311803c85be1..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 @@ -319,11 +319,11 @@ theorem exists_normalized_aux1 {N : ℕ} {τ : ℝ} (a : SatelliteConfig E N τ) _ = (1 : ℝ) - δ ^ 2 / 16 := by ring _ ≤ 1 := by linarith only [sq_nonneg δ] have J : 1 - δ ≤ 1 - δ / 4 := by linarith only [δnonneg] - have K : 1 - δ / 4 ≤ τ⁻¹ := by rw [inv_eq_one_div, le_div_iff τpos]; exact I + have K : 1 - δ / 4 ≤ τ⁻¹ := by rw [inv_eq_one_div, le_div_iff₀ τpos]; exact I suffices L : τ⁻¹ ≤ ‖a.c i - a.c j‖ by linarith only [J, K, L] have hτ' : ∀ k, τ⁻¹ ≤ a.r k := by intro k - rw [inv_eq_one_div, div_le_iff τpos, ← lastr, mul_comm] + rw [inv_eq_one_div, div_le_iff₀ τpos, ← lastr, mul_comm] exact a.hlast' k hτ rcases ah inej with (H | H) · apply le_trans _ H.1 @@ -380,7 +380,7 @@ theorem exists_normalized_aux2 {N : ℕ} {τ : ℝ} (a : SatelliteConfig E N τ) _ ≤ ‖a.c i - d‖ + ‖d - a.c j‖ := by simp only [← dist_eq_norm, dist_triangle] _ ≤ ‖a.c i - d‖ + (a.r j - 1) := by apply add_le_add_left - have A : 0 ≤ 1 - 2 / ‖a.c j‖ := by simpa [div_le_iff (zero_le_two.trans_lt hj)] using hj.le + have A : 0 ≤ 1 - 2 / ‖a.c j‖ := by simpa [div_le_iff₀ (zero_le_two.trans_lt hj)] using hj.le rw [← one_smul ℝ (a.c j), hd, ← sub_smul, norm_smul, norm_sub_rev, Real.norm_eq_abs, abs_of_nonneg A, sub_mul] field_simp [(zero_le_two.trans_lt hj).ne'] @@ -417,7 +417,7 @@ theorem exists_normalized_aux3 {N : ℕ} {τ : ℝ} (a : SatelliteConfig E N τ) nth_rw 1 [← one_smul ℝ (a.c j)] rw [add_left_inj, hd, ← sub_smul, norm_smul, Real.norm_eq_abs, abs_of_nonneg, sub_mul, one_mul, div_mul_cancel₀ _ (zero_le_two.trans_lt hj).ne'] - rwa [sub_nonneg, div_le_iff (zero_lt_two.trans hj), one_mul] + rwa [sub_nonneg, div_le_iff₀ (zero_lt_two.trans hj), one_mul] have J : a.r j - ‖a.c j - a.c i‖ ≤ s / 2 * δ := calc a.r j - ‖a.c j - a.c i‖ ≤ s * (τ - 1) := by @@ -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..62c58768b78a6 100644 --- a/Mathlib/MeasureTheory/Covering/DensityTheorem.lean +++ b/Mathlib/MeasureTheory/Covering/DensityTheorem.lean @@ -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)] diff --git a/Mathlib/MeasureTheory/Covering/Differentiation.lean b/Mathlib/MeasureTheory/Covering/Differentiation.lean index cb24a16d2a1c8..803d605ca1b7f 100644 --- a/Mathlib/MeasureTheory/Covering/Differentiation.lean +++ b/Mathlib/MeasureTheory/Covering/Differentiation.lean @@ -245,7 +245,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 +324,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 +368,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 +448,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 +485,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) @@ -539,7 +539,7 @@ theorem withDensity_le_mul {s : Set α} (hs : MeasurableSet s) {t : ℝ≥0} (ht have M : MeasurableSet (s ∩ f ⁻¹' {0}) := hs.inter (f_meas (measurableSet_singleton _)) simp only [ν, nonpos_iff_eq_zero, M, withDensity_apply, lintegral_eq_zero_iff f_meas] apply (ae_restrict_iff' M).2 - exact eventually_of_forall fun x hx => hx.2 + exact Eventually.of_forall fun x hx => hx.2 have B : ν (s ∩ f ⁻¹' {∞}) ≤ ((t : ℝ≥0∞) ^ 2 • ρ :) (s ∩ f ⁻¹' {∞}) := by apply le_trans (le_of_eq _) (zero_le _) apply withDensity_absolutelyContinuous μ _ @@ -555,7 +555,7 @@ theorem withDensity_le_mul {s : Set α} (hs : MeasurableSet s) {t : ℝ≥0} (ht simp only [ν, M, withDensity_apply, coe_nnreal_smul_apply] calc (∫⁻ x in s ∩ f ⁻¹' I, f x ∂μ) ≤ ∫⁻ _ in s ∩ f ⁻¹' I, (t : ℝ≥0∞) ^ (n + 1) ∂μ := - lintegral_mono_ae ((ae_restrict_iff' M).2 (eventually_of_forall fun x hx => hx.2.2.le)) + lintegral_mono_ae ((ae_restrict_iff' M).2 (Eventually.of_forall fun x hx => hx.2.2.le)) _ = (t : ℝ≥0∞) ^ (n + 1) * μ (s ∩ f ⁻¹' I) := by simp only [lintegral_const, MeasurableSet.univ, Measure.restrict_apply, univ_inter] _ = (t : ℝ≥0∞) ^ (2 : ℤ) * ((t : ℝ≥0∞) ^ (n - 1) * μ (s ∩ f ⁻¹' I)) := by @@ -573,7 +573,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 ⁻¹' {∞}) + @@ -626,7 +626,7 @@ theorem le_mul_withDensity {s : Set α} (hs : MeasurableSet s) {t : ℝ≥0} (ht _ = ∫⁻ _ in s ∩ f ⁻¹' I, (t : ℝ≥0∞) ^ (n + 1) ∂μ := by simp only [lintegral_const, MeasurableSet.univ, Measure.restrict_apply, univ_inter] _ ≤ ∫⁻ x in s ∩ f ⁻¹' I, t * f x ∂μ := by - apply lintegral_mono_ae ((ae_restrict_iff' M).2 (eventually_of_forall fun x hx => ?_)) + apply lintegral_mono_ae ((ae_restrict_iff' M).2 (Eventually.of_forall fun x hx => ?_)) rw [add_comm, ENNReal.zpow_add t_ne_zero ENNReal.coe_ne_top, zpow_one] exact mul_le_mul_left' hx.2.1 _ _ = t * ∫⁻ x in s ∩ f ⁻¹' I, f x ∂μ := lintegral_const_mul _ f_meas @@ -649,8 +649,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 +659,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 +809,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 : @@ -875,7 +875,7 @@ theorem ae_tendsto_lintegral_nnnorm_sub_div {f : α → E} (hf : LocallyIntegrab filter_upwards [v.eventually_filterAt_subset_of_nhds ((u_open n).mem_nhds hn), v.eventually_filterAt_measurableSet x] with a ha h'a congr 1 - refine setLIntegral_congr_fun h'a (eventually_of_forall (fun y hy ↦ ?_)) + refine setLIntegral_congr_fun h'a (Eventually.of_forall (fun y hy ↦ ?_)) rw [indicator_of_mem (ha hy) f, indicator_of_mem hn f] /-- *Lebesgue differentiation theorem*: for almost every point `x`, the @@ -902,7 +902,7 @@ theorem ae_tendsto_average [NormedSpace ℝ E] [CompleteSpace E] {f : α → E} ∀ᵐ x ∂μ, Tendsto (fun a => ⨍ y in a, f y ∂μ) (v.filterAt x) (𝓝 (f x)) := by filter_upwards [v.ae_tendsto_average_norm_sub hf, v.ae_eventually_measure_pos] with x hx h'x rw [tendsto_iff_norm_sub_tendsto_zero] - refine squeeze_zero' (eventually_of_forall fun a => norm_nonneg _) ?_ hx + refine squeeze_zero' (Eventually.of_forall fun a => norm_nonneg _) ?_ hx filter_upwards [h'x, v.eventually_measure_lt_top x, v.eventually_filterAt_integrableOn x hf] with a ha h'a h''a nth_rw 1 [← setAverage_const ha.ne' h'a.ne (f x)] diff --git a/Mathlib/MeasureTheory/Covering/LiminfLimsup.lean b/Mathlib/MeasureTheory/Covering/LiminfLimsup.lean index c4bb3f2085e98..539f24411b7c9 100644 --- a/Mathlib/MeasureTheory/Covering/LiminfLimsup.lean +++ b/Mathlib/MeasureTheory/Covering/LiminfLimsup.lean @@ -105,7 +105,7 @@ theorem blimsup_cthickening_ae_le_of_eventually_mul_le_aux (p : ℕ → Prop) {s obtain ⟨η, hη, hη'⟩ := this replace hη' : 1 ≤ η := by simpa only [ENNReal.one_le_coe_iff] using - le_of_tendsto (hd' w (fun j => r₁ (f j)) hr <| eventually_of_forall hw') hη' + le_of_tendsto (hd' w (fun j => r₁ (f j)) hr <| Eventually.of_forall hw') hη' exact (lt_self_iff_false _).mp (lt_of_lt_of_le hη hη') refine ⟨1 - C⁻¹, tsub_lt_self zero_lt_one (inv_pos.mpr hC), ?_⟩ replace hC : C ≠ 0 := ne_of_gt hC @@ -198,13 +198,13 @@ theorem blimsup_cthickening_mul_ae_eq (p : ℕ → Prop) (s : ℕ → Set α) {M convert TendstoNhdsWithinIoi.const_mul hM hr <;> simp only [mul_zero] refine eventuallyLE_antisymm_iff.mpr ⟨?_, ?_⟩ · exact blimsup_cthickening_ae_le_of_eventually_mul_le μ p (inv_pos.mpr hM) hr' - (eventually_of_forall fun i => by rw [inv_mul_cancel_left₀ hM.ne' (r i)]) + (Eventually.of_forall fun i => by rw [inv_mul_cancel_left₀ hM.ne' (r i)]) · exact blimsup_cthickening_ae_le_of_eventually_mul_le μ p hM hr - (eventually_of_forall fun i => le_refl _) + (Eventually.of_forall fun i => le_refl _) let r' : ℕ → ℝ := fun i => if 0 < r i then r i else 1 / ((i : ℝ) + 1) have hr' : Tendsto r' atTop (𝓝[>] 0) := by refine tendsto_nhdsWithin_iff.mpr - ⟨Tendsto.if' hr tendsto_one_div_add_atTop_nhds_zero_nat, eventually_of_forall fun i => ?_⟩ + ⟨Tendsto.if' hr tendsto_one_div_add_atTop_nhds_zero_nat, Eventually.of_forall fun i => ?_⟩ by_cases hi : 0 < r i · simp [r', hi] · simp only [r', hi, one_div, mem_Ioi, if_false, inv_pos]; positivity @@ -220,8 +220,8 @@ theorem blimsup_cthickening_mul_ae_eq (p : ℕ → Prop) (s : ℕ → Set α) {M ext i; simp [← and_or_left, lt_or_le 0 (r i)] rw [hp, blimsup_or_eq_sup, blimsup_or_eq_sup] simp only [sup_eq_union] - rw [blimsup_congr (eventually_of_forall h₀), blimsup_congr (eventually_of_forall h₁), - blimsup_congr (eventually_of_forall h₂)] + rw [blimsup_congr (Eventually.of_forall h₀), blimsup_congr (Eventually.of_forall h₁), + blimsup_congr (Eventually.of_forall h₂)] exact ae_eq_set_union (this (fun i => p i ∧ 0 < r i) hr') (ae_eq_refl _) theorem blimsup_cthickening_ae_eq_blimsup_thickening {p : ℕ → Prop} {s : ℕ → Set α} {r : ℕ → ℝ} @@ -268,14 +268,14 @@ theorem blimsup_thickening_mul_ae_eq (p : ℕ → Prop) (s : ℕ → Set α) {M let q : ℕ → Prop := fun i => p i ∧ 0 < r i have h₁ : blimsup (fun i => thickening (r i) (s i)) atTop p = blimsup (fun i => thickening (r i) (s i)) atTop q := by - refine blimsup_congr' (eventually_of_forall fun i h => ?_) + refine blimsup_congr' (Eventually.of_forall fun i h => ?_) replace hi : 0 < r i := by contrapose! h; apply thickening_of_nonpos h simp only [q, hi, iff_self_and, imp_true_iff] have h₂ : blimsup (fun i => thickening (M * r i) (s i)) atTop p = blimsup (fun i => thickening (M * r i) (s i)) atTop q := by - refine blimsup_congr' (eventually_of_forall fun i h ↦ ?_) + refine blimsup_congr' (Eventually.of_forall fun i h ↦ ?_) replace h : 0 < r i := by rw [← mul_pos_iff_of_pos_left hM]; contrapose! h; apply thickening_of_nonpos h simp only [q, h, iff_self_and, imp_true_iff] rw [h₁, h₂] - exact blimsup_thickening_mul_ae_eq_aux μ q s hM r hr (eventually_of_forall fun i hi => hi.2) + exact blimsup_thickening_mul_ae_eq_aux μ q s hM r hr (Eventually.of_forall fun i hi => hi.2) diff --git a/Mathlib/MeasureTheory/Covering/Vitali.lean b/Mathlib/MeasureTheory/Covering/Vitali.lean index 5928bb689a9c9..364031a842a49 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⟩ diff --git a/Mathlib/MeasureTheory/Decomposition/Exhaustion.lean b/Mathlib/MeasureTheory/Decomposition/Exhaustion.lean new file mode 100644 index 0000000000000..a6f283377c6c5 --- /dev/null +++ b/Mathlib/MeasureTheory/Decomposition/Exhaustion.lean @@ -0,0 +1,340 @@ +/- +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.MeasureTheory.Measure.Typeclasses + +/-! +# Method of exhaustion + +If `μ, ν` are two measures with `ν` s-finite, then there exists a set `s` such that +`μ` is sigma-finite on `s`, and for all sets `t ⊆ sᶜ`, either `ν t = 0` or `μ t = ∞`. + +## Main definitions + +* `MeasureTheory.Measure.sigmaFiniteSetWRT`: if such a set exists, `μ.sigmaFiniteSetWRT ν` is + a measurable set such that `μ.restrict (μ.sigmaFiniteSetWRT ν)` is sigma-finite and + for all sets `t ⊆ (μ.sigmaFiniteSetWRT ν)ᶜ`, either `ν t = 0` or `μ t = ∞`. + If no such set exists (which is only possible if `ν` is not s-finite), we define + `μ.sigmaFiniteSetWRT ν = ∅`. +* `MeasureTheory.Measure.sigmaFiniteSet`: for an s-finite measure `μ`, a measurable set such that + `μ.restrict μ.sigmaFiniteSet` is sigma-finite, and for all sets `s ⊆ μ.sigmaFiniteSetᶜ`, + either `μ s = 0` or `μ s = ∞`. + Defined as `μ.sigmaFiniteSetWRT μ`. + +## Main statements + +* `measure_eq_top_of_subset_compl_sigmaFiniteSetWRT`: for s-finite `ν`, for all sets `s` + in `(sigmaFiniteSetWRT μ ν)ᶜ`, if `ν s ≠ 0` then `μ s = ∞`. +* An instance showing that `μ.restrict (sigmaFiniteSetWRT μ ν)` is sigma-finite. +* `restrict_compl_sigmaFiniteSetWRT`: if `μ ≪ ν` and `ν` is s-finite, then + `μ.restrict (μ.sigmaFiniteSetWRT ν)ᶜ = ∞ • ν.restrict (μ.sigmaFiniteSetWRT ν)ᶜ`. As a consequence, + that restriction is s-finite. + +* An instance showing that `μ.restrict μ.sigmaFiniteSet` is sigma-finite. +* `restrict_compl_sigmaFiniteSet_eq_zero_or_top`: the measure `μ.restrict μ.sigmaFiniteSetᶜ` takes + only two values: 0 and ∞ . +* `measure_compl_sigmaFiniteSet_eq_zero_iff_sigmaFinite`: a measure `μ` is sigma-finite + iff `μ μ.sigmaFiniteSetᶜ = 0`. + +## References + +* [P. R. Halmos, *Measure theory*, 17.3 and 30.11][halmos1950measure] + +-/ + +open scoped ENNReal Topology + +open Filter + +namespace MeasureTheory + +variable {α : Type*} {mα : MeasurableSpace α} {μ ν : Measure α} {s t : Set α} + +open Classical in +/-- A measurable set such that `μ.restrict (μ.sigmaFiniteSetWRT ν)` is sigma-finite and for all +measurable sets `t ⊆ sᶜ`, either `ν t = 0` or `μ t = ∞`. -/ +def Measure.sigmaFiniteSetWRT (μ ν : Measure α) : Set α := + if h : ∃ s : Set α, MeasurableSet s ∧ SigmaFinite (μ.restrict s) + ∧ (∀ t, t ⊆ sᶜ → ν t ≠ 0 → μ t = ∞) + then h.choose + else ∅ + +@[measurability] +lemma measurableSet_sigmaFiniteSetWRT : + MeasurableSet (μ.sigmaFiniteSetWRT ν) := by + rw [Measure.sigmaFiniteSetWRT] + split_ifs with h + · exact h.choose_spec.1 + · exact MeasurableSet.empty + +instance : SigmaFinite (μ.restrict (μ.sigmaFiniteSetWRT ν)) := by + rw [Measure.sigmaFiniteSetWRT] + split_ifs with h + · exact h.choose_spec.2.1 + · rw [Measure.restrict_empty] + infer_instance + +section IsFiniteMeasure + +/-! We prove that the condition in the definition of `sigmaFiniteSetWRT` is true for finite +measures. Since every s-finite measure is absolutely continuous with respect to a finite measure, +the condition will then also be true for s-finite measures. -/ + +/-- Let `C` be the supremum of `ν s` over all measurable sets `s` such that `μ.restrict s` is +sigma-finite. `C` is finite since `ν` is a finite measure. Then there exists a measurable set `t` +with `μ.restrict t` sigma-finite such that `ν t ≥ C - 1/n`. -/ +lemma exists_isSigmaFiniteSet_measure_ge (μ ν : Measure α) [IsFiniteMeasure ν] (n : ℕ) : + ∃ t, MeasurableSet t ∧ SigmaFinite (μ.restrict t) + ∧ (⨆ (s) (_ : MeasurableSet s) (_ : SigmaFinite (μ.restrict s)), ν s) - 1/n ≤ ν t := by + by_cases hC_lt : 1/n < ⨆ (s) (_ : MeasurableSet s) (_ : SigmaFinite (μ.restrict s)), ν s + · have h_lt_top : ⨆ (s) (_ : MeasurableSet s) (_ : SigmaFinite (μ.restrict s)), ν s < ∞ := by + refine (?_ : ⨆ (s) (_ : MeasurableSet s) + (_ : SigmaFinite (μ.restrict s)), ν s ≤ ν Set.univ).trans_lt (measure_lt_top _ _) + refine iSup_le (fun s ↦ ?_) + exact iSup_le (fun _ ↦ iSup_le (fun _ ↦ measure_mono (Set.subset_univ s))) + obtain ⟨t, ht⟩ := exists_lt_of_lt_ciSup + (ENNReal.sub_lt_self h_lt_top.ne (ne_zero_of_lt hC_lt) (by simp) : + (⨆ (s) (_ : MeasurableSet s) (_ : SigmaFinite (μ.restrict s)), ν s) - 1/n + < ⨆ (s) (_ : MeasurableSet s) (_ : SigmaFinite (μ.restrict s)), ν s) + have ht_meas : MeasurableSet t := by + by_contra h_not_mem + simp only [h_not_mem] at ht + simp at ht + have ht_mem : SigmaFinite (μ.restrict t) := by + by_contra h_not_mem + simp only [h_not_mem] at ht + simp at ht + refine ⟨t, ht_meas, ht_mem, ?_⟩ + simp only [ht_meas, ht_mem, iSup_true] at ht + exact ht.le + · refine ⟨∅, MeasurableSet.empty, by rw [Measure.restrict_empty]; infer_instance, ?_⟩ + rw [tsub_eq_zero_of_le (not_lt.mp hC_lt)] + exact zero_le' + +/-- A measurable set such that `μ.restrict (μ.sigmaFiniteSetGE ν n)` is sigma-finite and +for `C` the supremum of `ν s` over all measurable sets `s` with `μ.restrict s` sigma-finite, +`ν (μ.sigmaFiniteSetGE ν n) ≥ C - 1/n`. -/ +def Measure.sigmaFiniteSetGE (μ ν : Measure α) [IsFiniteMeasure ν] (n : ℕ) : Set α := + (exists_isSigmaFiniteSet_measure_ge μ ν n).choose + +lemma measurableSet_sigmaFiniteSetGE [IsFiniteMeasure ν] (n : ℕ) : + MeasurableSet (μ.sigmaFiniteSetGE ν n) := + (exists_isSigmaFiniteSet_measure_ge μ ν n).choose_spec.1 + +lemma sigmaFinite_restrict_sigmaFiniteSetGE (μ ν : Measure α) [IsFiniteMeasure ν] (n : ℕ) : + SigmaFinite (μ.restrict (μ.sigmaFiniteSetGE ν n)) := + (exists_isSigmaFiniteSet_measure_ge μ ν n).choose_spec.2.1 + +lemma measure_sigmaFiniteSetGE_le (μ ν : Measure α) [IsFiniteMeasure ν] (n : ℕ) : + ν (μ.sigmaFiniteSetGE ν n) + ≤ ⨆ (s) (_ : MeasurableSet s) (_ : SigmaFinite (μ.restrict s)), ν s := by + refine (le_iSup (f := fun s ↦ _) + (sigmaFinite_restrict_sigmaFiniteSetGE μ ν n)).trans ?_ + exact le_iSup₂ (f := fun s _ ↦ ⨆ (_ : SigmaFinite (μ.restrict s)), ν s) (μ.sigmaFiniteSetGE ν n) + (measurableSet_sigmaFiniteSetGE n) + +lemma measure_sigmaFiniteSetGE_ge (μ ν : Measure α) [IsFiniteMeasure ν] (n : ℕ) : + (⨆ (s) (_ : MeasurableSet s) (_ : SigmaFinite (μ.restrict s)), ν s) - 1/n + ≤ ν (μ.sigmaFiniteSetGE ν n) := + (exists_isSigmaFiniteSet_measure_ge μ ν n).choose_spec.2.2 + +lemma tendsto_measure_sigmaFiniteSetGE (μ ν : Measure α) [IsFiniteMeasure ν] : + Tendsto (fun n ↦ ν (μ.sigmaFiniteSetGE ν n)) atTop + (𝓝 (⨆ (s) (_ : MeasurableSet s) (_ : SigmaFinite (μ.restrict s)), ν s)) := by + refine tendsto_of_tendsto_of_tendsto_of_le_of_le ?_ + tendsto_const_nhds (measure_sigmaFiniteSetGE_ge μ ν) (measure_sigmaFiniteSetGE_le μ ν) + nth_rewrite 2 [← tsub_zero (⨆ (s) (_ : MeasurableSet s) (_ : SigmaFinite (μ.restrict s)), ν s)] + refine ENNReal.Tendsto.sub tendsto_const_nhds ?_ (Or.inr ENNReal.zero_ne_top) + simp only [one_div] + exact ENNReal.tendsto_inv_nat_nhds_zero + +/-- A measurable set such that `μ.restrict (μ.sigmaFiniteSetWRT' ν)` is sigma-finite and +`ν (μ.sigmaFiniteSetWRT' ν)` has maximal measure among such sets. -/ +def Measure.sigmaFiniteSetWRT' (μ ν : Measure α) [IsFiniteMeasure ν] : Set α := + ⋃ n, μ.sigmaFiniteSetGE ν n + +lemma measurableSet_sigmaFiniteSetWRT' [IsFiniteMeasure ν] : + MeasurableSet (μ.sigmaFiniteSetWRT' ν) := + MeasurableSet.iUnion measurableSet_sigmaFiniteSetGE + +lemma sigmaFinite_restrict_sigmaFiniteSetWRT' (μ ν : Measure α) [IsFiniteMeasure ν] : + SigmaFinite (μ.restrict (μ.sigmaFiniteSetWRT' ν)) := by + have := sigmaFinite_restrict_sigmaFiniteSetGE μ ν + let f : ℕ × ℕ → Set α := fun p : ℕ × ℕ ↦ (μ.sigmaFiniteSetWRT' ν)ᶜ + ∪ (spanningSets (μ.restrict (μ.sigmaFiniteSetGE ν p.1)) p.2 ∩ (μ.sigmaFiniteSetGE ν p.1)) + suffices (μ.restrict (μ.sigmaFiniteSetWRT' ν)).FiniteSpanningSetsIn (Set.range f) from + this.sigmaFinite + let e : ℕ ≃ ℕ × ℕ := Nat.pairEquiv.symm + refine ⟨fun n ↦ f (e n), fun _ ↦ by simp, fun n ↦ ?_, ?_⟩ + · simp only [Nat.pairEquiv_symm_apply, gt_iff_lt, measure_union_lt_top_iff, f, e] + rw [Measure.restrict_apply' measurableSet_sigmaFiniteSetWRT', Set.compl_inter_self, + Measure.restrict_apply' measurableSet_sigmaFiniteSetWRT'] + simp only [measure_empty, ENNReal.zero_lt_top, true_and] + refine (measure_mono Set.inter_subset_left).trans_lt ?_ + rw [← Measure.restrict_apply' (measurableSet_sigmaFiniteSetGE _)] + exact measure_spanningSets_lt_top _ _ + · simp only [Nat.pairEquiv_symm_apply, f, e] + rw [← Set.union_iUnion] + suffices ⋃ n, (spanningSets (μ.restrict (μ.sigmaFiniteSetGE ν (Nat.unpair n).1)) n.unpair.2 + ∩ μ.sigmaFiniteSetGE ν n.unpair.1) = μ.sigmaFiniteSetWRT' ν by + rw [this, Set.compl_union_self] + calc ⋃ n, (spanningSets (μ.restrict (μ.sigmaFiniteSetGE ν (Nat.unpair n).1)) n.unpair.2 + ∩ μ.sigmaFiniteSetGE ν n.unpair.1) + = ⋃ n, ⋃ m, (spanningSets (μ.restrict (μ.sigmaFiniteSetGE ν n)) m + ∩ μ.sigmaFiniteSetGE ν n) := + Set.iUnion_unpair (fun n m ↦ spanningSets (μ.restrict (μ.sigmaFiniteSetGE ν n)) m + ∩ μ.sigmaFiniteSetGE ν n) + _ = ⋃ n, μ.sigmaFiniteSetGE ν n := by + refine Set.iUnion_congr (fun n ↦ ?_) + rw [← Set.iUnion_inter, iUnion_spanningSets, Set.univ_inter] + _ = μ.sigmaFiniteSetWRT' ν := rfl + +/-- `μ.sigmaFiniteSetWRT' ν` has maximal `ν`-measure among all measurable sets `s` with sigma-finite +`μ.restrict s`. -/ +lemma measure_sigmaFiniteSetWRT' (μ ν : Measure α) [IsFiniteMeasure ν] : + ν (μ.sigmaFiniteSetWRT' ν) + = ⨆ (s) (_ : MeasurableSet s) (_ : SigmaFinite (μ.restrict s)), ν s := by + apply le_antisymm + · refine (le_iSup (f := fun _ ↦ _) + (sigmaFinite_restrict_sigmaFiniteSetWRT' μ ν)).trans ?_ + exact le_iSup₂ (f := fun s _ ↦ ⨆ (_ : SigmaFinite (μ.restrict s)), ν s) (μ.sigmaFiniteSetWRT' ν) + measurableSet_sigmaFiniteSetWRT' + · exact le_of_tendsto' (tendsto_measure_sigmaFiniteSetGE μ ν) + (fun _ ↦ measure_mono (Set.subset_iUnion _ _)) + +/-- Auxiliary lemma for `measure_eq_top_of_subset_compl_sigmaFiniteSetWRT'`. -/ +lemma measure_eq_top_of_subset_compl_sigmaFiniteSetWRT'_of_measurableSet [IsFiniteMeasure ν] + (hs : MeasurableSet s) (hs_subset : s ⊆ (μ.sigmaFiniteSetWRT' ν)ᶜ) (hνs : ν s ≠ 0) : + μ s = ∞ := by + suffices ¬ SigmaFinite (μ.restrict s) by + by_contra h + have h_lt_top : Fact (μ s < ∞) := ⟨Ne.lt_top h⟩ + exact this inferInstance + intro hsσ + have h_lt : ν (μ.sigmaFiniteSetWRT' ν) < ν (μ.sigmaFiniteSetWRT' ν ∪ s) := by + rw [measure_union _ hs] + · exact ENNReal.lt_add_right (measure_ne_top _ _) hνs + · exact disjoint_compl_right.mono_right hs_subset + have h_le : ν (μ.sigmaFiniteSetWRT' ν ∪ s) ≤ ν (μ.sigmaFiniteSetWRT' ν) := by + conv_rhs => rw [measure_sigmaFiniteSetWRT'] + refine (le_iSup + (f := fun (_ : SigmaFinite (μ.restrict (μ.sigmaFiniteSetWRT' ν ∪ s))) ↦ _) ?_).trans ?_ + · have := sigmaFinite_restrict_sigmaFiniteSetWRT' μ ν + infer_instance + · exact le_iSup₂ (f := fun s _ ↦ ⨆ (_ : SigmaFinite (μ.restrict _)), ν s) + (μ.sigmaFiniteSetWRT' ν ∪ s) (measurableSet_sigmaFiniteSetWRT'.union hs) + exact h_lt.not_le h_le + +/-- For all sets `s` in `(μ.sigmaFiniteSetWRT ν)ᶜ`, if `ν s ≠ 0` then `μ s = ∞`. -/ +lemma measure_eq_top_of_subset_compl_sigmaFiniteSetWRT' [IsFiniteMeasure ν] + (hs_subset : s ⊆ (μ.sigmaFiniteSetWRT' ν)ᶜ) (hνs : ν s ≠ 0) : + μ s = ∞ := by + rw [measure_eq_iInf] + simp_rw [iInf_eq_top] + suffices ∀ t, t ⊆ (μ.sigmaFiniteSetWRT' ν)ᶜ → s ⊆ t → MeasurableSet t → μ t = ∞ by + intro t hts ht + suffices μ (t ∩ (μ.sigmaFiniteSetWRT' ν)ᶜ) = ∞ from + measure_mono_top Set.inter_subset_left this + have hs_subset_t : s ⊆ t ∩ (μ.sigmaFiniteSetWRT' ν)ᶜ := Set.subset_inter hts hs_subset + exact this (t ∩ (μ.sigmaFiniteSetWRT' ν)ᶜ) Set.inter_subset_right hs_subset_t + (ht.inter measurableSet_sigmaFiniteSetWRT'.compl) + intro t ht_subset hst ht + refine measure_eq_top_of_subset_compl_sigmaFiniteSetWRT'_of_measurableSet ht ht_subset ?_ + exact fun hνt ↦ hνs (measure_mono_null hst hνt) + +end IsFiniteMeasure + +section SFinite + +/-- For all sets `s` in `(μ.sigmaFiniteSetWRT ν)ᶜ`, if `ν s ≠ 0` then `μ s = ∞`. -/ +lemma measure_eq_top_of_subset_compl_sigmaFiniteSetWRT [SFinite ν] + (hs_subset : s ⊆ (μ.sigmaFiniteSetWRT ν)ᶜ) (hνs : ν s ≠ 0) : + μ s = ∞ := by + have ⟨ν', hν', hνν', _⟩ := exists_isFiniteMeasure_absolutelyContinuous ν + have h : ∃ s : Set α, MeasurableSet s ∧ SigmaFinite (μ.restrict s) + ∧ (∀ t ⊆ sᶜ, ν t ≠ 0 → μ t = ∞) := by + refine ⟨μ.sigmaFiniteSetWRT' ν', measurableSet_sigmaFiniteSetWRT', + sigmaFinite_restrict_sigmaFiniteSetWRT' _ _, + fun t ht_subset hνt ↦ measure_eq_top_of_subset_compl_sigmaFiniteSetWRT' ht_subset ?_⟩ + exact fun hν't ↦ hνt (hνν' hν't) + rw [Measure.sigmaFiniteSetWRT, dif_pos h] at hs_subset + exact h.choose_spec.2.2 s hs_subset hνs + +lemma restrict_compl_sigmaFiniteSetWRT [SFinite ν] (hμν : μ ≪ ν) : + μ.restrict (μ.sigmaFiniteSetWRT ν)ᶜ = ∞ • ν.restrict (μ.sigmaFiniteSetWRT ν)ᶜ := by + ext s + rw [Measure.restrict_apply' measurableSet_sigmaFiniteSetWRT.compl, + Measure.smul_apply, smul_eq_mul, + Measure.restrict_apply' measurableSet_sigmaFiniteSetWRT.compl] + by_cases hνs : ν (s ∩ (μ.sigmaFiniteSetWRT ν)ᶜ) = 0 + · rw [hνs, mul_zero] + exact hμν hνs + · rw [ENNReal.top_mul hνs, measure_eq_top_of_subset_compl_sigmaFiniteSetWRT + Set.inter_subset_right hνs] + +end SFinite + +@[simp] +lemma measure_compl_sigmaFiniteSetWRT (hμν : μ ≪ ν) [SigmaFinite μ] [SFinite ν] : + ν (μ.sigmaFiniteSetWRT ν)ᶜ = 0 := by + have h : ν (μ.sigmaFiniteSetWRT ν)ᶜ ≠ 0 → μ (μ.sigmaFiniteSetWRT ν)ᶜ = ∞ := + measure_eq_top_of_subset_compl_sigmaFiniteSetWRT subset_rfl + 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] + intro i + by_contra h_ne_zero + have h_zero_top := measure_eq_top_of_subset_compl_sigmaFiniteSetWRT + (Set.inter_subset_left : (μ.sigmaFiniteSetWRT ν)ᶜ ∩ spanningSets μ i ⊆ _) ?_ + swap; · exact fun h ↦ h_ne_zero (hμν h) + refine absurd h_zero_top (ne_of_lt ?_) + exact (measure_mono Set.inter_subset_right).trans_lt (measure_spanningSets_lt_top μ i) + +section SigmaFiniteSet + +/-- A measurable set such that `μ.restrict μ.sigmaFiniteSet` is sigma-finite, + and for all measurable sets `s ⊆ μ.sigmaFiniteSetᶜ`, either `μ s = 0` or `μ s = ∞`. -/ +def Measure.sigmaFiniteSet (μ : Measure α) : Set α := μ.sigmaFiniteSetWRT μ + +@[measurability] +lemma measurableSet_sigmaFiniteSet : MeasurableSet μ.sigmaFiniteSet := + measurableSet_sigmaFiniteSetWRT + +lemma measure_eq_zero_or_top_of_subset_compl_sigmaFiniteSet [SFinite μ] + (ht_subset : t ⊆ μ.sigmaFiniteSetᶜ) : + μ t = 0 ∨ μ t = ∞ := by + rw [or_iff_not_imp_left] + exact measure_eq_top_of_subset_compl_sigmaFiniteSetWRT ht_subset + +/-- The measure `μ.restrict μ.sigmaFiniteSetᶜ` takes only two values: 0 and ∞ . -/ +lemma restrict_compl_sigmaFiniteSet_eq_zero_or_top (μ : Measure α) [SFinite μ] (s : Set α) : + μ.restrict μ.sigmaFiniteSetᶜ s = 0 ∨ μ.restrict μ.sigmaFiniteSetᶜ s = ∞ := by + rw [Measure.restrict_apply' measurableSet_sigmaFiniteSet.compl] + exact measure_eq_zero_or_top_of_subset_compl_sigmaFiniteSet Set.inter_subset_right + +/-- The restriction of an s-finite measure `μ` to `μ.sigmaFiniteSet` is sigma-finite. -/ +instance : SigmaFinite (μ.restrict μ.sigmaFiniteSet) := by + rw [Measure.sigmaFiniteSet] + infer_instance + +lemma sigmaFinite_of_measure_compl_sigmaFiniteSet_eq_zero (h : μ μ.sigmaFiniteSetᶜ = 0) : + SigmaFinite μ := by + rw [← Measure.restrict_add_restrict_compl (μ := μ) (measurableSet_sigmaFiniteSet (μ := μ)), + Measure.restrict_eq_zero.mpr h, add_zero] + infer_instance + +@[simp] +lemma measure_compl_sigmaFiniteSet (μ : Measure α) [SigmaFinite μ] : μ μ.sigmaFiniteSetᶜ = 0 := + measure_compl_sigmaFiniteSetWRT Measure.AbsolutelyContinuous.rfl + +/-- An s-finite measure `μ` is sigma-finite iff `μ μ.sigmaFiniteSetᶜ = 0`. -/ +lemma measure_compl_sigmaFiniteSet_eq_zero_iff_sigmaFinite (μ : Measure α) : + μ μ.sigmaFiniteSetᶜ = 0 ↔ SigmaFinite μ := + ⟨sigmaFinite_of_measure_compl_sigmaFiniteSet_eq_zero, fun _ ↦ measure_compl_sigmaFiniteSet μ⟩ + +end SigmaFiniteSet + +end MeasureTheory diff --git a/Mathlib/MeasureTheory/Decomposition/Lebesgue.lean b/Mathlib/MeasureTheory/Decomposition/Lebesgue.lean index 5cc54ff5324a5..243efac2011bc 100644 --- a/Mathlib/MeasureTheory/Decomposition/Lebesgue.lean +++ b/Mathlib/MeasureTheory/Decomposition/Lebesgue.lean @@ -108,9 +108,15 @@ theorem haveLebesgueDecomposition_add (μ ν : Measure α) [HaveLebesgueDecompos μ = μ.singularPart ν + ν.withDensity (μ.rnDeriv ν) := (haveLebesgueDecomposition_spec μ ν).2.2 +/-- For the versions of this lemma where `ν.withDensity (μ.rnDeriv ν)` or `μ.singularPart ν` are +isolated, see `MeasureTheory.Measure.measure_sub_singularPart` and +`MeasureTheory.Measure.measure_sub_rnDeriv`. -/ lemma singularPart_add_rnDeriv (μ ν : Measure α) [HaveLebesgueDecomposition μ ν] : μ.singularPart ν + ν.withDensity (μ.rnDeriv ν) = μ := (haveLebesgueDecomposition_add μ ν).symm +/-- For the versions of this lemma where `μ.singularPart ν` or `ν.withDensity (μ.rnDeriv ν)` are +isolated, see `MeasureTheory.Measure.measure_sub_singularPart` and +`MeasureTheory.Measure.measure_sub_rnDeriv`. -/ lemma rnDeriv_add_singularPart (μ ν : Measure α) [HaveLebesgueDecomposition μ ν] : ν.withDensity (μ.rnDeriv ν) + μ.singularPart ν = μ := by rw [add_comm, singularPart_add_rnDeriv] @@ -464,6 +470,17 @@ lemma singularPart_restrict (μ ν : Measure α) [HaveLebesgueDecomposition μ rw [withDensity_indicator hs, ← restrict_withDensity hs, ← Measure.restrict_add, ← μ.haveLebesgueDecomposition_add ν] +lemma measure_sub_singularPart (μ ν : Measure α) [HaveLebesgueDecomposition μ ν] + [IsFiniteMeasure μ] : + μ - μ.singularPart ν = ν.withDensity (μ.rnDeriv ν) := by + nth_rw 1 [← rnDeriv_add_singularPart μ ν] + exact Measure.add_sub_cancel + +lemma measure_sub_rnDeriv (μ ν : Measure α) [HaveLebesgueDecomposition μ ν] [IsFiniteMeasure μ] : + μ - ν.withDensity (μ.rnDeriv ν) = μ.singularPart ν := by + nth_rw 1 [← singularPart_add_rnDeriv μ ν] + exact Measure.add_sub_cancel + /-- Given measures `μ` and `ν`, if `s` is a measure mutually singular to `ν` and `f` is a measurable function such that `μ = s + fν`, then `f = μ.rnDeriv ν`. @@ -824,9 +841,9 @@ theorem haveLebesgueDecomposition_of_finiteMeasure [IsFiniteMeasure μ] [IsFinit refine Measurable.aemeasurable ?_ convert (iSup_mem_measurableLE _ hf₁ n).1 simp - · refine Filter.eventually_of_forall fun a ↦ ?_ + · refine Filter.Eventually.of_forall fun a ↦ ?_ simp [iSup_monotone' f _] - · refine Filter.eventually_of_forall fun a ↦ ?_ + · 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 diff --git a/Mathlib/MeasureTheory/Decomposition/RadonNikodym.lean b/Mathlib/MeasureTheory/Decomposition/RadonNikodym.lean index da28661366bca..48bb69b5fadb2 100644 --- a/Mathlib/MeasureTheory/Decomposition/RadonNikodym.lean +++ b/Mathlib/MeasureTheory/Decomposition/RadonNikodym.lean @@ -78,7 +78,7 @@ lemma rnDeriv_pos [HaveLebesgueDecomposition μ ν] (hμν : μ ≪ ν) : ae_withDensity_iff (Measure.measurable_rnDeriv _ _), Measure.withDensity_rnDeriv_eq _ _ hμν] exact ae_of_all _ (fun x hx ↦ lt_of_le_of_ne (zero_le _) hx.symm) -lemma rnDeriv_pos' [SigmaFinite μ] [SFinite ν] (hμν : μ ≪ ν) : +lemma rnDeriv_pos' [HaveLebesgueDecomposition ν μ] [SigmaFinite μ] (hμν : μ ≪ ν) : ∀ᵐ x ∂μ, 0 < ν.rnDeriv μ x := by refine (absolutelyContinuous_withDensity_rnDeriv hμν).ae_le ?_ filter_upwards [Measure.rnDeriv_pos (withDensity_absolutelyContinuous μ (ν.rnDeriv μ)), @@ -143,8 +143,8 @@ lemma rnDeriv_withDensity_left {μ ν : Measure α} [SigmaFinite μ] [SigmaFinit rw [← hx2, hx, hx1] /-- Auxiliary lemma for `rnDeriv_withDensity_right`. -/ -lemma rnDeriv_withDensity_right_of_absolutelyContinuous {ν : Measure α} [SigmaFinite μ] - [SigmaFinite ν] (hμν : μ ≪ ν) (hf : AEMeasurable f ν) +lemma rnDeriv_withDensity_right_of_absolutelyContinuous {ν : Measure α} + [HaveLebesgueDecomposition μ ν] [SigmaFinite ν] (hμν : μ ≪ ν) (hf : AEMeasurable f ν) (hf_ne_zero : ∀ᵐ x ∂ν, f x ≠ 0) (hf_ne_top : ∀ᵐ x ∂ν, f x ≠ ∞) : μ.rnDeriv (ν.withDensity f) =ᵐ[ν] fun x ↦ (f x)⁻¹ * μ.rnDeriv ν x := by have : SigmaFinite (ν.withDensity f) := SigmaFinite.withDensity_of_ne_top hf_ne_top @@ -173,7 +173,6 @@ lemma rnDeriv_withDensity_right (μ ν : Measure α) [SigmaFinite μ] [SigmaFini rnDeriv_withDensity_withDensity_rnDeriv_right μ ν hf hf_ne_zero hf_ne_top have h₂ : μ.rnDeriv ν =ᵐ[ν] μ'.rnDeriv ν := (Measure.rnDeriv_withDensity _ (Measure.measurable_rnDeriv _ _)).symm - have : SigmaFinite μ' := SigmaFinite.withDensity_of_ne_top (Measure.rnDeriv_ne_top _ _) have hμ' := rnDeriv_withDensity_right_of_absolutelyContinuous (withDensity_absolutelyContinuous ν (μ.rnDeriv ν)) hf hf_ne_zero hf_ne_top filter_upwards [h₁, h₂, hμ'] with x hx₁ hx₂ hx_eq @@ -181,7 +180,7 @@ lemma rnDeriv_withDensity_right (μ ν : Measure α) [SigmaFinite μ] [SigmaFini end rnDeriv_withDensity_leftRight -lemma rnDeriv_eq_zero_of_mutuallySingular [SigmaFinite μ] {ν' : Measure α} +lemma rnDeriv_eq_zero_of_mutuallySingular {ν' : Measure α} [HaveLebesgueDecomposition μ ν'] [SigmaFinite ν'] (h : μ ⟂ₘ ν) (hνν' : ν ≪ ν') : μ.rnDeriv ν' =ᵐ[ν] 0 := by let t := h.nullSet @@ -203,7 +202,7 @@ lemma rnDeriv_eq_zero_of_mutuallySingular [SigmaFinite μ] {ν' : Measure α} /-- Auxiliary lemma for `rnDeriv_add_right_of_mutuallySingular`. -/ lemma rnDeriv_add_right_of_absolutelyContinuous_of_mutuallySingular {ν' : Measure α} - [SigmaFinite μ] [SigmaFinite ν] [SigmaFinite ν'] + [HaveLebesgueDecomposition μ ν] [HaveLebesgueDecomposition μ (ν + ν')] [SigmaFinite ν] (hμν : μ ≪ ν) (hνν' : ν ⟂ₘ ν') : μ.rnDeriv (ν + ν') =ᵐ[ν] μ.rnDeriv ν := by let t := hνν'.nullSet @@ -265,7 +264,8 @@ lemma rnDeriv_withDensity_rnDeriv [SigmaFinite μ] [SigmaFinite ν] (hμν : μ (Measure.mutuallySingular_singularPart ν μ).symm.withDensity).symm /-- Auxiliary lemma for `inv_rnDeriv`. -/ -lemma inv_rnDeriv_aux [SigmaFinite μ] [SigmaFinite ν] (hμν : μ ≪ ν) (hνμ : ν ≪ μ) : +lemma inv_rnDeriv_aux [HaveLebesgueDecomposition μ ν] [HaveLebesgueDecomposition ν μ] + [SigmaFinite μ] (hμν : μ ≪ ν) (hνμ : ν ≪ μ) : (μ.rnDeriv ν)⁻¹ =ᵐ[μ] ν.rnDeriv μ := by suffices μ.withDensity (μ.rnDeriv ν)⁻¹ = μ.withDensity (ν.rnDeriv μ) by calc (μ.rnDeriv ν)⁻¹ =ᵐ[μ] (μ.withDensity (μ.rnDeriv ν)⁻¹).rnDeriv μ := @@ -390,6 +390,12 @@ lemma integral_toReal_rnDeriv [SigmaFinite μ] [SigmaFinite ν] (hμν : μ ≪ ∫ x, (μ.rnDeriv ν x).toReal ∂ν = (μ Set.univ).toReal := by rw [← integral_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] + end integral lemma rnDeriv_mul_rnDeriv {κ : Measure α} [SigmaFinite μ] [SigmaFinite ν] [SigmaFinite κ] @@ -400,11 +406,32 @@ lemma rnDeriv_mul_rnDeriv {κ : Measure α} [SigmaFinite μ] [SigmaFinite ν] [S · exact rnDeriv_ne_top _ _ · rw [Measure.withDensity_rnDeriv_eq _ _ hμν] +lemma rnDeriv_mul_rnDeriv' {κ : Measure α} [SigmaFinite μ] [SigmaFinite ν] [SigmaFinite κ] + (hνκ : ν ≪ κ) : + μ.rnDeriv ν * ν.rnDeriv κ =ᵐ[ν] μ.rnDeriv κ := by + obtain ⟨h_meas, h_sing, hμν⟩ := Measure.haveLebesgueDecomposition_spec μ ν + filter_upwards [hνκ <| Measure.rnDeriv_add' (μ.singularPart ν) (ν.withDensity (μ.rnDeriv ν)) κ, + hνκ <| Measure.rnDeriv_withDensity_left_of_absolutelyContinuous hνκ h_meas.aemeasurable, + Measure.rnDeriv_eq_zero_of_mutuallySingular h_sing hνκ] with x hx1 hx2 hx3 + nth_rw 2 [hμν] + rw [hx1, Pi.add_apply, hx2, Pi.mul_apply, hx3, Pi.zero_apply, zero_add] + lemma rnDeriv_le_one_of_le (hμν : μ ≤ ν) [SigmaFinite ν] : μ.rnDeriv ν ≤ᵐ[ν] 1 := by refine ae_le_of_forall_setLIntegral_le_of_sigmaFinite (μ.measurable_rnDeriv ν) fun s _ _ ↦ ?_ simp only [Pi.one_apply, MeasureTheory.setLIntegral_one] exact (Measure.setLIntegral_rnDeriv_le s).trans (hμν s) +lemma rnDeriv_le_one_iff_le [HaveLebesgueDecomposition μ ν] [SigmaFinite ν] (hμν : μ ≪ ν) : + μ.rnDeriv ν ≤ᵐ[ν] 1 ↔ μ ≤ ν := by + refine ⟨fun h s ↦ ?_, fun h ↦ rnDeriv_le_one_of_le h⟩ + rw [← withDensity_rnDeriv_eq _ _ hμν, withDensity_apply', ← setLIntegral_one] + exact setLIntegral_mono_ae aemeasurable_const (h.mono fun _ hh _ ↦ hh) + +lemma rnDeriv_eq_one_iff_eq [HaveLebesgueDecomposition μ ν] [SigmaFinite ν] (hμν : μ ≪ ν) : + μ.rnDeriv ν =ᵐ[ν] 1 ↔ μ = ν := by + refine ⟨fun h ↦ ?_, fun h ↦ h ▸ ν.rnDeriv_self⟩ + rw [← withDensity_rnDeriv_eq _ _ hμν, withDensity_congr_ae h, withDensity_one] + section MeasurableEmbedding variable {mβ : MeasurableSpace β} {f : α → β} @@ -542,6 +569,11 @@ theorem integral_rnDeriv_smul [HaveLebesgueDecomposition μ ν] (hμν : μ ≪ contrapose! hf exact (integrable_rnDeriv_smul_iff hμν).mp hf +lemma setIntegral_rnDeriv_smul [HaveLebesgueDecomposition μ ν] (hμν : μ ≪ ν) + [SigmaFinite μ] {f : α → E} {s : Set α} (hs : MeasurableSet s) : + ∫ x in s, (μ.rnDeriv ν x).toReal • f x ∂ν = ∫ x in s, f x ∂μ := by + simp_rw [← integral_indicator hs, Set.indicator_smul, integral_rnDeriv_smul hμν] + end IntegralRNDerivMul end MeasureTheory diff --git a/Mathlib/MeasureTheory/Decomposition/SignedHahn.lean b/Mathlib/MeasureTheory/Decomposition/SignedHahn.lean index 13feeda01ee5a..77cd7b8a79759 100644 --- a/Mathlib/MeasureTheory/Decomposition/SignedHahn.lean +++ b/Mathlib/MeasureTheory/Decomposition/SignedHahn.lean @@ -81,7 +81,7 @@ To implement this in Lean, we define several auxiliary definitions. where `restrictNonposSeq s i 0 = someExistsOneDivLT s (i \ ∅)` and `restrictNonposSeq s i (n + 1) = someExistsOneDivLT s (i \ ⋃ k ≤ n, restrictNonposSeq k)`. - This definition represents the sequence $(A_n)$ in the proof as described above. + This definition represents the sequence $(A_n)$ in the proof as described above. With these definitions, we are able consider the case where the sequence terminates separately, allowing us to prove `exists_subset_restrict_nonpos`. @@ -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 @@ -372,7 +372,7 @@ theorem exists_compl_positive_negative (s : SignedMeasure α) : have hA₂ : s ≤[A] 0 := restrict_le_restrict_iUnion _ _ hB₁ hB₂ have hA₃ : s A = sInf s.measureOfNegatives := by apply le_antisymm - · refine le_of_tendsto_of_tendsto tendsto_const_nhds hf₂ (eventually_of_forall fun n => ?_) + · refine le_of_tendsto_of_tendsto tendsto_const_nhds hf₂ (Eventually.of_forall fun n => ?_) rw [← (hB n).2, hA, ← Set.diff_union_of_subset (Set.subset_iUnion _ n), of_union Set.disjoint_sdiff_left _ (hB₁ n)] · refine add_le_of_nonpos_left ?_ diff --git a/Mathlib/MeasureTheory/Decomposition/UnsignedHahn.lean b/Mathlib/MeasureTheory/Decomposition/UnsignedHahn.lean index f6b3615d79356..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,15 +49,15 @@ 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) : 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_iInter hs hm ?_ + refine NNReal.tendsto_coe.2 <| (ENNReal.tendsto_toNNReal <| ?_).comp <| + tendsto_measure_iInter (fun n ↦ (hs n).nullMeasurableSet) hm ?_ exacts [hμ _, ⟨0, hμ _⟩, hν _, ⟨0, hν _⟩] have bdd_c : BddAbove c := by use (μ univ).toNNReal diff --git a/Mathlib/MeasureTheory/Function/AEEqFun.lean b/Mathlib/MeasureTheory/Function/AEEqFun.lean index cb6030efa880d..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 /-! @@ -93,7 +93,7 @@ variable (α) /-- The space of equivalence classes of almost everywhere strongly measurable functions, where two strongly measurable functions are equivalent if they agree almost everywhere, i.e., - they differ on a set of measure `0`. -/ + they differ on a set of measure `0`. -/ def AEEqFun (μ : Measure α) : Type _ := Quotient (μ.aeEqSetoid β) @@ -235,7 +235,7 @@ variable [TopologicalSpace γ] [MeasurableSpace β] {ν : MeasureTheory.Measure /-- Composition of an almost everywhere equal function and a quasi measure preserving function. This is an important special case of `AEEqFun.compQuasiMeasurePreserving`. We use a separate -definition so that lemmas that need `f` to be measure preserving can be `@[simp]` lemmas. -/ +definition so that lemmas that need `f` to be measure preserving can be `@[simp]` lemmas. -/ def compMeasurePreserving (g : β →ₘ[ν] γ) (f : α → β) (hf : MeasurePreserving f μ ν) : α →ₘ[μ] γ := g.compQuasiMeasurePreserving f hf.quasiMeasurePreserving @@ -576,7 +576,7 @@ theorem coeFn_const (b : β) : (const α b : α →ₘ[μ] β) =ᵐ[μ] Function @[simp] theorem coeFn_const_eq [NeZero μ] (b : β) (x : α) : (const α b : α →ₘ[μ] β) x = b := by simp only [cast] - split_ifs with h; swap; exact h.elim ⟨b, rfl⟩ + split_ifs with h; swap; · exact h.elim ⟨b, rfl⟩ have := Classical.choose_spec h set b' := Classical.choose h simp_rw [const, mk_eq_mk, EventuallyEq, ← const_def, eventually_const] at this diff --git a/Mathlib/MeasureTheory/Function/AEEqOfIntegral.lean b/Mathlib/MeasureTheory/Function/AEEqOfIntegral.lean index 6c90b652e93b4..20685e3ff10ed 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 @@ -107,7 +107,7 @@ theorem ae_eq_zero_of_forall_dual [NormedAddCommGroup E] [NormedSpace 𝕜 E] [SecondCountableTopology E] {f : α → E} (hf : ∀ c : Dual 𝕜 E, (fun x => ⟪f x, c⟫) =ᵐ[μ] 0) : f =ᵐ[μ] 0 := ae_eq_zero_of_forall_dual_of_isSeparable 𝕜 (.of_separableSpace Set.univ) hf - (eventually_of_forall fun _ => Set.mem_univ _) + (Eventually.of_forall fun _ => Set.mem_univ _) variable {𝕜} @@ -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) @@ -260,7 +260,7 @@ theorem ae_nonneg_of_forall_setIntegral_nonneg (hf : Integrable f μ) have h_const_le : (∫ x in s, f x ∂μ) ≤ ∫ _ in s, b ∂μ := by refine setIntegral_mono_ae_restrict hf.integrableOn (integrableOn_const.mpr (Or.inr mus)) ?_ rw [EventuallyLE, ae_restrict_iff₀ (hs.mono μ.restrict_le_self)] - exact eventually_of_forall fun x hxs => hxs + exact Eventually.of_forall fun x hxs => hxs rwa [setIntegral_const, smul_eq_mul, mul_comm] at h_const_le contrapose! h_int_gt with H calc @@ -523,7 +523,7 @@ theorem ae_eq_zero_of_forall_setIntegral_eq_of_finStronglyMeasurable_trim (hm : haveI : SigmaFinite ((μ.restrict t).trim hm) := by rwa [restrict_trim hm μ ht_meas] at htμ have htf_zero : f =ᵐ[μ.restrict tᶜ] 0 := by rw [EventuallyEq, ae_restrict_iff' (MeasurableSet.compl (hm _ ht_meas))] - exact eventually_of_forall htf_zero + exact Eventually.of_forall htf_zero have hf_meas_m : StronglyMeasurable[m] f := hf.stronglyMeasurable suffices f =ᵐ[μ.restrict t] 0 from ae_of_ae_restrict_of_ae_restrict_compl _ this htf_zero @@ -581,7 +581,7 @@ alias Integrable.ae_eq_of_forall_set_integral_eq := variable {β : Type*} [TopologicalSpace β] [MeasurableSpace β] [BorelSpace β] /-- If an integrable function has zero integral on all closed sets, then it is zero -almost everwhere. -/ +almost everywhere. -/ lemma ae_eq_zero_of_forall_setIntegral_isClosed_eq_zero {μ : Measure β} {f : β → E} (hf : Integrable f μ) (h'f : ∀ (s : Set β), IsClosed s → ∫ x in s, f x ∂μ = 0) : f =ᵐ[μ] 0 := by @@ -604,7 +604,7 @@ alias ae_eq_zero_of_forall_set_integral_isClosed_eq_zero := ae_eq_zero_of_forall_setIntegral_isClosed_eq_zero /-- If an integrable function has zero integral on all compact sets in a sigma-compact space, then -it is zero almost everwhere. -/ +it is zero almost everywhere. -/ lemma ae_eq_zero_of_forall_setIntegral_isCompact_eq_zero [SigmaCompactSpace β] [R1Space β] {μ : Measure β} {f : β → E} (hf : Integrable f μ) (h'f : ∀ (s : Set β), IsCompact s → ∫ x in s, f x ∂μ = 0) : @@ -628,7 +628,7 @@ lemma ae_eq_zero_of_forall_setIntegral_isCompact_eq_zero · exact hf.integrableOn /-- If a locally integrable function has zero integral on all compact sets in a sigma-compact space, -then it is zero almost everwhere. -/ +then it is zero almost everywhere. -/ lemma ae_eq_zero_of_forall_setIntegral_isCompact_eq_zero' [SigmaCompactSpace β] [R1Space β] {μ : Measure β} {f : β → E} (hf : LocallyIntegrable f μ) (h'f : ∀ (s : Set β), IsCompact s → ∫ x in s, f x ∂μ = 0) : diff --git a/Mathlib/MeasureTheory/Function/ConditionalExpectation/AEMeasurable.lean b/Mathlib/MeasureTheory/Function/ConditionalExpectation/AEMeasurable.lean index 2f9b8035e0291..98a2a41d0a279 100644 --- a/Mathlib/MeasureTheory/Function/ConditionalExpectation/AEMeasurable.lean +++ b/Mathlib/MeasureTheory/Function/ConditionalExpectation/AEMeasurable.lean @@ -100,6 +100,12 @@ theorem const_inner {𝕜 β} [RCLike 𝕜] [NormedAddCommGroup β] [InnerProduc dsimp only rw [hx] +@[simp] theorem of_subsingleton [Subsingleton β] : AEStronglyMeasurable' m f μ := + ⟨f, by simp, by simp⟩ + +@[simp] theorem of_subsingleton' [Subsingleton α] : AEStronglyMeasurable' m f μ := + ⟨f, by simp, by simp⟩ + /-- An `m`-strongly measurable function almost everywhere equal to `f`. -/ noncomputable def mk (f : α → β) (hfm : AEStronglyMeasurable' m f μ) : α → β := hfm.choose @@ -379,7 +385,7 @@ theorem lpMeasSubgroupToLpTrim_neg (hm : m ≤ m0) (f : lpMeasSubgroup F m p μ) refine EventuallyEq.trans ?_ (EventuallyEq.neg (lpMeasSubgroupToLpTrim_ae_eq hm f).symm) refine (Lp.coeFn_neg _).trans ?_ simp_rw [lpMeasSubgroup_coe] - exact eventually_of_forall fun x => by rfl + exact Eventually.of_forall fun x => by rfl theorem lpMeasSubgroupToLpTrim_sub (hm : m ≤ m0) (f g : lpMeasSubgroup F m p μ) : lpMeasSubgroupToLpTrim F p μ hm (f - g) = diff --git a/Mathlib/MeasureTheory/Function/ConditionalExpectation/Basic.lean b/Mathlib/MeasureTheory/Function/ConditionalExpectation/Basic.lean index 5feff3cfacb85..daab2ab684f35 100644 --- a/Mathlib/MeasureTheory/Function/ConditionalExpectation/Basic.lean +++ b/Mathlib/MeasureTheory/Function/ConditionalExpectation/Basic.lean @@ -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] @@ -138,7 +138,7 @@ theorem condexp_ae_eq_condexpL1 (hm : m ≤ m0) [hμm : SigmaFinite (μ.trim hm) theorem condexp_ae_eq_condexpL1CLM (hm : m ≤ m0) [SigmaFinite (μ.trim hm)] (hf : Integrable f μ) : μ[f|m] =ᵐ[μ] condexpL1CLM F' hm μ (hf.toL1 f) := by - refine (condexp_ae_eq_condexpL1 hm f).trans (eventually_of_forall fun x => ?_) + refine (condexp_ae_eq_condexpL1 hm f).trans (Eventually.of_forall fun x => ?_) rw [condexpL1_eq hf] theorem condexp_undef (hf : ¬Integrable f μ) : μ[f|m] = 0 := by @@ -256,7 +256,7 @@ theorem condexp_bot_ae_eq (f : α → F') : μ[f|⊥] =ᵐ[μ] fun _ => (μ Set.univ).toReal⁻¹ • ∫ x, f x ∂μ := by rcases eq_zero_or_neZero μ with rfl | hμ · rw [ae_zero]; exact eventually_bot - · exact eventually_of_forall <| congr_fun (condexp_bot' f) + · exact Eventually.of_forall <| congr_fun (condexp_bot' f) theorem condexp_bot [IsProbabilityMeasure μ] (f : α → F') : μ[f|⊥] = fun _ => ∫ x, f x ∂μ := by refine (condexp_bot' f).trans ?_; rw [measure_univ, ENNReal.one_toReal, inv_one, one_smul] @@ -385,6 +385,6 @@ theorem tendsto_condexp_unique (fs gs : ℕ → α → F') (f g : α → F') have hcond_gs : Tendsto (fun n => condexpL1 hm μ (gs n)) atTop (𝓝 (condexpL1 hm μ g)) := tendsto_condexpL1_of_dominated_convergence hm _ (fun n => (hgs_int n).1) h_int_bound_gs hgs_bound hgs - exact tendsto_nhds_unique_of_eventuallyEq hcond_gs hcond_fs (eventually_of_forall hn_eq) + exact tendsto_nhds_unique_of_eventuallyEq hcond_gs hcond_fs (Eventually.of_forall hn_eq) end MeasureTheory diff --git a/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondexpL1.lean b/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondexpL1.lean index 6980909f8a5ae..a0b70b96c1884 100644 --- a/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondexpL1.lean +++ b/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondexpL1.lean @@ -11,7 +11,7 @@ This file contains two more steps of the construction of the conditional expecta completed in `MeasureTheory.Function.ConditionalExpectation.Basic`. See that file for a description of the full process. -The contitional expectation of an `L²` function is defined in +The conditional expectation of an `L²` function is defined in `MeasureTheory.Function.ConditionalExpectation.CondexpL2`. In this file, we perform two steps. * Show that the conditional expectation of the indicator of a measurable set with finite measure is integrable and define a map `Set α → (E →L[ℝ] (α →₁[μ] E))` which to a set associates a linear @@ -93,7 +93,7 @@ theorem condexpIndL1Fin_add (hs : MeasurableSet s) (hμs : μ s ≠ ∞) (x y : refine EventuallyEq.trans ?_ (EventuallyEq.add (Memℒp.coeFn_toLp q).symm (Memℒp.coeFn_toLp q).symm) rw [condexpIndSMul_add] - refine (Lp.coeFn_add _ _).trans (eventually_of_forall fun a => ?_) + refine (Lp.coeFn_add _ _).trans (Eventually.of_forall fun a => ?_) rfl theorem condexpIndL1Fin_smul (hs : MeasurableSet s) (hμs : μ s ≠ ∞) (c : ℝ) (x : G) : @@ -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 diff --git a/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondexpL2.lean b/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondexpL2.lean index bea64c5684025..fd79dc7a0b777 100644 --- a/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondexpL2.lean +++ b/Mathlib/MeasureTheory/Function/ConditionalExpectation/CondexpL2.lean @@ -347,7 +347,7 @@ theorem integrable_condexpL2_indicator (hm : m ≤ m0) [SigmaFinite (μ.trim hm) (hs : MeasurableSet s) (hμs : μ s ≠ ∞) (x : E') : Integrable (β := E') (condexpL2 E' 𝕜 hm (indicatorConstLp 2 hs hμs x)) μ := by refine integrable_of_forall_fin_meas_le' hm (μ s * ‖x‖₊) - (ENNReal.mul_lt_top hμs ENNReal.coe_ne_top) ?_ ?_ + (ENNReal.mul_lt_top hμs.lt_top ENNReal.coe_lt_top) ?_ ?_ · rw [lpMeas_coe]; exact Lp.aestronglyMeasurable _ · refine fun t ht hμt => (setLIntegral_nnnorm_condexpL2_indicator_le hm hs hμs x ht hμt).trans ?_ @@ -426,7 +426,7 @@ with finite measure is integrable. -/ theorem integrable_condexpIndSMul (hm : m ≤ m0) [SigmaFinite (μ.trim hm)] (hs : MeasurableSet s) (hμs : μ s ≠ ∞) (x : G) : Integrable (condexpIndSMul hm hs hμs x) μ := by refine integrable_of_forall_fin_meas_le' hm (μ s * ‖x‖₊) - (ENNReal.mul_lt_top hμs ENNReal.coe_ne_top) ?_ ?_ + (ENNReal.mul_lt_top hμs.lt_top ENNReal.coe_lt_top) ?_ ?_ · exact Lp.aestronglyMeasurable _ · refine fun t ht hμt => (setLIntegral_nnnorm_condexpIndSMul_le hm hs hμs x ht hμt).trans ?_ gcongr diff --git a/Mathlib/MeasureTheory/Function/ConditionalExpectation/Real.lean b/Mathlib/MeasureTheory/Function/ConditionalExpectation/Real.lean index 3b2163fa2524d..44d7dd73837dd 100644 --- a/Mathlib/MeasureTheory/Function/ConditionalExpectation/Real.lean +++ b/Mathlib/MeasureTheory/Function/ConditionalExpectation/Real.lean @@ -127,12 +127,12 @@ theorem setIntegral_abs_condexp_le {s : Set α} (hs : MeasurableSet[m] s) (f : refine integral_congr_ae ?_ have : (fun x => |(μ[s.indicator f|m]) x|) =ᵐ[μ] fun x => |s.indicator (μ[f|m]) x| := (condexp_indicator hfint hs).fun_comp abs - refine EventuallyEq.trans (eventually_of_forall fun x => ?_) this.symm + refine EventuallyEq.trans (Eventually.of_forall fun x => ?_) this.symm rw [← Real.norm_eq_abs, norm_indicator_eq_indicator_norm] simp only [Real.norm_eq_abs] rw [this, ← integral_indicator (hnm _ hs)] refine (integral_abs_condexp_le _).trans - (le_of_eq <| integral_congr_ae <| eventually_of_forall fun x => ?_) + (le_of_eq <| integral_congr_ae <| Eventually.of_forall fun x => ?_) simp_rw [← Real.norm_eq_abs, norm_indicator_eq_indicator_norm] @[deprecated (since := "2024-04-17")] @@ -145,7 +145,7 @@ theorem ae_bdd_condexp_of_ae_bdd {R : ℝ≥0} {f : α → ℝ} (hbdd : ∀ᵐ x by_cases hnm : m ≤ m0 swap · simp_rw [condexp_of_not_le hnm, Pi.zero_apply, abs_zero] - exact eventually_of_forall fun _ => R.coe_nonneg + exact Eventually.of_forall fun _ => R.coe_nonneg by_cases hfint : Integrable f μ swap · simp_rw [condexp_undef hfint] @@ -268,19 +268,19 @@ theorem condexp_stronglyMeasurable_mul_of_bound (hm : m ≤ m0) [IsFiniteMeasure refine tendsto_condexp_unique (fun n x => fs n x * g x) (fun n x => fs n x * (μ[g|m]) x) (f * g) (f * μ[g|m]) ?_ ?_ ?_ ?_ (c * ‖g ·‖) ?_ (c * ‖(μ[g|m]) ·‖) ?_ ?_ ?_ ?_ · exact fun n => hg.bdd_mul' ((SimpleFunc.stronglyMeasurable (fs n)).mono hm).aestronglyMeasurable - (eventually_of_forall (hfs_bound n)) + (Eventually.of_forall (hfs_bound n)) · exact fun n => integrable_condexp.bdd_mul' ((SimpleFunc.stronglyMeasurable (fs n)).mono hm).aestronglyMeasurable - (eventually_of_forall (hfs_bound n)) + (Eventually.of_forall (hfs_bound n)) · filter_upwards [hfs_tendsto] with x hx exact hx.mul tendsto_const_nhds · filter_upwards [hfs_tendsto] with x hx exact hx.mul tendsto_const_nhds · exact hg.norm.const_mul c · exact integrable_condexp.norm.const_mul c - · refine fun n => eventually_of_forall fun x => ?_ + · refine fun n => Eventually.of_forall fun x => ?_ exact (norm_mul_le _ _).trans (mul_le_mul_of_nonneg_right (hfs_bound n x) (norm_nonneg _)) - · refine fun n => eventually_of_forall fun x => ?_ + · refine fun n => Eventually.of_forall fun x => ?_ exact (norm_mul_le _ _).trans (mul_le_mul_of_nonneg_right (hfs_bound n x) (norm_nonneg _)) · intro n simp_rw [← Pi.mul_apply] @@ -289,7 +289,7 @@ theorem condexp_stronglyMeasurable_mul_of_bound (hm : m ≤ m0) [IsFiniteMeasure ((SimpleFunc.stronglyMeasurable _).mul stronglyMeasurable_condexp) _] exact integrable_condexp.bdd_mul' ((SimpleFunc.stronglyMeasurable (fs n)).mono hm).aestronglyMeasurable - (eventually_of_forall (hfs_bound n)) + (Eventually.of_forall (hfs_bound n)) theorem condexp_stronglyMeasurable_mul_of_bound₀ (hm : m ≤ m0) [IsFiniteMeasure μ] {f g : α → ℝ} (hf : AEStronglyMeasurable' m f μ) (hg : Integrable g μ) (c : ℝ) diff --git a/Mathlib/MeasureTheory/Function/ContinuousMapDense.lean b/Mathlib/MeasureTheory/Function/ContinuousMapDense.lean index d16ec22981a70..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 @@ -366,7 +366,7 @@ namespace ContinuousMap /-- Continuous functions are dense in `MeasureTheory.Lp`, `1 ≤ p < ∞`. This theorem assumes that the domain is a compact space because otherwise `ContinuousMap.toLp` is undefined. Use -`BoundedContinuousFunction.toLp_denseRange` if the domain is not a compact space. -/ +`BoundedContinuousFunction.toLp_denseRange` if the domain is not a compact space. -/ theorem toLp_denseRange [CompactSpace α] [μ.WeaklyRegular] [IsFiniteMeasure μ] (hp : p ≠ ∞) : DenseRange (toLp p μ 𝕜 : C(α, E) →L[𝕜] Lp E p μ) := by refine (BoundedContinuousFunction.toLp_denseRange _ _ 𝕜 hp).mono ?_ diff --git a/Mathlib/MeasureTheory/Function/ConvergenceInMeasure.lean b/Mathlib/MeasureTheory/Function/ConvergenceInMeasure.lean index 40edbfe36294c..f9a7daf12fa48 100644 --- a/Mathlib/MeasureTheory/Function/ConvergenceInMeasure.lean +++ b/Mathlib/MeasureTheory/Function/ConvergenceInMeasure.lean @@ -78,7 +78,7 @@ protected theorem congr' (h_left : ∀ᶠ i in l, f i =ᵐ[μ] f' i) (h_right : protected theorem congr (h_left : ∀ i, f i =ᵐ[μ] f' i) (h_right : g =ᵐ[μ] g') (h_tendsto : TendstoInMeasure μ f l g) : TendstoInMeasure μ f' l g' := - TendstoInMeasure.congr' (eventually_of_forall h_left) h_right h_tendsto + TendstoInMeasure.congr' (Eventually.of_forall h_left) h_right h_tendsto theorem congr_left (h : ∀ i, f i =ᵐ[μ] f' i) (h_tendsto : TendstoInMeasure μ f l g) : TendstoInMeasure μ f' l g := @@ -191,8 +191,8 @@ theorem TendstoInMeasure.exists_seq_tendsto_ae (hfg : TendstoInMeasure μ f atTo fun k => ExistsSeqTendstoAe.seqTendstoAeSeq_spec hfg k (ns k) le_rfl set s := Filter.atTop.limsup S with hs have hμs : μ s = 0 := by - refine measure_limsup_eq_zero (ne_of_lt <| lt_of_le_of_lt (ENNReal.tsum_le_tsum hμS_le) ?_) - simp only [ENNReal.tsum_geometric, ENNReal.one_sub_inv_two, ENNReal.two_lt_top, inv_inv] + refine measure_limsup_atTop_eq_zero (ne_top_of_le_ne_top ?_ (ENNReal.tsum_le_tsum hμS_le)) + simpa only [ENNReal.tsum_geometric, ENNReal.one_sub_inv_two, inv_inv] using ENNReal.two_ne_top have h_tendsto : ∀ x ∈ sᶜ, Tendsto (fun i => f (ns i) x) atTop (𝓝 (g x)) := by refine fun x hx => Metric.tendsto_atTop.mpr fun ε hε => ?_ rw [hs, limsup_eq_iInf_iSup_of_nat] at hx @@ -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 @@ -249,7 +250,7 @@ section TendstoInMeasureOf variable [NormedAddCommGroup E] {p : ℝ≥0∞} variable {f : ι → α → E} {g : α → E} -/-- This lemma is superceded by `MeasureTheory.tendstoInMeasure_of_tendsto_eLpNorm` where we +/-- This lemma is superseded by `MeasureTheory.tendstoInMeasure_of_tendsto_eLpNorm` where we allow `p = ∞` and only require `AEStronglyMeasurable`. -/ theorem tendstoInMeasure_of_tendsto_eLpNorm_of_stronglyMeasurable (hp_ne_zero : p ≠ 0) (hp_ne_top : p ≠ ∞) (hf : ∀ n, StronglyMeasurable (f n)) (hg : StronglyMeasurable g) @@ -278,7 +279,7 @@ theorem tendstoInMeasure_of_tendsto_eLpNorm_of_stronglyMeasurable (hp_ne_zero : alias tendstoInMeasure_of_tendsto_snorm_of_stronglyMeasurable := tendstoInMeasure_of_tendsto_eLpNorm_of_stronglyMeasurable -/-- This lemma is superceded by `MeasureTheory.tendstoInMeasure_of_tendsto_eLpNorm` where we +/-- This lemma is superseded by `MeasureTheory.tendstoInMeasure_of_tendsto_eLpNorm` where we allow `p = ∞`. -/ theorem tendstoInMeasure_of_tendsto_eLpNorm_of_ne_top (hp_ne_zero : p ≠ 0) (hp_ne_top : p ≠ ∞) (hf : ∀ n, AEStronglyMeasurable (f n) μ) (hg : AEStronglyMeasurable g μ) {l : Filter ι} @@ -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 402e64e727ca0..932a6fefb1d33 100644 --- a/Mathlib/MeasureTheory/Function/Egorov.lean +++ b/Mathlib/MeasureTheory/Function/Egorov.lean @@ -81,7 +81,8 @@ theorem measure_notConvergentSeq_tendsto_zero [SemilatticeSup ι] [Countable ι] rw [this] exact tendsto_const_nhds rw [← measure_inter_notConvergentSeq_eq_zero hfg n, Set.inter_iInter] - refine tendsto_measure_iInter (fun n => hsm.inter <| notConvergentSeq_measurableSet hf hg) + refine tendsto_measure_iInter + (fun n ↦ (hsm.inter <| notConvergentSeq_measurableSet hf hg).nullMeasurableSet) (fun k l hkl => Set.inter_subset_inter_right _ <| notConvergentSeq_antitone hkl) ⟨h.some, ne_top_of_le_ne_top hs (measure_mono Set.inter_subset_left)⟩ diff --git a/Mathlib/MeasureTheory/Function/EssSup.lean b/Mathlib/MeasureTheory/Function/EssSup.lean index ceac0322c5019..08d14b549d3b7 100644 --- a/Mathlib/MeasureTheory/Function/EssSup.lean +++ b/Mathlib/MeasureTheory/Function/EssSup.lean @@ -4,7 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. 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 @@ -27,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. -/ @@ -67,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 @@ -171,9 +206,17 @@ 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_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_eq_iInf] + +@[simp] lemma essSup_count [MeasurableSingletonClass α] (f : α → β) : essSup f .count = ⨆ i, f i := + essSup_eq_iSup (by simp) _ + +@[simp] lemma essInf_count [MeasurableSingletonClass α] (f : α → β) : essInf f .count = ⨅ i, f i := + essInf_eq_iInf (by simp) _ section TopologicalSpace diff --git a/Mathlib/MeasureTheory/Function/Intersectivity.lean b/Mathlib/MeasureTheory/Function/Intersectivity.lean index a8aa6fa0f1d78..c571061c05018 100644 --- a/Mathlib/MeasureTheory/Function/Intersectivity.lean +++ b/Mathlib/MeasureTheory/Function/Intersectivity.lean @@ -61,53 +61,52 @@ 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] - refine (ENNReal.div_le_iff_le_mul (Or.inl $ Nat.cast_ne_zero.2 n.succ_ne_zero) $ + refine (ENNReal.div_le_iff_le_mul (Or.inl <| Nat.cast_ne_zero.2 n.succ_ne_zero) <| Or.inr one_ne_zero).2 ?_ rw [mul_comm, ← nsmul_eq_mul, ← Finset.card_range n.succ] exact Finset.sum_le_card_nsmul _ _ _ fun _ _ ↦ indicator_le (fun _ _ ↦ le_rfl) _ -- By assumption, `f n` has integral at least `r`. have hrf n : r ≤ ∫⁻ a, f n a ∂μ := by simp_rw [hfapp] - rw [lintegral_const_mul _ (Finset.measurable_sum _ fun _ _ ↦ measurable_one.indicator $ hs _), + rw [lintegral_const_mul _ (Finset.measurable_sum _ fun _ _ ↦ measurable_one.indicator <| hs _), lintegral_finset_sum _ fun _ _ ↦ measurable_one.indicator (hs _)] simp only [lintegral_indicator_one (hs _)] rw [← ENNReal.div_eq_inv_mul, ENNReal.le_div_iff_mul_le (by simp) (by simp), ← nsmul_eq_mul'] simpa using Finset.card_nsmul_le_sum (Finset.range (n + 1)) _ _ fun _ _ ↦ hr _ -- Collect some basic fact - have hμ : μ ≠ 0 := by rintro rfl; exact hr₀ $ le_bot_iff.1 $ hr 0 + have hμ : μ ≠ 0 := by rintro rfl; exact hr₀ <| le_bot_iff.1 <| hr 0 have : ∫⁻ x, limsup (f · x) atTop ∂μ ≤ μ univ := by rw [← lintegral_one] - exact lintegral_mono fun a ↦ limsup_le_of_le ⟨0, fun R _ ↦ bot_le⟩ $ - eventually_of_forall fun n ↦ hf₁ _ _ + exact lintegral_mono fun a ↦ limsup_le_of_le ⟨0, fun R _ ↦ bot_le⟩ <| + Eventually.of_forall fun n ↦ hf₁ _ _ -- By the first moment method, there exists some `x ∉ N` such that `limsup f n x` is at least `r`. obtain ⟨x, hxN, hx⟩ := exists_not_mem_null_laverage_le hμ (ne_top_of_le_ne_top (measure_ne_top μ univ) this) hN₀ replace hx : r / μ univ ≤ limsup (f · x) atTop := calc _ ≤ limsup (⨍⁻ x, f · x ∂μ) atTop := le_limsup_of_le ⟨1, eventually_map.2 ?_⟩ fun b hb ↦ ?_ - _ ≤ ⨍⁻ x, limsup (f · x) atTop ∂μ := limsup_lintegral_le 1 hf (ae_of_all _ $ hf₁ ·) (by simp) + _ ≤ ⨍⁻ x, limsup (f · x) atTop ∂μ := limsup_lintegral_le 1 hf (ae_of_all _ <| hf₁ ·) (by simp) _ ≤ limsup (f · x) atTop := hx -- This exactly means that the `s n` containing `x` have all their finite intersection non-null. · refine ⟨{n | x ∈ s n}, fun hxs ↦ ?_, fun u hux hu ↦ ?_⟩ -- This next block proves that a set of strictly positive natural density is infinite, mixed -- with the fact that `{n | x ∈ s n}` has strictly positive natural density. -- TODO: Separate it out to a lemma once we have a natural density API. - · refine ENNReal.div_ne_zero.2 ⟨hr₀, measure_ne_top _ _⟩ $ eq_bot_mono hx $ Tendsto.limsup_eq $ - tendsto_of_tendsto_of_tendsto_of_le_of_le tendsto_const_nhds + · refine ENNReal.div_ne_zero.2 ⟨hr₀, measure_ne_top _ _⟩ <| eq_bot_mono hx <| + Tendsto.limsup_eq <| tendsto_of_tendsto_of_tendsto_of_le_of_le tendsto_const_nhds (h := fun n ↦ (n.succ : ℝ≥0∞)⁻¹ * hxs.toFinset.card) ?_ bot_le fun n ↦ mul_le_mul_left' ?_ _ - · simpa using ENNReal.Tendsto.mul_const (ENNReal.tendsto_inv_nat_nhds_zero.comp $ - tendsto_add_atTop_nat 1) (.inr $ ENNReal.natCast_ne_top _) + · simpa using ENNReal.Tendsto.mul_const (ENNReal.tendsto_inv_nat_nhds_zero.comp <| + tendsto_add_atTop_nat 1) (.inr <| ENNReal.natCast_ne_top _) · classical simpa only [Finset.sum_apply, indicator_apply, Pi.one_apply, Finset.sum_boole, Nat.cast_le] using Finset.card_le_card fun m hm ↦ hxs.mem_toFinset.2 (Finset.mem_filter.1 hm).2 · simp_rw [← hu.mem_toFinset] - exact hN₁ _ ⟨x, mem_iInter₂.2 fun n hn ↦ hux $ hu.mem_toFinset.1 hn, hxN⟩ - · refine eventually_of_forall fun n ↦ ?_ + exact hN₁ _ ⟨x, mem_iInter₂.2 fun n hn ↦ hux <| hu.mem_toFinset.1 hn, hxN⟩ + · refine Eventually.of_forall fun n ↦ ?_ obtain rfl | _ := eq_zero_or_neZero μ · simp · rw [← laverage_const μ 1] @@ -121,9 +120,9 @@ measure at least `r` has an infinite subset whose finite intersections all have lemma bergelson [Infinite ι] {s : ι → Set α} (hs : ∀ i, MeasurableSet (s i)) (hr₀ : r ≠ 0) (hr : ∀ i, r ≤ μ (s i)) : ∃ t : Set ι, t.Infinite ∧ ∀ ⦃u⦄, u ⊆ t → u.Finite → 0 < μ (⋂ i ∈ u, s i) := by - obtain ⟨t, ht, h⟩ := bergelson' (fun n ↦ hs $ Infinite.natEmbedding _ n) hr₀ (fun n ↦ hr _) - refine ⟨_, ht.image $ (Infinite.natEmbedding _).injective.injOn, fun u hut hu ↦ - (h (preimage_subset_of_surjOn (Infinite.natEmbedding _).injective hut) $ hu.preimage - (Embedding.injective _).injOn).trans_le $ measure_mono $ subset_iInter₂ fun i hi ↦ ?_⟩ + obtain ⟨t, ht, h⟩ := bergelson' (fun n ↦ hs <| Infinite.natEmbedding _ n) hr₀ (fun n ↦ hr _) + refine ⟨_, ht.image <| (Infinite.natEmbedding _).injective.injOn, fun u hut hu ↦ + (h (preimage_subset_of_surjOn (Infinite.natEmbedding _).injective hut) <| hu.preimage + (Embedding.injective _).injOn).trans_le <| measure_mono <| subset_iInter₂ fun i hi ↦ ?_⟩ obtain ⟨n, -, rfl⟩ := hut hi exact iInter₂_subset n hi diff --git a/Mathlib/MeasureTheory/Function/Jacobian.lean b/Mathlib/MeasureTheory/Function/Jacobian.lean index 71aec0c9f8971..ce6116b747cb5 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 @@ -183,7 +183,7 @@ theorem exists_closed_cover_approximatesLinearOn_of_hasFDerivWithinAt [SecondCou have L : Tendsto (fun k => f (a k)) atTop (𝓝 (f x)) := by apply (hf' x xs).continuousWithinAt.tendsto.comp apply tendsto_nhdsWithin_of_tendsto_nhds_of_eventually_within _ a_lim - exact eventually_of_forall fun k => (aM k).1 + exact Eventually.of_forall fun k => (aM k).1 apply Tendsto.sub (tendsto_const_nhds.sub L) exact ((f' z).continuous.tendsto _).comp (tendsto_const_nhds.sub a_lim) have L2 : Tendsto (fun k : ℕ => (r (f' z) : ℝ) * ‖y - a k‖) atTop (𝓝 (r (f' z) * ‖y - x‖)) := @@ -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 _ _)) @@ -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, @@ -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 d9a16a74df256..9994ae4d6e8b1 100644 --- a/Mathlib/MeasureTheory/Function/L1Space.lean +++ b/Mathlib/MeasureTheory/Function/L1Space.lean @@ -191,7 +191,7 @@ theorem hasFiniteIntegral_add_measure {f : α → β} : theorem HasFiniteIntegral.smul_measure {f : α → β} (h : HasFiniteIntegral f μ) {c : ℝ≥0∞} (hc : c ≠ ∞) : HasFiniteIntegral f (c • μ) := by simp only [HasFiniteIntegral, lintegral_smul_measure] at * - exact mul_lt_top hc h.ne + exact mul_lt_top hc.lt_top h @[simp] theorem hasFiniteIntegral_zero_measure {m : MeasurableSpace α} (f : α → β) : @@ -222,7 +222,7 @@ theorem HasFiniteIntegral.norm {f : α → β} (hfi : HasFiniteIntegral f μ) : theorem hasFiniteIntegral_norm_iff (f : α → β) : HasFiniteIntegral (fun a => ‖f a‖) μ ↔ HasFiniteIntegral f μ := - hasFiniteIntegral_congr' <| eventually_of_forall fun x => norm_norm (f x) + hasFiniteIntegral_congr' <| Eventually.of_forall fun x => norm_norm (f x) theorem hasFiniteIntegral_toReal_of_lintegral_ne_top {f : α → ℝ≥0∞} (hf : (∫⁻ x, f x ∂μ) ≠ ∞) : HasFiniteIntegral (fun x => (f x).toReal) μ := by @@ -336,11 +336,11 @@ section PosPart theorem HasFiniteIntegral.max_zero {f : α → ℝ} (hf : HasFiniteIntegral f μ) : HasFiniteIntegral (fun a => max (f a) 0) μ := - hf.mono <| eventually_of_forall fun x => by simp [abs_le, le_abs_self] + hf.mono <| Eventually.of_forall fun x => by simp [abs_le, le_abs_self] theorem HasFiniteIntegral.min_zero {f : α → ℝ} (hf : HasFiniteIntegral f μ) : HasFiniteIntegral (fun a => min (f a) 0) μ := - hf.mono <| eventually_of_forall fun x => by simpa [abs_le] using neg_abs_le _ + hf.mono <| Eventually.of_forall fun x => by simpa [abs_le] using neg_abs_le _ end PosPart @@ -360,7 +360,7 @@ theorem HasFiniteIntegral.smul [NormedAddCommGroup 𝕜] [SMulZeroClass 𝕜 β] exact mod_cast (nnnorm_smul_le c (f i)) _ < ∞ := by rw [lintegral_const_mul'] - exacts [mul_lt_top coe_ne_top hfi.ne, coe_ne_top] + exacts [mul_lt_top coe_lt_top hfi, coe_ne_top] theorem hasFiniteIntegral_smul_iff [NormedRing 𝕜] [MulActionWithZero 𝕜 β] [BoundedSMul 𝕜 β] {c : 𝕜} (hc : IsUnit c) (f : α → β) : HasFiniteIntegral (c • f) μ ↔ HasFiniteIntegral f μ := by @@ -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 @@ -693,7 +697,7 @@ theorem Integrable.bdd_mul {F : Type*} [NormedDivisionRing F] {f g : α → F} ( refine lt_of_le_of_lt (lintegral_mono_nnreal this) ?_ simp only [ENNReal.coe_mul] rw [lintegral_const_mul' _ _ ENNReal.coe_ne_top] - exact ENNReal.mul_lt_top ENNReal.coe_ne_top (ne_of_lt hint.2) + exact ENNReal.mul_lt_top ENNReal.coe_lt_top hint.2 /-- **Hölder's inequality for integrable functions**: the scalar multiplication of an integrable vector-valued function by a scalar function with finite essential supremum is integrable. -/ @@ -708,7 +712,7 @@ theorem Integrable.essSup_smul {𝕜 : Type*} [NormedField 𝕜] [NormedSpace calc eLpNorm (fun x : α => g x • f x) 1 μ ≤ _ := by simpa using MeasureTheory.eLpNorm_smul_le_mul_eLpNorm hf.1 g_aestronglyMeasurable h - _ < ∞ := ENNReal.mul_lt_top hg' hf.2.ne + _ < ∞ := ENNReal.mul_lt_top hg'.lt_top hf.2 /-- Hölder's inequality for integrable functions: the scalar multiplication of an integrable scalar-valued function by a vector-value function with finite essential supremum is integrable. -/ @@ -724,7 +728,7 @@ theorem Integrable.smul_essSup {𝕜 : Type*} [NormedRing 𝕜] [Module 𝕜 β] calc eLpNorm (fun x : α => f x • g x) 1 μ ≤ _ := by simpa using MeasureTheory.eLpNorm_smul_le_mul_eLpNorm g_aestronglyMeasurable hf.1 h - _ < ∞ := ENNReal.mul_lt_top hf.2.ne hg' + _ < ∞ := ENNReal.mul_lt_top hf.2 hg'.lt_top theorem integrable_norm_iff {f : α → β} (hf : AEStronglyMeasurable f μ) : Integrable (fun a => ‖f a‖) μ ↔ Integrable f μ := by @@ -745,7 +749,7 @@ theorem Integrable.prod_mk {f : α → β} {g : α → γ} (hf : Integrable f μ Integrable (fun x => (f x, g x)) μ := ⟨hf.aestronglyMeasurable.prod_mk hg.aestronglyMeasurable, (hf.norm.add' hg.norm).mono <| - eventually_of_forall fun x => + Eventually.of_forall fun x => calc max ‖f x‖ ‖g x‖ ≤ ‖f x‖ + ‖g x‖ := max_le_add_of_nonneg (norm_nonneg _) (norm_nonneg _) _ ≤ ‖‖f x‖ + ‖g x‖‖ := le_abs_self _⟩ @@ -763,10 +767,10 @@ theorem Integrable.measure_norm_ge_lt_top {f : α → β} (hf : Integrable f μ) refine (meas_ge_le_mul_pow_eLpNorm μ one_ne_zero ENNReal.one_ne_top hf.1 ?_).trans_lt ?_ · simpa only [Ne, ENNReal.ofReal_eq_zero, not_le] using hε apply ENNReal.mul_lt_top - · simpa only [ENNReal.one_toReal, ENNReal.rpow_one, Ne, ENNReal.inv_eq_top, - ENNReal.ofReal_eq_zero, not_le] using hε - simpa only [ENNReal.one_toReal, ENNReal.rpow_one] using - (memℒp_one_iff_integrable.2 hf).eLpNorm_ne_top + · simpa only [ENNReal.one_toReal, ENNReal.rpow_one, ENNReal.inv_lt_top, ENNReal.ofReal_pos] + using hε + · simpa only [ENNReal.one_toReal, ENNReal.rpow_one] using + (memℒp_one_iff_integrable.2 hf).eLpNorm_lt_top /-- A non-quantitative version of Markov inequality for integrable functions: the measure of points where `‖f x‖ > ε` is finite for all positive `ε`. -/ @@ -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) μ := @@ -983,7 +986,7 @@ noncomputable def withDensitySMulLI {f : α → ℝ≥0} (f_meas : Measurable f) one_ne_zero, ENNReal.one_ne_top, ENNReal.one_toReal, if_false, eLpNorm', ENNReal.rpow_one, _root_.div_one, Lp.norm_def] rw [lintegral_withDensity_eq_lintegral_mul_non_measurable _ f_meas.coe_nnreal_ennreal - (Filter.eventually_of_forall fun x => ENNReal.coe_lt_top)] + (Filter.Eventually.of_forall fun x => ENNReal.coe_lt_top)] congr 1 apply lintegral_congr_ae filter_upwards [(memℒ1_smul_of_L1_withDensity f_meas u).coeFn_toLp] with x hx @@ -1182,7 +1185,8 @@ theorem integrable_of_forall_fin_meas_le [SigmaFinite μ] (C : ℝ≥0∞) (hC : (hf_meas : AEStronglyMeasurable f μ) (hf : ∀ s : Set α, MeasurableSet[m] s → μ s ≠ ∞ → (∫⁻ x in s, ‖f x‖₊ ∂μ) ≤ C) : Integrable f μ := - @integrable_of_forall_fin_meas_le' _ m _ m _ _ _ (by rwa [@trim_eq_self _ m]) C hC _ hf_meas hf + have : SigmaFinite (μ.trim le_rfl) := by rwa [@trim_eq_self _ m] + integrable_of_forall_fin_meas_le' le_rfl C hC hf_meas hf end SigmaFinite @@ -1419,7 +1423,7 @@ theorem ContinuousLinearMap.integrable_comp {φ : α → H} (L : H →L[𝕜] E) Integrable (fun a : α => L (φ a)) μ := ((Integrable.norm φ_int).const_mul ‖L‖).mono' (L.continuous.comp_aestronglyMeasurable φ_int.aestronglyMeasurable) - (eventually_of_forall fun a => L.le_opNorm (φ a)) + (Eventually.of_forall fun a => L.le_opNorm (φ a)) @[simp] theorem ContinuousLinearEquiv.integrable_comp_iff {φ : α → H} (L : H ≃L[𝕜] E) : diff --git a/Mathlib/MeasureTheory/Function/L2Space.lean b/Mathlib/MeasureTheory/Function/L2Space.lean index 1c7c073e397b5..e89d919547be1 100644 --- a/Mathlib/MeasureTheory/Function/L2Space.lean +++ b/Mathlib/MeasureTheory/Function/L2Space.lean @@ -62,11 +62,11 @@ local notation "⟪" x ", " y "⟫" => @inner 𝕜 E _ x y theorem Memℒp.const_inner (c : E) {f : α → E} (hf : Memℒp f p μ) : Memℒp (fun a => ⟪c, f a⟫) p μ := hf.of_le_mul (AEStronglyMeasurable.inner aestronglyMeasurable_const hf.1) - (eventually_of_forall fun _ => norm_inner_le_norm _ _) + (Eventually.of_forall fun _ => norm_inner_le_norm _ _) theorem Memℒp.inner_const {f : α → E} (hf : Memℒp f p μ) (c : E) : Memℒp (fun a => ⟪f a, c⟫) p μ := - hf.of_le_mul (AEStronglyMeasurable.inner hf.1 aestronglyMeasurable_const) - (eventually_of_forall fun x => by rw [mul_comm]; exact norm_inner_le_norm _ _) + hf.of_le_mul (c := ‖c‖) (AEStronglyMeasurable.inner hf.1 aestronglyMeasurable_const) + (Eventually.of_forall fun x => by rw [mul_comm]; exact norm_inner_le_norm _ _) variable {f : α → E} @@ -148,7 +148,7 @@ theorem integral_inner_eq_sq_eLpNorm (f : α →₂[μ] E) : norm_cast rw [integral_eq_lintegral_of_nonneg_ae] rotate_left - · exact Filter.eventually_of_forall fun x => sq_nonneg _ + · exact Filter.Eventually.of_forall fun x => sq_nonneg _ · exact ((Lp.aestronglyMeasurable f).norm.aemeasurable.pow_const _).aestronglyMeasurable congr ext1 x diff --git a/Mathlib/MeasureTheory/Function/LocallyIntegrable.lean b/Mathlib/MeasureTheory/Function/LocallyIntegrable.lean index 2acd297ad0fd6..0d8110dc76977 100644 --- a/Mathlib/MeasureTheory/Function/LocallyIntegrable.lean +++ b/Mathlib/MeasureTheory/Function/LocallyIntegrable.lean @@ -127,24 +127,16 @@ 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`. -/ -theorem locallyIntegrableOn_iff [LocallyCompactSpace X] [T2Space X] (hs : IsClosed s ∨ IsOpen s) : - LocallyIntegrableOn f s μ ↔ ∀ (k : Set X), k ⊆ s → (IsCompact k → IntegrableOn f k μ) := by - -- The correct condition is that `s` be *locally closed*, i.e. for every `x ∈ s` there is some - -- `U ∈ 𝓝 x` such that `U ∩ s` is closed. But mathlib doesn't have locally closed sets yet. - refine ⟨fun hf k hk => hf.integrableOn_compact_subset hk, fun hf x hx => ?_⟩ - cases hs with - | inl hs => - exact - let ⟨K, hK, h2K⟩ := exists_compact_mem_nhds x - ⟨_, inter_mem_nhdsWithin s h2K, - hf _ inter_subset_left - (hK.of_isClosed_subset (hs.inter hK.isClosed) inter_subset_right)⟩ - | inr hs => - obtain ⟨K, hK, h2K, h3K⟩ := exists_compact_subset hs hx - refine ⟨K, ?_, hf K h3K hK⟩ - simpa only [IsOpen.nhdsWithin_eq hs hx, interior_eq_nhds'] using h2K +/-- 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 + 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⟩ + rw [nhdsWithin_inter_of_mem (nhdsWithin_le_nhds <| hU.mem_nhds hx.1)] + refine ⟨Z ∩ K, inter_mem_nhdsWithin _ (mem_interior_iff_mem_nhds.1 hxK), ?_⟩ + exact hf (Z ∩ K) (fun y hy ↦ ⟨hKU hy.2, hy.1⟩) (.inter_left hK hZ) protected theorem LocallyIntegrableOn.add (hf : LocallyIntegrableOn f s μ) (hg : LocallyIntegrableOn g s μ) : @@ -506,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)) @@ -619,28 +611,30 @@ namespace LocallyIntegrableOn theorem continuousOn_mul [LocallyCompactSpace X] [T2Space X] [NormedRing R] [SecondCountableTopologyEither X R] {f g : X → R} {s : Set X} (hf : LocallyIntegrableOn f s μ) - (hg : ContinuousOn g s) (hs : IsOpen s) : LocallyIntegrableOn (fun x => g x * f x) s μ := by - rw [MeasureTheory.locallyIntegrableOn_iff (Or.inr hs)] at hf ⊢ + (hg : ContinuousOn g s) (hs : IsLocallyClosed s) : + LocallyIntegrableOn (fun x => g x * f x) s μ := by + rw [MeasureTheory.locallyIntegrableOn_iff hs] at hf ⊢ exact fun k hk_sub hk_c => (hf k hk_sub hk_c).continuousOn_mul (hg.mono hk_sub) hk_c theorem mul_continuousOn [LocallyCompactSpace X] [T2Space X] [NormedRing R] [SecondCountableTopologyEither X R] {f g : X → R} {s : Set X} (hf : LocallyIntegrableOn f s μ) - (hg : ContinuousOn g s) (hs : IsOpen s) : LocallyIntegrableOn (fun x => f x * g x) s μ := by - rw [MeasureTheory.locallyIntegrableOn_iff (Or.inr hs)] at hf ⊢ + (hg : ContinuousOn g s) (hs : IsLocallyClosed s) : + LocallyIntegrableOn (fun x => f x * g x) s μ := by + rw [MeasureTheory.locallyIntegrableOn_iff hs] at hf ⊢ exact fun k hk_sub hk_c => (hf k hk_sub hk_c).mul_continuousOn (hg.mono hk_sub) hk_c theorem continuousOn_smul [LocallyCompactSpace X] [T2Space X] {𝕜 : Type*} [NormedField 𝕜] [SecondCountableTopologyEither X 𝕜] [NormedSpace 𝕜 E] {f : X → E} {g : X → 𝕜} {s : Set X} - (hs : IsOpen s) (hf : LocallyIntegrableOn f s μ) (hg : ContinuousOn g s) : + (hs : IsLocallyClosed s) (hf : LocallyIntegrableOn f s μ) (hg : ContinuousOn g s) : LocallyIntegrableOn (fun x => g x • f x) s μ := by - rw [MeasureTheory.locallyIntegrableOn_iff (Or.inr hs)] at hf ⊢ + rw [MeasureTheory.locallyIntegrableOn_iff hs] at hf ⊢ exact fun k hk_sub hk_c => (hf k hk_sub hk_c).continuousOn_smul (hg.mono hk_sub) hk_c theorem smul_continuousOn [LocallyCompactSpace X] [T2Space X] {𝕜 : Type*} [NormedField 𝕜] [SecondCountableTopologyEither X E] [NormedSpace 𝕜 E] {f : X → 𝕜} {g : X → E} {s : Set X} - (hs : IsOpen s) (hf : LocallyIntegrableOn f s μ) (hg : ContinuousOn g s) : + (hs : IsLocallyClosed s) (hf : LocallyIntegrableOn f s μ) (hg : ContinuousOn g s) : LocallyIntegrableOn (fun x => f x • g x) s μ := by - rw [MeasureTheory.locallyIntegrableOn_iff (Or.inr hs)] at hf ⊢ + rw [MeasureTheory.locallyIntegrableOn_iff hs] at hf ⊢ exact fun k hk_sub hk_c => (hf k hk_sub hk_c).smul_continuousOn (hg.mono hk_sub) hk_c end LocallyIntegrableOn diff --git a/Mathlib/MeasureTheory/Function/LpOrder.lean b/Mathlib/MeasureTheory/Function/LpOrder.lean index 51148571e059f..86290745da5ec 100644 --- a/Mathlib/MeasureTheory/Function/LpOrder.lean +++ b/Mathlib/MeasureTheory/Function/LpOrder.lean @@ -59,12 +59,12 @@ instance instOrderedAddCommGroup : OrderedAddCommGroup (Lp E p μ) := theorem _root_.MeasureTheory.Memℒp.sup {f g : α → E} (hf : Memℒp f p μ) (hg : Memℒp g p μ) : Memℒp (f ⊔ g) p μ := Memℒp.mono' (hf.norm.add hg.norm) (hf.1.sup hg.1) - (Filter.eventually_of_forall fun x => norm_sup_le_add (f x) (g x)) + (Filter.Eventually.of_forall fun x => norm_sup_le_add (f x) (g x)) theorem _root_.MeasureTheory.Memℒp.inf {f g : α → E} (hf : Memℒp f p μ) (hg : Memℒp g p μ) : Memℒp (f ⊓ g) p μ := Memℒp.mono' (hf.norm.add hg.norm) (hf.1.inf hg.1) - (Filter.eventually_of_forall fun x => norm_inf_le_add (f x) (g x)) + (Filter.Eventually.of_forall fun x => norm_inf_le_add (f x) (g x)) theorem _root_.MeasureTheory.Memℒp.abs {f : α → E} (hf : Memℒp f p μ) : Memℒp |f| p μ := hf.sup hf.neg diff --git a/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean b/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean index 7cdd71d229171..fdf5f19ca96be 100644 --- a/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean +++ b/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean @@ -75,7 +75,8 @@ def eLpNormEssSup {_ : MeasurableSpace α} (f : α → F) (μ : Measure α) := /-- `ℒp` seminorm, equal to `0` for `p=0`, to `(∫ ‖f a‖^p ∂μ) ^ (1/p)` for `0 < p < ∞` and to `essSup ‖f‖ μ` for `p = ∞`. -/ -def eLpNorm {_ : MeasurableSpace α} (f : α → F) (p : ℝ≥0∞) (μ : Measure α) : ℝ≥0∞ := +def eLpNorm {_ : MeasurableSpace α} + (f : α → F) (p : ℝ≥0∞) (μ : Measure α := by volume_tac) : ℝ≥0∞ := if p = 0 then 0 else if p = ∞ then eLpNormEssSup f μ else eLpNorm' f (ENNReal.toReal p) μ @[deprecated (since := "2024-07-26")] noncomputable alias snorm := eLpNorm @@ -403,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")] @@ -427,8 +428,8 @@ theorem memℒp_const (c : E) [IsFiniteMeasure μ] : Memℒp (fun _ : α => c) p by_cases hμ : μ = 0 · simp [hμ] rw [eLpNorm_const c h0 hμ] - refine ENNReal.mul_lt_top ENNReal.coe_ne_top ?_ - refine (ENNReal.rpow_lt_top_of_nonneg ?_ (measure_ne_top μ Set.univ)).ne + refine ENNReal.mul_lt_top ENNReal.coe_lt_top ?_ + refine ENNReal.rpow_lt_top_of_nonneg ?_ (measure_ne_top μ Set.univ) simp theorem memℒp_top_const (c : E) : Memℒp (fun _ : α => c) ∞ μ := by @@ -526,21 +527,21 @@ alias snorm_mono_ae_real := eLpNorm_mono_ae_real theorem eLpNorm_mono_nnnorm {f : α → F} {g : α → G} (h : ∀ x, ‖f x‖₊ ≤ ‖g x‖₊) : eLpNorm f p μ ≤ eLpNorm g p μ := - eLpNorm_mono_nnnorm_ae (eventually_of_forall fun x => h x) + eLpNorm_mono_nnnorm_ae (Eventually.of_forall fun x => h x) @[deprecated (since := "2024-07-27")] alias snorm_mono_nnnorm := eLpNorm_mono_nnnorm theorem eLpNorm_mono {f : α → F} {g : α → G} (h : ∀ x, ‖f x‖ ≤ ‖g x‖) : eLpNorm f p μ ≤ eLpNorm g p μ := - eLpNorm_mono_ae (eventually_of_forall fun x => h x) + eLpNorm_mono_ae (Eventually.of_forall fun x => h x) @[deprecated (since := "2024-07-27")] alias snorm_mono := eLpNorm_mono theorem eLpNorm_mono_real {f : α → F} {g : α → ℝ} (h : ∀ x, ‖f x‖ ≤ g x) : eLpNorm f p μ ≤ eLpNorm g p μ := - eLpNorm_mono_ae_real (eventually_of_forall fun x => h x) + eLpNorm_mono_ae_real (Eventually.of_forall fun x => h x) @[deprecated (since := "2024-07-27")] alias snorm_mono_real := eLpNorm_mono_real @@ -627,7 +628,7 @@ alias snorm'_norm := eLpNorm'_norm @[simp] theorem eLpNorm_norm (f : α → F) : eLpNorm (fun x => ‖f x‖) p μ = eLpNorm f p μ := - eLpNorm_congr_norm_ae <| eventually_of_forall fun _ => norm_norm _ + eLpNorm_congr_norm_ae <| Eventually.of_forall fun _ => norm_norm _ @[deprecated (since := "2024-07-27")] alias snorm_norm := eLpNorm_norm @@ -660,7 +661,7 @@ theorem eLpNorm_norm_rpow (f : α → F) (hq_pos : 0 < q) : congr ext1 x conv_rhs => rw [← nnnorm_norm] - rw [ENNReal.coe_rpow_of_nonneg _ hq_pos.le, ENNReal.coe_inj] + rw [← ENNReal.coe_rpow_of_nonneg _ hq_pos.le, ENNReal.coe_inj] ext push_cast rw [Real.norm_rpow_of_nonneg (norm_nonneg _)] @@ -793,10 +794,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 @@ -849,7 +856,7 @@ theorem Memℒp.of_measure_le_smul {μ' : Measure α} (c : ℝ≥0∞) (hc : c by_cases hc0 : c = 0 · simp [hc0] rw [eLpNorm_smul_measure_of_ne_zero hc0, smul_eq_mul] - refine ENNReal.mul_lt_top ?_ hf.2.ne + refine ENNReal.mul_lt_top (Ne.lt_top ?_) hf.2 simp [hc, hc0] theorem Memℒp.smul_measure {f : α → E} {c : ℝ≥0∞} (hf : Memℒp f p μ) (hc : c ≠ ∞) : @@ -878,6 +885,12 @@ theorem eLpNorm_le_add_measure_left (f : α → F) (μ ν : Measure α) {p : ℝ @[deprecated (since := "2024-07-27")] alias snorm_le_add_measure_left := eLpNorm_le_add_measure_left +lemma eLpNormEssSup_eq_iSup (hμ : ∀ a, μ {a} ≠ 0) (f : α → E) : eLpNormEssSup f μ = ⨆ a, ↑‖f a‖₊ := + essSup_eq_iSup hμ _ + +@[simp] lemma eLpNormEssSup_count [MeasurableSingletonClass α] (f : α → E) : + eLpNormEssSup f .count = ⨆ a, ↑‖f a‖₊ := essSup_count _ + theorem Memℒp.left_of_add_measure {f : α → E} (h : Memℒp f p (μ + ν)) : Memℒp f p μ := h.mono_measure <| Measure.le_add_right <| le_refl _ @@ -885,7 +898,7 @@ theorem Memℒp.right_of_add_measure {f : α → E} (h : Memℒp f p (μ + ν)) h.mono_measure <| Measure.le_add_left <| le_refl _ theorem Memℒp.norm {f : α → E} (h : Memℒp f p μ) : Memℒp (fun x => ‖f x‖) p μ := - h.of_le h.aestronglyMeasurable.norm (eventually_of_forall fun x => by simp) + h.of_le h.aestronglyMeasurable.norm (Eventually.of_forall fun x => by simp) theorem memℒp_norm_iff {f : α → E} (hf : AEStronglyMeasurable f μ) : Memℒp (fun x => ‖f x‖) p μ ↔ Memℒp f p μ := @@ -957,6 +970,10 @@ theorem eLpNorm_eq_zero_iff {f : α → E} (hf : AEStronglyMeasurable f μ) (h0 @[deprecated (since := "2024-07-27")] alias snorm_eq_zero_iff := eLpNorm_eq_zero_iff +theorem eLpNorm_eq_zero_of_ae_zero {f : α → E} (hf : f =ᵐ[μ] 0) : eLpNorm f p μ = 0 := by + rw [← eLpNorm_zero (p := p) (μ := μ) (α := α) (F := E)] + exact eLpNorm_congr_ae hf + theorem ae_le_eLpNormEssSup {f : α → F} : ∀ᵐ y ∂μ, ‖f y‖₊ ≤ eLpNormEssSup f μ := ae_le_essSup @@ -1083,7 +1100,7 @@ theorem eLpNorm'_le_nnreal_smul_eLpNorm'_of_ae_le_mul {f : α → F} {g : α → rw [← ENNReal.rpow_le_rpow_iff hp, ENNReal.smul_def, smul_eq_mul, ENNReal.mul_rpow_of_nonneg _ _ hp.le] simp_rw [← ENNReal.rpow_mul, one_div, inv_mul_cancel₀ hp.ne.symm, ENNReal.rpow_one, - ENNReal.coe_rpow_of_nonneg _ hp.le, ← lintegral_const_mul' _ _ ENNReal.coe_ne_top, ← + ← ENNReal.coe_rpow_of_nonneg _ hp.le, ← lintegral_const_mul' _ _ ENNReal.coe_ne_top, ← ENNReal.coe_mul] apply lintegral_mono_ae simp_rw [ENNReal.coe_le_coe, ← NNReal.mul_rpow, NNReal.rpow_le_rpow_iff hp] @@ -1154,13 +1171,13 @@ theorem Memℒp.of_nnnorm_le_mul {f : α → E} {g : α → F} {c : ℝ≥0} (hg (hf : AEStronglyMeasurable f μ) (hfg : ∀ᵐ x ∂μ, ‖f x‖₊ ≤ c * ‖g x‖₊) : Memℒp f p μ := ⟨hf, (eLpNorm_le_nnreal_smul_eLpNorm_of_ae_le_mul hfg p).trans_lt <| - ENNReal.mul_lt_top ENNReal.coe_ne_top hg.eLpNorm_ne_top⟩ + ENNReal.mul_lt_top ENNReal.coe_lt_top hg.eLpNorm_lt_top⟩ theorem Memℒp.of_le_mul {f : α → E} {g : α → F} {c : ℝ} (hg : Memℒp g p μ) (hf : AEStronglyMeasurable f μ) (hfg : ∀ᵐ x ∂μ, ‖f x‖ ≤ c * ‖g x‖) : Memℒp f p μ := ⟨hf, (eLpNorm_le_mul_eLpNorm_of_ae_le_mul hfg p).trans_lt <| - ENNReal.mul_lt_top ENNReal.ofReal_ne_top hg.eLpNorm_ne_top⟩ + ENNReal.mul_lt_top ENNReal.ofReal_lt_top hg.eLpNorm_lt_top⟩ end Monotonicity @@ -1176,7 +1193,7 @@ variable [BoundedSMul 𝕜 E] [BoundedSMul 𝕜 F] theorem eLpNorm'_const_smul_le (c : 𝕜) (f : α → F) (hq_pos : 0 < q) : eLpNorm' (c • f) q μ ≤ ‖c‖₊ • eLpNorm' f q μ := - eLpNorm'_le_nnreal_smul_eLpNorm'_of_ae_le_mul (eventually_of_forall fun _ => nnnorm_smul_le _ _) + eLpNorm'_le_nnreal_smul_eLpNorm'_of_ae_le_mul (Eventually.of_forall fun _ => nnnorm_smul_le _ _) hq_pos @[deprecated (since := "2024-07-27")] @@ -1185,21 +1202,21 @@ alias snorm'_const_smul_le := eLpNorm'_const_smul_le theorem eLpNormEssSup_const_smul_le (c : 𝕜) (f : α → F) : eLpNormEssSup (c • f) μ ≤ ‖c‖₊ • eLpNormEssSup f μ := eLpNormEssSup_le_nnreal_smul_eLpNormEssSup_of_ae_le_mul - (eventually_of_forall fun _ => by simp [nnnorm_smul_le]) + (Eventually.of_forall fun _ => by simp [nnnorm_smul_le]) @[deprecated (since := "2024-07-27")] alias snormEssSup_const_smul_le := eLpNormEssSup_const_smul_le theorem eLpNorm_const_smul_le (c : 𝕜) (f : α → F) : eLpNorm (c • f) p μ ≤ ‖c‖₊ • eLpNorm f p μ := eLpNorm_le_nnreal_smul_eLpNorm_of_ae_le_mul - (eventually_of_forall fun _ => by simp [nnnorm_smul_le]) _ + (Eventually.of_forall fun _ => by simp [nnnorm_smul_le]) _ @[deprecated (since := "2024-07-27")] alias snorm_const_smul_le := eLpNorm_const_smul_le theorem Memℒp.const_smul {f : α → E} (hf : Memℒp f p μ) (c : 𝕜) : Memℒp (c • f) p μ := ⟨AEStronglyMeasurable.const_smul hf.1 c, - (eLpNorm_const_smul_le c f).trans_lt (ENNReal.mul_lt_top ENNReal.coe_ne_top hf.2.ne)⟩ + (eLpNorm_const_smul_le c f).trans_lt (ENNReal.mul_lt_top ENNReal.coe_lt_top hf.2)⟩ theorem Memℒp.const_mul {R} [NormedRing R] {f : α → R} (hf : Memℒp f p μ) (c : R) : Memℒp (fun x => c * f x) p μ := @@ -1280,7 +1297,7 @@ theorem Memℒp.re (hf : Memℒp f p μ) : Memℒp (fun x => RCLike.re (f x)) p intro x rw [one_mul] exact RCLike.norm_re_le_norm (f x) - refine hf.of_le_mul ?_ (eventually_of_forall this) + refine hf.of_le_mul ?_ (Eventually.of_forall this) exact RCLike.continuous_re.comp_aestronglyMeasurable hf.1 theorem Memℒp.im (hf : Memℒp f p μ) : Memℒp (fun x => RCLike.im (f x)) p μ := by @@ -1288,7 +1305,7 @@ theorem Memℒp.im (hf : Memℒp f p μ) : Memℒp (fun x => RCLike.im (f x)) p intro x rw [one_mul] exact RCLike.norm_im_le_norm (f x) - refine hf.of_le_mul ?_ (eventually_of_forall this) + refine hf.of_le_mul ?_ (Eventually.of_forall this) exact RCLike.continuous_im.comp_aestronglyMeasurable hf.1 end RCLike @@ -1334,7 +1351,7 @@ theorem ae_bdd_liminf_atTop_of_eLpNorm_bdd {p : ℝ≥0∞} (hp : p ≠ 0) {f : (lt_of_le_of_lt (hbdd n) <| ENNReal.lt_add_right ENNReal.coe_ne_top one_ne_zero) rw [← ae_all_iff] at this filter_upwards [this] with x hx using lt_of_le_of_lt - (liminf_le_of_frequently_le' <| frequently_of_forall fun n => (hx n).le) + (liminf_le_of_frequently_le' <| Frequently.of_forall fun n => (hx n).le) (ENNReal.add_lt_top.2 ⟨ENNReal.coe_lt_top, ENNReal.one_lt_top⟩) filter_upwards [ae_bdd_liminf_atTop_rpow_of_eLpNorm_bdd hfmeas hbdd] with x hx have hppos : 0 < p.toReal := ENNReal.toReal_pos hp hp' @@ -1363,7 +1380,7 @@ theorem _root_.Continuous.memℒp_top_of_hasCompactSupport {f : X → E} (hf : Continuous f) (h'f : HasCompactSupport f) (μ : Measure X) : Memℒp f ⊤ μ := by borelize E rcases hf.bounded_above_of_compact_support h'f with ⟨C, hC⟩ - apply memℒp_top_of_bound ?_ C (Filter.eventually_of_forall hC) + apply memℒp_top_of_bound ?_ C (Filter.Eventually.of_forall hC) exact (hf.stronglyMeasurable_of_hasCompactSupport h'f).aestronglyMeasurable section UnifTight diff --git a/Mathlib/MeasureTheory/Function/LpSeminorm/ChebyshevMarkov.lean b/Mathlib/MeasureTheory/Function/LpSeminorm/ChebyshevMarkov.lean index df00ceb205d0a..6248e4a2c5925 100644 --- a/Mathlib/MeasureTheory/Function/LpSeminorm/ChebyshevMarkov.lean +++ b/Mathlib/MeasureTheory/Function/LpSeminorm/ChebyshevMarkov.lean @@ -11,7 +11,7 @@ import Mathlib.MeasureTheory.Function.LpSeminorm.Basic In this file we formulate several versions of the Chebyshev-Markov inequality in terms of the `MeasureTheory.eLpNorm` seminorm. -/ -open scoped ENNReal +open scoped NNReal ENNReal namespace MeasureTheory @@ -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 ε @@ -67,4 +67,18 @@ theorem meas_ge_le_mul_pow_eLpNorm (hp_ne_zero : p ≠ 0) (hp_ne_top : p ≠ ∞ @[deprecated (since := "2024-07-27")] alias meas_ge_le_mul_pow_snorm := meas_ge_le_mul_pow_eLpNorm +theorem Memℒp.meas_ge_lt_top' {μ : Measure α} (hℒp : Memℒp f p μ) (hp_ne_zero : p ≠ 0) + (hp_ne_top : p ≠ ∞) {ε : ℝ≥0∞} (hε : ε ≠ 0) : + μ { x | ε ≤ ‖f x‖₊ } < ∞ := by + apply (meas_ge_le_mul_pow_eLpNorm μ hp_ne_zero hp_ne_top hℒp.aestronglyMeasurable hε).trans_lt + (ENNReal.mul_lt_top ?_ ?_) + · simp [hε, lt_top_iff_ne_top] + · simp [hℒp.eLpNorm_lt_top.ne, lt_top_iff_ne_top] + +theorem Memℒp.meas_ge_lt_top {μ : Measure α} (hℒp : Memℒp f p μ) (hp_ne_zero : p ≠ 0) + (hp_ne_top : p ≠ ∞) {ε : ℝ≥0} (hε : ε ≠ 0) : + μ { x | ε ≤ ‖f x‖₊ } < ∞ := by + simp_rw [← ENNReal.coe_le_coe] + apply hℒp.meas_ge_lt_top' hp_ne_zero hp_ne_top (by simp [hε]) + end MeasureTheory diff --git a/Mathlib/MeasureTheory/Function/LpSeminorm/CompareExp.lean b/Mathlib/MeasureTheory/Function/LpSeminorm/CompareExp.lean index 74680c8ebc928..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 := @@ -148,8 +148,8 @@ theorem Memℒp.memℒp_of_exponent_le {p q : ℝ≥0∞} [IsFiniteMeasure μ] { · rw [eLpNorm_eq_eLpNorm' hp0 hp_top] rw [hq_top, eLpNorm_exponent_top] at hfq_lt_top refine lt_of_le_of_lt (eLpNorm'_le_eLpNormEssSup_mul_rpow_measure_univ hp_pos) ?_ - refine ENNReal.mul_lt_top hfq_lt_top.ne ?_ - exact (ENNReal.rpow_lt_top_of_nonneg (by simp [hp_pos.le]) (measure_ne_top μ Set.univ)).ne + refine ENNReal.mul_lt_top hfq_lt_top ?_ + exact ENNReal.rpow_lt_top_of_nonneg (by simp [hp_pos.le]) (measure_ne_top μ Set.univ) have hq0 : q ≠ 0 := by by_contra hq_eq_zero have hp_eq_zero : p = 0 := le_antisymm (by rwa [hq_eq_zero] at hpq) (zero_le _) @@ -306,7 +306,7 @@ variable {𝕜 α E F : Type*} {m : MeasurableSpace α} {μ : Measure α} [Norme theorem eLpNorm_smul_le_eLpNorm_top_mul_eLpNorm (p : ℝ≥0∞) (hf : AEStronglyMeasurable f μ) (φ : α → 𝕜) : eLpNorm (φ • f) p μ ≤ eLpNorm φ ∞ μ * eLpNorm f p μ := (eLpNorm_le_eLpNorm_top_mul_eLpNorm p φ hf (· • ·) - (eventually_of_forall fun _ => nnnorm_smul_le _ _) : _) + (Eventually.of_forall fun _ => nnnorm_smul_le _ _) : _) @[deprecated (since := "2024-07-27")] alias snorm_smul_le_snorm_top_mul_snorm := eLpNorm_smul_le_eLpNorm_top_mul_eLpNorm @@ -314,7 +314,7 @@ alias snorm_smul_le_snorm_top_mul_snorm := eLpNorm_smul_le_eLpNorm_top_mul_eLpNo theorem eLpNorm_smul_le_eLpNorm_mul_eLpNorm_top (p : ℝ≥0∞) (f : α → E) {φ : α → 𝕜} (hφ : AEStronglyMeasurable φ μ) : eLpNorm (φ • f) p μ ≤ eLpNorm φ p μ * eLpNorm f ∞ μ := (eLpNorm_le_eLpNorm_mul_eLpNorm_top p hφ f (· • ·) - (eventually_of_forall fun _ => nnnorm_smul_le _ _) : _) + (Eventually.of_forall fun _ => nnnorm_smul_le _ _) : _) @[deprecated (since := "2024-07-27")] alias snorm_smul_le_snorm_mul_snorm_top := eLpNorm_smul_le_eLpNorm_mul_eLpNorm_top @@ -322,7 +322,7 @@ alias snorm_smul_le_snorm_mul_snorm_top := eLpNorm_smul_le_eLpNorm_mul_eLpNorm_t theorem eLpNorm'_smul_le_mul_eLpNorm' {p q r : ℝ} {f : α → E} (hf : AEStronglyMeasurable f μ) {φ : α → 𝕜} (hφ : AEStronglyMeasurable φ μ) (hp0_lt : 0 < p) (hpq : p < q) (hpqr : 1 / p = 1 / q + 1 / r) : eLpNorm' (φ • f) p μ ≤ eLpNorm' φ q μ * eLpNorm' f r μ := - eLpNorm'_le_eLpNorm'_mul_eLpNorm' hφ hf (· • ·) (eventually_of_forall fun _ => nnnorm_smul_le _ _) + eLpNorm'_le_eLpNorm'_mul_eLpNorm' hφ hf (· • ·) (Eventually.of_forall fun _ => nnnorm_smul_le _ _) hp0_lt hpq hpqr @[deprecated (since := "2024-07-27")] @@ -333,7 +333,7 @@ theorem eLpNorm_smul_le_mul_eLpNorm {p q r : ℝ≥0∞} {f : α → E} (hf : AE {φ : α → 𝕜} (hφ : AEStronglyMeasurable φ μ) (hpqr : 1 / p = 1 / q + 1 / r) : eLpNorm (φ • f) p μ ≤ eLpNorm φ q μ * eLpNorm f r μ := (eLpNorm_le_eLpNorm_mul_eLpNorm_of_nnnorm hφ hf (· • ·) - (eventually_of_forall fun _ => nnnorm_smul_le _ _) hpqr : + (Eventually.of_forall fun _ => nnnorm_smul_le _ _) hpqr : _) @[deprecated (since := "2024-07-27")] @@ -343,7 +343,7 @@ theorem Memℒp.smul {p q r : ℝ≥0∞} {f : α → E} {φ : α → 𝕜} (hf (hpqr : 1 / p = 1 / q + 1 / r) : Memℒp (φ • f) p μ := ⟨hφ.1.smul hf.1, (eLpNorm_smul_le_mul_eLpNorm hf.1 hφ.1 hpqr).trans_lt - (ENNReal.mul_lt_top hφ.eLpNorm_ne_top hf.eLpNorm_ne_top)⟩ + (ENNReal.mul_lt_top hφ.eLpNorm_lt_top hf.eLpNorm_lt_top)⟩ theorem Memℒp.smul_of_top_right {p : ℝ≥0∞} {f : α → E} {φ : α → 𝕜} (hf : Memℒp f p μ) (hφ : Memℒp φ ∞ μ) : Memℒp (φ • f) p μ := by diff --git a/Mathlib/MeasureTheory/Function/LpSeminorm/TriangleInequality.lean b/Mathlib/MeasureTheory/Function/LpSeminorm/TriangleInequality.lean index 36a7d7423dd74..cc56d954aa492 100644 --- a/Mathlib/MeasureTheory/Function/LpSeminorm/TriangleInequality.lean +++ b/Mathlib/MeasureTheory/Function/LpSeminorm/TriangleInequality.lean @@ -48,7 +48,7 @@ alias snorm'_add_le_of_le_one := eLpNorm'_add_le_of_le_one theorem eLpNormEssSup_add_le {f g : α → E} : eLpNormEssSup (f + g) μ ≤ eLpNormEssSup f μ + eLpNormEssSup g μ := by - refine le_trans (essSup_mono_ae (eventually_of_forall fun x => ?_)) (ENNReal.essSup_add_le _ _) + refine le_trans (essSup_mono_ae (Eventually.of_forall fun x => ?_)) (ENNReal.essSup_add_le _ _) simp_rw [Pi.add_apply, ← ENNReal.coe_add, ENNReal.coe_le_coe] exact nnnorm_add_le _ _ @@ -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 μ) @@ -154,8 +153,8 @@ theorem eLpNorm_add_lt_top {f g : α → E} (hf : Memℒp f p μ) (hg : Memℒp eLpNorm (f + g) p μ ≤ LpAddConst p * (eLpNorm f p μ + eLpNorm g p μ) := eLpNorm_add_le' hf.aestronglyMeasurable hg.aestronglyMeasurable p _ < ∞ := by - apply ENNReal.mul_lt_top (LpAddConst_lt_top p).ne - exact (ENNReal.add_lt_top.2 ⟨hf.2, hg.2⟩).ne + apply ENNReal.mul_lt_top (LpAddConst_lt_top p) + exact ENNReal.add_lt_top.2 ⟨hf.2, hg.2⟩ @[deprecated (since := "2024-07-27")] alias snorm_add_lt_top := eLpNorm_add_lt_top diff --git a/Mathlib/MeasureTheory/Function/LpSpace.lean b/Mathlib/MeasureTheory/Function/LpSpace.lean index 77bda2bdf1659..22f250535cb26 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 μ) : @@ -387,7 +387,7 @@ theorem nnnorm_le_of_ae_bound [IsFiniteMeasure μ] {f : Lp E p μ} {C : ℝ≥0} · simp [hμ, nnnorm_def, Real.zero_rpow hp] rw [← ENNReal.coe_le_coe, nnnorm_def, ENNReal.coe_toNNReal (eLpNorm_ne_top _)] refine (eLpNorm_le_of_ae_nnnorm_bound hfC).trans_eq ?_ - rw [← coe_measureUnivNNReal μ, ENNReal.coe_rpow_of_ne_zero (measureUnivNNReal_pos hμ).ne', + rw [← coe_measureUnivNNReal μ, ← ENNReal.coe_rpow_of_ne_zero (measureUnivNNReal_pos hμ).ne', ENNReal.coe_mul, mul_comm, ENNReal.smul_def, smul_eq_mul] theorem norm_le_of_ae_bound [IsFiniteMeasure μ] {f : Lp E p μ} {C : ℝ} (hC : 0 ≤ C) @@ -502,7 +502,7 @@ variable {c : E} {f : α → E} {hf : AEStronglyMeasurable f μ} {s : Set α} theorem eLpNormEssSup_indicator_le (s : Set α) (f : α → G) : eLpNormEssSup (s.indicator f) μ ≤ eLpNormEssSup f μ := by - refine essSup_mono_ae (eventually_of_forall fun x => ?_) + refine essSup_mono_ae (Eventually.of_forall fun x => ?_) rw [ENNReal.coe_le_coe, nnnorm_indicator_eq_indicator_nnnorm] exact Set.indicator_le_self s _ x @@ -532,7 +532,7 @@ theorem eLpNormEssSup_indicator_const_eq (s : Set α) (c : G) (hμs : μ s ≠ 0 alias snormEssSup_indicator_const_eq := eLpNormEssSup_indicator_const_eq theorem eLpNorm_indicator_le (f : α → E) : eLpNorm (s.indicator f) p μ ≤ eLpNorm f p μ := by - refine eLpNorm_mono_ae (eventually_of_forall fun x => ?_) + refine eLpNorm_mono_ae (Eventually.of_forall fun x => ?_) suffices ‖s.indicator f x‖₊ ≤ ‖f x‖₊ by exact NNReal.coe_mono this rw [nnnorm_indicator_eq_indicator_nnnorm] exact s.indicator_le_self _ x @@ -677,7 +677,7 @@ theorem exists_eLpNorm_indicator_le (hp : p ≠ ∞) (c : E) {ε : ℝ≥0∞} ( NNReal.nhds_zero_basis.eventually_iff.mp (eventually_le_of_tendsto_lt hε' this) obtain ⟨η, hη, hηδ⟩ := exists_between hδ refine ⟨η, hη, ?_⟩ - rw [ENNReal.coe_rpow_of_nonneg _ hp₀', ← ENNReal.coe_mul] + rw [← ENNReal.coe_rpow_of_nonneg _ hp₀', ← ENNReal.coe_mul] exact hδε' hηδ refine ⟨η, hη_pos, fun s hs => ?_⟩ refine (eLpNorm_indicator_const_le _ _).trans (le_trans ?_ hη_le) @@ -802,7 +802,7 @@ theorem nnnorm_indicatorConstLp_le : theorem ennnorm_indicatorConstLp_le : (‖indicatorConstLp p hs hμs c‖₊ : ℝ≥0∞) ≤ ‖c‖₊ * (μ s) ^ (1 / p.toReal) := by refine (ENNReal.coe_le_coe.mpr nnnorm_indicatorConstLp_le).trans_eq ?_ - simp [← ENNReal.coe_rpow_of_nonneg, ENNReal.coe_toNNReal hμs] + simp [ENNReal.coe_rpow_of_nonneg, ENNReal.coe_toNNReal hμs] theorem edist_indicatorConstLp_eq_nnnorm {t : Set α} {ht : MeasurableSet t} {hμt : μ t ≠ ∞} : edist (indicatorConstLp p hs hμs c) (indicatorConstLp p ht hμt c) = @@ -1052,7 +1052,7 @@ theorem LipschitzWith.comp_memℒp {α E F} {K} [MeasurableSpace α] {μ : Measu have : ∀ x, ‖g (f x)‖ ≤ K * ‖f x‖ := fun x ↦ by -- TODO: add `LipschitzWith.nnnorm_sub_le` and `LipschitzWith.nnnorm_le` simpa [g0] using hg.norm_sub_le (f x) 0 - hL.of_le_mul (hg.continuous.comp_aestronglyMeasurable hL.1) (eventually_of_forall this) + hL.of_le_mul (hg.continuous.comp_aestronglyMeasurable hL.1) (Eventually.of_forall this) theorem MeasureTheory.Memℒp.of_comp_antilipschitzWith {α E F} {K'} [MeasurableSpace α] {μ : Measure α} [NormedAddCommGroup E] [NormedAddCommGroup F] {f : α → E} {g : E → F} @@ -1064,8 +1064,8 @@ 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 - exact hL.of_le_mul B (Filter.eventually_of_forall A) + (hg'.isUniformEmbedding hg).embedding.aestronglyMeasurable_comp_iff.1 hL.1 + exact hL.of_le_mul B (Filter.Eventually.of_forall A) namespace LipschitzWith @@ -1300,7 +1300,6 @@ end Composition We show that `L^p` is a complete space for `1 ≤ p`. -/ - section CompleteSpace namespace MeasureTheory @@ -1317,7 +1316,7 @@ theorem eLpNorm'_lim_eq_lintegral_liminf {ι} [Nonempty ι] [LinearOrder ι] {f refine lintegral_congr_ae (h_lim.mono fun a ha => ?_) dsimp only rw [Tendsto.liminf_eq] - simp_rw [ENNReal.coe_rpow_of_nonneg _ hp_nonneg, ENNReal.tendsto_coe] + simp_rw [← ENNReal.coe_rpow_of_nonneg _ hp_nonneg, ENNReal.tendsto_coe] refine ((NNReal.continuous_rpow_const hp_nonneg).tendsto ‖f_lim a‖₊).comp ?_ exact (continuous_nnnorm.tendsto (f_lim a)).comp ha @@ -1547,7 +1546,7 @@ private theorem lintegral_rpow_tsum_coe_nnnorm_sub_le_tsum {f : ℕ → α → E (Finset.aemeasurable_sum (Finset.range (n + 1)) fun i _ => ((hf (i + 1)).sub (hf i)).ennnorm).pow_const _ - · exact liminf_le_of_frequently_le' (frequently_of_forall h) + · exact liminf_le_of_frequently_le' (Frequently.of_forall h) private theorem tsum_nnnorm_sub_ae_lt_top {f : ℕ → α → E} (hf : ∀ n, AEStronglyMeasurable (f n) μ) {p : ℝ} (hp1 : 1 ≤ p) {B : ℕ → ℝ≥0∞} (hB : ∑' i, B i ≠ ∞) @@ -1877,7 +1876,7 @@ theorem toLp_inj {f g : C(α, E)} [μ.IsOpenPosMeasure] [NormedField 𝕜] [Norm variable {μ} /-- If a sum of continuous functions `g n` is convergent, and the same sum converges in `Lᵖ` to `h`, -then in fact `g n` converges uniformly to `h`. -/ +then in fact `g n` converges uniformly to `h`. -/ theorem hasSum_of_hasSum_Lp {β : Type*} [μ.IsOpenPosMeasure] [NormedField 𝕜] [NormedSpace 𝕜 E] {g : β → C(α, E)} {f : C(α, E)} (hg : Summable g) (hg2 : HasSum (toLp (E := E) p μ 𝕜 ∘ g) (toLp (E := E) p μ 𝕜 f)) : HasSum g f := by @@ -1929,3 +1928,5 @@ theorem meas_ge_le_mul_pow_norm (f : Lp E p μ) (hp_ne_zero : p ≠ 0) (hp_ne_to end Lp end MeasureTheory + +set_option linter.style.longFile 2100 diff --git a/Mathlib/MeasureTheory/Function/LpSpace/ContinuousCompMeasurePreserving.lean b/Mathlib/MeasureTheory/Function/LpSpace/ContinuousCompMeasurePreserving.lean index 09380e0b12e50..ecb76ae835229 100644 --- a/Mathlib/MeasureTheory/Function/LpSpace/ContinuousCompMeasurePreserving.lean +++ b/Mathlib/MeasureTheory/Function/LpSpace/ContinuousCompMeasurePreserving.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.MeasureTheory.Function.SimpleFuncDenseLp -import Mathlib.MeasureTheory.Measure.Regular +import Mathlib.MeasureTheory.Measure.ContinuousPreimage /-! # Continuity of `MeasureTheory.Lp.compMeasurePreserving` @@ -30,70 +30,6 @@ variable {α X Y : Type*} {μ : Measure X} {ν : Measure Y} [μ.InnerRegularCompactLTTop] [IsLocallyFiniteMeasure ν] namespace MeasureTheory - -/-- Let `X` and `Y` be R₁ topological spaces -with Borel σ-algebras and measures `μ` and `ν`, respectively. -Suppose that `μ` is inner regular for finite measure sets with respect to compact sets -and `ν` is a locally finite measure. -Let `f : α → C(X, Y)` be a family of continuous maps -that converges to a continuous map `g : C(X, Y)` in the compact-open topology along a filter `l`. -Suppose that `g` is a measure preserving map -and `f a` is a measure preserving map eventually along `l`. -Then for any finite measure measurable set `s`, -the preimages `f a ⁻¹' s` tend to the preimage `g ⁻¹' s` in measure. -More precisely, the measure of the symmetric difference of these two sets tends to zero. -/ -theorem tendsto_measure_symmDiff_preimage_nhds_zero - {l : Filter α} {f : α → C(X, Y)} {g : C(X, Y)} {s : Set Y} (hfg : Tendsto f l (𝓝 g)) - (hf : ∀ᶠ a in l, MeasurePreserving (f a) μ ν) (hg : MeasurePreserving g μ ν) - (hs : NullMeasurableSet s ν) (hνs : ν s ≠ ∞) : - Tendsto (fun a ↦ μ ((f a ⁻¹' s) ∆ (g ⁻¹' s))) l (𝓝 0) := by - have : ν.InnerRegularCompactLTTop := by - rw [← hg.map_eq] - exact .map_of_continuous (map_continuous _) - rw [ENNReal.tendsto_nhds_zero] - intro ε hε - -- Without loss of generality, `s` is an open set. - wlog hso : IsOpen s generalizing s ε - · have H : 0 < ε / 3 := ENNReal.div_pos hε.ne' ENNReal.coe_ne_top - -- Indeed, we can choose an open set `U` such that `ν (U ∆ s) < ε / 3`, - -- apply the lemma to `U`, then use the triangle inequality for `μ (_ ∆ _)`. - rcases hs.exists_isOpen_symmDiff_lt hνs H.ne' with ⟨U, hUo, hU, hUs⟩ - have hmU : NullMeasurableSet U ν := hUo.measurableSet.nullMeasurableSet - replace hUs := hUs.le - filter_upwards [hf, this hmU hU.ne _ H hUo] with a hfa ha - calc - μ ((f a ⁻¹' s) ∆ (g ⁻¹' s)) - ≤ μ ((f a ⁻¹' s) ∆ (f a ⁻¹' U)) + μ ((f a ⁻¹' U) ∆ (g ⁻¹' U)) - + μ ((g ⁻¹' U) ∆ (g ⁻¹' s)) := by - refine (measure_symmDiff_le _ (g ⁻¹' U) _).trans ?_ - gcongr - apply measure_symmDiff_le - _ ≤ ε / 3 + ε / 3 + ε / 3 := by - gcongr - · rwa [← preimage_symmDiff, hfa.measure_preimage (hs.symmDiff hmU), symmDiff_comm] - · rwa [← preimage_symmDiff, hg.measure_preimage (hmU.symmDiff hs)] - _ = ε := by simp - -- Take a compact closed subset `K ⊆ g ⁻¹' s` of almost full measure, - -- `μ (g ⁻¹' s \ K) < ε / 2`. - have hνs' : μ (g ⁻¹' s) ≠ ∞ := by rwa [hg.measure_preimage hs] - obtain ⟨K, hKg, hKco, hKcl, hKμ⟩ : - ∃ K, MapsTo g K s ∧ IsCompact K ∧ IsClosed K ∧ μ (g ⁻¹' s \ K) < ε / 2 := - (hg.measurable hso.measurableSet).exists_isCompact_isClosed_diff_lt hνs' <| by simp [hε.ne'] - have hKm : MeasurableSet K := hKcl.measurableSet - -- Take `a` such that `f a` is measure preserving and maps `K` to `s`. - -- This is possible, because `K` is a compact set and `s` is an open set. - filter_upwards [hf, ContinuousMap.tendsto_nhds_compactOpen.mp hfg K hKco s hso hKg] with a hfa ha - -- Then each of the sets `g ⁻¹' s ∆ K = g ⁻¹' s \ K` and `f a ⁻¹' s ∆ K = f a ⁻¹' s \ K` - -- have measure at most `ε / 2`, thus `f a ⁻¹' s ∆ g ⁻¹' s` has measure at most `ε`. - rw [← ENNReal.add_halves ε] - refine (measure_symmDiff_le _ K _).trans ?_ - rw [symmDiff_of_ge ha.subset_preimage, symmDiff_of_le hKg.subset_preimage] - gcongr - have hK' : μ K ≠ ∞ := ne_top_of_le_ne_top hνs' <| measure_mono hKg.subset_preimage - rw [measure_diff_le_iff_le_add hKm ha.subset_preimage hK', hfa.measure_preimage hs, - ← hg.measure_preimage hs, ← measure_diff_le_iff_le_add hKm hKg.subset_preimage hK'] - exact hKμ.le - namespace Lp variable (μ ν) @@ -122,7 +58,7 @@ theorem compMeasurePreserving_continuous (hp : p ≠ ∞) : refine continuous_indicatorConstLp_set hp fun f ↦ ?_ apply tendsto_measure_symmDiff_preimage_nhds_zero continuousAt_subtype_val _ f.2 hs.nullMeasurableSet hνs.ne - exact eventually_of_forall Subtype.property + exact .of_forall Subtype.property end Lp diff --git a/Mathlib/MeasureTheory/Function/SimpleFunc.lean b/Mathlib/MeasureTheory/Function/SimpleFunc.lean index 76cad3cf36a87..ea3760f408df5 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 @@ -353,6 +353,10 @@ theorem pair_preimage_singleton (f : α →ₛ β) (g : α →ₛ γ) (b : β) ( rw [← singleton_prod_singleton] exact pair_preimage _ _ _ _ +@[simp] theorem map_fst_pair (f : α →ₛ β) (g : α →ₛ γ) : (f.pair g).map Prod.fst = f := rfl +@[simp] theorem map_snd_pair (f : α →ₛ β) (g : α →ₛ γ) : (f.pair g).map Prod.snd = g := rfl + +@[simp] theorem bind_const (f : α →ₛ β) : f.bind (const α) = f := by ext; simp @[to_additive] @@ -767,9 +771,9 @@ def eapproxDiff (f : α → ℝ≥0∞) : ℕ → α →ₛ ℝ≥0 theorem sum_eapproxDiff (f : α → ℝ≥0∞) (n : ℕ) (a : α) : (∑ k ∈ Finset.range (n + 1), (eapproxDiff f k a : ℝ≥0∞)) = eapprox f n a := by induction' n with n IH - · simp only [Nat.zero_eq, Nat.zero_add, Finset.sum_singleton, Finset.range_one] + · 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 @@ -812,7 +816,7 @@ theorem lintegral_eq_of_subset' (f : α →ₛ ℝ≥0∞) {s : Finset ℝ≥0 f.lintegral_eq_of_subset fun x hfx _ => hs <| Finset.mem_sdiff.2 ⟨f.mem_range_self x, mt Finset.mem_singleton.1 hfx⟩ -/-- Calculate the integral of `(g ∘ f)`, where `g : β → ℝ≥0∞` and `f : α →ₛ β`. -/ +/-- Calculate the integral of `(g ∘ f)`, where `g : β → ℝ≥0∞` and `f : α →ₛ β`. -/ theorem map_lintegral (g : β → ℝ≥0∞) (f : α →ₛ β) : (f.map g).lintegral μ = ∑ x ∈ f.range, g x * μ (f ⁻¹' {x}) := by simp only [lintegral, range_map] @@ -924,27 +928,30 @@ theorem restrict_const_lintegral (c : ℝ≥0∞) {s : Set α} (hs : MeasurableS ((const α c).restrict s).lintegral μ = c * μ s := by rw [restrict_lintegral_eq_lintegral_restrict _ hs, const_lintegral_restrict] -theorem le_sup_lintegral (f g : α →ₛ ℝ≥0∞) : f.lintegral μ ⊔ g.lintegral μ ≤ (f ⊔ g).lintegral μ := +@[gcongr] +theorem lintegral_mono_fun {f g : α →ₛ ℝ≥0∞} (h : f ≤ g) : f.lintegral μ ≤ g.lintegral μ := by + refine Monotone.of_left_le_map_sup (f := (lintegral · μ)) (fun f g ↦ ?_) h calc - f.lintegral μ ⊔ g.lintegral μ = - ((pair f g).map Prod.fst).lintegral μ ⊔ ((pair f g).map Prod.snd).lintegral μ := - rfl - _ ≤ ∑ x ∈ (pair f g).range, (x.1 ⊔ x.2) * μ (pair f g ⁻¹' {x}) := by - rw [map_lintegral, map_lintegral] - refine sup_le ?_ ?_ <;> refine Finset.sum_le_sum fun a _ => mul_le_mul_right' ?_ _ - · exact le_sup_left - · exact le_sup_right - _ = (f ⊔ g).lintegral μ := by rw [sup_eq_map₂, map_lintegral] + f.lintegral μ = ((pair f g).map Prod.fst).lintegral μ := by rw [map_fst_pair] + _ ≤ ((pair f g).map fun p ↦ p.1 ⊔ p.2).lintegral μ := by + simp only [map_lintegral] + gcongr + exact le_sup_left + +theorem le_sup_lintegral (f g : α →ₛ ℝ≥0∞) : f.lintegral μ ⊔ g.lintegral μ ≤ (f ⊔ g).lintegral μ := + Monotone.le_map_sup (fun _ _ ↦ lintegral_mono_fun) f g + +@[gcongr] +theorem lintegral_mono_measure {f : α →ₛ ℝ≥0∞} (h : μ ≤ ν) : f.lintegral μ ≤ f.lintegral ν := by + simp only [lintegral] + gcongr + apply h /-- `SimpleFunc.lintegral` is monotone both in function and in measure. -/ -@[mono] +@[mono, gcongr] theorem lintegral_mono {f g : α →ₛ ℝ≥0∞} (hfg : f ≤ g) (hμν : μ ≤ ν) : f.lintegral μ ≤ g.lintegral ν := - calc - f.lintegral μ ≤ f.lintegral μ ⊔ g.lintegral μ := le_sup_left - _ ≤ (f ⊔ g).lintegral μ := le_sup_lintegral _ _ - _ = g.lintegral μ := by rw [sup_of_le_right hfg] - _ ≤ g.lintegral ν := Finset.sum_le_sum fun y _ => ENNReal.mul_left_mono <| hμν _ + (lintegral_mono_fun hfg).trans (lintegral_mono_measure hμν) /-- `SimpleFunc.lintegral` depends only on the measures of `f ⁻¹' {y}`. -/ theorem lintegral_eq_of_measure_preimage [MeasurableSpace β] {f : α →ₛ ℝ≥0∞} {g : β →ₛ ℝ≥0∞} @@ -980,7 +987,7 @@ open Finset Function theorem support_eq [MeasurableSpace α] [Zero β] (f : α →ₛ β) : support f = ⋃ y ∈ f.range.filter fun y => 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 : α →ₛ β} @@ -1003,8 +1010,7 @@ theorem finMeasSupp_iff : f.FinMeasSupp μ ↔ ∀ y, y ≠ 0 → μ (f ⁻¹' { exact fun x hx (H : f x = 0) => hy <| H ▸ Eq.symm hx · intro H rw [finMeasSupp_iff_support, support_eq] - refine lt_of_le_of_lt (measure_biUnion_finset_le _ _) (sum_lt_top ?_) - exact fun y hy => (H y (Finset.mem_filter.1 hy).2).ne + exact measure_biUnion_lt_top (finite_toSet _) fun y hy ↦ H y (mem_filter.1 hy).2 namespace FinMeasSupp @@ -1046,14 +1052,14 @@ protected theorem mul {β} [MonoidWithZero β] {f g : α →ₛ β} (hf : f.FinM theorem lintegral_lt_top {f : α →ₛ ℝ≥0∞} (hm : f.FinMeasSupp μ) (hf : ∀ᵐ a ∂μ, f a ≠ ∞) : f.lintegral μ < ∞ := by - refine sum_lt_top fun a ha => ?_ + refine sum_lt_top.2 fun a ha => ?_ rcases eq_or_ne a ∞ with (rfl | ha) · simp only [ae_iff, Ne, Classical.not_not] at hf simp [Set.preimage, hf] · by_cases ha0 : a = 0 · subst a - rwa [zero_mul] - · exact mul_ne_top ha (finMeasSupp_iff.1 hm _ ha0).ne + simp + · exact mul_lt_top ha.lt_top (finMeasSupp_iff.1 hm _ ha0) theorem of_lintegral_ne_top {f : α →ₛ ℝ≥0∞} (h : f.lintegral μ ≠ ∞) : f.FinMeasSupp μ := by refine finMeasSupp_iff.2 fun b hb => ?_ diff --git a/Mathlib/MeasureTheory/Function/SimpleFuncDenseLp.lean b/Mathlib/MeasureTheory/Function/SimpleFuncDenseLp.lean index 26d57a24e44ae..e017f36bbf06c 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 @@ -110,7 +110,7 @@ theorem tendsto_approxOn_Lp_eLpNorm [OpensMeasurableSpace E] {f : β → E} (hf ∀ n, (fun x => (‖approxOn f hf s y₀ h₀ n x - f x‖₊ : ℝ≥0∞) ^ p.toReal) ≤ᵐ[μ] fun x => (‖f x - y₀‖₊ : ℝ≥0∞) ^ p.toReal := fun n => - eventually_of_forall fun x => + Eventually.of_forall fun x => rpow_le_rpow (coe_mono (nnnorm_approxOn_le hf h₀ x n)) toReal_nonneg -- (3) The bounding function `fun x => ‖f x - y₀‖ ^ p.toReal` has finite integral have h_fin : (∫⁻ a : β, (‖f a - y₀‖₊ : ℝ≥0∞) ^ p.toReal ∂μ) ≠ ⊤ := @@ -275,7 +275,7 @@ theorem memℒp_zero (f : α →ₛ E) (μ : Measure α) : Memℒp f 0 μ := theorem memℒp_top (f : α →ₛ E) (μ : Measure α) : Memℒp f ∞ μ := let ⟨C, hfC⟩ := f.exists_forall_norm_le - memℒp_top_of_bound f.aestronglyMeasurable C <| eventually_of_forall hfC + memℒp_top_of_bound f.aestronglyMeasurable C <| Eventually.of_forall hfC protected theorem eLpNorm'_eq {p : ℝ} (f : α →ₛ F) (μ : Measure α) : eLpNorm' f p μ = (∑ y ∈ f.range, (‖y‖₊ : ℝ≥0∞) ^ p * μ (f ⁻¹' {y})) ^ (1 / p) := by @@ -293,13 +293,13 @@ theorem measure_preimage_lt_top_of_memℒp (hp_pos : p ≠ 0) (hp_ne_top : p ≠ rw [eLpNorm_eq_eLpNorm' hp_pos hp_ne_top, f.eLpNorm'_eq, one_div, ← @ENNReal.lt_rpow_inv_iff _ _ p.toReal⁻¹ (by simp [hp_pos_real]), @ENNReal.top_rpow_of_pos p.toReal⁻¹⁻¹ (by simp [hp_pos_real]), - ENNReal.sum_lt_top_iff] at hf_eLpNorm + ENNReal.sum_lt_top] at hf_eLpNorm by_cases hyf : y ∈ f.range swap · 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⟩ @@ -322,11 +322,11 @@ theorem memℒp_of_finite_measure_preimage (p : ℝ≥0∞) {f : α →ₛ E} · rw [hp_top]; exact memℒp_top f μ refine ⟨f.aestronglyMeasurable, ?_⟩ rw [eLpNorm_eq_eLpNorm' hp0 hp_top, f.eLpNorm'_eq] - refine ENNReal.rpow_lt_top_of_nonneg (by simp) (ENNReal.sum_lt_top_iff.mpr fun y _ => ?_).ne + refine ENNReal.rpow_lt_top_of_nonneg (by simp) (ENNReal.sum_lt_top.mpr fun y _ => ?_).ne by_cases hy0 : y = 0 · simp [hy0, ENNReal.toReal_pos hp0 hp_top] - · refine ENNReal.mul_lt_top ?_ (hf y hy0).ne - exact (ENNReal.rpow_lt_top_of_nonneg ENNReal.toReal_nonneg ENNReal.coe_ne_top).ne + · refine ENNReal.mul_lt_top ?_ (hf y hy0) + exact ENNReal.rpow_lt_top_of_nonneg ENNReal.toReal_nonneg ENNReal.coe_ne_top theorem memℒp_iff {f : α →ₛ E} (hp_pos : p ≠ 0) (hp_ne_top : p ≠ ∞) : Memℒp f p μ ↔ ∀ y, y ≠ 0 → μ (f ⁻¹' {y}) < ∞ := @@ -357,7 +357,7 @@ theorem integrable_pair {f : α →ₛ E} {g : α →ₛ F} : theorem memℒp_of_isFiniteMeasure (f : α →ₛ E) (p : ℝ≥0∞) (μ : Measure α) [IsFiniteMeasure μ] : Memℒp f p μ := let ⟨C, hfC⟩ := f.exists_forall_norm_le - Memℒp.of_bound f.aestronglyMeasurable C <| eventually_of_forall hfC + Memℒp.of_bound f.aestronglyMeasurable C <| Eventually.of_forall hfC theorem integrable_of_isFiniteMeasure [IsFiniteMeasure μ] (f : α →ₛ E) : Integrable f μ := memℒp_one_iff_integrable.mp (f.memℒp_of_isFiniteMeasure 1 μ) @@ -369,7 +369,7 @@ theorem measure_preimage_lt_top_of_integrable (f : α →ₛ E) (hf : Integrable theorem measure_support_lt_top [Zero β] (f : α →ₛ β) (hf : ∀ y, y ≠ 0 → μ (f ⁻¹' {y}) < ∞) : μ (support f) < ∞ := by rw [support_eq] - refine (measure_biUnion_finset_le _ _).trans_lt (ENNReal.sum_lt_top_iff.mpr fun y hy => ?_) + refine (measure_biUnion_finset_le _ _).trans_lt (ENNReal.sum_lt_top.mpr fun y hy => ?_) rw [Finset.mem_filter] at hy exact hf y hy.2 @@ -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 @@ -773,7 +781,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 e5e60b719ee57..b9644215bcca2 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 := @@ -278,13 +278,13 @@ theorem finStronglyMeasurable_of_set_sigmaFinite [TopologicalSpace β] [Zero β] refine Set.indicator_of_not_mem ?_ _ simp [hxt] refine ⟨fs, ?_, fun x => ?_⟩ - · simp_rw [SimpleFunc.support_eq] - refine fun n => (measure_biUnion_finset_le _ _).trans_lt ?_ - refine ENNReal.sum_lt_top_iff.mpr fun y hy => ?_ + · simp_rw [SimpleFunc.support_eq, ← Finset.mem_coe] + classical + refine fun n => measure_biUnion_lt_top {y ∈ (fs n).range | y ≠ 0}.finite_toSet fun y hy => ?_ rw [SimpleFunc.restrict_preimage_singleton _ ((hS_meas n).inter ht)] swap · letI : (y : β) → Decidable (y = 0) := fun y => Classical.propDecidable _ - rw [Finset.mem_filter] at hy + rw [Finset.mem_coe, Finset.mem_filter] at hy exact hy.2 refine (measure_mono Set.inter_subset_left).trans_lt ?_ have h_lt_top := measure_spanningSets_lt_top (μ.restrict t) n @@ -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 @@ -1107,6 +1107,9 @@ namespace AEStronglyMeasurable variable {m : MeasurableSpace α} {μ ν : Measure α} [TopologicalSpace β] [TopologicalSpace γ] {f g : α → β} +lemma of_finite [DiscreteMeasurableSpace α] [Finite α] : AEStronglyMeasurable f μ := + ⟨_, .of_finite, ae_eq_rfl⟩ + section Mk /-- A `StronglyMeasurable` function such that `f =ᵐ[μ] hf.mk f`. See lemmas @@ -1752,7 +1755,7 @@ theorem exists_set_sigmaFinite (hf : AEFinStronglyMeasurable f μ) : refine ⟨t, ht, ?_, htμ⟩ refine EventuallyEq.trans (ae_restrict_of_ae hfg) ?_ rw [EventuallyEq, ae_restrict_iff' ht.compl] - exact eventually_of_forall hgt_zero + exact Eventually.of_forall hgt_zero /-- A measurable set `t` such that `f =ᵐ[μ.restrict tᶜ] 0` and `sigma_finite (μ.restrict t)`. -/ def sigmaFiniteSet (hf : AEFinStronglyMeasurable f μ) : Set α := @@ -1877,3 +1880,5 @@ theorem stronglyMeasurable_uncurry_of_continuous_of_stronglyMeasurable {α β ι exact ((t_sf n).measurable.comp measurable_fst).subtype_mk end MeasureTheory + +set_option linter.style.longFile 2000 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 f337d65513ca3..52d0280c4dbba 100644 --- a/Mathlib/MeasureTheory/Function/UniformIntegrable.lean +++ b/Mathlib/MeasureTheory/Function/UniformIntegrable.lean @@ -213,14 +213,14 @@ 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 simp only [coe_nnnorm, ENNReal.ofReal_eq_coe_nnreal (norm_nonneg _)] rfl -/-- This lemma is superceded by `MeasureTheory.Memℒp.integral_indicator_norm_ge_nonneg_le` +/-- This lemma is superseded by `MeasureTheory.Memℒp.integral_indicator_norm_ge_nonneg_le` which does not require measurability. -/ theorem Memℒp.integral_indicator_norm_ge_nonneg_le_of_meas (hf : Memℒp f 1 μ) (hmeas : StronglyMeasurable f) {ε : ℝ} (hε : 0 < ε) : @@ -288,7 +288,7 @@ theorem Memℒp.eLpNorm_indicator_norm_ge_le (hf : Memℒp f p μ) (hmeas : Stro ENNReal.ofReal_rpow_of_pos hε] convert hM rename_i x - rw [ENNReal.coe_rpow_of_nonneg _ ENNReal.toReal_nonneg, nnnorm_indicator_eq_indicator_nnnorm, + rw [← ENNReal.coe_rpow_of_nonneg _ ENNReal.toReal_nonneg, nnnorm_indicator_eq_indicator_nnnorm, nnnorm_indicator_eq_indicator_nnnorm] have hiff : M ^ (1 / p.toReal) ≤ ‖f x‖₊ ↔ M ≤ ‖‖f x‖ ^ p.toReal‖₊ := by rw [coe_nnnorm, coe_nnnorm, Real.norm_rpow_of_nonneg (norm_nonneg _), norm_norm, @@ -393,7 +393,7 @@ theorem Memℒp.eLpNorm_indicator_le' (hp_one : 1 ≤ p) (hp_top : p ≠ ∞) (h @[deprecated (since := "2024-07-27")] alias Memℒp.snorm_indicator_le' := Memℒp.eLpNorm_indicator_le' -/-- This lemma is superceded by `MeasureTheory.Memℒp.eLpNorm_indicator_le` which does not require +/-- This lemma is superseded by `MeasureTheory.Memℒp.eLpNorm_indicator_le` which does not require 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 < ε) : @@ -641,7 +641,7 @@ theorem tendstoInMeasure_iff_tendsto_Lp_finite [IsFiniteMeasure μ] (hp : 1 ≤ (fun n => (hf n).aestronglyMeasurable) hg.aestronglyMeasurable h, unifIntegrable_of_tendsto_Lp hp hp' hf hg h⟩⟩ -/-- This lemma is superceded by `unifIntegrable_of` which do not require `C` to be positive. -/ +/-- This lemma is superseded by `unifIntegrable_of` which do not require `C` to be positive. -/ theorem unifIntegrable_of' (hp : 1 ≤ p) (hp' : p ≠ ∞) {f : ι → α → β} (hf : ∀ i, StronglyMeasurable (f i)) (h : ∀ ε : ℝ, 0 < ε → ∃ C : ℝ≥0, 0 < C ∧ @@ -790,7 +790,7 @@ theorem uniformIntegrable_const {g : α → β} (hp : 1 ≤ p) (hp_ne_top : p ⟨fun _ => hg.1, unifIntegrable_const hp hp_ne_top hg, ⟨(eLpNorm g p μ).toNNReal, fun _ => le_of_eq (ENNReal.coe_toNNReal hg.2.ne).symm⟩⟩ -/-- This lemma is superceded by `uniformIntegrable_of` which only requires +/-- This lemma is superseded by `uniformIntegrable_of` which only requires `AEStronglyMeasurable`. -/ theorem uniformIntegrable_of' [IsFiniteMeasure μ] (hp : 1 ≤ p) (hp' : p ≠ ∞) (hf : ∀ i, StronglyMeasurable (f i)) @@ -851,7 +851,7 @@ theorem uniformIntegrable_of [IsFiniteMeasure μ] (hp : 1 ≤ p) (hp' : p ≠ · rw [Set.indicator_of_not_mem hfx, Set.indicator_of_not_mem] rwa [Set.mem_setOf, hx] at hfx -/-- This lemma is superceded by `UniformIntegrable.spec` which does not require measurability. -/ +/-- This lemma is superseded by `UniformIntegrable.spec` which does not require measurability. -/ theorem UniformIntegrable.spec' (hp : p ≠ 0) (hp' : p ≠ ∞) (hf : ∀ i, StronglyMeasurable (f i)) (hfu : UniformIntegrable f p μ) {ε : ℝ} (hε : 0 < ε) : ∃ C : ℝ≥0, ∀ i, eLpNorm ({ x | C ≤ ‖f i x‖₊ }.indicator (f i)) p μ ≤ ENNReal.ofReal ε := by @@ -872,11 +872,11 @@ theorem UniformIntegrable.spec' (hp : p ≠ 0) (hp' : p ≠ ∞) (hf : ∀ i, St _ ≤ eLpNorm ({ x | C ≤ ‖f (ℐ C) x‖₊ }.indicator (f (ℐ C))) p μ := by refine le_eLpNorm_of_bddBelow hp hp' _ (measurableSet_le measurable_const (hf _).nnnorm.measurable) - (eventually_of_forall fun x hx => ?_) + (Eventually.of_forall fun x hx => ?_) rwa [nnnorm_indicator_eq_indicator_nnnorm, Set.indicator_of_mem hx] _ ≤ eLpNorm (f (ℐ C)) p μ := eLpNorm_indicator_le _ specialize this (2 * max M 1 * δ⁻¹ ^ (1 / p.toReal)) - rw [ENNReal.coe_rpow_of_nonneg _ (one_div_nonneg.2 ENNReal.toReal_nonneg), ← ENNReal.coe_smul, + rw [← ENNReal.coe_rpow_of_nonneg _ (one_div_nonneg.2 ENNReal.toReal_nonneg), ← ENNReal.coe_smul, smul_eq_mul, mul_assoc, NNReal.inv_rpow, inv_mul_cancel₀ (NNReal.rpow_pos (NNReal.coe_pos.1 hδpos)).ne.symm, mul_one, ENNReal.coe_mul, ← NNReal.inv_rpow] at this diff --git a/Mathlib/MeasureTheory/Group/Action.lean b/Mathlib/MeasureTheory/Group/Action.lean index 159a5bff0f4ff..04f432bce67b9 100644 --- a/Mathlib/MeasureTheory/Group/Action.lean +++ b/Mathlib/MeasureTheory/Group/Action.lean @@ -171,7 +171,7 @@ theorem smulInvariantMeasure_iterateMulAct section SMulHomClass universe uM uN uα uβ -variable {M : Type uM} {N : Type uN} {α : Type uα} {β : Type uβ} +variable {M : Type uM} {N : Type uN} {α : Type uα} {β : Type uβ} [MeasurableSpace M] [MeasurableSpace N] [MeasurableSpace α] [MeasurableSpace β] @[to_additive] @@ -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/AddCircle.lean b/Mathlib/MeasureTheory/Group/AddCircle.lean index 6483fa54f3cec..38e54d654f75e 100644 --- a/Mathlib/MeasureTheory/Group/AddCircle.lean +++ b/Mathlib/MeasureTheory/Group/AddCircle.lean @@ -35,9 +35,9 @@ theorem closedBall_ae_eq_ball {x : AddCircle T} {ε : ℝ} : closedBall x ε = · rw [ball_eq_empty.mpr hε, ae_eq_empty, volume_closedBall, min_eq_right (by linarith [hT.out] : 2 * ε ≤ T), ENNReal.ofReal_eq_zero] exact mul_nonpos_of_nonneg_of_nonpos zero_le_two hε - · suffices volume (closedBall x ε) ≤ volume (ball x ε) by - exact (ae_eq_of_subset_of_measure_ge ball_subset_closedBall this measurableSet_ball - (measure_ne_top _ _)).symm + · suffices volume (closedBall x ε) ≤ volume (ball x ε) from + (ae_eq_of_subset_of_measure_ge ball_subset_closedBall this + measurableSet_ball.nullMeasurableSet (measure_ne_top _ _)).symm have : Tendsto (fun δ => volume (closedBall x δ)) (𝓝[<] ε) (𝓝 <| volume (closedBall x ε)) := by simp_rw [volume_closedBall] refine ENNReal.tendsto_ofReal (Tendsto.min tendsto_const_nhds <| Tendsto.const_mul _ ?_) @@ -70,7 +70,7 @@ theorem isAddFundamentalDomain_of_ae_ball (I : Set <| AddCircle T) (u x : AddCir rw [hBg] apply ball_disjoint_ball rw [dist_eq_norm, add_sub_cancel_right, div_mul_eq_div_div, ← add_div, ← add_div, - add_self_div_two, div_le_iff' (by positivity : 0 < (n : ℝ)), ← nsmul_eq_mul] + add_self_div_two, div_le_iff₀' (by positivity : 0 < (n : ℝ)), ← nsmul_eq_mul] refine (le_add_order_smul_norm_of_isOfFinAddOrder (hu.of_mem_zmultiples hg) hg').trans (nsmul_le_nsmul_left (norm_nonneg g) ?_) exact Nat.le_of_dvd (addOrderOf_pos_iff.mpr hu) (addOrderOf_dvd_of_mem_zmultiples hg) diff --git a/Mathlib/MeasureTheory/Group/Arithmetic.lean b/Mathlib/MeasureTheory/Group/Arithmetic.lean index 6fd334466abb6..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) @@ -166,7 +168,7 @@ instance Monoid.measurablePow (M : Type*) [Monoid M] [MeasurableSpace M] [Measur MeasurablePow M ℕ := ⟨measurable_from_prod_countable fun n => by induction' n with n ih - · simp only [Nat.zero_eq, pow_zero, ← Pi.one_def, measurable_one] + · simp only [pow_zero, ← Pi.one_def, measurable_one] · simp only [pow_succ] exact ih.mul measurable_id⟩ @@ -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) : @@ -588,7 +600,7 @@ instance AddMonoid.measurableSMul_nat₂ (M : Type*) [AddMonoid M] [MeasurableSp suffices Measurable fun p : M × ℕ => p.2 • p.1 by apply this.comp measurable_swap refine measurable_from_prod_countable fun n => ?_ induction' n with n ih - · simp only [Nat.zero_eq, zero_smul, ← Pi.zero_def, measurable_zero] + · simp only [zero_smul, ← Pi.zero_def, measurable_zero] · simp only [succ_nsmul] exact ih.add measurable_id⟩ @@ -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) μ) : @@ -836,23 +851,23 @@ variable [MeasurableSpace α] [Mul α] [Div α] [Inv α] @[to_additive] -- See note [lower instance priority] instance (priority := 100) DiscreteMeasurableSpace.toMeasurableMul [DiscreteMeasurableSpace α] : MeasurableMul α where - measurable_const_mul _ := measurable_discrete _ - measurable_mul_const _ := measurable_discrete _ + measurable_const_mul _ := .of_discrete + measurable_mul_const _ := .of_discrete @[to_additive DiscreteMeasurableSpace.toMeasurableAdd₂] -- See note [lower instance priority] instance (priority := 100) DiscreteMeasurableSpace.toMeasurableMul₂ - [DiscreteMeasurableSpace (α × α)] : MeasurableMul₂ α := ⟨measurable_discrete _⟩ + [DiscreteMeasurableSpace (α × α)] : MeasurableMul₂ α := ⟨.of_discrete⟩ @[to_additive] -- See note [lower instance priority] instance (priority := 100) DiscreteMeasurableSpace.toMeasurableInv [DiscreteMeasurableSpace α] : - MeasurableInv α := ⟨measurable_discrete _⟩ + MeasurableInv α := ⟨.of_discrete⟩ @[to_additive] -- See note [lower instance priority] instance (priority := 100) DiscreteMeasurableSpace.toMeasurableDiv [DiscreteMeasurableSpace α] : MeasurableDiv α where - measurable_const_div _ := measurable_discrete _ - measurable_div_const _ := measurable_discrete _ + measurable_const_div _ := .of_discrete + measurable_div_const _ := .of_discrete @[to_additive DiscreteMeasurableSpace.toMeasurableSub₂] -- See note [lower instance priority] instance (priority := 100) DiscreteMeasurableSpace.toMeasurableDiv₂ - [DiscreteMeasurableSpace (α × α)] : MeasurableDiv₂ α := ⟨measurable_discrete _⟩ + [DiscreteMeasurableSpace (α × α)] : MeasurableDiv₂ α := ⟨.of_discrete⟩ 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 5b5f6208fd138..b7e676a68b71b 100644 --- a/Mathlib/MeasureTheory/Group/FundamentalDomain.lean +++ b/Mathlib/MeasureTheory/Group/FundamentalDomain.lean @@ -84,7 +84,7 @@ is a fundamental domain for the action of `G` on `α`. -/ theorem mk' (h_meas : NullMeasurableSet s μ) (h_exists : ∀ x : α, ∃! g : G, g • x ∈ s) : IsFundamentalDomain G s μ where nullMeasurableSet := h_meas - ae_covers := eventually_of_forall fun x => (h_exists x).exists + ae_covers := Eventually.of_forall fun x => (h_exists x).exists aedisjoint a b hab := Disjoint.aedisjoint <| disjoint_left.2 fun x hxa hxb => by rw [mem_smul_set_iff_inv_smul_mem] at hxa hxb exact hab (inv_injective <| (h_exists x).unique hxa hxb) @@ -346,7 +346,7 @@ protected theorem aEStronglyMeasurable_on_iff {β : Type*} [TopologicalSpace β] have he : MeasurableEmbedding (g⁻¹ • · : α → α) := measurableEmbedding_const_smul _ rw [← image_smul, ← ((measurePreserving_smul g⁻¹ μ).restrict_image_emb he _).aestronglyMeasurable_comp_iff he] - simp only [(· ∘ ·), hf] + simp only [Function.comp_def, hf] _ ↔ AEStronglyMeasurable f (μ.restrict t) := by simp only [← aestronglyMeasurable_sum_measure_iff, ← hs.restrict_restrict, hs.sum_restrict_of_ac restrict_le_self.absolutelyContinuous] @@ -540,7 +540,6 @@ theorem fundamentalInterior_union_fundamentalFrontier : theorem fundamentalFrontier_union_fundamentalInterior : fundamentalFrontier G s ∪ fundamentalInterior G s = s := inter_union_diff _ _ --- Porting note: there is a typo in `to_additive` in mathlib3, so there is no additive version @[to_additive (attr := simp) MeasureTheory.sdiff_addFundamentalInterior] theorem sdiff_fundamentalInterior : s \ fundamentalInterior G s = fundamentalFrontier G s := diff --git a/Mathlib/MeasureTheory/Group/GeometryOfNumbers.lean b/Mathlib/MeasureTheory/Group/GeometryOfNumbers.lean index 9fd4d3c6d24d8..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 @@ -57,7 +57,7 @@ theorem exists_pair_mem_lattice_not_disjoint_vadd [AddCommGroup L] [Countable L] /-- The **Minkowski Convex Body Theorem**. If `s` is a convex symmetric domain of `E` whose volume is large enough compared to the covolume of a lattice `L` of `E`, then it contains a non-zero -lattice point of `L`. -/ +lattice point of `L`. -/ theorem exists_ne_zero_mem_lattice_of_measure_mul_two_pow_lt_measure [NormedAddCommGroup E] [NormedSpace ℝ E] [BorelSpace E] [FiniteDimensional ℝ E] [IsAddHaarMeasure μ] {L : AddSubgroup E} [Countable L] (fund : IsAddFundamentalDomain L F μ) @@ -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/Measure.lean b/Mathlib/MeasureTheory/Group/Measure.lean index f6a2650672d2e..3e36cb114970b 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.Topology.ContinuousMap.CocompactMap /-! # Measures on Groups @@ -277,9 +271,7 @@ end Group namespace Measure --- Porting note: Even in `noncomputable section`, a definition with `to_additive` require --- `noncomputable` to generate an additive definition. --- Please refer to leanprover/lean4#2077. +-- TODO: noncomputable has to be specified explicitly. #1074 (item 8) /-- The measure `A ↦ μ (A⁻¹)`, where `A⁻¹` is the pointwise inverse of `A`. -/ @[to_additive "The measure `A ↦ μ (- A)`, where `- A` is the pointwise negation of `A`."] @@ -361,7 +353,7 @@ instance inv.instIsMulRightInvariant [IsMulLeftInvariant μ] : IsMulRightInvaria intro g conv_rhs => rw [← map_mul_left_eq_self μ g⁻¹] simp_rw [Measure.inv, map_map (measurable_mul_const g) measurable_inv, - map_map measurable_inv (measurable_const_mul g⁻¹), Function.comp, mul_inv_rev, inv_inv] + map_map measurable_inv (measurable_const_mul g⁻¹), Function.comp_def, mul_inv_rev, inv_inv] @[to_additive] instance inv.instIsMulLeftInvariant [IsMulRightInvariant μ] : IsMulLeftInvariant μ.inv := by @@ -369,7 +361,7 @@ instance inv.instIsMulLeftInvariant [IsMulRightInvariant μ] : IsMulLeftInvarian intro g conv_rhs => rw [← map_mul_right_eq_self μ g⁻¹] simp_rw [Measure.inv, map_map (measurable_const_mul g) measurable_inv, - map_map measurable_inv (measurable_mul_const g⁻¹), Function.comp, mul_inv_rev, inv_inv] + map_map measurable_inv (measurable_mul_const g⁻¹), Function.comp_def, mul_inv_rev, inv_inv] @[to_additive] theorem measurePreserving_div_left (μ : Measure G) [IsInvInvariant μ] [IsMulLeftInvariant μ] @@ -472,7 +464,7 @@ lemma eventually_nhds_one_measure_smul_diff_lt [LocallyCompactSpace G] μ (g • k \ k) ≤ μ (U \ k) := by gcongr exact (smul_set_subset_smul hg).trans hVkU - _ < ε := measure_diff_lt_of_lt_add h'k.measurableSet hUk hk.measure_lt_top.ne hμUk + _ < ε := measure_diff_lt_of_lt_add h'k.nullMeasurableSet hUk hk.measure_lt_top.ne hμUk /-- Continuity of the measure of translates of a compact set: Given a closed compact set `k` in a topological group, @@ -526,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} @@ -546,13 +538,9 @@ any compact set."] theorem measure_lt_top_of_isCompact_of_isMulLeftInvariant (U : Set G) (hU : IsOpen U) (h'U : U.Nonempty) (h : μ U ≠ ∞) {K : Set G} (hK : IsCompact K) : μ K < ∞ := by rw [← hU.interior_eq] at h'U - obtain ⟨t, hKt⟩ : ∃ t : Finset G, K ⊆ ⋃ (g : G) (_ : g ∈ t), (fun h : G => g * h) ⁻¹' U := + obtain ⟨t, hKt⟩ : ∃ t : Finset G, K ⊆ ⋃ g ∈ t, (fun h : G => g * h) ⁻¹' U := compact_covered_by_mul_left_translates hK h'U - calc - μ K ≤ μ (⋃ (g : G) (_ : g ∈ t), (fun h : G => g * h) ⁻¹' U) := measure_mono hKt - _ ≤ ∑ g ∈ t, μ ((fun h : G => g * h) ⁻¹' U) := measure_biUnion_finset_le _ _ - _ = Finset.card t * μ U := by simp only [measure_preimage_mul, Finset.sum_const, nsmul_eq_mul] - _ < ∞ := ENNReal.mul_lt_top (ENNReal.natCast_ne_top _) h + exact (measure_mono hKt).trans_lt <| measure_biUnion_lt_top t.finite_toSet <| by simp [h.lt_top] /-- If a left-invariant measure gives finite mass to a set with nonempty interior, then it gives finite mass to any compact set. -/ @@ -597,7 +585,7 @@ theorem measure_univ_of_isMulLeftInvariant [WeaklyLocallyCompactSpace G] [Noncom have M : ∀ n, μ (L n) = (n + 1 : ℕ) * μ K := by intro n induction' n with n IH - · simp only [L, one_mul, Nat.cast_one, iterate_zero, id, Nat.zero_eq, Nat.zero_add] + · simp only [L, one_mul, Nat.cast_one, iterate_zero, id, Nat.zero_add] · calc μ (L (n + 1)) = μ (L n) + μ (g (L n) • K) := by simp_rw [L, iterate_succ'] @@ -713,7 +701,7 @@ theorem haar_singleton [TopologicalGroup G] [BorelSpace G] (g : G) : μ {g} = μ @[to_additive IsAddHaarMeasure.smul] theorem IsHaarMeasure.smul {c : ℝ≥0∞} (cpos : c ≠ 0) (ctop : c ≠ ∞) : IsHaarMeasure (c • μ) := - { lt_top_of_isCompact := fun _K hK => ENNReal.mul_lt_top ctop hK.measure_lt_top.ne + { lt_top_of_isCompact := fun _K hK => ENNReal.mul_lt_top ctop.lt_top hK.measure_lt_top toIsOpenPosMeasure := isOpenPosMeasure_smul μ cpos } /-- If a left-invariant measure gives positive mass to some compact set with nonempty interior, then @@ -734,14 +722,15 @@ a Haar measure. See also `MulEquiv.isHaarMeasure_map`. -/ "The image of an additive Haar measure under a continuous surjective proper additive group homomorphism is again an additive Haar measure. See also `AddEquiv.isAddHaarMeasure_map`."] theorem isHaarMeasure_map [BorelSpace G] [TopologicalGroup G] {H : Type*} [Group H] - [TopologicalSpace H] [MeasurableSpace H] [BorelSpace H] [T2Space H] [TopologicalGroup H] + [TopologicalSpace H] [MeasurableSpace H] [BorelSpace H] [TopologicalGroup H] (f : G →* H) (hf : Continuous f) (h_surj : Surjective f) (h_prop : Tendsto f (cocompact G) (cocompact H)) : IsHaarMeasure (Measure.map f μ) := { toIsMulLeftInvariant := isMulLeftInvariant_map f.toMulHom hf.measurable h_surj lt_top_of_isCompact := by intro K hK - rw [map_apply hf.measurable hK.measurableSet] - exact IsCompact.measure_lt_top ((⟨⟨f, hf⟩, h_prop⟩ : CocompactMap G H).isCompact_preimage hK) + rw [← hK.measure_closure, map_apply hf.measurable isClosed_closure.measurableSet] + set g : CocompactMap G H := ⟨⟨f, hf⟩, h_prop⟩ + exact IsCompact.measure_lt_top (g.isCompact_preimage_of_isClosed hK.closure isClosed_closure) toIsOpenPosMeasure := hf.isOpenPosMeasure_map h_surj } /-- The image of a finite Haar measure under a continuous surjective group homomorphism is again @@ -753,10 +742,9 @@ theorem isHaarMeasure_map_of_isFiniteMeasure [BorelSpace G] [TopologicalGroup G] {H : Type*} [Group H] [TopologicalSpace H] [MeasurableSpace H] [BorelSpace H] [TopologicalGroup H] [IsFiniteMeasure μ] (f : G →* H) (hf : Continuous f) (h_surj : Surjective f) : - IsHaarMeasure (Measure.map f μ) := - { toIsMulLeftInvariant := isMulLeftInvariant_map f.toMulHom hf.measurable h_surj - lt_top_of_isCompact := fun _K hK ↦ hK.measure_lt_top - toIsOpenPosMeasure := hf.isOpenPosMeasure_map h_surj } + IsHaarMeasure (Measure.map f μ) where + toIsMulLeftInvariant := isMulLeftInvariant_map f.toMulHom hf.measurable h_surj + toIsOpenPosMeasure := hf.isOpenPosMeasure_map h_surj /-- The image of a Haar measure under map of a left action is again a Haar measure. -/ @[to_additive @@ -786,20 +774,11 @@ nonrec theorem _root_.MulEquiv.isHaarMeasure_map [BorelSpace G] [TopologicalGrou [Group H] [TopologicalSpace H] [MeasurableSpace H] [BorelSpace H] [TopologicalGroup H] (e : G ≃* H) (he : Continuous e) (hesymm : Continuous e.symm) : IsHaarMeasure (Measure.map e μ) := - { toIsMulLeftInvariant := isMulLeftInvariant_map e.toMulHom he.measurable e.surjective - lt_top_of_isCompact := by - intro K hK - let F : G ≃ₜ H := { - e.toEquiv with - continuous_toFun := he - continuous_invFun := hesymm } - change map F.toMeasurableEquiv μ K < ∞ - rw [F.toMeasurableEquiv.map_apply K] - exact (F.isCompact_preimage.mpr hK).measure_lt_top - toIsOpenPosMeasure := he.isOpenPosMeasure_map e.surjective } + let f : G ≃ₜ H := .mk e + isHaarMeasure_map μ e he e.surjective f.closedEmbedding.tendsto_cocompact /-- A convenience wrapper for MeasureTheory.Measure.isAddHaarMeasure_map`. -/ -theorem _root_.ContinuousLinearEquiv.isAddHaarMeasure_map +instance _root_.ContinuousLinearEquiv.isAddHaarMeasure_map {E F R S : Type*} [Semiring R] [Semiring S] [AddCommGroup E] [Module R E] [AddCommGroup F] [Module S F] [TopologicalSpace E] [TopologicalAddGroup E] [TopologicalSpace F] diff --git a/Mathlib/MeasureTheory/Group/Prod.lean b/Mathlib/MeasureTheory/Group/Prod.lean index f2e659ca8ab0e..38b8691d5bc0d 100644 --- a/Mathlib/MeasureTheory/Group/Prod.lean +++ b/Mathlib/MeasureTheory/Group/Prod.lean @@ -83,7 +83,7 @@ There, the map in this lemma is called `S`. -/ theorem measurePreserving_prod_mul [IsMulLeftInvariant ν] : MeasurePreserving (fun z : G × G => (z.1, z.1 * z.2)) (μ.prod ν) (μ.prod ν) := (MeasurePreserving.id μ).skew_product measurable_mul <| - Filter.eventually_of_forall <| map_mul_left_eq_self ν + Filter.Eventually.of_forall <| map_mul_left_eq_self ν /-- The map `(x, y) ↦ (y, yx)` sends the measure `μ × ν` to `ν × μ`. This is the map `SR` in [Halmos, §59]. @@ -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 @@ -342,7 +342,7 @@ section RightInvariant theorem measurePreserving_prod_mul_right [IsMulRightInvariant ν] : MeasurePreserving (fun z : G × G => (z.1, z.2 * z.1)) (μ.prod ν) (μ.prod ν) := MeasurePreserving.skew_product (g := fun x y => y * x) (MeasurePreserving.id μ) - (measurable_snd.mul measurable_fst) <| Filter.eventually_of_forall <| map_mul_right_eq_self ν + (measurable_snd.mul measurable_fst) <| Filter.Eventually.of_forall <| map_mul_right_eq_self ν /-- The map `(x, y) ↦ (y, xy)` sends the measure `μ × ν` to `ν × μ`. -/ @[to_additive measurePreserving_prod_add_swap_right @@ -356,7 +356,7 @@ theorem measurePreserving_prod_mul_swap_right [IsMulRightInvariant μ] : " The map `(x, y) ↦ (x + y, y)` preserves the measure `μ × ν`. "] theorem measurePreserving_mul_prod [IsMulRightInvariant μ] : MeasurePreserving (fun z : G × G => (z.1 * z.2, z.2)) (μ.prod ν) (μ.prod ν) := - measurePreserving_swap.comp <| by apply measurePreserving_prod_mul_swap_right μ ν + measurePreserving_swap.comp (measurePreserving_prod_mul_swap_right μ ν) variable [MeasurableInv G] @@ -378,7 +378,7 @@ theorem measurePreserving_prod_div_swap [IsMulRightInvariant μ] : " The map `(x, y) ↦ (x - y, y)` preserves the measure `μ × ν`. "] theorem measurePreserving_div_prod [IsMulRightInvariant μ] : MeasurePreserving (fun z : G × G => (z.1 / z.2, z.2)) (μ.prod ν) (μ.prod ν) := - measurePreserving_swap.comp <| by apply measurePreserving_prod_div_swap μ ν + measurePreserving_swap.comp (measurePreserving_prod_div_swap μ ν) /-- The map `(x, y) ↦ (xy, x⁻¹)` is measure-preserving. -/ @[to_additive measurePreserving_add_prod_neg_right @@ -422,7 +422,7 @@ theorem quasiMeasurePreserving_div_left_of_right_invariant [IsMulRightInvariant @[to_additive] theorem quasiMeasurePreserving_div_of_right_invariant [IsMulRightInvariant μ] : QuasiMeasurePreserving (fun p : G × G => p.1 / p.2) (μ.prod ν) μ := by - refine QuasiMeasurePreserving.prod_of_left measurable_div (eventually_of_forall fun y => ?_) + refine QuasiMeasurePreserving.prod_of_left measurable_div (Eventually.of_forall fun y => ?_) exact (measurePreserving_div_right μ y).quasiMeasurePreserving @[to_additive] @@ -455,7 +455,7 @@ theorem quasiMeasurePreserving_mul_left [IsMulRightInvariant μ] (g : G) : have := (quasiMeasurePreserving_inv_of_right_invariant μ).comp (this.comp (quasiMeasurePreserving_inv_of_right_invariant μ)) - simp_rw [Function.comp, mul_inv_rev, inv_inv] at this + simp_rw [Function.comp_def, mul_inv_rev, inv_inv] at this exact this end QuasiMeasurePreserving diff --git a/Mathlib/MeasureTheory/Integral/Asymptotics.lean b/Mathlib/MeasureTheory/Integral/Asymptotics.lean index 17d15d5d198ac..f80409c54ea35 100644 --- a/Mathlib/MeasureTheory/Integral/Asymptotics.lean +++ b/Mathlib/MeasureTheory/Integral/Asymptotics.lean @@ -5,6 +5,7 @@ Authors: Lawrence Wu -/ import Mathlib.MeasureTheory.Group.Measure import Mathlib.MeasureTheory.Integral.IntegrableOn +import Mathlib.MeasureTheory.Integral.SetIntegral import Mathlib.MeasureTheory.Function.LocallyIntegrable /-! @@ -28,8 +29,13 @@ We establish integrability of `f` from `f = O(g)`. open Asymptotics MeasureTheory Set Filter -variable {α E F : Type*} [MeasurableSpace α] [NormedAddCommGroup E] [NormedAddCommGroup F] - {f : α → E} {g : α → F} {a b : α} {μ : Measure α} {l : Filter α} +variable {α E F : Type*} [NormedAddCommGroup E] {f : α → E} {g : α → F} {a b : α} {l : Filter α} + +namespace Asymptotics + +section Basic + +variable [MeasurableSpace α] [NormedAddCommGroup F] {μ : Measure α} /-- If `f = O[l] g` on measurably generated `l`, `f` is strongly measurable at `l`, and `g` is integrable at `l`, then `f` is integrable at `l`. -/ @@ -49,7 +55,53 @@ theorem _root_.Asymptotics.IsBigO.integrable (hfm : AEStronglyMeasurable f μ) rewrite [← integrableAtFilter_top] at * exact hf.integrableAtFilter ⟨univ, univ_mem, hfm.restrict⟩ hg -variable [TopologicalSpace α] [SecondCountableTopology α] +end Basic + +variable {ι : Type*} [MeasurableSpace ι] {f : ι × α → E} {s : Set ι} {μ : Measure ι} + +/-- Let `f : X x Y → Z`. If as `y` tends to `l`, `f(x, y) = O(g(y))` uniformly on `s : Set X` +of finite measure, then f is eventually (as `y` tends to `l`) integrable along `s`. -/ +theorem IsBigO.eventually_integrableOn [Norm F] + (hf : f =O[𝓟 s ×ˢ l] (g ∘ Prod.snd)) + (hfm : ∀ᶠ x in l, AEStronglyMeasurable (fun i ↦ f (i, x)) (μ.restrict s)) + (hs : MeasurableSet s) (hμ : μ s < ⊤) : + ∀ᶠ x in l, IntegrableOn (fun i ↦ f (i, x)) s μ := by + obtain ⟨C, hC⟩ := hf.bound + obtain ⟨t, htl, ht⟩ := hC.exists_mem + obtain ⟨u, hu, v, hv, huv⟩ := Filter.mem_prod_iff.mp htl + obtain ⟨w, hwl, hw⟩ := hfm.exists_mem + refine eventually_iff_exists_mem.mpr ⟨w ∩ v, inter_mem hwl hv, fun x hx ↦ ?_⟩ + haveI : IsFiniteMeasure (μ.restrict s) := ⟨Measure.restrict_apply_univ s ▸ hμ⟩ + refine Integrable.mono' (integrable_const (C * ‖g x‖)) (hw x hx.1) ?_ + filter_upwards [MeasureTheory.self_mem_ae_restrict hs] + intro y hy + exact ht (y, x) <| huv ⟨hu hy, hx.2⟩ + +variable [NormedSpace ℝ E] [NormedAddCommGroup F] + +/-- Let `f : X x Y → Z`. If as `y` tends to `l`, `f(x, y) = O(g(y))` uniformly on `s : Set X` +of finite measure, then the integral of `f` along `s` is `O(g(y))`. -/ +theorem IsBigO.set_integral_isBigO + (hf : f =O[𝓟 s ×ˢ l] (g ∘ Prod.snd)) (hs : MeasurableSet s) (hμ : μ s < ⊤) : + (fun x ↦ ∫ i in s, f (i, x) ∂μ) =O[l] g := by + obtain ⟨C, hC⟩ := hf.bound + obtain ⟨t, htl, ht⟩ := hC.exists_mem + obtain ⟨u, hu, v, hv, huv⟩ := Filter.mem_prod_iff.mp htl + refine isBigO_iff.mpr ⟨C * (μ s).toReal, eventually_iff_exists_mem.mpr ⟨v, hv, fun x hx ↦ ?_⟩⟩ + rw [mul_assoc, ← smul_eq_mul (a' := ‖g x‖), ← MeasureTheory.Measure.restrict_apply_univ, + ← integral_const, mul_comm, ← smul_eq_mul, ← integral_smul_const] + haveI : IsFiniteMeasure (μ.restrict s) := ⟨by rw [Measure.restrict_apply_univ s]; exact hμ⟩ + refine (norm_integral_le_integral_norm _).trans <| + integral_mono_of_nonneg (univ_mem' fun _ ↦ norm_nonneg _) (integrable_const _) ?_ + filter_upwards [MeasureTheory.self_mem_ae_restrict hs] + intro y hy + rw [smul_eq_mul, mul_comm] + exact ht (y, x) <| huv ⟨hu hy, hx⟩ + +end Asymptotics + +variable [TopologicalSpace α] [SecondCountableTopology α] [MeasurableSpace α] {μ : Measure α} + [NormedAddCommGroup F] namespace MeasureTheory diff --git a/Mathlib/MeasureTheory/Integral/Average.lean b/Mathlib/MeasureTheory/Integral/Average.lean index 8ec1ba5cb9b64..2b93b827a0339 100644 --- a/Mathlib/MeasureTheory/Integral/Average.lean +++ b/Mathlib/MeasureTheory/Integral/Average.lean @@ -752,7 +752,7 @@ theorem tendsto_integral_smul_of_tendsto_average_norm_sub rw [← integrableOn_iff_integrable_of_support_subset A] apply Integrable.smul_of_top_right hif exact memℒp_top_of_bound hig.aestronglyMeasurable.restrict - (K / (μ (a i)).toReal) (eventually_of_forall hibound) + (K / (μ (a i)).toReal) (Eventually.of_forall hibound) · exact hig.smul_const _ have L0 : Tendsto (fun i ↦ ∫ y, g i y • (f y - c) ∂μ) l (𝓝 0) := by have := hf.const_mul K @@ -773,8 +773,8 @@ theorem tendsto_integral_smul_of_tendsto_average_norm_sub have : g i x = 0 := by rw [← Function.nmem_support]; exact fun h ↦ hx (hi h) simp [this] rw [← setIntegral_eq_integral_of_forall_compl_eq_zero this (μ := μ)] - refine integral_mono_of_nonneg (eventually_of_forall (fun x ↦ by positivity)) ?_ - (eventually_of_forall (fun x ↦ ?_)) + refine integral_mono_of_nonneg (Eventually.of_forall (fun x ↦ by positivity)) ?_ + (Eventually.of_forall (fun x ↦ ?_)) · apply (Integrable.sub h''i _).norm.const_mul change IntegrableOn (fun _ ↦ c) (a i) μ simp [integrableOn_const, mu_ai] diff --git a/Mathlib/MeasureTheory/Integral/Bochner.lean b/Mathlib/MeasureTheory/Integral/Bochner.lean index 74bbe759404b4..411b231ffbadc 100644 --- a/Mathlib/MeasureTheory/Integral/Bochner.lean +++ b/Mathlib/MeasureTheory/Integral/Bochner.lean @@ -433,7 +433,7 @@ theorem norm_eq_integral (f : α →₁ₛ[μ] E) : ‖f‖ = ((toSimpleFunc f). section PosPart -/-- Positive part of a simple function in L1 space. -/ +/-- Positive part of a simple function in L1 space. -/ nonrec def posPart (f : α →₁ₛ[μ] ℝ) : α →₁ₛ[μ] ℝ := ⟨Lp.posPart (f : α →₁[μ] ℝ), by rcases f with ⟨f, s, hsf⟩ @@ -441,7 +441,7 @@ nonrec def posPart (f : α →₁ₛ[μ] ℝ) : α →₁ₛ[μ] ℝ := simp only [Subtype.coe_mk, Lp.coe_posPart, ← hsf, AEEqFun.posPart_mk, SimpleFunc.coe_map, mk_eq_mk] -- Porting note: added - simp [SimpleFunc.posPart, Function.comp, EventuallyEq.rfl] ⟩ + simp [SimpleFunc.posPart, Function.comp_def, EventuallyEq.rfl] ⟩ /-- Negative part of a simple function in L1 space. -/ def negPart (f : α →₁ₛ[μ] ℝ) : α →₁ₛ[μ] ℝ := @@ -588,7 +588,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 {𝕜} @@ -1000,7 +1000,7 @@ theorem continuous_of_dominated {F : X → α → G} {bound : α → ℝ} · simp [integral, hG, continuous_const] /-- The Bochner integral of a real-valued function `f : α → ℝ` is the difference between the - integral of the positive part of `f` and the integral of the negative part of `f`. -/ + integral of the positive part of `f` and the integral of the negative part of `f`. -/ theorem integral_eq_lintegral_pos_part_sub_lintegral_neg_part {f : α → ℝ} (hf : Integrable f μ) : ∫ a, f a ∂μ = ENNReal.toReal (∫⁻ a, .ofReal (f a) ∂μ) - ENNReal.toReal (∫⁻ a, .ofReal (-f a) ∂μ) := by @@ -1044,7 +1044,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 => ?_) @@ -1077,7 +1077,7 @@ theorem integral_nonneg_of_ae {f : α → ℝ} (hf : 0 ≤ᵐ[μ] f) : 0 ≤ ∫ theorem lintegral_coe_eq_integral (f : α → ℝ≥0) (hfi : Integrable (fun x => (f x : ℝ)) μ) : ∫⁻ a, f a ∂μ = ENNReal.ofReal (∫ a, f a ∂μ) := by - simp_rw [integral_eq_lintegral_of_nonneg_ae (eventually_of_forall fun x => (f x).coe_nonneg) + simp_rw [integral_eq_lintegral_of_nonneg_ae (Eventually.of_forall fun x => (f x).coe_nonneg) hfi.aestronglyMeasurable, ← ENNReal.coe_nnreal_eq] rw [ENNReal.ofReal_toReal] rw [← lt_top_iff_ne_top] @@ -1096,7 +1096,7 @@ theorem integral_toReal {f : α → ℝ≥0∞} (hfm : AEMeasurable f μ) (hf : ∫ a, (f a).toReal ∂μ = (∫⁻ a, f a ∂μ).toReal := by rw [integral_eq_lintegral_of_nonneg_ae _ hfm.ennreal_toReal.aestronglyMeasurable, lintegral_congr_ae (ofReal_toReal_ae_eq hf)] - exact eventually_of_forall fun x => ENNReal.toReal_nonneg + exact Eventually.of_forall fun x => ENNReal.toReal_nonneg theorem lintegral_coe_le_coe_iff_integral_le {f : α → ℝ≥0} (hfi : Integrable (fun x => (f x : ℝ)) μ) {b : ℝ≥0} : ∫⁻ a, f a ∂μ ≤ b ↔ ∫ a, (f a : ℝ) ∂μ ≤ b := by @@ -1110,7 +1110,7 @@ theorem integral_coe_le_of_lintegral_coe_le {f : α → ℝ≥0} {b : ℝ≥0} ( · rw [integral_undef hf]; exact b.2 theorem integral_nonneg {f : α → ℝ} (hf : 0 ≤ f) : 0 ≤ ∫ a, f a ∂μ := - integral_nonneg_of_ae <| eventually_of_forall hf + integral_nonneg_of_ae <| Eventually.of_forall hf theorem integral_nonpos_of_ae {f : α → ℝ} (hf : f ≤ᵐ[μ] 0) : ∫ a, f a ∂μ ≤ 0 := by have hf : 0 ≤ᵐ[μ] -f := hf.mono fun a h => by rwa [Pi.neg_apply, Pi.zero_apply, neg_nonneg] @@ -1118,12 +1118,12 @@ theorem integral_nonpos_of_ae {f : α → ℝ} (hf : f ≤ᵐ[μ] 0) : ∫ a, f rwa [integral_neg, neg_nonneg] at this theorem integral_nonpos {f : α → ℝ} (hf : f ≤ 0) : ∫ a, f a ∂μ ≤ 0 := - integral_nonpos_of_ae <| eventually_of_forall hf + integral_nonpos_of_ae <| Eventually.of_forall hf 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] @@ -1132,7 +1132,7 @@ theorem integral_eq_zero_iff_of_nonneg_ae {f : α → ℝ} (hf : 0 ≤ᵐ[μ] f) theorem integral_eq_zero_iff_of_nonneg {f : α → ℝ} (hf : 0 ≤ f) (hfi : Integrable f μ) : ∫ x, f x ∂μ = 0 ↔ f =ᵐ[μ] 0 := - integral_eq_zero_iff_of_nonneg_ae (eventually_of_forall hf) hfi + integral_eq_zero_iff_of_nonneg_ae (Eventually.of_forall hf) hfi lemma integral_eq_iff_of_ae_le {f g : α → ℝ} (hf : Integrable f μ) (hg : Integrable g μ) (hfg : f ≤ᵐ[μ] g) : @@ -1150,7 +1150,7 @@ theorem integral_pos_iff_support_of_nonneg_ae {f : α → ℝ} (hf : 0 ≤ᵐ[μ theorem integral_pos_iff_support_of_nonneg {f : α → ℝ} (hf : 0 ≤ f) (hfi : Integrable f μ) : (0 < ∫ x, f x ∂μ) ↔ 0 < μ (Function.support f) := - integral_pos_iff_support_of_nonneg_ae (eventually_of_forall hf) hfi + integral_pos_iff_support_of_nonneg_ae (Eventually.of_forall hf) hfi lemma integral_exp_pos {μ : Measure α} {f : α → ℝ} [hμ : NeZero μ] (hf : Integrable (fun x ↦ Real.exp (f x)) μ) : @@ -1301,7 +1301,7 @@ variable {H : Type*} [NormedAddCommGroup H] theorem L1.norm_eq_integral_norm (f : α →₁[μ] H) : ‖f‖ = ∫ a, ‖f a‖ ∂μ := by simp only [eLpNorm, eLpNorm', ENNReal.one_toReal, ENNReal.rpow_one, Lp.norm_def, if_false, ENNReal.one_ne_top, one_ne_zero, _root_.div_one] - rw [integral_eq_lintegral_of_nonneg_ae (eventually_of_forall (by simp [norm_nonneg])) + rw [integral_eq_lintegral_of_nonneg_ae (Eventually.of_forall (by simp [norm_nonneg])) (Lp.aestronglyMeasurable f).norm] simp [ofReal_norm_eq_coe_nnnorm] @@ -1341,7 +1341,7 @@ theorem integral_mono_ae {f g : α → ℝ} (hf : Integrable f μ) (hg : Integra @[mono] theorem integral_mono {f g : α → ℝ} (hf : Integrable f μ) (hg : Integrable g μ) (h : f ≤ g) : ∫ a, f a ∂μ ≤ ∫ a, g a ∂μ := - integral_mono_ae hf hg <| eventually_of_forall h + integral_mono_ae hf hg <| Eventually.of_forall h theorem integral_mono_of_nonneg {f g : α → ℝ} (hf : 0 ≤ᵐ[μ] f) (hgi : Integrable g μ) (h : f ≤ᵐ[μ] g) : ∫ a, f a ∂μ ≤ ∫ a, g a ∂μ := by @@ -1362,7 +1362,7 @@ theorem integral_mono_measure {f : α → ℝ} {ν} (hle : μ ≤ ν) (hf : 0 ((hasFiniteIntegral_iff_ofReal hf).1 hfi.2).ne] theorem norm_integral_le_integral_norm (f : α → G) : ‖∫ a, f a ∂μ‖ ≤ ∫ a, ‖f a‖ ∂μ := by - have le_ae : ∀ᵐ a ∂μ, 0 ≤ ‖f a‖ := eventually_of_forall fun a => norm_nonneg _ + have le_ae : ∀ᵐ a ∂μ, 0 ≤ ‖f a‖ := Eventually.of_forall fun a => norm_nonneg _ by_cases h : AEStronglyMeasurable f μ · calc ‖∫ a, f a ∂μ‖ ≤ ENNReal.toReal (∫⁻ a, ENNReal.ofReal ‖f a‖ ∂μ) := @@ -1375,7 +1375,7 @@ theorem norm_integral_le_of_norm_le {f : α → G} {g : α → ℝ} (hg : Integr (h : ∀ᵐ x ∂μ, ‖f x‖ ≤ g x) : ‖∫ x, f x ∂μ‖ ≤ ∫ x, g x ∂μ := calc ‖∫ x, f x ∂μ‖ ≤ ∫ x, ‖f x‖ ∂μ := norm_integral_le_integral_norm f - _ ≤ ∫ x, g x ∂μ := integral_mono_of_nonneg (eventually_of_forall fun _ => norm_nonneg _) hg h + _ ≤ ∫ x, g x ∂μ := integral_mono_of_nonneg (Eventually.of_forall fun _ => norm_nonneg _) hg h theorem SimpleFunc.integral_eq_integral (f : α →ₛ E) (hfi : Integrable f μ) : f.integral μ = ∫ x, f x ∂μ := by @@ -1422,7 +1422,7 @@ theorem tendsto_integral_approxOn_of_measurable_of_range_subset [MeasurableSpace Tendsto (fun n => (SimpleFunc.approxOn f fmeas s 0 (hs <| by simp) n).integral μ) atTop (𝓝 <| ∫ x, f x ∂μ) := by apply tendsto_integral_approxOn_of_measurable hf fmeas _ _ (integrable_zero _ _ _) - exact eventually_of_forall fun x => subset_closure (hs (Set.mem_union_left _ (mem_range_self _))) + exact Eventually.of_forall fun x => subset_closure (hs (Set.mem_union_left _ (mem_range_self _))) -- We redeclare `E` here to temporarily avoid -- the `[CompleteSpace E]` and `[NormedSpace ℝ E]` instances. @@ -1468,6 +1468,13 @@ theorem integral_zero_measure {m : MeasurableSpace α} (f : α → G) : exact setToFun_measure_zero (dominatedFinMeasAdditive_weightedSMul _) rfl · simp [integral, hG] +@[simp] +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 @@ -1661,11 +1668,11 @@ theorem integral_mul_norm_le_Lp_mul_Lq {E} [NormedAddCommGroup E] {f g : α → rw [integral_eq_lintegral_of_nonneg_ae, integral_eq_lintegral_of_nonneg_ae, integral_eq_lintegral_of_nonneg_ae] rotate_left - · exact eventually_of_forall fun x => Real.rpow_nonneg (norm_nonneg _) _ + · exact Eventually.of_forall fun x => Real.rpow_nonneg (norm_nonneg _) _ · exact (hg.1.norm.aemeasurable.pow aemeasurable_const).aestronglyMeasurable - · exact eventually_of_forall fun x => Real.rpow_nonneg (norm_nonneg _) _ + · exact Eventually.of_forall fun x => Real.rpow_nonneg (norm_nonneg _) _ · exact (hf.1.norm.aemeasurable.pow aemeasurable_const).aestronglyMeasurable - · exact eventually_of_forall fun x => mul_nonneg (norm_nonneg _) (norm_nonneg _) + · exact Eventually.of_forall fun x => mul_nonneg (norm_nonneg _) (norm_nonneg _) · exact hf.1.norm.mul hg.1.norm rw [ENNReal.toReal_rpow, ENNReal.toReal_rpow, ← ENNReal.toReal_mul] -- replace norms by nnnorm @@ -1830,12 +1837,12 @@ theorem integral_trim (hm : m ≤ m0) {f : β → G} (hf : StronglyMeasurable[m] have hf_seq_eq : ∀ n, ∫ x, f_seq n x ∂μ = ∫ x, f_seq n x ∂μ.trim hm := fun n => integral_trim_simpleFunc hm (f_seq n) (hf_seq_int n) have h_lim_1 : atTop.Tendsto (fun n => ∫ x, f_seq n x ∂μ) (𝓝 (∫ x, f x ∂μ)) := by - refine tendsto_integral_of_L1 f hf_int (eventually_of_forall hf_seq_int) ?_ + refine tendsto_integral_of_L1 f hf_int (Eventually.of_forall hf_seq_int) ?_ exact SimpleFunc.tendsto_approxOn_range_L1_nnnorm (hf.mono hm).measurable hf_int have h_lim_2 : atTop.Tendsto (fun n => ∫ x, f_seq n x ∂μ) (𝓝 (∫ x, f x ∂μ.trim hm)) := by simp_rw [hf_seq_eq] refine @tendsto_integral_of_L1 β G _ _ m (μ.trim hm) _ f (hf_int.trim hm hf) _ _ - (eventually_of_forall hf_seq_int_m) ?_ + (Eventually.of_forall hf_seq_int_m) ?_ exact @SimpleFunc.tendsto_approxOn_range_L1_nnnorm β G m _ _ _ f _ _ hf.measurable (hf_int.trim hm hf) exact tendsto_nhds_unique h_lim_1 h_lim_2 @@ -1958,3 +1965,5 @@ def evalIntegral : PositivityExt where eval {u α} zα pα e := do | _ => throwError "not MeasureTheory.integral" end Mathlib.Meta.Positivity + +set_option linter.style.longFile 2100 diff --git a/Mathlib/MeasureTheory/Integral/BoundedContinuousFunction.lean b/Mathlib/MeasureTheory/Integral/BoundedContinuousFunction.lean index 1a10dec86151f..326da6df177b3 100644 --- a/Mathlib/MeasureTheory/Integral/BoundedContinuousFunction.lean +++ b/Mathlib/MeasureTheory/Integral/BoundedContinuousFunction.lean @@ -64,7 +64,7 @@ theorem toReal_lintegral_coe_eq_integral [OpensMeasurableSpace X] (f : X →ᵇ rw [integral_eq_lintegral_of_nonneg_ae _ (by simpa [Function.comp_apply] using (NNReal.continuous_coe.comp f.continuous).measurable.aestronglyMeasurable)] · simp only [ENNReal.ofReal_coe_nnreal] - · exact eventually_of_forall (by simp only [Pi.zero_apply, NNReal.zero_le_coe, imp_true_iff]) + · exact Eventually.of_forall (by simp only [Pi.zero_apply, NNReal.zero_le_coe, imp_true_iff]) end NNRealValued @@ -87,7 +87,7 @@ lemma integrable [IsFiniteMeasure μ] (f : X →ᵇ E) : refine ⟨f.continuous.measurable.aestronglyMeasurable, (hasFiniteIntegral_def _ _).mp ?_⟩ calc ∫⁻ x, ‖f x‖₊ ∂μ _ ≤ ‖f‖₊ * (μ Set.univ) := f.lintegral_nnnorm_le μ - _ < ∞ := ENNReal.mul_lt_top ENNReal.coe_ne_top (measure_ne_top μ Set.univ) + _ < ∞ := ENNReal.mul_lt_top ENNReal.coe_lt_top (measure_lt_top μ Set.univ) variable [NormedSpace ℝ E] @@ -142,8 +142,8 @@ lemma tendsto_integral_of_forall_limsup_integral_le_integral {ι : Type*} {L : F rcases eq_or_neBot L with rfl|hL · simp only [tendsto_bot] have obs := BoundedContinuousFunction.isBounded_range_integral μs f - have bdd_above : IsBoundedUnder (· ≤ ·) L (fun i ↦ ∫ x, f x ∂μs i) := obs.bddAbove.isBoundedUnder - have bdd_below : IsBoundedUnder (· ≥ ·) L (fun i ↦ ∫ x, f x ∂μs i) := obs.bddBelow.isBoundedUnder + have bdd_above := BddAbove.isBoundedUnder L.univ_mem (by simpa using obs.bddAbove) + have bdd_below := BddBelow.isBoundedUnder L.univ_mem (by simpa using obs.bddBelow) apply tendsto_of_le_liminf_of_limsup_le _ _ bdd_above bdd_below · have key := h _ (f.norm_sub_nonneg) simp_rw [f.integral_const_sub ‖f‖] at key @@ -164,8 +164,8 @@ lemma tendsto_integral_of_forall_integral_le_liminf_integral {ι : Type*} {L : F rcases eq_or_neBot L with rfl|hL · simp only [tendsto_bot] have obs := BoundedContinuousFunction.isBounded_range_integral μs f - have bdd_above : IsBoundedUnder (· ≤ ·) L (fun i ↦ ∫ x, f x ∂μs i) := obs.bddAbove.isBoundedUnder - have bdd_below : IsBoundedUnder (· ≥ ·) L (fun i ↦ ∫ x, f x ∂μs i) := obs.bddBelow.isBoundedUnder + have bdd_above := BddAbove.isBoundedUnder L.univ_mem (by simpa using obs.bddAbove) + have bdd_below := BddBelow.isBoundedUnder L.univ_mem (by simpa using obs.bddBelow) apply @tendsto_of_le_liminf_of_limsup_le ℝ ι _ _ _ L (fun i ↦ ∫ x, f x ∂ (μs i)) (∫ x, f x ∂μ) · have key := h _ (f.add_norm_nonneg) simp_rw [f.integral_add_const ‖f‖] at key diff --git a/Mathlib/MeasureTheory/Integral/CircleIntegral.lean b/Mathlib/MeasureTheory/Integral/CircleIntegral.lean index a2409b3431d6b..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 => @@ -362,7 +362,7 @@ theorem norm_two_pi_i_inv_smul_integral_le_of_norm_le_const {f : ℂ → E} {c : (hR : 0 ≤ R) (hf : ∀ z ∈ sphere c R, ‖f z‖ ≤ C) : ‖(2 * π * I : ℂ)⁻¹ • ∮ z in C(c, R), f z‖ ≤ R * C := by have : ‖(2 * π * I : ℂ)⁻¹‖ = (2 * π)⁻¹ := by simp [Real.pi_pos.le] - rw [norm_smul, this, ← div_eq_inv_mul, div_le_iff Real.two_pi_pos, mul_comm (R * C), ← mul_assoc] + rw [norm_smul, this, ← div_eq_inv_mul, div_le_iff₀ Real.two_pi_pos, mul_comm (R * C), ← mul_assoc] exact norm_integral_le_of_norm_le_const hR hf /-- If `f` is continuous on the circle `|z - c| = R`, `R > 0`, the `‖f z‖` is less than or equal to @@ -532,10 +532,10 @@ theorem hasSum_two_pi_I_cauchyPowerSeries_integral {f : ℂ → E} {c : ℂ} {R · fun_prop · fun_prop · simp [norm_smul, abs_of_pos hR, mul_left_comm R, inv_mul_cancel_left₀ hR.ne', mul_comm ‖_‖] - · exact eventually_of_forall fun _ _ => (summable_geometric_of_lt_one hwR.1 hwR.2).mul_left _ + · exact Eventually.of_forall fun _ _ => (summable_geometric_of_lt_one hwR.1 hwR.2).mul_left _ · simpa only [tsum_mul_left, tsum_geometric_of_lt_one hwR.1 hwR.2] using hf.norm.mul_continuousOn continuousOn_const - · refine eventually_of_forall fun θ _ => HasSum.const_smul _ ?_ + · refine Eventually.of_forall fun θ _ => HasSum.const_smul _ ?_ simp only [smul_smul] refine HasSum.smul_const ?_ _ have : ‖w / (circleMap c R θ - c)‖ < 1 := by simpa [abs_of_pos hR] using hwR.2 diff --git a/Mathlib/MeasureTheory/Integral/DivergenceTheorem.lean b/Mathlib/MeasureTheory/Integral/DivergenceTheorem.lean index bdd921a649991..2280f163883e0 100644 --- a/Mathlib/MeasureTheory/Integral/DivergenceTheorem.lean +++ b/Mathlib/MeasureTheory/Integral/DivergenceTheorem.lean @@ -170,7 +170,7 @@ theorem integral_divergence_of_hasFDerivWithinAt_off_countable_aux₂ (I : Box ( exact tendsto_setIntegral_of_monotone (fun k => (J k).measurableSet_Ioo) (Box.Ioo.comp J).monotone Hi -- Thus it suffices to prove the same about the RHS. - refine tendsto_nhds_unique_of_eventuallyEq hI_tendsto ?_ (eventually_of_forall HJ_eq) + refine tendsto_nhds_unique_of_eventuallyEq hI_tendsto ?_ (Eventually.of_forall HJ_eq) clear hI_tendsto rw [tendsto_pi_nhds] at hJl hJu /- We'll need to prove a similar statement about the integrals over the front sides and the @@ -187,7 +187,7 @@ theorem integral_divergence_of_hasFDerivWithinAt_off_countable_aux₂ (I : Box ( /- First we prove that the integrals of the restriction of `f` to `{x | x i = d}` over increasing boxes `((J k).face i).Icc` tend to the desired limit. The proof mostly repeats the one above. -/ have hd : d ∈ Icc (I.lower i) (I.upper i) := - isClosed_Icc.mem_of_tendsto hcd (eventually_of_forall hc) + isClosed_Icc.mem_of_tendsto hcd (Eventually.of_forall hc) have Hic : ∀ k, IntegrableOn (fun x => f (i.insertNth (c k) x) i) (Box.Icc (I.face i)) := fun k => (Box.continuousOn_face_Icc ((continuous_apply i).comp_continuousOn Hc) (hc k)).integrableOn_Icc have Hid : IntegrableOn (fun x => f (i.insertNth d x) i) (Box.Icc (I.face i)) := @@ -236,7 +236,7 @@ theorem integral_divergence_of_hasFDerivWithinAt_off_countable_aux₂ (I : Box ( exact max_le hk.le δpos.lt.le _ ≤ ε := by rw [Box.Icc_def, Real.volume_Icc_pi_toReal ((J k).face i).lower_le_upper, - ← le_div_iff (hvol_pos _)] + ← le_div_iff₀ (hvol_pos _)] gcongr exacts [hvol_pos _, fun _ _ ↦ sub_nonneg.2 (Box.lower_le_upper _ _), (hJ_sub' _ (J _).upper_mem_Icc).2 _, (hJ_sub' _ (J _).lower_mem_Icc).1 _] @@ -350,7 +350,7 @@ theorem integral_divergence_of_hasFDerivWithinAt_off_countable_of_equiv {F : Typ simpa only [Set.mem_preimage, eL.apply_symm_apply, ← pi_univ_Icc, interior_pi_set (@finite_univ (Fin _) _), interior_Icc] using hx.1 · rw [← he_vol.integrableOn_comp_preimage he_emb, hIcc] - simp [← hDF, (· ∘ ·), Hi] + simp [← hDF, Function.comp_def, Hi] end diff --git a/Mathlib/MeasureTheory/Integral/DominatedConvergence.lean b/Mathlib/MeasureTheory/Integral/DominatedConvergence.lean index 50035d3ae4173..7dc0c8c165627 100644 --- a/Mathlib/MeasureTheory/Integral/DominatedConvergence.lean +++ b/Mathlib/MeasureTheory/Integral/DominatedConvergence.lean @@ -93,7 +93,7 @@ theorem hasSum_integral_of_dominated_convergence {ι} [Countable ι] {F : ι → simp only [HasSum, ← integral_finset_sum _ fun n _ => hF_integrable n] refine tendsto_integral_filter_of_dominated_convergence (fun a => ∑' n, bound n a) ?_ ?_ bound_integrable h_lim - · exact eventually_of_forall fun s => s.aestronglyMeasurable_sum fun n _ => hF_meas n + · exact Eventually.of_forall fun s => s.aestronglyMeasurable_sum fun n _ => hF_meas n · filter_upwards with s filter_upwards [eventually_countable_forall.2 h_bound, hb_nonneg, bound_summable] with a hFa ha0 has @@ -177,7 +177,7 @@ theorem _root_.Antitone.tendsto_setIntegral (hsm : ∀ i, MeasurableSet (s i)) ( · rw [integrable_indicator_iff (hsm 0)] exact hfi.norm · simp_rw [norm_indicator_eq_indicator_norm] - refine fun n => eventually_of_forall fun x => ?_ + refine fun n => Eventually.of_forall fun x => ?_ exact indicator_le_indicator_of_subset (h_anti (zero_le n)) (fun a => norm_nonneg _) _ · filter_upwards [] with a using le_trans (h_anti.tendsto_indicator _ _ _) (pure_le_nhds _) @@ -255,8 +255,8 @@ variable {X : Type*} [TopologicalSpace X] [FirstCountableTopology X] /-- Continuity of interval integral with respect to a parameter, at a point within a set. Given `F : X → ℝ → E`, assume `F x` is ae-measurable on `[a, b]` for `x` in a - neighborhood of `x₀` within `s` and at `x₀`, and assume it is bounded by a function integrable - on `[a, b]` independent of `x` in a neighborhood of `x₀` within `s`. If `(fun x ↦ F x t)` + neighborhood of `x₀` within `s` and at `x₀`, and assume it is bounded by a function integrable + on `[a, b]` independent of `x` in a neighborhood of `x₀` within `s`. If `(fun x ↦ F x t)` is continuous at `x₀` within `s` for almost every `t` in `[a, b]` then the same holds for `(fun x ↦ ∫ t in a..b, F x t ∂μ) s x₀`. -/ theorem continuousWithinAt_of_dominated_interval {F : X → ℝ → E} {x₀ : X} {bound : ℝ → ℝ} {a b : ℝ} @@ -293,7 +293,7 @@ theorem continuous_of_dominated_interval {F : X → ℝ → E} {bound : ℝ → (h_cont : ∀ᵐ t ∂μ, t ∈ Ι a b → Continuous fun x => F x t) : Continuous fun x => ∫ t in a..b, F x t ∂μ := continuous_iff_continuousAt.mpr fun _ => - continuousAt_of_dominated_interval (eventually_of_forall hF_meas) (eventually_of_forall h_bound) + continuousAt_of_dominated_interval (Eventually.of_forall hF_meas) (Eventually.of_forall h_bound) bound_integrable <| h_cont.mono fun _ himp hx => (himp hx).continuousAt @@ -395,7 +395,7 @@ theorem continuousAt_parametric_primitive_of_dominated [FirstCountableTopology X have hiF : ∀ {x a₀ b₀}, (∀ᵐ t : ℝ ∂μ.restrict (Ι a b), ‖F x t‖ ≤ bound t) → a₀ ∈ Ioo a b → b₀ ∈ Ioo a b → IntervalIntegrable (F x) μ a₀ b₀ := fun {x a₀ b₀} hx ha₀ hb₀ ↦ - (bound_integrable.mono_set_ae <| eventually_of_forall <| hsub ha₀ hb₀).mono_fun' + (bound_integrable.mono_set_ae <| Eventually.of_forall <| hsub ha₀ hb₀).mono_fun' ((hF_meas x).mono_set <| hsub ha₀ hb₀) (ae_restrict_of_ae_restrict_of_subset (hsub ha₀ hb₀) hx) rw [intervalIntegral.integral_sub, add_assoc, add_sub_cancel, @@ -407,10 +407,10 @@ theorem continuousAt_parametric_primitive_of_dominated [FirstCountableTopology X rw [continuousAt_congr this]; clear this refine (ContinuousAt.add ?_ ?_).add ?_ · exact (intervalIntegral.continuousAt_of_dominated_interval - (eventually_of_forall fun x ↦ (hF_meas x).mono_set <| hsub ha₀ hb₀) + (Eventually.of_forall fun x ↦ (hF_meas x).mono_set <| hsub ha₀ hb₀) (h_bound.mono fun x hx ↦ ae_imp_of_ae_restrict <| ae_restrict_of_ae_restrict_of_subset (hsub ha₀ hb₀) hx) - (bound_integrable.mono_set_ae <| eventually_of_forall <| hsub ha₀ hb₀) <| + (bound_integrable.mono_set_ae <| Eventually.of_forall <| hsub ha₀ hb₀) <| ae_imp_of_ae_restrict <| ae_restrict_of_ae_restrict_of_subset (hsub ha₀ hb₀) h_cont).fst' · refine (?_ : ContinuousAt (fun t ↦ ∫ s in b₀..t, F x₀ s ∂μ) b₀).snd' apply ContinuousWithinAt.continuousAt _ (Icc_mem_nhds hb₀.1 hb₀.2) @@ -577,17 +577,17 @@ theorem continuous_parametric_primitive_of_continuous gcongr · apply setIntegral_mono_set · exact (hf.uncurry_left _).norm.integrableOn_Icc - · exact eventually_of_forall (fun x ↦ norm_nonneg _) + · exact Eventually.of_forall (fun x ↦ norm_nonneg _) · have : Ι b₀ s ⊆ Icc (b₀ - δ) (b₀ + δ) := by apply uIoc_subset_uIcc.trans (uIcc_subset_Icc ?_ ⟨hs.1.le, hs.2.le⟩ ) simp [δpos.le] - exact eventually_of_forall this + exact Eventually.of_forall this · apply setIntegral_mono_set · exact ((hf.uncurry_left _).sub (hf.uncurry_left _)).norm.integrableOn_Icc - · exact eventually_of_forall (fun x ↦ norm_nonneg _) + · exact Eventually.of_forall (fun x ↦ norm_nonneg _) · have : Ι a₀ b₀ ⊆ Icc a b := uIoc_subset_uIcc.trans (uIcc_subset_Icc ⟨a_lt.1.le, lt_b.1.le⟩ ⟨a_lt.2.le, lt_b.2.le⟩) - exact eventually_of_forall this + exact Eventually.of_forall this _ ≤ ∫ t in Icc (b₀ - δ) (b₀ + δ), M + 1 ∂μ + ∫ _t in Icc a b, δ ∂μ := by gcongr · apply setIntegral_mono_on diff --git a/Mathlib/MeasureTheory/Integral/FundThmCalculus.lean b/Mathlib/MeasureTheory/Integral/FundThmCalculus.lean index 0ab09a7e17c02..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 /-! @@ -1559,3 +1559,5 @@ theorem integral_deriv_comp_mul_deriv {f f' g g' : ℝ → ℝ} end Mul end intervalIntegral + +set_option linter.style.longFile 1700 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 958b5b34a0ce4..ae1b813c974c1 100644 --- a/Mathlib/MeasureTheory/Integral/IntegrableOn.lean +++ b/Mathlib/MeasureTheory/Integral/IntegrableOn.lean @@ -122,7 +122,7 @@ theorem integrableOn_congr_fun_ae (hst : f =ᵐ[μ.restrict s] g) : theorem IntegrableOn.congr_fun (h : IntegrableOn f s μ) (hst : EqOn f g s) (hs : MeasurableSet s) : IntegrableOn g s μ := - h.congr_fun_ae ((ae_restrict_iff' hs).2 (eventually_of_forall hst)) + h.congr_fun_ae ((ae_restrict_iff' hs).2 (Eventually.of_forall hst)) theorem integrableOn_congr_fun (hst : EqOn f g s) (hs : MeasurableSet s) : IntegrableOn f s μ ↔ IntegrableOn g s μ := @@ -294,7 +294,7 @@ theorem IntegrableOn.of_ae_diff_eq_zero (hf : IntegrableOn f s μ) (ht : NullMea if `t` is measurable. -/ theorem IntegrableOn.of_forall_diff_eq_zero (hf : IntegrableOn f s μ) (ht : MeasurableSet t) (h't : ∀ x ∈ t \ s, f x = 0) : IntegrableOn f t μ := - hf.of_ae_diff_eq_zero ht.nullMeasurableSet (eventually_of_forall h't) + hf.of_ae_diff_eq_zero ht.nullMeasurableSet (Eventually.of_forall h't) /-- If a function is integrable on a set `s` and vanishes almost everywhere on its complement, then it is integrable. -/ @@ -308,7 +308,7 @@ theorem IntegrableOn.integrable_of_ae_not_mem_eq_zero (hf : IntegrableOn f s μ) then it is integrable. -/ theorem IntegrableOn.integrable_of_forall_not_mem_eq_zero (hf : IntegrableOn f s μ) (h't : ∀ x, x ∉ s → f x = 0) : Integrable f μ := - hf.integrable_of_ae_not_mem_eq_zero (eventually_of_forall fun x hx => h't x hx) + hf.integrable_of_ae_not_mem_eq_zero (Eventually.of_forall fun x hx => h't x hx) theorem integrableOn_iff_integrable_of_support_subset (h1s : support f ⊆ s) : IntegrableOn f s μ ↔ Integrable f μ := by @@ -444,7 +444,7 @@ theorem Measure.FiniteAtFilter.integrableAtFilter {l : Filter α} [IsMeasurablyG ⟨s, hsl, hsm, hfm, hμ, hC⟩ refine ⟨s, hsl, ⟨hfm, hasFiniteIntegral_restrict_of_bounded hμ (C := C) ?_⟩⟩ rw [ae_restrict_eq hsm, eventually_inf_principal] - exact eventually_of_forall hC + exact Eventually.of_forall hC theorem Measure.FiniteAtFilter.integrableAtFilter_of_tendsto_ae {l : Filter α} [IsMeasurablyGenerated l] (hfm : StronglyMeasurableAtFilter f l μ) (hμ : μ.FiniteAtFilter l) {b} @@ -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 cbb80865f8332..737247f5c8918 100644 --- a/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean +++ b/Mathlib/MeasureTheory/Integral/IntegralEqImproper.lean @@ -474,8 +474,8 @@ theorem AECover.integral_tendsto_of_countably_generated [l.IsCountablyGenerated] suffices h : Tendsto (fun i => ∫ x : α, (φ i).indicator f x ∂μ) l (𝓝 (∫ x : α, f x ∂μ)) from by 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 i => hfi.aestronglyMeasurable.indicator <| hφ.measurableSet i) + (Eventually.of_forall fun i => ae_of_all _ fun x => norm_indicator_le_norm_self _ _) hfi.norm (hφ.ae_tendsto_indicator f) /-- Slight reformulation of @@ -712,7 +712,7 @@ theorem tendsto_zero_of_hasDerivAt_of_integrableOn_Ioi 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 + exact (Completion.isUniformEmbedding_coe E).embedding variable [CompleteSpace E] @@ -909,7 +909,7 @@ theorem tendsto_zero_of_hasDerivAt_of_integrableOn_Iic rw [← volume_Iic (a := b)] exact measure_mono hb rwa [B, ← Embedding.tendsto_nhds_iff] at A - exact (Completion.uniformEmbedding_coe E).embedding + exact (Completion.isUniformEmbedding_coe E).embedding variable [CompleteSpace E] @@ -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 @@ -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 @@ -1241,7 +1241,7 @@ theorem integral_mul_deriv_eq_deriv_mul [CompleteSpace A] (huv' : Integrable (u * v')) (hu'v : Integrable (u' * v)) (h_bot : Tendsto (u * v) atBot (𝓝 a')) (h_top : Tendsto (u * v) atTop (𝓝 b')) : ∫ (x : ℝ), u x * v' x = b' - a' - ∫ (x : ℝ), u' x * v x := - integral_bilinear_hasDerivAt_right_eq_sub (L := ContinuousLinearMap.mul ℝ A) + integral_bilinear_hasDerivAt_right_eq_sub (L := ContinuousLinearMap.mul ℝ A) hu hv huv' hu'v h_bot h_top /-- **Integration by parts on (-∞, ∞).** diff --git a/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean b/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean index 53d163b674b03..d7473d6e2d8df 100644 --- a/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean +++ b/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean @@ -199,7 +199,7 @@ theorem mono_set_ae (hf : IntervalIntegrable f μ a b) (h : Ι c d ≤ᵐ[μ] Ι theorem mono_set' (hf : IntervalIntegrable f μ a b) (hsub : Ι c d ⊆ Ι a b) : IntervalIntegrable f μ c d := - hf.mono_set_ae <| eventually_of_forall hsub + hf.mono_set_ae <| Eventually.of_forall hsub theorem mono_fun [NormedAddCommGroup F] {g : ℝ → F} (hf : IntervalIntegrable f μ a b) (hgm : AEStronglyMeasurable g (μ.restrict (Ι a b))) @@ -516,7 +516,7 @@ theorem norm_integral_le_of_norm_le_const_ae {a b C : ℝ} {f : ℝ → E} theorem norm_integral_le_of_norm_le_const {a b C : ℝ} {f : ℝ → E} (h : ∀ x ∈ Ι a b, ‖f x‖ ≤ C) : ‖∫ x in a..b, f x‖ ≤ C * |b - a| := - norm_integral_le_of_norm_le_const_ae <| eventually_of_forall h + norm_integral_le_of_norm_le_const_ae <| Eventually.of_forall h @[simp] nonrec theorem integral_add (hf : IntervalIntegrable f μ a b) (hg : IntervalIntegrable g μ a b) : @@ -620,12 +620,7 @@ section Comp variable {a b c d : ℝ} (f : ℝ → E) -/-! -Porting note: some `@[simp]` attributes in this section were removed to make the `simpNF` linter -happy. TODO: find out if these lemmas are actually good or bad `simp` lemmas. --/ - -@[simp] -- Porting note (#10618): was @[simp] +@[simp] 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 := @@ -638,32 +633,32 @@ theorem integral_comp_mul_right (hc : c ≠ 0) : Measure.restrict_congr_set (α := ℝ) (μ := volume) Ico_ae_eq_Ioc] · simp [h, mul_div_cancel_right₀, hc, abs_of_pos] -@[simp] -- Porting note (#10618): was @[simp] +@[simp] theorem smul_integral_comp_mul_right (c) : (c • ∫ x in a..b, f (x * c)) = ∫ x in a * c..b * c, f x := by by_cases hc : c = 0 <;> simp [hc, integral_comp_mul_right] -@[simp] -- Porting note (#10618): was @[simp] +@[simp] theorem integral_comp_mul_left (hc : c ≠ 0) : (∫ x in a..b, f (c * x)) = c⁻¹ • ∫ x in c * a..c * b, f x := by simpa only [mul_comm c] using integral_comp_mul_right f hc -@[simp] -- Porting note (#10618): was @[simp] +@[simp] theorem smul_integral_comp_mul_left (c) : (c • ∫ x in a..b, f (c * x)) = ∫ x in c * a..c * b, f x := by by_cases hc : c = 0 <;> simp [hc, integral_comp_mul_left] -@[simp] -- Porting note (#10618): was @[simp] +@[simp] theorem integral_comp_div (hc : c ≠ 0) : (∫ x in a..b, f (x / c)) = c • ∫ x in a / c..b / c, f x := by simpa only [inv_inv] using integral_comp_mul_right f (inv_ne_zero hc) -@[simp] -- Porting note (#10618): was @[simp] +@[simp] theorem inv_smul_integral_comp_div (c) : (c⁻¹ • ∫ x in a..b, f (x / c)) = ∫ x in a / c..b / c, f x := by by_cases hc : c = 0 <;> simp [hc, integral_comp_div] -@[simp] -- Porting note (#10618): was @[simp] +@[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 @@ -672,102 +667,102 @@ theorem integral_comp_add_right (d) : (∫ x in a..b, f (x + d)) = ∫ x in a + simp [intervalIntegral, A.setIntegral_map] _ = ∫ x in a + d..b + d, f x := by rw [map_add_right_eq_self] -@[simp] -- Porting note (#10618): was @[simp] +@[simp] nonrec theorem integral_comp_add_left (d) : (∫ x in a..b, f (d + x)) = ∫ x in d + a..d + b, f x := by simpa only [add_comm d] using integral_comp_add_right f d -@[simp] -- Porting note (#10618): was @[simp] +@[simp] theorem integral_comp_mul_add (hc : c ≠ 0) (d) : (∫ x in a..b, f (c * x + d)) = c⁻¹ • ∫ x in c * a + d..c * b + d, f x := by rw [← integral_comp_add_right, ← integral_comp_mul_left _ hc] -@[simp] -- Porting note (#10618): was @[simp] +@[simp] theorem smul_integral_comp_mul_add (c d) : (c • ∫ x in a..b, f (c * x + d)) = ∫ x in c * a + d..c * b + d, f x := by by_cases hc : c = 0 <;> simp [hc, integral_comp_mul_add] -@[simp] -- Porting note (#10618): was @[simp] +@[simp] theorem integral_comp_add_mul (hc : c ≠ 0) (d) : (∫ x in a..b, f (d + c * x)) = c⁻¹ • ∫ x in d + c * a..d + c * b, f x := by rw [← integral_comp_add_left, ← integral_comp_mul_left _ hc] --- Porting note (#10618): was @[simp] +@[simp] theorem smul_integral_comp_add_mul (c d) : (c • ∫ x in a..b, f (d + c * x)) = ∫ x in d + c * a..d + c * b, f x := by by_cases hc : c = 0 <;> simp [hc, integral_comp_add_mul] --- Porting note (#10618): was @[simp] +@[simp] theorem integral_comp_div_add (hc : c ≠ 0) (d) : (∫ x in a..b, f (x / c + d)) = c • ∫ x in a / c + d..b / c + d, f x := by simpa only [div_eq_inv_mul, inv_inv] using integral_comp_mul_add f (inv_ne_zero hc) d --- Porting note (#10618): was @[simp] +@[simp] theorem inv_smul_integral_comp_div_add (c d) : (c⁻¹ • ∫ x in a..b, f (x / c + d)) = ∫ x in a / c + d..b / c + d, f x := by by_cases hc : c = 0 <;> simp [hc, integral_comp_div_add] --- Porting note (#10618): was @[simp] +@[simp] theorem integral_comp_add_div (hc : c ≠ 0) (d) : (∫ x in a..b, f (d + x / c)) = c • ∫ x in d + a / c..d + b / c, f x := by simpa only [div_eq_inv_mul, inv_inv] using integral_comp_add_mul f (inv_ne_zero hc) d --- Porting note (#10618): was @[simp] +@[simp] theorem inv_smul_integral_comp_add_div (c d) : (c⁻¹ • ∫ x in a..b, f (d + x / c)) = ∫ x in d + a / c..d + b / c, f x := by by_cases hc : c = 0 <;> simp [hc, integral_comp_add_div] --- Porting note (#10618): was @[simp] +@[simp] theorem integral_comp_mul_sub (hc : c ≠ 0) (d) : (∫ x in a..b, f (c * x - d)) = c⁻¹ • ∫ x in c * a - d..c * b - d, f x := by simpa only [sub_eq_add_neg] using integral_comp_mul_add f hc (-d) --- Porting note (#10618): was @[simp] +@[simp] theorem smul_integral_comp_mul_sub (c d) : (c • ∫ x in a..b, f (c * x - d)) = ∫ x in c * a - d..c * b - d, f x := by by_cases hc : c = 0 <;> simp [hc, integral_comp_mul_sub] --- Porting note (#10618): was @[simp] +@[simp] theorem integral_comp_sub_mul (hc : c ≠ 0) (d) : (∫ x in a..b, f (d - c * x)) = c⁻¹ • ∫ x in d - c * b..d - c * a, f x := by simp only [sub_eq_add_neg, neg_mul_eq_neg_mul] rw [integral_comp_add_mul f (neg_ne_zero.mpr hc) d, integral_symm] simp only [inv_neg, smul_neg, neg_neg, neg_smul] --- Porting note (#10618): was @[simp] +@[simp] theorem smul_integral_comp_sub_mul (c d) : (c • ∫ x in a..b, f (d - c * x)) = ∫ x in d - c * b..d - c * a, f x := by by_cases hc : c = 0 <;> simp [hc, integral_comp_sub_mul] --- Porting note (#10618): was @[simp] +@[simp] theorem integral_comp_div_sub (hc : c ≠ 0) (d) : (∫ x in a..b, f (x / c - d)) = c • ∫ x in a / c - d..b / c - d, f x := by simpa only [div_eq_inv_mul, inv_inv] using integral_comp_mul_sub f (inv_ne_zero hc) d --- Porting note (#10618): was @[simp] +@[simp] theorem inv_smul_integral_comp_div_sub (c d) : (c⁻¹ • ∫ x in a..b, f (x / c - d)) = ∫ x in a / c - d..b / c - d, f x := by by_cases hc : c = 0 <;> simp [hc, integral_comp_div_sub] --- Porting note (#10618): was @[simp] +@[simp] theorem integral_comp_sub_div (hc : c ≠ 0) (d) : (∫ x in a..b, f (d - x / c)) = c • ∫ x in d - b / c..d - a / c, f x := by simpa only [div_eq_inv_mul, inv_inv] using integral_comp_sub_mul f (inv_ne_zero hc) d --- Porting note (#10618): was @[simp] +@[simp] theorem inv_smul_integral_comp_sub_div (c d) : (c⁻¹ • ∫ x in a..b, f (d - x / c)) = ∫ x in d - b / c..d - a / c, f x := by by_cases hc : c = 0 <;> simp [hc, integral_comp_sub_div] --- Porting note (#10618): was @[simp] +@[simp] theorem integral_comp_sub_right (d) : (∫ x in a..b, f (x - d)) = ∫ x in a - d..b - d, f x := by simpa only [sub_eq_add_neg] using integral_comp_add_right f (-d) --- Porting note (#10618): was @[simp] +@[simp] theorem integral_comp_sub_left (d) : (∫ x in a..b, f (d - x)) = ∫ x in d - b..d - a, f x := by simpa only [one_mul, one_smul, inv_one] using integral_comp_sub_mul f one_ne_zero d --- Porting note (#10618): was @[simp] +@[simp] theorem integral_comp_neg : (∫ x in a..b, f (-x)) = ∫ x in -b..-a, f x := by simpa only [zero_sub] using integral_comp_sub_left f 0 @@ -883,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 @@ -941,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 @@ -1004,7 +999,7 @@ theorem integral_lt_integral_of_continuousOn_of_le_of_exists_lt {f g : ℝ → have h_eq : f =ᵐ[volume.restrict (Ioc a b)] g := by simp only [← not_le, ← ae_iff] at hlt exact EventuallyLE.antisymm ((ae_restrict_iff' measurableSet_Ioc).2 <| - eventually_of_forall hle) hlt + Eventually.of_forall hle) hlt rw [Measure.restrict_congr_set Ioc_ae_eq_Icc] at h_eq exact fun c hc ↦ (Measure.eqOn_Icc_of_ae_eq volume hab.ne h_eq hfc hgc hc).ge @@ -1017,7 +1012,7 @@ theorem integral_nonneg_of_ae (hab : a ≤ b) (hf : 0 ≤ᵐ[μ] f) : 0 ≤ ∫ integral_nonneg_of_ae_restrict hab <| ae_restrict_of_ae hf theorem integral_nonneg_of_forall (hab : a ≤ b) (hf : ∀ u, 0 ≤ f u) : 0 ≤ ∫ u in a..b, f u ∂μ := - integral_nonneg_of_ae hab <| eventually_of_forall hf + integral_nonneg_of_ae hab <| Eventually.of_forall hf theorem integral_nonneg (hab : a ≤ b) (hf : ∀ u, u ∈ Icc a b → 0 ≤ f u) : 0 ≤ ∫ u in a..b, f u ∂μ := integral_nonneg_of_ae_restrict hab <| (ae_restrict_iff' measurableSet_Icc).mpr <| ae_of_all μ hf @@ -1026,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) diff --git a/Mathlib/MeasureTheory/Integral/Layercake.lean b/Mathlib/MeasureTheory/Integral/Layercake.lean index 9c055c3e3bd82..ccdbcf47487ab 100644 --- a/Mathlib/MeasureTheory/Integral/Layercake.lean +++ b/Mathlib/MeasureTheory/Integral/Layercake.lean @@ -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 @@ -237,7 +237,7 @@ theorem lintegral_comp_eq_lintegral_meas_le_mul_of_measurable (μ : Measure α) exact fun a ha ↦ hx.2.trans (le_of_lt ha) _ ≤ ∫⁻ t in Ioi 0, μ {a : α | t ≤ f a} * ENNReal.ofReal (g t) := lintegral_mono_set Ioc_subset_Ioi_self - /- The second integral is infinite, as one integrates amont other things on those `ω` where + /- The second integral is infinite, as one integrates among other things on those `ω` where `f ω > s`: this is an infinite measure set, and on it the integrand is bounded below by `∫ t in 0..s, g t` which is positive. -/ have B : ∫⁻ ω, ENNReal.ofReal (∫ t in (0)..f ω, g t) ∂μ = ∞ := by @@ -343,7 +343,7 @@ theorem lintegral_comp_eq_lintegral_meas_le_mul_of_measurable (μ : Measure α) have meas : MeasurableSet {a | M < f a} := measurableSet_lt measurable_const f_mble have I : ∫⁻ ω in {a | M < f a}ᶜ, ENNReal.ofReal (∫ t in (0).. f ω, g t) ∂μ = ∫⁻ _ in {a | M < f a}ᶜ, 0 ∂μ := by - apply setLIntegral_congr_fun meas.compl (eventually_of_forall (fun s hs ↦ ?_)) + apply setLIntegral_congr_fun meas.compl (Eventually.of_forall (fun s hs ↦ ?_)) have : ∫ (t : ℝ) in (0)..f s, g t = ∫ (t : ℝ) in (0)..f s, 0 := by simp_rw [intervalIntegral.integral_of_le (f_nonneg s)] apply integral_congr_ae @@ -364,7 +364,7 @@ theorem lintegral_comp_eq_lintegral_meas_le_mul_of_measurable (μ : Measure α) simp [ht] have B2 : ∫⁻ t in Ioi M, μ {a : α | t ≤ f a} * ENNReal.ofReal (g t) = ∫⁻ t in Ioi M, ν {a : α | t ≤ f a} * ENNReal.ofReal (g t) := by - apply setLIntegral_congr_fun measurableSet_Ioi (eventually_of_forall (fun t ht ↦ ?_)) + apply setLIntegral_congr_fun measurableSet_Ioi (Eventually.of_forall (fun t ht ↦ ?_)) rw [Measure.restrict_apply (measurableSet_le measurable_const f_mble)] congr 3 exact (inter_eq_left.2 (fun a ha ↦ (mem_Ioi.1 ht).trans_le ha)).symm @@ -448,7 +448,7 @@ theorem lintegral_eq_lintegral_meas_le (μ : Measure α) (f_nn : 0 ≤ᵐ[μ] f) intervalIntegrable_const have key := lintegral_comp_eq_lintegral_meas_le_mul μ f_nn f_mble cst_intble - (eventually_of_forall fun _ => zero_le_one) + (Eventually.of_forall fun _ => zero_le_one) simp_rw [cst, ENNReal.ofReal_one, mul_one] at key rw [← key] congr with ω @@ -528,9 +528,9 @@ theorem Integrable.integral_eq_integral_meas_lt (fun t ↦ ENNReal.toReal (μ {a : α | t < f a})) ?_ ?_ · rw [aux] congr 1 - apply setLIntegral_congr_fun measurableSet_Ioi (eventually_of_forall _) + apply setLIntegral_congr_fun measurableSet_Ioi (Eventually.of_forall _) exact fun t t_pos ↦ ENNReal.ofReal_toReal (rhs_integrand_finite t t_pos).ne - · exact eventually_of_forall (fun x ↦ by simp only [Pi.zero_apply, ENNReal.toReal_nonneg]) + · exact Eventually.of_forall (fun x ↦ by simp only [Pi.zero_apply, ENNReal.toReal_nonneg]) · apply Measurable.aestronglyMeasurable refine Measurable.ennreal_toReal ?_ exact Antitone.measurable (fun _ _ hst ↦ measure_mono (fun _ h ↦ lt_of_le_of_lt hst h)) @@ -548,8 +548,8 @@ 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 ?_] - apply eventually_of_forall (fun t ht ↦ ?_) + 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 rw [measure_zero_iff_ae_nmem] diff --git a/Mathlib/MeasureTheory/Integral/Lebesgue.lean b/Mathlib/MeasureTheory/Integral/Lebesgue.lean index 78b990a4b3679..184a66e158c30 100644 --- a/Mathlib/MeasureTheory/Integral/Lebesgue.lean +++ b/Mathlib/MeasureTheory/Integral/Lebesgue.lean @@ -146,7 +146,7 @@ alias set_lintegral_one := setLIntegral_one theorem setLIntegral_const_lt_top [IsFiniteMeasure μ] (s : Set α) {c : ℝ≥0∞} (hc : c ≠ ∞) : ∫⁻ _ in s, c ∂μ < ∞ := by rw [lintegral_const] - exact ENNReal.mul_lt_top hc (measure_ne_top (μ.restrict s) univ) + exact ENNReal.mul_lt_top hc.lt_top (measure_lt_top (μ.restrict s) univ) @[deprecated (since := "2024-06-29")] alias set_lintegral_const_lt_top := setLIntegral_const_lt_top @@ -339,7 +339,7 @@ theorem lintegral_nnnorm_eq_of_ae_nonneg {f : α → ℝ} (h_nonneg : 0 ≤ᵐ[ theorem lintegral_nnnorm_eq_of_nonneg {f : α → ℝ} (h_nonneg : 0 ≤ f) : ∫⁻ x, ‖f x‖₊ ∂μ = ∫⁻ x, ENNReal.ofReal (f x) ∂μ := - lintegral_nnnorm_eq_of_ae_nonneg (Filter.eventually_of_forall h_nonneg) + lintegral_nnnorm_eq_of_ae_nonneg (Filter.Eventually.of_forall h_nonneg) /-- **Monotone convergence theorem** -- sometimes called **Beppo-Levi convergence**. See `lintegral_iSup_directed` for a more general form. -/ @@ -358,7 +358,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 +385,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 _ * μ ?_ @@ -476,7 +475,7 @@ theorem exists_pos_setLIntegral_lt_of_measure_lt {f : α → ℝ≥0∞} (h : exact SimpleFunc.lintegral_mono le_rfl Measure.restrict_le_self _ ≤ (SimpleFunc.const α (C : ℝ≥0∞)).lintegral (μ.restrict s) + ε₁ := by gcongr - exact SimpleFunc.lintegral_mono (fun x ↦ ENNReal.coe_le_coe.2 (hC x)) le_rfl + exact fun x ↦ ENNReal.coe_le_coe.2 (hC x) _ = C * μ s + ε₁ := by simp only [← SimpleFunc.lintegral_eq_lintegral, coe_const, lintegral_const, Measure.restrict_apply, MeasurableSet.univ, univ_inter, Function.const] @@ -531,7 +530,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 _ @@ -766,12 +765,21 @@ theorem lintegral_indicator (f : α → ℝ≥0∞) {s : Set α} (hs : Measurabl refine ⟨⟨φ.restrict s, fun x => ?_⟩, le_rfl⟩ simp [hφ x, hs, indicator_le_indicator] +lemma setLIntegral_indicator (f : α → ℝ≥0∞) {s t : Set α} (hs : MeasurableSet s) : + ∫⁻ 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₀ (f : α → ℝ≥0∞) {s : Set α} (hs : NullMeasurableSet s μ) : ∫⁻ 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 _ _), 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 @@ -861,6 +869,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 <| @@ -918,6 +933,15 @@ theorem lintegral_eq_zero_iff' {f : α → ℝ≥0∞} (hf : AEMeasurable f μ) theorem lintegral_eq_zero_iff {f : α → ℝ≥0∞} (hf : Measurable f) : ∫⁻ a, f a ∂μ = 0 ↔ f =ᵐ[μ] 0 := lintegral_eq_zero_iff' hf.aemeasurable +theorem setLIntegral_eq_zero_iff' {s : Set α} (hs : MeasurableSet s) + {f : α → ℝ≥0∞} (hf : AEMeasurable f (μ.restrict s)) : + ∫⁻ a in s, f a ∂μ = 0 ↔ ∀ᵐ x ∂μ, x ∈ s → f x = 0 := + (lintegral_eq_zero_iff' hf).trans (ae_restrict_iff' hs) + +theorem setLIntegral_eq_zero_iff {s : Set α} (hs : MeasurableSet s) {f : α → ℝ≥0∞} + (hf : Measurable f) : ∫⁻ a in s, f a ∂μ = 0 ↔ ∀ᵐ x ∂μ, x ∈ s → f x = 0 := + setLIntegral_eq_zero_iff' hs hf.aemeasurable + theorem lintegral_pos_iff_support {f : α → ℝ≥0∞} (hf : Measurable f) : (0 < ∫⁻ a, f a ∂μ) ↔ 0 < μ (Function.support f) := by simp [pos_iff_ne_zero, hf, Filter.EventuallyEq, ae_iff, Function.support] @@ -926,7 +950,7 @@ theorem setLintegral_pos_iff {f : α → ℝ≥0∞} (hf : Measurable f) {s : Se 0 < ∫⁻ a in s, f a ∂μ ↔ 0 < μ (Function.support f ∩ s) := by rw [lintegral_pos_iff_support hf, Measure.restrict_apply (measurableSet_support hf)] -/-- Weaker version of the monotone convergence theorem-/ +/-- Weaker version of the monotone convergence theorem -/ theorem lintegral_iSup_ae {f : ℕ → α → ℝ≥0∞} (hf : ∀ n, Measurable (f n)) (h_mono : ∀ n, ∀ᵐ a ∂μ, f n a ≤ f n.succ a) : ∫⁻ a, ⨆ n, f n a ∂μ = ⨆ n, ∫⁻ a, f n a ∂μ := by classical @@ -1410,7 +1434,7 @@ theorem _root_.MeasurableEmbedding.lintegral_map [MeasurableSpace β] {g : α exact le_iSup_of_le (comp f₀ g hg.measurable) (by exact le_iSup (α := ℝ≥0∞) _ this) · rw [← f₀.extend_comp_eq hg (const _ 0), ← SimpleFunc.lintegral_map, ← SimpleFunc.lintegral_eq_lintegral, ← lintegral] - refine lintegral_mono_ae (hg.ae_map_iff.2 <| eventually_of_forall fun x => ?_) + refine lintegral_mono_ae (hg.ae_map_iff.2 <| Eventually.of_forall fun x => ?_) exact (extend_apply _ _ _ _).trans_le (hf₀ _) /-- The `lintegral` transforms appropriately under a measurable equivalence `g : α ≃ᵐ β`. @@ -1649,7 +1673,7 @@ theorem setLIntegral_lt_top_of_le_nnreal {s : Set α} (hs : μ s ≠ ∞) {f : (hbdd : ∃ y : ℝ≥0, ∀ x ∈ s, f x ≤ y) : ∫⁻ x in s, f x ∂μ < ∞ := by obtain ⟨M, hM⟩ := hbdd refine lt_of_le_of_lt (setLIntegral_mono measurable_const hM) ?_ - simp [ENNReal.mul_lt_top, hs] + simp [ENNReal.mul_lt_top, hs.lt_top] /-- Lebesgue integral of a bounded function over a set of finite measure is finite. Note that this lemma assumes no regularity of either `f` or `s`. -/ @@ -1753,7 +1777,7 @@ lemma tendsto_of_lintegral_tendsto_of_monotone {α : Type*} {mα : MeasurableSpa · exact fun n ↦ (M n).aemeasurable · simp_rw [Int_eq] exact hf_tendsto - · exact eventually_of_forall (fun x ↦ monotone_nat_of_le_succ (fun n ↦ le_max_right _ _)) + · exact Eventually.of_forall (fun x ↦ monotone_nat_of_le_succ (fun n ↦ le_max_right _ _)) · filter_upwards [h_bound, I'] with x h'x hx n using (hx n).trans (h'x n) filter_upwards [this, I', h_bound] with x hx h'x h''x exact tendsto_of_tendsto_of_tendsto_of_le_of_le hx tendsto_const_nhds h'x h''x @@ -1832,7 +1856,7 @@ theorem exists_measurable_le_forall_setLIntegral_eq [SFinite μ] (f : α → ℝ have hφle : φ ≤ f := fun x ↦ iSup_le (hgf · x) refine ⟨φ, hφm, hφle, fun s ↦ ?_⟩ -- Now we show the inequality between set integrals. - -- Choose a simple function `ψ ≤ f` with values in `ℝ≥0` and prove for `ψ`. + -- Choose a simple function `ψ ≤ f` with values in `ℝ≥0` and prove for `ψ`. rw [lintegral_eq_nnreal] refine iSup₂_le fun ψ hψ ↦ ?_ -- Choose `n` such that `ψ x ≤ n` for all `x`. @@ -1943,7 +1967,8 @@ constant. -/ theorem lintegral_le_of_forall_fin_meas_le [MeasurableSpace α] {μ : Measure α} [SigmaFinite μ] (C : ℝ≥0∞) {f : α → ℝ≥0∞} (hf : ∀ s, MeasurableSet s → μ s ≠ ∞ → ∫⁻ x in s, f x ∂μ ≤ C) : ∫⁻ x, f x ∂μ ≤ C := - @lintegral_le_of_forall_fin_meas_trim_le _ _ _ _ _ (by rwa [trim_eq_self]) C _ hf + have : SigmaFinite (μ.trim le_rfl) := by rwa [trim_eq_self] + lintegral_le_of_forall_fin_meas_trim_le _ C hf theorem SimpleFunc.exists_lt_lintegral_simpleFunc_of_lt_lintegral {m : MeasurableSpace α} {μ : Measure α} [SigmaFinite μ] {f : α →ₛ ℝ≥0} {L : ℝ≥0∞} (hL : L < ∫⁻ x, f x ∂μ) : @@ -1957,8 +1982,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 @@ -1967,13 +1992,13 @@ theorem SimpleFunc.exists_lt_lintegral_simpleFunc_of_lt_lintegral {m : Measurabl exact zero_le _ · simp only [ht, const_zero, coe_piecewise, coe_const, SimpleFunc.coe_zero, univ_inter, piecewise_eq_indicator, ENNReal.coe_indicator, Function.const_apply, lintegral_indicator, - lintegral_const, Measure.restrict_apply', ENNReal.mul_lt_top ENNReal.coe_ne_top t_top.ne] + lintegral_const, Measure.restrict_apply', ENNReal.mul_lt_top ENNReal.coe_lt_top t_top] · simp only [ht, const_zero, coe_piecewise, coe_const, SimpleFunc.coe_zero, 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 @@ -1986,8 +2011,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₂⟩ @@ -2029,10 +2053,10 @@ lemma tendsto_measure_of_ae_tendsto_indicator {μ : Measure α} (A_mble : Measur simp_rw [← MeasureTheory.lintegral_indicator_one A_mble, ← MeasureTheory.lintegral_indicator_one (As_mble _)] refine tendsto_lintegral_filter_of_dominated_convergence (B.indicator (1 : α → ℝ≥0∞)) - (eventually_of_forall ?_) ?_ ?_ ?_ + (Eventually.of_forall ?_) ?_ ?_ ?_ · exact fun i ↦ Measurable.indicator measurable_const (As_mble i) · filter_upwards [As_le_B] with i hi - exact eventually_of_forall (fun x ↦ indicator_le_indicator_of_subset hi (by simp) x) + exact Eventually.of_forall (fun x ↦ indicator_le_indicator_of_subset hi (by simp) x) · rwa [← lintegral_indicator_one B_mble] at B_finmeas · simpa only [Pi.one_def, tendsto_indicator_const_apply_iff_eventually] using h_lim @@ -2044,8 +2068,10 @@ lemma tendsto_measure_of_ae_tendsto_indicator_of_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)) := tendsto_measure_of_ae_tendsto_indicator L A_mble As_mble MeasurableSet.univ - (measure_ne_top μ univ) (eventually_of_forall (fun i ↦ subset_univ (As i))) h_lim + (measure_ne_top μ univ) (Eventually.of_forall (fun i ↦ subset_univ (As i))) h_lim end TendstoIndicator -- section end MeasureTheory + +set_option linter.style.longFile 2200 diff --git a/Mathlib/MeasureTheory/Integral/MeanInequalities.lean b/Mathlib/MeasureTheory/Integral/MeanInequalities.lean index 9db0c3fc5fb59..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) @@ -296,7 +295,7 @@ theorem lintegral_rpow_add_lt_top_of_lintegral_rpow_lt_top {p : ℝ} {f g : α ENNReal.rpow_ne_top_of_nonneg (by simp [hp1]) ENNReal.coe_ne_top rw [lintegral_add_left', lintegral_const_mul'' _ (hf.pow_const p), lintegral_const_mul' _ _ h_two, ENNReal.add_lt_top] - · exact ⟨ENNReal.mul_lt_top h_two hf_top.ne, ENNReal.mul_lt_top h_two hg_top.ne⟩ + · exact ⟨ENNReal.mul_lt_top h_two.lt_top hf_top, ENNReal.mul_lt_top h_two.lt_top hg_top⟩ · exact (hf.pow_const p).const_mul _ theorem lintegral_Lp_mul_le_Lq_mul_Lr {α} [MeasurableSpace α] {p q r : ℝ} (hp0_lt : 0 < p) @@ -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 af565327ab251..845644d23d8fb 100644 --- a/Mathlib/MeasureTheory/Integral/PeakFunction.lean +++ b/Mathlib/MeasureTheory/Integral/PeakFunction.lean @@ -30,7 +30,7 @@ functions are also called approximations of unity, or approximations of identity at `0` and integrable. Note that there are related results about convolution with respect to peak functions in the file -`Analysis.Convolution`, such as `MeasureTheory.convolution_tendsto_right` there. +`Mathlib.Analysis.Convolution`, such as `MeasureTheory.convolution_tendsto_right` there. -/ open Set Filter MeasureTheory MeasureTheory.Measure TopologicalSpace Metric @@ -144,8 +144,8 @@ theorem tendsto_setIntegral_peak_smul_of_integrableOn_of_tendsto_aux _ ≤ ∫ x in t, ‖φ i x‖ * δ ∂μ := by apply setIntegral_mono_set · exact I.norm.mul_const _ - · exact eventually_of_forall fun x => mul_nonneg (norm_nonneg _) δpos.le - · exact eventually_of_forall ut + · 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 => ?_ rw [Real.norm_of_nonneg (hφpos _ (hts hx))] @@ -319,7 +319,7 @@ theorem tendsto_setIntegral_pow_smul_of_unique_maximum_of_isCompact_of_measure_n · intro x hx exact pow_le_pow_left t'_pos.le (le_of_lt (hv hx)) _ _ ≤ ∫ y in s, c y ^ n ∂μ := - setIntegral_mono_set (I n) (J n) (eventually_of_forall inter_subset_right) + setIntegral_mono_set (I n) (J n) (Eventually.of_forall inter_subset_right) simp_rw [φ, ← div_eq_inv_mul, div_pow, div_div] apply div_le_div (pow_nonneg t_pos n) _ _ B · exact pow_le_pow_left (hnc _ hx.1) (ht x hx) _ @@ -341,10 +341,10 @@ theorem tendsto_setIntegral_pow_smul_of_unique_maximum_of_isCompact_of_measure_n have B : Tendsto (fun i ↦ ∫ (x : α) in s, φ i x ∂μ) atTop (𝓝 1) := tendsto_const_nhds.congr (fun n ↦ (hiφ n).symm) have C : ∀ᶠ (i : ℕ) in atTop, AEStronglyMeasurable (fun x ↦ φ i x) (μ.restrict s) := by - apply eventually_of_forall (fun n ↦ ((I n).const_mul _).aestronglyMeasurable) + apply Eventually.of_forall (fun n ↦ ((I n).const_mul _).aestronglyMeasurable) exact tendsto_setIntegral_peak_smul_of_integrableOn_of_tendsto hs.measurableSet hs.measurableSet (Subset.rfl) (self_mem_nhdsWithin) - hs.measure_lt_top.ne (eventually_of_forall hnφ) A B C hmg hcg + hs.measure_lt_top.ne (Eventually.of_forall hnφ) A B C hmg hcg convert this simp_rw [φ, ← smul_smul, integral_smul] @@ -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 00da4d383fa2e..c86458b3ee841 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 @@ -112,7 +112,7 @@ theorem volume_closedBall {x : AddCircle T} (ε : ℝ) : · simp [I, hε, min_eq_left (by linarith : T ≤ 2 * ε)] instance : IsUnifLocDoublingMeasure (volume : Measure (AddCircle T)) := by - refine ⟨⟨Real.toNNReal 2, Filter.eventually_of_forall fun ε x => ?_⟩⟩ + refine ⟨⟨Real.toNNReal 2, Filter.Eventually.of_forall fun ε x => ?_⟩⟩ simp only [volume_closedBall] erw [← ENNReal.ofReal_mul zero_le_two] apply ENNReal.ofReal_le_ofReal diff --git a/Mathlib/MeasureTheory/Integral/Pi.lean b/Mathlib/MeasureTheory/Integral/Pi.lean index b01b627974865..3445cc3f930f1 100644 --- a/Mathlib/MeasureTheory/Integral/Pi.lean +++ b/Mathlib/MeasureTheory/Integral/Pi.lean @@ -28,12 +28,13 @@ theorem Integrable.fin_nat_prod {n : ℕ} {E : Fin n → Type*} {f : (i : Fin n) → E i → 𝕜} (hf : ∀ i, Integrable (f i)) : Integrable (fun (x : (i : Fin n) → E i) ↦ ∏ i, f i (x i)) := by induction n with - | zero => simp only [Nat.zero_eq, Finset.univ_eq_empty, Finset.prod_empty, volume_pi, + | zero => simp only [Finset.univ_eq_empty, Finset.prod_empty, volume_pi, integrable_const_iff, one_ne_zero, pi_empty_univ, ENNReal.one_lt_top, or_true] | succ n n_ih => have := ((measurePreserving_piFinSuccAbove (fun i => (volume : Measure (E i))) 0).symm) rw [volume_pi, ← this.integrable_comp_emb (MeasurableEquiv.measurableEmbedding _)] - simp_rw [MeasurableEquiv.piFinSuccAbove_symm_apply, Fin.prod_univ_succ, Fin.insertNth_zero] + simp_rw [MeasurableEquiv.piFinSuccAbove_symm_apply, Fin.insertNthEquiv, + Fin.prod_univ_succ, Fin.insertNth_zero] simp only [Fin.zero_succAbove, cast_eq, Function.comp_def, Fin.cons_zero, Fin.cons_succ] have : Integrable (fun (x : (j : Fin n) → E (Fin.succ j)) ↦ ∏ j, f (Fin.succ j) (x j)) := n_ih (fun i ↦ hf _) @@ -67,7 +68,7 @@ theorem integral_fin_nat_prod_eq_prod {n : ℕ} {E : Fin n → Type*} ∫ x : (i : Fin n) → E i, ∏ i, f i (x i) = ∏ i, ∫ x, f i x := by induction n with | zero => - simp only [Nat.zero_eq, volume_pi, Finset.univ_eq_empty, Finset.prod_empty, integral_const, + simp only [volume_pi, Finset.univ_eq_empty, Finset.prod_empty, integral_const, pi_empty_univ, ENNReal.one_toReal, smul_eq_mul, mul_one, pow_zero, one_smul] | succ n n_ih => calc @@ -75,9 +76,9 @@ theorem integral_fin_nat_prod_eq_prod {n : ℕ} {E : Fin n → Type*} f 0 x.1 * ∏ i : Fin n, f (Fin.succ i) (x.2 i) := by rw [volume_pi, ← ((measurePreserving_piFinSuccAbove (fun i => (volume : Measure (E i))) 0).symm).integral_comp'] - simp_rw [MeasurableEquiv.piFinSuccAbove_symm_apply, - Fin.prod_univ_succ, Fin.insertNth_zero, Fin.cons_succ, volume_eq_prod, volume_pi, - Fin.zero_succAbove, cast_eq, Fin.cons_zero] + simp_rw [MeasurableEquiv.piFinSuccAbove_symm_apply, Fin.insertNthEquiv, + Fin.prod_univ_succ, Fin.insertNth_zero, Equiv.coe_fn_mk, Fin.cons_succ, volume_eq_prod, + volume_pi, Fin.zero_succAbove, cast_eq, Fin.cons_zero] _ = (∫ x, f 0 x) * ∏ i : Fin n, ∫ (x : E (Fin.succ i)), f (Fin.succ i) x := by rw [← n_ih, ← integral_prod_mul, volume_eq_prod] _ = ∏ i, ∫ x, f i x := by rw [Fin.prod_univ_succ] diff --git a/Mathlib/MeasureTheory/Integral/RieszMarkovKakutani.lean b/Mathlib/MeasureTheory/Integral/RieszMarkovKakutani.lean index 20a484f42774c..b6a9c18db7857 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 /-! diff --git a/Mathlib/MeasureTheory/Integral/SetIntegral.lean b/Mathlib/MeasureTheory/Integral/SetIntegral.lean index 44f6063be9b79..be099131dfc9b 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.Compact +import Mathlib.Topology.ContinuousMap.ContinuousMapZero import Mathlib.Analysis.NormedSpace.HahnBanach.SeparatingDual /-! @@ -84,14 +84,14 @@ alias set_integral_congr_ae := setIntegral_congr_ae theorem setIntegral_congr₀ (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 + setIntegral_congr_ae₀ hs <| Eventually.of_forall h @[deprecated (since := "2024-04-17")] alias set_integral_congr₀ := setIntegral_congr₀ theorem setIntegral_congr (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 + setIntegral_congr_ae hs <| Eventually.of_forall h @[deprecated (since := "2024-04-17")] alias set_integral_congr := setIntegral_congr @@ -228,12 +228,12 @@ 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] refine (ennnorm_integral_le_lintegral_ennnorm _).trans ?_ - rw [← withDensity_apply _ (hSm.diff (hsm _)), ← hν, measure_diff hsub (hsm _)] + rw [← withDensity_apply _ (hSm.diff (hsm _)), ← hν, measure_diff hsub (hsm _).nullMeasurableSet] exacts [tsub_le_iff_tsub_le.mp hi.1, (hi.2.trans_lt <| ENNReal.add_lt_top.2 ⟨hfi', ENNReal.coe_lt_top⟩).ne] @@ -255,14 +255,15 @@ theorem tendsto_setIntegral_of_antitone {ι : Type*} [Countable ι] [Semilattice simpa [hsm i₀, ν, ENNReal.ofReal, norm_toNNReal] using hi₀.norm.lintegral_lt_top.ne have νS : ν S ≠ ∞ := ((measure_mono (hsub i₀)).trans_lt νi₀.lt_top).ne have : ∀ᶠ i in atTop, ν (s i) ∈ Icc (ν S - ε) (ν S + ε) := by - apply tendsto_measure_iInter hsm h_anti ⟨i₀, νi₀⟩ + apply tendsto_measure_iInter (fun i ↦ (hsm i).nullMeasurableSet) h_anti ⟨i₀, νi₀⟩ apply ENNReal.Icc_mem_nhds νS (ENNReal.coe_pos.2 ε0).ne' filter_upwards [this, Ici_mem_atTop i₀] with i hi h'i rw [mem_closedBall_iff_norm, ← integral_diff hSm (hi₀.mono_set (h_anti h'i)) (hsub i), ← coe_nnnorm, NNReal.coe_le_coe, ← ENNReal.coe_le_coe] refine (ennnorm_integral_le_lintegral_ennnorm _).trans ?_ - rw [← withDensity_apply _ ((hsm _).diff hSm), ← hν, measure_diff (hsub i) hSm νS] - exact tsub_le_iff_left.2 hi.2 + rw [← withDensity_apply _ ((hsm _).diff hSm), ← hν, + measure_diff_le_iff_le_add hSm.nullMeasurableSet (hsub i) νS] + exact hi.2 @[deprecated (since := "2024-04-17")] alias tendsto_set_integral_of_antitone := tendsto_setIntegral_of_antitone @@ -312,7 +313,7 @@ alias set_integral_eq_zero_of_ae_eq_zero := setIntegral_eq_zero_of_ae_eq_zero theorem setIntegral_eq_zero_of_forall_eq_zero (ht_eq : ∀ x ∈ t, f x = 0) : ∫ x in t, f x ∂μ = 0 := - setIntegral_eq_zero_of_ae_eq_zero (eventually_of_forall ht_eq) + setIntegral_eq_zero_of_ae_eq_zero (Eventually.of_forall ht_eq) @[deprecated (since := "2024-04-17")] alias set_integral_eq_zero_of_forall_eq_zero := setIntegral_eq_zero_of_forall_eq_zero @@ -353,7 +354,7 @@ theorem integral_union_eq_left_of_ae (ht_eq : ∀ᵐ x ∂μ.restrict t, f x = 0 theorem integral_union_eq_left_of_forall₀ {f : X → E} (ht : NullMeasurableSet t μ) (ht_eq : ∀ x ∈ t, f x = 0) : ∫ x in s ∪ t, f x ∂μ = ∫ x in s, f x ∂μ := - integral_union_eq_left_of_ae ((ae_restrict_iff'₀ ht).2 (eventually_of_forall ht_eq)) + integral_union_eq_left_of_ae ((ae_restrict_iff'₀ ht).2 (Eventually.of_forall ht_eq)) theorem integral_union_eq_left_of_forall {f : X → E} (ht : MeasurableSet t) (ht_eq : ∀ x ∈ t, f x = 0) : ∫ x in s ∪ t, f x ∂μ = ∫ x in s, f x ∂μ := @@ -377,7 +378,7 @@ theorem setIntegral_eq_of_subset_of_ae_diff_eq_zero_aux (hts : s ⊆ t) 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 @@ -418,7 +419,7 @@ and `t` coincide if `t` is measurable. -/ theorem setIntegral_eq_of_subset_of_forall_diff_eq_zero (ht : MeasurableSet t) (hts : s ⊆ t) (h't : ∀ x ∈ t \ s, f x = 0) : ∫ x in t, f x ∂μ = ∫ x in s, f x ∂μ := setIntegral_eq_of_subset_of_ae_diff_eq_zero ht.nullMeasurableSet hts - (eventually_of_forall fun x hx => h't x hx) + (Eventually.of_forall fun x hx => h't x hx) @[deprecated (since := "2024-04-17")] alias set_integral_eq_of_subset_of_forall_diff_eq_zero := @@ -440,7 +441,7 @@ alias set_integral_eq_integral_of_ae_compl_eq_zero := setIntegral_eq_integral_of whole space. -/ theorem setIntegral_eq_integral_of_forall_compl_eq_zero (h : ∀ x, x ∉ s → f x = 0) : ∫ x in s, f x ∂μ = ∫ x, f x ∂μ := - setIntegral_eq_integral_of_ae_compl_eq_zero (eventually_of_forall h) + setIntegral_eq_integral_of_ae_compl_eq_zero (Eventually.of_forall h) @[deprecated (since := "2024-04-17")] alias set_integral_eq_integral_of_forall_compl_eq_zero := @@ -605,14 +606,14 @@ alias norm_set_integral_le_of_norm_le_const_ae'' := norm_setIntegral_le_of_norm_ theorem norm_setIntegral_le_of_norm_le_const {C : ℝ} (hs : μ s < ∞) (hC : ∀ x ∈ s, ‖f x‖ ≤ C) (hfm : AEStronglyMeasurable f (μ.restrict s)) : ‖∫ x in s, f x ∂μ‖ ≤ C * (μ s).toReal := - norm_setIntegral_le_of_norm_le_const_ae' hs (eventually_of_forall hC) hfm + norm_setIntegral_le_of_norm_le_const_ae' hs (Eventually.of_forall hC) hfm @[deprecated (since := "2024-04-17")] alias norm_set_integral_le_of_norm_le_const := norm_setIntegral_le_of_norm_le_const theorem norm_setIntegral_le_of_norm_le_const' {C : ℝ} (hs : μ s < ∞) (hsm : MeasurableSet s) (hC : ∀ x ∈ s, ‖f x‖ ≤ C) : ‖∫ x in s, f x ∂μ‖ ≤ C * (μ s).toReal := - norm_setIntegral_le_of_norm_le_const_ae'' hs hsm <| eventually_of_forall hC + norm_setIntegral_le_of_norm_le_const_ae'' hs hsm <| Eventually.of_forall hC @[deprecated (since := "2024-04-17")] alias norm_set_integral_le_of_norm_le_const' := norm_setIntegral_le_of_norm_le_const' @@ -648,7 +649,7 @@ theorem setIntegral_gt_gt {R : ℝ} {f : X → ℝ} (hR : 0 ≤ R) rwa [Set.inter_eq_self_of_subset_right] exact fun x hx => Ne.symm (ne_of_lt <| sub_pos.2 hx) · rw [Pi.zero_def, EventuallyLE, ae_restrict_iff₀] - · exact eventually_of_forall fun x hx => sub_nonneg.2 <| le_of_lt hx + · exact Eventually.of_forall fun x hx => sub_nonneg.2 <| le_of_lt hx · exact nullMeasurableSet_le aemeasurable_zero (hfint.1.aemeasurable.sub aemeasurable_const) · exact Integrable.sub hfint this @@ -896,7 +897,7 @@ lemma integral_le_measure {f : X → ℝ} {s : Set X} apply ENNReal.ofReal_le_ofReal exact integral_mono H g_int (fun x ↦ le_max_left _ _) apply this.trans - rw [ofReal_integral_eq_lintegral_ofReal g_int (eventually_of_forall (fun x ↦ le_max_right _ _))] + rw [ofReal_integral_eq_lintegral_ofReal g_int (Eventually.of_forall (fun x ↦ le_max_right _ _))] apply lintegral_le_meas · intro x apply ENNReal.ofReal_le_of_le_toReal @@ -1259,23 +1260,34 @@ 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, *] end ContinuousLinearEquiv -namespace ContinuousMap +section ContinuousMap -lemma integral_apply [TopologicalSpace Y] [CompactSpace Y] [NormedSpace ℝ E] - [CompleteSpace E] {f : X → C(Y, E)} (hf : Integrable f μ) (y : Y) : - (∫ x, f x ∂μ) y = ∫ x, f x y ∂μ := by +variable [TopologicalSpace Y] [CompactSpace Y] + +lemma ContinuousMap.integral_apply [NormedSpace ℝ E] [CompleteSpace E] {f : X → C(Y, E)} + (hf : Integrable f μ) (y : Y) : (∫ x, f x ∂μ) y = ∫ x, f x y ∂μ := by calc (∫ x, f x ∂μ) y = ContinuousMap.evalCLM ℝ y (∫ x, f x ∂μ) := rfl _ = ∫ x, ContinuousMap.evalCLM ℝ y (f x) ∂μ := (ContinuousLinearMap.integral_comp_comm _ hf).symm _ = _ := rfl +open scoped ContinuousMapZero in +theorem ContinuousMapZero.integral_apply {R : Type*} [NormedCommRing R] [Zero Y] + [NormedAlgebra ℝ R] [CompleteSpace R] {f : X → C(Y, R)₀} + (hf : MeasureTheory.Integrable f μ) (y : Y) : + (∫ (x : X), f x ∂μ) y = ∫ (x : X), (f x) y ∂μ := by + calc (∫ x, f x ∂μ) y = ContinuousMapZero.evalCLM ℝ y (∫ x, f x ∂μ) := rfl + _ = ∫ x, ContinuousMapZero.evalCLM ℝ y (f x) ∂μ := + (ContinuousLinearMap.integral_comp_comm _ hf).symm + _ = _ := rfl + end ContinuousMap @[norm_cast] @@ -1563,7 +1575,7 @@ lemma continuousOn_integral_bilinear_of_locally_integrable_of_compact_support apply StronglyMeasurable.aestronglyMeasurable apply Continuous.stronglyMeasurable_of_support_subset_isCompact (A p hp) hk apply support_subset_iff'.2 (fun y hy ↦ hfs p y hp hy) - · apply eventually_of_forall (fun y ↦ (le_opNorm₂ L (g y) (f p y)).trans ?_) + · apply Eventually.of_forall (fun y ↦ (le_opNorm₂ L (g y) (f p y)).trans ?_) gcongr apply hC filter_upwards [v_mem, self_mem_nhdsWithin] with p hp h'p @@ -1578,7 +1590,7 @@ lemma continuousOn_integral_bilinear_of_locally_integrable_of_compact_support _ = ‖∫ x in k, L (g x) (f p x) - L (g x) (f q x) ∂μ‖ := by rw [integral_sub (I p h'p) (I q hq)] _ ≤ ∫ x in k, ‖L (g x) (f p x) - L (g x) (f q x)‖ ∂μ := norm_integral_le_integral_norm _ _ ≤ ∫ x in k, ‖L‖ * ‖g x‖ * δ ∂μ := by - apply integral_mono_of_nonneg (eventually_of_forall (fun y ↦ by positivity)) + apply integral_mono_of_nonneg (Eventually.of_forall (fun y ↦ by positivity)) · exact (hg.norm.const_mul _).mul_const _ · filter_upwards with y by_cases hy : y ∈ k @@ -1604,3 +1616,5 @@ lemma continuousOn_integral_of_compact_support hk hf hfs (integrableOn_const.2 (Or.inr hk.measure_lt_top)) (μ := μ) (g := fun _ ↦ 1) end ParametricIntegral + +set_option linter.style.longFile 1700 diff --git a/Mathlib/MeasureTheory/Integral/SetToL1.lean b/Mathlib/MeasureTheory/Integral/SetToL1.lean index c177aeb5d4943..b1c2e325add44 100644 --- a/Mathlib/MeasureTheory/Integral/SetToL1.lean +++ b/Mathlib/MeasureTheory/Integral/SetToL1.lean @@ -116,14 +116,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 ≠ ∞) : @@ -158,9 +158,8 @@ theorem map_iUnion_fin_meas_set_eq_sum (T : Set α → β) (T_empty : T ∅ = 0) h_add (S a) (⋃ i ∈ s, S i) (hS_meas a) (measurableSet_biUnion _ fun i _ => hS_meas i) (hps a (Finset.mem_insert_self a s))] · congr; convert Finset.iSup_insert a s S - · exact - ((measure_biUnion_finset_le _ _).trans_lt <| - ENNReal.sum_lt_top fun i hi => hps i <| Finset.mem_insert_of_mem hi).ne + · 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] @@ -232,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 @@ -921,18 +920,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) @@ -1384,7 +1383,7 @@ theorem tendsto_setToFun_approxOn_of_measurable (hT : DominatedFinMeasAdditive Tendsto (fun n => setToFun μ T hT (SimpleFunc.approxOn f hfm s y₀ h₀ n)) atTop (𝓝 <| setToFun μ T hT f) := tendsto_setToFun_of_L1 hT _ hfi - (eventually_of_forall (SimpleFunc.integrable_approxOn hfm hfi h₀ h₀i)) + (Eventually.of_forall (SimpleFunc.integrable_approxOn hfm hfi h₀ h₀i)) (SimpleFunc.tendsto_approxOn_L1_nnnorm hfm _ hs (hfi.sub h₀i).2) theorem tendsto_setToFun_approxOn_of_measurable_of_range_subset @@ -1394,7 +1393,7 @@ theorem tendsto_setToFun_approxOn_of_measurable_of_range_subset Tendsto (fun n => setToFun μ T hT (SimpleFunc.approxOn f fmeas s 0 (hs <| by simp) n)) atTop (𝓝 <| setToFun μ T hT f) := by refine tendsto_setToFun_approxOn_of_measurable hT hf fmeas ?_ _ (integrable_zero _ _ _) - exact eventually_of_forall fun x => subset_closure (hs (Set.mem_union_left _ (mem_range_self _))) + exact Eventually.of_forall fun x => subset_closure (hs (Set.mem_union_left _ (mem_range_self _))) /-- Auxiliary lemma for `setToFun_congr_measure`: the function sending `f : α →₁[μ] G` to `f : α →₁[μ'] G` is continuous when `μ' ≤ c' • μ` for `c' ≠ ∞`. -/ @@ -1427,8 +1426,8 @@ theorem continuous_L1_toL1 {μ' : Measure α} (c' : ℝ≥0∞) (hc' : c' ≠ have h_eLpNorm_ne_top' : eLpNorm (⇑g - ⇑f) 1 μ' ≠ ∞ := by refine ((eLpNorm_mono_measure _ hμ'_le).trans_lt ?_).ne rw [eLpNorm_smul_measure_of_ne_zero hc'0, smul_eq_mul] - refine ENNReal.mul_lt_top ?_ h_eLpNorm_ne_top - simp [hc', hc'0] + refine ENNReal.mul_lt_top ?_ h_eLpNorm_ne_top.lt_top + simp [hc'.lt_top, hc'0] calc (eLpNorm (⇑g - ⇑f) 1 μ').toReal ≤ (c' * eLpNorm (⇑g - ⇑f) 1 μ).toReal := by rw [toReal_le_toReal h_eLpNorm_ne_top' (ENNReal.mul_ne_top hc' h_eLpNorm_ne_top)] @@ -1455,7 +1454,7 @@ theorem setToFun_congr_measure_of_integrable {μ' : Measure α} (c' : ℝ≥0∞ have hμ's : μ' s ≠ ∞ := by refine ((hμ'_le s).trans_lt ?_).ne rw [Measure.smul_apply, smul_eq_mul] - exact ENNReal.mul_lt_top hc' hμs.ne + exact ENNReal.mul_lt_top hc'.lt_top hμs rw [setToFun_indicator_const hT hs hμs.ne, setToFun_indicator_const hT' hs hμ's] · intro f₂ g₂ _ hf₂ hg₂ h_eq_f h_eq_g rw [setToFun_add hT hf₂ hg₂, setToFun_add hT' (h_int f₂ hf₂) (h_int g₂ hg₂), h_eq_f, h_eq_g] @@ -1503,7 +1502,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] @@ -1639,10 +1638,12 @@ theorem continuous_setToFun_of_dominated (hT : DominatedFinMeasAdditive μ T C) (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₀ => - continuousAt_setToFun_of_dominated hT (eventually_of_forall hfs_meas) - (eventually_of_forall h_bound) ‹_› <| + continuousAt_setToFun_of_dominated hT (Eventually.of_forall hfs_meas) + (Eventually.of_forall h_bound) ‹_› <| h_cont.mono fun _ => Continuous.continuousAt end Function end MeasureTheory + +set_option linter.style.longFile 1800 diff --git a/Mathlib/MeasureTheory/Integral/TorusIntegral.lean b/Mathlib/MeasureTheory/Integral/TorusIntegral.lean index 3398c9ead73c2..2ac46ce80a629 100644 --- a/Mathlib/MeasureTheory/Integral/TorusIntegral.lean +++ b/Mathlib/MeasureTheory/Integral/TorusIntegral.lean @@ -217,7 +217,7 @@ theorem torusIntegral_succAbove have hem : MeasurePreserving e := (volume_preserving_piFinSuccAbove (fun _ : Fin (n + 1) => ℝ) i).symm _ have heπ : (e ⁻¹' Icc 0 fun _ => 2 * π) = Icc 0 (2 * π) ×ˢ Icc (0 : ℝⁿ) fun _ => 2 * π := - ((OrderIso.piFinSuccAboveIso (fun _ => ℝ) i).symm.preimage_Icc _ _).trans (Icc_prod_eq _ _) + ((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 θ _ => ?_ @@ -225,7 +225,7 @@ theorem torusIntegral_succAbove deriv_circleMap, i.prod_univ_succAbove _, smul_smul, torusMap, circleMap_zero] refine setIntegral_congr measurableSet_Icc fun Θ _ => ?_ simp only [MeasurableEquiv.piFinSuccAbove_symm_apply, i.insertNth_apply_same, - i.insertNth_apply_succAbove, (· ∘ ·)] + i.insertNth_apply_succAbove, (· ∘ ·), Fin.insertNthEquiv, Equiv.coe_fn_mk] congr 2 simp only [funext_iff, i.forall_iff_succAbove, circleMap, Fin.insertNth_apply_same, eq_self_iff_true, Fin.insertNth_apply_succAbove, imp_true_iff, and_self_iff] diff --git a/Mathlib/MeasureTheory/Integral/VitaliCaratheodory.lean b/Mathlib/MeasureTheory/Integral/VitaliCaratheodory.lean index 7894d2996f639..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⟩ @@ -297,9 +297,9 @@ theorem exists_lt_lowerSemicontinuous_integral_gt_nnreal [SigmaFinite μ] (f : _ < ENNReal.toReal (∫⁻ a : α, f a ∂μ) + ε := add_lt_add_left hδε _ _ = (∫⁻ a : α, ENNReal.ofReal ↑(f a) ∂μ).toReal + ε := by simp - · apply Filter.eventually_of_forall fun x => _; simp + · apply Filter.Eventually.of_forall fun x => _; simp · exact fmeas.coe_nnreal_real.aestronglyMeasurable - · apply Filter.eventually_of_forall fun x => _; simp + · apply Filter.Eventually.of_forall fun x => _; simp · apply gcont.measurable.ennreal_toReal.aemeasurable.aestronglyMeasurable /-! ### Upper semicontinuous lower bound for nonnegative functions -/ @@ -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' @@ -421,16 +421,16 @@ theorem exists_upperSemicontinuous_le_integral_le (f : α → ℝ≥0) refine ⟨g, gf, gcont, ?_, ?_⟩ · refine Integrable.mono fint gcont.measurable.coe_nnreal_real.aemeasurable.aestronglyMeasurable ?_ - exact Filter.eventually_of_forall fun x => by simp [gf x] + exact Filter.Eventually.of_forall fun x => by simp [gf x] · rw [integral_eq_lintegral_of_nonneg_ae, integral_eq_lintegral_of_nonneg_ae] · rw [sub_le_iff_le_add] convert ENNReal.toReal_mono _ gint · simp · rw [ENNReal.toReal_add Ig.ne ENNReal.coe_ne_top]; simp · simpa using Ig.ne - · apply Filter.eventually_of_forall; simp + · apply Filter.Eventually.of_forall; simp · exact gcont.measurable.coe_nnreal_real.aemeasurable.aestronglyMeasurable - · apply Filter.eventually_of_forall; simp + · apply Filter.Eventually.of_forall; simp · exact fint.aestronglyMeasurable /-! ### Vitali-Carathéodory theorem -/ diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean b/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean index 7d3dad830959e..61c55dee0d648 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean @@ -5,12 +5,12 @@ Authors: Johannes Hölzl, Mario Carneiro -/ import Mathlib.Data.Finset.Update import Mathlib.Data.Prod.TProd -import Mathlib.GroupTheory.Coset 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 /-! # Measurable spaces and measurable functions @@ -231,7 +231,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 @@ -351,6 +351,16 @@ theorem measurable_to_countable' [MeasurableSpace α] [Countable α] [Measurable (h : ∀ x, MeasurableSet (f ⁻¹' {x})) : Measurable f := measurable_to_countable fun y => h (f y) +theorem ENat.measurable_iff {α : Type*} [MeasurableSpace α] {f : α → ℕ∞} : + Measurable f ↔ ∀ n : ℕ, MeasurableSet (f ⁻¹' {↑n}) := by + refine ⟨fun hf n ↦ hf <| measurableSet_singleton _, fun h ↦ measurable_to_countable' fun n ↦ ?_⟩ + cases n with + | top => + rw [← WithTop.none_eq_top, ← compl_range_some, preimage_compl, ← iUnion_singleton_eq_range, + preimage_iUnion] + exact .compl <| .iUnion h + | coe n => exact h n + @[measurability] theorem measurable_unit [MeasurableSpace α] (f : Unit → α) : Measurable f := measurable_from_top @@ -508,7 +518,7 @@ alias Measurable.subtype_val := Measurable.subtype_coe @[measurability] theorem Measurable.subtype_mk {p : β → Prop} {f : α → β} (hf : Measurable f) {h : ∀ x, p (f x)} : Measurable fun x => (⟨f x, h x⟩ : Subtype p) := fun t ⟨s, hs⟩ => - hs.2 ▸ by simp only [← preimage_comp, (· ∘ ·), Subtype.coe_mk, hf hs.1] + hs.2 ▸ by simp only [← preimage_comp, Function.comp_def, Subtype.coe_mk, hf hs.1] @[measurability] protected theorem Measurable.rangeFactorization {f : α → β} (hf : Measurable f) : @@ -661,6 +671,7 @@ theorem Measurable.prod_mk {β γ} {_ : MeasurableSpace β} {_ : MeasurableSpace {g : α → γ} (hf : Measurable f) (hg : Measurable g) : Measurable fun a : α => (f a, g a) := Measurable.prod hf hg +@[fun_prop] theorem Measurable.prod_map [MeasurableSpace δ] {f : α → β} {g : γ → δ} (hf : Measurable f) (hg : Measurable g) : Measurable (Prod.map f g) := (hf.comp measurable_fst).prod_mk (hg.comp measurable_snd) @@ -805,7 +816,7 @@ variable [∀ a, MeasurableSpace (π a)] [MeasurableSpace γ] theorem measurable_pi_iff {g : α → ∀ a, π a} : Measurable g ↔ ∀ a, Measurable fun x => g x a := by simp_rw [measurable_iff_comap_le, MeasurableSpace.pi, MeasurableSpace.comap_iSup, - MeasurableSpace.comap_comp, Function.comp, iSup_le_iff] + MeasurableSpace.comap_comp, Function.comp_def, iSup_le_iff] @[fun_prop, aesop safe 100 apply (rule_sets := [Measurable])] theorem measurable_pi_apply (a : δ) : Measurable fun f : ∀ a, π a => f a := @@ -854,6 +865,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 @@ -1081,7 +1128,7 @@ lemma measurable_set_mem (a : α) : Measurable fun s : Set α ↦ a ∈ s := mea @[aesop safe 100 apply (rule_sets := [Measurable])] lemma measurable_set_not_mem (a : α) : Measurable fun s : Set α ↦ a ∉ s := - (measurable_discrete Not).comp <| measurable_set_mem a + (Measurable.of_discrete (f := Not)).comp <| measurable_set_mem a @[aesop safe 100 apply (rule_sets := [Measurable])] lemma measurableSet_mem (a : α) : MeasurableSet {s : Set α | a ∈ s} := @@ -1094,6 +1141,20 @@ lemma measurableSet_not_mem (a : α) : MeasurableSet {s : Set α | a ∉ s} := lemma measurable_compl : Measurable ((·ᶜ) : Set α → Set α) := measurable_set_iff.2 fun _ ↦ measurable_set_not_mem _ +lemma MeasurableSet.setOf_finite [Countable α] : MeasurableSet {s : Set α | s.Finite} := + Countable.setOf_finite.measurableSet + +lemma MeasurableSet.setOf_infinite [Countable α] : MeasurableSet {s : Set α | s.Infinite} := + .setOf_finite |> .compl + +lemma MeasurableSet.sep_finite [Countable α] {S : Set (Set α)} (hS : MeasurableSet S) : + MeasurableSet {s ∈ S | s.Finite} := + hS.inter .setOf_finite + +lemma MeasurableSet.sep_infinite [Countable α] {S : Set (Set α)} (hS : MeasurableSet S) : + MeasurableSet {s ∈ S | s.Infinite} := + hS.inter .setOf_infinite + end Set end Constructions @@ -1204,7 +1265,7 @@ namespace MeasurableSet variable [MeasurableSpace α] instance Subtype.instMembership : Membership α (Subtype (MeasurableSet : Set α → Prop)) := - ⟨fun a s => a ∈ (s : Set α)⟩ + ⟨fun s a => a ∈ (s : Set α)⟩ @[simp] theorem mem_coe (a : α) (s : Subtype (MeasurableSet : Set α → Prop)) : a ∈ (s : Set α) ↔ a ∈ s := diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Card.lean b/Mathlib/MeasureTheory/MeasurableSpace/Card.lean index 879f1bfe0994b..9da03d77e896e 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/Card.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/Card.lean @@ -32,7 +32,7 @@ variable {α : Type u} open Cardinal Set -- Porting note: fix universe below, not here -local notation "ω₁" => (WellOrder.α <| Quotient.out <| Cardinal.ord (aleph 1 : Cardinal)) +local notation "ω₁" => (Ordinal.toType <| Cardinal.ord (aleph 1)) namespace MeasurableSpace @@ -42,12 +42,11 @@ countable unions of already constructed sets. We index this construction by an o this will be enough to generate all sets in the sigma-algebra. This construction is very similar to that of the Borel hierarchy. -/ -def generateMeasurableRec (s : Set (Set α)) : (ω₁ : Type u) → Set (Set α) - | i => - let S := ⋃ j : Iio i, generateMeasurableRec s (j.1) - s ∪ {∅} ∪ compl '' S ∪ Set.range fun f : ℕ → S => ⋃ n, (f n).1 - termination_by i => i - decreasing_by exact j.2 +def generateMeasurableRec (s : Set (Set α)) (i : (ω₁ : Type u)) : Set (Set α) := + let S := ⋃ j : Iio i, generateMeasurableRec s (j.1) + s ∪ {∅} ∪ compl '' S ∪ Set.range fun f : ℕ → S => ⋃ n, (f n).1 +termination_by i +decreasing_by exact j.2 theorem self_subset_generateMeasurableRec (s : Set (Set α)) (i : ω₁) : s ⊆ generateMeasurableRec s i := by @@ -78,20 +77,19 @@ theorem generateMeasurableRec_subset (s : Set (Set α)) {i j : ω₁} (h : i ≤ · convert iUnion_mem_generateMeasurableRec fun _ => ⟨i, h, hx⟩ exact (iUnion_const x).symm -/-- At each step of the inductive construction, the cardinality bound `≤ (max #s 2) ^ ℵ₀` holds. --/ +/-- At each step of the inductive construction, the cardinality bound `≤ (max #s 2) ^ ℵ₀` holds. -/ theorem cardinal_generateMeasurableRec_le (s : Set (Set α)) (i : ω₁) : - #(generateMeasurableRec s i) ≤ max #s 2 ^ aleph0.{u} := by - apply (aleph 1).ord.out.wo.wf.induction i + #(generateMeasurableRec s i) ≤ max #s 2 ^ ℵ₀ := by + apply WellFoundedLT.induction i intro i IH have A := aleph0_le_aleph 1 - have B : aleph 1 ≤ max #s 2 ^ aleph0.{u} := + have B : aleph 1 ≤ max #s 2 ^ ℵ₀ := aleph_one_le_continuum.trans (power_le_power_right (le_max_right _ _)) - have C : ℵ₀ ≤ max #s 2 ^ aleph0.{u} := A.trans B - have J : #(⋃ j : Iio i, generateMeasurableRec s j.1) ≤ max #s 2 ^ aleph0.{u} := by + have C : ℵ₀ ≤ max #s 2 ^ ℵ₀ := A.trans B + have J : #(⋃ j : Iio i, generateMeasurableRec s j.1) ≤ max #s 2 ^ ℵ₀ := by refine (mk_iUnion_le _).trans ?_ have D : ⨆ j : Iio i, #(generateMeasurableRec s j) ≤ _ := ciSup_le' fun ⟨j, hj⟩ => IH j hj - apply (mul_le_mul' ((mk_subtype_le _).trans (aleph 1).mk_ord_out.le) D).trans + apply (mul_le_mul' ((mk_subtype_le _).trans (aleph 1).mk_ord_toType.le) D).trans rw [mul_eq_max A C] exact max_le B le_rfl rw [generateMeasurableRec] @@ -107,20 +105,21 @@ theorem cardinal_generateMeasurableRec_le (s : Set (Set α)) (i : ω₁) : /-- `generateMeasurableRec s` generates precisely the smallest sigma-algebra containing `s`. -/ theorem generateMeasurable_eq_rec (s : Set (Set α)) : { t | GenerateMeasurable s t } = - ⋃ (i : (Quotient.out (aleph 1).ord).α), generateMeasurableRec s i := by + ⋃ (i : (aleph 1).ord.toType), generateMeasurableRec s i := by ext t; refine ⟨fun ht => ?_, fun ht => ?_⟩ · inhabit ω₁ - induction' ht with u hu u _ IH f _ IH - · exact mem_iUnion.2 ⟨default, self_subset_generateMeasurableRec s _ hu⟩ - · exact mem_iUnion.2 ⟨default, empty_mem_generateMeasurableRec s _⟩ - · rcases mem_iUnion.1 IH with ⟨i, hi⟩ + induction ht with + | basic u hu => exact mem_iUnion.2 ⟨default, self_subset_generateMeasurableRec s _ hu⟩ + | empty => exact mem_iUnion.2 ⟨default, empty_mem_generateMeasurableRec s _⟩ + | compl _ _ IH => + rcases mem_iUnion.1 IH with ⟨i, hi⟩ obtain ⟨j, hj⟩ := exists_gt i exact mem_iUnion.2 ⟨j, compl_mem_generateMeasurableRec hj hi⟩ - · have : ∀ n, ∃ i, f n ∈ generateMeasurableRec s i := fun n => by simpa using IH n + | iUnion f _ IH => + have : ∀ n, ∃ i, f n ∈ generateMeasurableRec s i := fun n => by simpa using IH n choose I hI using this - have : IsWellOrder (ω₁ : Type u) (· < ·) := isWellOrder_out_lt _ - refine mem_iUnion.2 - ⟨Ordinal.enum (· < ·) (Ordinal.lsub fun n => Ordinal.typein.{u} (· < ·) (I n)) ?_, + 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] refine Ordinal.lsub_lt_ord_lift ?_ fun i => Ordinal.typein_lt_self _ @@ -130,7 +129,7 @@ theorem generateMeasurable_eq_rec (s : Set (Set α)) : apply Ordinal.lt_lsub fun n : ℕ => _ · rcases ht with ⟨t, ⟨i, rfl⟩, hx⟩ revert t - apply (aleph 1).ord.out.wo.wf.induction i + apply WellFoundedLT.induction i intro j H t ht unfold generateMeasurableRec at ht rcases ht with (((h | (rfl : t = ∅)) | ⟨u, ⟨-, ⟨⟨k, hk⟩, rfl⟩, hu⟩, rfl⟩) | ⟨f, rfl⟩) @@ -144,10 +143,10 @@ theorem generateMeasurable_eq_rec (s : Set (Set α)) : /-- If a sigma-algebra is generated by a set of sets `s`, then the sigma-algebra has cardinality at most `(max #s 2) ^ ℵ₀`. -/ theorem cardinal_generateMeasurable_le (s : Set (Set α)) : - #{ t | GenerateMeasurable s t } ≤ max #s 2 ^ aleph0.{u} := by + #{ t | GenerateMeasurable s t } ≤ max #s 2 ^ ℵ₀ := by rw [generateMeasurable_eq_rec] apply (mk_iUnion_le _).trans - rw [(aleph 1).mk_ord_out] + rw [(aleph 1).mk_ord_toType] refine le_trans (mul_le_mul' aleph_one_le_continuum (ciSup_le' fun i => cardinal_generateMeasurableRec_le s i)) ?_ refine (mul_le_max_of_aleph0_le_left aleph0_le_continuum).trans (max_le ?_ le_rfl) @@ -156,7 +155,7 @@ theorem cardinal_generateMeasurable_le (s : Set (Set α)) : /-- If a sigma-algebra is generated by a set of sets `s`, then the sigma algebra has cardinality at most `(max #s 2) ^ ℵ₀`. -/ theorem cardinalMeasurableSet_le (s : Set (Set α)) : - #{ t | @MeasurableSet α (generateFrom s) t } ≤ max #s 2 ^ aleph0.{u} := + #{ t | @MeasurableSet α (generateFrom s) t } ≤ max #s 2 ^ ℵ₀ := cardinal_generateMeasurable_le s /-- If a sigma-algebra is generated by a set of sets `s` with cardinality at most the continuum, diff --git a/Mathlib/MeasureTheory/MeasurableSpace/CountablyGenerated.lean b/Mathlib/MeasureTheory/MeasurableSpace/CountablyGenerated.lean index 3469ca0689e07..9ff18dc3605be 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/CountablyGenerated.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/CountablyGenerated.lean @@ -89,7 +89,7 @@ lemma generateFrom_natGeneratingSequence (α : Type*) [m : MeasurableSpace α] lemma measurableSet_natGeneratingSequence [MeasurableSpace α] [CountablyGenerated α] (n : ℕ) : MeasurableSet (natGeneratingSequence α n) := - measurableSet_countableGeneratingSet $ Set.enumerateCountable_mem _ + measurableSet_countableGeneratingSet <| Set.enumerateCountable_mem _ empty_mem_countableGeneratingSet n theorem CountablyGenerated.comap [m : MeasurableSpace β] [h : CountablyGenerated β] (f : α → β) : @@ -159,7 +159,7 @@ theorem separating_of_generateFrom (S : Set (Set α)) letI := generateFrom S intros x y hxy rw [← forall_generateFrom_mem_iff_mem_iff] at hxy - exact separatesPoints_def $ fun _ hs ↦ (hxy _ hs).mp + exact separatesPoints_def <| fun _ hs ↦ (hxy _ hs).mp theorem SeparatesPoints.mono {m m' : MeasurableSpace α} [hsep : @SeparatesPoints _ m] (h : m ≤ m') : @SeparatesPoints _ m' := @SeparatesPoints.mk _ m' fun _ _ hxy ↦ @@ -194,12 +194,12 @@ theorem CountablySeparated.subtype_iff [MeasurableSpace α] {s : Set α} : instance (priority := 100) Subtype.separatesPoints [MeasurableSpace α] [h : SeparatesPoints α] {s : Set α} : SeparatesPoints s := - ⟨fun _ _ hxy ↦ Subtype.val_injective $ h.1 _ _ fun _ ht ↦ hxy _ $ measurable_subtype_coe ht⟩ + ⟨fun _ _ hxy ↦ Subtype.val_injective <| h.1 _ _ fun _ ht ↦ hxy _ <| measurable_subtype_coe ht⟩ instance (priority := 100) Subtype.countablySeparated [MeasurableSpace α] [h : CountablySeparated α] {s : Set α} : CountablySeparated s := by rw [CountablySeparated.subtype_iff] - exact h.countably_separated.mono (fun s ↦ id) $ subset_univ _ + exact h.countably_separated.mono (fun s ↦ id) <| subset_univ _ instance (priority := 100) separatesPoints_of_measurableSingletonClass [MeasurableSpace α] [MeasurableSingletonClass α] : SeparatesPoints α := by @@ -208,6 +208,17 @@ instance (priority := 100) separatesPoints_of_measurableSingletonClass [Measurab simp_rw [mem_singleton_iff, forall_true_left] at h exact h.symm +instance (priority := 50) MeasurableSingletonClass.of_separatesPoints [MeasurableSpace α] + [Countable α] [SeparatesPoints α] : MeasurableSingletonClass α where + measurableSet_singleton x := by + choose s hsm hxs hys using fun y (h : x ≠ y) ↦ exists_measurableSet_of_ne h + convert MeasurableSet.iInter fun y ↦ .iInter fun h ↦ hsm y h + ext y + rcases eq_or_ne x y with rfl | h + · simpa + · simp only [mem_singleton_iff, h.symm, false_iff, mem_iInter, not_forall] + exact ⟨y, h, hys y h⟩ + instance hasCountableSeparatingOn_of_countablySeparated_subtype [MeasurableSpace α] {s : Set α} [h : CountablySeparated s] : HasCountableSeparatingOn _ MeasurableSet s := CountablySeparated.subtype_iff.mp h @@ -235,7 +246,7 @@ theorem exists_countablyGenerated_le_of_countablySeparated [m : MeasurableSpace refine ⟨generateFrom b, ?_, ?_, generateFrom_le hbm⟩ · use b rw [@separatesPoints_iff] - exact fun x y hxy ↦ hb _ trivial _ trivial fun _ hs ↦ hxy _ $ measurableSet_generateFrom hs + exact fun x y hxy ↦ hb _ trivial _ trivial fun _ hs ↦ hxy _ <| measurableSet_generateFrom hs open Function @@ -270,9 +281,9 @@ the Cantor Space. -/ theorem measurableEquiv_nat_bool_of_countablyGenerated [MeasurableSpace α] [CountablyGenerated α] [SeparatesPoints α] : ∃ s : Set (ℕ → Bool), Nonempty (α ≃ᵐ s) := by - use range (mapNatBool α), Equiv.ofInjective _ $ + use range (mapNatBool α), Equiv.ofInjective _ <| injective_mapNatBool _, - Measurable.subtype_mk $ measurable_mapNatBool _ + Measurable.subtype_mk <| measurable_mapNatBool _ simp_rw [← generateFrom_natGeneratingSequence α] apply measurable_generateFrom rintro _ ⟨n, rfl⟩ @@ -299,7 +310,7 @@ theorem measurableSingletonClass_of_countablySeparated rcases measurable_injection_nat_bool_of_countablySeparated α with ⟨f, fmeas, finj⟩ refine ⟨fun x ↦ ?_⟩ rw [← finj.preimage_image {x}, image_singleton] - exact fmeas $ MeasurableSet.singleton _ + exact fmeas <| MeasurableSet.singleton _ end SeparatesPoints @@ -373,7 +384,7 @@ lemma generateFrom_iUnion_memPartition (t : ℕ → Set α) : obtain ⟨n, hun⟩ := hu induction n generalizing u with | zero => - simp only [Nat.zero_eq, memPartition_zero, mem_insert_iff, mem_singleton_iff] at hun + simp only [memPartition_zero, mem_insert_iff, mem_singleton_iff] at hun rw [hun] exact MeasurableSet.univ | succ n ih => @@ -418,7 +429,7 @@ end MeasurableMemPartition variable [m : MeasurableSpace α] [h : CountablyGenerated α] /-- For each `n : ℕ`, `countablePartition α n` is a partition of the space in at most -`2^n` sets. Each partition is finer than the preceeding one. The measurable space generated by +`2^n` sets. Each partition is finer than the preceding one. The measurable space generated by the union of all those partitions is the measurable space on `α`. -/ def countablePartition (α : Type*) [MeasurableSpace α] [CountablyGenerated α] : ℕ → Set (Set α) := memPartition (enumerateCountable countable_countableGeneratingSet ∅) @@ -505,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 24be3674a76da..5c9f7d9d195dc 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/Defs.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/Defs.lean @@ -517,7 +517,7 @@ end MeasurableFunctions /-- A typeclass mixin for `MeasurableSpace`s such that all sets are measurable. -/ class DiscreteMeasurableSpace (α : Type*) [MeasurableSpace α] : Prop where - /-- Do not use this. Use `measurableSet_discrete` instead. -/ + /-- Do not use this. Use `MeasurableSet.of_discrete` instead. -/ forall_measurableSet : ∀ s : Set α, MeasurableSet s instance : @DiscreteMeasurableSpace α ⊤ := @@ -529,19 +529,24 @@ instance (priority := 100) MeasurableSingletonClass.toDiscreteMeasurableSpace [M forall_measurableSet _ := (Set.to_countable _).measurableSet section DiscreteMeasurableSpace -variable [MeasurableSpace α] [MeasurableSpace β] [DiscreteMeasurableSpace α] +variable [MeasurableSpace α] [MeasurableSpace β] [DiscreteMeasurableSpace α] {s : Set α} {f : α → β} -@[measurability] lemma measurableSet_discrete (s : Set α) : MeasurableSet s := +@[measurability] lemma MeasurableSet.of_discrete : MeasurableSet s := DiscreteMeasurableSpace.forall_measurableSet _ -@[measurability] -lemma measurable_discrete (f : α → β) : Measurable f := fun _ _ ↦ measurableSet_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 + +@[deprecated Measurable.of_discrete (since := "2024-08-25")] +lemma measurable_discrete (f : α → β) : Measurable f := .of_discrete /-- Warning: Creates a typeclass loop with `MeasurableSingletonClass.toDiscreteMeasurableSpace`. To be monitored. -/ -- See note [lower instance priority] instance (priority := 100) DiscreteMeasurableSpace.toMeasurableSingletonClass : MeasurableSingletonClass α where - measurableSet_singleton _ := measurableSet_discrete _ + measurableSet_singleton _ := .of_discrete end DiscreteMeasurableSpace diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Embedding.lean b/Mathlib/MeasureTheory/MeasurableSpace/Embedding.lean index ec89ef7faa51b..295f11d4408f2 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 : β → γ} @@ -155,7 +157,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 +352,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 @@ -488,17 +502,17 @@ def finTwoArrow : (Fin 2 → α) ≃ᵐ α × α := piFinTwo fun _ => α /-- Measurable equivalence between `Π j : Fin (n + 1), α j` and -`α i × Π j : Fin n, α (Fin.succAbove i j)`. -/ +`α i × Π j : Fin n, α (Fin.succAbove i j)`. + +Measurable version of `Fin.insertNthEquiv`. -/ @[simps! (config := .asFn)] def piFinSuccAbove {n : ℕ} (α : Fin (n + 1) → Type*) [∀ i, MeasurableSpace (α i)] (i : Fin (n + 1)) : (∀ j, α j) ≃ᵐ α i × ∀ j, α (i.succAbove j) where - toEquiv := .piFinSuccAbove α i + toEquiv := (Fin.insertNthEquiv α i).symm measurable_toFun := (measurable_pi_apply i).prod_mk <| measurable_pi_iff.2 fun j => measurable_pi_apply _ measurable_invFun := measurable_pi_iff.2 <| i.forall_iff_succAbove.2 - ⟨by simp only [piFinSuccAbove_symm_apply, Fin.insertNth_apply_same, measurable_fst], - fun j => by simpa only [piFinSuccAbove_symm_apply, Fin.insertNth_apply_succAbove] - using (measurable_pi_apply _).comp measurable_snd⟩ + ⟨by simp [measurable_fst], fun j => by simpa using (measurable_pi_apply _).comp measurable_snd⟩ variable (π) diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Instances.lean b/Mathlib/MeasureTheory/MeasurableSpace/Instances.lean index 2de7f4465974c..a760b97654d0d 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/Instances.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/Instances.lean @@ -25,6 +25,8 @@ instance Prop.instMeasurableSpace : MeasurableSpace Prop := ⊤ instance Nat.instMeasurableSpace : MeasurableSpace ℕ := ⊤ +instance ENat.instMeasurableSpace : MeasurableSpace ℕ∞ := ⊤ + instance Fin.instMeasurableSpace (n : ℕ) : MeasurableSpace (Fin n) := ⊤ instance ZMod.instMeasurableSpace (n : ℕ) : MeasurableSpace (ZMod n) := ⊤ @@ -53,6 +55,10 @@ instance Prop.instMeasurableSingletonClass : MeasurableSingletonClass Prop := instance Nat.instMeasurableSingletonClass : MeasurableSingletonClass ℕ := ⟨fun _ => trivial⟩ +instance ENat.instDiscreteMeasurableSpace : DiscreteMeasurableSpace ℕ∞ := ⟨fun _ ↦ trivial⟩ + +instance ENat.instMeasurableSingletonClass : MeasurableSingletonClass ℕ∞ := inferInstance + instance Fin.instMeasurableSingletonClass (n : ℕ) : MeasurableSingletonClass (Fin n) := ⟨fun _ => trivial⟩ diff --git a/Mathlib/MeasureTheory/MeasurableSpace/NCard.lean b/Mathlib/MeasureTheory/MeasurableSpace/NCard.lean new file mode 100644 index 0000000000000..4385de7626560 --- /dev/null +++ b/Mathlib/MeasureTheory/MeasurableSpace/NCard.lean @@ -0,0 +1,27 @@ +/- +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.MeasureTheory.MeasurableSpace.Basic +import Mathlib.Data.Set.Card + +/-! +# Measurability of `Set.encard` and `Set.ncard` + +In this file we prove that `Set.encard` and `Set.ncard` are measurable functions, +provided that the ambient space is countable. +-/ + +open Set + +variable {α : Type*} [Countable α] + +@[measurability] +theorem measurable_encard : Measurable (Set.encard : Set α → ℕ∞) := + ENat.measurable_iff.2 fun _n ↦ Countable.measurableSet <| Countable.setOf_finite.mono fun _s hs ↦ + finite_of_encard_eq_coe hs + +@[measurability] +theorem measurable_ncard : Measurable (Set.ncard : Set α → ℕ) := + Measurable.of_discrete.comp measurable_encard 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/Measure/AEDisjoint.lean b/Mathlib/MeasureTheory/Measure/AEDisjoint.lean index 4e7005ee1da8e..7998e50fd3efc 100644 --- a/Mathlib/MeasureTheory/Measure/AEDisjoint.lean +++ b/Mathlib/MeasureTheory/Measure/AEDisjoint.lean @@ -117,7 +117,7 @@ set `u`. -/ theorem exists_disjoint_diff (h : AEDisjoint μ s t) : ∃ u, MeasurableSet u ∧ μ u = 0 ∧ Disjoint (s \ u) t := ⟨toMeasurable μ (s ∩ t), measurableSet_toMeasurable _ _, (measure_toMeasurable _).trans h, - disjoint_sdiff_self_left.mono_left fun x hx => by + disjoint_sdiff_self_left.mono_left (b := s \ t) fun x hx => by simpa using ⟨hx.1, fun hxt => hx.2 <| subset_toMeasurable _ _ ⟨hx.1, hxt⟩⟩⟩ theorem of_null_right (h : μ t = 0) : AEDisjoint μ s t := diff --git a/Mathlib/MeasureTheory/Measure/AEMeasurable.lean b/Mathlib/MeasureTheory/Measure/AEMeasurable.lean index c1459922a78e9..7ea4ac9be4b94 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 @@ -208,7 +208,7 @@ theorem subtype_mk (h : AEMeasurable f μ) {s : Set β} {hfs : ∀ x, f x ∈ s} AEMeasurable (codRestrict f s hfs) μ := by nontriviality α; inhabit α obtain ⟨g, g_meas, hg, fg⟩ : ∃ g : α → β, Measurable g ∧ range g ⊆ s ∧ f =ᵐ[μ] g := - h.exists_ae_eq_range_subset (eventually_of_forall hfs) ⟨_, hfs default⟩ + h.exists_ae_eq_range_subset (Eventually.of_forall hfs) ⟨_, hfs default⟩ refine ⟨codRestrict g s fun x => hg (mem_range_self _), Measurable.subtype_mk g_meas, ?_⟩ filter_upwards [fg] with x hx simpa [Subtype.ext_iff] diff --git a/Mathlib/MeasureTheory/Measure/AddContent.lean b/Mathlib/MeasureTheory/Measure/AddContent.lean index 362cd5b634339..e07a40a78c24f 100644 --- a/Mathlib/MeasureTheory/Measure/AddContent.lean +++ b/Mathlib/MeasureTheory/Measure/AddContent.lean @@ -63,9 +63,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 +90,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 ccb2008885c00..7ce4fcfe8f699 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` @@ -42,6 +40,10 @@ 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. -/ @@ -54,7 +56,7 @@ def re : ComplexMeasure α →ₗ[ℝ] SignedMeasure α := def im : ComplexMeasure α →ₗ[ℝ] SignedMeasure α := mapRangeₗ Complex.imCLM Complex.continuous_im -/-- Given `s` and `t` signed measures, `s + it` is a complex measure-/ +/-- Given `s` and `t` signed measures, `s + it` is a complex measure -/ @[simps!] def _root_.MeasureTheory.SignedMeasure.toComplexMeasure (s t : SignedMeasure α) : ComplexMeasure α where diff --git a/Mathlib/MeasureTheory/Measure/Content.lean b/Mathlib/MeasureTheory/Measure/Content.lean index 5306eb0281091..b07a09b9ad57e 100644 --- a/Mathlib/MeasureTheory/Measure/Content.lean +++ b/Mathlib/MeasureTheory/Measure/Content.lean @@ -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/ContinuousPreimage.lean b/Mathlib/MeasureTheory/Measure/ContinuousPreimage.lean new file mode 100644 index 0000000000000..b98c2b2b39069 --- /dev/null +++ b/Mathlib/MeasureTheory/Measure/ContinuousPreimage.lean @@ -0,0 +1,121 @@ +/- +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.CompactOpen +import Mathlib.Dynamics.Ergodic.MeasurePreserving +import Mathlib.MeasureTheory.Measure.Regular + +/-! +# Continuity of the preimage of a set under a measure preserving continuous function + +In this file we prove that the preimage of a null measurable set `s : Set Y` +under a measure preserving continuous function `f : C(X, Y)` is continuous in `f` +in the sense that `μ ((f a ⁻¹' s) ∆ (g ⁻¹' s))` tends to zero as `f a` tends to `g`. + +As a corollary, we show that +for a continuous family of continuous maps `f z : C(X, Y)`, +a null measurable set `s`, and a null measurable set `t` of finite measure, +the set of parameters `z` such that `f z ⁻¹' t` is a.e. equal to `s` is a closed set. +-/ + +open Filter Set +open scoped ENNReal symmDiff Topology + +namespace MeasureTheory + +variable {α X Y Z : Type*} + [TopologicalSpace X] [MeasurableSpace X] [BorelSpace X] [R1Space X] + [TopologicalSpace Y] [MeasurableSpace Y] [BorelSpace Y] [R1Space Y] + [TopologicalSpace Z] + {μ : Measure X} {ν : Measure Y} [μ.InnerRegularCompactLTTop] [IsLocallyFiniteMeasure ν] + +/-- Let `X` and `Y` be R₁ topological spaces +with Borel σ-algebras and measures `μ` and `ν`, respectively. +Suppose that `μ` is inner regular for finite measure sets with respect to compact sets +and `ν` is a locally finite measure. +Let `f : α → C(X, Y)` be a family of continuous maps +that converges to a continuous map `g : C(X, Y)` in the compact-open topology along a filter `l`. +Suppose that `g` is a measure preserving map +and `f a` is a measure preserving map eventually along `l`. +Then for any finite measure measurable set `s`, +the preimages `f a ⁻¹' s` tend to the preimage `g ⁻¹' s` in measure. +More precisely, the measure of the symmetric difference of these two sets tends to zero. -/ +theorem tendsto_measure_symmDiff_preimage_nhds_zero + {l : Filter α} {f : α → C(X, Y)} {g : C(X, Y)} {s : Set Y} (hfg : Tendsto f l (𝓝 g)) + (hf : ∀ᶠ a in l, MeasurePreserving (f a) μ ν) (hg : MeasurePreserving g μ ν) + (hs : NullMeasurableSet s ν) (hνs : ν s ≠ ∞) : + Tendsto (fun a ↦ μ ((f a ⁻¹' s) ∆ (g ⁻¹' s))) l (𝓝 0) := by + have : ν.InnerRegularCompactLTTop := by + rw [← hg.map_eq] + exact .map_of_continuous (map_continuous _) + rw [ENNReal.tendsto_nhds_zero] + intro ε hε + -- Without loss of generality, `s` is an open set. + wlog hso : IsOpen s generalizing s ε + · have H : 0 < ε / 3 := ENNReal.div_pos hε.ne' ENNReal.coe_ne_top + -- Indeed, we can choose an open set `U` such that `ν (U ∆ s) < ε / 3`, + -- apply the lemma to `U`, then use the triangle inequality for `μ (_ ∆ _)`. + rcases hs.exists_isOpen_symmDiff_lt hνs H.ne' with ⟨U, hUo, hU, hUs⟩ + have hmU : NullMeasurableSet U ν := hUo.measurableSet.nullMeasurableSet + replace hUs := hUs.le + filter_upwards [hf, this hmU hU.ne _ H hUo] with a hfa ha + calc + μ ((f a ⁻¹' s) ∆ (g ⁻¹' s)) + ≤ μ ((f a ⁻¹' s) ∆ (f a ⁻¹' U)) + μ ((f a ⁻¹' U) ∆ (g ⁻¹' U)) + + μ ((g ⁻¹' U) ∆ (g ⁻¹' s)) := by + refine (measure_symmDiff_le _ (g ⁻¹' U) _).trans ?_ + gcongr + apply measure_symmDiff_le + _ ≤ ε / 3 + ε / 3 + ε / 3 := by + gcongr + · rwa [← preimage_symmDiff, hfa.measure_preimage (hs.symmDiff hmU), symmDiff_comm] + · rwa [← preimage_symmDiff, hg.measure_preimage (hmU.symmDiff hs)] + _ = ε := by simp + -- Take a compact closed subset `K ⊆ g ⁻¹' s` of almost full measure, + -- `μ (g ⁻¹' s \ K) < ε / 2`. + have hνs' : μ (g ⁻¹' s) ≠ ∞ := by rwa [hg.measure_preimage hs] + obtain ⟨K, hKg, hKco, hKcl, hKμ⟩ : + ∃ K, MapsTo g K s ∧ IsCompact K ∧ IsClosed K ∧ μ (g ⁻¹' s \ K) < ε / 2 := + (hg.measurable hso.measurableSet).exists_isCompact_isClosed_diff_lt hνs' <| by simp [hε.ne'] + have hKm : NullMeasurableSet K μ := hKcl.nullMeasurableSet + -- Take `a` such that `f a` is measure preserving and maps `K` to `s`. + -- This is possible, because `K` is a compact set and `s` is an open set. + filter_upwards [hf, ContinuousMap.tendsto_nhds_compactOpen.mp hfg K hKco s hso hKg] with a hfa ha + -- Then each of the sets `g ⁻¹' s ∆ K = g ⁻¹' s \ K` and `f a ⁻¹' s ∆ K = f a ⁻¹' s \ K` + -- have measure at most `ε / 2`, thus `f a ⁻¹' s ∆ g ⁻¹' s` has measure at most `ε`. + rw [← ENNReal.add_halves ε] + refine (measure_symmDiff_le _ K _).trans ?_ + rw [symmDiff_of_ge ha.subset_preimage, symmDiff_of_le hKg.subset_preimage] + gcongr + have hK' : μ K ≠ ∞ := ne_top_of_le_ne_top hνs' <| measure_mono hKg.subset_preimage + rw [measure_diff_le_iff_le_add hKm ha.subset_preimage hK', hfa.measure_preimage hs, + ← hg.measure_preimage hs, ← measure_diff_le_iff_le_add hKm hKg.subset_preimage hK'] + exact hKμ.le + +/-- Let `f : Z → C(X, Y)` be a continuous (in the compact open topology) family +of continuous measure preserving maps. +Let `t : Set Y` be a null measurable set of finite measure. +Then for any `s`, the set of parameters `z` +such that the preimage of `t` under `f_z` is a.e. equal to `s` +is a closed set. + +In particular, if `X = Y` and `s = t`, +then we see that the a.e. stabilizer of a set is a closed set. -/ +theorem isClosed_setOf_preimage_ae_eq {f : Z → C(X, Y)} (hf : Continuous f) + (hfm : ∀ z, MeasurePreserving (f z) μ ν) (s : Set X) + {t : Set Y} (htm : NullMeasurableSet t ν) (ht : ν t ≠ ∞) : + IsClosed {z | f z ⁻¹' t =ᵐ[μ] s} := by + rw [← isOpen_compl_iff, isOpen_iff_mem_nhds] + intro z hz + replace hz : ∀ᶠ ε : ℝ≥0∞ in 𝓝 0, ε < μ ((f z ⁻¹' t) ∆ s) := by + apply gt_mem_nhds + rwa [pos_iff_ne_zero, ne_eq, measure_symmDiff_eq_zero_iff] + filter_upwards [(tendsto_measure_symmDiff_preimage_nhds_zero (hf.tendsto z) + (.of_forall hfm) (hfm z) htm ht).eventually hz] with w hw + intro (hw' : f w ⁻¹' t =ᵐ[μ] s) + rw [measure_congr (hw'.symmDiff (ae_eq_refl _)), symmDiff_comm] at hw + exact hw.false + +end MeasureTheory diff --git a/Mathlib/MeasureTheory/Measure/Count.lean b/Mathlib/MeasureTheory/Measure/Count.lean index 6b263eb05db16..0383da666916a 100644 --- a/Mathlib/MeasureTheory/Measure/Count.lean +++ b/Mathlib/MeasureTheory/Measure/Count.lean @@ -26,6 +26,8 @@ namespace MeasureTheory.Measure def count : Measure α := sum dirac +@[simp] lemma count_ne_zero'' [Nonempty α] : (count : Measure α) ≠ 0 := by simp [count] + theorem le_count_apply : ∑' _ : s, (1 : ℝ≥0∞) ≤ count s := calc (∑' _ : s, 1 : ℝ≥0∞) = ∑' i, indicator s 1 i := tsum_subtype s 1 @@ -157,9 +159,10 @@ theorem count_injective_image [MeasurableSingletonClass α] [MeasurableSingleton instance count.isFiniteMeasure [Finite α] : IsFiniteMeasure (Measure.count : Measure α) := - ⟨by - cases nonempty_fintype α - simpa [Measure.count_apply, tsum_fintype] using (ENNReal.natCast_ne_top _).lt_top⟩ + ⟨by cases nonempty_fintype α; simp [Measure.count_apply, tsum_fintype]⟩ + +@[simp] lemma count_univ [Fintype α] : count (univ : Set α) = Fintype.card α := by + rw [count_apply .univ]; exact (tsum_univ 1).trans (by simp [tsum_fintype]) end Measure diff --git a/Mathlib/MeasureTheory/Measure/Dirac.lean b/Mathlib/MeasureTheory/Measure/Dirac.lean index ad6623a9ff812..29e9d534230ce 100644 --- a/Mathlib/MeasureTheory/Measure/Dirac.lean +++ b/Mathlib/MeasureTheory/Measure/Dirac.lean @@ -54,6 +54,9 @@ theorem dirac_apply [MeasurableSingletonClass α] (a : α) (s : Set α) : dirac a s ≤ dirac a {a}ᶜ := measure_mono (subset_compl_comm.1 <| singleton_subset_iff.2 h) _ = 0 := by simp [dirac_apply' _ (measurableSet_singleton _).compl] +@[simp] lemma dirac_ne_zero : dirac a ≠ 0 := + fun h ↦ by simpa [h] using dirac_apply_of_mem (mem_univ a) + theorem map_dirac {f : α → β} (hf : Measurable f) (a : α) : (dirac a).map f = dirac (f a) := by classical exact ext fun s hs => by simp [hs, map_apply hf hs, hf hs, indicator_apply] diff --git a/Mathlib/MeasureTheory/Measure/DiracProba.lean b/Mathlib/MeasureTheory/Measure/DiracProba.lean index 4dd9303f1e13b..18bc9a7f40a5e 100644 --- a/Mathlib/MeasureTheory/Measure/DiracProba.lean +++ b/Mathlib/MeasureTheory/Measure/DiracProba.lean @@ -101,7 +101,7 @@ lemma not_tendsto_diracProba_of_not_tendsto [CompletelyRegularSpace X] {x : X} ( lintegral_dirac' _ (measurable_coe_nnreal_ennreal_iff.mpr f.continuous.measurable)] apply not_tendsto_iff_exists_frequently_nmem.mpr refine ⟨Ioi 0, Ioi_mem_nhds (by simp only [ENNReal.coe_one, zero_lt_one]), - hU.mp (eventually_of_forall ?_)⟩ + hU.mp (Eventually.of_forall ?_)⟩ intro x x_notin_U rw [f_vanishes_outside x (compl_subset_compl.mpr (show interior U ⊆ U from interior_subset) x_notin_U)] diff --git a/Mathlib/MeasureTheory/Measure/EverywherePos.lean b/Mathlib/MeasureTheory/Measure/EverywherePos.lean index 753d1e7f9e58c..1d8c5d6773ce4 100644 --- a/Mathlib/MeasureTheory/Measure/EverywherePos.lean +++ b/Mathlib/MeasureTheory/Measure/EverywherePos.lean @@ -243,13 +243,13 @@ lemma IsEverywherePos.IsGdelta_of_isMulLeftInvariant apply le_of_lt (hW _ _ ?_) have : W n * {z} ∈ 𝓝 z := (IsOpen.mul_right (W_open n)).mem_nhds (by simp [mem_W]) obtain ⟨i, hi, ni⟩ : ∃ i, y i ∈ W n * {z} ∧ n < i := - (((mapClusterPt_iff _ _ _).1 hz _ this).and_eventually (eventually_gt_atTop n)).exists + ((mapClusterPt_iff.1 hz _ this).and_eventually (eventually_gt_atTop n)).exists refine ⟨x * (y i) ⁻¹, ?_, y i * z⁻¹, by simpa using hi, by group⟩ have I : V i ⊆ W n := iInter₂_subset n (by simp [ni]) have J : x * (y i) ⁻¹ ∈ V i := by simpa [← hvy i] using hv i exact I J have B : μ (((x * z ⁻¹) • k) \ k) = 0 := - le_antisymm (ge_of_tendsto u_lim (eventually_of_forall A)) bot_le + le_antisymm (ge_of_tendsto u_lim (Eventually.of_forall A)) bot_le have C : μ (k \ (z * x⁻¹) • k) = 0 := by have : μ ((z * x⁻¹) • (((x * z ⁻¹) • k) \ k)) = 0 := by rwa [measure_smul] rw [← this, smul_set_sdiff, smul_smul] diff --git a/Mathlib/MeasureTheory/Measure/FiniteMeasure.lean b/Mathlib/MeasureTheory/Measure/FiniteMeasure.lean index 788da2c597187..f10ffdcda79a3 100644 --- a/Mathlib/MeasureTheory/Measure/FiniteMeasure.lean +++ b/Mathlib/MeasureTheory/Measure/FiniteMeasure.lean @@ -81,14 +81,7 @@ weak convergence of measures, finite measure noncomputable section -open MeasureTheory - -open Set - -open Filter - -open BoundedContinuousFunction - +open MeasureTheory Set Filter BoundedContinuousFunction open scoped Topology ENNReal NNReal BoundedContinuousFunction namespace MeasureTheory @@ -125,22 +118,19 @@ def _root_.MeasureTheory.FiniteMeasure (Ω : Type*) [MeasurableSpace Ω] : Type def toMeasure : FiniteMeasure Ω → Measure Ω := Subtype.val /-- A finite measure can be interpreted as a measure. -/ -instance instCoe : Coe (FiniteMeasure Ω) (MeasureTheory.Measure Ω) where - coe := toMeasure +instance instCoe : Coe (FiniteMeasure Ω) (MeasureTheory.Measure Ω) := { coe := toMeasure } -instance isFiniteMeasure (μ : FiniteMeasure Ω) : IsFiniteMeasure (μ : Measure Ω) := - μ.prop +instance isFiniteMeasure (μ : FiniteMeasure Ω) : IsFiniteMeasure (μ : Measure Ω) := μ.prop @[simp] -theorem val_eq_toMeasure (ν : FiniteMeasure Ω) : ν.val = (ν : Measure Ω) := - rfl +theorem val_eq_toMeasure (ν : FiniteMeasure Ω) : ν.val = (ν : Measure Ω) := rfl theorem toMeasure_injective : Function.Injective ((↑) : FiniteMeasure Ω → Measure Ω) := Subtype.coe_injective instance instFunLike : FunLike (FiniteMeasure Ω) (Set Ω) ℝ≥0 where coe μ s := ((μ : Measure Ω) s).toNNReal - coe_injective' μ ν h := toMeasure_injective $ Measure.ext fun s _ ↦ by + coe_injective' μ ν h := toMeasure_injective <| Measure.ext fun s _ ↦ by simpa [ENNReal.toNNReal_eq_toNNReal_iff, measure_ne_top] using congr_fun h s lemma coeFn_def (μ : FiniteMeasure Ω) : μ = fun s ↦ ((μ : Measure Ω) s).toNNReal := rfl @@ -157,15 +147,18 @@ theorem ennreal_coeFn_eq_coeFn_toMeasure (ν : FiniteMeasure Ω) (s : Set Ω) : (ν s : ℝ≥0∞) = (ν : Measure Ω) s := ENNReal.coe_toNNReal (measure_lt_top (↑ν) s).ne -theorem apply_mono (μ : FiniteMeasure Ω) {s₁ s₂ : Set Ω} (h : s₁ ⊆ s₂) : μ s₁ ≤ μ s₂ := by - change ((μ : Measure Ω) s₁).toNNReal ≤ ((μ : Measure Ω) s₂).toNNReal - have key : (μ : Measure Ω) s₁ ≤ (μ : Measure Ω) s₂ := (μ : Measure Ω).mono h - apply (ENNReal.toNNReal_le_toNNReal (measure_ne_top _ s₁) (measure_ne_top _ s₂)).mpr key +@[simp] +theorem null_iff_toMeasure_null (ν : FiniteMeasure Ω) (s : Set Ω) : + ν s = 0 ↔ (ν : Measure Ω) s = 0 := + ⟨fun h ↦ by rw [← ennreal_coeFn_eq_coeFn_toMeasure, h, ENNReal.coe_zero], + fun h ↦ congrArg ENNReal.toNNReal h⟩ + +theorem apply_mono (μ : FiniteMeasure Ω) {s₁ s₂ : Set Ω} (h : s₁ ⊆ s₂) : μ s₁ ≤ μ s₂ := + ENNReal.toNNReal_mono (measure_ne_top _ s₂) ((μ : Measure Ω).mono h) /-- The (total) mass of a finite measure `μ` is `μ univ`, i.e., the cast to `NNReal` of `(μ : measure Ω) univ`. -/ -def mass (μ : FiniteMeasure Ω) : ℝ≥0 := - μ univ +def mass (μ : FiniteMeasure Ω) : ℝ≥0 := μ univ @[simp] theorem apply_le_mass (μ : FiniteMeasure Ω) (s : Set Ω) : μ s ≤ μ.mass := by simpa using apply_mono μ (subset_univ s) @@ -179,8 +172,7 @@ instance instZero : Zero (FiniteMeasure Ω) where zero := ⟨0, MeasureTheory.is @[simp, norm_cast] lemma coeFn_zero : ⇑(0 : FiniteMeasure Ω) = 0 := rfl @[simp] -theorem zero_mass : (0 : FiniteMeasure Ω).mass = 0 := - rfl +theorem zero_mass : (0 : FiniteMeasure Ω).mass = 0 := rfl @[simp] theorem mass_zero_iff (μ : FiniteMeasure Ω) : μ.mass = 0 ↔ μ = 0 := by @@ -189,9 +181,8 @@ theorem mass_zero_iff (μ : FiniteMeasure Ω) : μ.mass = 0 ↔ μ = 0 := by apply Measure.measure_univ_eq_zero.mp rwa [← ennreal_mass, ENNReal.coe_eq_zero] -theorem mass_nonzero_iff (μ : FiniteMeasure Ω) : μ.mass ≠ 0 ↔ μ ≠ 0 := by - rw [not_iff_not] - exact FiniteMeasure.mass_zero_iff μ +theorem mass_nonzero_iff (μ : FiniteMeasure Ω) : μ.mass ≠ 0 ↔ μ ≠ 0 := + not_iff_not.mpr <| FiniteMeasure.mass_zero_iff μ @[ext] theorem eq_of_forall_toMeasure_apply_eq (μ ν : FiniteMeasure Ω) @@ -205,8 +196,7 @@ theorem eq_of_forall_apply_eq (μ ν : FiniteMeasure Ω) ext1 s s_mble simpa [ennreal_coeFn_eq_coeFn_toMeasure] using congr_arg ((↑) : ℝ≥0 → ℝ≥0∞) (h s s_mble) -instance instInhabited : Inhabited (FiniteMeasure Ω) := - ⟨0⟩ +instance instInhabited : Inhabited (FiniteMeasure Ω) := ⟨0⟩ instance instAdd : Add (FiniteMeasure Ω) where add μ ν := ⟨μ + ν, MeasureTheory.isFiniteMeasureAdd⟩ @@ -217,13 +207,11 @@ instance instSMul : SMul R (FiniteMeasure Ω) where smul (c : R) μ := ⟨c • (μ : Measure Ω), MeasureTheory.isFiniteMeasureSMulOfNNRealTower⟩ @[simp, norm_cast] -theorem toMeasure_zero : ((↑) : FiniteMeasure Ω → Measure Ω) 0 = 0 := - rfl +theorem toMeasure_zero : ((↑) : FiniteMeasure Ω → Measure Ω) 0 = 0 := rfl -- Porting note: with `simp` here the `coeFn` lemmas below fall prey to `simpNF`: the LHS simplifies @[norm_cast] -theorem toMeasure_add (μ ν : FiniteMeasure Ω) : ↑(μ + ν) = (↑μ + ↑ν : Measure Ω) := - rfl +theorem toMeasure_add (μ ν : FiniteMeasure Ω) : ↑(μ + ν) = (↑μ + ↑ν : Measure Ω) := rfl @[simp, norm_cast] theorem toMeasure_smul (c : R) (μ : FiniteMeasure Ω) : ↑(c • μ) = c • (μ : Measure Ω) := @@ -242,7 +230,7 @@ theorem coeFn_smul [IsScalarTower R ℝ≥0 ℝ≥0] (c : R) (μ : FiniteMeasure funext; simp [← ENNReal.coe_inj, ENNReal.coe_smul] instance instAddCommMonoid : AddCommMonoid (FiniteMeasure Ω) := - toMeasure_injective.addCommMonoid (↑) toMeasure_zero toMeasure_add fun _ _ => toMeasure_smul _ _ + toMeasure_injective.addCommMonoid (↑) toMeasure_zero toMeasure_add fun _ _ ↦ toMeasure_smul _ _ /-- Coercion is an `AddMonoidHom`. -/ @[simps] @@ -265,8 +253,7 @@ def restrict (μ : FiniteMeasure Ω) (A : Set Ω) : FiniteMeasure Ω where property := MeasureTheory.isFiniteMeasureRestrict (μ : Measure Ω) A theorem restrict_measure_eq (μ : FiniteMeasure Ω) (A : Set Ω) : - (μ.restrict A : Measure Ω) = (μ : Measure Ω).restrict A := - rfl + (μ.restrict A : Measure Ω) = (μ : Measure Ω).restrict A := rfl theorem restrict_apply_measure (μ : FiniteMeasure Ω) (A : Set Ω) {s : Set Ω} (s_mble : MeasurableSet s) : (μ.restrict A : Measure Ω) s = (μ : Measure Ω) (s ∩ A) := @@ -358,8 +345,7 @@ theorem testAgainstNN_smul [IsScalarTower R ℝ≥0 ℝ≥0] [PseudoMetricSpace ENNReal.coe_smul] simp_rw [← smul_one_smul ℝ≥0∞ c (f _ : ℝ≥0∞), ← smul_one_smul ℝ≥0∞ c (lintegral _ _ : ℝ≥0∞), smul_eq_mul] - exact - @lintegral_const_mul _ _ (μ : Measure Ω) (c • (1 : ℝ≥0∞)) _ f.measurable_coe_ennreal_comp + exact lintegral_const_mul (c • (1 : ℝ≥0∞)) f.measurable_coe_ennreal_comp theorem testAgainstNN_lipschitz_estimate (μ : FiniteMeasure Ω) (f g : Ω →ᵇ ℝ≥0) : μ.testAgainstNN f ≤ μ.testAgainstNN g + nndist f g * μ.mass := by @@ -370,32 +356,29 @@ theorem testAgainstNN_lipschitz_estimate (μ : FiniteMeasure Ω) (f g : Ω → have le_dist : ∀ ω, dist (f ω) (g ω) ≤ nndist f g := BoundedContinuousFunction.dist_coe_le_dist intro ω have le' : f ω ≤ g ω + nndist f g := by - apply (NNReal.le_add_nndist (f ω) (g ω)).trans - rw [add_le_add_iff_left] - exact dist_le_coe.mp (le_dist ω) + calc f ω + _ ≤ g ω + nndist (f ω) (g ω) := NNReal.le_add_nndist (f ω) (g ω) + _ ≤ g ω + nndist f g := (add_le_add_iff_left (g ω)).mpr (le_dist ω) have le : (f ω : ℝ≥0∞) ≤ (g ω : ℝ≥0∞) + nndist f g := by - rw [← ENNReal.coe_add] - exact ENNReal.coe_mono le' + simpa only [← ENNReal.coe_add] using (by exact_mod_cast le') rwa [coe_nnreal_ennreal_nndist] at le theorem testAgainstNN_lipschitz (μ : FiniteMeasure Ω) : - LipschitzWith μ.mass fun f : Ω →ᵇ ℝ≥0 => μ.testAgainstNN f := by + LipschitzWith μ.mass fun f : Ω →ᵇ ℝ≥0 ↦ μ.testAgainstNN f := by rw [lipschitzWith_iff_dist_le_mul] intro f₁ f₂ suffices abs (μ.testAgainstNN f₁ - μ.testAgainstNN f₂ : ℝ) ≤ μ.mass * dist f₁ f₂ by rwa [NNReal.dist_eq] apply abs_le.mpr constructor - · have key' := μ.testAgainstNN_lipschitz_estimate f₂ f₁ - rw [mul_comm] at key' + · have key := μ.testAgainstNN_lipschitz_estimate f₂ f₁ + rw [mul_comm] at key suffices ↑(μ.testAgainstNN f₂) ≤ ↑(μ.testAgainstNN f₁) + ↑μ.mass * dist f₁ f₂ by linarith - have key := NNReal.coe_mono key' - rwa [NNReal.coe_add, NNReal.coe_mul, nndist_comm] at key - · have key' := μ.testAgainstNN_lipschitz_estimate f₁ f₂ - rw [mul_comm] at key' + simpa [nndist_comm] using NNReal.coe_mono key + · have key := μ.testAgainstNN_lipschitz_estimate f₁ f₂ + rw [mul_comm] at key suffices ↑(μ.testAgainstNN f₁) ≤ ↑(μ.testAgainstNN f₂) + ↑μ.mass * dist f₁ f₂ by linarith - have key := NNReal.coe_mono key' - rwa [NNReal.coe_add, NNReal.coe_mul] at key + simpa using NNReal.coe_mono key /-- Finite measures yield elements of the `WeakDual` of bounded continuous nonnegative functions via `MeasureTheory.FiniteMeasure.testAgainstNN`, i.e., integration. -/ @@ -411,8 +394,7 @@ theorem coe_toWeakDualBCNN (μ : FiniteMeasure Ω) : ⇑μ.toWeakDualBCNN = μ.t @[simp] theorem toWeakDualBCNN_apply (μ : FiniteMeasure Ω) (f : Ω →ᵇ ℝ≥0) : - μ.toWeakDualBCNN f = (∫⁻ x, f x ∂(μ : Measure Ω)).toNNReal := - rfl + μ.toWeakDualBCNN f = (∫⁻ x, f x ∂(μ : Measure Ω)).toNNReal := rfl /-- The topology of weak convergence on `MeasureTheory.FiniteMeasure Ω` is inherited (induced) from the weak-* topology on `WeakDual ℝ≥0 (Ω →ᵇ ℝ≥0)` via the function @@ -426,8 +408,8 @@ theorem toWeakDualBCNN_continuous : Continuous (@toWeakDualBCNN Ω _ _ _) := /-- Integration of (nonnegative bounded continuous) test functions against finite Borel measures depends continuously on the measure. -/ theorem continuous_testAgainstNN_eval (f : Ω →ᵇ ℝ≥0) : - Continuous fun μ : FiniteMeasure Ω => μ.testAgainstNN f := by - show Continuous ((fun φ : WeakDual ℝ≥0 (Ω →ᵇ ℝ≥0) => φ f) ∘ toWeakDualBCNN) + Continuous fun μ : FiniteMeasure Ω ↦ μ.testAgainstNN f := by + show Continuous ((fun φ : WeakDual ℝ≥0 (Ω →ᵇ ℝ≥0) ↦ φ f) ∘ toWeakDualBCNN) refine Continuous.comp ?_ (toWeakDualBCNN_continuous (Ω := Ω)) exact WeakBilin.eval_continuous (𝕜 := ℝ≥0) (E := (Ω →ᵇ ℝ≥0) →L[ℝ≥0] ℝ≥0) _ _ /- porting note: without explicitly providing `𝕜` and `E` TC synthesis times @@ -435,29 +417,29 @@ theorem continuous_testAgainstNN_eval (f : Ω →ᵇ ℝ≥0) : `set_option synthInstance.maxHeartbeats 47000` was sufficient. -/ /-- The total mass of a finite measure depends continuously on the measure. -/ -theorem continuous_mass : Continuous fun μ : FiniteMeasure Ω => μ.mass := by +theorem continuous_mass : Continuous fun μ : FiniteMeasure Ω ↦ μ.mass := by simp_rw [← testAgainstNN_one]; exact continuous_testAgainstNN_eval 1 /-- Convergence of finite measures implies the convergence of their total masses. -/ theorem _root_.Filter.Tendsto.mass {γ : Type*} {F : Filter γ} {μs : γ → FiniteMeasure Ω} - {μ : FiniteMeasure Ω} (h : Tendsto μs F (𝓝 μ)) : Tendsto (fun i => (μs i).mass) F (𝓝 μ.mass) := + {μ : FiniteMeasure Ω} (h : Tendsto μs F (𝓝 μ)) : Tendsto (fun i ↦ (μs i).mass) F (𝓝 μ.mass) := (continuous_mass.tendsto μ).comp h -theorem tendsto_iff_weak_star_tendsto {γ : Type*} {F : Filter γ} {μs : γ → FiniteMeasure Ω} +theorem tendsto_iff_weakDual_tendsto {γ : Type*} {F : Filter γ} {μs : γ → FiniteMeasure Ω} {μ : FiniteMeasure Ω} : - Tendsto μs F (𝓝 μ) ↔ Tendsto (fun i => (μs i).toWeakDualBCNN) F (𝓝 μ.toWeakDualBCNN) := + Tendsto μs F (𝓝 μ) ↔ Tendsto (fun i ↦ (μs i).toWeakDualBCNN) F (𝓝 μ.toWeakDualBCNN) := Inducing.tendsto_nhds_iff ⟨rfl⟩ theorem tendsto_iff_forall_toWeakDualBCNN_tendsto {γ : Type*} {F : Filter γ} {μs : γ → FiniteMeasure Ω} {μ : FiniteMeasure Ω} : Tendsto μs F (𝓝 μ) ↔ - ∀ f : Ω →ᵇ ℝ≥0, Tendsto (fun i => (μs i).toWeakDualBCNN f) F (𝓝 (μ.toWeakDualBCNN f)) := by - rw [tendsto_iff_weak_star_tendsto, tendsto_iff_forall_eval_tendsto_topDualPairing]; rfl + ∀ f : Ω →ᵇ ℝ≥0, Tendsto (fun i ↦ (μs i).toWeakDualBCNN f) F (𝓝 (μ.toWeakDualBCNN f)) := by + rw [tendsto_iff_weakDual_tendsto, tendsto_iff_forall_eval_tendsto_topDualPairing]; rfl theorem tendsto_iff_forall_testAgainstNN_tendsto {γ : Type*} {F : Filter γ} {μs : γ → FiniteMeasure Ω} {μ : FiniteMeasure Ω} : Tendsto μs F (𝓝 μ) ↔ - ∀ f : Ω →ᵇ ℝ≥0, Tendsto (fun i => (μs i).testAgainstNN f) F (𝓝 (μ.testAgainstNN f)) := by + ∀ f : Ω →ᵇ ℝ≥0, Tendsto (fun i ↦ (μs i).testAgainstNN f) F (𝓝 (μ.testAgainstNN f)) := by rw [FiniteMeasure.tendsto_iff_forall_toWeakDualBCNN_tendsto]; rfl /-- If the total masses of finite measures tend to zero, then the measures tend to @@ -465,23 +447,21 @@ zero. This formulation concerns the associated functionals on bounded continuous nonnegative test functions. See `MeasureTheory.FiniteMeasure.tendsto_zero_of_tendsto_zero_mass` for a formulation stating the weak convergence of measures. -/ theorem tendsto_zero_testAgainstNN_of_tendsto_zero_mass {γ : Type*} {F : Filter γ} - {μs : γ → FiniteMeasure Ω} (mass_lim : Tendsto (fun i => (μs i).mass) F (𝓝 0)) (f : Ω →ᵇ ℝ≥0) : - Tendsto (fun i => (μs i).testAgainstNN f) F (𝓝 0) := by + {μs : γ → FiniteMeasure Ω} (mass_lim : Tendsto (fun i ↦ (μs i).mass) F (𝓝 0)) (f : Ω →ᵇ ℝ≥0) : + Tendsto (fun i ↦ (μs i).testAgainstNN f) F (𝓝 0) := by apply tendsto_iff_dist_tendsto_zero.mpr - have obs := fun i => (μs i).testAgainstNN_lipschitz_estimate f 0 + have obs := fun i ↦ (μs i).testAgainstNN_lipschitz_estimate f 0 simp_rw [testAgainstNN_zero, zero_add] at obs simp_rw [show ∀ i, dist ((μs i).testAgainstNN f) 0 = (μs i).testAgainstNN f by simp only [dist_nndist, NNReal.nndist_zero_eq_val', eq_self_iff_true, imp_true_iff]] - refine squeeze_zero (fun i => NNReal.coe_nonneg _) obs ?_ - have lim_pair : Tendsto (fun i => (⟨nndist f 0, (μs i).mass⟩ : ℝ × ℝ)) F (𝓝 ⟨nndist f 0, 0⟩) := by - refine (Prod.tendsto_iff _ _).mpr ⟨tendsto_const_nhds, ?_⟩ - exact (NNReal.continuous_coe.tendsto 0).comp mass_lim - have key := tendsto_mul.comp lim_pair - rwa [mul_zero] at key + apply squeeze_zero (fun i ↦ NNReal.coe_nonneg _) obs + have lim_pair : Tendsto (fun i ↦ (⟨nndist f 0, (μs i).mass⟩ : ℝ × ℝ)) F (𝓝 ⟨nndist f 0, 0⟩) := + (Prod.tendsto_iff _ _).mpr ⟨tendsto_const_nhds, (NNReal.continuous_coe.tendsto 0).comp mass_lim⟩ + simpa using tendsto_mul.comp lim_pair /-- If the total masses of finite measures tend to zero, then the measures tend to zero. -/ theorem tendsto_zero_of_tendsto_zero_mass {γ : Type*} {F : Filter γ} {μs : γ → FiniteMeasure Ω} - (mass_lim : Tendsto (fun i => (μs i).mass) F (𝓝 0)) : Tendsto μs F (𝓝 0) := by + (mass_lim : Tendsto (fun i ↦ (μs i).mass) F (𝓝 0)) : Tendsto μs F (𝓝 0) := by rw [tendsto_iff_forall_testAgainstNN_tendsto] intro f convert tendsto_zero_testAgainstNN_of_tendsto_zero_mass mass_lim f @@ -493,7 +473,7 @@ theorem tendsto_iff_forall_lintegral_tendsto {γ : Type*} {F : Filter γ} {μs : {μ : FiniteMeasure Ω} : Tendsto μs F (𝓝 μ) ↔ ∀ f : Ω →ᵇ ℝ≥0, - Tendsto (fun i => ∫⁻ x, f x ∂(μs i : Measure Ω)) F (𝓝 (∫⁻ x, f x ∂(μ : Measure Ω))) := by + Tendsto (fun i ↦ ∫⁻ x, f x ∂(μs i : Measure Ω)) F (𝓝 (∫⁻ x, f x ∂(μ : Measure Ω))) := by rw [tendsto_iff_forall_toWeakDualBCNN_tendsto] simp_rw [toWeakDualBCNN_apply _ _, ← testAgainstNN_coe_eq, ENNReal.tendsto_coe, ENNReal.toNNReal_coe] @@ -557,11 +537,11 @@ A related result with more general assumptions is -/ theorem tendsto_lintegral_nn_of_le_const (μ : FiniteMeasure Ω) {fs : ℕ → Ω →ᵇ ℝ≥0} {c : ℝ≥0} (fs_le_const : ∀ n ω, fs n ω ≤ c) {f : Ω → ℝ≥0} - (fs_lim : ∀ ω, Tendsto (fun n => fs n ω) atTop (𝓝 (f ω))) : - Tendsto (fun n => ∫⁻ ω, fs n ω ∂(μ : Measure Ω)) atTop (𝓝 (∫⁻ ω, f ω ∂(μ : Measure Ω))) := + (fs_lim : ∀ ω, Tendsto (fun n ↦ fs n ω) atTop (𝓝 (f ω))) : + Tendsto (fun n ↦ ∫⁻ ω, fs n ω ∂(μ : Measure Ω)) atTop (𝓝 (∫⁻ ω, f ω ∂(μ : Measure Ω))) := tendsto_lintegral_nn_filter_of_le_const μ - (eventually_of_forall fun n => eventually_of_forall (fs_le_const n)) - (eventually_of_forall fs_lim) + (.of_forall fun n ↦ .of_forall (fs_le_const n)) + (.of_forall fs_lim) /-- A bounded convergence theorem for a finite measure: If bounded continuous non-negative functions are uniformly bounded by a constant and tend to a @@ -579,8 +559,8 @@ A related result using `MeasureTheory.lintegral` for integration is theorem tendsto_testAgainstNN_filter_of_le_const {ι : Type*} {L : Filter ι} [L.IsCountablyGenerated] {μ : FiniteMeasure Ω} {fs : ι → Ω →ᵇ ℝ≥0} {c : ℝ≥0} (fs_le_const : ∀ᶠ i in L, ∀ᵐ ω : Ω ∂(μ : Measure Ω), fs i ω ≤ c) {f : Ω →ᵇ ℝ≥0} - (fs_lim : ∀ᵐ ω : Ω ∂(μ : Measure Ω), Tendsto (fun i => fs i ω) L (𝓝 (f ω))) : - Tendsto (fun i => μ.testAgainstNN (fs i)) L (𝓝 (μ.testAgainstNN f)) := by + (fs_lim : ∀ᵐ ω : Ω ∂(μ : Measure Ω), Tendsto (fun i ↦ fs i ω) L (𝓝 (f ω))) : + Tendsto (fun i ↦ μ.testAgainstNN (fs i)) L (𝓝 (μ.testAgainstNN f)) := by apply (ENNReal.tendsto_toNNReal (f.lintegral_lt_top_of_nnreal (μ : Measure Ω)).ne).comp exact tendsto_lintegral_nn_filter_of_le_const μ fs_le_const fs_lim @@ -597,11 +577,11 @@ Related results: -/ theorem tendsto_testAgainstNN_of_le_const {μ : FiniteMeasure Ω} {fs : ℕ → Ω →ᵇ ℝ≥0} {c : ℝ≥0} (fs_le_const : ∀ n ω, fs n ω ≤ c) {f : Ω →ᵇ ℝ≥0} - (fs_lim : ∀ ω, Tendsto (fun n => fs n ω) atTop (𝓝 (f ω))) : - Tendsto (fun n => μ.testAgainstNN (fs n)) atTop (𝓝 (μ.testAgainstNN f)) := + (fs_lim : ∀ ω, Tendsto (fun n ↦ fs n ω) atTop (𝓝 (f ω))) : + Tendsto (fun n ↦ μ.testAgainstNN (fs n)) atTop (𝓝 (μ.testAgainstNN f)) := tendsto_testAgainstNN_filter_of_le_const - (eventually_of_forall fun n => eventually_of_forall (fs_le_const n)) - (eventually_of_forall fs_lim) + (.of_forall fun n ↦ .of_forall (fs_le_const n)) + (.of_forall fs_lim) end FiniteMeasureBoundedConvergence @@ -619,27 +599,23 @@ variable {Ω : Type*} [MeasurableSpace Ω] [TopologicalSpace Ω] [OpensMeasurabl theorem tendsto_of_forall_integral_tendsto {γ : Type*} {F : Filter γ} {μs : γ → FiniteMeasure Ω} {μ : FiniteMeasure Ω} - (h : - ∀ f : Ω →ᵇ ℝ, - Tendsto (fun i => ∫ x, f x ∂(μs i : Measure Ω)) F (𝓝 (∫ x, f x ∂(μ : Measure Ω)))) : + (h : ∀ f : Ω →ᵇ ℝ, + Tendsto (fun i ↦ ∫ x, f x ∂(μs i : Measure Ω)) F (𝓝 (∫ x, f x ∂(μ : Measure Ω)))) : Tendsto μs F (𝓝 μ) := by - apply (@tendsto_iff_forall_lintegral_tendsto Ω _ _ _ γ F μs μ).mpr + apply tendsto_iff_forall_lintegral_tendsto.mpr intro f - have key := - @ENNReal.tendsto_toReal_iff _ F _ - (fun i => (f.lintegral_lt_top_of_nnreal (μs i)).ne) _ (f.lintegral_lt_top_of_nnreal μ).ne - simp only [ENNReal.ofReal_coe_nnreal] at key - apply key.mp + apply (ENNReal.tendsto_toReal_iff (fi := F) + (fun i ↦ (f.lintegral_lt_top_of_nnreal (μs i)).ne) (f.lintegral_lt_top_of_nnreal μ).ne).mp have lip : LipschitzWith 1 ((↑) : ℝ≥0 → ℝ) := isometry_subtype_coe.lipschitz set f₀ := BoundedContinuousFunction.comp _ lip f with _def_f₀ have f₀_eq : ⇑f₀ = ((↑) : ℝ≥0 → ℝ) ∘ ⇑f := rfl - have f₀_nn : 0 ≤ ⇑f₀ := fun _ => by + have f₀_nn : 0 ≤ ⇑f₀ := fun _ ↦ by simp only [f₀_eq, Pi.zero_apply, Function.comp_apply, NNReal.zero_le_coe] - have f₀_ae_nn : 0 ≤ᵐ[(μ : Measure Ω)] ⇑f₀ := eventually_of_forall f₀_nn - have f₀_ae_nns : ∀ i, 0 ≤ᵐ[(μs i : Measure Ω)] ⇑f₀ := fun i => eventually_of_forall f₀_nn + have f₀_ae_nn : 0 ≤ᵐ[(μ : Measure Ω)] ⇑f₀ := .of_forall f₀_nn + have f₀_ae_nns : ∀ i, 0 ≤ᵐ[(μs i : Measure Ω)] ⇑f₀ := fun i ↦ .of_forall f₀_nn have aux := integral_eq_lintegral_of_nonneg_ae f₀_ae_nn f₀.continuous.measurable.aestronglyMeasurable - have auxs := fun i => + have auxs := fun i ↦ integral_eq_lintegral_of_nonneg_ae (f₀_ae_nns i) f₀.continuous.measurable.aestronglyMeasurable simp_rw [f₀_eq, Function.comp_apply, ENNReal.ofReal_coe_nnreal] at aux auxs simpa only [← aux, ← auxs] using h f₀ @@ -650,7 +626,7 @@ theorem tendsto_iff_forall_integral_tendsto {γ : Type*} {F : Filter γ} {μs : {μ : FiniteMeasure Ω} : Tendsto μs F (𝓝 μ) ↔ ∀ f : Ω →ᵇ ℝ, - Tendsto (fun i => ∫ x, f x ∂(μs i : Measure Ω)) F (𝓝 (∫ x, f x ∂(μ : Measure Ω))) := by + Tendsto (fun i ↦ ∫ x, f x ∂(μs i : Measure Ω)) F (𝓝 (∫ x, f x ∂(μ : Measure Ω))) := by refine ⟨?_, tendsto_of_forall_integral_tendsto⟩ rw [tendsto_iff_forall_lintegral_tendsto] intro h f @@ -661,9 +637,9 @@ theorem tendsto_iff_forall_integral_tendsto {γ : Type*} {F : Filter γ} {μs : have tends_neg := (ENNReal.tendsto_toReal (f_neg.lintegral_lt_top_of_nnreal μ).ne).comp (h f_neg) have aux : ∀ g : Ω →ᵇ ℝ≥0, - (ENNReal.toReal ∘ fun i : γ => ∫⁻ x : Ω, ↑(g x) ∂(μs i : Measure Ω)) = fun i : γ => - (∫⁻ x : Ω, ↑(g x) ∂(μs i : Measure Ω)).toReal := - fun _ => rfl + (ENNReal.toReal ∘ fun i : γ ↦ ∫⁻ x : Ω, ↑(g x) ∂(μs i : Measure Ω)) = + fun i : γ ↦ (∫⁻ x : Ω, ↑(g x) ∂(μs i : Measure Ω)).toReal := + fun _ ↦ rfl simp_rw [aux, BoundedContinuousFunction.toReal_lintegral_coe_eq_integral] at tends_pos tends_neg exact Tendsto.sub tends_pos tends_neg @@ -695,8 +671,8 @@ lemma map_apply' (ν : FiniteMeasure Ω) {f : Ω → Ω'} (f_aemble : AEMeasurab lemma map_apply_of_aemeasurable (ν : FiniteMeasure Ω) {f : Ω → Ω'} (f_aemble : AEMeasurable f ν) {A : Set Ω'} (A_mble : MeasurableSet A) : ν.map f 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 + have key := ν.map_apply' f_aemble A_mble + exact (ENNReal.toNNReal_eq_toNNReal_iff' (measure_ne_top _ _) (measure_ne_top _ _)).mpr key lemma map_apply (ν : FiniteMeasure Ω) {f : Ω → Ω'} (f_mble : Measurable f) {A : Set Ω'} (A_mble : MeasurableSet A) : diff --git a/Mathlib/MeasureTheory/Measure/FiniteMeasureProd.lean b/Mathlib/MeasureTheory/Measure/FiniteMeasureProd.lean index 5ec34e572fd68..97ffeece7c11c 100644 --- a/Mathlib/MeasureTheory/Measure/FiniteMeasureProd.lean +++ b/Mathlib/MeasureTheory/Measure/FiniteMeasureProd.lean @@ -71,7 +71,7 @@ lemma prod_prod (s : Set α) (t : Set β) : μ.prod ν (s ×ˢ t) = μ s * ν t @[simp] lemma map_snd_prod : (μ.prod ν).map Prod.snd = μ univ • ν := by ext; simp lemma map_prod_map {α' : Type*} [MeasurableSpace α'] {β' : Type*} [MeasurableSpace β'] - {f : α → α'} {g : β → β'} (f_mble : Measurable f) (g_mble : Measurable g) : + {f : α → α'} {g : β → β'} (f_mble : Measurable f) (g_mble : Measurable g) : (μ.map f).prod (ν.map g) = (μ.prod ν).map (Prod.map f g) := by apply Subtype.ext simp only [val_eq_toMeasure, toMeasure_prod, toMeasure_map] diff --git a/Mathlib/MeasureTheory/Measure/Haar/Basic.lean b/Mathlib/MeasureTheory/Measure/Haar/Basic.lean index 58a67caecf0c9..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 @@ -265,7 +265,7 @@ theorem is_left_invariant_index {K : Set G} (hK : IsCompact K) (g : G) {V : Set @[to_additive add_prehaar_le_addIndex] theorem prehaar_le_index (K₀ : PositiveCompacts G) {U : Set G} (K : Compacts G) (hU : (interior U).Nonempty) : prehaar (K₀ : Set G) U K ≤ index (K : Set G) K₀ := by - unfold prehaar; rw [div_le_iff] <;> norm_cast + unfold prehaar; rw [div_le_iff₀] <;> norm_cast · apply le_index_mul K₀ K hU · exact index_pos K₀ hU @@ -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/Disintegration.lean b/Mathlib/MeasureTheory/Measure/Haar/Disintegration.lean index df47302132fae..c3c47f6abc70a 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/Disintegration.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/Disintegration.lean @@ -36,6 +36,10 @@ variable {𝕜 E F : Type*} variable [LocallyCompactSpace E] variable (L μ ν) +-- Instances with keys using `Submodule` +instance (T : Submodule 𝕜 E) : BorelSpace T := Subtype.borelSpace _ +instance (T : Submodule 𝕜 E) : OpensMeasurableSpace T := Subtype.opensMeasurableSpace _ + /-- The image of an additive Haar measure under a surjective linear map is proportional to a given additive Haar measure. The proportionality factor will be infinite if the linear map has a nontrivial kernel. -/ @@ -46,7 +50,6 @@ theorem LinearMap.exists_map_addHaar_eq_smul_addHaar' (h : Function.Surjective L is also true for linear equivalences, as they map Haar measure to Haar measure. The general case follows from these two and linear algebra, as `L` can be interpreted as the composition of the projection `P` on a complement `T` to its kernel `S`, together with a linear equivalence. -/ - have : ProperSpace E := .of_locallyCompactSpace 𝕜 have : FiniteDimensional 𝕜 E := .of_locallyCompactSpace 𝕜 have : ProperSpace F := by rcases subsingleton_or_nontrivial E with hE|hE @@ -97,7 +100,8 @@ theorem LinearMap.exists_map_addHaar_eq_smul_addHaar' (h : Function.Surjective L isAddLeftInvariant_eq_smul _ _⟩ simpa only [ne_eq, ENNReal.coe_eq_zero] using (addHaarScalarFactor_pos_of_isAddHaarMeasure (μT.map L') ν).ne' - refine ⟨c₀ * c₁, by simp [pos_iff_ne_zero, c₀_pos, c₁_pos], ENNReal.mul_lt_top c₀_fin c₁_fin, ?_⟩ + refine ⟨c₀ * c₁, by simp [pos_iff_ne_zero, c₀_pos, c₁_pos], + ENNReal.mul_lt_top c₀_fin.lt_top c₁_fin.lt_top, ?_⟩ simp only [I, h₀, Measure.map_smul, J, smul_smul, h₁] rw [mul_assoc, mul_comm _ c₁, ← mul_assoc] @@ -146,6 +150,6 @@ suffices to check it almost everywhere along all translates of a given vector su instance of a disintegration argument for additive Haar measures. -/ lemma ae_mem_of_ae_add_linearMap_mem [LocallyCompactSpace F] {s : Set F} (hs : MeasurableSet s) (h : ∀ y, ∀ᵐ x ∂μ, y + L x ∈ s) : ∀ᵐ y ∂ν, y ∈ s := - (ae_ae_add_linearMap_mem_iff L μ ν hs).1 (Filter.eventually_of_forall h) + (ae_ae_add_linearMap_mem_iff L μ ν hs).1 (Filter.Eventually.of_forall h) end MeasureTheory 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 23979e07b5cf8..a4030ed00f9d7 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 @@ -30,23 +30,19 @@ example {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [Nontrivial E] [F [MeasurableSpace E] [BorelSpace E] (μ : Measure E) [IsAddHaarMeasure μ] : NoAtoms μ := by infer_instance -section ContinuousLinearEquiv +section LinearEquiv variable {𝕜 G H : Type*} [MeasurableSpace G] [MeasurableSpace H] [NontriviallyNormedField 𝕜] [TopologicalSpace G] [TopologicalSpace H] [AddCommGroup G] [AddCommGroup H] [TopologicalAddGroup G] [TopologicalAddGroup H] [Module 𝕜 G] [Module 𝕜 H] (μ : Measure G) - [IsAddHaarMeasure μ] [BorelSpace G] [BorelSpace H] [T2Space H] - -instance MapContinuousLinearEquiv.isAddHaarMeasure (e : G ≃L[𝕜] H) : IsAddHaarMeasure (μ.map e) := - e.toAddEquiv.isAddHaarMeasure_map _ e.continuous e.symm.continuous - -variable [CompleteSpace 𝕜] [T2Space G] [FiniteDimensional 𝕜 G] [ContinuousSMul 𝕜 G] - [ContinuousSMul 𝕜 H] + [IsAddHaarMeasure μ] [BorelSpace G] [BorelSpace H] + [CompleteSpace 𝕜] [T2Space G] [FiniteDimensional 𝕜 G] [ContinuousSMul 𝕜 G] + [ContinuousSMul 𝕜 H] [T2Space H] instance MapLinearEquiv.isAddHaarMeasure (e : G ≃ₗ[𝕜] H) : IsAddHaarMeasure (μ.map e) := - MapContinuousLinearEquiv.isAddHaarMeasure _ e.toContinuousLinearEquiv + e.toContinuousLinearEquiv.isAddHaarMeasure_map _ -end ContinuousLinearEquiv +end LinearEquiv variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [MeasurableSpace E] [BorelSpace E] [FiniteDimensional ℝ E] (μ : Measure E) [IsAddHaarMeasure μ] {F : Type*} [NormedAddCommGroup F] @@ -126,11 +122,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..853e3faeab186 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 @@ -290,7 +290,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 31dbff7cf6c84..6cb8d92d7d95f 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/Quotient.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/Quotient.lean @@ -223,12 +223,12 @@ 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'] have finiteCovol : covolume Γ.op G ν ≠ ⊤ := - ne_top_of_lt $ QuotientMeasureEqMeasurePreimage.covolume_ne_top μ (ν := ν) + ne_top_of_lt <| QuotientMeasureEqMeasurePreimage.covolume_ne_top μ (ν := ν) obtain ⟨s, fund_dom_s⟩ := i rw [fund_dom_s.covolume_eq_volume] at finiteCovol -- TODO: why `rw` fails? @@ -379,7 +379,7 @@ attribute [-instance] Quotient.instMeasurableSpace integral of a function `f` on `G` with respect to a right-invariant measure `μ` is equal to the integral over the quotient `G ⧸ Γ` of the automorphization of `f`. -/ @[to_additive "This is a simple version of the **Unfolding Trick**: Given a subgroup `Γ` of an - additive group `G`, the integral of a function `f` on `G` with respect to a right-invariant + additive group `G`, the integral of a function `f` on `G` with respect to a right-invariant measure `μ` is equal to the integral over the quotient `G ⧸ Γ` of the automorphization of `f`."] lemma QuotientGroup.integral_eq_integral_automorphize {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [μ.IsMulRightInvariant] {f : G → E} diff --git a/Mathlib/MeasureTheory/Measure/Haar/Unique.lean b/Mathlib/MeasureTheory/Measure/Haar/Unique.lean index cd5d79900442d..0b75436b65433 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/Unique.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/Unique.lean @@ -81,7 +81,7 @@ lemma IsCompact.measure_eq_biInf_integral_hasCompactSupport · simp only [le_iInf_iff] intro f f_cont f_comp fk f_nonneg apply (f_cont.integrable_of_hasCompactSupport f_comp).measure_le_integral - · exact eventually_of_forall f_nonneg + · exact Eventually.of_forall f_nonneg · exact fun x hx ↦ by simp [fk hx] · apply le_of_forall_lt' (fun r hr ↦ ?_) simp only [iInf_lt_iff, exists_prop, exists_and_left] @@ -378,7 +378,7 @@ lemma haarScalarFactor_eq_mul (μ' μ ν : Measure G) · exact g_cont.integrable_of_hasCompactSupport g_comp change (haarScalarFactor μ' ν : ℝ) * ∫ (x : G), g x ∂ν = (haarScalarFactor μ' μ * haarScalarFactor μ ν : ℝ≥0) * ∫ (x : G), g x ∂ν at Z - simpa only [mul_eq_mul_right_iff (M₀ := ℝ), int_g_pos.ne', or_false, NNReal.eq_iff] using Z + simpa only [mul_eq_mul_right_iff (M₀ := ℝ), int_g_pos.ne', or_false, ← NNReal.eq_iff] using Z /-- The scalar factor between two left-invariant measures is non-zero when both measures are positive on open sets. -/ @@ -468,7 +468,7 @@ lemma measure_preimage_isMulLeftInvariant_eq_smul_of_hasCompactSupport · exact fun n ↦ (vf_cont n).aestronglyMeasurable · apply IntegrableOn.integrable_indicator _ (isClosed_tsupport f).measurableSet simpa using IsCompact.measure_lt_top h'f - · refine fun n ↦ eventually_of_forall (fun x ↦ ?_) + · refine fun n ↦ Eventually.of_forall (fun x ↦ ?_) by_cases hx : x ∈ tsupport f · simp only [v, Real.norm_eq_abs, NNReal.abs_eq, hx, indicator_of_mem] norm_cast @@ -573,7 +573,8 @@ lemma measure_isMulInvariant_eq_smul_of_isCompact_closure_of_innerRegularCompact exact t_comp.closure_of_subset diff_subset have B : μ' t = ν t := measure_preimage_isMulLeftInvariant_eq_smul_of_hasCompactSupport _ _ f_cont f_comp - rwa [measure_diff st hs, measure_diff st hs, ← B, ENNReal.sub_le_sub_iff_left] at A + rwa [measure_diff st hs.nullMeasurableSet, measure_diff st hs.nullMeasurableSet, ← B, + ENNReal.sub_le_sub_iff_left] at A · exact measure_mono st · exact t_comp.measure_lt_top.ne · exact ((measure_mono st).trans_lt t_comp.measure_lt_top).ne @@ -908,6 +909,32 @@ theorem absolutelyContinuous_isHaarMeasure [LocallyCompactSpace G] rw [haarMeasure_unique μ K, h, smul_smul] exact AbsolutelyContinuous.smul (Eq.absolutelyContinuous rfl) _ +/-- A continuous surjective monoid homomorphism of topological groups with compact codomain +is measure preserving, provided that the Haar measures on the domain and on the codomain +have the same total mass. +-/ +@[to_additive + "A continuous surjective additive monoid homomorphism of topological groups with compact codomain +is measure preserving, provided that the Haar measures on the domain and on the codomain +have the same total mass."] +theorem _root_.MonoidHom.measurePreserving + {H : Type*} [Group H] [TopologicalSpace H] [TopologicalGroup H] [CompactSpace H] + [MeasurableSpace H] [BorelSpace H] + {μ : Measure G} [IsHaarMeasure μ] {ν : Measure H} [IsHaarMeasure ν] + {f : G →* H} (hcont : Continuous f) (hsurj : Surjective f) (huniv : μ univ = ν univ) : + MeasurePreserving f μ ν where + measurable := hcont.measurable + map_eq := by + have : IsFiniteMeasure μ := ⟨by rw [huniv]; apply measure_lt_top⟩ + have : (μ.map f).IsHaarMeasure := isHaarMeasure_map_of_isFiniteMeasure μ f hcont hsurj + set C : ℝ≥0 := haarScalarFactor (μ.map f) ν + have hC : μ.map f = C • ν := isMulLeftInvariant_eq_smul_of_innerRegular _ _ + suffices C = 1 by rwa [this, one_smul] at hC + have : C * ν univ = 1 * ν univ := by + rw [one_mul, ← smul_eq_mul, ← ENNReal.smul_def, ← smul_apply, ← hC, + map_apply hcont.measurable .univ, preimage_univ, huniv] + rwa [ENNReal.mul_eq_mul_right (NeZero.ne _) (measure_ne_top _ _), ENNReal.coe_eq_one] at this + end Group section CommGroup @@ -968,22 +995,8 @@ instance (priority := 100) IsHaarMeasure.isInvInvariant_of_innerRegular @[to_additive] theorem measurePreserving_zpow [CompactSpace G] [RootableBy G ℤ] {n : ℤ} (hn : n ≠ 0) : MeasurePreserving (fun g : G => g ^ n) μ μ := - { measurable := (continuous_zpow n).measurable - map_eq := by - let f := @zpowGroupHom G _ n - have hf : Continuous f := continuous_zpow n - have : (μ.map f).IsHaarMeasure := - isHaarMeasure_map_of_isFiniteMeasure μ f hf (RootableBy.surjective_pow G ℤ hn) - let C : ℝ≥0∞ := haarScalarFactor (μ.map f) μ - have hC : μ.map f = C • μ := isMulLeftInvariant_eq_smul_of_innerRegular _ _ - suffices C = 1 by rwa [this, one_smul] at hC - have h_univ : (μ.map f) univ = μ univ := by - rw [map_apply_of_aemeasurable hf.measurable.aemeasurable MeasurableSet.univ, - preimage_univ] - have hμ₀ : μ univ ≠ 0 := IsOpenPosMeasure.open_pos univ isOpen_univ univ_nonempty - have hμ₁ : μ univ ≠ ∞ := CompactSpace.isFiniteMeasure.measure_univ_lt_top.ne - rwa [hC, smul_apply, Algebra.id.smul_eq_mul, mul_comm, ← ENNReal.eq_div_iff hμ₀ hμ₁, - ENNReal.div_self hμ₀ hμ₁] at h_univ } + (zpowGroupHom n).measurePreserving (continuous_zpow n) + (RootableBy.surjective_pow G ℤ hn) rfl @[to_additive] theorem MeasurePreserving.zpow [CompactSpace G] [RootableBy G ℤ] diff --git a/Mathlib/MeasureTheory/Measure/HasOuterApproxClosed.lean b/Mathlib/MeasureTheory/Measure/HasOuterApproxClosed.lean index b3d825fc3b697..d824d0aecc8ad 100644 --- a/Mathlib/MeasureTheory/Measure/HasOuterApproxClosed.lean +++ b/Mathlib/MeasureTheory/Measure/HasOuterApproxClosed.lean @@ -59,7 +59,7 @@ theorem tendsto_lintegral_nn_filter_of_le_const {ι : Type*} {L : Filter ι} [L. (fs_lim : ∀ᵐ ω : Ω ∂μ, Tendsto (fun i ↦ fs i ω) L (𝓝 (f ω))) : Tendsto (fun i ↦ ∫⁻ ω, fs i ω ∂μ) L (𝓝 (∫⁻ ω, f ω ∂μ)) := by refine tendsto_lintegral_filter_of_dominated_convergence (fun _ ↦ c) - (eventually_of_forall fun i ↦ (ENNReal.continuous_coe.comp (fs i).continuous).measurable) ?_ + (Eventually.of_forall fun i ↦ (ENNReal.continuous_coe.comp (fs i).continuous).measurable) ?_ (@lintegral_const_lt_top _ _ μ _ _ (@ENNReal.coe_ne_top c)).ne ?_ · simpa only [Function.comp_apply, ENNReal.coe_le_coe] using fs_le_const · simpa only [Function.comp_apply, ENNReal.tendsto_coe] using fs_lim @@ -100,7 +100,7 @@ theorem measure_of_cont_bdd_of_tendsto_indicator rw [tendsto_pi_nhds] at fs_lim exact fun ω ↦ fs_lim ω apply measure_of_cont_bdd_of_tendsto_filter_indicator μ E_mble fs - (eventually_of_forall fun n ↦ eventually_of_forall (fs_bdd n)) (eventually_of_forall fs_lim') + (Eventually.of_forall fun n ↦ Eventually.of_forall (fs_bdd n)) (Eventually.of_forall fs_lim') /-- The integrals of thickened indicators of a closed set against a finite measure tend to the measure of the closed set if the thickening radii tend to zero. -/ @@ -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 28921d6562aa6..2558bd6c6aa54 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))` @@ -279,7 +279,7 @@ theorem tendsto_pre (m : Set X → ℝ≥0∞) (s : Set X) : theorem tendsto_pre_nat (m : Set X → ℝ≥0∞) (s : Set X) : Tendsto (fun n : ℕ => pre m n⁻¹ s) atTop (𝓝 <| mkMetric' m s) := by refine (tendsto_pre m s).comp (tendsto_inf.2 ⟨ENNReal.tendsto_inv_nat_nhds_zero, ?_⟩) - refine tendsto_principal.2 (eventually_of_forall fun n => ?_) + refine tendsto_principal.2 (Eventually.of_forall fun n => ?_) simp theorem eq_iSup_nat (m : Set X → ℝ≥0∞) : mkMetric' m = ⨆ n : ℕ, mkMetric'.pre m n⁻¹ := 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 @@ -574,7 +574,7 @@ theorem hausdorffMeasure_zero_or_top {d₁ d₂ : ℝ} (h : d₁ < d₂) (s : Se intro c hc refine le_iff'.1 (mkMetric_mono_smul ENNReal.coe_ne_top (mod_cast hc) ?_) s have : 0 < ((c : ℝ≥0∞) ^ (d₂ - d₁)⁻¹) := by - rw [ENNReal.coe_rpow_of_ne_zero hc, pos_iff_ne_zero, Ne, ENNReal.coe_eq_zero, + rw [← ENNReal.coe_rpow_of_ne_zero hc, pos_iff_ne_zero, Ne, ENNReal.coe_eq_zero, NNReal.rpow_eq_zero_iff] exact mt And.left hc filter_upwards [Ico_mem_nhdsWithin_Ici ⟨le_rfl, this⟩] @@ -732,7 +732,7 @@ variable {K : ℝ≥0} {f : X → Y} by the factor of `K ^ d`. -/ theorem hausdorffMeasure_image_le (h : LipschitzWith K f) {d : ℝ} (hd : 0 ≤ d) (s : Set X) : μH[d] (f '' s) ≤ (K : ℝ≥0∞) ^ d * μH[d] s := - (h.lipschitzOnWith s).hausdorffMeasure_image_le hd + h.lipschitzOnWith.hausdorffMeasure_image_le hd end LipschitzWith @@ -741,17 +741,16 @@ open scoped Pointwise theorem MeasureTheory.Measure.hausdorffMeasure_smul₀ {𝕜 E : Type*} [NormedAddCommGroup E] [NormedField 𝕜] [NormedSpace 𝕜 E] [MeasurableSpace E] [BorelSpace E] {d : ℝ} (hd : 0 ≤ d) {r : 𝕜} (hr : r ≠ 0) (s : Set E) : μH[d] (r • s) = ‖r‖₊ ^ d • μH[d] s := by - suffices ∀ {r : 𝕜}, r ≠ 0 → ∀ s : Set E, μH[d] (r • s) ≤ ‖r‖₊ ^ d • μH[d] s by - refine le_antisymm (this hr s) ?_ - rw [← le_inv_smul_iff_of_pos] - · dsimp - rw [← NNReal.inv_rpow, ← nnnorm_inv] - · refine Eq.trans_le ?_ (this (inv_ne_zero hr) (r • s)) - rw [inv_smul_smul₀ hr] - · simp [pos_iff_ne_zero, hr] - intro r _ s - simp only [NNReal.rpow_eq_pow, ENNReal.smul_def, ← ENNReal.coe_rpow_of_nonneg _ hd, smul_eq_mul] - exact (lipschitzWith_smul (β := E) r).hausdorffMeasure_image_le hd s + have {r : 𝕜} (s : Set E) : μH[d] (r • s) ≤ ‖r‖₊ ^ d • μH[d] s := by + simpa [ENNReal.coe_rpow_of_nonneg, hd] + using (lipschitzWith_smul r).hausdorffMeasure_image_le hd s + refine le_antisymm (this s) ?_ + rw [← le_inv_smul_iff_of_pos] + · dsimp + rw [← NNReal.inv_rpow, ← nnnorm_inv] + · refine Eq.trans_le ?_ (this (r • s)) + rw [inv_smul_smul₀ hr] + · simp [pos_iff_ne_zero, hr] /-! ### Antilipschitz maps do not decrease Hausdorff measures and dimension @@ -958,6 +957,30 @@ theorem hausdorffMeasure_pi_real {ι : Type*} [Fintype ι] : ENNReal.ofReal_natCast] · simp only [ENNReal.ofReal_ne_top, Ne, not_false_iff] +instance isAddHaarMeasure_hausdorffMeasure {E : Type*} + [NormedAddCommGroup E] [NormedSpace ℝ E] [FiniteDimensional ℝ E] + [MeasurableSpace E] [BorelSpace E] : + IsAddHaarMeasure (G := E) μH[finrank ℝ E] where + lt_top_of_isCompact K hK := by + set e : E ≃L[ℝ] Fin (finrank ℝ E) → ℝ := ContinuousLinearEquiv.ofFinrankEq (by simp) + suffices μH[finrank ℝ E] (e '' K) < ⊤ by + rw [← e.symm_image_image K] + apply lt_of_le_of_lt <| e.symm.lipschitz.hausdorffMeasure_image_le (by simp) (e '' K) + rw [ENNReal.rpow_natCast] + exact ENNReal.mul_lt_top (ENNReal.pow_lt_top ENNReal.coe_lt_top _) this + conv_lhs => congr; congr; rw [← Fintype.card_fin (finrank ℝ E)] + rw [hausdorffMeasure_pi_real] + exact (hK.image e.continuous).measure_lt_top + open_pos U hU hU' := by + set e : E ≃L[ℝ] Fin (finrank ℝ E) → ℝ := ContinuousLinearEquiv.ofFinrankEq (by simp) + suffices 0 < μH[finrank ℝ E] (e '' U) from + (ENNReal.mul_pos_iff.mp (lt_of_lt_of_le this <| + e.lipschitz.hausdorffMeasure_image_le (by simp) _)).2.ne' + conv_rhs => congr; congr; rw [← Fintype.card_fin (finrank ℝ E)] + rw [hausdorffMeasure_pi_real] + apply (e.isOpenMap U hU).measure_pos (μ := volume) + simpa + variable (ι X) theorem hausdorffMeasure_measurePreserving_funUnique [Unique ι] diff --git a/Mathlib/MeasureTheory/Measure/Lebesgue/EqHaar.lean b/Mathlib/MeasureTheory/Measure/Lebesgue/EqHaar.lean index 666c2b7b7b87f..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 `ℝ^ι`. @@ -492,7 +492,8 @@ theorem addHaar_sphere_of_ne_zero (x : E) {r : ℝ} (hr : r ≠ 0) : μ (sphere rcases hr.lt_or_lt with (h | h) · simp only [empty_diff, measure_empty, ← closedBall_diff_ball, closedBall_eq_empty.2 h] · rw [← closedBall_diff_ball, - measure_diff ball_subset_closedBall measurableSet_ball measure_ball_lt_top.ne, + measure_diff ball_subset_closedBall measurableSet_ball.nullMeasurableSet + measure_ball_lt_top.ne, addHaar_ball_of_pos μ _ h, addHaar_closedBall μ _ h.le, tsub_self] theorem addHaar_sphere [Nontrivial E] (x : E) (r : ℝ) : μ (sphere x r) = 0 := by @@ -511,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] @@ -601,12 +602,11 @@ theorem tendsto_addHaar_inter_smul_zero_of_density_zero_aux1 (s : Set E) (x : E) have A : Tendsto (fun r : ℝ => μ (s ∩ ({x} + r • t)) / μ (closedBall x r)) (𝓝[>] 0) (𝓝 0) := by apply tendsto_of_tendsto_of_tendsto_of_le_of_le' tendsto_const_nhds h - (eventually_of_forall fun b => zero_le _) + (Eventually.of_forall fun b => zero_le _) filter_upwards [self_mem_nhdsWithin] 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 @@ -623,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` @@ -696,7 +696,8 @@ theorem tendsto_addHaar_inter_smul_zero_of_density_zero (s : Set E) (x : E) (𝓝 (μ (⋂ n : ℕ, t \ closedBall 0 n))) := by have N : ∃ n : ℕ, μ (t \ closedBall 0 n) ≠ ∞ := ⟨0, ((measure_mono diff_subset).trans_lt h''t.lt_top).ne⟩ - refine tendsto_measure_iInter (fun n ↦ ht.diff measurableSet_closedBall) (fun m n hmn ↦ ?_) N + refine tendsto_measure_iInter (fun n ↦ (ht.diff measurableSet_closedBall).nullMeasurableSet) + (fun m n hmn ↦ ?_) N exact diff_subset_diff Subset.rfl (closedBall_subset_closedBall (Nat.cast_le.2 hmn)) have : ⋂ n : ℕ, t \ closedBall 0 n = ∅ := by simp_rw [diff_eq, ← inter_iInter, iInter_eq_compl_iUnion_compl, compl_compl, @@ -744,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' _ @@ -778,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 @@ -798,7 +796,7 @@ theorem tendsto_addHaar_inter_smul_one_of_density_one (s : Set E) (x : E) tendsto_addHaar_inter_smul_one_of_density_one_aux μ _ (measurableSet_toMeasurable _ _) _ _ t ht h't h''t apply tendsto_of_tendsto_of_tendsto_of_le_of_le' h tendsto_const_nhds - · refine eventually_of_forall fun r ↦ ?_ + · refine Eventually.of_forall fun r ↦ ?_ gcongr apply subset_toMeasurable · filter_upwards [self_mem_nhdsWithin] diff --git a/Mathlib/MeasureTheory/Measure/Lebesgue/Integral.lean b/Mathlib/MeasureTheory/Measure/Lebesgue/Integral.lean index 50a9a66664f98..15ee5ceb0977a 100644 --- a/Mathlib/MeasureTheory/Measure/Lebesgue/Integral.lean +++ b/Mathlib/MeasureTheory/Measure/Lebesgue/Integral.lean @@ -35,7 +35,7 @@ theorem volume_regionBetween_eq_integral [SigmaFinite μ] (f_int : IntegrableOn (g_int : IntegrableOn g s μ) (hs : MeasurableSet s) (hfg : ∀ x ∈ s, f x ≤ g x) : μ.prod volume (regionBetween f g s) = ENNReal.ofReal (∫ y in s, (g - f) y ∂μ) := volume_regionBetween_eq_integral' f_int g_int hs - ((ae_restrict_iff' hs).mpr (eventually_of_forall hfg)) + ((ae_restrict_iff' hs).mpr (Eventually.of_forall hfg)) end regionBetween @@ -102,7 +102,7 @@ theorem integral_comp_abs {f : ℝ → ℝ} : rw [← Measure.map_neg_eq_self (volume : Measure ℝ)] let m : MeasurableEmbedding fun x : ℝ => -x := (Homeomorph.neg ℝ).measurableEmbedding rw [m.integrableOn_map_iff] - simp_rw [Function.comp, abs_neg, neg_preimage, preimage_neg_Iic, neg_zero] + simp_rw [Function.comp_def, abs_neg, neg_preimage, preimage_neg_Iic, neg_zero] exact integrableOn_Ici_iff_integrableOn_Ioi.mpr hf calc _ = (∫ x in Iic 0, f |x|) + ∫ x in Ioi 0, f |x| := by diff --git a/Mathlib/MeasureTheory/Measure/Lebesgue/VolumeOfBalls.lean b/Mathlib/MeasureTheory/Measure/Lebesgue/VolumeOfBalls.lean index a43d6a7133501..7e7bce6be7fc8 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] @@ -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 fd452eb706c2f..fd684e18cafc6 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 @@ -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 @@ -219,9 +218,43 @@ noncomputable instance levyProkhorovDist_pseudoMetricSpace_finiteMeasure : 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 @@ -233,6 +266,29 @@ noncomputable instance levyProkhorovDist_pseudoMetricSpace_probabilityMeasure : 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 @@ -279,20 +335,6 @@ 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 [PseudoMetricSpace Ω] [OpensMeasurableSpace Ω] /-- A version of the layer cake formula for bounded continuous functions which have finite integral: @@ -303,7 +345,7 @@ lemma BoundedContinuousFunction.integral_eq_integral_meas_le_of_hasFiniteIntegra ∫ ω, f ω ∂μ = ∫ t in Ioc 0 ‖f‖, ENNReal.toReal (μ {a : α | t ≤ f a}) := by rw [Integrable.integral_eq_integral_Ioc_meas_le (M := ‖f‖) ?_ f_nn ?_] · refine ⟨f.continuous.measurable.aestronglyMeasurable, hf⟩ - · exact eventually_of_forall (fun x ↦ BoundedContinuousFunction.apply_le_norm f x) + · exact Eventually.of_forall (fun x ↦ BoundedContinuousFunction.apply_le_norm f x) /-- A version of the layer cake formula for bounded continuous functions and finite measures: ∫ f dμ = ∫ t in (0, ‖f‖], μ {x | f(x) ≥ t} dt. -/ @@ -333,7 +375,7 @@ lemma BoundedContinuousFunction.integral_le_of_levyProkhorovEDist_lt (μ ν : Me apply Measure.integrableOn_of_bounded (M := ENNReal.toReal (μ univ)) measure_Ioc_lt_top.ne · apply (Measurable.ennreal_toReal (Antitone.measurable ?_)).aestronglyMeasurable exact fun _ _ hst ↦ measure_mono (fun _ h ↦ hst.trans h) - · apply eventually_of_forall <| fun t ↦ ?_ + · apply Eventually.of_forall <| fun t ↦ ?_ simp only [Real.norm_eq_abs, abs_toReal] exact (ENNReal.toReal_le_toReal (measure_ne_top _ _) (measure_ne_top _ _)).mpr <| measure_mono (subset_univ _) @@ -342,7 +384,7 @@ lemma BoundedContinuousFunction.integral_le_of_levyProkhorovEDist_lt (μ ν : Me apply Measure.integrableOn_of_bounded (M := ENNReal.toReal (ν univ)) measure_Ioc_lt_top.ne · apply (Measurable.ennreal_toReal (Antitone.measurable ?_)).aestronglyMeasurable exact fun _ _ hst ↦ measure_mono <| thickening_subset_of_subset ε (fun _ h ↦ hst.trans h) - · apply eventually_of_forall <| fun t ↦ ?_ + · apply Eventually.of_forall <| fun t ↦ ?_ simp only [Real.norm_eq_abs, abs_toReal] exact (ENNReal.toReal_le_toReal (measure_ne_top _ _) (measure_ne_top _ _)).mpr <| measure_mono (subset_univ _) @@ -366,17 +408,17 @@ lemma tendsto_integral_meas_thickening_le (f : Ω →ᵇ ℝ) (𝓝 (∫ t in A, ENNReal.toReal (μ {a | t ≤ f a}))) := by apply tendsto_integral_filter_of_dominated_convergence (G := ℝ) (μ := volume.restrict A) (F := fun ε t ↦ (μ (thickening ε {a | t ≤ f a}))) (f := fun t ↦ (μ {a | t ≤ f a})) 1 - · apply eventually_of_forall fun n ↦ Measurable.aestronglyMeasurable ?_ + · apply Eventually.of_forall fun n ↦ Measurable.aestronglyMeasurable ?_ simp only [measurable_coe_nnreal_real_iff] apply measurable_toNNReal.comp <| Antitone.measurable (fun s t hst ↦ ?_) exact measure_mono <| thickening_subset_of_subset _ <| fun ω h ↦ hst.trans h - · apply eventually_of_forall (fun i ↦ ?_) - apply eventually_of_forall (fun t ↦ ?_) + · apply Eventually.of_forall (fun i ↦ ?_) + apply Eventually.of_forall (fun t ↦ ?_) simp only [Real.norm_eq_abs, NNReal.abs_eq, Pi.one_apply] exact (ENNReal.toReal_le_toReal (measure_ne_top _ _) one_ne_top).mpr prob_le_one · have aux : IsFiniteMeasure (volume.restrict A) := ⟨by simp [lt_top_iff_ne_top, A_finmeas]⟩ apply integrable_const - · apply eventually_of_forall (fun t ↦ ?_) + · apply Eventually.of_forall (fun t ↦ ?_) simp only [NNReal.tendsto_coe] apply (ENNReal.tendsto_toNNReal _).comp · apply tendsto_measure_thickening_of_isClosed ?_ ?_ @@ -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 @@ -405,14 +447,14 @@ lemma LevyProkhorov.continuous_toProbabilityMeasure : have ε_of_room := Tendsto.add (tendsto_iff_dist_tendsto_zero.mp hμs) εs_lim have ε_of_room' : Tendsto (fun n ↦ dist (μs n) ν + εs n) atTop (𝓝[>] 0) := by rw [tendsto_nhdsWithin_iff] - refine ⟨by simpa using ε_of_room, eventually_of_forall fun n ↦ ?_⟩ + refine ⟨by simpa using ε_of_room, Eventually.of_forall fun n ↦ ?_⟩ · rw [mem_Ioi] linarith [εs_pos n, dist_nonneg (x := μs n) (y := ν)] rw [add_zero] at ε_of_room have key := (tendsto_integral_meas_thickening_le f (A := Ioc 0 ‖f‖) (by simp) P).comp ε_of_room' have aux : ∀ (z : ℝ), Iio (z + δ/2) ∈ 𝓝 z := fun z ↦ Iio_mem_nhds (by linarith) filter_upwards [key (aux _), ε_of_room <| Iio_mem_nhds <| half_pos <| - Real.mul_pos (inv_pos.mpr norm_f_pos) δ_pos] + mul_pos (inv_pos.mpr norm_f_pos) δ_pos] with n hn hn' simp only [mem_preimage, mem_Iio] at * specialize εs_pos n @@ -428,15 +470,14 @@ lemma LevyProkhorov.continuous_toProbabilityMeasure : δ / 2 + ‖f‖ * (dist (μs n) ν + εs n) _ ≤ δ / 2 + ‖f‖ * (‖f‖⁻¹ * δ / 2) := by gcongr _ = δ := by field_simp; ring - · exact eventually_of_forall f_nn + · exact Eventually.of_forall f_nn · positivity · 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] - · exact eventually_of_forall f_nn + 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] refine ⟨0, fun a i hia ↦ le_trans (integral_nonneg f_nn) (hia i le_rfl)⟩ @@ -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*} {Ω : 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] @@ -525,7 +566,7 @@ lemma ProbabilityMeasure.continuous_toLevyProkhorov [SeparableSpace Ω] : have third_ε_pos : 0 < ε / 3 := by linarith have third_ε_pos' : 0 < ENNReal.ofReal (ε / 3) := ofReal_pos.mpr third_ε_pos -- First use separability to choose a countable partition of `Ω` into measurable - -- subsets `Es n ⊆ Ω` of small diamater, `diam (Es n) < ε/3`. + -- subsets `Es n ⊆ Ω` of small diameter, `diam (Es n) < ε/3`. obtain ⟨Es, Es_mble, Es_bdd, Es_diam, Es_cover, Es_disjoint⟩ := SeparableSpace.exists_measurable_partition_diam_le Ω third_ε_pos -- Instead of the whole space `Ω = ⋃ n ∈ ℕ, Es n`, focus on a large but finite @@ -533,7 +574,7 @@ lemma ProbabilityMeasure.continuous_toLevyProkhorov [SeparableSpace Ω] : -- `P (⋃ n < N, Es n)ᶜ < ε/3`. obtain ⟨N, hN⟩ : ∃ N, P.toMeasure (⋃ j ∈ Iio N, Es j)ᶜ < ENNReal.ofReal (ε/3) := by have exhaust := @tendsto_measure_biUnion_Ici_zero_of_pairwise_disjoint Ω _ P.toMeasure _ - Es Es_mble Es_disjoint + Es (fun n ↦ (Es_mble n).nullMeasurableSet) Es_disjoint simp only [tendsto_atTop_nhds, Function.comp_apply] at exhaust obtain ⟨N, hN⟩ := exhaust (Iio (ENNReal.ofReal (ε / 3))) third_ε_pos' isOpen_Iio refine ⟨N, ?_⟩ @@ -612,22 +653,22 @@ 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] @@ -636,6 +677,13 @@ instance (X : Type*) [TopologicalSpace X] [PseudoMetrizableSpace X] [SeparableSp letI : PseudoMetricSpace X := TopologicalSpace.pseudoMetrizableSpacePseudoMetric X (homeomorph_probabilityMeasure_levyProkhorov (Ω := X)).inducing.pseudoMetrizableSpace +/-- The topology of convergence in distribution on a separable Borel space is metrizable. -/ +instance instMetrizableSpaceProbabilityMeasure (X : Type*) [TopologicalSpace X] + [PseudoMetrizableSpace X] [SeparableSpace X] [MeasurableSpace X] [BorelSpace X] : + MetrizableSpace (ProbabilityMeasure X) := by + letI : PseudoMetricSpace X := TopologicalSpace.pseudoMetrizableSpacePseudoMetric X + exact homeomorph_probabilityMeasure_levyProkhorov.embedding.metrizableSpace + end Levy_Prokhorov_metrizes_convergence_in_distribution end MeasureTheory -- namespace diff --git a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean index 9ada0295ca07b..2c1821c1225d6 100644 --- a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean +++ b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean @@ -5,7 +5,9 @@ Authors: Johannes Hölzl, Mario Carneiro -/ 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 @@ -126,9 +128,10 @@ theorem measure_union_add_inter' (hs : MeasurableSet s) (t : Set α) : μ (s ∪ t) + μ (s ∩ t) = μ s + μ t := by rw [union_comm, inter_comm, measure_union_add_inter t hs, add_comm] -lemma measure_symmDiff_eq (hs : MeasurableSet s) (ht : MeasurableSet t) : +lemma measure_symmDiff_eq (hs : NullMeasurableSet s μ) (ht : NullMeasurableSet t μ) : μ (s ∆ t) = μ (s \ t) + μ (t \ s) := by - simpa only [symmDiff_def, sup_eq_union] using measure_union disjoint_sdiff_sdiff (ht.diff hs) + simpa only [symmDiff_def, sup_eq_union] + using measure_union₀ (ht.diff hs) disjoint_sdiff_sdiff.aedisjoint lemma measure_symmDiff_le (s t u : Set α) : μ (s ∆ u) ≤ μ (s ∆ t) + μ (t ∆ u) := @@ -205,14 +208,15 @@ theorem sum_measure_preimage_singleton (s : Finset β) {f : α → β} theorem measure_diff_null' (h : μ (s₁ ∩ s₂) = 0) : μ (s₁ \ s₂) = μ s₁ := measure_congr <| diff_ae_eq_self.2 h -theorem measure_add_diff (hs : MeasurableSet s) (t : Set α) : μ s + μ (t \ s) = μ (s ∪ t) := by - rw [← measure_union' disjoint_sdiff_right hs, union_diff_self] +theorem measure_add_diff (hs : NullMeasurableSet s μ) (t : Set α) : + μ s + μ (t \ s) = μ (s ∪ t) := by + rw [← measure_union₀' hs disjoint_sdiff_right.aedisjoint, union_diff_self] -theorem measure_diff' (s : Set α) (hm : MeasurableSet t) (h_fin : μ t ≠ ∞) : +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₂ : MeasurableSet s₂) (h_fin : μ s₂ ≠ ∞) : +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] theorem le_measure_diff : μ s₁ - μ s₂ ≤ μ (s₁ \ s₂) := @@ -238,13 +242,14 @@ then one has finite measure if and only if the other one does. -/ theorem measure_ne_top_iff_of_symmDiff (hμst : μ (s ∆ t) ≠ ∞) : μ s ≠ ∞ ↔ μ t ≠ ∞ := (measure_eq_top_iff_of_symmDiff hμst).ne -theorem measure_diff_lt_of_lt_add (hs : MeasurableSet s) (hst : s ⊆ t) (hs' : μ s ≠ ∞) {ε : ℝ≥0∞} - (h : μ t < μ s + ε) : μ (t \ s) < ε := by +theorem measure_diff_lt_of_lt_add (hs : NullMeasurableSet s μ) (hst : s ⊆ t) (hs' : μ s ≠ ∞) + {ε : ℝ≥0∞} (h : μ t < μ s + ε) : μ (t \ s) < ε := by rw [measure_diff hst hs hs']; rw [add_comm] at h exact ENNReal.sub_lt_of_lt_add (measure_mono hst) h -theorem measure_diff_le_iff_le_add (hs : MeasurableSet s) (hst : s ⊆ t) (hs' : μ s ≠ ∞) {ε : ℝ≥0∞} : - μ (t \ s) ≤ ε ↔ μ t ≤ μ s + ε := by rw [measure_diff hst hs hs', tsub_le_iff_left] +theorem measure_diff_le_iff_le_add (hs : NullMeasurableSet s μ) (hst : s ⊆ t) (hs' : μ s ≠ ∞) + {ε : ℝ≥0∞} : μ (t \ s) ≤ ε ↔ μ t ≤ μ s + ε := by + rw [measure_diff hst hs hs', tsub_le_iff_left] theorem measure_eq_measure_of_null_diff {s t : Set α} (hst : s ⊆ t) (h_nulldiff : μ (t \ s) = 0) : μ s = μ t := measure_congr <| @@ -295,26 +300,27 @@ theorem union_ae_eq_left_iff_ae_subset : (s ∪ t : Set α) =ᵐ[μ] s ↔ t ≤ theorem union_ae_eq_right_iff_ae_subset : (s ∪ t : Set α) =ᵐ[μ] t ↔ s ≤ᵐ[μ] t := by rw [union_comm, union_ae_eq_left_iff_ae_subset] -theorem ae_eq_of_ae_subset_of_measure_ge (h₁ : s ≤ᵐ[μ] t) (h₂ : μ t ≤ μ s) (hsm : MeasurableSet s) - (ht : μ t ≠ ∞) : s =ᵐ[μ] t := by +theorem ae_eq_of_ae_subset_of_measure_ge (h₁ : s ≤ᵐ[μ] t) (h₂ : μ t ≤ μ s) + (hsm : NullMeasurableSet s μ) (ht : μ t ≠ ∞) : s =ᵐ[μ] t := by refine eventuallyLE_antisymm_iff.mpr ⟨h₁, ae_le_set.mpr ?_⟩ replace h₂ : μ t = μ s := h₂.antisymm (measure_mono_ae h₁) replace ht : μ s ≠ ∞ := h₂ ▸ ht rw [measure_diff' t hsm ht, measure_congr (union_ae_eq_left_iff_ae_subset.mpr h₁), h₂, tsub_self] /-- If `s ⊆ t`, `μ t ≤ μ s`, `μ t ≠ ∞`, and `s` is measurable, then `s =ᵐ[μ] t`. -/ -theorem ae_eq_of_subset_of_measure_ge (h₁ : s ⊆ t) (h₂ : μ t ≤ μ s) (hsm : MeasurableSet s) +theorem ae_eq_of_subset_of_measure_ge (h₁ : s ⊆ t) (h₂ : μ t ≤ μ s) (hsm : NullMeasurableSet s μ) (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 ?_ ?_ ?_ @@ -325,7 +331,7 @@ theorem measure_iUnion_congr_of_subset [Countable β] {s : β → Set α} {t : measure_mono <| subset_inter ((hsub b).trans <| subset_toMeasurable _ _) ((subset_iUnion _ _).trans <| subset_toMeasurable _ _) - · exact (measurableSet_toMeasurable _ _).inter (measurableSet_toMeasurable _ _) + · measurability · rw [measure_toMeasurable] exact htop b calc @@ -340,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 @@ -416,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, (· ∘ ·), 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 @@ -452,51 +455,72 @@ 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. -/ -theorem measure_iInter_eq_iInf [Countable ι] {s : ι → Set α} (h : ∀ i, MeasurableSet (s i)) +theorem measure_iInter_eq_iInf [Countable ι] {s : ι → Set α} (h : ∀ i, NullMeasurableSet (s i) μ) (hd : Directed (· ⊇ ·) s) (hfin : ∃ i, μ (s i) ≠ ∞) : μ (⋂ i, s i) = ⨅ i, μ (s i) := by rcases hfin with ⟨k, hk⟩ have : ∀ t ⊆ s k, μ t ≠ ∞ := fun t ht => ne_top_of_le_ne_top hk (measure_mono ht) rw [← ENNReal.sub_sub_cancel hk (iInf_le _ k), ENNReal.sub_iInf, ← ENNReal.sub_sub_cancel hk (measure_mono (iInter_subset _ k)), ← - measure_diff (iInter_subset _ k) (MeasurableSet.iInter h) (this _ (iInter_subset _ k)), - diff_iInter, measure_iUnion_eq_iSup] + measure_diff (iInter_subset _ k) (.iInter h) (this _ (iInter_subset _ k)), + 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 - · rw [tsub_le_iff_right, ← measure_union, Set.union_comm] - · exact measure_mono (diff_subset_iff.1 Subset.rfl) - · apply disjoint_sdiff_left - · apply h i + 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 α} [Countable ι] [Preorder ι] [IsDirected ι (· ≤ ·)] - {f : ι → Set α} (h : ∀ i, MeasurableSet (f i)) (hfin : ∃ i, μ (f i) ≠ ∞) : + {f : ι → Set α} (h : ∀ i, NullMeasurableSet (f i) μ) (hfin : ∃ i, μ (f i) ≠ ∞) : μ (⋂ i, f i) = ⨅ i, μ (⋂ j ≤ i, f j) := by let s := fun i ↦ ⋂ j ≤ i, f j have iInter_eq : ⋂ i, f i = ⋂ i, s i := by @@ -505,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, MeasurableSet (s i) := - fun i ↦ MeasurableSet.biInter (countable_univ.mono <| subset_univ _) 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⟩ @@ -520,31 +543,47 @@ 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 α} - (hs : ∀ n, MeasurableSet (s n)) (hm : Antitone s) (hf : ∃ i, μ (s i) ≠ ∞) : +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 ι] - [Preorder ι] [IsDirected ι (· ≤ ·)] {f : ι → Set α} (hm : ∀ i, MeasurableSet (f i)) + [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 rw [measure_iInter_eq_iInf' hm hf] @@ -555,7 +594,7 @@ theorem tendsto_measure_iInter' {α ι : Type*} [MeasurableSpace α] {μ : Measu sets indexed by a linear order with first countable topology is the limit of the measures. -/ theorem tendsto_measure_biInter_gt {ι : Type*} [LinearOrder ι] [TopologicalSpace ι] [OrderTopology ι] [DenselyOrdered ι] [FirstCountableTopology ι] {s : ι → Set α} - {a : ι} (hs : ∀ r > a, MeasurableSet (s r)) (hm : ∀ i j, a < i → i ≤ j → s i ⊆ s j) + {a : ι} (hs : ∀ r > a, NullMeasurableSet (s r) μ) (hm : ∀ i j, a < i → i ≤ j → s i ⊆ s j) (hf : ∃ r > a, μ (s r) ≠ ∞) : Tendsto (μ ∘ s) (𝓝[Ioi a] a) (𝓝 (μ (⋂ r > a, s r))) := by refine tendsto_order.2 ⟨fun l hl => ?_, fun L hL => ?_⟩ · filter_upwards [self_mem_nhdsWithin (s := Ioi a)] with r hr using hl.trans_le @@ -588,66 +627,6 @@ theorem tendsto_measure_biInter_gt {ι : Type*} [LinearOrder ι] [TopologicalSpa have : Ioc a (u n) ∈ 𝓝[>] a := Ioc_mem_nhdsWithin_Ioi ⟨le_rfl, u_pos n⟩ filter_upwards [this] with r hr using lt_of_le_of_lt (measure_mono (hm _ _ hr.1 hr.2)) hn -/-- One direction of the **Borel-Cantelli lemma** (sometimes called the "*first* Borel-Cantelli -lemma"): if (sᵢ) is a sequence of sets such that `∑ μ sᵢ` is finite, then the limit superior of the -`sᵢ` is a null set. - -Note: for the *second* Borel-Cantelli lemma (applying to independent sets in a probability space), -see `ProbabilityTheory.measure_limsup_eq_one`. -/ -theorem measure_limsup_eq_zero {s : ℕ → Set α} (hs : (∑' i, μ (s i)) ≠ ∞) : - μ (limsup s atTop) = 0 := by - -- First we replace the sequence `sₙ` with a sequence of measurable sets `tₙ ⊇ sₙ` of the same - -- measure. - set t : ℕ → Set α := fun n => toMeasurable μ (s n) - have ht : (∑' i, μ (t i)) ≠ ∞ := by simpa only [t, measure_toMeasurable] using hs - suffices μ (limsup t atTop) = 0 by - have A : s ≤ t := fun n => subset_toMeasurable μ (s n) - -- TODO default args fail - exact measure_mono_null (limsup_le_limsup (eventually_of_forall (Pi.le_def.mp A))) this - -- Next we unfold `limsup` for sets and replace equality with an inequality - simp only [limsup_eq_iInf_iSup_of_nat', Set.iInf_eq_iInter, Set.iSup_eq_iUnion, ← - nonpos_iff_eq_zero] - -- Finally, we estimate `μ (⋃ i, t (i + n))` by `∑ i', μ (t (i + n))` - refine - le_of_tendsto_of_tendsto' - (tendsto_measure_iInter - (fun i => MeasurableSet.iUnion fun b => measurableSet_toMeasurable _ _) ?_ - ⟨0, ne_top_of_le_ne_top ht (measure_iUnion_le t)⟩) - (ENNReal.tendsto_sum_nat_add (μ ∘ t) ht) fun n => measure_iUnion_le _ - intro n m hnm x - simp only [Set.mem_iUnion] - exact fun ⟨i, hi⟩ => ⟨i + (m - n), by simpa only [add_assoc, tsub_add_cancel_of_le hnm] using hi⟩ - -theorem measure_liminf_eq_zero {s : ℕ → Set α} (h : (∑' i, μ (s i)) ≠ ∞) : - μ (liminf s atTop) = 0 := by - rw [← le_zero_iff] - have : liminf s atTop ≤ limsup s atTop := liminf_le_limsup - exact (μ.mono this).trans (by simp [measure_limsup_eq_zero h]) - --- Need to specify `α := Set α` below because of diamond; see #19041 -theorem limsup_ae_eq_of_forall_ae_eq (s : ℕ → Set α) {t : Set α} - (h : ∀ n, s n =ᵐ[μ] t) : limsup (α := Set α) s atTop =ᵐ[μ] t := by - simp_rw [ae_eq_set] at h ⊢ - constructor - · rw [atTop.limsup_sdiff s t] - apply measure_limsup_eq_zero - simp [h] - · rw [atTop.sdiff_limsup s t] - apply measure_liminf_eq_zero - simp [h] - --- Need to specify `α := Set α` above because of diamond; see #19041 -theorem liminf_ae_eq_of_forall_ae_eq (s : ℕ → Set α) {t : Set α} - (h : ∀ n, s n =ᵐ[μ] t) : liminf (α := Set α) s atTop =ᵐ[μ] t := by - simp_rw [ae_eq_set] at h ⊢ - constructor - · rw [atTop.liminf_sdiff s t] - apply measure_liminf_eq_zero - simp [h] - · rw [atTop.sdiff_liminf s t] - apply measure_limsup_eq_zero - simp [h] - theorem measure_if {x : β} {t : Set β} {s : Set α} [Decidable (x ∈ t)] : μ (if x ∈ t then s else ∅) = indicator t (fun _ => μ s) x := by split_ifs with h <;> simp [h] @@ -749,6 +728,12 @@ theorem zero_toOuterMeasure {_m : MeasurableSpace α} : (0 : Measure α).toOuter theorem coe_zero {_m : MeasurableSpace α} : ⇑(0 : Measure α) = 0 := rfl +@[simp] lemma _root_.MeasureTheory.OuterMeasure.toMeasure_zero + [ms : MeasurableSpace α] (h : ms ≤ (0 : OuterMeasure α).caratheodory) : + (0 : OuterMeasure α).toMeasure h = 0 := by + ext s hs + simp [hs] + @[nontriviality] lemma apply_eq_zero_of_isEmpty [IsEmpty α] {_ : MeasurableSpace α} (μ : Measure α) (s : Set α) : μ s = 0 := by @@ -870,14 +855,18 @@ theorem nnreal_smul_coe_apply {_m : MeasurableSpace α} (c : ℝ≥0) (μ : Meas c • μ s = c * μ s := by rfl -theorem ae_smul_measure_iff {p : α → Prop} {c : ℝ≥0∞} (hc : c ≠ 0) : - (∀ᵐ x ∂c • μ, p x) ↔ ∀ᵐ x ∂μ, p x := by +section SMulWithZero + +variable {R : Type*} [Zero R] [SMulWithZero R ℝ≥0∞] [IsScalarTower R ℝ≥0∞ ℝ≥0∞] + [NoZeroSMulDivisors R ℝ≥0∞] {c : R} {p : α → Prop} + +lemma ae_smul_measure_iff (hc : c ≠ 0) {μ : Measure α} : (∀ᵐ x ∂c • μ, p x) ↔ ∀ᵐ x ∂μ, p x := by simp [ae_iff, hc] -@[simp] -theorem ae_smul_measure_eq {c : ℝ≥0∞} (hc : c ≠ 0) : ae (c • μ) = ae μ := by - ext - exact ae_smul_measure_iff hc +@[simp] lemma ae_smul_measure_eq (hc : c ≠ 0) (μ : Measure α) : ae (c • μ) = ae μ := by + ext; exact ae_smul_measure_iff hc + +end SMulWithZero theorem measure_eq_left_of_subset_of_measure_add_eq {s t : Set α} (h : (μ + ν) t ≠ ∞) (h' : s ⊆ t) (h'' : (μ + ν) s = (μ + ν) t) : μ s = μ t := by @@ -1322,7 +1311,13 @@ theorem comap_preimage {β} [MeasurableSpace α] {mβ : MeasurableSpace β} (f : μ.comap f (f ⁻¹' s) = μ (s ∩ range f) := by rw [comap_apply₀ _ _ hf h (hf' hs).nullMeasurableSet, image_preimage_eq_inter_range] +@[simp] lemma comap_zero : (0 : Measure β).comap f = 0 := by + by_cases hf : Injective f ∧ ∀ s, MeasurableSet s → NullMeasurableSet (f '' s) (0 : Measure β) + · simp [comap, hf] + · simp [comap, hf] + section Sum +variable {f : ι → Measure α} /-- Sum of an indexed family of measures. -/ noncomputable def sum (f : ι → Measure α) : Measure α := @@ -1341,7 +1336,7 @@ theorem sum_apply (f : ι → Measure α) {s : Set α} (hs : MeasurableSet s) : theorem sum_apply₀ (f : ι → Measure α) {s : Set α} (hs : NullMeasurableSet s (sum f)) : sum f s = ∑' i, f i s := by apply le_antisymm ?_ (le_sum_apply _ _) - rcases hs.exists_measurable_subset_ae_eq with ⟨t, ts, t_meas, ht⟩ + rcases hs.exists_measurable_subset_ae_eq with ⟨t, ts, t_meas, ht⟩ calc sum f s = sum f t := measure_congr ht.symm _ = ∑' i, f i t := sum_apply _ t_meas @@ -1375,6 +1370,9 @@ theorem sum_apply_eq_zero [Countable ι] {μ : ι → Measure α} {s : Set α} : theorem sum_apply_eq_zero' {μ : ι → Measure α} {s : Set α} (hs : MeasurableSet s) : sum μ s = 0 ↔ ∀ i, μ i s = 0 := by simp [hs] +@[simp] lemma sum_eq_zero : sum f = 0 ↔ ∀ i, f i = 0 := by + simp (config := { contextual := true }) [Measure.ext_iff, forall_swap (α := ι)] + @[simp] lemma sum_zero : Measure.sum (fun (_ : ι) ↦ (0 : Measure α)) = 0 := by ext s hs @@ -1647,6 +1645,13 @@ theorem preimage_ae_eq {s t : Set β} (hf : QuasiMeasurePreserving f μa μb) (h f ⁻¹' s =ᵐ[μa] f ⁻¹' t := EventuallyLE.antisymm (hf.preimage_mono_ae h.le) (hf.preimage_mono_ae h.symm.le) +/-- The preimage of a null measurable set under a (quasi) measure preserving map is a null +measurable set. -/ +theorem _root_.MeasureTheory.NullMeasurableSet.preimage {s : Set β} (hs : NullMeasurableSet s μb) + (hf : QuasiMeasurePreserving f μa μb) : NullMeasurableSet (f ⁻¹' s) μa := + let ⟨t, htm, hst⟩ := hs + ⟨f ⁻¹' t, hf.measurable htm, hf.preimage_ae_eq hst⟩ + theorem preimage_iterate_ae_eq {s : Set α} {f : α → α} (hf : QuasiMeasurePreserving f μ μ) (k : ℕ) (hs : f ⁻¹' s =ᵐ[μ] s) : f^[k] ⁻¹' s =ᵐ[μ] s := by induction' k with k ih; · rfl @@ -1668,37 +1673,31 @@ theorem image_zpow_ae_eq {s : Set α} {e : α ≃ α} (he : QuasiMeasurePreservi replace he : (⇑e)^[k] ⁻¹' s =ᵐ[μ] s := he.preimage_iterate_ae_eq k hs rwa [Equiv.Perm.iterate_eq_pow e k] at he --- Need to specify `α := Set α` below because of diamond; see #19041 +-- Need to specify `α := Set α` below because of diamond; see #10941 theorem limsup_preimage_iterate_ae_eq {f : α → α} (hf : QuasiMeasurePreserving f μ μ) (hs : f ⁻¹' s =ᵐ[μ] s) : limsup (α := Set α) (fun n => (preimage f)^[n] s) atTop =ᵐ[μ] s := - haveI : ∀ n, (preimage f)^[n] s =ᵐ[μ] s := by - intro n - induction' n with n ih - · rfl - simpa only [iterate_succ', comp_apply] using ae_eq_trans (hf.ae_eq ih) hs - (limsup_ae_eq_of_forall_ae_eq (fun n => (preimage f)^[n] s) this).trans (ae_eq_refl _) - --- Need to specify `α := Set α` below because of diamond; see #19041 -theorem liminf_preimage_iterate_ae_eq {f : α → α} (hf : QuasiMeasurePreserving f μ μ) - (hs : f ⁻¹' s =ᵐ[μ] s) : liminf (α := Set α) (fun n => (preimage f)^[n] s) atTop =ᵐ[μ] s := by - rw [← ae_eq_set_compl_compl, @Filter.liminf_compl (Set α)] - rw [← ae_eq_set_compl_compl, ← preimage_compl] at hs - convert hf.limsup_preimage_iterate_ae_eq hs - ext1 n - simp only [← Set.preimage_iterate_eq, comp_apply, preimage_compl] + limsup_ae_eq_of_forall_ae_eq (fun n => (preimage f)^[n] s) fun n ↦ by + simpa only [Set.preimage_iterate_eq] using hf.preimage_iterate_ae_eq n hs -/-- By replacing a measurable set that is almost invariant with the `limsup` of its preimages, we -obtain a measurable set that is almost equal and strictly invariant. +-- Need to specify `α := Set α` below because of diamond; see #10941 +theorem liminf_preimage_iterate_ae_eq {f : α → α} (hf : QuasiMeasurePreserving f μ μ) + (hs : f ⁻¹' s =ᵐ[μ] s) : liminf (α := Set α) (fun n => (preimage f)^[n] s) atTop =ᵐ[μ] s := + liminf_ae_eq_of_forall_ae_eq (fun n => (preimage f)^[n] s) fun n ↦ by + simpa only [Set.preimage_iterate_eq] using hf.preimage_iterate_ae_eq n hs -(The `liminf` would work just as well.) -/ +/-- For a quasi measure preserving self-map `f`, if a null measurable set `s` is a.e. invariant, +then it is a.e. equal to a measurable invariant set. +-/ theorem exists_preimage_eq_of_preimage_ae {f : α → α} (h : QuasiMeasurePreserving f μ μ) - (hs : MeasurableSet s) (hs' : f ⁻¹' s =ᵐ[μ] s) : - ∃ t : Set α, MeasurableSet t ∧ t =ᵐ[μ] s ∧ f ⁻¹' t = t := - ⟨limsup (fun n => (preimage f)^[n] s) atTop, - MeasurableSet.measurableSet_limsup fun n => - preimage_iterate_eq ▸ h.measurable.iterate n hs, - h.limsup_preimage_iterate_ae_eq hs', - (CompleteLatticeHom.setPreimage f).apply_limsup_iterate s⟩ + (hs : NullMeasurableSet s μ) (hs' : f ⁻¹' s =ᵐ[μ] s) : + ∃ t : Set α, MeasurableSet t ∧ t =ᵐ[μ] s ∧ f ⁻¹' t = t := by + obtain ⟨t, htm, ht⟩ := hs + refine ⟨limsup (f^[·] ⁻¹' t) atTop, ?_, ?_, ?_⟩ + · exact .measurableSet_limsup fun n ↦ h.measurable.iterate n htm + · have : f ⁻¹' t =ᵐ[μ] t := (h.preimage_ae_eq ht.symm).trans (hs'.trans ht) + exact limsup_ae_eq_of_forall_ae_eq _ fun n ↦ .trans (h.preimage_iterate_ae_eq _ this) ht.symm + · simp only [Set.preimage_iterate_eq] + exact CompleteLatticeHom.apply_limsup_iterate (CompleteLatticeHom.setPreimage f) t open Pointwise @@ -1770,14 +1769,6 @@ lemma _root_.AEMeasurable.nullMeasurableSet_preimage {f : α → β} {s : Set β (hf : AEMeasurable f μ) (hs : MeasurableSet s) : NullMeasurableSet (f ⁻¹' s) μ := hf.nullMeasurable hs -/-- The preimage of a null measurable set under a (quasi) measure preserving map is a null -measurable set. -/ -theorem NullMeasurableSet.preimage {ν : Measure β} {f : α → β} {t : Set β} - (ht : NullMeasurableSet t ν) (hf : QuasiMeasurePreserving f μ ν) : - NullMeasurableSet (f ⁻¹' t) μ := - ⟨f ⁻¹' toMeasurable ν t, hf.measurable (measurableSet_toMeasurable _ _), - hf.ae_eq ht.toMeasurable_ae_eq.symm⟩ - theorem NullMeasurableSet.mono_ac (h : NullMeasurableSet s μ) (hle : ν ≪ μ) : NullMeasurableSet s ν := h.preimage <| (QuasiMeasurePreserving.id μ).mono_left hle @@ -1843,61 +1834,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 : α} @@ -2015,13 +1971,6 @@ theorem quasiMeasurePreserving_symm (μ : Measure α) (e : α ≃ᵐ β) : end MeasurableEquiv -namespace MeasureTheory - -theorem OuterMeasure.toMeasure_zero [MeasurableSpace α] : - (0 : OuterMeasure α).toMeasure (le_top.trans OuterMeasure.zero_caratheodory.symm.le) = 0 := by - rw [← Measure.measure_univ_eq_zero, toMeasure_apply _ _ MeasurableSet.univ, - OuterMeasure.coe_zero, Pi.zero_apply] - -end MeasureTheory - end + +set_option linter.style.longFile 2000 diff --git a/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean b/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean index 3c9f822f568c8..5dcc0f77d0243 100644 --- a/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean +++ b/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean @@ -203,11 +203,11 @@ theorem exists_measurable_superset_iff_measure_eq_zero : ⟨fun ⟨_t, hst, _, ht⟩ => measure_mono_null hst ht, exists_measurable_superset_of_null⟩ theorem measure_biUnion_lt_top {s : Set β} {f : β → Set α} (hs : s.Finite) - (hfin : ∀ i ∈ s, μ (f i) ≠ ∞) : μ (⋃ i ∈ s, f i) < ∞ := by + (hfin : ∀ i ∈ s, μ (f i) < ∞) : μ (⋃ i ∈ s, f i) < ∞ := by convert (measure_biUnion_finset_le (μ := μ) hs.toFinset f).trans_lt _ using 3 · ext rw [Finite.mem_toFinset] - · apply ENNReal.sum_lt_top; simpa only [Finite.mem_toFinset] + · simpa only [ENNReal.sum_lt_top, Finite.mem_toFinset] @[deprecated measure_iUnion_null_iff (since := "2024-01-14")] theorem measure_iUnion_null_iff' {ι : Prop} {s : ι → Set α} : μ (⋃ i, s i) = 0 ↔ ∀ i, μ (s i) = 0 := @@ -378,6 +378,9 @@ theorem Measurable.aemeasurable (h : Measurable f) : AEMeasurable f μ := namespace AEMeasurable +lemma of_discrete [DiscreteMeasurableSpace α] : AEMeasurable f μ := + Measurable.of_discrete.aemeasurable + /-- Given an almost everywhere measurable function `f`, associate to it a measurable function that coincides with it almost everywhere. `f` is explicit in the definition to make sure that it shows in pretty-printing. -/ diff --git a/Mathlib/MeasureTheory/Measure/NullMeasurable.lean b/Mathlib/MeasureTheory/Measure/NullMeasurable.lean index f1d91454da789..3f2767ff07960 100644 --- a/Mathlib/MeasureTheory/Measure/NullMeasurable.lean +++ b/Mathlib/MeasureTheory/Measure/NullMeasurable.lean @@ -122,6 +122,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 +136,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 @@ -278,6 +280,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 α μ)] 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 674c9e951c5a9..4d82e897d1771 100644 --- a/Mathlib/MeasureTheory/Measure/Portmanteau.lean +++ b/Mathlib/MeasureTheory/Measure/Portmanteau.lean @@ -51,12 +51,11 @@ theorem, however, is most convenient for probability measures on pseudo-emetriza their Borel sigma algebras. Some specific considerations on the assumptions in the different implications: - * `MeasureTheory.FiniteMeasure.limsup_measure_closed_le_of_tendsto` assumes - `PseudoEMetricSpace`. The only reason is to have bounded continuous pointwise approximations - to the indicator function of a closed set. Clearly for example metrizability or - pseudo-emetrizability would be sufficient assumptions. The typeclass assumptions should be later - adjusted in a way that takes into account use cases, but the proof will presumably remain - essentially the same. + * `MeasureTheory.FiniteMeasure.limsup_measure_closed_le_of_tendsto`, i.e., implication (T) → (C), + assumes that in the underlying topological space, indicator functions of closed sets have + decreasing bounded continuous pointwise approximating sequences. The assumption is in the form + of the type class `HasOuterApproxClosed`. Type class inference knows that for example the more + common assumptions of metrizability or pseudo-emetrizability suffice. * Where formulations are currently only provided for probability measures, one can obtain the finite measure formulations using the characterization of convergence of finite measures by their total masses and their probability-normalized versions, i.e., by @@ -99,11 +98,10 @@ of measures. variable {Ω : Type*} [MeasurableSpace Ω] -/-- **Portmanteau theorem** -/ theorem le_measure_compl_liminf_of_limsup_measure_le {ι : Type*} {L : Filter ι} {μ : Measure Ω} {μs : ι → Measure Ω} [IsProbabilityMeasure μ] [∀ i, IsProbabilityMeasure (μs i)] {E : Set Ω} - (E_mble : MeasurableSet E) (h : (L.limsup fun i => μs i E) ≤ μ E) : - μ Eᶜ ≤ L.liminf fun i => μs i Eᶜ := by + (E_mble : MeasurableSet E) (h : (L.limsup fun i ↦ μs i E) ≤ μ E) : + μ Eᶜ ≤ L.liminf fun i ↦ μs i Eᶜ := by rcases L.eq_or_neBot with rfl | hne · simp only [liminf_bot, le_top] have meas_Ec : μ Eᶜ = 1 - μ E := by @@ -112,24 +110,22 @@ theorem le_measure_compl_liminf_of_limsup_measure_le {ι : Type*} {L : Filter ι intro i simpa only [measure_univ] using measure_compl E_mble (measure_lt_top (μs i) E).ne simp_rw [meas_Ec, meas_i_Ec] - have obs : - (L.liminf fun i : ι => 1 - μs i E) = L.liminf ((fun x => 1 - x) ∘ fun i : ι => μs i E) := rfl - rw [obs] - have := antitone_const_tsub.map_limsup_of_continuousAt (F := L) - (fun i => μs i E) (ENNReal.continuous_sub_left ENNReal.one_ne_top).continuousAt - simp_rw [← this] - exact antitone_const_tsub h + rw [show (L.liminf fun i : ι ↦ 1 - μs i E) = L.liminf ((fun x ↦ 1 - x) ∘ fun i : ι ↦ μs i E) + from rfl] + have key := antitone_const_tsub.map_limsup_of_continuousAt (F := L) + (fun i ↦ μs i E) (ENNReal.continuous_sub_left ENNReal.one_ne_top).continuousAt + simpa [← key] using antitone_const_tsub h theorem le_measure_liminf_of_limsup_measure_compl_le {ι : Type*} {L : Filter ι} {μ : Measure Ω} {μs : ι → Measure Ω} [IsProbabilityMeasure μ] [∀ i, IsProbabilityMeasure (μs i)] {E : Set Ω} - (E_mble : MeasurableSet E) (h : (L.limsup fun i => μs i Eᶜ) ≤ μ Eᶜ) : - μ E ≤ L.liminf fun i => μs i E := + (E_mble : MeasurableSet E) (h : (L.limsup fun i ↦ μs i Eᶜ) ≤ μ Eᶜ) : + μ E ≤ L.liminf fun i ↦ μs i E := compl_compl E ▸ le_measure_compl_liminf_of_limsup_measure_le (MeasurableSet.compl E_mble) h theorem limsup_measure_compl_le_of_le_liminf_measure {ι : Type*} {L : Filter ι} {μ : Measure Ω} {μs : ι → Measure Ω} [IsProbabilityMeasure μ] [∀ i, IsProbabilityMeasure (μs i)] {E : Set Ω} - (E_mble : MeasurableSet E) (h : μ E ≤ L.liminf fun i => μs i E) : - (L.limsup fun i => μs i Eᶜ) ≤ μ Eᶜ := by + (E_mble : MeasurableSet E) (h : μ E ≤ L.liminf fun i ↦ μs i E) : + (L.limsup fun i ↦ μs i Eᶜ) ≤ μ Eᶜ := by rcases L.eq_or_neBot with rfl | hne · simp only [limsup_bot, bot_le] have meas_Ec : μ Eᶜ = 1 - μ E := by @@ -138,18 +134,16 @@ theorem limsup_measure_compl_le_of_le_liminf_measure {ι : Type*} {L : Filter ι intro i simpa only [measure_univ] using measure_compl E_mble (measure_lt_top (μs i) E).ne simp_rw [meas_Ec, meas_i_Ec] - have obs : - (L.limsup fun i : ι => 1 - μs i E) = L.limsup ((fun x => 1 - x) ∘ fun i : ι => μs i E) := rfl - rw [obs] - have := antitone_const_tsub.map_liminf_of_continuousAt (F := L) - (fun i => μs i E) (ENNReal.continuous_sub_left ENNReal.one_ne_top).continuousAt - simp_rw [← this] - exact antitone_const_tsub h + rw [show (L.limsup fun i : ι ↦ 1 - μs i E) = L.limsup ((fun x ↦ 1 - x) ∘ fun i : ι ↦ μs i E) + from rfl] + have key := antitone_const_tsub.map_liminf_of_continuousAt (F := L) + (fun i ↦ μs i E) (ENNReal.continuous_sub_left ENNReal.one_ne_top).continuousAt + simpa [← key] using antitone_const_tsub h theorem limsup_measure_le_of_le_liminf_measure_compl {ι : Type*} {L : Filter ι} {μ : Measure Ω} {μs : ι → Measure Ω} [IsProbabilityMeasure μ] [∀ i, IsProbabilityMeasure (μs i)] {E : Set Ω} - (E_mble : MeasurableSet E) (h : μ Eᶜ ≤ L.liminf fun i => μs i Eᶜ) : - (L.limsup fun i => μs i E) ≤ μ E := + (E_mble : MeasurableSet E) (h : μ Eᶜ ≤ L.liminf fun i ↦ μs i Eᶜ) : + (L.limsup fun i ↦ μs i E) ≤ μ E := compl_compl E ▸ limsup_measure_compl_le_of_le_liminf_measure (MeasurableSet.compl E_mble) h variable [TopologicalSpace Ω] [OpensMeasurableSpace Ω] @@ -166,8 +160,8 @@ under a candidate limit measure. theorem limsup_measure_closed_le_iff_liminf_measure_open_ge {ι : Type*} {L : Filter ι} {μ : Measure Ω} {μs : ι → Measure Ω} [IsProbabilityMeasure μ] [∀ i, IsProbabilityMeasure (μs i)] : - (∀ F, IsClosed F → (L.limsup fun i => μs i F) ≤ μ F) ↔ - ∀ G, IsOpen G → μ G ≤ L.liminf fun i => μs i G := by + (∀ F, IsClosed F → (L.limsup fun i ↦ μs i F) ≤ μ F) ↔ + ∀ G, IsOpen G → μ G ≤ L.liminf fun i ↦ μs i G := by constructor · intro h G G_open exact le_measure_liminf_of_limsup_measure_compl_le @@ -201,23 +195,23 @@ variable {Ω : Type*} [MeasurableSpace Ω] theorem tendsto_measure_of_le_liminf_measure_of_limsup_measure_le {ι : Type*} {L : Filter ι} {μ : Measure Ω} {μs : ι → Measure Ω} {E₀ E E₁ : Set Ω} (E₀_subset : E₀ ⊆ E) (subset_E₁ : E ⊆ E₁) - (nulldiff : μ (E₁ \ E₀) = 0) (h_E₀ : μ E₀ ≤ L.liminf fun i => μs i E₀) - (h_E₁ : (L.limsup fun i => μs i E₁) ≤ μ E₁) : L.Tendsto (fun i => μs i E) (𝓝 (μ E)) := by + (nulldiff : μ (E₁ \ E₀) = 0) (h_E₀ : μ E₀ ≤ L.liminf fun i ↦ μs i E₀) + (h_E₁ : (L.limsup fun i ↦ μs i E₁) ≤ μ E₁) : L.Tendsto (fun i ↦ μs i E) (𝓝 (μ E)) := by apply tendsto_of_le_liminf_of_limsup_le · have E₀_ae_eq_E : E₀ =ᵐ[μ] E := EventuallyLE.antisymm E₀_subset.eventuallyLE (subset_E₁.eventuallyLE.trans (ae_le_set.mpr nulldiff)) calc μ E = μ E₀ := measure_congr E₀_ae_eq_E.symm - _ ≤ L.liminf fun i => μs i E₀ := h_E₀ - _ ≤ L.liminf fun i => μs i E := - liminf_le_liminf (eventually_of_forall fun _ => measure_mono E₀_subset) + _ ≤ L.liminf fun i ↦ μs i E₀ := h_E₀ + _ ≤ L.liminf fun i ↦ μs i E := + liminf_le_liminf (.of_forall fun _ ↦ measure_mono E₀_subset) · have E_ae_eq_E₁ : E =ᵐ[μ] E₁ := EventuallyLE.antisymm subset_E₁.eventuallyLE ((ae_le_set.mpr nulldiff).trans E₀_subset.eventuallyLE) calc - (L.limsup fun i => μs i E) ≤ L.limsup fun i => μs i E₁ := - limsup_le_limsup (eventually_of_forall fun _ => measure_mono subset_E₁) + (L.limsup fun i ↦ μs i E) ≤ L.limsup fun i ↦ μs i E₁ := + limsup_le_limsup (.of_forall fun _ ↦ measure_mono subset_E₁) _ ≤ μ E₁ := h_E₁ _ = μ E := measure_congr E_ae_eq_E₁.symm · infer_param @@ -233,9 +227,9 @@ sequence converge to its measure under the candidate limit measure. -/ theorem tendsto_measure_of_null_frontier {ι : Type*} {L : Filter ι} {μ : Measure Ω} {μs : ι → Measure Ω} [IsProbabilityMeasure μ] [∀ i, IsProbabilityMeasure (μs i)] - (h_opens : ∀ G, IsOpen G → μ G ≤ L.liminf fun i => μs i G) {E : Set Ω} - (E_nullbdry : μ (frontier E) = 0) : L.Tendsto (fun i => μs i E) (𝓝 (μ E)) := - haveI h_closeds : ∀ F, IsClosed F → (L.limsup fun i => μs i F) ≤ μ F := + (h_opens : ∀ G, IsOpen G → μ G ≤ L.liminf fun i ↦ μs i G) {E : Set Ω} + (E_nullbdry : μ (frontier E) = 0) : L.Tendsto (fun i ↦ μs i E) (𝓝 (μ E)) := + haveI h_closeds : ∀ F, IsClosed F → (L.limsup fun i ↦ μs i F) ≤ μ F := limsup_measure_closed_le_iff_liminf_measure_open_ge.mpr h_opens tendsto_measure_of_le_liminf_measure_of_limsup_measure_le interior_subset subset_closure E_nullbdry (h_opens _ isOpen_interior) (h_closeds _ isClosed_closure) @@ -273,27 +267,24 @@ theorem FiniteMeasure.limsup_measure_closed_le_of_tendsto {Ω ι : Type*} {L : F [MeasurableSpace Ω] [TopologicalSpace Ω] [HasOuterApproxClosed Ω] [OpensMeasurableSpace Ω] {μ : FiniteMeasure Ω} {μs : ι → FiniteMeasure Ω} (μs_lim : Tendsto μs L (𝓝 μ)) {F : Set Ω} (F_closed : IsClosed F) : - (L.limsup fun i => (μs i : Measure Ω) F) ≤ (μ : Measure Ω) F := by + (L.limsup fun i ↦ (μs i : Measure Ω) F) ≤ (μ : Measure Ω) F := by rcases L.eq_or_neBot with rfl | hne · simp only [limsup_bot, bot_le] apply ENNReal.le_of_forall_pos_le_add intro ε ε_pos _ + have ε_pos' := (ENNReal.half_pos (ENNReal.coe_ne_zero.mpr ε_pos.ne.symm)).ne.symm let fs := F_closed.apprSeq have key₁ : Tendsto (fun n ↦ ∫⁻ ω, (fs n ω : ℝ≥0∞) ∂μ) atTop (𝓝 ((μ : Measure Ω) F)) := HasOuterApproxClosed.tendsto_lintegral_apprSeq F_closed (μ : Measure Ω) - have room₁ : (μ : Measure Ω) F < (μ : Measure Ω) F + ε / 2 := by - apply - ENNReal.lt_add_right (measure_lt_top (μ : Measure Ω) F).ne - (ENNReal.div_pos_iff.mpr ⟨(ENNReal.coe_pos.mpr ε_pos).ne.symm, ENNReal.two_ne_top⟩).ne.symm - rcases eventually_atTop.mp (eventually_lt_of_tendsto_lt room₁ key₁) with ⟨M, hM⟩ + have room₁ : (μ : Measure Ω) F < (μ : Measure Ω) F + ε / 2 := + ENNReal.lt_add_right (measure_lt_top (μ : Measure Ω) F).ne ε_pos' + obtain ⟨M, hM⟩ := eventually_atTop.mp <| eventually_lt_of_tendsto_lt room₁ key₁ have key₂ := FiniteMeasure.tendsto_iff_forall_lintegral_tendsto.mp μs_lim (fs M) have room₂ : - (lintegral (μ : Measure Ω) fun a => fs M a) < - (lintegral (μ : Measure Ω) fun a => fs M a) + ε / 2 := by - apply ENNReal.lt_add_right (ne_of_lt ?_) - (ENNReal.div_pos_iff.mpr ⟨(ENNReal.coe_pos.mpr ε_pos).ne.symm, ENNReal.two_ne_top⟩).ne.symm - apply BoundedContinuousFunction.lintegral_lt_top_of_nnreal - have ev_near := Eventually.mono (eventually_lt_of_tendsto_lt room₂ key₂) fun n => le_of_lt + (lintegral (μ : Measure Ω) fun a ↦ fs M a) < + (lintegral (μ : Measure Ω) fun a ↦ fs M a) + ε / 2 := + ENNReal.lt_add_right (ne_of_lt ((fs M).lintegral_lt_top_of_nnreal _)) ε_pos' + have ev_near := Eventually.mono (eventually_lt_of_tendsto_lt room₂ key₂) fun n ↦ le_of_lt have ev_near' := Eventually.mono ev_near (fun n ↦ le_trans (HasOuterApproxClosed.measure_le_lintegral F_closed (μs n) M)) apply (Filter.limsup_le_limsup ev_near').trans @@ -309,9 +300,9 @@ theorem ProbabilityMeasure.limsup_measure_closed_le_of_tendsto {Ω ι : Type*} { [MeasurableSpace Ω] [TopologicalSpace Ω] [OpensMeasurableSpace Ω] [HasOuterApproxClosed Ω] {μ : ProbabilityMeasure Ω} {μs : ι → ProbabilityMeasure Ω} (μs_lim : Tendsto μs L (𝓝 μ)) {F : Set Ω} (F_closed : IsClosed F) : - (L.limsup fun i => (μs i : Measure Ω) F) ≤ (μ : Measure Ω) F := by + (L.limsup fun i ↦ (μs i : Measure Ω) F) ≤ (μ : Measure Ω) F := by apply FiniteMeasure.limsup_measure_closed_le_of_tendsto - ((ProbabilityMeasure.tendsto_nhds_iff_toFiniteMeasure_tendsto_nhds L).mp μs_lim) F_closed + ((tendsto_nhds_iff_toFiniteMeasure_tendsto_nhds L).mp μs_lim) F_closed /-- One implication of the portmanteau theorem: Weak convergence of probability measures implies that the liminf of the measures of any open set @@ -321,9 +312,9 @@ theorem ProbabilityMeasure.le_liminf_measure_open_of_tendsto {Ω ι : Type*} {L [MeasurableSpace Ω] [PseudoEMetricSpace Ω] [OpensMeasurableSpace Ω] [HasOuterApproxClosed Ω] {μ : ProbabilityMeasure Ω} {μs : ι → ProbabilityMeasure Ω} (μs_lim : Tendsto μs L (𝓝 μ)) {G : Set Ω} (G_open : IsOpen G) : - (μ : Measure Ω) G ≤ L.liminf fun i => (μs i : Measure Ω) G := + (μ : Measure Ω) G ≤ L.liminf fun i ↦ (μs i : Measure Ω) G := haveI h_closeds : ∀ F, IsClosed F → (L.limsup fun i ↦ (μs i : Measure Ω) F) ≤ (μ : Measure Ω) F := - fun _ F_closed => ProbabilityMeasure.limsup_measure_closed_le_of_tendsto μs_lim F_closed + fun _ F_closed ↦ limsup_measure_closed_le_of_tendsto μs_lim F_closed le_measure_liminf_of_limsup_measure_compl_le G_open.measurableSet (h_closeds _ (isClosed_compl_iff.mpr G_open)) @@ -331,9 +322,9 @@ theorem ProbabilityMeasure.tendsto_measure_of_null_frontier_of_tendsto' {Ω ι : {L : Filter ι} [MeasurableSpace Ω] [PseudoEMetricSpace Ω] [OpensMeasurableSpace Ω] [HasOuterApproxClosed Ω] {μ : ProbabilityMeasure Ω} {μs : ι → ProbabilityMeasure Ω} (μs_lim : Tendsto μs L (𝓝 μ)) {E : Set Ω} (E_nullbdry : (μ : Measure Ω) (frontier E) = 0) : - Tendsto (fun i => (μs i : Measure Ω) E) L (𝓝 ((μ : Measure Ω) E)) := - haveI h_opens : ∀ G, IsOpen G → (μ : Measure Ω) G ≤ L.liminf fun i => (μs i : Measure Ω) G := - fun _ G_open => ProbabilityMeasure.le_liminf_measure_open_of_tendsto μs_lim G_open + Tendsto (fun i ↦ (μs i : Measure Ω) E) L (𝓝 ((μ : Measure Ω) E)) := + haveI h_opens : ∀ G, IsOpen G → (μ : Measure Ω) G ≤ L.liminf fun i ↦ (μs i : Measure Ω) G := + fun _ G_open ↦ le_liminf_measure_open_of_tendsto μs_lim G_open tendsto_measure_of_null_frontier h_opens E_nullbdry /-- One implication of the portmanteau theorem: @@ -347,10 +338,8 @@ A version with coercions to ordinary `ℝ≥0∞`-valued measures is theorem ProbabilityMeasure.tendsto_measure_of_null_frontier_of_tendsto {Ω ι : Type*} {L : Filter ι} [MeasurableSpace Ω] [PseudoEMetricSpace Ω] [OpensMeasurableSpace Ω] [HasOuterApproxClosed Ω] {μ : ProbabilityMeasure Ω} {μs : ι → ProbabilityMeasure Ω} (μs_lim : Tendsto μs L (𝓝 μ)) - {E : Set Ω} (E_nullbdry : μ (frontier E) = 0) : Tendsto (fun i => μs i E) L (𝓝 (μ E)) := by - have E_nullbdry' : (μ : Measure Ω) (frontier E) = 0 := by - rw [← ProbabilityMeasure.ennreal_coeFn_eq_coeFn_toMeasure, E_nullbdry, ENNReal.coe_zero] - have key := ProbabilityMeasure.tendsto_measure_of_null_frontier_of_tendsto' μs_lim E_nullbdry' + {E : Set Ω} (E_nullbdry : μ (frontier E) = 0) : Tendsto (fun i ↦ μs i E) L (𝓝 (μ E)) := by + have key := tendsto_measure_of_null_frontier_of_tendsto' μs_lim (by simpa using E_nullbdry) exact (ENNReal.tendsto_toNNReal (measure_ne_top (↑μ) E)).comp key end ConvergenceImpliesLimsupClosedLE --section @@ -385,7 +374,7 @@ variable {Ω : Type*} [PseudoEMetricSpace Ω] [MeasurableSpace Ω] [OpensMeasura theorem exists_null_frontier_thickening (μ : Measure Ω) [SFinite μ] (s : Set Ω) {a b : ℝ} (hab : a < b) : ∃ r ∈ Ioo a b, μ (frontier (Metric.thickening r s)) = 0 := by have mbles : ∀ r : ℝ, MeasurableSet (frontier (Metric.thickening r s)) := - fun r => isClosed_frontier.measurableSet + fun r ↦ isClosed_frontier.measurableSet have disjs := Metric.frontier_thickening_disjoint s have key := Measure.countable_meas_pos_of_disjoint_iUnion (μ := μ) mbles disjs have aux := measure_diff_null (s := Ioo a b) (Set.Countable.measure_zero key volume) @@ -402,21 +391,22 @@ theorem exists_null_frontiers_thickening (μ : Measure Ω) [SFinite μ] (s : Set have obs := fun n : ℕ => exists_null_frontier_thickening μ s (Rs_pos n) refine ⟨fun n : ℕ => (obs n).choose, ⟨?_, ?_⟩⟩ · exact tendsto_of_tendsto_of_tendsto_of_le_of_le tendsto_const_nhds Rs_lim - (fun n => (obs n).choose_spec.1.1.le) fun n => (obs n).choose_spec.1.2.le - · exact fun n => ⟨(obs n).choose_spec.1.1, (obs n).choose_spec.2⟩ + (fun n ↦ (obs n).choose_spec.1.1.le) fun n ↦ (obs n).choose_spec.1.2.le + · exact fun n ↦ ⟨(obs n).choose_spec.1.1, (obs n).choose_spec.2⟩ /-- One implication of the portmanteau theorem: Assuming that for all Borel sets E whose boundary ∂E carries no probability mass under a 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 @@ -430,15 +420,13 @@ lemma limsup_measure_closed_le_of_forall_tendsto_measure intros ε ε_pos μF_finite have keyB := tendsto_measure_cthickening_of_isClosed (μ := μ) (s := F) ⟨1, ⟨by simp only [gt_iff_lt, zero_lt_one], measure_ne_top _ _⟩⟩ F_closed - have nhd : Iio (μ F + ε) ∈ 𝓝 (μ F) := by - apply Iio_mem_nhds - exact ENNReal.lt_add_right μF_finite.ne (ENNReal.coe_pos.mpr ε_pos).ne' + have nhd : Iio (μ F + ε) ∈ 𝓝 (μ F) := + Iio_mem_nhds <| ENNReal.lt_add_right μF_finite.ne (ENNReal.coe_pos.mpr ε_pos).ne' specialize rs_lim (keyB nhd) - simp only [mem_map, mem_atTop_sets, mem_preimage, mem_Iio] at rs_lim + simp only [mem_map, mem_atTop_sets, ge_iff_le, mem_preimage, mem_Iio] at rs_lim obtain ⟨m, hm⟩ := rs_lim - have aux' := fun i ↦ measure_mono (μ := μs i) (Metric.self_subset_thickening (rs_pos m) F) have aux : (fun i ↦ (μs i F)) ≤ᶠ[L] (fun i ↦ μs i (Metric.thickening (rs m) F)) := - eventually_of_forall aux' + .of_forall <| fun i ↦ measure_mono (Metric.self_subset_thickening (rs_pos m) F) refine (limsup_le_limsup aux).trans ?_ rw [Tendsto.limsup_eq (key m)] apply (measure_mono (Metric.thickening_subset_cthickening (rs m) F)).trans (hm m rfl.le).le @@ -448,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))) @@ -481,7 +469,7 @@ lemma lintegral_le_liminf_lintegral_of_forall_isOpen_measure_le_liminf_measure {μ : Measure Ω} {μs : ℕ → Measure Ω} {f : Ω → ℝ} (f_cont : Continuous f) (f_nn : 0 ≤ f) (h_opens : ∀ G, IsOpen G → μ G ≤ atTop.liminf (fun i ↦ μs i G)) : ∫⁻ x, ENNReal.ofReal (f x) ∂μ ≤ atTop.liminf (fun i ↦ ∫⁻ x, ENNReal.ofReal (f x) ∂ (μs i)) := by - simp_rw [lintegral_eq_lintegral_meas_lt _ (eventually_of_forall f_nn) f_cont.aemeasurable] + simp_rw [lintegral_eq_lintegral_meas_lt _ (Eventually.of_forall f_nn) f_cont.aemeasurable] calc ∫⁻ (t : ℝ) in Set.Ioi 0, μ {a | t < f a} ≤ ∫⁻ (t : ℝ) in Set.Ioi 0, atTop.liminf (fun i ↦ (μs i) {a | t < f a}) := ?_ -- (i) _ ≤ atTop.liminf (fun i ↦ ∫⁻ (t : ℝ) in Set.Ioi 0, (μs i) {a | t < f a}) := ?_ -- (ii) @@ -499,23 +487,23 @@ lemma integral_le_liminf_integral_of_forall_isOpen_measure_le_liminf_measure ∫ x, (f x) ∂μ ≤ atTop.liminf (fun i ↦ ∫ x, (f x) ∂ (μs i)) := by have same := lintegral_le_liminf_lintegral_of_forall_isOpen_measure_le_liminf_measure f.continuous f_nn h_opens - rw [@integral_eq_lintegral_of_nonneg_ae Ω _ μ f (eventually_of_forall f_nn) + rw [@integral_eq_lintegral_of_nonneg_ae Ω _ μ f (Eventually.of_forall f_nn) f.continuous.measurable.aestronglyMeasurable] convert (ENNReal.toReal_le_toReal ?_ ?_).mpr same - · simp only [fun i ↦ @integral_eq_lintegral_of_nonneg_ae Ω _ (μs i) f (eventually_of_forall f_nn) + · simp only [fun i ↦ @integral_eq_lintegral_of_nonneg_ae Ω _ (μs i) f (Eventually.of_forall f_nn) f.continuous.measurable.aestronglyMeasurable] let g := BoundedContinuousFunction.comp _ Real.lipschitzWith_toNNReal f have bound : ∀ i, ∫⁻ x, ENNReal.ofReal (f x) ∂(μs i) ≤ nndist 0 g := fun i ↦ by - simpa only [coe_nnreal_ennreal_nndist, measure_univ, mul_one] using + simpa only [coe_nnreal_ennreal_nndist, measure_univ, mul_one, ge_iff_le] using BoundedContinuousFunction.lintegral_le_edist_mul (μ := μs i) g - apply ENNReal.liminf_toReal_eq ENNReal.coe_ne_top (eventually_of_forall bound) + apply ENNReal.liminf_toReal_eq ENNReal.coe_ne_top (Eventually.of_forall bound) · exact (f.lintegral_of_real_lt_top μ).ne · apply ne_of_lt have obs := fun (i : ℕ) ↦ @BoundedContinuousFunction.lintegral_nnnorm_le Ω _ _ (μs i) ℝ _ f simp only [measure_univ, mul_one] at obs apply lt_of_le_of_lt _ (show (‖f‖₊ : ℝ≥0∞) < ∞ from ENNReal.coe_lt_top) apply liminf_le_of_le - · refine ⟨0, eventually_of_forall (by simp only [zero_le, forall_const])⟩ + · refine ⟨0, .of_forall (by simp only [ge_iff_le, zero_le, forall_const])⟩ · intro x hx obtain ⟨i, hi⟩ := hx.exists apply le_trans hi @@ -542,13 +530,9 @@ theorem tendsto_of_forall_isOpen_le_liminf {μ : ProbabilityMeasure Ω} have aux : ENNReal.ofNNReal (liminf (fun i ↦ μs i G) atTop) = liminf (ENNReal.ofNNReal ∘ fun i ↦ μs i G) atTop := by refine Monotone.map_liminf_of_continuousAt (F := atTop) ENNReal.coe_mono (μs · G) ?_ ?_ ?_ - · apply ENNReal.continuous_coe.continuousAt - · apply IsBoundedUnder.isCoboundedUnder_ge ⟨1, ?_⟩ - simp only [eventually_map, ProbabilityMeasure.apply_le_one, eventually_atTop, ge_iff_le, - implies_true, forall_const, exists_const] - · use 0 - simp only [zero_le, eventually_map, eventually_atTop, implies_true, forall_const, - exists_const] + · exact ENNReal.continuous_coe.continuousAt + · exact IsBoundedUnder.isCoboundedUnder_ge ⟨1, by simp⟩ + · exact ⟨0, by simp⟩ have obs := ENNReal.coe_mono h_opens simp only [ne_eq, ProbabilityMeasure.ennreal_coeFn_eq_coeFn_toMeasure, aux] at obs convert obs diff --git a/Mathlib/MeasureTheory/Measure/ProbabilityMeasure.lean b/Mathlib/MeasureTheory/Measure/ProbabilityMeasure.lean index e990eebe4d4d6..465298ca8e9fc 100644 --- a/Mathlib/MeasureTheory/Measure/ProbabilityMeasure.lean +++ b/Mathlib/MeasureTheory/Measure/ProbabilityMeasure.lean @@ -74,14 +74,7 @@ convergence in distribution, convergence in law, weak convergence of measures, p noncomputable section -open MeasureTheory - -open Set - -open Filter - -open BoundedContinuousFunction - +open MeasureTheory Set Filter BoundedContinuousFunction open scoped Topology ENNReal NNReal BoundedContinuousFunction namespace MeasureTheory @@ -120,8 +113,7 @@ instance [Inhabited Ω] : Inhabited (ProbabilityMeasure Ω) := def toMeasure : ProbabilityMeasure Ω → Measure Ω := Subtype.val /-- A probability measure can be interpreted as a measure. -/ -instance : Coe (ProbabilityMeasure Ω) (MeasureTheory.Measure Ω) where - coe := toMeasure +instance : Coe (ProbabilityMeasure Ω) (MeasureTheory.Measure Ω) := { coe := toMeasure } instance (μ : ProbabilityMeasure Ω) : IsProbabilityMeasure (μ : Measure Ω) := μ.prop @@ -129,15 +121,14 @@ instance (μ : ProbabilityMeasure Ω) : IsProbabilityMeasure (μ : Measure Ω) : @[simp, norm_cast] lemma coe_mk (μ : Measure Ω) (hμ) : toMeasure ⟨μ, hμ⟩ = μ := rfl @[simp] -theorem val_eq_to_measure (ν : ProbabilityMeasure Ω) : ν.val = (ν : Measure Ω) := - rfl +theorem val_eq_to_measure (ν : ProbabilityMeasure Ω) : ν.val = (ν : Measure Ω) := rfl theorem toMeasure_injective : Function.Injective ((↑) : ProbabilityMeasure Ω → Measure Ω) := Subtype.coe_injective instance instFunLike : FunLike (ProbabilityMeasure Ω) (Set Ω) ℝ≥0 where coe μ s := ((μ : Measure Ω) s).toNNReal - coe_injective' μ ν h := toMeasure_injective $ Measure.ext fun s _ ↦ by + coe_injective' μ ν h := toMeasure_injective <| Measure.ext fun s _ ↦ by simpa [ENNReal.toNNReal_eq_toNNReal_iff, measure_ne_top] using congr_fun h s lemma coeFn_def (μ : ProbabilityMeasure Ω) : μ = fun s ↦ ((μ : Measure Ω) s).toNNReal := rfl @@ -157,8 +148,7 @@ theorem coeFn_univ_ne_zero (ν : ProbabilityMeasure Ω) : ν univ ≠ 0 := by simp only [coeFn_univ, Ne, one_ne_zero, not_false_iff] /-- A probability measure can be interpreted as a finite measure. -/ -def toFiniteMeasure (μ : ProbabilityMeasure Ω) : FiniteMeasure Ω := - ⟨μ, inferInstance⟩ +def toFiniteMeasure (μ : ProbabilityMeasure Ω) : FiniteMeasure Ω := ⟨μ, inferInstance⟩ @[simp] lemma coeFn_toFiniteMeasure (μ : ProbabilityMeasure Ω) : ⇑μ.toFiniteMeasure = μ := rfl lemma toFiniteMeasure_apply (μ : ProbabilityMeasure Ω) (s : Set Ω) : @@ -166,13 +156,11 @@ lemma toFiniteMeasure_apply (μ : ProbabilityMeasure Ω) (s : Set Ω) : @[simp] theorem toMeasure_comp_toFiniteMeasure_eq_toMeasure (ν : ProbabilityMeasure Ω) : - (ν.toFiniteMeasure : Measure Ω) = (ν : Measure Ω) := - rfl + (ν.toFiniteMeasure : Measure Ω) = (ν : Measure Ω) := rfl @[simp] theorem coeFn_comp_toFiniteMeasure_eq_coeFn (ν : ProbabilityMeasure Ω) : - (ν.toFiniteMeasure : Set Ω → ℝ≥0) = (ν : Set Ω → ℝ≥0) := - rfl + (ν.toFiniteMeasure : Set Ω → ℝ≥0) = (ν : Set Ω → ℝ≥0) := rfl @[simp] theorem toFiniteMeasure_apply_eq_apply (ν : ProbabilityMeasure Ω) (s : Set Ω) : @@ -184,6 +172,12 @@ theorem ennreal_coeFn_eq_coeFn_toMeasure (ν : ProbabilityMeasure Ω) (s : Set rw [← coeFn_comp_toFiniteMeasure_eq_coeFn, FiniteMeasure.ennreal_coeFn_eq_coeFn_toMeasure, toMeasure_comp_toFiniteMeasure_eq_toMeasure] +@[simp] +theorem null_iff_toMeasure_null (ν : ProbabilityMeasure Ω) (s : Set Ω) : + ν s = 0 ↔ (ν : Measure Ω) s = 0 := + ⟨fun h ↦ by rw [← ennreal_coeFn_eq_coeFn_toMeasure, h, ENNReal.coe_zero], + fun h ↦ congrArg ENNReal.toNNReal h⟩ + theorem apply_mono (μ : ProbabilityMeasure Ω) {s₁ s₂ : Set Ω} (h : s₁ ⊆ s₂) : μ s₁ ≤ μ s₂ := by rw [← coeFn_comp_toFiniteMeasure_eq_coeFn] exact MeasureTheory.FiniteMeasure.apply_mono _ h @@ -215,15 +209,14 @@ theorem mass_toFiniteMeasure (μ : ProbabilityMeasure Ω) : μ.toFiniteMeasure.m μ.coeFn_univ theorem toFiniteMeasure_nonzero (μ : ProbabilityMeasure Ω) : μ.toFiniteMeasure ≠ 0 := by - rw [← FiniteMeasure.mass_nonzero_iff, μ.mass_toFiniteMeasure] - exact one_ne_zero + simp [← FiniteMeasure.mass_nonzero_iff] section convergence_in_distribution variable [TopologicalSpace Ω] [OpensMeasurableSpace Ω] theorem testAgainstNN_lipschitz (μ : ProbabilityMeasure Ω) : - LipschitzWith 1 fun f : Ω →ᵇ ℝ≥0 => μ.toFiniteMeasure.testAgainstNN f := + LipschitzWith 1 fun f : Ω →ᵇ ℝ≥0 ↦ μ.toFiniteMeasure.testAgainstNN f := μ.mass_toFiniteMeasure ▸ μ.toFiniteMeasure.testAgainstNN_lipschitz /-- The topology of weak convergence on `MeasureTheory.ProbabilityMeasure Ω`. This is inherited @@ -243,21 +236,19 @@ def toWeakDualBCNN : ProbabilityMeasure Ω → WeakDual ℝ≥0 (Ω →ᵇ ℝ @[simp] theorem coe_toWeakDualBCNN (μ : ProbabilityMeasure Ω) : - ⇑μ.toWeakDualBCNN = μ.toFiniteMeasure.testAgainstNN := - rfl + ⇑μ.toWeakDualBCNN = μ.toFiniteMeasure.testAgainstNN := rfl @[simp] theorem toWeakDualBCNN_apply (μ : ProbabilityMeasure Ω) (f : Ω →ᵇ ℝ≥0) : - μ.toWeakDualBCNN f = (∫⁻ ω, f ω ∂(μ : Measure Ω)).toNNReal := - rfl + μ.toWeakDualBCNN f = (∫⁻ ω, f ω ∂(μ : Measure Ω)).toNNReal := rfl -theorem toWeakDualBCNN_continuous : Continuous fun μ : ProbabilityMeasure Ω => μ.toWeakDualBCNN := +theorem toWeakDualBCNN_continuous : Continuous fun μ : ProbabilityMeasure Ω ↦ μ.toWeakDualBCNN := FiniteMeasure.toWeakDualBCNN_continuous.comp toFiniteMeasure_continuous /- Integration of (nonnegative bounded continuous) test functions against Borel probability measures depends continuously on the measure. -/ theorem continuous_testAgainstNN_eval (f : Ω →ᵇ ℝ≥0) : - Continuous fun μ : ProbabilityMeasure Ω => μ.toFiniteMeasure.testAgainstNN f := + Continuous fun μ : ProbabilityMeasure Ω ↦ μ.toFiniteMeasure.testAgainstNN f := (FiniteMeasure.continuous_testAgainstNN_eval f).comp toFiniteMeasure_continuous -- The canonical mapping from probability measures to finite measures is an embedding. @@ -265,7 +256,7 @@ theorem toFiniteMeasure_embedding (Ω : Type*) [MeasurableSpace Ω] [Topological [OpensMeasurableSpace Ω] : Embedding (toFiniteMeasure : ProbabilityMeasure Ω → FiniteMeasure Ω) := { induced := rfl - inj := fun _μ _ν h => Subtype.eq <| congr_arg FiniteMeasure.toMeasure h } + inj := fun _μ _ν h ↦ Subtype.eq <| congr_arg FiniteMeasure.toMeasure h } theorem tendsto_nhds_iff_toFiniteMeasure_tendsto_nhds {δ : Type*} (F : Filter δ) {μs : δ → ProbabilityMeasure Ω} {μ₀ : ProbabilityMeasure Ω} : @@ -279,7 +270,7 @@ theorem tendsto_iff_forall_lintegral_tendsto {γ : Type*} {F : Filter γ} {μs : γ → ProbabilityMeasure Ω} {μ : ProbabilityMeasure Ω} : Tendsto μs F (𝓝 μ) ↔ ∀ f : Ω →ᵇ ℝ≥0, - Tendsto (fun i => ∫⁻ ω, f ω ∂(μs i : Measure Ω)) F (𝓝 (∫⁻ ω, f ω ∂(μ : Measure Ω))) := by + Tendsto (fun i ↦ ∫⁻ ω, f ω ∂(μs i : Measure Ω)) F (𝓝 (∫⁻ ω, f ω ∂(μ : Measure Ω))) := by rw [tendsto_nhds_iff_toFiniteMeasure_tendsto_nhds] exact FiniteMeasure.tendsto_iff_forall_lintegral_tendsto @@ -290,7 +281,7 @@ theorem tendsto_iff_forall_integral_tendsto {γ : Type*} {F : Filter γ} {μs : γ → ProbabilityMeasure Ω} {μ : ProbabilityMeasure Ω} : Tendsto μs F (𝓝 μ) ↔ ∀ f : Ω →ᵇ ℝ, - Tendsto (fun i => ∫ ω, f ω ∂(μs i : Measure Ω)) F (𝓝 (∫ ω, f ω ∂(μ : Measure Ω))) := by + Tendsto (fun i ↦ ∫ ω, f ω ∂(μs i : Measure Ω)) F (𝓝 (∫ ω, f ω ∂(μ : Measure Ω))) := by rw [tendsto_nhds_iff_toFiniteMeasure_tendsto_nhds] rw [FiniteMeasure.tendsto_iff_forall_integral_tendsto] rfl @@ -411,25 +402,25 @@ variable {μ} theorem tendsto_testAgainstNN_of_tendsto_normalize_testAgainstNN_of_tendsto_mass {γ : Type*} {F : Filter γ} {μs : γ → FiniteMeasure Ω} - (μs_lim : Tendsto (fun i => (μs i).normalize) F (𝓝 μ.normalize)) - (mass_lim : Tendsto (fun i => (μs i).mass) F (𝓝 μ.mass)) (f : Ω →ᵇ ℝ≥0) : - Tendsto (fun i => (μs i).testAgainstNN f) F (𝓝 (μ.testAgainstNN f)) := by + (μs_lim : Tendsto (fun i ↦ (μs i).normalize) F (𝓝 μ.normalize)) + (mass_lim : Tendsto (fun i ↦ (μs i).mass) F (𝓝 μ.mass)) (f : Ω →ᵇ ℝ≥0) : + Tendsto (fun i ↦ (μs i).testAgainstNN f) F (𝓝 (μ.testAgainstNN f)) := by by_cases h_mass : μ.mass = 0 · simp only [μ.mass_zero_iff.mp h_mass, zero_testAgainstNN_apply, zero_mass, - eq_self_iff_true] at * + eq_self_iff_true] at mass_lim ⊢ exact tendsto_zero_testAgainstNN_of_tendsto_zero_mass mass_lim f - simp_rw [fun i => (μs i).testAgainstNN_eq_mass_mul f, μ.testAgainstNN_eq_mass_mul f] + simp_rw [fun i ↦ (μs i).testAgainstNN_eq_mass_mul f, μ.testAgainstNN_eq_mass_mul f] rw [ProbabilityMeasure.tendsto_nhds_iff_toFiniteMeasure_tendsto_nhds] at μs_lim rw [tendsto_iff_forall_testAgainstNN_tendsto] at μs_lim have lim_pair : - Tendsto (fun i => (⟨(μs i).mass, (μs i).normalize.toFiniteMeasure.testAgainstNN f⟩ : ℝ≥0 × ℝ≥0)) + Tendsto (fun i ↦ (⟨(μs i).mass, (μs i).normalize.toFiniteMeasure.testAgainstNN f⟩ : ℝ≥0 × ℝ≥0)) F (𝓝 ⟨μ.mass, μ.normalize.toFiniteMeasure.testAgainstNN f⟩) := (Prod.tendsto_iff _ _).mpr ⟨mass_lim, μs_lim f⟩ exact tendsto_mul.comp lim_pair theorem tendsto_normalize_testAgainstNN_of_tendsto {γ : Type*} {F : Filter γ} {μs : γ → FiniteMeasure Ω} (μs_lim : Tendsto μs F (𝓝 μ)) (nonzero : μ ≠ 0) (f : Ω →ᵇ ℝ≥0) : - Tendsto (fun i => (μs i).normalize.toFiniteMeasure.testAgainstNN f) F + Tendsto (fun i ↦ (μs i).normalize.toFiniteMeasure.testAgainstNN f) F (𝓝 (μ.normalize.toFiniteMeasure.testAgainstNN f)) := by have lim_mass := μs_lim.mass have aux : {(0 : ℝ≥0)}ᶜ ∈ 𝓝 μ.mass := @@ -445,7 +436,7 @@ theorem tendsto_normalize_testAgainstNN_of_tendsto {γ : Type*} {F : Filter γ} apply normalize_testAgainstNN _ hi simp_rw [tendsto_congr' eve, μ.normalize_testAgainstNN nonzero] have lim_pair : - Tendsto (fun i => (⟨(μs i).mass⁻¹, (μs i).testAgainstNN f⟩ : ℝ≥0 × ℝ≥0)) F + Tendsto (fun i ↦ (⟨(μs i).mass⁻¹, (μs i).testAgainstNN f⟩ : ℝ≥0 × ℝ≥0)) F (𝓝 ⟨μ.mass⁻¹, μ.testAgainstNN f⟩) := by refine (Prod.tendsto_iff _ _).mpr ⟨?_, ?_⟩ · exact (continuousOn_inv₀.continuousAt aux).tendsto.comp lim_mass @@ -455,27 +446,27 @@ theorem tendsto_normalize_testAgainstNN_of_tendsto {γ : Type*} {F : Filter γ} /-- If the normalized versions of finite measures converge weakly and their total masses also converge, then the finite measures themselves converge weakly. -/ theorem tendsto_of_tendsto_normalize_testAgainstNN_of_tendsto_mass {γ : Type*} {F : Filter γ} - {μs : γ → FiniteMeasure Ω} (μs_lim : Tendsto (fun i => (μs i).normalize) F (𝓝 μ.normalize)) - (mass_lim : Tendsto (fun i => (μs i).mass) F (𝓝 μ.mass)) : Tendsto μs F (𝓝 μ) := by + {μs : γ → FiniteMeasure Ω} (μs_lim : Tendsto (fun i ↦ (μs i).normalize) F (𝓝 μ.normalize)) + (mass_lim : Tendsto (fun i ↦ (μs i).mass) F (𝓝 μ.mass)) : Tendsto μs F (𝓝 μ) := by rw [tendsto_iff_forall_testAgainstNN_tendsto] - exact fun f => + exact fun f ↦ tendsto_testAgainstNN_of_tendsto_normalize_testAgainstNN_of_tendsto_mass μs_lim mass_lim f /-- If finite measures themselves converge weakly to a nonzero limit measure, then their normalized versions also converge weakly. -/ theorem tendsto_normalize_of_tendsto {γ : Type*} {F : Filter γ} {μs : γ → FiniteMeasure Ω} (μs_lim : Tendsto μs F (𝓝 μ)) (nonzero : μ ≠ 0) : - Tendsto (fun i => (μs i).normalize) F (𝓝 μ.normalize) := by + Tendsto (fun i ↦ (μs i).normalize) F (𝓝 μ.normalize) := by rw [ProbabilityMeasure.tendsto_nhds_iff_toFiniteMeasure_tendsto_nhds, tendsto_iff_forall_testAgainstNN_tendsto] - exact fun f => tendsto_normalize_testAgainstNN_of_tendsto μs_lim nonzero f + exact fun f ↦ tendsto_normalize_testAgainstNN_of_tendsto μs_lim nonzero f /-- The weak convergence of finite measures to a nonzero limit can be characterized by the weak convergence of both their normalized versions (probability measures) and their total masses. -/ theorem tendsto_normalize_iff_tendsto {γ : Type*} {F : Filter γ} {μs : γ → FiniteMeasure Ω} (nonzero : μ ≠ 0) : - Tendsto (fun i => (μs i).normalize) F (𝓝 μ.normalize) ∧ - Tendsto (fun i => (μs i).mass) F (𝓝 μ.mass) ↔ + Tendsto (fun i ↦ (μs i).normalize) F (𝓝 μ.normalize) ∧ + Tendsto (fun i ↦ (μs i).mass) F (𝓝 μ.mass) ↔ Tendsto μs F (𝓝 μ) := by constructor · rintro ⟨normalized_lim, mass_lim⟩ @@ -513,8 +504,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/Measure/Regular.lean b/Mathlib/MeasureTheory/Measure/Regular.lean index 3ba9dadd512e0..362b5a971e2a4 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}`. @@ -361,7 +361,7 @@ theorem _root_.MeasurableSet.exists_isOpen_diff_lt [OuterRegular μ] {A : Set α ∃ U, U ⊇ A ∧ IsOpen U ∧ μ U < ∞ ∧ μ (U \ A) < ε := by rcases A.exists_isOpen_lt_add hA' hε with ⟨U, hAU, hUo, hU⟩ use U, hAU, hUo, hU.trans_le le_top - exact measure_diff_lt_of_lt_add hA hAU hA' hU + exact measure_diff_lt_of_lt_add hA.nullMeasurableSet hAU hA' hU protected theorem map [OpensMeasurableSpace α] [MeasurableSpace β] [TopologicalSpace β] [BorelSpace β] (f : α ≃ₜ β) (μ : Measure α) [OuterRegular μ] : @@ -455,10 +455,9 @@ lemma of_restrict {μ : Measure α} {s : ℕ → Set α} (h : ∀ n, InnerRegularWRT (μ.restrict (s n)) p MeasurableSet) (hs : univ ⊆ ⋃ n, s n) (hmono : Monotone s) : InnerRegularWRT μ p MeasurableSet := by intro F hF r hr - have hBU : ⋃ n, F ∩ s n = F := by rw [← inter_iUnion, univ_subset_iff.mp hs, inter_univ] + 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,8 +508,7 @@ 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⟩ @@ -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`. -/ @@ -730,7 +728,7 @@ theorem _root_.MeasurableSet.exists_isCompact_diff_lt [OpensMeasurableSpace α] {ε : ℝ≥0∞} (hε : ε ≠ 0) : ∃ K, K ⊆ A ∧ IsCompact K ∧ μ (A \ K) < ε := by rcases hA.exists_isCompact_lt_add h'A hε with ⟨K, hKA, hKc, hK⟩ - exact ⟨K, hKA, hKc, measure_diff_lt_of_lt_add hKc.measurableSet hKA + exact ⟨K, hKA, hKc, measure_diff_lt_of_lt_add hKc.nullMeasurableSet hKA (ne_top_of_le_ne_top h'A <| measure_mono hKA) hK⟩ /-- If `μ` is inner regular for finite measure sets with respect to compact sets, @@ -742,7 +740,7 @@ theorem _root_.MeasurableSet.exists_isCompact_isClosed_diff_lt [BorelSpace α] [ {ε : ℝ≥0∞} (hε : ε ≠ 0) : ∃ K, K ⊆ A ∧ IsCompact K ∧ IsClosed K ∧ μ (A \ K) < ε := by rcases hA.exists_isCompact_isClosed_lt_add h'A hε with ⟨K, hKA, hKco, hKcl, hK⟩ - exact ⟨K, hKA, hKco, hKcl, measure_diff_lt_of_lt_add hKcl.measurableSet hKA + exact ⟨K, hKA, hKco, hKcl, measure_diff_lt_of_lt_add hKcl.nullMeasurableSet hKA (ne_top_of_le_ne_top h'A <| measure_mono hKA) hK⟩ /-- If `μ` is inner regular for finite measure sets with respect to compact sets, @@ -826,12 +824,12 @@ protected theorem _root_.MeasurableSet.exists_isOpen_symmDiff_lt [InnerRegularCo rcases hs.exists_isCompact_isClosed_diff_lt hμs this with ⟨K, hKs, hKco, hKcl, hμK⟩ rcases hKco.exists_isOpen_lt_add (μ := μ) this with ⟨U, hKU, hUo, hμU⟩ refine ⟨U, hUo, hμU.trans_le le_top, ?_⟩ - rw [← ENNReal.add_halves ε, measure_symmDiff_eq hUo.measurableSet hs] + rw [← ENNReal.add_halves ε, measure_symmDiff_eq hUo.nullMeasurableSet hs.nullMeasurableSet] gcongr · calc μ (U \ s) ≤ μ (U \ K) := by gcongr _ < ε / 2 := by - apply measure_diff_lt_of_lt_add hKcl.measurableSet hKU _ hμU + apply measure_diff_lt_of_lt_add hKcl.nullMeasurableSet hKU _ hμU exact ne_top_of_le_ne_top hμs (by gcongr) · exact lt_of_le_of_lt (by gcongr) hμK @@ -918,7 +916,7 @@ theorem _root_.MeasurableSet.exists_isClosed_diff_lt [OpensMeasurableSpace α] [ ⦃A : Set α⦄ (hA : MeasurableSet A) (h'A : μ A ≠ ∞) {ε : ℝ≥0∞} (hε : ε ≠ 0) : ∃ F, F ⊆ A ∧ IsClosed F ∧ μ (A \ F) < ε := by rcases hA.exists_isClosed_lt_add h'A hε with ⟨F, hFA, hFc, hF⟩ - exact ⟨F, hFA, hFc, measure_diff_lt_of_lt_add hFc.measurableSet hFA + exact ⟨F, hFA, hFc, measure_diff_lt_of_lt_add hFc.nullMeasurableSet hFA (ne_top_of_le_ne_top h'A <| measure_mono hFA) hF⟩ /-- Given a weakly regular measure, any measurable set of finite mass can be approximated from @@ -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 0acae1a750f6c..5e3e7702c9a7e 100644 --- a/Mathlib/MeasureTheory/Measure/Restrict.lean +++ b/Mathlib/MeasureTheory/Measure/Restrict.lean @@ -76,11 +76,21 @@ theorem restrict_mono' {_m0 : MeasurableSpace α} ⦃s s' : Set α⦄ ⦃μ ν : _ = ν.restrict s' t := (restrict_apply ht).symm /-- Restriction of a measure to a subset is monotone both in set and in measure. -/ -@[mono] +@[mono, gcongr] theorem restrict_mono {_m0 : MeasurableSpace α} ⦃s s' : Set α⦄ (hs : s ⊆ s') ⦃μ ν : Measure α⦄ (hμν : μ ≤ ν) : μ.restrict s ≤ ν.restrict s' := restrict_mono' (ae_of_all _ hs) hμν +@[gcongr] +theorem restrict_mono_measure {_ : MeasurableSpace α} {μ ν : Measure α} (h : μ ≤ ν) (s : Set α) : + μ.restrict s ≤ ν.restrict s := + restrict_mono subset_rfl h + +@[gcongr] +theorem restrict_mono_set {_ : MeasurableSpace α} (μ : Measure α) {s t : Set α} (h : s ⊆ t) : + μ.restrict s ≤ μ.restrict t := + restrict_mono h le_rfl + theorem restrict_mono_ae (h : s ≤ᵐ[μ] t) : μ.restrict s ≤ μ.restrict t := restrict_mono' h (le_refl μ) @@ -271,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 @@ -307,11 +317,8 @@ measurable subsets of `s ∪ t`. -/ theorem restrict_union_congr : μ.restrict (s ∪ t) = ν.restrict (s ∪ t) ↔ μ.restrict s = ν.restrict s ∧ μ.restrict t = ν.restrict t := by - refine - ⟨fun h => - ⟨restrict_congr_mono subset_union_left h, - restrict_congr_mono subset_union_right h⟩, - ?_⟩ + refine ⟨fun h ↦ ⟨restrict_congr_mono subset_union_left h, + restrict_congr_mono subset_union_right h⟩, ?_⟩ rintro ⟨hs, ht⟩ ext1 u hu simp only [restrict_apply hu, inter_union_distrib_left] @@ -319,14 +326,14 @@ theorem restrict_union_congr : calc μ (u ∩ s ∪ u ∩ t) = μ (US ∪ u ∩ t) := measure_union_congr_of_subset hsub hμ.le Subset.rfl le_rfl - _ = μ US + μ ((u ∩ t) \ US) := (measure_add_diff hm _).symm + _ = μ US + μ ((u ∩ t) \ US) := (measure_add_diff hm.nullMeasurableSet _).symm _ = restrict μ s u + restrict μ t (u \ US) := by simp only [restrict_apply, hu, hu.diff hm, hμ, ← inter_comm t, inter_diff_assoc] _ = restrict ν s u + restrict ν t (u \ US) := by rw [hs, ht] _ = ν US + ν ((u ∩ t) \ US) := by simp only [restrict_apply, hu, hu.diff hm, hν, ← inter_comm t, inter_diff_assoc] - _ = ν (US ∪ u ∩ t) := measure_add_diff hm _ - _ = ν (u ∩ s ∪ u ∩ t) := Eq.symm <| measure_union_congr_of_subset hsub hν.le Subset.rfl le_rfl + _ = ν (US ∪ u ∩ t) := measure_add_diff hm.nullMeasurableSet _ + _ = ν (u ∩ s ∪ u ∩ t) := .symm <| measure_union_congr_of_subset hsub hν.le Subset.rfl le_rfl theorem restrict_finset_biUnion_congr {s : Finset ι} {t : ι → Set α} : μ.restrict (⋃ i ∈ s, t i) = ν.restrict (⋃ i ∈ s, t i) ↔ @@ -370,6 +377,20 @@ theorem exists_mem_of_measure_ne_zero_of_ae (hs : μ s ≠ 0) {p : α → Prop} rw [← μ.restrict_apply_self, ← frequently_ae_mem_iff] at hs exact (hs.and_eventually hp).exists +/-- If a quasi measure preserving map `f` maps a set `s` to a set `t`, +then it is quasi measure preserving with respect to the restrictions of the measures. -/ +theorem QuasiMeasurePreserving.restrict {ν : Measure β} {f : α → β} + (hf : QuasiMeasurePreserving f μ ν) {t : Set β} (hmaps : MapsTo f s t) : + QuasiMeasurePreserving f (μ.restrict s) (ν.restrict t) where + measurable := hf.measurable + absolutelyContinuous := by + refine AbsolutelyContinuous.mk fun u hum ↦ ?_ + suffices ν (u ∩ t) = 0 → μ (f ⁻¹' u ∩ s) = 0 by simpa [hum, hf.measurable, hf.measurable hum] + refine fun hu ↦ measure_mono_null ?_ (hf.preimage_null hu) + rw [preimage_inter] + gcongr + assumption + /-! ### Extensionality results -/ /-- Two measures are equal if they have equal restrictions on a spanning collection of sets @@ -556,7 +577,7 @@ theorem _root_.Filter.EventuallyEq.restrict {f g : α → δ} {s : Set α} (hfg exact Measure.absolutelyContinuous_of_le Measure.restrict_le_self theorem ae_restrict_mem₀ (hs : NullMeasurableSet s μ) : ∀ᵐ x ∂μ.restrict s, x ∈ s := - (ae_restrict_iff'₀ hs).2 (Filter.eventually_of_forall fun _ => id) + (ae_restrict_iff'₀ hs).2 (Filter.Eventually.of_forall fun _ => id) theorem ae_restrict_mem (hs : MeasurableSet s) : ∀ᵐ x ∂μ.restrict s, x ∈ s := ae_restrict_mem₀ hs.nullMeasurableSet @@ -652,20 +673,6 @@ theorem ae_restrict_congr_set {s t} (hst : s =ᵐ[μ] t) {p : α → Prop} : (∀ᵐ x ∂μ.restrict s, p x) ↔ ∀ᵐ x ∂μ.restrict t, p x := ⟨ae_restrict_of_ae_eq_of_ae_restrict hst, ae_restrict_of_ae_eq_of_ae_restrict hst.symm⟩ -/-- A version of the **Borel-Cantelli lemma**: if `pᵢ` is a sequence of predicates such that -`∑ μ {x | pᵢ x}` is finite, then the measure of `x` such that `pᵢ x` holds frequently as `i → ∞` (or -equivalently, `pᵢ x` holds for infinitely many `i`) is equal to zero. -/ -theorem measure_setOf_frequently_eq_zero {p : ℕ → α → Prop} (hp : ∑' i, μ { x | p i x } ≠ ∞) : - μ { x | ∃ᶠ n in atTop, p n x } = 0 := by - simpa only [limsup_eq_iInf_iSup_of_nat, frequently_atTop, ← bex_def, setOf_forall, - setOf_exists] using measure_limsup_eq_zero hp - -/-- A version of the **Borel-Cantelli lemma**: if `sᵢ` is a sequence of sets such that -`∑ μ sᵢ` exists, then for almost all `x`, `x` does not belong to almost all `sᵢ`. -/ -theorem ae_eventually_not_mem {s : ℕ → Set α} (hs : (∑' i, μ (s i)) ≠ ∞) : - ∀ᵐ x ∂μ, ∀ᶠ n in atTop, x ∉ s n := - measure_setOf_frequently_eq_zero hs - lemma NullMeasurable.measure_preimage_eq_measure_restrict_preimage_of_ae_compl_eq_const {β : Type*} [MeasurableSpace β] {b : β} {f : α → β} {s : Set α} (f_mble : NullMeasurable f (μ.restrict s)) (hs : f =ᵐ[Measure.restrict μ sᶜ] (fun _ ↦ b)) diff --git a/Mathlib/MeasureTheory/Measure/SeparableMeasure.lean b/Mathlib/MeasureTheory/Measure/SeparableMeasure.lean new file mode 100644 index 0000000000000..167c0d5bdfb53 --- /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 BigOperators symmDiff Filter 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 98968697286c0..841b773d2cd9d 100644 --- a/Mathlib/MeasureTheory/Measure/Stieltjes.lean +++ b/Mathlib/MeasureTheory/Measure/Stieltjes.lean @@ -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,8 +373,9 @@ 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) (fun m n hmn => ?_) ?_ - · exact Ioc_subset_Ioc (u_mono.monotone hmn) le_rfl + 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⟩ have L2 : Tendsto (fun n => f.measure (Ioc (u n) a)) atTop (𝓝 (ofReal (f a - leftLim f a))) := by @@ -383,7 +384,7 @@ theorem measure_singleton (a : ℝ) : f.measure {a} = ofReal (f a - leftLim f a) apply (f.mono.tendsto_leftLim a).comp exact tendsto_nhdsWithin_of_tendsto_nhds_of_eventually_within _ u_lim - (eventually_of_forall fun n => u_lt_a n) + (Eventually.of_forall fun n => u_lt_a n) exact ENNReal.continuous_ofReal.continuousAt.tendsto.comp (tendsto_const_nhds.sub this) exact tendsto_nhds_unique L1 L2 diff --git a/Mathlib/MeasureTheory/Measure/Sub.lean b/Mathlib/MeasureTheory/Measure/Sub.lean index 956465498e954..224f04d912129 100644 --- a/Mathlib/MeasureTheory/Measure/Sub.lean +++ b/Mathlib/MeasureTheory/Measure/Sub.lean @@ -91,7 +91,7 @@ theorem sub_add_cancel_of_le [IsFiniteMeasure ν] (h₁ : ν ≤ μ) : μ - ν + rw [add_apply, sub_apply h_s_meas h₁, tsub_add_cancel_of_le (h₁ s)] @[simp] -lemma add_sub_cancel [IsFiniteMeasure ν] : μ + ν - ν = μ := by +protected lemma add_sub_cancel [IsFiniteMeasure ν] : μ + ν - ν = μ := by ext1 s hs rw [sub_apply hs (Measure.le_add_left (le_refl _)), add_apply, ENNReal.add_sub_cancel_right (measure_ne_top ν s)] diff --git a/Mathlib/MeasureTheory/Measure/Typeclasses.lean b/Mathlib/MeasureTheory/Measure/Typeclasses.lean index 0777f34ae5b0a..9268fb8418824 100644 --- a/Mathlib/MeasureTheory/Measure/Typeclasses.lean +++ b/Mathlib/MeasureTheory/Measure/Typeclasses.lean @@ -12,6 +12,7 @@ We introduce the following typeclasses for measures: * `IsProbabilityMeasure μ`: `μ univ = 1`; * `IsFiniteMeasure μ`: `μ univ < ∞`; +* `IsZeroOrProbabilityMeasure μ`: `μ univ = 0 ∨ μ univ = 1`; * `SigmaFinite μ`: there exists a countable collection of sets that cover `univ` where `μ` is finite; * `SFinite μ`: the measure `μ` can be written as a countable sum of finite measures; @@ -45,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] theorem measure_ne_top (μ : Measure α) [IsFiniteMeasure μ] (s : Set α) : μ s ≠ ∞ := ne_of_lt (measure_lt_top μ s) @@ -95,7 +97,7 @@ instance isFiniteMeasureAdd [IsFiniteMeasure μ] [IsFiniteMeasure ν] : IsFinite exact ⟨measure_lt_top _ _, measure_lt_top _ _⟩ instance isFiniteMeasureSMulNNReal [IsFiniteMeasure μ] {r : ℝ≥0} : IsFiniteMeasure (r • μ) where - measure_univ_lt_top := ENNReal.mul_lt_top ENNReal.coe_ne_top (measure_ne_top _ _) + measure_univ_lt_top := ENNReal.mul_lt_top ENNReal.coe_lt_top (measure_lt_top _ _) instance IsFiniteMeasure.average : IsFiniteMeasure ((μ univ)⁻¹ • μ) where measure_univ_lt_top := by @@ -142,13 +144,9 @@ theorem summable_measure_toReal [hμ : IsFiniteMeasure μ] {f : ℕ → Set α} exact ne_of_lt (measure_lt_top _ _) theorem ae_eq_univ_iff_measure_eq [IsFiniteMeasure μ] (hs : NullMeasurableSet s μ) : - s =ᵐ[μ] univ ↔ μ s = μ univ := by - refine ⟨measure_congr, fun h => ?_⟩ - obtain ⟨t, -, ht₁, ht₂⟩ := hs.exists_measurable_subset_ae_eq - exact - ht₂.symm.trans - (ae_eq_of_subset_of_measure_ge (subset_univ t) (Eq.le ((measure_congr ht₂).trans h).symm) ht₁ - (measure_ne_top μ univ)) + s =ᵐ[μ] univ ↔ μ s = μ univ := + ⟨measure_congr, fun h ↦ + 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 @@ -160,7 +158,7 @@ theorem ae_mem_iff_measure_eq [IsFiniteMeasure μ] {s : Set α} (hs : NullMeasur lemma tendsto_measure_biUnion_Ici_zero_of_pairwise_disjoint {X : Type*} [MeasurableSpace X] {μ : Measure X} [IsFiniteMeasure μ] - {Es : ℕ → Set X} (Es_mble : ∀ i, MeasurableSet (Es i)) + {Es : ℕ → Set X} (Es_mble : ∀ i, NullMeasurableSet (Es i) μ) (Es_disj : Pairwise fun n m ↦ Disjoint (Es n) (Es m)) : Tendsto (μ ∘ fun n ↦ ⋃ i ≥ n, Es i) atTop (𝓝 0) := by have decr : Antitone fun n ↦ ⋃ i ≥ n, Es i := @@ -173,15 +171,16 @@ lemma tendsto_measure_biUnion_Ici_zero_of_pairwise_disjoint obtain ⟨k, k_gt_j, x_in_Es_k⟩ := hx (j+1) have oops := (Es_disj (Nat.ne_of_lt k_gt_j)).ne_of_mem x_in_Es_j x_in_Es_k contradiction - have key := - tendsto_measure_iInter (μ := μ) (fun n ↦ by measurability) decr ⟨0, measure_ne_top _ _⟩ + -- TODO: `by measurability` fails + have key := tendsto_measure_iInter (μ := μ) (fun n ↦ .iUnion fun _ ↦ .iUnion fun _ ↦ Es_mble _) + decr ⟨0, measure_ne_top _ _⟩ simp only [nothing, measure_empty] at key convert key open scoped symmDiff theorem abs_toReal_measure_sub_le_measure_symmDiff' - (hs : MeasurableSet s) (ht : MeasurableSet t) (hs' : μ s ≠ ∞) (ht' : μ t ≠ ∞) : + (hs : NullMeasurableSet s μ) (ht : NullMeasurableSet t μ) (hs' : μ s ≠ ∞) (ht' : μ t ≠ ∞) : |(μ s).toReal - (μ t).toReal| ≤ (μ (s ∆ t)).toReal := by have hst : μ (s \ t) ≠ ∞ := (measure_lt_top_of_subset diff_subset hs').ne have hts : μ (t \ s) ≠ ∞ := (measure_lt_top_of_subset diff_subset ht').ne @@ -195,12 +194,49 @@ theorem abs_toReal_measure_sub_le_measure_symmDiff' abel theorem abs_toReal_measure_sub_le_measure_symmDiff [IsFiniteMeasure μ] - (hs : MeasurableSet s) (ht : MeasurableSet t) : + (hs : NullMeasurableSet s μ) (ht : NullMeasurableSet t μ) : |(μ s).toReal - (μ t).toReal| ≤ (μ (s ∆ t)).toReal := abs_toReal_measure_sub_le_measure_symmDiff' hs ht (measure_ne_top μ s) (measure_ne_top μ t) +instance {s : Finset ι} {μ : ι → Measure α} [∀ i, IsFiniteMeasure (μ i)] : + IsFiniteMeasure (∑ i ∈ s, μ i) where measure_univ_lt_top := by simp [measure_lt_top] + +instance [Finite ι] {μ : ι → Measure α} [∀ i, IsFiniteMeasure (μ i)] : + IsFiniteMeasure (.sum μ) where + measure_univ_lt_top := by + cases nonempty_fintype ι + simp [measure_lt_top] + end IsFiniteMeasure +section IsZeroOrProbabilityMeasure + +/-- A measure `μ` is zero or a probability measure if `μ univ = 0` or `μ univ = 1`. This class +of measures appears naturally when conditioning on events, and many results which are true for +probability measures hold more generally over this class. -/ +class IsZeroOrProbabilityMeasure (μ : Measure α) : Prop where + measure_univ : μ univ = 0 ∨ μ univ = 1 + +lemma isZeroOrProbabilityMeasure_iff : IsZeroOrProbabilityMeasure μ ↔ μ univ = 0 ∨ μ univ = 1 := + ⟨fun _ ↦ IsZeroOrProbabilityMeasure.measure_univ, IsZeroOrProbabilityMeasure.mk⟩ + +lemma prob_le_one {μ : Measure α} [IsZeroOrProbabilityMeasure μ] {s : Set α} : μ s ≤ 1 := by + apply (measure_mono (subset_univ _)).trans + rcases IsZeroOrProbabilityMeasure.measure_univ (μ := μ) with h | h <;> simp [h] + +@[simp] +theorem one_le_prob_iff {μ : Measure α} [IsZeroOrProbabilityMeasure μ] : 1 ≤ μ s ↔ μ s = 1 := + ⟨fun h => le_antisymm prob_le_one h, fun h => h ▸ le_refl _⟩ + +instance (priority := 100) IsZeroOrProbabilityMeasure.toIsFiniteMeasure (μ : Measure α) + [IsZeroOrProbabilityMeasure μ] : IsFiniteMeasure μ := + ⟨prob_le_one.trans_lt one_lt_top⟩ + +instance : IsZeroOrProbabilityMeasure (0 : Measure α) := + ⟨Or.inl rfl⟩ + +end IsZeroOrProbabilityMeasure + section IsProbabilityMeasure /-- A measure `μ` is called a probability measure if `μ univ = 1`. -/ @@ -214,9 +250,9 @@ attribute [simp] IsProbabilityMeasure.measure_univ lemma isProbabilityMeasure_iff : IsProbabilityMeasure μ ↔ μ univ = 1 := ⟨fun _ ↦ measure_univ, IsProbabilityMeasure.mk⟩ -instance (priority := 100) IsProbabilityMeasure.toIsFiniteMeasure (μ : Measure α) - [IsProbabilityMeasure μ] : IsFiniteMeasure μ := - ⟨by simp only [measure_univ, ENNReal.one_lt_top]⟩ +instance (priority := 100) (μ : Measure α) [IsProbabilityMeasure μ] : + IsZeroOrProbabilityMeasure μ := + ⟨Or.inr measure_univ⟩ theorem IsProbabilityMeasure.ne_zero (μ : Measure α) [IsProbabilityMeasure μ] : μ ≠ 0 := mt measure_univ_eq_zero.2 <| by simp [measure_univ] @@ -230,9 +266,6 @@ theorem IsProbabilityMeasure.ae_neBot [IsProbabilityMeasure μ] : NeBot (ae μ) theorem prob_add_prob_compl [IsProbabilityMeasure μ] (h : MeasurableSet s) : μ s + μ sᶜ = 1 := (measure_add_measure_compl h).trans measure_univ -theorem prob_le_one [IsProbabilityMeasure μ] : μ s ≤ 1 := - (measure_mono <| Set.subset_univ _).trans_eq measure_univ - -- Porting note: made an `instance`, using `NeZero` instance isProbabilityMeasureSMul [IsFiniteMeasure μ] [NeZero μ] : IsProbabilityMeasure ((μ univ)⁻¹ • μ) := @@ -244,10 +277,6 @@ theorem isProbabilityMeasure_map {f : α → β} (hf : AEMeasurable f μ) : IsProbabilityMeasure (map f μ) := ⟨by simp [map_apply_of_aemeasurable, hf]⟩ -@[simp] -theorem one_le_prob_iff : 1 ≤ μ s ↔ μ s = 1 := - ⟨fun h => le_antisymm prob_le_one h, fun h => h ▸ le_refl _⟩ - /-- 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 `ℝ`. -/ @@ -260,17 +289,6 @@ better-behaved subtraction of `ℝ`. -/ theorem prob_compl_eq_one_sub (hs : MeasurableSet s) : μ sᶜ = 1 - μ s := prob_compl_eq_one_sub₀ hs.nullMeasurableSet -lemma prob_compl_lt_one_sub_of_lt_prob {p : ℝ≥0∞} (hμs : p < μ s) (s_mble : MeasurableSet s) : - μ sᶜ < 1 - p := by - rw [prob_compl_eq_one_sub s_mble] - apply ENNReal.sub_lt_of_sub_lt prob_le_one (Or.inl one_ne_top) - convert hμs - exact ENNReal.sub_sub_cancel one_ne_top (lt_of_lt_of_le hμs prob_le_one).le - -lemma prob_compl_le_one_sub_of_le_prob {p : ℝ≥0∞} (hμs : p ≤ μ s) (s_mble : MeasurableSet s) : - μ sᶜ ≤ 1 - p := by - simpa [prob_compl_eq_one_sub s_mble] using tsub_le_tsub_left hμs 1 - @[simp] lemma prob_compl_eq_zero_iff₀ (hs : NullMeasurableSet s μ) : μ sᶜ = 0 ↔ μ s = 1 := by rw [prob_compl_eq_one_sub₀ hs, tsub_eq_zero_iff_le, one_le_prob_iff] @@ -313,6 +331,47 @@ instance isProbabilityMeasure_comap_down : IsProbabilityMeasure (μ.comap ULift. end IsProbabilityMeasure +section IsZeroOrProbabilityMeasure + +instance isZeroOrProbabilityMeasureSMul : + IsZeroOrProbabilityMeasure ((μ univ)⁻¹ • μ) := by + rcases eq_zero_or_neZero μ with rfl | h + · simp; infer_instance + rcases eq_top_or_lt_top (μ univ) with h | h + · simp [h]; infer_instance + have : IsFiniteMeasure μ := ⟨h⟩ + infer_instance + +variable [IsZeroOrProbabilityMeasure μ] {p : α → Prop} {f : β → α} + +variable (μ) in +lemma eq_zero_or_isProbabilityMeasure : μ = 0 ∨ IsProbabilityMeasure μ := by + rcases IsZeroOrProbabilityMeasure.measure_univ (μ := μ) with h | h + · apply Or.inl (measure_univ_eq_zero.mp h) + · exact Or.inr ⟨h⟩ + +instance {f : α → β} : IsZeroOrProbabilityMeasure (map f μ) := by + by_cases hf : AEMeasurable f μ + · simpa [isZeroOrProbabilityMeasure_iff, hf] using IsZeroOrProbabilityMeasure.measure_univ + · simp [isZeroOrProbabilityMeasure_iff, hf] + +lemma prob_compl_lt_one_sub_of_lt_prob {p : ℝ≥0∞} (hμs : p < μ s) (s_mble : MeasurableSet s) : + μ sᶜ < 1 - p := by + rcases eq_zero_or_isProbabilityMeasure μ with rfl | h + · simp at hμs + · rw [prob_compl_eq_one_sub s_mble] + apply ENNReal.sub_lt_of_sub_lt prob_le_one (Or.inl one_ne_top) + convert hμs + exact ENNReal.sub_sub_cancel one_ne_top (lt_of_lt_of_le hμs prob_le_one).le + +lemma prob_compl_le_one_sub_of_le_prob {p : ℝ≥0∞} (hμs : p ≤ μ s) (s_mble : MeasurableSet s) : + μ sᶜ ≤ 1 - p := by + rcases eq_zero_or_isProbabilityMeasure μ with rfl | h + · simp + · simpa [prob_compl_eq_one_sub s_mble] using tsub_le_tsub_left hμs 1 + +end IsZeroOrProbabilityMeasure + section NoAtoms /-- Measure `μ` *has no atoms* if the measure of each singleton is zero. @@ -499,18 +558,17 @@ instance isFiniteMeasure_sFiniteSeq [h : SFinite μ] (n : ℕ) : IsFiniteMeasure lemma sum_sFiniteSeq (μ : Measure α) [h : SFinite μ] : sum (sFiniteSeq μ) = μ := h.1.choose_spec.2.symm +lemma sFiniteSeq_le (μ : Measure α) [SFinite μ] (n : ℕ) : sFiniteSeq μ n ≤ μ := + (le_sum _ n).trans (sum_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 _ _ /-- A countable sum of finite measures is s-finite. -This lemma is superseeded by the instance below. -/ +This lemma is superseded by the instance below. -/ lemma sfinite_sum_of_countable [Countable ι] (m : ι → Measure α) [∀ n, IsFiniteMeasure (m n)] : SFinite (Measure.sum m) := by classical @@ -536,17 +594,24 @@ instance [SFinite μ] (s : Set α) : SFinite (μ.restrict s) := by rw [← restrict_sum_of_countable, sum_sFiniteSeq]⟩ variable (μ) in -/-- An s-finite measure is absolutely continuous with respect to some finite measure. -/ -theorem exists_absolutelyContinuous_isFiniteMeasure [SFinite μ] : - ∃ ν : Measure α, IsFiniteMeasure ν ∧ μ ≪ ν := by +/-- For an s-finite measure `μ`, there exists a finite measure `ν` +such that each of `μ` and `ν` is absolutely continuous with respect to the other. +-/ +theorem exists_isFiniteMeasure_absolutelyContinuous [SFinite μ] : + ∃ ν : Measure α, IsFiniteMeasure ν ∧ μ ≪ ν ∧ ν ≪ μ := by rcases ENNReal.exists_pos_tsum_mul_lt_of_countable top_ne_zero (sFiniteSeq μ · univ) fun _ ↦ measure_ne_top _ _ with ⟨c, hc₀, hc⟩ - refine ⟨.sum fun n ↦ c n • sFiniteSeq μ n, ⟨?_⟩, ?_⟩ - · simpa [mul_comm] using hc - · refine AbsolutelyContinuous.mk fun s hsm hs ↦ ?_ - have : ∀ n, (sFiniteSeq μ n) s = 0 := by simpa [hsm, (hc₀ _).ne'] using hs - rw [← sum_sFiniteSeq μ, sum_apply _ hsm] - simp [this] + 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⟩ + simpa [mul_comm] using hc + +variable (μ) in +@[deprecated exists_isFiniteMeasure_absolutelyContinuous (since := "2024-08-25")] +theorem exists_absolutelyContinuous_isFiniteMeasure [SFinite μ] : + ∃ ν : Measure α, IsFiniteMeasure ν ∧ μ ≪ ν := + let ⟨ν, hfin, h, _⟩ := exists_isFiniteMeasure_absolutelyContinuous μ; ⟨ν, hfin, h⟩ end SFinite @@ -586,7 +651,7 @@ theorem measurable_spanningSets (μ : Measure α) [SigmaFinite μ] (i : ℕ) : theorem measure_spanningSets_lt_top (μ : Measure α) [SigmaFinite μ] (i : ℕ) : μ (spanningSets μ i) < ∞ := - measure_biUnion_lt_top (finite_le_nat i) fun j _ => (μ.toFiniteSpanningSetsIn.finite j).ne + measure_biUnion_lt_top (finite_le_nat i) fun j _ => μ.toFiniteSpanningSetsIn.finite j theorem iUnion_spanningSets (μ : Measure α) [SigmaFinite μ] : ⋃ i : ℕ, spanningSets μ i = univ := by simp_rw [spanningSets, iUnion_accumulate, μ.toFiniteSpanningSetsIn.spanning] @@ -1013,7 +1078,7 @@ instance sum.sigmaFinite {ι} [Finite ι] (μ : ι → Measure α) [∀ i, Sigma have : ∀ n, MeasurableSet (⋂ i : ι, spanningSets (μ i) n) := fun n => MeasurableSet.iInter fun i => measurable_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_iff] + · rw [sum_apply _ (this n), tsum_fintype, ENNReal.sum_lt_top] rintro i - exact (measure_mono <| iInter_subset _ i).trans_lt (measure_spanningSets_lt_top (μ i) n) · rw [iUnion_iInter_of_monotone] @@ -1033,9 +1098,18 @@ instance SMul.sigmaFinite {μ : Measure α} [SigmaFinite μ] (c : ℝ≥0) : finite := by intro i simp only [Measure.coe_smul, Pi.smul_apply, nnreal_smul_coe_apply] - exact ENNReal.mul_lt_top ENNReal.coe_ne_top (measure_spanningSets_lt_top μ i).ne + exact ENNReal.mul_lt_top ENNReal.coe_lt_top (measure_spanningSets_lt_top μ i) spanning := iUnion_spanningSets μ }⟩ +instance [SigmaFinite (μ.restrict s)] [SigmaFinite (μ.restrict t)] : + SigmaFinite (μ.restrict (s ∪ t)) := sigmaFinite_of_le _ (restrict_union_le _ _) + +instance [SigmaFinite (μ.restrict s)] : SigmaFinite (μ.restrict (s ∩ t)) := + sigmaFinite_of_le (μ.restrict s) (restrict_mono_ae (ae_of_all _ Set.inter_subset_left)) + +instance [SigmaFinite (μ.restrict t)] : SigmaFinite (μ.restrict (s ∩ t)) := + sigmaFinite_of_le (μ.restrict t) (restrict_mono_ae (ae_of_all _ Set.inter_subset_right)) + 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 @@ -1104,7 +1178,7 @@ instance isLocallyFiniteMeasureSMulNNReal [TopologicalSpace α] (μ : Measure α refine ⟨fun x => ?_⟩ rcases μ.exists_isOpen_measure_lt_top x with ⟨o, xo, o_open, μo⟩ refine ⟨o, o_open.mem_nhds xo, ?_⟩ - apply ENNReal.mul_lt_top _ μo.ne + apply ENNReal.mul_lt_top _ μo simp protected theorem Measure.isTopologicalBasis_isOpen_lt_top [TopologicalSpace α] @@ -1149,7 +1223,7 @@ theorem measure_ball_lt_top [PseudoMetricSpace α] [ProperSpace α] {μ : Measur protected theorem IsFiniteMeasureOnCompacts.smul [TopologicalSpace α] (μ : Measure α) [IsFiniteMeasureOnCompacts μ] {c : ℝ≥0∞} (hc : c ≠ ∞) : IsFiniteMeasureOnCompacts (c • μ) := - ⟨fun _K hK => ENNReal.mul_lt_top hc hK.measure_lt_top.ne⟩ + ⟨fun _K hK => ENNReal.mul_lt_top hc.lt_top hK.measure_lt_top⟩ instance IsFiniteMeasureOnCompacts.smul_nnreal [TopologicalSpace α] (μ : Measure α) [IsFiniteMeasureOnCompacts μ] (c : ℝ≥0) : IsFiniteMeasureOnCompacts (c • μ) := @@ -1466,3 +1540,5 @@ theorem measure_Ioo_lt_top : μ (Ioo a b) < ∞ := (measure_mono Ioo_subset_Icc_self).trans_lt measure_Icc_lt_top end MeasureIxx + +set_option linter.style.longFile 1700 diff --git a/Mathlib/MeasureTheory/Measure/VectorMeasure.lean b/Mathlib/MeasureTheory/Measure/VectorMeasure.lean index d9b3f84d8bdb6..50bf902e8d3cf 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,11 +90,6 @@ 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 @@ -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) @@ -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 @@ -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 _ _) @@ -1162,7 +1138,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 4697f0f82f956..4af7da3eaff23 100644 --- a/Mathlib/MeasureTheory/Measure/WithDensity.lean +++ b/Mathlib/MeasureTheory/Measure/WithDensity.lean @@ -3,6 +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, Johannes Hölzl -/ +import Mathlib.MeasureTheory.Decomposition.Exhaustion import Mathlib.MeasureTheory.Integral.Lebesgue /-! @@ -234,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⟩ @@ -270,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 := @@ -649,6 +650,17 @@ lemma sFinite_withDensity_of_measurable (μ : Measure α) [SFinite μ] SFinite (μ.withDensity f) := inferInstance +instance [SFinite μ] (c : ℝ≥0∞) : SFinite (c • μ) := by + rw [← withDensity_const] + infer_instance + +/-- If `μ ≪ ν` and `ν` is s-finite, then `μ` is s-finite. -/ +theorem sFinite_of_absolutelyContinuous {ν : Measure α} [SFinite ν] (hμν : μ ≪ ν) : + SFinite μ := by + rw [← Measure.restrict_add_restrict_compl (μ := μ) measurableSet_sigmaFiniteSetWRT, + restrict_compl_sigmaFiniteSetWRT hμν] + infer_instance + end SFinite variable [TopologicalSpace α] [OpensMeasurableSpace α] [IsLocallyFiniteMeasure μ] diff --git a/Mathlib/MeasureTheory/Measure/WithDensityFinite.lean b/Mathlib/MeasureTheory/Measure/WithDensityFinite.lean index 5452770ee04c0..5b496cf711c4d 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,26 +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.sigmaFiniteSet`: a measurable set such that `μ.restrict μ.sigmaFiniteSet` - is sigma-finite, and for all sets `s ⊆ μ.sigmaFiniteSetᶜ`, either `μ s = 0` or `μ s = ∞`. +* `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 = μ`. - -* An instance showing that `μ.restrict μ.sigmaFiniteSet` is sigma-finite. -* `restrict_compl_sigmaFiniteSet_eq_zero_or_top`: the measure `μ.restrict μ.sigmaFiniteSetᶜ` takes - only two values: 0 and ∞ . -* `measure_compl_sigmaFiniteSet_eq_zero_iff_sigmaFinite`: an s-finite measure `μ` is sigma-finite - iff `μ μ.sigmaFiniteSetᶜ = 0`. +* `ae_toFinite`: `ae μ.toFinite = ae μ`. -/ -open scoped ENNReal +open Set +open scoped ENNReal ProbabilityTheory namespace MeasureTheory @@ -53,227 +46,112 @@ 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 - -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] + μ.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_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] +instance [SFinite μ] [NeZero μ] : IsProbabilityMeasure μ.toFinite := by + apply ProbabilityTheory.cond_isProbabilityMeasure + simp [ne_eq, ← compl_mem_ae_iff, ae_toFiniteAux] -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 _ _) - -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 absolutelyContinuous_toFinite (μ : Measure α) [SFinite μ] : μ ≪ μ.toFinite := by - conv_lhs => rw [← sum_sFiniteSeq μ] - exact Measure.absolutelyContinuous_sum_left (sFiniteSeq_absolutelyContinuous_toFinite μ) + (sFiniteSeq_le μ n).absolutelyContinuous.trans (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) -section SigmaFiniteSet - -variable {s t : Set α} - -/-- A measurable set such that `μ.restrict μ.sigmaFiniteSet` is sigma-finite, - and for all measurable sets `s ⊆ μ.sigmaFiniteSetᶜ`, either `μ s = 0` or `μ s = ∞`. -/ -def Measure.sigmaFiniteSet (μ : Measure α) [SFinite μ] : Set α := {x | μ.densityToFinite x ≠ ∞} - -lemma measurableSet_sigmaFiniteSet (μ : Measure α) [SFinite μ] : - MeasurableSet μ.sigmaFiniteSet := - (measurable_densityToFinite μ (measurableSet_singleton ∞)).compl - lemma restrict_compl_sigmaFiniteSet [SFinite μ] : μ.restrict μ.sigmaFiniteSetᶜ = ∞ • μ.toFinite.restrict μ.sigmaFiniteSetᶜ := by + rw [Measure.sigmaFiniteSet, + restrict_compl_sigmaFiniteSetWRT (Measure.AbsolutelyContinuous.refl μ)] ext t ht - have : μ.restrict μ.sigmaFiniteSetᶜ - = (μ.toFinite.withDensity μ.densityToFinite).restrict μ.sigmaFiniteSetᶜ := by - rw [withDensity_densitytoFinite μ] - simp only [Measure.coe_smul, Pi.smul_apply, smul_eq_mul] - rw [this, Measure.restrict_apply ht, - withDensity_apply _ (ht.inter (measurableSet_sigmaFiniteSet μ).compl), - Measure.restrict_apply ht] - calc ∫⁻ a in t ∩ μ.sigmaFiniteSetᶜ, μ.densityToFinite a ∂μ.toFinite - _ = ∫⁻ _ in t ∩ μ.sigmaFiniteSetᶜ, ∞ ∂μ.toFinite := by - refine setLIntegral_congr_fun (ht.inter (measurableSet_sigmaFiniteSet μ).compl) - (ae_of_all _ (fun x hx ↦ ?_)) - simpa [Measure.sigmaFiniteSet] using ((Set.inter_subset_right) hx) - _ = ∞ * μ.toFinite (t ∩ μ.sigmaFiniteSetᶜ) := by simp - -/-- The measure `μ.restrict μ.sigmaFiniteSetᶜ` takes only two values: 0 and ∞ . -/ -lemma restrict_compl_sigmaFiniteSet_eq_zero_or_top (μ : Measure α) [SFinite μ] (s : Set α) : - μ.restrict μ.sigmaFiniteSetᶜ s = 0 ∨ μ.restrict μ.sigmaFiniteSetᶜ s = ∞ := by - rw [restrict_compl_sigmaFiniteSet] - simp only [Measure.coe_smul, Pi.smul_apply, smul_eq_mul, mul_eq_zero, ENNReal.top_ne_zero, - false_or] - rw [Measure.restrict_apply' (measurableSet_sigmaFiniteSet μ).compl] - by_cases h_zero : μ.toFinite (s ∩ μ.sigmaFiniteSetᶜ) = 0 - · exact Or.inl h_zero - · exact Or.inr (ENNReal.top_mul h_zero) - -lemma measure_eq_zero_or_top_of_subset_compl_sigmaFiniteSet [SFinite μ] - (ht_subset : t ⊆ μ.sigmaFiniteSetᶜ) : - μ t = 0 ∨ μ t = ∞ := by - have : μ t = μ.restrict μ.sigmaFiniteSetᶜ t := by - rw [Measure.restrict_apply' (measurableSet_sigmaFiniteSet μ).compl, - Set.inter_eq_left.mpr ht_subset] - rw [this] - exact restrict_compl_sigmaFiniteSet_eq_zero_or_top μ t - -lemma toFinite_withDensity_restrict_sigmaFiniteSet (μ : Measure α) [SFinite μ] : - (μ.toFinite.withDensity - (fun x ↦ if μ.densityToFinite x ≠ ∞ then μ.densityToFinite x else 1)).restrict - μ.sigmaFiniteSet - = μ.restrict μ.sigmaFiniteSet := by - have : μ.restrict μ.sigmaFiniteSet - = (μ.toFinite.withDensity μ.densityToFinite).restrict μ.sigmaFiniteSet := by - rw [withDensity_densitytoFinite μ] - rw [this] - ext s hs - rw [Measure.restrict_apply hs, Measure.restrict_apply hs, - withDensity_apply _ (hs.inter (measurableSet_sigmaFiniteSet μ)), - withDensity_apply _ (hs.inter (measurableSet_sigmaFiniteSet μ))] - refine setLIntegral_congr_fun (hs.inter (measurableSet_sigmaFiniteSet μ)) - (ae_of_all _ (fun x hx ↦ Eq.symm ?_)) - simp only [Measure.sigmaFiniteSet, Set.mem_inter_iff, Set.mem_compl_iff, Set.mem_setOf_eq, - ne_eq] at hx - rw [if_pos hx.2] - -/-- The restriction of an s-finite measure `μ` to `μ.sigmaFiniteSet` is sigma-finite. -/ -instance (μ : Measure α) [SFinite μ] : SigmaFinite (μ.restrict μ.sigmaFiniteSet) := by - rw [← toFinite_withDensity_restrict_sigmaFiniteSet] - have : SigmaFinite (μ.toFinite.withDensity - (fun x ↦ if μ.densityToFinite x ≠ ∞ then μ.densityToFinite x else 1)) := by - refine SigmaFinite.withDensity_of_ne_top ?_ - · refine ae_of_all _ (fun x ↦ ?_) - split_ifs with h <;> simp [h] - exact Restrict.sigmaFinite _ _ - -lemma sigmaFinite_of_measure_compl_sigmaFiniteSet_eq_zero [SFinite μ] - (h : μ μ.sigmaFiniteSetᶜ = 0) : - SigmaFinite μ := by - rw [← Measure.restrict_add_restrict_compl (μ := μ) (measurableSet_sigmaFiniteSet μ), - Measure.restrict_eq_zero.mpr h, add_zero] - infer_instance - -@[simp] -lemma measure_compl_sigmaFiniteSet (μ : Measure α) [SigmaFinite μ] : μ μ.sigmaFiniteSetᶜ = 0 := - densityToFinite_ae_ne_top μ - -/-- An s-finite measure `μ` is sigma-finite iff `μ μ.sigmaFiniteSetᶜ = 0`. -/ -lemma measure_compl_sigmaFiniteSet_eq_zero_iff_sigmaFinite (μ : Measure α) [SFinite μ] : - μ μ.sigmaFiniteSetᶜ = 0 ↔ SigmaFinite μ := - ⟨sigmaFinite_of_measure_compl_sigmaFiniteSet_eq_zero, fun _ ↦ measure_compl_sigmaFiniteSet μ⟩ - -end SigmaFiniteSet + simp only [Measure.smul_apply, smul_eq_mul] + rw [Measure.restrict_apply ht, Measure.restrict_apply ht] + by_cases hμt : μ (t ∩ (μ.sigmaFiniteSetWRT μ)ᶜ) = 0 + · rw [hμt, toFinite_absolutelyContinuous μ hμt] + · rw [ENNReal.top_mul hμt, ENNReal.top_mul] + exact fun h ↦ hμt (absolutelyContinuous_toFinite μ h) end MeasureTheory diff --git a/Mathlib/MeasureTheory/Order/UpperLower.lean b/Mathlib/MeasureTheory/Order/UpperLower.lean index 65f4ad6fa888a..6e04d112e9d58 100644 --- a/Mathlib/MeasureTheory/Order/UpperLower.lean +++ b/Mathlib/MeasureTheory/Order/UpperLower.lean @@ -64,7 +64,7 @@ private lemma aux₀ intro H obtain ⟨ε, -, hε', hε₀⟩ := exists_seq_strictAnti_tendsto_nhdsWithin (0 : ℝ) refine not_eventually.2 - (frequently_of_forall fun _ ↦ lt_irrefl $ ENNReal.ofReal $ 4⁻¹ ^ Fintype.card ι) + (Frequently.of_forall fun _ ↦ lt_irrefl <| ENNReal.ofReal <| 4⁻¹ ^ Fintype.card ι) ((Filter.Tendsto.eventually_lt (H.comp hε₀) tendsto_const_nhds ?_).mono fun n ↦ lt_of_le_of_lt ?_) on_goal 2 => @@ -72,7 +72,8 @@ private lemma aux₀ ENNReal.ofReal (4⁻¹ ^ Fintype.card ι) = volume (closedBall (f (ε n) (hε' n)) (ε n / 4)) / volume (closedBall x (ε n)) := ?_ _ ≤ volume (closure s ∩ closedBall x (ε n)) / volume (closedBall x (ε n)) := by - gcongr; exact subset_inter ((hf₁ _ $ hε' n).trans interior_subset_closure) $ hf₀ _ $ hε' n + gcongr + exact subset_inter ((hf₁ _ <| hε' n).trans interior_subset_closure) <| hf₀ _ <| hε' n have := hε' n rw [Real.volume_pi_closedBall, Real.volume_pi_closedBall, ← ENNReal.ofReal_div_of_pos, ← div_pow, mul_div_mul_left _ _ (two_ne_zero' ℝ), div_right_comm, div_self, one_div] @@ -92,14 +93,14 @@ private lemma aux₁ intro H obtain ⟨ε, -, hε', hε₀⟩ := exists_seq_strictAnti_tendsto_nhdsWithin (0 : ℝ) refine not_eventually.2 - (frequently_of_forall fun _ ↦ lt_irrefl $ 1 - ENNReal.ofReal (4⁻¹ ^ Fintype.card ι)) - ((Filter.Tendsto.eventually_lt tendsto_const_nhds (H.comp hε₀) $ + (Frequently.of_forall fun _ ↦ lt_irrefl <| 1 - ENNReal.ofReal (4⁻¹ ^ Fintype.card ι)) + ((Filter.Tendsto.eventually_lt tendsto_const_nhds (H.comp hε₀) <| ENNReal.sub_lt_self ENNReal.one_ne_top one_ne_zero ?_).mono fun n ↦ lt_of_le_of_lt' ?_) on_goal 2 => calc volume (closure s ∩ closedBall x (ε n)) / volume (closedBall x (ε n)) - ≤ volume (closedBall x (ε n) \ closedBall (f (ε n) $ hε' n) (ε n / 4)) / + ≤ volume (closedBall x (ε n) \ closedBall (f (ε n) <| hε' n) (ε n / 4)) / volume (closedBall x (ε n)) := by gcongr rw [diff_eq_compl_inter] @@ -115,7 +116,7 @@ private lemma aux₁ mul_div_mul_left _ _ (two_ne_zero' ℝ), div_right_comm, div_self, one_div] all_goals try positivity · simp_all - · measurability + · exact measurableSet_closedBall.nullMeasurableSet theorem IsUpperSet.null_frontier (hs : IsUpperSet s) : volume (frontier s) = 0 := by refine measure_mono_null (fun x hx ↦ ?_) @@ -124,9 +125,9 @@ theorem IsUpperSet.null_frontier (hs : IsUpperSet s) : volume (frontier s) = 0 : by_cases h : x ∈ closure s <;> simp only [mem_compl_iff, mem_setOf, h, not_false_eq_true, indicator_of_not_mem, indicator_of_mem, Pi.one_apply] - · refine aux₁ fun _ ↦ hs.compl.exists_subset_ball $ frontier_subset_closure ?_ + · refine aux₁ fun _ ↦ hs.compl.exists_subset_ball <| frontier_subset_closure ?_ rwa [frontier_compl] - · exact aux₀ fun _ ↦ hs.exists_subset_ball $ frontier_subset_closure hx + · exact aux₀ fun _ ↦ hs.exists_subset_ball <| frontier_subset_closure hx theorem IsLowerSet.null_frontier (hs : IsLowerSet s) : volume (frontier s) = 0 := by refine measure_mono_null (fun x hx ↦ ?_) @@ -135,13 +136,13 @@ theorem IsLowerSet.null_frontier (hs : IsLowerSet s) : volume (frontier s) = 0 : by_cases h : x ∈ closure s <;> simp only [mem_compl_iff, mem_setOf, h, not_false_eq_true, indicator_of_not_mem, indicator_of_mem, Pi.one_apply] - · refine aux₁ fun _ ↦ hs.compl.exists_subset_ball $ frontier_subset_closure ?_ + · refine aux₁ fun _ ↦ hs.compl.exists_subset_ball <| frontier_subset_closure ?_ rwa [frontier_compl] - · exact aux₀ fun _ ↦ hs.exists_subset_ball $ frontier_subset_closure hx + · exact aux₀ fun _ ↦ hs.exists_subset_ball <| frontier_subset_closure hx theorem Set.OrdConnected.null_frontier (hs : s.OrdConnected) : volume (frontier s) = 0 := by rw [← hs.upperClosure_inter_lowerClosure] - exact measure_mono_null (frontier_inter_subset _ _) $ measure_union_null + exact measure_mono_null (frontier_inter_subset _ _) <| measure_union_null (measure_inter_null_of_null_left _ (UpperSet.upper _).null_frontier) (measure_inter_null_of_null_right _ (LowerSet.lower _).null_frontier) diff --git a/Mathlib/MeasureTheory/OuterMeasure/AE.lean b/Mathlib/MeasureTheory/OuterMeasure/AE.lean index ba7bd3fa9d612..bf766c468a301 100644 --- a/Mathlib/MeasureTheory/OuterMeasure/AE.lean +++ b/Mathlib/MeasureTheory/OuterMeasure/AE.lean @@ -85,7 +85,7 @@ theorem measure_zero_iff_ae_nmem {s : Set α} : μ s = 0 ↔ ∀ᵐ a ∂μ, a compl_mem_ae_iff.symm theorem ae_of_all {p : α → Prop} (μ : F) : (∀ a, p a) → ∀ᵐ a ∂μ, p a := - eventually_of_forall + Eventually.of_forall instance instCountableInterFilter : CountableInterFilter (ae μ) := by unfold ae; infer_instance @@ -106,8 +106,9 @@ theorem ae_ball_iff {ι : Type*} {S : Set ι} (hS : S.Countable) {p : α → ∀ (∀ᵐ x ∂μ, ∀ i (hi : i ∈ S), p x i hi) ↔ ∀ i (hi : i ∈ S), ∀ᵐ x ∂μ, p x i hi := eventually_countable_ball hS -theorem ae_eq_refl (f : α → β) : f =ᵐ[μ] f := - EventuallyEq.rfl +lemma ae_eq_refl (f : α → β) : f =ᵐ[μ] f := EventuallyEq.rfl +lemma ae_eq_rfl {f : α → β} : f =ᵐ[μ] f := EventuallyEq.rfl +lemma ae_eq_comm {f g : α → β} : f =ᵐ[μ] g ↔ g =ᵐ[μ] f := eventuallyEq_comm theorem ae_eq_symm {f g : α → β} (h : f =ᵐ[μ] g) : g =ᵐ[μ] f := h.symm @@ -115,6 +116,15 @@ theorem ae_eq_symm {f g : α → β} (h : f =ᵐ[μ] g) : g =ᵐ[μ] f := theorem ae_eq_trans {f g h : α → β} (h₁ : f =ᵐ[μ] g) (h₂ : g =ᵐ[μ] h) : f =ᵐ[μ] h := h₁.trans h₂ +@[simp] lemma ae_eq_top : ae μ = ⊤ ↔ ∀ a, μ {a} ≠ 0 := by + simp only [Filter.ext_iff, mem_ae_iff, mem_top, ne_eq] + refine ⟨fun h a ha ↦ by simpa [ha] using (h {a}ᶜ).1, fun h s ↦ ⟨fun hs ↦ ?_, ?_⟩⟩ + · rw [← compl_empty_iff, ← not_nonempty_iff_eq_empty] + rintro ⟨a, ha⟩ + exact h _ <| measure_mono_null (singleton_subset_iff.2 ha) hs + · rintro rfl + simp + theorem ae_le_of_ae_lt {β : Type*} [Preorder β] {f g : α → β} (h : ∀ᵐ x ∂μ, f x < g x) : f ≤ᵐ[μ] g := h.mono fun _ ↦ le_of_lt diff --git a/Mathlib/MeasureTheory/OuterMeasure/BorelCantelli.lean b/Mathlib/MeasureTheory/OuterMeasure/BorelCantelli.lean new file mode 100644 index 0000000000000..e3e8075a43882 --- /dev/null +++ b/Mathlib/MeasureTheory/OuterMeasure/BorelCantelli.lean @@ -0,0 +1,113 @@ +/- +Copyright (c) 2020 Markus Himmel. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Markus Himmel, Yury Kudryashov +-/ +import Mathlib.MeasureTheory.OuterMeasure.AE + +/-! +# Borel-Cantelli lemma, part 1 + +In this file we show one implication of the **Borel-Cantelli lemma**: +if `s i` is a countable family of sets such that `∑' i, μ (s i)` is finite, +then a.e. all points belong to finitely many sets of the family. + +We prove several versions of this lemma: + +- `MeasureTheory.ae_finite_setOf_mem`: as stated above; +- `MeasureTheory.measure_limsup_cofinite_eq_zero`: + in terms of `Filter.limsup` along `Filter.cofinite`; +- `MeasureTheory.measure_limsup_atTop_eq_zero`: + in terms of `Filter.limsup` along `(Filter.atTop : Filter ℕ)`. + +For the *second* Borel-Cantelli lemma (applying to independent sets in a probability space), +see `ProbabilityTheory.measure_limsup_eq_one`. +-/ + +open Filter Set +open scoped ENNReal Topology + +namespace MeasureTheory + +variable {α ι F : Type*} [FunLike F (Set α) ℝ≥0∞] [OuterMeasureClass F α] [Countable ι] {μ : F} + +/-- One direction of the **Borel-Cantelli lemma** +(sometimes called the "*first* Borel-Cantelli lemma"): +if `(s i)` is a countable family of sets such that `∑' i, μ (s i)` is finite, +then the limit superior of the `s i` along the cofinite filter is a null set. + +Note: for the *second* Borel-Cantelli lemma (applying to independent sets in a probability space), +see `ProbabilityTheory.measure_limsup_eq_one`. -/ +theorem measure_limsup_cofinite_eq_zero {s : ι → Set α} (hs : ∑' i, μ (s i) ≠ ∞) : + μ (limsup s cofinite) = 0 := by + refine bot_unique <| ge_of_tendsto' (ENNReal.tendsto_tsum_compl_atTop_zero hs) fun t ↦ ?_ + calc + μ (limsup s cofinite) ≤ μ (⋃ i : {i // i ∉ t}, s i) := by + gcongr + rw [hasBasis_cofinite.limsup_eq_iInf_iSup, iUnion_subtype] + exact iInter₂_subset _ t.finite_toSet + _ ≤ ∑' i : {i // i ∉ t}, μ (s i) := measure_iUnion_le _ + +/-- One direction of the **Borel-Cantelli lemma** +(sometimes called the "*first* Borel-Cantelli lemma"): +if `(s i)` is a sequence of sets such that `∑' i, μ (s i)` is finite, +then the limit superior of the `s i` along the `atTop` filter is a null set. + +Note: for the *second* Borel-Cantelli lemma (applying to independent sets in a probability space), +see `ProbabilityTheory.measure_limsup_eq_one`. -/ +theorem measure_limsup_atTop_eq_zero {s : ℕ → Set α} (hs : ∑' i, μ (s i) ≠ ∞) : + μ (limsup s atTop) = 0 := by + rw [← Nat.cofinite_eq_atTop, measure_limsup_cofinite_eq_zero hs] + +@[deprecated (since := "2024-09-01")] +alias measure_limsup_eq_zero := measure_limsup_atTop_eq_zero + +/-- One direction of the **Borel-Cantelli lemma** +(sometimes called the "*first* Borel-Cantelli lemma"): +if `(s i)` is a countable family of sets such that `∑' i, μ (s i)` is finite, +then a.e. all points belong to finitely sets of the family. -/ +theorem ae_finite_setOf_mem {s : ι → Set α} (h : ∑' i, μ (s i) ≠ ∞) : + ∀ᵐ x ∂μ, {i | x ∈ s i}.Finite := by + rw [ae_iff, ← measure_limsup_cofinite_eq_zero h] + congr 1 with x + simp [mem_limsup_iff_frequently_mem, Filter.Frequently] + +/-- A version of the **Borel-Cantelli lemma**: if `pᵢ` is a sequence of predicates such that +`∑' i, μ {x | pᵢ x}` is finite, then the measure of `x` such that `pᵢ x` holds frequently as `i → ∞` +(or equivalently, `pᵢ x` holds for infinitely many `i`) is equal to zero. -/ +theorem measure_setOf_frequently_eq_zero {p : ℕ → α → Prop} (hp : ∑' i, μ { x | p i x } ≠ ∞) : + μ { x | ∃ᶠ n in atTop, p n x } = 0 := by + simpa only [limsup_eq_iInf_iSup_of_nat, frequently_atTop, ← bex_def, setOf_forall, + setOf_exists] using measure_limsup_atTop_eq_zero hp + +/-- A version of the **Borel-Cantelli lemma**: if `sᵢ` is a sequence of sets such that +`∑' i, μ sᵢ` is finite, then for almost all `x`, `x` does not belong to `sᵢ` for large `i`. -/ +theorem ae_eventually_not_mem {s : ℕ → Set α} (hs : (∑' i, μ (s i)) ≠ ∞) : + ∀ᵐ x ∂μ, ∀ᶠ n in atTop, x ∉ s n := + measure_setOf_frequently_eq_zero hs + +theorem measure_liminf_cofinite_eq_zero [Infinite ι] {s : ι → Set α} (h : ∑' i, μ (s i) ≠ ∞) : + μ (liminf s cofinite) = 0 := by + rw [← le_zero_iff, ← measure_limsup_cofinite_eq_zero h] + exact measure_mono liminf_le_limsup + +theorem measure_liminf_atTop_eq_zero {s : ℕ → Set α} (h : (∑' i, μ (s i)) ≠ ∞) : + μ (liminf s atTop) = 0 := by + rw [← Nat.cofinite_eq_atTop, measure_liminf_cofinite_eq_zero h] + +-- TODO: the next 2 lemmas are true for any filter with countable intersections, not only `ae`. +-- Need to specify `α := Set α` below because of diamond; see #19041 +theorem limsup_ae_eq_of_forall_ae_eq (s : ℕ → Set α) {t : Set α} + (h : ∀ n, s n =ᵐ[μ] t) : limsup (α := Set α) s atTop =ᵐ[μ] t := by + simp only [eventuallyEq_set, ← eventually_countable_forall] at h + refine eventuallyEq_set.2 <| h.mono fun x hx ↦ ?_ + simp [mem_limsup_iff_frequently_mem, hx] + +-- Need to specify `α := Set α` above because of diamond; see #19041 +theorem liminf_ae_eq_of_forall_ae_eq (s : ℕ → Set α) {t : Set α} + (h : ∀ n, s n =ᵐ[μ] t) : liminf (α := Set α) s atTop =ᵐ[μ] t := by + simp only [eventuallyEq_set, ← eventually_countable_forall] at h + refine eventuallyEq_set.2 <| h.mono fun x hx ↦ ?_ + simp only [mem_liminf_iff_eventually_mem, hx, eventually_const] + +end MeasureTheory diff --git a/Mathlib/MeasureTheory/OuterMeasure/Caratheodory.lean b/Mathlib/MeasureTheory/OuterMeasure/Caratheodory.lean index 706d7e9a7b206..167ea1437b67c 100644 --- a/Mathlib/MeasureTheory/OuterMeasure/Caratheodory.lean +++ b/Mathlib/MeasureTheory/OuterMeasure/Caratheodory.lean @@ -89,6 +89,21 @@ theorem isCaratheodory_inter (h₁ : IsCaratheodory m s₁) (h₂ : IsCaratheodo rw [← isCaratheodory_compl_iff, Set.compl_inter] exact isCaratheodory_union _ (isCaratheodory_compl _ h₁) (isCaratheodory_compl _ h₂) +lemma isCaratheodory_diff (h₁ : IsCaratheodory m s₁) (h₂ : IsCaratheodory m s₂) : + IsCaratheodory m (s₁ \ s₂) := m.isCaratheodory_inter h₁ (m.isCaratheodory_compl h₂) + +lemma isCaratheodory_partialSups {s : ℕ → Set α} (h : ∀ i, m.IsCaratheodory (s i)) (i : ℕ) : + m.IsCaratheodory (partialSups s i) := by + induction i with + | zero => exact h 0 + | succ i hi => exact m.isCaratheodory_union hi (h (i + 1)) + +lemma isCaratheodory_disjointed {s : ℕ → Set α} (h : ∀ i, m.IsCaratheodory (s i)) (i : ℕ) : + m.IsCaratheodory (disjointed s i) := by + induction i with + | zero => exact h 0 + | succ i _ => exact m.isCaratheodory_diff (h (i + 1)) (m.isCaratheodory_partialSups h i) + theorem isCaratheodory_sum {s : ℕ → Set α} (h : ∀ i, IsCaratheodory m (s i)) (hd : Pairwise (Disjoint on s)) {t : Set α} : ∀ {n}, (∑ i ∈ Finset.range n, m (t ∩ s i)) = m (t ∩ ⋃ i < n, s i) @@ -99,13 +114,13 @@ theorem isCaratheodory_sum {s : ℕ → Set α} (h : ∀ i, IsCaratheodory m (s intro a simpa using fun (h₁ : a ∈ s n) i (hi : i < n) h₂ => (hd (ne_of_gt hi)).le_bot ⟨h₁, h₂⟩ -set_option linter.deprecated false in -- not immediately obvious how to replace `iUnion` here. -theorem isCaratheodory_iUnion_nat {s : ℕ → Set α} (h : ∀ i, IsCaratheodory m (s i)) +/-- Use `isCaratheodory_iUnion` instead, which does not require the disjoint assumption. -/ +theorem isCaratheodory_iUnion_of_disjoint {s : ℕ → Set α} (h : ∀ i, IsCaratheodory m (s i)) (hd : Pairwise (Disjoint on s)) : IsCaratheodory m (⋃ i, s i) := by apply (isCaratheodory_iff_le' m).mpr intro t have hp : m (t ∩ ⋃ i, s i) ≤ ⨆ n, m (t ∩ ⋃ i < n, s i) := by - convert m.iUnion fun i => t ∩ s i using 1 + convert measure_iUnion_le (μ := m) fun i => t ∩ s i using 1 · simp [inter_iUnion] · simp [ENNReal.tsum_eq_iSup_nat, isCaratheodory_sum m h hd] refine le_trans (add_le_add_right hp _) ?_ @@ -115,6 +130,15 @@ theorem isCaratheodory_iUnion_nat {s : ℕ → Set α} (h : ∀ i, IsCaratheodor refine m.mono (diff_subset_diff_right ?_) exact iUnion₂_subset fun i _ => subset_iUnion _ i +@[deprecated (since := "2024-07-29")] +alias isCaratheodory_iUnion_nat := isCaratheodory_iUnion_of_disjoint + +lemma isCaratheodory_iUnion {s : ℕ → Set α} (h : ∀ i, m.IsCaratheodory (s i)) : + m.IsCaratheodory (⋃ i, s i) := by + rw [← iUnion_disjointed] + exact m.isCaratheodory_iUnion_of_disjoint (m.isCaratheodory_disjointed h) + (disjoint_disjointed _) + theorem f_iUnion {s : ℕ → Set α} (h : ∀ i, IsCaratheodory m (s i)) (hd : Pairwise (Disjoint on s)) : m (⋃ i, s i) = ∑' i, m (s i) := by refine le_antisymm (measure_iUnion_le s) ?_ @@ -124,12 +148,12 @@ theorem f_iUnion {s : ℕ → Set α} (h : ∀ i, IsCaratheodory m (s i)) (hd : simp only [inter_comm, inter_univ, univ_inter] at this; simp only [this] exact m.mono (iUnion₂_subset fun i _ => subset_iUnion _ i) -/-- The Carathéodory-measurable sets for an outer measure `m` form a Dynkin system. -/ +/-- The Carathéodory-measurable sets for an outer measure `m` form a Dynkin system. -/ def caratheodoryDynkin : MeasurableSpace.DynkinSystem α where Has := IsCaratheodory m has_empty := isCaratheodory_empty m has_compl s := isCaratheodory_compl m s - has_iUnion_nat f hf hn := by apply isCaratheodory_iUnion_nat m hf f + has_iUnion_nat _ hf hn := by apply isCaratheodory_iUnion m hf /-- Given an outer measure `μ`, the Carathéodory-measurable space is defined such that `s` is measurable if `∀t, μ t = μ (t ∩ s) + μ (t \ s)`. -/ diff --git a/Mathlib/MeasureTheory/OuterMeasure/Induced.lean b/Mathlib/MeasureTheory/OuterMeasure/Induced.lean index b1dd27d6be85b..d28e4da40ac3e 100644 --- a/Mathlib/MeasureTheory/OuterMeasure/Induced.lean +++ b/Mathlib/MeasureTheory/OuterMeasure/Induced.lean @@ -409,7 +409,7 @@ and `m₃ s`. -/ theorem trim_binop {m₁ m₂ m₃ : OuterMeasure α} {op : ℝ≥0∞ → ℝ≥0∞ → ℝ≥0∞} (h : ∀ s, m₁ s = op (m₂ s) (m₃ s)) (s : Set α) : m₁.trim s = op (m₂.trim s) (m₃.trim s) := by rcases exists_measurable_superset_forall_eq_trim ![m₁, m₂, m₃] s with ⟨t, _hst, _ht, htm⟩ - simp only [Fin.forall_fin_succ, Matrix.cons_val_zero, Matrix.cons_val_succ] at htm + simp only [Fin.forall_iff_succ, Matrix.cons_val_zero, Matrix.cons_val_succ] at htm rw [← htm.1, ← htm.2.1, ← htm.2.2.1, h] /-- If `m₁ s = op (m₂ s)` for all `s`, then the same is true for `m₁.trim` and `m₂.trim`. -/ diff --git a/Mathlib/MeasureTheory/OuterMeasure/OfFunction.lean b/Mathlib/MeasureTheory/OuterMeasure/OfFunction.lean index 9bdbbdf07b9ed..7e859de1147fc 100644 --- a/Mathlib/MeasureTheory/OuterMeasure/OfFunction.lean +++ b/Mathlib/MeasureTheory/OuterMeasure/OfFunction.lean @@ -46,11 +46,11 @@ section OfFunction -- Porting note: "set_option eqn_compiler.zeta true" removed -variable {α : Type*} (m : Set α → ℝ≥0∞) (m_empty : m ∅ = 0) +variable {α : Type*} -/-- Given any function `m` assigning measures to sets satisying `m ∅ = 0`, there is +/-- Given any function `m` assigning measures to sets satisfying `m ∅ = 0`, there is a unique maximal outer measure `μ` satisfying `μ s ≤ m s` for all `s : Set α`. -/ -protected def ofFunction : OuterMeasure α := +protected def ofFunction (m : Set α → ℝ≥0∞) (m_empty : m ∅ = 0) : OuterMeasure α := let μ s := ⨅ (f : ℕ → Set α) (_ : s ⊆ ⋃ i, f i), ∑' i, m (f i) { measureOf := μ empty := @@ -86,10 +86,35 @@ protected def ofFunction : OuterMeasure α := intro j apply subset_iUnion₂ i } +variable (m : Set α → ℝ≥0∞) (m_empty : m ∅ = 0) + +/-- `ofFunction` of a set `s` is the infimum of `∑ᵢ, m (tᵢ)` for all collections of sets +`tᵢ` that cover `s`. -/ theorem ofFunction_apply (s : Set α) : OuterMeasure.ofFunction m m_empty s = ⨅ (t : ℕ → Set α) (_ : s ⊆ iUnion t), ∑' n, m (t n) := rfl +/-- `ofFunction` of a set `s` is the infimum of `∑ᵢ, m (tᵢ)` for all collections of sets +`tᵢ` that cover `s`, with all `tᵢ` satisfying a predicate `P` such that `m` is infinite for sets +that don't satisfy `P`. +This is similar to `ofFunction_apply`, except that the sets `tᵢ` satisfy `P`. +The hypothesis `m_top` applies in particular to a function of the form `extend m'`. -/ +theorem ofFunction_eq_iInf_mem {P : Set α → Prop} (m_top : ∀ s, ¬ P s → m s = ∞) (s : Set α) : + OuterMeasure.ofFunction m m_empty s = + ⨅ (t : ℕ → Set α) (_ : ∀ i, P (t i)) (_ : s ⊆ ⋃ i, t i), ∑' i, m (t i) := by + rw [OuterMeasure.ofFunction_apply] + apply le_antisymm + · exact le_iInf fun t ↦ le_iInf fun _ ↦ le_iInf fun h ↦ iInf₂_le _ (by exact h) + · simp_rw [le_iInf_iff] + refine fun t ht_subset ↦ iInf_le_of_le t ?_ + by_cases ht : ∀ i, P (t i) + · exact iInf_le_of_le ht (iInf_le_of_le ht_subset le_rfl) + · simp only [ht, not_false_eq_true, iInf_neg, top_le_iff] + push_neg at ht + obtain ⟨i, hti_not_mem⟩ := ht + have hfi_top : m (t i) = ∞ := m_top _ hti_not_mem + exact ENNReal.tsum_eq_top_of_eq_top ⟨i, hfi_top⟩ + variable {m m_empty} theorem ofFunction_le (s : Set α) : OuterMeasure.ofFunction m m_empty s ≤ m s := @@ -126,7 +151,7 @@ theorem ofFunction_eq_sSup : OuterMeasure.ofFunction m m_empty = sSup { μ | ∀ E.g., if `α` is an (e)metric space and `m u = ∞` on any set of diameter `≥ r`, then this lemma implies that `μ (s ∪ t) = μ s + μ t` on any two sets such that `r ≤ edist x y` for all `x ∈ s` -and `y ∈ t`. -/ +and `y ∈ t`. -/ theorem ofFunction_union_of_top_of_nonempty_inter {s t : Set α} (h : ∀ u, (s ∩ u).Nonempty → (t ∩ u).Nonempty → m u = ∞) : OuterMeasure.ofFunction m m_empty (s ∪ t) = @@ -207,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 @@ -289,7 +314,7 @@ theorem comap_boundedBy {β} (f : β → α) E.g., if `α` is an (e)metric space and `m u = ∞` on any set of diameter `≥ r`, then this lemma implies that `μ (s ∪ t) = μ s + μ t` on any two sets such that `r ≤ edist x y` for all `x ∈ s` -and `y ∈ t`. -/ +and `y ∈ t`. -/ theorem boundedBy_union_of_top_of_nonempty_inter {s t : Set α} (h : ∀ u, (s ∩ u).Nonempty → (t ∩ u).Nonempty → m u = ∞) : boundedBy m (s ∪ t) = boundedBy m s + boundedBy m t := diff --git a/Mathlib/MeasureTheory/PiSystem.lean b/Mathlib/MeasureTheory/PiSystem.lean index f00e51c4094e7..aed108095fc15 100644 --- a/Mathlib/MeasureTheory/PiSystem.lean +++ b/Mathlib/MeasureTheory/PiSystem.lean @@ -207,25 +207,25 @@ theorem subset_generatePiSystem_self {α} (S : Set (Set α)) : S ⊆ generatePiS theorem generatePiSystem_subset_self {α} {S : Set (Set α)} (h_S : IsPiSystem S) : generatePiSystem S ⊆ S := fun x h => by - induction' h with _ h_s s u _ _ h_nonempty h_s h_u - · exact h_s - · exact h_S _ h_s _ h_u h_nonempty + 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 := Set.Subset.antisymm (generatePiSystem_subset_self h_pi) (subset_generatePiSystem_self S) theorem generatePiSystem_mono {α} {S T : Set (Set α)} (hST : S ⊆ T) : generatePiSystem S ⊆ generatePiSystem T := fun t ht => by - induction' ht with s h_s s u _ _ h_nonempty h_s h_u - · exact generatePiSystem.base (Set.mem_of_subset_of_mem hST h_s) - · exact isPiSystem_generatePiSystem T _ h_s _ h_u h_nonempty + 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 α)} (h_meas_S : ∀ s ∈ S, MeasurableSet s) (t : Set α) (h_in_pi : t ∈ generatePiSystem S) : MeasurableSet t := by - induction' h_in_pi with s h_s s u _ _ _ h_s h_u - · apply h_meas_S _ h_s - · apply MeasurableSet.inter h_s h_u + 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 α) (ht : t ∈ generatePiSystem g) : MeasurableSet[generateFrom g] t := @@ -260,8 +260,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 +337,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 +349,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 ι) : diff --git a/Mathlib/MeasureTheory/SetSemiring.lean b/Mathlib/MeasureTheory/SetSemiring.lean index 4b0455aed5556..0727d10d8f8f5 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 @@ -313,13 +313,25 @@ lemma biInter_mem {ι : Type*} (hC : IsSetRing C) {s : ι → Set α} (S : Finset ι) (hS : S.Nonempty) (hs : ∀ n ∈ S, s n ∈ C) : ⋂ i ∈ S, s i ∈ C := by classical - induction' hS using Finset.Nonempty.cons_induction with _ i S hiS _ h hs - · simpa using hs - · simp_rw [← Finset.mem_coe, Finset.coe_cons, Set.biInter_insert] + induction hS using Finset.Nonempty.cons_induction with + | singleton => simpa using hs + | cons i S hiS _ h => + simp_rw [← Finset.mem_coe, Finset.coe_cons, Set.biInter_insert] simp only [cons_eq_insert, Finset.mem_insert, forall_eq_or_imp] at hs refine hC.inter_mem hs.1 ?_ exact h (fun n hnS ↦ hs.2 n hnS) +lemma partialSups_mem (hC : IsSetRing C) {s : ℕ → Set α} (hs : ∀ n, s n ∈ C) (n : ℕ) : + partialSups s n ∈ C := by + rw [partialSups_eq_biUnion_range] + exact hC.biUnion_mem _ (fun n _ ↦ hs n) + +lemma disjointed_mem (hC : IsSetRing C) {s : ℕ → Set α} (hs : ∀ n, s n ∈ C) (n : ℕ) : + disjointed s n ∈ C := by + cases n with + | zero => exact hs 0 + | succ n => exact hC.diff_mem (hs n.succ) (hC.partialSups_mem hs n) + end IsSetRing end MeasureTheory diff --git a/Mathlib/ModelTheory/Algebra/Field/IsAlgClosed.lean b/Mathlib/ModelTheory/Algebra/Field/IsAlgClosed.lean new file mode 100644 index 0000000000000..2d7efbda8ea35 --- /dev/null +++ b/Mathlib/ModelTheory/Algebra/Field/IsAlgClosed.lean @@ -0,0 +1,252 @@ +/- +Copyright (c) 2023 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes +-/ + +import Mathlib.Data.Nat.PrimeFin +import Mathlib.FieldTheory.IsAlgClosed.AlgebraicClosure +import Mathlib.FieldTheory.IsAlgClosed.Classification +import Mathlib.ModelTheory.Algebra.Field.CharP +import Mathlib.ModelTheory.Satisfiability + +/-! + +# The First Order Theory of Algebraically Closed Fields + +This file defines the theory of algebraically closed fields of characteristic `p`, as well +as proving completeness of the theory and the Lefschetz Principle. + +## Main definitions + +* `FirstOrder.Language.Theory.ACF p` : the theory of algebraically closed fields of characteristic + `p` as a theory over the language of rings. +* `FirstOrder.Field.ACF_isComplete` : the theory of algebraically closed fields of characteristic + `p` is complete whenever `p` is prime or zero. +* `FirstOrder.Field.ACF_zero_realize_iff_infinite_ACF_prime_realize` : the Lefschetz principle. + +## Implementation details + +To apply a theorem about the model theory of algebraically closed fields to a specific +algebraically closed field `K` which does not have a `Language.ring.Structure` instance, +you must introduce the local instance `compatibleRingOfRing K`. Theorems whose statement requires +both a `Language.ring.Structure` instance and a `Field` instance will all be stated with the +assumption `Field K`, `CharP K p`, `IsAlgClosed K` and `CompatibleRing K` and there are instances +defined saying that these assumptions imply `Theory.field.Model K` and `(Theory.ACF p).Model K` + +## References + +The first order theory of algebraically closed fields, along with the Lefschetz Principle and +the Ax-Grothendieck Theorem were first formalized in Lean 3 by Joseph Hua +[here](https://github.com/Jlh18/ModelTheoryInLean8) with the master's thesis +[here](https://github.com/Jlh18/ModelTheory8Report) + +-/ + +variable {K : Type*} + +namespace FirstOrder + +namespace Field + +open Ring FreeCommRing BigOperators 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 +of the `n` non-leading coefficients of the polynomial and one variable (`Fin.last n`) +for `X`. -/ +def genericMonicPoly (n : ℕ) : FreeCommRing (Fin (n + 1)) := + of (Fin.last _) ^ n + ∑ i : Fin n, of i.castSucc * of (Fin.last _) ^ (i : ℕ) + +theorem lift_genericMonicPoly [CommRing K] [Nontrivial K] {n : ℕ} (v : Fin (n+1) → K) : + FreeCommRing.lift v (genericMonicPoly n) = + (((monicEquivDegreeLT n).trans (degreeLTEquiv K n).toEquiv).symm (v ∘ Fin.castSucc)).1.eval + (v (Fin.last _)) := by + simp only [genericMonicPoly, map_add, map_pow, lift_of, map_sum, map_mul, monicEquivDegreeLT, + degreeLTEquiv, Equiv.symm_trans_apply, LinearEquiv.coe_toEquiv_symm, EquivLike.coe_coe, + LinearEquiv.coe_symm_mk, Function.comp_apply, Equiv.coe_fn_symm_mk, eval_add, eval_pow, eval_X, + eval_finset_sum, eval_monomial] + +/-- A sentence saying every monic polynomial of degree `n` has a root. -/ +noncomputable def genericMonicPolyHasRoot (n : ℕ) : Language.ring.Sentence := + (∃' ((termOfFreeCommRing (genericMonicPoly n)).relabel Sum.inr =' 0)).alls + +theorem realize_genericMonicPolyHasRoot [Field K] [CompatibleRing K] (n : ℕ) : + K ⊨ genericMonicPolyHasRoot n ↔ + ∀ p : { p : K[X] // p.Monic ∧ p.natDegree = n }, ∃ x, p.1.eval x = 0 := by + let _ := Classical.decEq K + rw [Equiv.forall_congr_left ((monicEquivDegreeLT n).trans (degreeLTEquiv K n).toEquiv)] + simp [Sentence.Realize, genericMonicPolyHasRoot, lift_genericMonicPoly] + +/-- The theory of algebraically closed fields of characteristic `p` as a theory over +the language of rings -/ +def _root_.FirstOrder.Language.Theory.ACF (p : ℕ) : Theory .ring := + Theory.fieldOfChar p ∪ genericMonicPolyHasRoot '' {n | 0 < n} + +instance [Language.ring.Structure K] (p : ℕ) [h : (Theory.ACF p).Model K] : + (Theory.fieldOfChar p).Model K := + Theory.Model.mono h Set.subset_union_left + +instance [Field K] [CompatibleRing K] {p : ℕ} [CharP K p] [IsAlgClosed K] : + (Theory.ACF p).Model K := by + refine Theory.model_union_iff.2 ⟨inferInstance, ?_⟩ + simp only [Theory.model_iff, Set.mem_image, Set.mem_singleton_iff, + exists_prop, forall_exists_index, and_imp] + rintro _ n hn0 rfl + simp only [realize_genericMonicPolyHasRoot] + rintro ⟨p, _, rfl⟩ + exact IsAlgClosed.exists_root p (ne_of_gt + (natDegree_pos_iff_degree_pos.1 hn0)) + +theorem modelField_of_modelACF (p : ℕ) (K : Type*) [Language.ring.Structure K] + [h : (Theory.ACF p).Model K] : Theory.field.Model K := + Theory.Model.mono h (Set.subset_union_of_subset_left Set.subset_union_left _) + +/-- A model for the Theory of algebraically closed fields is a Field. After introducing +this as a local instance on a particular Type, you should usually also introduce +`modelField_of_modelACF p M`, `compatibleRingOfModelField` and `isAlgClosed_of_model_ACF` -/ +@[reducible] +noncomputable def fieldOfModelACF (p : ℕ) (K : Type*) + [Language.ring.Structure K] + [h : (Theory.ACF p).Model K] : Field K := by + have := modelField_of_modelACF p K + exact fieldOfModelField K + +theorem isAlgClosed_of_model_ACF (p : ℕ) (K : Type*) + [Field K] [CompatibleRing K] [h : (Theory.ACF p).Model K] : + IsAlgClosed K := by + refine IsAlgClosed.of_exists_root _ ?_ + intro p hpm hpi + have h : K ⊨ genericMonicPolyHasRoot '' {n | 0 < n} := + Theory.Model.mono h (by simp [Theory.ACF]) + simp only [Theory.model_iff, Set.mem_image, Set.mem_singleton_iff, + exists_prop, forall_exists_index, and_imp] at h + have := h _ p.natDegree (natDegree_pos_iff_degree_pos.2 + (degree_pos_of_irreducible hpi)) rfl + rw [realize_genericMonicPolyHasRoot] at this + exact this ⟨_, hpm, rfl⟩ + +theorem ACF_isSatisfiable {p : ℕ} (hp : p.Prime ∨ p = 0) : + (Theory.ACF p).IsSatisfiable := by + cases hp with + | inl hp => + have : Fact p.Prime := ⟨hp⟩ + let _ := compatibleRingOfRing (AlgebraicClosure (ZMod p)) + have : CharP (AlgebraicClosure (ZMod p)) p := + charP_of_injective_algebraMap + (RingHom.injective (algebraMap (ZMod p) (AlgebraicClosure (ZMod p)))) p + exact ⟨⟨AlgebraicClosure (ZMod p)⟩⟩ + | inr hp => + subst hp + let _ := compatibleRingOfRing (AlgebraicClosure ℚ) + have : CharP (AlgebraicClosure ℚ) 0 := + charP_of_injective_algebraMap + (RingHom.injective (algebraMap ℚ (AlgebraicClosure ℚ))) 0 + exact ⟨⟨AlgebraicClosure ℚ⟩⟩ + +open Cardinal + +/-- The Theory `Theory.ACF p` is `κ`-categorical whenever `κ` is an uncountable cardinal. +At the moment this is not as universe polymorphic as it could be, +it currently requires `κ : Cardinal.{0}`, but it is true for any universe. -/ +theorem ACF_categorical {p : ℕ} (κ : Cardinal.{0}) (hκ : ℵ₀ < κ) : + Categorical κ (Theory.ACF p) := by + rintro ⟨M⟩ ⟨N⟩ hM hN + let _ := fieldOfModelACF p M + have := modelField_of_modelACF p M + let _ := compatibleRingOfModelField M + have := isAlgClosed_of_model_ACF p M + have := charP_of_model_fieldOfChar p M + let _ := fieldOfModelACF p N + have := modelField_of_modelACF p N + let _ := compatibleRingOfModelField N + have := isAlgClosed_of_model_ACF p N + have := charP_of_model_fieldOfChar p N + constructor + refine languageEquivEquivRingEquiv.symm ?_ + apply Classical.choice + refine IsAlgClosed.ringEquivOfCardinalEqOfCharEq p ?_ ?_ + · rw [hM]; exact hκ + · rw [hM, hN] + +theorem ACF_isComplete {p : ℕ} (hp : p.Prime ∨ p = 0) : + (Theory.ACF p).IsComplete := by + apply Categorical.isComplete.{0, 0, 0} (Order.succ ℵ₀) _ + (ACF_categorical _ (Order.lt_succ _)) + (Order.le_succ ℵ₀) + · simp only [card_ring, lift_id'] + exact le_trans (le_of_lt (lt_aleph0_of_finite _)) (Order.le_succ _) + · exact ACF_isSatisfiable hp + · rintro ⟨M⟩ + let _ := fieldOfModelACF p M + have := modelField_of_modelACF p M + let _ := compatibleRingOfModelField M + have := isAlgClosed_of_model_ACF p M + infer_instance + +theorem finite_ACF_prime_not_realize_of_ACF_zero_realize + (φ : Language.ring.Sentence) (h : Theory.ACF 0 ⊨ᵇ φ) : + Set.Finite { p : Nat.Primes | ¬ Theory.ACF p ⊨ᵇ φ } := by + rw [Theory.models_iff_finset_models] at h + rcases h with ⟨T0, hT0, h⟩ + have f : ∀ ψ ∈ Theory.ACF 0, + { s : Finset Nat.Primes // ∀ q : Nat.Primes, q ∉ s → Theory.ACF q ⊨ᵇ ψ } := by + intro ψ hψ + rw [Theory.ACF, Theory.fieldOfChar, Set.union_right_comm, Set.mem_union, if_pos rfl, + Set.mem_image] at hψ + apply Classical.choice + rcases hψ with h | ⟨p, hp, rfl⟩ + · refine ⟨⟨∅, ?_⟩⟩ + intro q _ + exact Theory.models_sentence_of_mem + (by rw [Theory.ACF, Theory.fieldOfChar, Set.union_right_comm]; + exact Set.mem_union_left _ h) + · refine ⟨⟨{⟨p, hp⟩}, ?_⟩⟩ + rintro ⟨q, _⟩ hq ⟨K⟩ _ _ + have hqp : q ≠ p := by simpa [← Nat.Primes.coe_nat_inj] using hq + let _ := fieldOfModelACF q K + have := modelField_of_modelACF q K + let _ := compatibleRingOfModelField K + have := charP_of_model_fieldOfChar q K + simp only [eqZero, Term.equal, Term.relabel, BoundedFormula.realize_not, + BoundedFormula.realize_bdEqual, Term.realize_relabel, Sum.elim_comp_inl, + realize_termOfFreeCommRing, map_natCast, Term.realize_func, CompatibleRing.funMap_zero, + ne_eq, ← CharP.charP_iff_prime_eq_zero hp] + intro _ + exact hqp <| CharP.eq K inferInstance inferInstance + let s : Finset Nat.Primes := T0.attach.biUnion (fun φ => f φ.1 (hT0 φ.2)) + have hs : ∀ (p : Nat.Primes) ψ, ψ ∈ T0 → p ∉ s → Theory.ACF p ⊨ᵇ ψ := by + intro p ψ hψ hpψ + simp only [s, Finset.mem_biUnion, Finset.mem_attach, true_and, + Subtype.exists, not_exists] at hpψ + exact (f ψ (hT0 hψ)).2 p (hpψ _ hψ) + refine Set.Finite.subset (Finset.finite_toSet s) (Set.compl_subset_comm.2 ?_) + intro p hp + exact Theory.models_of_models_theory (fun ψ hψ => hs p ψ hψ hp) h + +/-- The **Lefschetz principle**. A first order sentence is modeled by the theory +of algebraically closed fields of characteristic zero if and only if it is modeled by +the theory of algebraically closed fields of characteristic `p` for infinitely many `p`. -/ +theorem ACF_zero_realize_iff_infinite_ACF_prime_realize {φ : Language.ring.Sentence} : + Theory.ACF 0 ⊨ᵇ φ ↔ Set.Infinite { p : Nat.Primes | Theory.ACF p ⊨ᵇ φ } := by + refine ⟨fun h => Set.infinite_of_finite_compl + (finite_ACF_prime_not_realize_of_ACF_zero_realize φ h), + not_imp_not.1 ?_⟩ + simpa [(ACF_isComplete (Or.inr rfl)).models_not_iff, + fun p : Nat.Primes => (ACF_isComplete (Or.inl p.2)).models_not_iff] using + finite_ACF_prime_not_realize_of_ACF_zero_realize φ.not + +/-- Another statement of the **Lefschetz principle**. A first order sentence is modeled by the +theory of algebraically closed fields of characteristic zero if and only if it is modeled by the +theory of algebraically closed fields of characteristic `p` for all but finitely many primes `p`. +-/ +theorem ACF_zero_realize_iff_finite_ACF_prime_not_realize {φ : Language.ring.Sentence} : + Theory.ACF 0 ⊨ᵇ φ ↔ Set.Finite { p : Nat.Primes | Theory.ACF p ⊨ᵇ φ }ᶜ := + ⟨fun h => finite_ACF_prime_not_realize_of_ACF_zero_realize φ h, + fun h => ACF_zero_realize_iff_infinite_ACF_prime_realize.2 + (Set.infinite_of_finite_compl h)⟩ + + +end Field + +end FirstOrder diff --git a/Mathlib/ModelTheory/Algebra/Ring/Basic.lean b/Mathlib/ModelTheory/Algebra/Ring/Basic.lean index 7df3ce6ac5bdb..c2c75e666e4b2 100644 --- a/Mathlib/ModelTheory/Algebra/Ring/Basic.lean +++ b/Mathlib/ModelTheory/Algebra/Ring/Basic.lean @@ -59,16 +59,19 @@ inductive ringFunc : ℕ → Type def Language.ring : Language := { Functions := ringFunc Relations := fun _ => Empty } + deriving IsAlgebraic namespace Ring open ringFunc Language -instance (n : ℕ) : DecidableEq (Language.ring.Functions n) := by - dsimp [Language.ring]; infer_instance +/-- This instance does not get inferred without `instDecidableEqFunctions` in +`ModelTheory/Basic`. -/ +example (n : ℕ) : DecidableEq (Language.ring.Functions n) := inferInstance -instance (n : ℕ) : DecidableEq (Language.ring.Relations n) := by - dsimp [Language.ring]; infer_instance +/-- This instance does not get inferred without `instDecidableEqRelations` in +`ModelTheory/Basic`. -/ +example (n : ℕ) : DecidableEq (Language.ring.Relations n) := inferInstance /-- `RingFunc.add`, but with the defeq type `Language.ring.Functions 2` instead of `RingFunc 2` -/ @@ -137,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. @@ -223,7 +226,6 @@ def compatibleRingOfRing (R : Type*) [Add R] [Mul R] [Neg R] [One R] [Zero R] : | _, .neg => fun x => -x 0 | _, .zero => fun _ => 0 | _, .one => fun _ => 1 - RelMap := Empty.elim, funMap_add := fun _ => rfl, funMap_mul := fun _ => rfl, funMap_neg := fun _ => rfl, diff --git a/Mathlib/ModelTheory/Basic.lean b/Mathlib/ModelTheory/Basic.lean index 58d599986ed9e..baa0ada8d4271 100644 --- a/Mathlib/ModelTheory/Basic.lean +++ b/Mathlib/ModelTheory/Basic.lean @@ -58,154 +58,61 @@ structure Language where /-- For every arity, a `Type*` of relations of that arity -/ Relations : ℕ → Type v -/-- Used to define `FirstOrder.Language₂`. -/ ---@[simp] -def Sequence₂ (a₀ a₁ a₂ : Type u) : ℕ → Type u - | 0 => a₀ - | 1 => a₁ - | 2 => a₂ - | _ => PEmpty - -namespace Sequence₂ - -variable (a₀ a₁ a₂ : Type u) - -instance inhabited₀ [h : Inhabited a₀] : Inhabited (Sequence₂ a₀ a₁ a₂ 0) := - h - -instance inhabited₁ [h : Inhabited a₁] : Inhabited (Sequence₂ a₀ a₁ a₂ 1) := - h - -instance inhabited₂ [h : Inhabited a₂] : Inhabited (Sequence₂ a₀ a₁ a₂ 2) := - h - -instance {n : ℕ} : IsEmpty (Sequence₂ a₀ a₁ a₂ (n + 3)) := inferInstanceAs (IsEmpty PEmpty) - -@[simp] -theorem lift_mk {i : ℕ} : - Cardinal.lift.{v,u} #(Sequence₂ a₀ a₁ a₂ i) - = #(Sequence₂ (ULift.{v,u} a₀) (ULift.{v,u} a₁) (ULift.{v,u} a₂) i) := by - rcases i with (_ | _ | _ | i) <;> - simp only [Sequence₂, mk_uLift, Nat.succ_ne_zero, IsEmpty.forall_iff, Nat.succ.injEq, - add_eq_zero, OfNat.ofNat_ne_zero, and_false, one_ne_zero, mk_eq_zero, lift_zero] - -@[simp] -theorem sum_card : Cardinal.sum (fun i => #(Sequence₂ a₀ a₁ a₂ i)) = #a₀ + #a₁ + #a₂ := by - rw [sum_nat_eq_add_sum_succ, sum_nat_eq_add_sum_succ, sum_nat_eq_add_sum_succ] - simp [add_assoc, Sequence₂] +namespace Language -end Sequence₂ +variable (L : Language.{u, v}) -namespace Language +/-- A language is relational when it has no function symbols. -/ +abbrev IsRelational : Prop := ∀ n, IsEmpty (L.Functions n) -/-- A constructor for languages with only constants, unary and binary functions, and -unary and binary relations. -/ -@[simps] -protected def mk₂ (c f₁ f₂ : Type u) (r₁ r₂ : Type v) : Language := - ⟨Sequence₂ c f₁ f₂, Sequence₂ PEmpty r₁ r₂⟩ +/-- A language is algebraic when it has no relation symbols. -/ +abbrev IsAlgebraic : Prop := ∀ n, IsEmpty (L.Relations n) /-- The empty language has no symbols. -/ protected def empty : Language := ⟨fun _ => Empty, fun _ => Empty⟩ + deriving IsAlgebraic, IsRelational instance : Inhabited Language := ⟨Language.empty⟩ /-- The sum of two languages consists of the disjoint union of their symbols. -/ -protected def sum (L : Language.{u, v}) (L' : Language.{u', v'}) : Language := +protected def sum (L' : Language.{u', v'}) : Language := ⟨fun n => L.Functions n ⊕ L'.Functions n, fun n => L.Relations n ⊕ L'.Relations n⟩ -variable (L : Language.{u, v}) - /-- The type of constants in a given language. -/ -- Porting note(#5171): this linter isn't ported yet. -- @[nolint has_nonempty_instance] -protected def Constants := +protected abbrev Constants := L.Functions 0 -@[simp] -theorem constants_mk₂ (c f₁ f₂ : Type u) (r₁ r₂ : Type v) : - (Language.mk₂ c f₁ f₂ r₁ r₂).Constants = c := - rfl - /-- 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. -/ def card : Cardinal := #L.Symbols -/-- A language is relational when it has no function symbols. -/ -class IsRelational : Prop where - /-- There are no function symbols in the language. -/ - empty_functions : ∀ n, IsEmpty (L.Functions n) - -/-- A language is algebraic when it has no relation symbols. -/ -class IsAlgebraic : Prop where - /-- There are no relation symbols in the language. -/ - empty_relations : ∀ n, IsEmpty (L.Relations n) - variable {L} {L' : Language.{u', v'}} 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] - -instance [L.IsRelational] {n : ℕ} : IsEmpty (L.Functions n) := - IsRelational.empty_functions n - -instance [L.IsAlgebraic] {n : ℕ} : IsEmpty (L.Relations n) := - IsAlgebraic.empty_relations n - -instance isRelational_of_empty_functions {symb : ℕ → Type*} : - IsRelational ⟨fun _ => Empty, symb⟩ := - ⟨fun _ => instIsEmptyEmpty⟩ - -instance isAlgebraic_of_empty_relations {symb : ℕ → Type*} : IsAlgebraic ⟨symb, fun _ => Empty⟩ := - ⟨fun _ => instIsEmptyEmpty⟩ - -instance isRelational_empty : IsRelational Language.empty := - Language.isRelational_of_empty_functions - -instance isAlgebraic_empty : IsAlgebraic Language.empty := - Language.isAlgebraic_of_empty_relations + simp only [card, mk_sum, mk_sigma, lift_sum] instance isRelational_sum [L.IsRelational] [L'.IsRelational] : IsRelational (L.sum L') := - ⟨fun _ => instIsEmptySum⟩ + fun _ => instIsEmptySum instance isAlgebraic_sum [L.IsAlgebraic] [L'.IsAlgebraic] : IsAlgebraic (L.sum L') := - ⟨fun _ => instIsEmptySum⟩ - -instance isRelational_mk₂ {c f₁ f₂ : Type u} {r₁ r₂ : Type v} [h0 : IsEmpty c] [h1 : IsEmpty f₁] - [h2 : IsEmpty f₂] : IsRelational (Language.mk₂ c f₁ f₂ r₁ r₂) := - ⟨fun n => - Nat.casesOn n h0 fun n => Nat.casesOn n h1 fun n => Nat.casesOn n h2 fun _ => - inferInstanceAs (IsEmpty PEmpty)⟩ - -instance isAlgebraic_mk₂ {c f₁ f₂ : Type u} {r₁ r₂ : Type v} [h1 : IsEmpty r₁] [h2 : IsEmpty r₂] : - IsAlgebraic (Language.mk₂ c f₁ f₂ r₁ r₂) := - ⟨fun n => - Nat.casesOn n (inferInstanceAs (IsEmpty PEmpty)) fun n => - Nat.casesOn n h1 fun n => Nat.casesOn n h2 fun _ => inferInstanceAs (IsEmpty PEmpty)⟩ - -instance subsingleton_mk₂_functions {c f₁ f₂ : Type u} {r₁ r₂ : Type v} [h0 : Subsingleton c] - [h1 : Subsingleton f₁] [h2 : Subsingleton f₂] {n : ℕ} : - Subsingleton ((Language.mk₂ c f₁ f₂ r₁ r₂).Functions n) := - Nat.casesOn n h0 fun n => - Nat.casesOn n h1 fun n => Nat.casesOn n h2 fun _ => ⟨fun x => PEmpty.elim x⟩ - -instance subsingleton_mk₂_relations {c f₁ f₂ : Type u} {r₁ r₂ : Type v} [h1 : Subsingleton r₁] - [h2 : Subsingleton r₂] {n : ℕ} : Subsingleton ((Language.mk₂ c f₁ f₂ r₁ r₂).Relations n) := - Nat.casesOn n ⟨fun x => PEmpty.elim x⟩ fun n => - Nat.casesOn n h1 fun n => Nat.casesOn n h2 fun _ => ⟨fun x => PEmpty.elim x⟩ + 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] @@ -226,19 +133,23 @@ 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] -theorem card_mk₂ (c f₁ f₂ : Type u) (r₁ r₂ : Type v) : - (Language.mk₂ c f₁ f₂ r₁ r₂).card = - Cardinal.lift.{v} #c + Cardinal.lift.{v} #f₁ + Cardinal.lift.{v} #f₂ + - Cardinal.lift.{u} #r₁ + Cardinal.lift.{u} #r₂ := by - simp [card_eq_card_functions_add_card_relations, add_assoc] + 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 - +see the `example`s in `ModelTheory/Ring/Basic`. -/ +instance instDecidableEqFunctions {f : ℕ → Type*} {R : ℕ → Type*} (n : ℕ) [DecidableEq (f n)] : + DecidableEq ((⟨f, R⟩ : Language).Functions n) := inferInstance + +/-- Passes a `DecidableEq` instance on a type of relation symbols through the `Language` +constructor. Despite the fact that this is proven by `inferInstance`, it is still needed - +see the `example`s in `ModelTheory/Ring/Basic`. -/ +instance instDecidableEqRelations {f : ℕ → Type*} {R : ℕ → Type*} (n : ℕ) [DecidableEq (R n)] : + DecidableEq ((⟨f, R⟩ : Language).Relations n) := inferInstance variable (L) (M : Type w) @@ -249,9 +160,11 @@ variable (L) (M : Type w) @[ext] class Structure where /-- Interpretation of the function symbols -/ - funMap : ∀ {n}, L.Functions n → (Fin n → M) → M + funMap : ∀ {n}, L.Functions n → (Fin n → M) → M := by + exact fun {n} => isEmptyElim /-- Interpretation of the relation symbols -/ - RelMap : ∀ {n}, L.Relations n → (Fin n → M) → Prop + RelMap : ∀ {n}, L.Relations n → (Fin n → M) → Prop := by + exact fun {n} => isEmptyElim variable (N : Type w') [L.Structure M] [L.Structure N] @@ -332,71 +245,16 @@ theorem funMap_eq_coe_constants {c : L.Constants} {x : Fin 0 → M} : funMap c x theorem nonempty_of_nonempty_constants [h : Nonempty L.Constants] : Nonempty M := h.map (↑) -/-- The function map for `FirstOrder.Language.Structure₂`. -/ -def funMap₂ {c f₁ f₂ : Type u} {r₁ r₂ : Type v} (c' : c → M) (f₁' : f₁ → M → M) - (f₂' : f₂ → M → M → M) : ∀ {n}, (Language.mk₂ c f₁ f₂ r₁ r₂).Functions n → (Fin n → M) → M - | 0, f, _ => c' f - | 1, f, x => f₁' f (x 0) - | 2, f, x => f₂' f (x 0) (x 1) - | _ + 3, f, _ => PEmpty.elim f - -/-- The relation map for `FirstOrder.Language.Structure₂`. -/ -def RelMap₂ {c f₁ f₂ : Type u} {r₁ r₂ : Type v} (r₁' : r₁ → Set M) (r₂' : r₂ → M → M → Prop) : - ∀ {n}, (Language.mk₂ c f₁ f₂ r₁ r₂).Relations n → (Fin n → M) → Prop - | 0, r, _ => PEmpty.elim r - | 1, r, x => x 0 ∈ r₁' r - | 2, r, x => r₂' r (x 0) (x 1) - | _ + 3, r, _ => PEmpty.elim r - -/-- A structure constructor to match `FirstOrder.Language₂`. -/ -protected def Structure.mk₂ {c f₁ f₂ : Type u} {r₁ r₂ : Type v} (c' : c → M) (f₁' : f₁ → M → M) - (f₂' : f₂ → M → M → M) (r₁' : r₁ → Set M) (r₂' : r₂ → M → M → Prop) : - (Language.mk₂ c f₁ f₂ r₁ r₂).Structure M := - ⟨funMap₂ c' f₁' f₂', RelMap₂ r₁' r₂'⟩ - -namespace Structure - -variable {c f₁ f₂ : Type u} {r₁ r₂ : Type v} -variable {c' : c → M} {f₁' : f₁ → M → M} {f₂' : f₂ → M → M → M} -variable {r₁' : r₁ → Set M} {r₂' : r₂ → M → M → Prop} - -@[simp] -theorem funMap_apply₀ (c₀ : c) {x : Fin 0 → M} : - @Structure.funMap _ M (Structure.mk₂ c' f₁' f₂' r₁' r₂') 0 c₀ x = c' c₀ := - rfl - -@[simp] -theorem funMap_apply₁ (f : f₁) (x : M) : - @Structure.funMap _ M (Structure.mk₂ c' f₁' f₂' r₁' r₂') 1 f ![x] = f₁' f x := - rfl - -@[simp] -theorem funMap_apply₂ (f : f₂) (x y : M) : - @Structure.funMap _ M (Structure.mk₂ c' f₁' f₂' r₁' r₂') 2 f ![x, y] = f₂' f x y := - rfl - -@[simp] -theorem relMap_apply₁ (r : r₁) (x : M) : - @Structure.RelMap _ M (Structure.mk₂ c' f₁' f₂' r₁' r₂') 1 r ![x] = (x ∈ r₁' r) := - rfl - -@[simp] -theorem relMap_apply₂ (r : r₂) (x y : M) : - @Structure.RelMap _ M (Structure.mk₂ c' f₁' f₂' r₁' r₂') 2 r ![x, y] = r₂' r x y := - rfl - -end Structure - /-- `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 @@ -411,7 +269,7 @@ instance (priority := 100) StrongHomClass.homClass {F : Type*} [L.Structure M] theorem HomClass.strongHomClassOfIsAlgebraic [L.IsAlgebraic] {F M N} [L.Structure M] [L.Structure N] [FunLike F M N] [HomClass L F M N] : StrongHomClass L F M N where map_fun := HomClass.map_fun - map_rel _ n R _ := (IsAlgebraic.empty_relations n).elim R + map_rel _ _ := isEmptyElim theorem HomClass.map_constants {F M N} [L.Structure M] [L.Structure N] [FunLike F M N] [HomClass L F M N] (φ : F) (c : L.Constants) : φ c = c := @@ -508,7 +366,7 @@ theorem id_comp (f : M →[L] N) : (id L N).comp f = f := end Hom /-- Any element of a `HomClass` can be realized as a first_order homomorphism. -/ -def HomClass.toHom {F M N} [L.Structure M] [L.Structure N] [FunLike F M N] +@[simps] def HomClass.toHom {F M N} [L.Structure M] [L.Structure N] [FunLike F M N] [HomClass L F M N] : F → M →[L] N := fun φ => ⟨φ, HomClass.map_fun φ, HomClass.map_rel φ⟩ @@ -616,7 +474,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) := @@ -663,7 +521,7 @@ theorem refl_toHom : (refl L M).toHom = Hom.id L M := end Embedding /-- Any element of an injective `StrongHomClass` can be realized as a first_order embedding. -/ -def StrongHomClass.toEmbedding {F M N} [L.Structure M] [L.Structure N] [FunLike F M N] +@[simps] def StrongHomClass.toEmbedding {F M N} [L.Structure M] [L.Structure N] [FunLike F M N] [EmbeddingLike F M N] [StrongHomClass L F M N] : F → M ↪[L] N := fun φ => ⟨⟨φ, EmbeddingLike.injective φ⟩, StrongHomClass.map_fun φ, StrongHomClass.map_rel φ⟩ @@ -693,11 +551,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] } + 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 @@ -790,7 +648,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) := @@ -877,7 +735,7 @@ theorem comp_right_inj (h : M ≃[L] N) (f g : N ≃[L] P) : f.comp h = g.comp h end Equiv /-- Any element of a bijective `StrongHomClass` can be realized as a first_order isomorphism. -/ -def StrongHomClass.toEquiv {F M N} [L.Structure M] [L.Structure N] [EquivLike F M N] +@[simps] def StrongHomClass.toEquiv {F M N} [L.Structure M] [L.Structure N] [EquivLike F M N] [StrongHomClass L F M N] : F → M ≃[L] N := fun φ => ⟨⟨φ, EquivLike.inv φ, EquivLike.left_inv φ, EquivLike.right_inv φ⟩, StrongHomClass.map_fun φ, StrongHomClass.map_rel φ⟩ @@ -916,14 +774,23 @@ end SumStructure section Empty -section +/-- Any type can be made uniquely into a structure over the empty language. -/ +def emptyStructure : Language.empty.Structure M where + +instance : Unique (Language.empty.Structure M) := + ⟨⟨Language.emptyStructure⟩, fun a => by + ext _ f <;> exact Empty.elim f⟩ variable [Language.empty.Structure M] [Language.empty.Structure N] +instance (priority := 100) strongHomClassEmpty {F} [FunLike F M N] : + StrongHomClass Language.empty F M N := + ⟨fun _ _ f => Empty.elim f, fun _ _ r => Empty.elim r⟩ + @[simp] theorem empty.nonempty_embedding_iff : Nonempty (M ↪[Language.empty] N) ↔ Cardinal.lift.{w'} #M ≤ Cardinal.lift.{w} #N := - _root_.trans ⟨Nonempty.map fun f => f.toEmbedding, Nonempty.map fun f => { toEmbedding := f }⟩ + _root_.trans ⟨Nonempty.map fun f => f.toEmbedding, Nonempty.map StrongHomClass.toEmbedding⟩ Cardinal.lift_mk_le'.symm @[simp] @@ -932,47 +799,12 @@ theorem empty.nonempty_equiv_iff : _root_.trans ⟨Nonempty.map fun f => f.toEquiv, Nonempty.map fun f => { toEquiv := f }⟩ Cardinal.lift_mk_eq'.symm -end - -instance emptyStructure : Language.empty.Structure M := - ⟨Empty.elim, Empty.elim⟩ - -instance : Unique (Language.empty.Structure M) := - ⟨⟨Language.emptyStructure⟩, fun a => by - ext _ f <;> exact Empty.elim f⟩ - -instance (priority := 100) strongHomClassEmpty {F M N} [FunLike F M N] : - StrongHomClass Language.empty F M N := - ⟨fun _ _ f => Empty.elim f, fun _ _ r => Empty.elim r⟩ - -/-- Makes a `Language.empty.Hom` out of any function. -/ +/-- Makes a `Language.empty.Hom` out of any function. +This is only needed because there is no instance of `FunLike (M → N) M N`, and thus no instance of +`Language.empty.HomClass M N`. -/ @[simps] def _root_.Function.emptyHom (f : M → N) : M →[Language.empty] N where toFun := f -/-- Makes a `Language.empty.Embedding` out of any function. -/ ---@[simps] Porting note: commented out and lemmas added manually -def _root_.Embedding.empty (f : M ↪ N) : M ↪[Language.empty] N where toEmbedding := f - -@[simp] -theorem toFun_embedding_empty (f : M ↪ N) : (Embedding.empty f : M → N) = f := - rfl - -@[simp] -theorem toEmbedding_embedding_empty (f : M ↪ N) : (Embedding.empty f).toEmbedding = f := - rfl - -/-- Makes a `Language.empty.Equiv` out of any function. -/ ---@[simps] Porting note: commented out and lemmas added manually -def _root_.Equiv.empty (f : M ≃ N) : M ≃[Language.empty] N where toEquiv := f - -@[simp] -theorem toFun_equiv_empty (f : M ≃ N) : (Equiv.empty f : M → N) = f := - rfl - -@[simp] -theorem toEquiv_equiv_empty (f : M ≃ N) : (Equiv.empty f).toEquiv = f := - rfl - end Empty end Language @@ -998,8 +830,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/Bundled.lean b/Mathlib/ModelTheory/Bundled.lean index 9b260af7fec41..a480f4b745cd0 100644 --- a/Mathlib/ModelTheory/Bundled.lean +++ b/Mathlib/ModelTheory/Bundled.lean @@ -111,7 +111,8 @@ def equivInduced {M : ModelType.{u, v, w} T} {N : Type w'} (e : M ≃ N) : ModelType.{u, v, w'} T where Carrier := N struc := e.inducedStructure - is_model := @Equiv.theory_model L M N _ e.inducedStructure T e.inducedStructureEquiv _ + is_model := @StrongHomClass.theory_model L M N _ e.inducedStructure T + _ _ _ e.inducedStructureEquiv _ nonempty' := e.symm.nonempty instance of_small (M : Type w) [Nonempty M] [L.Structure M] [M ⊨ T] [h : Small.{w'} M] : diff --git a/Mathlib/ModelTheory/Complexity.lean b/Mathlib/ModelTheory/Complexity.lean index e51cf9755ab1a..e4d9bfc7ef31f 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 @@ -79,19 +79,31 @@ theorem IsAtomic.isQF {φ : L.BoundedFormula α n} : IsAtomic φ → IsQF φ := theorem isQF_bot : IsQF (⊥ : L.BoundedFormula α n) := IsQF.falsum -theorem IsQF.not {φ : L.BoundedFormula α n} (h : IsQF φ) : IsQF φ.not := +namespace IsQF + +theorem not {φ : L.BoundedFormula α n} (h : IsQF φ) : IsQF φ.not := h.imp isQF_bot -theorem IsQF.relabel {m : ℕ} {φ : L.BoundedFormula α m} (h : φ.IsQF) (f : α → β ⊕ (Fin n)) : +theorem top : IsQF (⊤ : L.BoundedFormula α n) := isQF_bot.not + +theorem sup {φ ψ : L.BoundedFormula α n} (hφ : IsQF φ) (hψ : IsQF ψ) : IsQF (φ ⊔ ψ) := + hφ.not.imp hψ + +theorem inf {φ ψ : L.BoundedFormula α n} (hφ : IsQF φ) (hψ : IsQF ψ) : IsQF (φ ⊓ ψ) := + (hφ.imp hψ.not).not + +protected theorem relabel {m : ℕ} {φ : L.BoundedFormula α m} (h : φ.IsQF) (f : α → β ⊕ (Fin n)) : (φ.relabel f).IsQF := IsQF.recOn h isQF_bot (fun h => (h.relabel f).isQF) fun _ _ h1 h2 => h1.imp h2 -theorem IsQF.liftAt {k m : ℕ} (h : IsQF φ) : (φ.liftAt k m).IsQF := +protected theorem liftAt {k m : ℕ} (h : IsQF φ) : (φ.liftAt k m).IsQF := IsQF.recOn h isQF_bot (fun ih => ih.liftAt.isQF) fun _ _ ih1 ih2 => ih1.imp ih2 -theorem IsQF.castLE {h : l ≤ n} (hφ : IsQF φ) : (φ.castLE h).IsQF := +protected theorem castLE {h : l ≤ n} (hφ : IsQF φ) : (φ.castLE h).IsQF := IsQF.recOn hφ isQF_bot (fun ih => ih.castLE.isQF) fun _ _ ih1 ih2 => ih1.imp ih2 +end IsQF + theorem not_all_isQF (φ : L.BoundedFormula α (n + 1)) : ¬φ.all.IsQF := fun con => by cases' con with _ con exact φ.not_all_isAtomic con @@ -157,11 +169,10 @@ theorem IsQF.toPrenexImpRight {φ : L.BoundedFormula α n} : theorem isPrenex_toPrenexImpRight {φ ψ : L.BoundedFormula α n} (hφ : IsQF φ) (hψ : IsPrenex ψ) : IsPrenex (φ.toPrenexImpRight ψ) := by - induction' hψ with _ _ hψ _ _ _ ih1 _ _ _ ih2 - · rw [hψ.toPrenexImpRight] - exact (hφ.imp hψ).isPrenex - · exact (ih1 hφ.liftAt).all - · exact (ih2 hφ.liftAt).ex + induction hψ with + | of_isQF hψ => rw [hψ.toPrenexImpRight]; exact (hφ.imp hψ).isPrenex + | all _ ih1 => exact (ih1 hφ.liftAt).all + | ex _ ih2 => exact (ih2 hφ.liftAt).ex -- Porting note: universes in different order /-- An auxiliary operation to `FirstOrder.Language.BoundedFormula.toPrenex`. @@ -184,11 +195,10 @@ theorem IsQF.toPrenexImp : theorem isPrenex_toPrenexImp {φ ψ : L.BoundedFormula α n} (hφ : IsPrenex φ) (hψ : IsPrenex ψ) : IsPrenex (φ.toPrenexImp ψ) := by - induction' hφ with _ _ hφ _ _ _ ih1 _ _ _ ih2 - · rw [hφ.toPrenexImp] - exact isPrenex_toPrenexImpRight hφ hψ - · exact (ih1 hψ.liftAt).ex - · exact (ih2 hψ.liftAt).all + induction hφ with + | of_isQF hφ => rw [hφ.toPrenexImp]; exact isPrenex_toPrenexImpRight hφ hψ + | all _ ih1 => exact (ih1 hψ.liftAt).ex + | ex _ ih2 => exact (ih2 hψ.liftAt).all -- Porting note: universes in different order /-- For any bounded formula `φ`, `φ.toPrenex` is a semantically-equivalent formula in prenex normal @@ -210,12 +220,14 @@ variable [Nonempty M] theorem realize_toPrenexImpRight {φ ψ : L.BoundedFormula α n} (hφ : IsQF φ) (hψ : IsPrenex ψ) {v : α → M} {xs : Fin n → M} : (φ.toPrenexImpRight ψ).Realize v xs ↔ (φ.imp ψ).Realize v xs := by - induction' hψ with _ _ hψ _ _ _hψ ih _ _ _hψ ih - · rw [hψ.toPrenexImpRight] - · refine _root_.trans (forall_congr' fun _ => ih hφ.liftAt) ?_ + induction hψ with + | of_isQF hψ => rw [hψ.toPrenexImpRight] + | all _ ih => + refine _root_.trans (forall_congr' fun _ => ih hφ.liftAt) ?_ simp only [realize_imp, realize_liftAt_one_self, snoc_comp_castSucc, realize_all] exact ⟨fun h1 a h2 => h1 h2 a, fun h1 h2 a => h1 a h2⟩ - · unfold toPrenexImpRight + | ex _ ih => + unfold toPrenexImpRight rw [realize_ex] refine _root_.trans (exists_congr fun _ => ih hφ.liftAt) ?_ simp only [realize_imp, realize_liftAt_one_self, snoc_comp_castSucc, realize_ex] @@ -231,10 +243,14 @@ theorem realize_toPrenexImpRight {φ ψ : L.BoundedFormula α n} (hφ : IsQF φ) theorem realize_toPrenexImp {φ ψ : L.BoundedFormula α n} (hφ : IsPrenex φ) (hψ : IsPrenex ψ) {v : α → M} {xs : Fin n → M} : (φ.toPrenexImp ψ).Realize v xs ↔ (φ.imp ψ).Realize v xs := by revert ψ - induction' hφ with _ _ hφ _ _ _hφ ih _ _ _hφ ih <;> intro ψ hψ - · rw [hφ.toPrenexImp] + induction hφ with + | of_isQF hφ => + intro ψ hψ + rw [hφ.toPrenexImp] exact realize_toPrenexImpRight hφ hψ - · unfold toPrenexImp + | all _ ih => + intro ψ hψ + unfold toPrenexImp rw [realize_ex] refine _root_.trans (exists_congr fun _ => ih hψ.liftAt) ?_ simp only [realize_imp, realize_liftAt_one_self, snoc_comp_castSucc, realize_all] @@ -246,20 +262,24 @@ theorem realize_toPrenexImp {φ ψ : L.BoundedFormula α n} (hφ : IsPrenex φ) exact ⟨default, fun _h'' => h⟩ · obtain ⟨a, ha⟩ := not_forall.1 (h ∘ h') exact ⟨a, fun h => (ha h).elim⟩ - · refine _root_.trans (forall_congr' fun _ => ih hψ.liftAt) ?_ + | ex _ ih => + intro ψ hψ + refine _root_.trans (forall_congr' fun _ => ih hψ.liftAt) ?_ simp @[simp] theorem realize_toPrenex (φ : L.BoundedFormula α n) {v : α → M} : ∀ {xs : Fin n → M}, φ.toPrenex.Realize v xs ↔ φ.Realize v xs := by - induction' φ with _ _ _ _ _ _ _ _ _ f1 f2 h1 h2 _ _ h - · exact Iff.rfl - · exact Iff.rfl - · exact Iff.rfl - · intros + induction φ with + | falsum => exact Iff.rfl + | equal => exact Iff.rfl + | rel => exact Iff.rfl + | imp f1 f2 h1 h2 => + intros rw [toPrenex, realize_toPrenexImp f1.toPrenex_isPrenex f2.toPrenex_isPrenex, realize_imp, realize_imp, h1, h2] - · intros + | all _ h => + intros rw [realize_all, toPrenex, realize_all] exact forall_congr' fun a => h @@ -268,25 +288,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) @@ -294,29 +314,166 @@ 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 _ _ hφ _ _ _ hφ _ _ _ hφ - · exact hqf hφ - · exact hall hφ - · exact hex hφ + induction hφ with + | of_isQF hφ => exact hqf hφ + | all _ hφ => exact hall hφ + | ex _ hφ => exact hex hφ theorem induction_on_exists_not {P : ∀ {m}, L.BoundedFormula α m → Prop} (φ : L.BoundedFormula α n) (hqf : ∀ {m} {ψ : L.BoundedFormula α m}, IsQF ψ → P ψ) (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 +quantifier-free formula. -/ +inductive IsUniversal : ∀ {n}, L.BoundedFormula α n → Prop + | of_isQF {n} {φ : L.BoundedFormula α n} (h : IsQF φ) : IsUniversal φ + | all {n} {φ : L.BoundedFormula α (n + 1)} (h : IsUniversal φ) : IsUniversal φ.all + +lemma IsQF.isUniversal {φ : L.BoundedFormula α n} : IsQF φ → IsUniversal φ := + IsUniversal.of_isQF + +lemma IsAtomic.isUniversal {φ : L.BoundedFormula α n} (h : IsAtomic φ) : IsUniversal φ := + h.isQF.isUniversal + +/-- An existential formula is a formula defined by applying only existential quantifiers to a +quantifier-free formula. -/ +inductive IsExistential : ∀ {n}, L.BoundedFormula α n → Prop + | of_isQF {n} {φ : L.BoundedFormula α n} (h : IsQF φ) : IsExistential φ + | ex {n} {φ : L.BoundedFormula α (n + 1)} (h : IsExistential φ) : IsExistential φ.ex + +lemma IsQF.isExistential {φ : L.BoundedFormula α n} : IsQF φ → IsExistential φ := + IsExistential.of_isQF + +lemma IsAtomic.isExistential {φ : L.BoundedFormula α n} (h : IsAtomic φ) : IsExistential φ := + h.isQF.isExistential + +section Preservation + +variable {M : Type*} [L.Structure M] {N : Type*} [L.Structure N] +variable {F : Type*} [FunLike F M N] + +lemma IsAtomic.realize_comp_of_injective {φ : L.BoundedFormula α n} (hA : φ.IsAtomic) + [L.HomClass F M N] {f : F} (hInj : Function.Injective f) {v : α → M} {xs : Fin n → M} : + φ.Realize v xs → φ.Realize (f ∘ v) (f ∘ xs) := by + induction hA with + | equal t₁ t₂ => simp only [realize_bdEqual, ← Sum.comp_elim, HomClass.realize_term, hInj.eq_iff, + imp_self] + | rel R ts => + simp only [realize_rel, ← Sum.comp_elim, HomClass.realize_term] + exact HomClass.map_rel f R (fun i => Term.realize (Sum.elim v xs) (ts i)) + +lemma IsAtomic.realize_comp {φ : L.BoundedFormula α n} (hA : φ.IsAtomic) + [EmbeddingLike F M N] [L.HomClass F M N] (f : F) {v : α → M} {xs : Fin n → M} : + φ.Realize v xs → φ.Realize (f ∘ v) (f ∘ xs) := + hA.realize_comp_of_injective (EmbeddingLike.injective f) + +variable [EmbeddingLike F M N] [L.StrongHomClass F M N] + +lemma IsQF.realize_embedding {φ : L.BoundedFormula α n} (hQF : φ.IsQF) + (f : F) {v : α → M} {xs : Fin n → M} : + φ.Realize (f ∘ v) (f ∘ xs) ↔ φ.Realize v xs := by + induction hQF with + | falsum => rfl + | of_isAtomic hA => induction hA with + | equal t₁ t₂ => simp only [realize_bdEqual, ← Sum.comp_elim, HomClass.realize_term, + (EmbeddingLike.injective f).eq_iff] + | rel R ts => + simp only [realize_rel, ← Sum.comp_elim, HomClass.realize_term] + exact StrongHomClass.map_rel f R (fun i => Term.realize (Sum.elim v xs) (ts i)) + | imp _ _ ihφ ihψ => simp only [realize_imp, ihφ, ihψ] + +lemma IsUniversal.realize_embedding {φ : L.BoundedFormula α n} (hU : φ.IsUniversal) + (f : F) {v : α → M} {xs : Fin n → M} : + φ.Realize (f ∘ v) (f ∘ xs) → φ.Realize v xs := by + induction hU with + | of_isQF hQF => simp [hQF.realize_embedding] + | all _ ih => + simp only [realize_all, Nat.succ_eq_add_one] + refine fun h a => ih ?_ + rw [Fin.comp_snoc] + exact h (f a) + +lemma IsExistential.realize_embedding {φ : L.BoundedFormula α n} (hE : φ.IsExistential) + (f : F) {v : α → M} {xs : Fin n → M} : + φ.Realize v xs → φ.Realize (f ∘ v) (f ∘ xs) := by + induction hE with + | of_isQF hQF => simp [hQF.realize_embedding] + | ex _ ih => + simp only [realize_ex, Nat.succ_eq_add_one] + refine fun ⟨a, ha⟩ => ⟨f a, ?_⟩ + rw [← Fin.comp_snoc] + exact ih ha + +end Preservation + end BoundedFormula +/-- A theory is universal when it is comprised only of universal sentences - these theories apply +also to substructures. -/ +class Theory.IsUniversal (T : L.Theory) : Prop where + isUniversal_of_mem : ∀ ⦃φ⦄, φ ∈ T → φ.IsUniversal + +lemma Theory.IsUniversal.models_of_embedding {T : L.Theory} [hT : T.IsUniversal] + {N : Type*} [L.Structure N] [N ⊨ T] (f : M ↪[L] N) : M ⊨ T := by + simp only [model_iff] + refine fun φ hφ => (hT.isUniversal_of_mem hφ).realize_embedding f (?_) + rw [Subsingleton.elim (f ∘ default) default, Subsingleton.elim (f ∘ default) default] + exact Theory.realize_sentence_of_mem T hφ + +instance Substructure.models_of_isUniversal + (S : L.Substructure M) (T : L.Theory) [T.IsUniversal] [M ⊨ T] : S ⊨ T := + Theory.IsUniversal.models_of_embedding (Substructure.subtype S) + +lemma Theory.IsUniversal.insert + {T : L.Theory} [hT : T.IsUniversal] {φ : L.Sentence} (hφ : φ.IsUniversal) : + (insert φ T).IsUniversal := ⟨by + simp only [Set.mem_insert_iff, forall_eq_or_imp, hφ, true_and] + exact hT.isUniversal_of_mem⟩ + +namespace Relations + +open BoundedFormula + +lemma isAtomic (r : L.Relations l) (ts : Fin l → L.Term (α ⊕ (Fin n))) : + IsAtomic (r.boundedFormula ts) := IsAtomic.rel r ts + +lemma isQF (r : L.Relations l) (ts : Fin l → L.Term (α ⊕ (Fin n))) : + IsQF (r.boundedFormula ts) := (r.isAtomic ts).isQF + +variable (r : L.Relations 2) + +protected lemma isUniversal_reflexive : r.reflexive.IsUniversal := + (r.isQF _).isUniversal.all + +protected lemma isUniversal_irreflexive : r.irreflexive.IsUniversal := + (r.isAtomic _).isQF.not.isUniversal.all + +protected lemma isUniversal_symmetric : r.symmetric.IsUniversal := + ((r.isQF _).imp (r.isQF _)).isUniversal.all.all + +protected lemma isUniversal_antisymmetric : r.antisymmetric.IsUniversal := + ((r.isQF _).imp ((r.isQF _).imp (IsAtomic.equal _ _).isQF)).isUniversal.all.all + +protected lemma isUniversal_transitive : r.transitive.IsUniversal := + ((r.isQF _).imp ((r.isQF _).imp (r.isQF _))).isUniversal.all.all.all + +protected lemma isUniversal_total : r.total.IsUniversal := + ((r.isQF _).sup (r.isQF _)).isUniversal.all.all + +end Relations + theorem Formula.isAtomic_graph (f : L.Functions n) : (Formula.graph f).IsAtomic := BoundedFormula.IsAtomic.equal _ _ diff --git a/Mathlib/ModelTheory/Definability.lean b/Mathlib/ModelTheory/Definability.lean index 771c189b32504..641713521c6c4 100644 --- a/Mathlib/ModelTheory/Definability.lean +++ b/Mathlib/ModelTheory/Definability.lean @@ -61,8 +61,8 @@ theorem definable_iff_exists_formula_sum : rw [Definable, Equiv.exists_congr_left (BoundedFormula.constantsVarsEquiv)] refine exists_congr (fun φ => iff_iff_eq.2 (congr_arg (s = ·) ?_)) ext - simp only [Formula.Realize, BoundedFormula.constantsVarsEquiv, constantsOn, mk₂_Relations, - BoundedFormula.mapTermRelEquiv_symm_apply, mem_setOf_eq] + simp only [BoundedFormula.constantsVarsEquiv, constantsOn, + BoundedFormula.mapTermRelEquiv_symm_apply, mem_setOf_eq, Formula.Realize] refine BoundedFormula.realize_mapTermRel_id ?_ (fun _ _ _ => rfl) intros simp only [Term.constantsVarsEquivLeft_symm_apply, Term.realize_varsToConstants, @@ -74,7 +74,7 @@ theorem definable_iff_exists_formula_sum : theorem empty_definable_iff : (∅ : Set M).Definable L s ↔ ∃ φ : L.Formula α, s = setOf φ.Realize := by rw [Definable, Equiv.exists_congr_left (LEquiv.addEmptyConstants L (∅ : Set M)).onFormula] - simp [-constantsOn] + simp theorem definable_iff_empty_definable_with_params : A.Definable L s ↔ (∅ : Set M).Definable (L[[A]]) s := diff --git a/Mathlib/ModelTheory/DirectLimit.lean b/Mathlib/ModelTheory/DirectLimit.lean index 5f0d653d1499c..3a74358878660 100644 --- a/Mathlib/ModelTheory/DirectLimit.lean +++ b/Mathlib/ModelTheory/DirectLimit.lean @@ -330,14 +330,14 @@ theorem exists_fg_substructure_in_Sigma (S : L.Substructure (DirectLimit G f)) ( rw [← image_univ, image_image, image_univ, ← eq_y, Subtype.range_coe_subtype, Finset.setOf_mem, A_closure] -variable {P : Type u₁} [L.Structure P] (g : ∀ i, G i ↪[L] P) -variable (Hg : ∀ i j hij x, g j (f i j hij x) = g i x) -variable (L ι G f) +variable {P : Type u₁} [L.Structure P] +variable (L ι G f) in /-- The universal property of the direct limit: maps from the components to another module that respect the directed system structure (i.e. make some diagram commute) give rise to a unique map out of the direct limit. -/ -def lift : DirectLimit G f ↪[L] P where +def lift (g : ∀ i, G i ↪[L] P) (Hg : ∀ i j hij x, g j (f i j hij x) = g i x) : + DirectLimit G f ↪[L] P where toFun := Quotient.lift (fun x : Σˣ f => (g x.1) x.2) fun x y xy => by simp only @@ -353,17 +353,17 @@ def lift : DirectLimit G f ↪[L] P where 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 -variable {L ι G f} +variable (g : ∀ i, G i ↪[L] P) (Hg : ∀ i j hij x, g j (f i j hij x) = g i x) @[simp] theorem lift_quotient_mk'_sigma_mk' {i} (x : G i) : lift L ι G f g Hg ⟦.mk f i x⟧ = (g i) x := by @@ -388,11 +388,11 @@ variable (L ι G f) variable (G' : ι → Type w') [∀ i, L.Structure (G' i)] variable (f' : ∀ i j, i ≤ j → G' i ↪[L] G' j) variable (g : ∀ i, G i ≃[L] G' i) -variable (H_commuting : ∀ i j hij x, g j (f i j hij x) = f' i j hij (g i x)) variable [DirectedSystem G' fun i j h => f' i j h] /-- The isomorphism between limits of isomorphic systems. -/ -noncomputable def equiv_lift : DirectLimit G f ≃[L] DirectLimit G' f' := by +noncomputable def equiv_lift (H_commuting : ∀ i j hij x, g j (f i j hij x) = f' i j hij (g i x)) : + DirectLimit G f ≃[L] DirectLimit G' f' := by let U i : G i ↪[L] DirectLimit G' f' := (of L _ G' f' i).comp (g i).toEmbedding let F : DirectLimit G f ↪[L] DirectLimit G' f' := lift L _ G f U <| by intro _ _ _ _ @@ -405,6 +405,8 @@ noncomputable def equiv_lift : DirectLimit G f ≃[L] DirectLimit G' f' := by rfl exact ⟨Equiv.ofBijective F ⟨F.injective, surj_f⟩, F.map_fun', F.map_rel'⟩ +variable (H_commuting : ∀ i j hij x, g j (f i j hij x) = f' i j hij (g i x)) + theorem equiv_lift_of {i : ι} (x : G i) : equiv_lift L ι G f G' f' g H_commuting (of L ι G f i x) = of L ι G' f' i (g i x) := rfl @@ -417,7 +419,7 @@ theorem cg {ι : Type*} [Countable ι] [Preorder ι] [IsDirected ι (· ≤ ·)] Structure.CG L (DirectLimit G f) := by refine ⟨⟨⋃ i, DirectLimit.of L ι G f i '' Classical.choose (h i).out, ?_, ?_⟩⟩ · exact Set.countable_iUnion fun i => Set.Countable.image (Classical.choose_spec (h i).out).1 _ - · rw [eq_top_iff, Substructure.closure_unionᵢ] + · rw [eq_top_iff, Substructure.closure_iUnion] simp_rw [← Embedding.coe_toHom, Substructure.closure_image] rw [le_iSup_iff] intro S hS x _ diff --git a/Mathlib/ModelTheory/ElementaryMaps.lean b/Mathlib/ModelTheory/ElementaryMaps.lean index 9c25fd43ecb9e..54428842a22a5 100644 --- a/Mathlib/ModelTheory/ElementaryMaps.lean +++ b/Mathlib/ModelTheory/ElementaryMaps.lean @@ -79,12 +79,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] @@ -224,7 +224,7 @@ def ElementaryEmbedding.ofModelsElementaryDiagram (N : Type*) [L.Structure N] [L (Constants.term ∘ Sum.inr ∘ x)).alls).trans ?_) · simp_rw [Sentence.Realize, BoundedFormula.realize_alls, BoundedFormula.realize_subst, - LHom.realize_onBoundedFormula, Formula.Realize, Unique.forall_iff, Function.comp, + LHom.realize_onBoundedFormula, Formula.Realize, Unique.forall_iff, Function.comp_def, Term.realize_constants] · simp_rw [Sentence.Realize, BoundedFormula.realize_alls, BoundedFormula.realize_subst, LHom.realize_onBoundedFormula, Formula.Realize, Unique.forall_iff] @@ -248,9 +248,9 @@ theorem isElementary_of_exists (f : M ↪[L] N) refine fun n φ => φ.recOn ?_ ?_ ?_ ?_ ?_ · exact fun {_} _ => Iff.rfl · intros - simp [BoundedFormula.Realize, ← Sum.comp_elim, Embedding.realize_term] + simp [BoundedFormula.Realize, ← Sum.comp_elim, HomClass.realize_term] · intros - simp only [BoundedFormula.Realize, ← Sum.comp_elim, realize_term] + simp only [BoundedFormula.Realize, ← Sum.comp_elim, HomClass.realize_term] erw [map_rel f] · intro _ _ _ ih1 ih2 _ simp [ih1, ih2] @@ -301,7 +301,7 @@ end Equiv @[simp] theorem realize_term_substructure {α : Type*} {S : L.Substructure M} (v : α → S) (t : L.Term α) : t.realize ((↑) ∘ v) = (↑(t.realize v) : M) := - S.subtype.realize_term t + HomClass.realize_term S.subtype end Language diff --git a/Mathlib/ModelTheory/Encoding.lean b/Mathlib/ModelTheory/Encoding.lean index 4c7fe629d2236..b8219e55752e1 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 @@ -83,7 +83,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'] @@ -132,8 +132,8 @@ theorem card_sigma : #(Σn, L.Term (α ⊕ (Fin n))) = max ℵ₀ #(α ⊕ (Σi, · simp only [Sum.elim_inl, Sigma.mk.inj_iff, heq_eq_eq, var.injEq, Sum.inl.injEq, true_and] at h rw [h] - · simp only [Sum.elim_inl, Sum.elim_inr, Sigma.mk.inj_iff, false_and] at h - · simp only [Sum.elim_inr, Sum.elim_inl, Sigma.mk.inj_iff, false_and] at h + · simp only [Sum.elim_inl, Sum.elim_inr, Sigma.mk.inj_iff, false_and, reduceCtorEq] at h + · simp only [Sum.elim_inr, Sum.elim_inl, Sigma.mk.inj_iff, false_and, reduceCtorEq] at h · simp only [Sum.elim_inr, Sigma.mk.inj_iff, heq_eq_eq, func.injEq, true_and] at h rw [Sigma.ext_iff.2 ⟨h.1, h.2.1⟩] @@ -146,7 +146,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 α) := @@ -227,12 +227,16 @@ theorem listDecode_encode_list (l : List (Σn, L.BoundedFormula α n)) : simp [listDecode] · rw [bind_cons, h φ _, ih] rintro ⟨n, φ⟩ - induction' φ with _ _ _ _ φ_n φ_l φ_R ts _ _ _ ih1 ih2 _ _ ih <;> intro l - · rw [listEncode, singleton_append, listDecode] - · rw [listEncode, cons_append, cons_append, listDecode, dif_pos] + induction φ with + | falsum => intro l; rw [listEncode, singleton_append, listDecode] + | equal => + intro l + rw [listEncode, cons_append, cons_append, listDecode, dif_pos] · simp only [eq_mp_eq_cast, cast_eq, eq_self_iff_true, heq_iff_eq, and_self_iff, nil_append] · simp only [eq_self_iff_true, heq_iff_eq, and_self_iff] - · rw [listEncode, cons_append, cons_append, singleton_append, cons_append, listDecode] + | @rel φ_n φ_l φ_R ts => + intro l + rw [listEncode, cons_append, cons_append, singleton_append, cons_append, listDecode] have h : ∀ i : Fin φ_l, ((List.map Sum.getLeft? (List.map (fun i : Fin φ_l => Sum.inl (⟨(⟨φ_n, rel φ_R ts⟩ : Σn, L.BoundedFormula α n).fst, ts i⟩ : Σn, L.Term (α ⊕ (Fin n)))) (finRange φ_l) ++ l)).get? ↑i).join = some ⟨_, ts i⟩ := by @@ -240,7 +244,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] @@ -260,11 +264,15 @@ theorem listDecode_encode_list (l : List (Σn, L.BoundedFormula α n)) : rw [List.drop_append_eq_append_drop, length_map, length_finRange, Nat.sub_self, drop, drop_eq_nil_of_le, nil_append] rw [length_map, length_finRange] - · simp only [] at * + | imp _ _ ih1 ih2 => + intro l + simp only [] at * rw [listEncode, List.append_assoc, cons_append, listDecode] simp only [ih1, ih2, length_cons, le_add_iff_nonneg_left, _root_.zero_le, ↓reduceDIte, getElem_cons_zero, getElem_cons_succ, sigmaImp_apply, drop_succ_cons, drop_zero] - · simp only [] at * + | all _ ih => + intro l + simp only [] at * rw [listEncode, cons_append, listDecode] simp only [ih, length_cons, le_add_iff_nonneg_left, _root_.zero_le, ↓reduceDIte, getElem_cons_zero, sigmaAll_apply, drop_succ_cons, drop_zero] 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/FinitelyGenerated.lean b/Mathlib/ModelTheory/FinitelyGenerated.lean index df79d2ed1b59d..1ac2ffb332707 100644 --- a/Mathlib/ModelTheory/FinitelyGenerated.lean +++ b/Mathlib/ModelTheory/FinitelyGenerated.lean @@ -61,6 +61,8 @@ theorem fg_iff_exists_fin_generating_family {N : L.Substructure M} : theorem fg_bot : (⊥ : L.Substructure M).FG := ⟨∅, by rw [Finset.coe_empty, closure_empty]⟩ +instance instInhabited_fg : Inhabited { S : L.Substructure M // S.FG } := ⟨⊥, fg_bot⟩ + theorem fg_closure {s : Set M} (hs : s.Finite) : FG (closure L s) := ⟨hs.toFinset, by rw [hs.coe_toFinset]⟩ @@ -90,6 +92,18 @@ theorem FG.of_map_embedding {N : Type*} [L.Structure N] (f : M ↪[L] N) {s : L. rw [h] at h' exact Hom.map_le_range h' +theorem FG.of_finite {s : L.Substructure M} [h : Finite s] : s.FG := + ⟨Set.Finite.toFinset h, by simp only [Finite.coe_toFinset, closure_eq]⟩ + +theorem FG.finite [L.IsRelational] {S : L.Substructure M} (h : S.FG) : Finite S := by + obtain ⟨s, rfl⟩ := h + have hs := s.finite_toSet + rw [← closure_eq_of_isRelational L (s : Set M)] at hs + exact hs + +theorem fg_iff_finite [L.IsRelational] {S : L.Substructure M} : S.FG ↔ Finite S := + ⟨FG.finite, fun _ => FG.of_finite⟩ + /-- A substructure of `M` is countably generated if it is the closure of a countable subset of `M`. -/ def CG (N : L.Substructure M) : Prop := @@ -161,13 +175,15 @@ theorem cg_iff_countable [Countable (Σl, L.Functions l)] {s : L.Substructure M} rintro ⟨s, h, rfl⟩ exact h.substructure_closure L +theorem cg_of_countable {s : L.Substructure M} [h : Countable s] : s.CG := + ⟨s, h.to_set, s.closure_eq⟩ + end Substructure open Substructure namespace Structure - variable (L) (M) /-- A structure is finitely generated if it is the closure of a finite subset. -/ @@ -197,6 +213,40 @@ theorem FG.map_of_surjective {N : Type*} [L.Structure N] (h : FG L M) (f : M → rw [fg_def, ← hs] exact h.range f +theorem FG.countable_hom (N : Type*) [L.Structure N] [Countable N] (h : FG L M) : + Countable (M →[L] N) := by + let ⟨S, finite_S, closure_S⟩ := fg_iff.1 h + let g : (M →[L] N) → (S → N) := + fun f ↦ f ∘ (↑) + have g_inj : Function.Injective g := by + intro f f' h + apply Hom.eq_of_eqOn_dense closure_S + intro x x_in_S + exact congr_fun h ⟨x, x_in_S⟩ + have : Finite ↑S := (S.finite_coe_iff).2 finite_S + exact Function.Embedding.countable ⟨g, g_inj⟩ + +instance FG.instCountable_hom (N : Type*) [L.Structure N] [Countable N] [h : FG L M] : + Countable (M →[L] N) := + FG.countable_hom N h + +theorem FG.countable_embedding (N : Type*) [L.Structure N] [Countable N] (_ : FG L M) : + Countable (M ↪[L] N) := + Function.Embedding.countable ⟨Embedding.toHom, Embedding.toHom_injective⟩ + +instance Fg.instCountable_embedding (N : Type*) [L.Structure N] + [Countable N] [h : FG L M] : Countable (M ↪[L] N) := + FG.countable_embedding N h + +theorem FG.of_finite [Finite M] : FG L M := by + simp only [fg_def, Substructure.FG.of_finite, topEquiv.toEquiv.finite_iff] + +theorem FG.finite [L.IsRelational] (h : FG L M) : Finite M := + Finite.of_finite_univ (Substructure.FG.finite (fg_def.1 h)) + +theorem fg_iff_finite [L.IsRelational] : FG L M ↔ Finite M := + ⟨FG.finite, fun _ => FG.of_finite⟩ + theorem cg_def : CG L M ↔ (⊤ : L.Substructure M).CG := ⟨fun h => h.1, fun h => ⟨h⟩⟩ @@ -217,6 +267,9 @@ theorem CG.map_of_surjective {N : Type*} [L.Structure N] (h : CG L M) (f : M → theorem cg_iff_countable [Countable (Σl, L.Functions l)] : CG L M ↔ Countable M := by rw [cg_def, Substructure.cg_iff_countable, topEquiv.toEquiv.countable_iff] +theorem cg_of_countable [Countable M] : CG L M := by + simp only [cg_def, Substructure.cg_of_countable, topEquiv.toEquiv.countable_iff] + theorem FG.cg (h : FG L M) : CG L M := cg_def.2 (fg_def.1 h).cg @@ -253,6 +306,21 @@ theorem Substructure.cg_iff_structure_cg (S : L.Substructure M) : S.CG ↔ Struc rw [← Hom.range_eq_map, range_subtype] at h exact h +theorem Substructure.countable_fg_substructures_of_countable [Countable M] : + Countable { S : L.Substructure M // S.FG } := by + let g : { S : L.Substructure M // S.FG } → Finset M := + fun S ↦ Exists.choose S.prop + have g_inj : Function.Injective g := by + intro S S' h + apply Subtype.eq + rw [(Exists.choose_spec S.prop).symm, (Exists.choose_spec S'.prop).symm] + exact congr_arg ((closure L) ∘ Finset.toSet) h + exact Function.Embedding.countable ⟨g, g_inj⟩ + +instance Substructure.instCountable_fg_substructures_of_countable [Countable M] : + Countable { S : L.Substructure M // S.FG } := + countable_fg_substructures_of_countable + end Language end FirstOrder diff --git a/Mathlib/ModelTheory/Fraisse.lean b/Mathlib/ModelTheory/Fraisse.lean index ca502e44d67e8..49c2b90badb5d 100644 --- a/Mathlib/ModelTheory/Fraisse.lean +++ b/Mathlib/ModelTheory/Fraisse.lean @@ -1,10 +1,10 @@ /- Copyright (c) 2022 Aaron Anderson. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Aaron Anderson +Authors: Aaron Anderson, Gabin Kolly -/ import Mathlib.ModelTheory.FinitelyGenerated -import Mathlib.ModelTheory.DirectLimit +import Mathlib.ModelTheory.PartialEquiv import Mathlib.ModelTheory.Bundled import Mathlib.Algebra.Order.Archimedean.Basic @@ -42,6 +42,12 @@ Fraïssé limit - the countable ultrahomogeneous structure with that age. essentially countable. - `FirstOrder.Language.exists_countable_is_age_of_iff` gives necessary and sufficient conditions for a class to be the age of a countable structure in a language with countably many functions. +- `FirstOrder.Language.IsFraisseLimit.nonempty_equiv` shows that any class which is Fraïssé has + at most one Fraïssé limit up to equivalence. +- `FirstOrder.Language.empty.isFraisseLimit_of_countable_infinite` shows that any countably infinite + structure in the empty language is a Fraïssé limit of the class of finite structures. +- `FirstOrder.Language.empty.isFraisse_finite` shows that the class of finite structures in the + empty language is Fraïssé. ## Implementation Notes @@ -56,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 -/ @@ -75,7 +81,7 @@ open Structure Substructure variable (L : Language.{u, v}) -/-! ### The Age of a Structure and Fraïssé Classes-/ +/-! ### The Age of a Structure and Fraïssé Classes -/ /-- The age of a structure `M` is the class of finitely-generated structures that embed into it. -/ @@ -86,7 +92,7 @@ variable {L} variable (K : Set (Bundled.{w} L.Structure)) /-- A class `K` has the hereditary property when all finitely-generated structures that embed into - structures in `K` are also in `K`. -/ + structures in `K` are also in `K`. -/ def Hereditary : Prop := ∀ M : Bundled.{w} L.Structure, M ∈ K → L.age M ⊆ K @@ -155,6 +161,22 @@ theorem age.jointEmbedding : JointEmbedding (L.age M) := fun _ hN _ hP => ⟨Embedding.comp (inclusion le_sup_left) hN.2.some.equivRange.toEmbedding⟩, ⟨Embedding.comp (inclusion le_sup_right) hP.2.some.equivRange.toEmbedding⟩⟩ +variable {M} + +theorem age.fg_substructure {S : L.Substructure M} (fg : S.FG) : Bundled.mk S ∈ L.age M := by + exact ⟨(Substructure.fg_iff_structure_fg _).1 fg, ⟨subtype _⟩⟩ + +variable (M) + +/-- Any class in the age of a structure has a representative which is a finitely generated +substructure. -/ +theorem age.has_representative_as_substructure : + ∀ C ∈ Quotient.mk' '' L.age M, ∃ V : {V : L.Substructure M // FG V}, + ⟦Bundled.mk V⟧ = C := by + rintro _ ⟨N, ⟨N_fg, ⟨N_incl⟩⟩, N_eq⟩ + refine N_eq.symm ▸ ⟨⟨N_incl.toHom.range, ?_⟩, Quotient.sound ⟨N_incl.equivRange.symm⟩⟩ + exact FG.range N_fg (Embedding.toHom N_incl) + /-- The age of a countable structure is essentially countable (has countably many isomorphism classes). -/ theorem age.countable_quotient [h : Countable M] : (Quotient.mk' '' L.age M).Countable := by @@ -265,6 +287,50 @@ structure IsFraisseLimit [Countable (Σ l, L.Functions l)] [Countable M] : Prop variable {M} +/-- Any embedding from a finitely generated `S` to an ultrahomogeneous structure `M` +can be extended to an embedding from any structure with an embedding to `M`. -/ +theorem IsUltrahomogeneous.extend_embedding (M_homog : L.IsUltrahomogeneous M) {S : Type*} + [L.Structure S] (S_FG : FG L S) {T : Type*} [L.Structure T] [h : Nonempty (T ↪[L] M)] + (f : S ↪[L] M) (g : S ↪[L] T) : + ∃ f' : T ↪[L] M, f = f'.comp g := by + let ⟨r⟩ := h + let s := r.comp g + let ⟨t, eq⟩ := M_homog s.toHom.range (S_FG.range s.toHom) (f.comp s.equivRange.symm.toEmbedding) + use t.toEmbedding.comp r + change _ = t.toEmbedding.comp s + ext x + have eq' := congr_fun (congr_arg DFunLike.coe eq) ⟨s x, Hom.mem_range.2 ⟨x, rfl⟩⟩ + simp only [Embedding.comp_apply, Hom.comp_apply, + Equiv.coe_toHom, Embedding.coe_toHom, coeSubtype] at eq' + simp only [Embedding.comp_apply, ← eq', Equiv.coe_toEmbedding, EmbeddingLike.apply_eq_iff_eq] + apply (Embedding.equivRange (Embedding.comp r g)).injective + ext + simp only [Equiv.apply_symm_apply, Embedding.equivRange_apply, s] + +/-- A countably generated structure is ultrahomogeneous if and only if any equivalence between +finitely generated substructures can be extended to any element in the domain.-/ +theorem isUltrahomogeneous_iff_IsExtensionPair (M_CG : CG L M) : L.IsUltrahomogeneous M ↔ + L.IsExtensionPair M M := by + constructor + · intro M_homog ⟨f, f_FG⟩ m + let S := f.dom ⊔ closure L {m} + have dom_le_S : f.dom ≤ S := le_sup_left + let ⟨f', eq_f'⟩ := M_homog.extend_embedding (f.dom.fg_iff_structure_fg.1 f_FG) + ((subtype _).comp f.toEquiv.toEmbedding) (inclusion dom_le_S) (h := ⟨subtype _⟩) + refine ⟨⟨⟨S, f'.toHom.range, f'.equivRange⟩, f_FG.sup (fg_closure_singleton _)⟩, + subset_closure.trans (le_sup_right : _ ≤ S) (mem_singleton m), ⟨dom_le_S, ?_⟩⟩ + ext + simp only [Embedding.comp_apply, Equiv.coe_toEmbedding, coeSubtype, eq_f', + Embedding.equivRange_apply, Substructure.coe_inclusion, EmbeddingLike.apply_eq_iff_eq] + · intro h S S_FG f + let ⟨g, ⟨dom_le_dom, eq⟩⟩ := + equiv_between_cg M_CG M_CG ⟨⟨S, f.toHom.range, f.equivRange⟩, S_FG⟩ h h + use g + simp only [Embedding.subtype_equivRange] at eq + rw [← eq] + ext + rfl + theorem IsUltrahomogeneous.amalgamation_age (h : L.IsUltrahomogeneous M) : Amalgamation (L.age M) := by rintro N P Q NP NQ ⟨Nfg, ⟨-⟩⟩ ⟨Pfg, ⟨PM⟩⟩ ⟨Qfg, ⟨QM⟩⟩ @@ -302,8 +368,74 @@ theorem isFraisse [Countable (Σ l, L.Functions l)] [Countable M] (h : IsFraisse IsFraisse K := (congr rfl h.age).mp h.ultrahomogeneous.age_isFraisse +variable {K} {N : Type w} [L.Structure N] +variable [Countable (Σ l, L.Functions l)] [Countable M] [Countable N] +variable (hM : IsFraisseLimit K M) (hN : IsFraisseLimit K N) + +include hM hN + +protected theorem isExtensionPair : L.IsExtensionPair M N := by + intro ⟨f, f_FG⟩ m + let S := f.dom ⊔ closure L {m} + have S_FG : S.FG := f_FG.sup (Substructure.fg_closure_singleton _) + have S_in_age_N : ⟨S, inferInstance⟩ ∈ L.age N := by + rw [hN.age, ← hM.age] + exact ⟨(fg_iff_structure_fg S).1 S_FG, ⟨subtype _⟩⟩ + haveI nonempty_S_N : Nonempty (S ↪[L] N) := S_in_age_N.2 + let ⟨g, g_eq⟩ := hN.ultrahomogeneous.extend_embedding (f.dom.fg_iff_structure_fg.1 f_FG) + ((subtype f.cod).comp f.toEquiv.toEmbedding) (inclusion (le_sup_left : _ ≤ S)) + refine ⟨⟨⟨S, g.toHom.range, g.equivRange⟩, S_FG⟩, + subset_closure.trans (le_sup_right : _ ≤ S) (mem_singleton m), ⟨le_sup_left, ?_⟩⟩ + ext + simp [Subtype.mk_le_mk, PartialEquiv.le_def, g_eq] + +/-- The Fraïssé limit of a class is unique, in that any two Fraïssé limits are isomorphic. -/ +theorem nonempty_equiv : Nonempty (M ≃[L] N) := by + let S : L.Substructure M := ⊥ + have S_fg : FG L S := (fg_iff_structure_fg _).1 Substructure.fg_bot + obtain ⟨_, ⟨emb_S : S ↪[L] N⟩⟩ : ⟨S, inferInstance⟩ ∈ L.age N := by + rw [hN.age, ← hM.age] + exact ⟨S_fg, ⟨subtype _⟩⟩ + let v : M ≃ₚ[L] N := { + dom := S + cod := emb_S.toHom.range + toEquiv := emb_S.equivRange + } + exact ⟨Exists.choose (equiv_between_cg cg_of_countable cg_of_countable + ⟨v, ((Substructure.fg_iff_structure_fg _).2 S_fg)⟩ (hM.isExtensionPair hN) + (hN.isExtensionPair hM))⟩ + end IsFraisseLimit +namespace empty + +/-- Any countable infinite structure in the empty language is a Fraïssé limit of the class of finite +structures. -/ +theorem isFraisseLimit_of_countable_infinite + (M : Type*) [Countable M] [Infinite M] [Language.empty.Structure M] : + IsFraisseLimit { S : Bundled Language.empty.Structure | Finite S } M where + age := by + ext S + simp only [age, Structure.fg_iff_finite, mem_setOf_eq, and_iff_left_iff_imp] + intro hS + simp + ultrahomogeneous S hS f := by + classical + have : Finite S := hS.finite + have : Infinite { x // x ∉ S } := ((Set.toFinite _).infinite_compl).to_subtype + have : Finite f.toHom.range := (((Substructure.fg_iff_structure_fg S).1 hS).range _).finite + have : Infinite { x // x ∉ f.toHom.range } := ((Set.toFinite _).infinite_compl ).to_subtype + refine ⟨StrongHomClass.toEquiv (f.equivRange.subtypeCongr nonempty_equiv_of_countable.some), ?_⟩ + ext x + simp [Equiv.subtypeCongr] + +/-- The class of finite structures in the empty language is Fraïssé. -/ +theorem isFraisse_finite : IsFraisse { S : Bundled.{w} Language.empty.Structure | Finite S } := by + have : Language.empty.Structure (ULift ℕ : Type w) := emptyStructure + exact (isFraisseLimit_of_countable_infinite (ULift ℕ)).isFraisse + +end empty + end Language end FirstOrder diff --git a/Mathlib/ModelTheory/Graph.lean b/Mathlib/ModelTheory/Graph.lean index 06519b49d2e04..c4ce433290e9c 100644 --- a/Mathlib/ModelTheory/Graph.lean +++ b/Mathlib/ModelTheory/Graph.lean @@ -21,9 +21,7 @@ This file defines first-order languages, structures, and theories in graph theor of the theory of simple graphs. -/ - - -universe u v w w' +universe u v namespace FirstOrder @@ -33,30 +31,31 @@ open FirstOrder open Structure -variable {L : Language.{u, v}} {α : Type w} {V : Type w'} {n : ℕ} +variable {α : Type u} {V : Type v} {n : ℕ} /-! ### Simple Graphs -/ +/-- The type of relations for the language of graphs, consisting of a single binary relation `adj`. +-/ +inductive graphRel : ℕ → Type + | adj : graphRel 2 + deriving DecidableEq /-- The language consisting of a single relation representing adjacency. -/ -protected def graph : Language := - Language.mk₂ Empty Empty Empty Empty Unit +protected def graph : Language := ⟨fun _ => Empty, graphRel⟩ + deriving IsRelational /-- The symbol representing the adjacency relation. -/ -def adj : Language.graph.Relations 2 := - Unit.unit +abbrev adj : Language.graph.Relations 2 := .adj /-- Any simple graph can be thought of as a structure in the language of graphs. -/ -def _root_.SimpleGraph.structure (G : SimpleGraph V) : Language.graph.Structure V := - Structure.mk₂ Empty.elim Empty.elim Empty.elim Empty.elim fun _ => G.Adj +def _root_.SimpleGraph.structure (G : SimpleGraph V) : Language.graph.Structure V where + RelMap | .adj => (fun x => G.Adj (x 0) (x 1)) namespace graph -instance instIsRelational : IsRelational Language.graph := - Language.isRelational_mk₂ - instance instSubsingleton : Subsingleton (Language.graph.Relations n) := - Language.subsingleton_mk₂_relations + ⟨by rintro ⟨⟩ ⟨⟩; rfl⟩ end graph @@ -73,7 +72,8 @@ theorem Theory.simpleGraph_model_iff [Language.graph.Structure V] : instance simpleGraph_model (G : SimpleGraph V) : @Theory.Model _ V G.structure Theory.simpleGraph := by - simp only [@Theory.simpleGraph_model_iff _ G.structure, relMap_apply₂] + letI := G.structure + rw [Theory.simpleGraph_model_iff] exact ⟨G.loopless, G.symm⟩ variable (V) @@ -104,19 +104,14 @@ theorem structure_simpleGraphOfStructure [S : Language.graph.Structure V] [V ⊨ (simpleGraphOfStructure V).structure = S := by ext case funMap n f xs => - exact (IsRelational.empty_functions n).elim f + exact isEmptyElim f case RelMap n r xs => - rw [iff_eq_eq] - cases' n with n - · exact r.elim - · cases' n with n - · exact r.elim - · cases' n with n - · cases r - change RelMap adj ![xs 0, xs 1] = _ - refine congr rfl (funext ?_) - simp [Fin.forall_fin_two] - · exact r.elim + match n, r with + | 2, .adj => + rw [iff_eq_eq] + change RelMap adj ![xs 0, xs 1] = _ + refine congr rfl (funext ?_) + simp [Fin.forall_fin_two] theorem Theory.simpleGraph_isSatisfiable : Theory.IsSatisfiable Theory.simpleGraph := ⟨@Theory.ModelType.of _ _ Unit (SimpleGraph.structure ⊥) _ _⟩ diff --git a/Mathlib/ModelTheory/LanguageMap.lean b/Mathlib/ModelTheory/LanguageMap.lean index a70065ee3ba7e..e7a57200c37cb 100644 --- a/Mathlib/ModelTheory/LanguageMap.lean +++ b/Mathlib/ModelTheory/LanguageMap.lean @@ -47,8 +47,10 @@ variable (L : Language.{u, v}) (L' : Language.{u', v'}) {M : Type w} [L.Structur /-- A language homomorphism maps the symbols of one language to symbols of another. -/ structure LHom where - onFunction : ∀ ⦃n⦄, L.Functions n → L'.Functions n - onRelation : ∀ ⦃n⦄, L.Relations n → L'.Relations n + onFunction : ∀ ⦃n⦄, L.Functions n → L'.Functions n := by + exact fun {n} => isEmptyElim + onRelation : ∀ ⦃n⦄, L.Relations n → L'.Relations n :=by + exact fun {n} => isEmptyElim @[inherit_doc FirstOrder.Language.LHom] infixl:10 " →ᴸ " => LHom @@ -58,16 +60,6 @@ variable {L L'} namespace LHom -/-- Defines a map between languages defined with `Language.mk₂`. -/ -protected def mk₂ {c f₁ f₂ : Type u} {r₁ r₂ : Type v} (φ₀ : c → L'.Constants) - (φ₁ : f₁ → L'.Functions 1) (φ₂ : f₂ → L'.Functions 2) (φ₁' : r₁ → L'.Relations 1) - (φ₂' : r₂ → L'.Relations 2) : Language.mk₂ c f₁ f₂ r₁ r₂ →ᴸ L' := - ⟨fun n => - Nat.casesOn n φ₀ fun n => Nat.casesOn n φ₁ fun n => Nat.casesOn n φ₂ fun _ => PEmpty.elim, - fun n => - Nat.casesOn n PEmpty.elim fun n => - Nat.casesOn n φ₁' fun n => Nat.casesOn n φ₂' fun _ => PEmpty.elim⟩ - variable (ϕ : L →ᴸ L') /-- Pulls a structure back along a language map. -/ @@ -97,8 +89,7 @@ variable (L L') /-- The inclusion of an empty language into any other language. -/ @[simps] -protected def ofIsEmpty [L.IsAlgebraic] [L.IsRelational] : L →ᴸ L' := - ⟨fun n => (IsRelational.empty_functions n).elim, fun n => (IsAlgebraic.empty_relations n).elim⟩ +protected def ofIsEmpty [L.IsAlgebraic] [L.IsRelational] : L →ᴸ L' where variable {L L'} {L'' : Language} @@ -113,23 +104,6 @@ protected theorem funext {F G : L →ᴸ L'} (h_fun : F.onFunction = G.onFunctio instance [L.IsAlgebraic] [L.IsRelational] : Unique (L →ᴸ L') := ⟨⟨LHom.ofIsEmpty L L'⟩, fun _ => LHom.funext (Subsingleton.elim _ _) (Subsingleton.elim _ _)⟩ -theorem mk₂_funext {c f₁ f₂ : Type u} {r₁ r₂ : Type v} {F G : Language.mk₂ c f₁ f₂ r₁ r₂ →ᴸ L'} - (h0 : ∀ c : (Language.mk₂ c f₁ f₂ r₁ r₂).Constants, F.onFunction c = G.onFunction c) - (h1 : ∀ f : (Language.mk₂ c f₁ f₂ r₁ r₂).Functions 1, F.onFunction f = G.onFunction f) - (h2 : ∀ f : (Language.mk₂ c f₁ f₂ r₁ r₂).Functions 2, F.onFunction f = G.onFunction f) - (h1' : ∀ r : (Language.mk₂ c f₁ f₂ r₁ r₂).Relations 1, F.onRelation r = G.onRelation r) - (h2' : ∀ r : (Language.mk₂ c f₁ f₂ r₁ r₂).Relations 2, F.onRelation r = G.onRelation r) : - F = G := - LHom.funext - (funext fun n => - Nat.casesOn n (funext h0) fun n => - Nat.casesOn n (funext h1) fun n => - Nat.casesOn n (funext h2) fun _n => funext fun f => PEmpty.elim f) - (funext fun n => - Nat.casesOn n (funext fun r => PEmpty.elim r) fun n => - Nat.casesOn n (funext h1') fun n => - Nat.casesOn n (funext h2') fun _n => funext fun r => PEmpty.elim r) - /-- The composition of two language homomorphisms. -/ @[simps] def comp (g : L' →ᴸ L'') (f : L →ᴸ L') : L →ᴸ L'' := @@ -219,9 +193,12 @@ noncomputable def defaultExpansion (ϕ : L →ᴸ L') /-- A language homomorphism is an expansion on a structure if it commutes with the interpretation of all symbols on that structure. -/ class IsExpansionOn (M : Type*) [L.Structure M] [L'.Structure M] : Prop where - map_onFunction : ∀ {n} (f : L.Functions n) (x : Fin n → M), funMap (ϕ.onFunction f) x = funMap f x - map_onRelation : ∀ {n} (R : L.Relations n) (x : Fin n → M), - RelMap (ϕ.onRelation R) x = RelMap R x + map_onFunction : + ∀ {n} (f : L.Functions n) (x : Fin n → M), funMap (ϕ.onFunction f) x = funMap f x := by + exact fun {n} => isEmptyElim + map_onRelation : + ∀ {n} (R : L.Relations n) (x : Fin n → M), RelMap (ϕ.onRelation R) x = RelMap R x := by + exact fun {n} => isEmptyElim @[simp] theorem map_onFunction {M : Type*} [L.Structure M] [L'.Structure M] [ϕ.IsExpansionOn M] {n} @@ -237,9 +214,7 @@ instance id_isExpansionOn (M : Type*) [L.Structure M] : IsExpansionOn (LHom.id L ⟨fun _ _ => rfl, fun _ _ => rfl⟩ instance ofIsEmpty_isExpansionOn (M : Type*) [L.Structure M] [L'.Structure M] [L.IsAlgebraic] - [L.IsRelational] : IsExpansionOn (LHom.ofIsEmpty L L') M := - ⟨fun {n} => (IsRelational.empty_functions n).elim, - fun {n} => (IsAlgebraic.empty_relations n).elim⟩ + [L.IsRelational] : IsExpansionOn (LHom.ofIsEmpty L L') M where instance sumElim_isExpansionOn {L'' : Language} (ψ : L'' →ᴸ L') (M : Type*) [L.Structure M] [L'.Structure M] [L''.Structure M] [ϕ.IsExpansionOn M] [ψ.IsExpansionOn M] : @@ -340,38 +315,47 @@ section ConstantsOn variable (α : Type u') -/-- A language with constants indexed by a type. -/ +/-- The type of functions for a language consisting only of constant symbols. -/ @[simp] -def constantsOn : Language.{u', 0} := - Language.mk₂ α PEmpty PEmpty PEmpty PEmpty +def constantsOnFunc : ℕ → Type u' + | 0 => α + | (_ + 1) => PEmpty + +/-- A language with constants indexed by a type. -/ +@[simps] +def constantsOn : Language.{u', 0} := ⟨constantsOnFunc α, fun _ => Empty⟩ variable {α} theorem constantsOn_constants : (constantsOn α).Constants = α := rfl -instance isAlgebraic_constantsOn : IsAlgebraic (constantsOn α) := - Language.isAlgebraic_mk₂ - -instance isRelational_constantsOn [_ie : IsEmpty α] : IsRelational (constantsOn α) := - Language.isRelational_mk₂ +instance isAlgebraic_constantsOn : IsAlgebraic (constantsOn α) := by + unfold constantsOn + infer_instance instance isEmpty_functions_constantsOn_succ {n : ℕ} : IsEmpty ((constantsOn α).Functions (n + 1)) := - Nat.casesOn n (inferInstanceAs (IsEmpty PEmpty)) - fun n => Nat.casesOn n (inferInstanceAs (IsEmpty PEmpty)) - fun _ => (inferInstanceAs (IsEmpty PEmpty)) + inferInstanceAs (IsEmpty PEmpty) + +instance isRelational_constantsOn [_ie : IsEmpty α] : IsRelational (constantsOn α) := + fun n => Nat.casesOn n _ie inferInstance -theorem card_constantsOn : (constantsOn α).card = #α := by simp +theorem card_constantsOn : (constantsOn α).card = #α := by + simp [card_eq_card_functions_add_card_relations, sum_nat_eq_add_sum_succ] /-- Gives a `constantsOn α` structure to a type by assigning each constant a value. -/ -def constantsOn.structure (f : α → M) : (constantsOn α).Structure M := - Structure.mk₂ f PEmpty.elim PEmpty.elim PEmpty.elim PEmpty.elim +def constantsOn.structure (f : α → M) : (constantsOn α).Structure M where + funMap := fun {n} c _ => + match n, c with + | 0, c => f c variable {β : Type v'} /-- A map between index types induces a map between constant languages. -/ -def LHom.constantsOnMap (f : α → β) : constantsOn α →ᴸ constantsOn β := - LHom.mk₂ f PEmpty.elim PEmpty.elim PEmpty.elim PEmpty.elim +def LHom.constantsOnMap (f : α → β) : constantsOn α →ᴸ constantsOn β where + onFunction := fun {n} c => + match n, c with + | 0, c => f c theorem constantsOnMap_isExpansionOn {f : α → β} {fα : α → M} {fβ : β → M} (h : fβ ∘ f = fα) : @LHom.IsExpansionOn _ _ (LHom.constantsOnMap f) M (constantsOn.structure fα) @@ -404,7 +388,7 @@ theorem card_withConstants : L[[α]].card = Cardinal.lift.{w'} L.card + Cardinal.lift.{max u v} #α := by rw [withConstants, card_sum, card_constantsOn] -/-- The language map adding constants. -/ +/-- The language map adding constants. -/ @[simps!] -- Porting note: add `!` to `simps` def lhomWithConstants : L →ᴸ L[[α]] := LHom.sumInl @@ -420,7 +404,7 @@ protected def con (a : α) : L[[α]].Constants := variable {L} (α) -/-- Adds constants to a language map. -/ +/-- Adds constants to a language map. -/ def LHom.addConstants {L' : Language} (φ : L →ᴸ L') : L[[α]] →ᴸ L'[[α]] := φ.sumMap (LHom.id _) @@ -429,7 +413,7 @@ instance paramsStructure (A : Set α) : (constantsOn A).Structure α := variable (L) -/-- The language map removing an empty constant set. -/ +/-- The language map removing an empty constant set. -/ @[simps] def LEquiv.addEmptyConstants [ie : IsEmpty α] : L ≃ᴸ L[[α]] where toLHom := lhomWithConstants L α @@ -451,7 +435,7 @@ theorem withConstants_relMap_sum_inl [L[[α]].Structure M] [(lhomWithConstants L {n} {R : L.Relations n} {x : Fin n → M} : @RelMap (L[[α]]) M _ n (Sum.inl R) x = RelMap R x := (lhomWithConstants L α).map_onRelation R x -/-- The language map extending the constant set. -/ +/-- The language map extending the constant set. -/ def lhomWithConstantsMap (f : α → β) : L[[α]] →ᴸ L[[β]] := LHom.sumMap (LHom.id L) (LHom.constantsOnMap f) diff --git a/Mathlib/ModelTheory/Order.lean b/Mathlib/ModelTheory/Order.lean index a5c6f4fce9ec4..af11c905aa569 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.ModelTheory.Semantics +import Mathlib.Data.Rat.Denumerable +import Mathlib.ModelTheory.Complexity +import Mathlib.ModelTheory.Fraisse +import Mathlib.Order.CountableDenseLinearOrder /-! # Ordered First-Ordered Structures @@ -13,8 +16,6 @@ This file defines ordered first-order languages and structures, as well as their ## Main Definitions - `FirstOrder.Language.order` is the language consisting of a single relation representing `≤`. -- `FirstOrder.Language.orderStructure` is the structure on an ordered type, assigning the symbol - representing `≤` to the actual relation `≤`. - `FirstOrder.Language.IsOrdered` points out a specific symbol in a language as representing `≤`. - `FirstOrder.Language.OrderedStructure` indicates that the `≤` symbol in an ordered language is interpreted as the actual relation `≤` in a particular structure. @@ -22,11 +23,29 @@ This file defines ordered first-order languages and structures, as well as their partial orders, and linear orders. - `FirstOrder.Language.dlo` defines the theory of dense linear orders without endpoints, a particularly useful example in model theory. +- `FirstOrder.Language.orderStructure` is the structure on an ordered type, assigning the symbol + representing `≤` to the actual relation `≤`. +- Conversely, `FirstOrder.Language.LEOfStructure`, `FirstOrder.Language.preorderOfModels`, + `FirstOrder.Language.partialOrderOfModels`, and `FirstOrder.Language.linearOrderOfModels` + are the orders induced by first-order structures modelling the relevant theory. ## Main Results - `PartialOrder`s model the theory of partial orders, `LinearOrder`s model the theory of linear orders, and dense linear orders without endpoints model `Language.dlo`. +- Under `L.orderedStructure` assumptions, elements of any `L.HomClass M N` are monotone, and + strictly monotone if injective. +- 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. + -/ @@ -36,34 +55,61 @@ namespace FirstOrder namespace Language - open FirstOrder Structure variable {L : Language.{u, v}} {α : Type w} {M : Type w'} {n : ℕ} -/-- The language consisting of a single relation representing `≤`. -/ -protected def order : Language := - Language.mk₂ Empty Empty Empty Empty Unit +/-- The type of relations for the language of orders, consisting of a single binary relation `le`. +-/ +inductive orderRel : ℕ → Type + | le : orderRel 2 + deriving DecidableEq -instance orderStructure [LE M] : Language.order.Structure M := - Structure.mk₂ Empty.elim Empty.elim Empty.elim Empty.elim fun _ => (· ≤ ·) +/-- The relational language consisting of a single relation representing `≤`. -/ +protected def order : Language := ⟨fun _ => Empty, orderRel⟩ + deriving IsRelational -namespace Order +namespace order -instance Language.instIsRelational : IsRelational Language.order := - Language.isRelational_mk₂ +@[simp] +lemma forall_relations {P : ∀ (n) (_ : Language.order.Relations n), Prop} : + (∀ {n} (R), P n R) ↔ P 2 .le := ⟨fun h => h _, fun h n R => + match n, R with + | 2, .le => h⟩ -instance Language.instSubsingleton : Subsingleton (Language.order.Relations n) := - Language.subsingleton_mk₂_relations +instance instSubsingleton : Subsingleton (Language.order.Relations n) := + ⟨by rintro ⟨⟩ ⟨⟩; rfl⟩ -end Order +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 `≤`. -/ class IsOrdered (L : Language.{u, v}) where + /-- The relation symbol representing `≤`. -/ leSymb : L.Relations 2 export IsOrdered (leSymb) +instance : IsOrdered Language.order := + ⟨.le⟩ + +lemma order.relation_eq_leSymb : (R : Language.order.Relations 2) → R = leSymb + | .le => rfl + section IsOrdered variable [IsOrdered L] @@ -80,16 +126,11 @@ variable (L) /-- The language homomorphism sending the unique symbol `≤` of `Language.order` to `≤` in an ordered language. -/ -def orderLHom : Language.order →ᴸ L := - LHom.mk₂ Empty.elim Empty.elim Empty.elim Empty.elim fun _ => leSymb - -end IsOrdered - -instance : IsOrdered Language.order := - ⟨Unit.unit⟩ +@[simps] def orderLHom : Language.order →ᴸ L where + onRelation | _, .le => leSymb @[simp] -theorem orderLHom_leSymb [L.IsOrdered] : +theorem orderLHom_leSymb : (orderLHom L).onRelation leSymb = (leSymb : L.Relations 2) := rfl @@ -97,24 +138,30 @@ theorem orderLHom_leSymb [L.IsOrdered] : theorem orderLHom_order : orderLHom Language.order = LHom.id Language.order := LHom.funext (Subsingleton.elim _ _) (Subsingleton.elim _ _) -instance sum.instIsOrdered : IsOrdered (L.sum Language.order) := - ⟨Sum.inr IsOrdered.leSymb⟩ - -section - -variable (L) [IsOrdered L] - /-- The theory of preorders. -/ def preorderTheory : L.Theory := {leSymb.reflexive, leSymb.transitive} +instance : Theory.IsUniversal L.preorderTheory := ⟨by + simp only [preorderTheory, Set.mem_insert_iff, Set.mem_singleton_iff, forall_eq_or_imp, forall_eq] + exact ⟨leSymb.isUniversal_reflexive, leSymb.isUniversal_transitive⟩⟩ + /-- The theory of partial orders. -/ def partialOrderTheory : L.Theory := - {leSymb.reflexive, leSymb.antisymmetric, leSymb.transitive} + insert leSymb.antisymmetric L.preorderTheory + +instance : Theory.IsUniversal L.partialOrderTheory := + Theory.IsUniversal.insert leSymb.isUniversal_antisymmetric /-- The theory of linear orders. -/ def linearOrderTheory : L.Theory := - {leSymb.reflexive, leSymb.antisymmetric, leSymb.transitive, leSymb.total} + insert leSymb.total L.partialOrderTheory + +instance : Theory.IsUniversal L.linearOrderTheory := + Theory.IsUniversal.insert leSymb.isUniversal_total + +example [L.Structure M] [M ⊨ L.linearOrderTheory] (S : L.Substructure M) : + S ⊨ L.linearOrderTheory := inferInstance /-- A sentence indicating that an order has no top element: $\forall x, \exists y, \neg y \le x$. -/ @@ -135,72 +182,64 @@ def denselyOrderedSentence : L.Sentence := def dlo : L.Theory := L.linearOrderTheory ∪ {L.noTopOrderSentence, L.noBotOrderSentence, L.denselyOrderedSentence} -end +variable [L.Structure M] + +instance [h : M ⊨ L.dlo] : M ⊨ L.linearOrderTheory := h.mono Set.subset_union_left + +instance [h : M ⊨ L.linearOrderTheory] : M ⊨ L.partialOrderTheory := h.mono (Set.subset_insert _ _) + +instance [h : M ⊨ L.partialOrderTheory] : M ⊨ L.preorderTheory := h.mono (Set.subset_insert _ _) + +end IsOrdered + +instance sum.instIsOrdered : IsOrdered (L.sum Language.order) := + ⟨Sum.inr IsOrdered.leSymb⟩ variable (L M) -/-- A structure is ordered if its language has a `≤` symbol whose interpretation is -/ -abbrev OrderedStructure [IsOrdered L] [LE M] [L.Structure M] : Prop := - LHom.IsExpansionOn (orderLHom L) M +/-- Any linearly-ordered type is naturally a structure in the language `Language.order`. +This is not an instance, because sometimes the `Language.order.Structure` is defined first. -/ +def orderStructure [LE M] : Language.order.Structure M where + RelMap | .le => (fun x => x 0 ≤ x 1) + +/-- A structure is ordered if its language has a `≤` symbol whose interpretation is `≤`. -/ +class OrderedStructure [L.IsOrdered] [LE M] [L.Structure M] : Prop where + relMap_leSymb : ∀ (x : Fin 2 → M), RelMap (leSymb : L.Relations 2) x ↔ (x 0 ≤ x 1) + +export OrderedStructure (relMap_leSymb) + +attribute [simp] relMap_leSymb variable {L M} -@[simp] -theorem orderedStructure_iff [IsOrdered L] [LE M] [L.Structure M] : - L.OrderedStructure M ↔ LHom.IsExpansionOn (orderLHom L) M := - Iff.rfl +section order_to_structure -instance orderedStructure_LE [LE M] : OrderedStructure Language.order M := by - rw [orderedStructure_iff, orderLHom_order] - exact LHom.id_isExpansionOn M +variable [IsOrdered L] [L.Structure M] -instance model_preorder [Preorder M] : M ⊨ Language.order.preorderTheory := by - simp only [preorderTheory, Theory.model_iff, Set.mem_insert_iff, Set.mem_singleton_iff, - forall_eq_or_imp, Relations.realize_reflexive, relMap_apply₂, forall_eq, - Relations.realize_transitive] - exact ⟨le_refl, fun _ _ _ => le_trans⟩ +section LE -instance model_partialOrder [PartialOrder M] : M ⊨ Language.order.partialOrderTheory := by - simp only [partialOrderTheory, Theory.model_iff, Set.mem_insert_iff, Set.mem_singleton_iff, - forall_eq_or_imp, Relations.realize_reflexive, relMap_apply₂, Relations.realize_antisymmetric, - forall_eq, Relations.realize_transitive] - exact ⟨le_refl, fun _ _ => le_antisymm, fun _ _ _ => le_trans⟩ +variable [LE M] -instance model_linearOrder [LinearOrder M] : M ⊨ Language.order.linearOrderTheory := by - simp only [linearOrderTheory, Theory.model_iff, Set.mem_insert_iff, Set.mem_singleton_iff, - forall_eq_or_imp, Relations.realize_reflexive, relMap_apply₂, Relations.realize_antisymmetric, - Relations.realize_transitive, forall_eq, Relations.realize_total] - exact ⟨le_refl, fun _ _ => le_antisymm, fun _ _ _ => le_trans, le_total⟩ +instance [Language.order.Structure M] [Language.order.OrderedStructure M] + [(orderLHom L).IsExpansionOn M] : L.OrderedStructure M where + relMap_leSymb x := by + rw [← orderLHom_leSymb L, LHom.IsExpansionOn.map_onRelation, relMap_leSymb] -section OrderedStructure +variable [L.OrderedStructure M] -variable [IsOrdered L] [L.Structure M] +instance [Language.order.Structure M] [Language.order.OrderedStructure M] : + LHom.IsExpansionOn (orderLHom L) M where + map_onRelation := by simp [order.relation_eq_leSymb] -@[simp] -theorem relMap_leSymb [LE M] [L.OrderedStructure M] {a b : M} : - RelMap (leSymb : L.Relations 2) ![a, b] ↔ a ≤ b := by - rw [← orderLHom_leSymb, LHom.map_onRelation] - rfl +instance (S : L.Substructure M) : L.OrderedStructure S := ⟨fun x => relMap_leSymb (S.subtype ∘ x)⟩ @[simp] -theorem Term.realize_le [LE M] [L.OrderedStructure M] {t₁ t₂ : L.Term (α ⊕ (Fin n))} {v : α → M} +theorem Term.realize_le {t₁ t₂ : L.Term (α ⊕ (Fin n))} {v : α → M} {xs : Fin n → M} : (t₁.le t₂).Realize v xs ↔ t₁.realize (Sum.elim v xs) ≤ t₂.realize (Sum.elim v xs) := by simp [Term.le] -@[simp] -theorem Term.realize_lt [Preorder M] [L.OrderedStructure M] {t₁ t₂ : L.Term (α ⊕ (Fin n))} - {v : α → M} {xs : Fin n → M} : - (t₁.lt t₂).Realize v xs ↔ t₁.realize (Sum.elim v xs) < t₂.realize (Sum.elim v xs) := by - simp [Term.lt, lt_iff_le_not_le] - -end OrderedStructure - -section LE - -variable [LE M] - -theorem realize_noTopOrder_iff : M ⊨ Language.order.noTopOrderSentence ↔ NoTopOrder M := by +theorem realize_noTopOrder_iff : M ⊨ L.noTopOrderSentence ↔ NoTopOrder M := by simp only [noTopOrderSentence, Sentence.Realize, Formula.Realize, BoundedFormula.realize_all, BoundedFormula.realize_ex, BoundedFormula.realize_not, Term.realize, Term.realize_le, Sum.elim_inr] @@ -208,11 +247,7 @@ theorem realize_noTopOrder_iff : M ⊨ Language.order.noTopOrderSentence ↔ NoT intro h a exact exists_not_le a -@[simp] -theorem realize_noTopOrder [h : NoTopOrder M] : M ⊨ Language.order.noTopOrderSentence := - realize_noTopOrder_iff.2 h - -theorem realize_noBotOrder_iff : M ⊨ Language.order.noBotOrderSentence ↔ NoBotOrder M := by +theorem realize_noBotOrder_iff : M ⊨ L.noBotOrderSentence ↔ NoBotOrder M := by simp only [noBotOrderSentence, Sentence.Realize, Formula.Realize, BoundedFormula.realize_all, BoundedFormula.realize_ex, BoundedFormula.realize_not, Term.realize, Term.realize_le, Sum.elim_inr] @@ -220,14 +255,49 @@ theorem realize_noBotOrder_iff : M ⊨ Language.order.noBotOrderSentence ↔ NoB intro h a exact exists_not_ge a +variable (L M) + +@[simp] +theorem realize_noTopOrder [h : NoTopOrder M] : M ⊨ L.noTopOrderSentence := + realize_noTopOrder_iff.2 h + @[simp] -theorem realize_noBotOrder [h : NoBotOrder M] : M ⊨ Language.order.noBotOrderSentence := +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 -theorem realize_denselyOrdered_iff [Preorder M] : - M ⊨ Language.order.denselyOrderedSentence ↔ DenselyOrdered M := by +@[simp] +theorem orderedStructure_iff + [LE M] [Language.order.Structure M] [Language.order.OrderedStructure M] : + L.OrderedStructure M ↔ LHom.IsExpansionOn (orderLHom L) M := + ⟨fun _ => inferInstance, fun _ => inferInstance⟩ + +section Preorder + +variable [Preorder M] [L.OrderedStructure M] + +instance model_preorder : M ⊨ L.preorderTheory := by + simp only [preorderTheory, Theory.model_insert_iff, Relations.realize_reflexive, relMap_leSymb, + Theory.model_singleton_iff, Relations.realize_transitive] + exact ⟨le_refl, fun _ _ _ => le_trans⟩ + +@[simp] +theorem Term.realize_lt {t₁ t₂ : L.Term (α ⊕ (Fin n))} + {v : α → M} {xs : Fin n → M} : + (t₁.lt t₂).Realize v xs ↔ t₁.realize (Sum.elim v xs) < t₂.realize (Sum.elim v xs) := by + simp [Term.lt, lt_iff_le_not_le] + +theorem realize_denselyOrdered_iff : + M ⊨ L.denselyOrderedSentence ↔ DenselyOrdered M := by simp only [denselyOrderedSentence, Sentence.Realize, Formula.Realize, BoundedFormula.realize_imp, BoundedFormula.realize_all, Term.realize, Term.realize_lt, Sum.elim_inr, BoundedFormula.realize_ex, BoundedFormula.realize_inf] @@ -236,18 +306,255 @@ theorem realize_denselyOrdered_iff [Preorder M] : exact exists_between ab @[simp] -theorem realize_denselyOrdered [Preorder M] [h : DenselyOrdered M] : - M ⊨ Language.order.denselyOrderedSentence := +theorem realize_denselyOrdered [h : DenselyOrdered M] : + M ⊨ L.denselyOrderedSentence := realize_denselyOrdered_iff.2 h -instance model_dlo [LinearOrder M] [DenselyOrdered M] [NoTopOrder M] [NoBotOrder M] : - M ⊨ Language.order.dlo := by - simp only [dlo, Set.union_insert, Set.union_singleton, Theory.model_iff, Set.mem_insert_iff, - forall_eq_or_imp, realize_noTopOrder, realize_noBotOrder, realize_denselyOrdered, - true_and_iff] - rw [← Theory.model_iff] - infer_instance +variable (L) (M) + +theorem denselyOrdered_of_dlo [h: 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] : + M ⊨ L.partialOrderTheory := by + simp only [partialOrderTheory, Theory.model_insert_iff, Relations.realize_antisymmetric, + relMap_leSymb, Fin.isValue, Matrix.cons_val_zero, Matrix.cons_val_one, Matrix.head_cons, + model_preorder, and_true] + exact fun _ _ => le_antisymm + +section LinearOrder + +variable [LinearOrder M] [L.OrderedStructure M] + +instance model_linearOrder : M ⊨ L.linearOrderTheory := by + simp only [linearOrderTheory, Theory.model_insert_iff, Relations.realize_total, relMap_leSymb, + Fin.isValue, Matrix.cons_val_zero, Matrix.cons_val_one, Matrix.head_cons, model_partialOrder, + and_true] + exact le_total + +instance model_dlo [DenselyOrdered M] [NoTopOrder M] [NoBotOrder M] : + M ⊨ L.dlo := by + simp [dlo, model_linearOrder, Theory.model_insert_iff] + +end LinearOrder + +end order_to_structure + +section structure_to_order + +variable (L) [IsOrdered L] (M) [L.Structure M] + +/-- Any structure in an ordered language can be ordered correspondingly. -/ +def leOfStructure : LE M where + le a b := Structure.RelMap (leSymb : L.Relations 2) ![a,b] + +instance : @OrderedStructure L M _ (L.leOfStructure M) _ := by + letI := L.leOfStructure M + constructor + simp only [Fin.forall_fin_succ_pi, Fin.cons_zero, Fin.forall_fin_zero_pi] + intros + rfl + +/-- 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 + __ := L.leOfStructure M + le_refl := Relations.realize_reflexive.1 ((Theory.model_iff _).1 h _ + (by simp only [preorderTheory, Set.mem_insert_iff, Set.mem_singleton_iff, true_or])) + le_trans := Relations.realize_transitive.1 ((Theory.model_iff _).1 h _ + (by simp only [preorderTheory, Set.mem_insert_iff, Set.mem_singleton_iff, or_true])) + +/-- Any model of a theory of partial orders is a partial order. -/ +def partialOrderOfModels [h : M ⊨ L.partialOrderTheory] : PartialOrder M where + __ := L.preorderOfModels M + le_antisymm := Relations.realize_antisymmetric.1 ((Theory.model_iff _).1 h _ + (by simp only [partialOrderTheory, Set.mem_insert_iff, Set.mem_singleton_iff, true_or])) + +/-- Any model of a theory of linear orders is a linear order. -/ +def linearOrderOfModels [h : M ⊨ L.linearOrderTheory] + [DecidableRel (fun (a b : M) => Structure.RelMap (leSymb : L.Relations 2) ![a,b])] : + LinearOrder M where + __ := L.partialOrderOfModels M + le_total := Relations.realize_total.1 ((Theory.model_iff _).1 h _ + (by simp only [linearOrderTheory, Set.mem_insert_iff, Set.mem_singleton_iff, true_or])) + decidableLE := inferInstance + +end structure_to_order + +namespace order + +variable [Language.order.Structure M] [LE M] [Language.order.OrderedStructure M] + {N : Type*} [Language.order.Structure N] [LE N] [Language.order.OrderedStructure N] + {F : Type*} + +instance [FunLike F M N] [OrderHomClass F M N] : Language.order.HomClass F M N := + ⟨fun _ => isEmptyElim, by + simp only [forall_relations, relation_eq_leSymb, relMap_leSymb, Fin.isValue, + Function.comp_apply] + exact fun φ x => map_rel φ⟩ + +-- If `OrderEmbeddingClass` or `RelEmbeddingClass` is defined, this should be generalized. +instance : Language.order.StrongHomClass (M ↪o N) M N := + ⟨fun _ => isEmptyElim, + by simp only [order.forall_relations, order.relation_eq_leSymb, relMap_leSymb, Fin.isValue, + Function.comp_apply, RelEmbedding.map_rel_iff, implies_true]⟩ + +instance [EquivLike F M N] [OrderIsoClass F M N] : Language.order.StrongHomClass F M N := + ⟨fun _ => isEmptyElim, + by simp only [order.forall_relations, order.relation_eq_leSymb, relMap_leSymb, Fin.isValue, + Function.comp_apply, map_le_map_iff, implies_true]⟩ + +end order + +namespace HomClass + +variable [L.IsOrdered] [L.Structure M] {N : Type*} [L.Structure N] + {F : Type*} [FunLike F M N] [L.HomClass F M N] + +lemma monotone [Preorder M] [L.OrderedStructure M] [Preorder N] [L.OrderedStructure N] (f : F) : + Monotone f := fun a b => by + have h := HomClass.map_rel f leSymb ![a,b] + simp only [relMap_leSymb, Fin.isValue, Matrix.cons_val_zero, Matrix.cons_val_one, + Matrix.head_cons, Function.comp_apply] at h + exact h + +lemma strictMono [EmbeddingLike F M N] [PartialOrder M] [L.OrderedStructure M] + [PartialOrder N] [L.OrderedStructure N] (f : F) : + StrictMono f := + (HomClass.monotone f).strictMono_of_injective (EmbeddingLike.injective f) + +end HomClass + +/-- This is not an instance because it would form a loop with + `FirstOrder.Language.order.instStrongHomClassOfOrderIsoClass`. + As both types are `Prop`s, it would only cause a slowdown. -/ +lemma StrongHomClass.toOrderIsoClass + (L : Language) [L.IsOrdered] (M : Type*) [L.Structure M] [LE M] [L.OrderedStructure M] + (N : Type*) [L.Structure N] [LE N] [L.OrderedStructure N] + (F : Type*) [EquivLike F M N] [L.StrongHomClass F M N] : + OrderIsoClass F M N where + map_le_map_iff f a b := by + have h := StrongHomClass.map_rel f leSymb ![a,b] + simp only [relMap_leSymb, Fin.isValue, Function.comp_apply, Matrix.cons_val_zero, + 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 M => 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 41ce920aed2f2..3db2f33308397 100644 --- a/Mathlib/ModelTheory/PartialEquiv.lean +++ b/Mathlib/ModelTheory/PartialEquiv.lean @@ -1,17 +1,36 @@ /- Copyright (c) 2024 Gabin Kolly. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Aaron Anderson, Gabin Kolly +Authors: Aaron Anderson, Gabin Kolly, David Wärn -/ -import Mathlib.ModelTheory.Substructures +import Mathlib.ModelTheory.DirectLimit +import Mathlib.Order.Ideal /-! # Partial Isomorphisms This file defines partial isomorphisms between first-order structures. ## Main Definitions -- `FirstOrder.Language.Substructure.PartialEquiv` is defined so that `L.PartialEquiv M N`, annotated - `M ≃ₚ[L] N`, is the type of equivalences between substructures of `M` and `N`. +- `FirstOrder.Language.PartialEquiv` is defined so that `L.PartialEquiv M N`, annotated + `M ≃ₚ[L] N`, is the type of equivalences between substructures of `M` and `N`. These can be + ordered, with an order that is defined here in terms of a commutative square, but could also be + defined as the order on the graphs of the partial equivalences under inclusion as subsets of + `M × N`. +- `FirstOrder.Language.FGEquiv` is the type of partial equivalences `M ≃ₚ[L] N` with + finitely-generated domain (or equivalently, codomain). +- `FirstOrder.Language.IsExtensionPair` is defined so that `L.IsExtensionPair M N` indicates that + any finitely-generated partial equivalence from `M` to `N` can be extended to include an arbitrary + element `m : M` in its domain. + +## Main Results +- `FirstOrder.Language.embedding_from_cg` shows that if structures `M` and `N` form an equivalence + pair with `M` countably-generated, then any finite-generated partial equivalence between them + can be extended to an embedding `M ↪[L] N`. +- `FirstOrder.Language.equiv_from_cg` shows that if countably-generated structures `M` and `N` form + an equivalence pair in both directions, then any finite-generated partial equivalence between them + can be extended to an isomorphism `M ↪[L] N`. +- The proofs of these results are adapted in part from David Wärn's approach to countable dense + linear orders, a special case of this phenomenon in the case where `L = Language.order`. -/ @@ -61,7 +80,7 @@ theorem symm_apply (f : M ≃ₚ[L] N) (x : f.cod) : f.symm.toEquiv x = f.toEqui rfl instance : LE (M ≃ₚ[L] N) := - ⟨fun f g ↦ ∃h : f.dom ≤ g.dom, + ⟨fun f g ↦ ∃ h : f.dom ≤ g.dom, (subtype _).comp (g.toEquiv.toEmbedding.comp (Substructure.inclusion h)) = (subtype _).comp f.toEquiv.toEmbedding⟩ @@ -90,7 +109,8 @@ theorem toEquiv_inclusion {f g : M ≃ₚ[L] N} (h : f ≤ g) : g.toEquiv.toEmbedding.comp (Substructure.inclusion (dom_le_dom h)) = (Substructure.inclusion (cod_le_cod h)).comp f.toEquiv.toEmbedding := by rw [← (subtype _).comp_inj, subtype_toEquiv_inclusion h] - rfl + ext + simp theorem toEquiv_inclusion_apply {f g : M ≃ₚ[L] N} (h : f ≤ g) (x : f.dom) : g.toEquiv (Substructure.inclusion (dom_le_dom h) x) = @@ -98,7 +118,7 @@ theorem toEquiv_inclusion_apply {f g : M ≃ₚ[L] N} (h : f ≤ g) (x : f.dom) apply (subtype _).injective change (subtype _).comp (g.toEquiv.toEmbedding.comp (inclusion _)) x = _ rw [subtype_toEquiv_inclusion h] - rfl + simp theorem le_iff {f g : M ≃ₚ[L] N} : f ≤ g ↔ ∃ dom_le_dom : f.dom ≤ g.dom, @@ -115,7 +135,8 @@ theorem le_trans (f g h : M ≃ₚ[L] N) : f ≤ g → g ≤ h → f ≤ h := by rintro ⟨le_fg, eq_fg⟩ ⟨le_gh, eq_gh⟩ refine ⟨le_fg.trans le_gh, ?_⟩ rw [← eq_fg, ← Embedding.comp_assoc (g := g.toEquiv.toEmbedding), ← eq_gh] - rfl + ext + simp private theorem le_refl (f : M ≃ₚ[L] N) : f ≤ f := ⟨le_rfl, rfl⟩ @@ -152,7 +173,7 @@ theorem ext {f g : M ≃ₚ[L] N} (h_dom : f.dom = g.dom) : (∀ x : M, ∀ h : intro h rcases f with ⟨dom_f, cod_f, equiv_f⟩ cases h_dom - apply le_antisymm <;> (rw [le_def]; use (by rfl); ext ⟨x, hx⟩) + apply le_antisymm <;> (rw [le_def]; use le_rfl; ext ⟨x, hx⟩) · exact (h x hx).symm · exact h x hx @@ -206,8 +227,7 @@ def toEmbedding (f : M ≃ₚ[L] N) : f.dom ↪[L] N := @[simp] theorem toEmbedding_apply {f : M ≃ₚ[L] N} (m : f.dom) : - f.toEmbedding m = f.toEquiv m := by - rcases f with ⟨dom, cod, g⟩ + f.toEmbedding m = f.toEquiv m := rfl /-- Given a partial equivalence which has the whole structure as domain, @@ -237,6 +257,10 @@ theorem toEquivOfEqTop_toEmbedding {f : M ≃ₚ[L] N} (h_dom : f.dom = ⊤) cases h_cod rfl +theorem dom_fg_iff_cod_fg {N : Type*} [L.Structure N] (f : M ≃ₚ[L] N) : + f.dom.FG ↔ f.cod.FG := by + rw [Substructure.fg_iff_structure_fg, f.toEquiv.fg_iff, Substructure.fg_iff_structure_fg] + end PartialEquiv namespace Embedding @@ -264,11 +288,241 @@ theorem toPartialEquiv_toEmbedding {f : M ≃ₚ[L] N} (h : f.dom = ⊤) : rcases f with ⟨_, _, _⟩ cases h apply PartialEquiv.ext - intro _ _ - rfl; rfl + · intro _ _ + rfl + · rfl end Embedding +namespace DirectLimit + +open PartialEquiv + +variable {ι : Type*} [Preorder ι] [Nonempty ι] [IsDirected ι (· ≤ ·)] +variable (S : ι →o M ≃ₚ[L] N) + +instance : DirectedSystem (fun i ↦ (S i).dom) + (fun _ _ h ↦ Substructure.inclusion (dom_le_dom (S.monotone h))) where + map_self' := fun _ _ _ ↦ rfl + map_map' := fun _ _ _ ↦ rfl + +instance : DirectedSystem (fun i ↦ (S i).cod) + (fun _ _ h ↦ Substructure.inclusion (cod_le_cod (S.monotone h))) where + map_self' := fun _ _ _ ↦ rfl + map_map' := fun _ _ _ ↦ rfl + +/-- The limit of a directed system of PartialEquivs. -/ +noncomputable def partialEquivLimit : M ≃ₚ[L] N where + dom := iSup (fun i ↦ (S i).dom) + cod := iSup (fun i ↦ (S i).cod) + toEquiv := + (Equiv_iSup { + toFun := (fun i ↦ (S i).cod) + monotone' := monotone_cod.comp S.monotone} + ).comp + ((DirectLimit.equiv_lift L ι (fun i ↦ (S i).dom) + (fun _ _ hij ↦ Substructure.inclusion (dom_le_dom (S.monotone hij))) + (fun i ↦ (S i).cod) + (fun _ _ hij ↦ Substructure.inclusion (cod_le_cod (S.monotone hij))) + (fun i ↦ (S i).toEquiv) + (fun _ _ hij _ ↦ toEquiv_inclusion_apply (S.monotone hij) _) + ).comp + (Equiv_iSup { + toFun := (fun i ↦ (S i).dom) + monotone' := monotone_dom.comp S.monotone}).symm) + +@[simp] +theorem dom_partialEquivLimit : (partialEquivLimit S).dom = iSup (fun x ↦ (S x).dom) := rfl + +@[simp] +theorem cod_partialEquivLimit : (partialEquivLimit S).cod = iSup (fun x ↦ (S x).cod) := rfl + +@[simp] +lemma partialEquivLimit_comp_inclusion {i : ι} : + (partialEquivLimit S).toEquiv.toEmbedding.comp (Substructure.inclusion (le_iSup _ i)) = + (Substructure.inclusion (le_iSup _ i)).comp (S i).toEquiv.toEmbedding := by + simp only [partialEquivLimit, Equiv.comp_toEmbedding, Embedding.comp_assoc] + rw [Equiv_isup_symm_inclusion] + congr + +theorem le_partialEquivLimit (i : ι) : S i ≤ partialEquivLimit S := + ⟨le_iSup (f := fun i ↦ (S i).dom) _, by + #adaptation_note /-- After lean4#5020, these two `simp` calls cannot be combined. -/ + simp only [partialEquivLimit_comp_inclusion] + simp only [cod_partialEquivLimit, dom_partialEquivLimit, ← Embedding.comp_assoc, + subtype_comp_inclusion]⟩ + +end DirectLimit + +section FGEquiv + +open PartialEquiv Set DirectLimit + +variable (M) (N) (L) + +/-- The type of equivalences between finitely generated substructures. -/ +abbrev FGEquiv := {f : M ≃ₚ[L] N // f.dom.FG} + +/-- Two structures `M` and `N` form an extension pair if the domain of any finitely-generated map +from `M` to `N` can be extended to include any element of `M`. -/ +def IsExtensionPair : Prop := ∀ (f : L.FGEquiv M N) (m : M), ∃ g, m ∈ g.1.dom ∧ f ≤ g + +variable {M N L} + +theorem countable_self_fgequiv_of_countable [Countable M] : + Countable (L.FGEquiv M M) := by + let g : L.FGEquiv M M → + Σ U : { S : L.Substructure M // S.FG }, U.val →[L] M := + fun f ↦ ⟨⟨f.val.dom, f.prop⟩, (subtype _).toHom.comp f.val.toEquiv.toHom⟩ + have g_inj : Function.Injective g := by + intro f f' h + ext + let ⟨⟨dom_f, cod_f, equiv_f⟩, f_fin⟩ := f + cases congr_arg (·.1) h + apply PartialEquiv.ext (by rfl) + simp only [g, Sigma.mk.inj_iff, heq_eq_eq, true_and] at h + exact fun x hx ↦ congr_fun (congr_arg (↑) h) ⟨x, hx⟩ + have : ∀ U : { S : L.Substructure M // S.FG }, Structure.FG L U.val := + fun U ↦ (U.val.fg_iff_structure_fg.1 U.prop) + exact Function.Embedding.countable ⟨g, g_inj⟩ + +instance inhabited_self_FGEquiv : Inhabited (L.FGEquiv M M) := + ⟨⟨⟨⊥, ⊥, Equiv.refl L (⊥ : L.Substructure M)⟩, fg_bot⟩⟩ + +instance inhabited_FGEquiv_of_IsEmpty_Constants_and_Relations + [IsEmpty L.Constants] [IsEmpty (L.Relations 0)] [L.Structure N] : + Inhabited (L.FGEquiv M N) := + ⟨⟨⟨⊥, ⊥, { + toFun := isEmptyElim + invFun := isEmptyElim + left_inv := isEmptyElim + right_inv := isEmptyElim + map_fun' := fun {n} f x => by + cases n + · exact isEmptyElim f + · exact isEmptyElim (x 0) + map_rel' := fun {n} r x => by + cases n + · exact isEmptyElim r + · exact isEmptyElim (x 0) + }⟩, fg_bot⟩⟩ + +/-- Maps to the symmetric finitely-generated partial equivalence. -/ +@[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 ↔ + ∀ (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 + +/-- The cofinal set of finite equivalences with a given element in their domain. -/ +def definedAtLeft + (h : L.IsExtensionPair M N) (m : M) : Order.Cofinal (FGEquiv L M N) where + carrier := {f | m ∈ f.val.dom} + mem_gt := fun f => h f m + +/-- The cofinal set of finite equivalences with a given element in their codomain. -/ +def definedAtRight + (h : L.IsExtensionPair N M) (n : N) : Order.Cofinal (FGEquiv L M N) where + carrier := {f | n ∈ f.val.cod} + mem_gt := fun f => h.cod f n + +end IsExtensionPair + +/-- For a countably generated structure `M` and a structure `N`, if any partial equivalence +between finitely generated substructures can be extended to any element in the domain, +then there exists an embedding of `M` in `N`. -/ +theorem embedding_from_cg (M_cg : Structure.CG L M) (g : L.FGEquiv M N) + (H : L.IsExtensionPair M N) : + ∃ f : M ↪[L] N, g ≤ f.toPartialEquiv := by + rcases M_cg with ⟨X, _, X_gen⟩ + have _ : Countable (↑X : Type _) := by simpa only [countable_coe_iff] + have _ : Encodable (↑X : Type _) := Encodable.ofCountable _ + let D : X → Order.Cofinal (FGEquiv L M N) := fun x ↦ H.definedAtLeft x + let S : ℕ →o M ≃ₚ[L] N := + ⟨Subtype.val ∘ (Order.sequenceOfCofinals g D), + (Subtype.mono_coe _).comp (Order.sequenceOfCofinals.monotone _ _)⟩ + let F := DirectLimit.partialEquivLimit S + have _ : X ⊆ F.dom := by + intro x hx + have := Order.sequenceOfCofinals.encode_mem g D ⟨x, hx⟩ + exact dom_le_dom + (le_partialEquivLimit S (Encodable.encode (⟨x, hx⟩ : X) + 1)) this + have isTop : F.dom = ⊤ := by rwa [← top_le_iff, ← X_gen, Substructure.closure_le] + exact ⟨toEmbeddingOfEqTop isTop, + by convert (le_partialEquivLimit S 0); apply Embedding.toPartialEquiv_toEmbedding⟩ + +/-- For two countably generated structure `M` and `N`, if any PartialEquiv +between finitely generated substructures can be extended to any element in the domain and to +any element in the codomain, then there exists an equivalence between `M` and `N`. -/ +theorem equiv_between_cg (M_cg : Structure.CG L M) (N_cg : Structure.CG L N) + (g : L.FGEquiv M N) + (ext_dom : L.IsExtensionPair M N) + (ext_cod : L.IsExtensionPair N M) : + ∃ f : M ≃[L] N, g ≤ f.toEmbedding.toPartialEquiv := by + rcases M_cg with ⟨X, X_count, X_gen⟩ + rcases N_cg with ⟨Y, Y_count, Y_gen⟩ + have _ : Countable (↑X : Type _) := by simpa only [countable_coe_iff] + have _ : Encodable (↑X : Type _) := Encodable.ofCountable _ + have _ : Countable (↑Y : Type _) := by simpa only [countable_coe_iff] + have _ : Encodable (↑Y : Type _) := Encodable.ofCountable _ + let D : Sum X Y → Order.Cofinal (FGEquiv L M N) := fun p ↦ + Sum.recOn p (fun x ↦ ext_dom.definedAtLeft x) (fun y ↦ ext_cod.definedAtRight y) + let S : ℕ →o M ≃ₚ[L] N := + ⟨Subtype.val ∘ (Order.sequenceOfCofinals g D), + (Subtype.mono_coe _).comp (Order.sequenceOfCofinals.monotone _ _)⟩ + let F := @DirectLimit.partialEquivLimit L M N _ _ ℕ _ _ _ S + have _ : X ⊆ F.dom := by + intro x hx + have := Order.sequenceOfCofinals.encode_mem g D (Sum.inl ⟨x, hx⟩) + exact dom_le_dom + (le_partialEquivLimit S (Encodable.encode (Sum.inl (⟨x, hx⟩ : X)) + 1)) this + have _ : Y ⊆ F.cod := by + intro y hy + have := Order.sequenceOfCofinals.encode_mem g D (Sum.inr ⟨y, hy⟩) + exact cod_le_cod + (le_partialEquivLimit S (Encodable.encode (Sum.inr (⟨y, hy⟩ : Y)) + 1)) this + have dom_top : F.dom = ⊤ := by rwa [← top_le_iff, ← X_gen, Substructure.closure_le] + have cod_top : F.cod = ⊤ := by rwa [← top_le_iff, ← Y_gen, Substructure.closure_le] + refine ⟨toEquivOfEqTop dom_top cod_top, ?_⟩ + convert le_partialEquivLimit S 0 + rw [toEquivOfEqTop_toEmbedding] + apply Embedding.toPartialEquiv_toEmbedding + +end FGEquiv + end Language end FirstOrder diff --git a/Mathlib/ModelTheory/Quotients.lean b/Mathlib/ModelTheory/Quotients.lean index 798514c512fb1..fef412e512ae8 100644 --- a/Mathlib/ModelTheory/Quotients.lean +++ b/Mathlib/ModelTheory/Quotients.lean @@ -64,9 +64,9 @@ theorem relMap_quotient_mk' {n : ℕ} (r : L.Relations n) (x : Fin n → M) : theorem Term.realize_quotient_mk' {β : Type*} (t : L.Term β) (x : β → M) : (t.realize fun i => (⟦x i⟧ : Quotient s)) = ⟦@Term.realize _ _ ps.toStructure _ x t⟧ := by - induction' t with _ _ _ _ ih - · rfl - · simp only [ih, funMap_quotient_mk', Term.realize] + induction t with + | var => rfl + | func _ _ ih => simp only [ih, funMap_quotient_mk', Term.realize] end Language diff --git a/Mathlib/ModelTheory/Satisfiability.lean b/Mathlib/ModelTheory/Satisfiability.lean index 3185e8db3b62c..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 @@ -571,15 +487,16 @@ theorem Categorical.isComplete (h : κ.Categorical T) (h1 : ℵ₀ ≤ κ) obtain ⟨TF⟩ := h (MNT.toModel T) (MNF.toModel T) hNT hNF exact ((MNT.realize_sentence φ).trans - ((TF.realize_sentence φ).trans (MNF.realize_sentence φ).symm)).1 hMT⟩ + ((StrongHomClass.realize_sentence TF φ).trans (MNF.realize_sentence φ).symm)).1 hMT⟩ theorem empty_theory_categorical (T : Language.empty.Theory) : κ.Categorical T := fun M N hM hN => by rw [empty.nonempty_equiv_iff, hM, hN] theorem empty_infinite_Theory_isComplete : Language.empty.infiniteTheory.IsComplete := (empty_theory_categorical.{0} ℵ₀ _).isComplete ℵ₀ _ le_rfl (by simp) - ⟨Theory.Model.bundled ((model_infiniteTheory_iff Language.empty).2 - (inferInstanceAs (Infinite ℕ)))⟩ fun M => - (model_infiniteTheory_iff Language.empty).1 M.is_model + ⟨by + haveI : Language.empty.Structure ℕ := emptyStructure + exact ((model_infiniteTheory_iff Language.empty).2 (inferInstanceAs (Infinite ℕ))).bundled⟩ + fun M => (model_infiniteTheory_iff Language.empty).1 M.is_model end Cardinal diff --git a/Mathlib/ModelTheory/Semantics.lean b/Mathlib/ModelTheory/Semantics.lean index 41d4021996c56..3da6c40283d18 100644 --- a/Mathlib/ModelTheory/Semantics.lean +++ b/Mathlib/ModelTheory/Semantics.lean @@ -122,16 +122,17 @@ theorem realize_con {A : Set M} {a : A} {v : α → M} : (L.con a).term.realize @[simp] theorem realize_subst {t : L.Term α} {tf : α → L.Term β} {v : β → M} : (t.subst tf).realize v = t.realize fun a => (tf a).realize v := by - induction' t with _ _ _ _ ih - · rfl - · simp [ih] + induction t with + | var => rfl + | func _ _ ih => simp [ih] @[simp] theorem realize_restrictVar [DecidableEq α] {t : L.Term α} {s : Set α} (h : ↑t.varFinset ⊆ s) {v : α → M} : (t.restrictVar (Set.inclusion h)).realize (v ∘ (↑)) = t.realize v := by - induction' t with _ _ _ _ ih - · rfl - · simp_rw [varFinset, Finset.coe_biUnion, Set.iUnion_subset_iff] at h + induction t with + | var => rfl + | func _ _ ih => + simp_rw [varFinset, Finset.coe_biUnion, Set.iUnion_subset_iff] at h exact congr rfl (funext fun i => ih i (h i (Finset.mem_univ i))) @[simp] @@ -139,9 +140,10 @@ theorem realize_restrictVarLeft [DecidableEq α] {γ : Type*} {t : L.Term (α (h : ↑t.varFinsetLeft ⊆ s) {v : α → M} {xs : γ → M} : (t.restrictVarLeft (Set.inclusion h)).realize (Sum.elim (v ∘ (↑)) xs) = t.realize (Sum.elim v xs) := by - induction' t with a _ _ _ ih - · cases a <;> rfl - · simp_rw [varFinsetLeft, Finset.coe_biUnion, Set.iUnion_subset_iff] at h + induction t with + | var a => cases a <;> rfl + | func _ _ ih => + simp_rw [varFinsetLeft, Finset.coe_biUnion, Set.iUnion_subset_iff] at h exact congr rfl (funext fun i => ih i (h i (Finset.mem_univ i))) @[simp] @@ -152,13 +154,13 @@ theorem realize_constantsToVars [L[[α]].Structure M] [(lhomWithConstants L α). · simp · cases n · cases f - · simp only [realize, ih, Nat.zero_eq, constantsOn, mk₂_Functions] + · simp only [realize, ih, constantsOn, constantsOnFunc] -- Porting note: below lemma does not work with simp for some reason rw [withConstants_funMap_sum_inl] · simp only [realize, constantsToVars, Sum.elim_inl, funMap_eq_coe_constants] rfl · cases' f with _ f - · simp only [realize, ih, constantsOn, mk₂_Functions] + · simp only [realize, ih, constantsOn, constantsOnFunc] -- Porting note: below lemma does not work with simp for some reason rw [withConstants_funMap_sum_inl] · exact isEmptyElim f @@ -172,7 +174,7 @@ theorem realize_varsToConstants [L[[α]].Structure M] [(lhomWithConstants L α). -- Porting note: both cases were `simp [Language.con]` · simp [Language.con, realize, funMap_eq_coe_constants] · simp [realize, constantMap] - · simp only [realize, constantsOn, mk₂_Functions, ih] + · simp only [realize, constantsOn, constantsOnFunc, ih] -- Porting note: below lemma does not work with simp for some reason rw [withConstants_funMap_sum_inl] @@ -201,25 +203,16 @@ theorem realize_onTerm [L'.Structure M] (φ : L →ᴸ L') [φ.IsExpansionOn M] end LHom @[simp] -theorem Hom.realize_term (g : M →[L] N) {t : L.Term α} {v : α → M} : +theorem HomClass.realize_term {F : Type*} [FunLike F M N] [HomClass L F M N] + (g : F) {t : L.Term α} {v : α → M} : t.realize (g ∘ v) = g (t.realize v) := by induction t · rfl - · rw [Term.realize, Term.realize, g.map_fun] + · rw [Term.realize, Term.realize, HomClass.map_fun] refine congr rfl ?_ ext x simp [*] -@[simp] -theorem Embedding.realize_term {v : α → M} (t : L.Term α) (g : M ↪[L] N) : - t.realize (g ∘ v) = g (t.realize v) := - g.toHom.realize_term - -@[simp] -theorem Equiv.realize_term {v : α → M} (t : L.Term α) (g : M ≃[L] N) : - t.realize (g ∘ v) = g (t.realize v) := - g.toHom.realize_term - variable {n : ℕ} namespace BoundedFormula @@ -330,12 +323,12 @@ theorem realize_mapTermRel_id [L'.Structure M] (ft n t).realize (Sum.elim v' xs) = t.realize (Sum.elim v xs)) (h2 : ∀ (n) (R : L.Relations n) (x : Fin n → M), RelMap (fr n R) x = RelMap R x) : (φ.mapTermRel ft fr fun _ => id).Realize v' xs ↔ φ.Realize v xs := by - induction' φ with _ _ _ _ _ _ _ _ _ _ _ ih1 ih2 _ _ ih - · rfl - · simp [mapTermRel, Realize, h1] - · simp [mapTermRel, Realize, h1, h2] - · simp [mapTermRel, Realize, ih1, ih2] - · simp only [mapTermRel, Realize, ih, id] + induction φ with + | falsum => rfl + | equal => simp [mapTermRel, Realize, h1] + | rel => simp [mapTermRel, Realize, h1, h2] + | imp _ _ ih1 ih2 => simp [mapTermRel, Realize, ih1, ih2] + | all _ ih => simp only [mapTermRel, Realize, ih, id] theorem realize_mapTermRel_add_castLe [L'.Structure M] {k : ℕ} {ft : ∀ n, L.Term (α ⊕ (Fin n)) → L'.Term (β ⊕ (Fin (k + n)))} @@ -348,31 +341,32 @@ theorem realize_mapTermRel_add_castLe [L'.Structure M] {k : ℕ} (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 ↔ φ.Realize (v xs) (xs ∘ Fin.natAdd _) := by - induction' φ with _ _ _ _ _ _ _ _ _ _ _ ih1 ih2 _ _ ih - · rfl - · simp [mapTermRel, Realize, h1] - · simp [mapTermRel, Realize, h1, h2] - · simp [mapTermRel, Realize, ih1, ih2] - · simp [mapTermRel, Realize, ih, hv] + induction φ with + | falsum => rfl + | equal => simp [mapTermRel, Realize, h1] + | rel => simp [mapTermRel, Realize, h1, h2] + | imp _ _ ih1 ih2 => simp [mapTermRel, Realize, ih1, ih2] + | all _ ih => simp [mapTermRel, Realize, ih, hv] @[simp] theorem realize_relabel {m n : ℕ} {φ : L.BoundedFormula α n} {g : α → β ⊕ (Fin m)} {v : β → M} {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) : (φ.liftAt n' m).Realize v xs ↔ φ.Realize v (xs ∘ fun i => if ↑i < m then Fin.castAdd n' i else Fin.addNat i n') := by rw [liftAt] - induction' φ with _ _ _ _ _ _ _ _ _ _ _ ih1 ih2 k _ ih3 - · simp [mapTermRel, Realize] - · simp [mapTermRel, Realize, realize_rel, realize_liftAt, Sum.elim_comp_map] - · simp [mapTermRel, Realize, realize_rel, realize_liftAt, Sum.elim_comp_map] - · simp only [mapTermRel, Realize, ih1 hmn, ih2 hmn] - · have h : k + 1 + n' = k + n' + 1 := by rw [add_assoc, add_comm 1 n', ← add_assoc] + induction φ with + | falsum => simp [mapTermRel, Realize] + | equal => simp [mapTermRel, Realize, realize_rel, realize_liftAt, Sum.elim_comp_map] + | rel => simp [mapTermRel, Realize, realize_rel, realize_liftAt, Sum.elim_comp_map] + | imp _ _ ih1 ih2 => simp only [mapTermRel, Realize, ih1 hmn, ih2 hmn] + | @all k _ ih3 => + have h : k + 1 + n' = k + n' + 1 := by rw [add_assoc, add_comm 1 n', ← add_assoc] simp only [mapTermRel, Realize, realize_castLE_of_eq h, ih3 (hmn.trans k.succ.le_succ)] refine forall_congr' fun x => iff_eq_eq.mpr (congr rfl (funext (Fin.lastCases ?_ fun i => ?_))) · simp only [Function.comp_apply, val_last, snoc_last] @@ -420,12 +414,22 @@ theorem realize_subst {φ : L.BoundedFormula α n} {tf : α → L.Term β} {v : theorem realize_restrictFreeVar [DecidableEq α] {n : ℕ} {φ : L.BoundedFormula α n} {s : Set α} (h : ↑φ.freeVarFinset ⊆ s) {v : α → M} {xs : Fin n → M} : (φ.restrictFreeVar (Set.inclusion h)).Realize (v ∘ (↑)) xs ↔ φ.Realize v xs := by - induction' φ with _ _ _ _ _ _ _ _ _ _ _ ih1 ih2 _ _ ih3 - · rfl - · simp [restrictFreeVar, Realize] - · simp [restrictFreeVar, Realize] - · simp [restrictFreeVar, Realize, ih1, ih2] - · simp [restrictFreeVar, Realize, ih3] + induction φ with + | falsum => rfl + | equal => + simp only [Realize, freeVarFinset.eq_2] + rw [Set.inclusion_comp_inclusion, Set.inclusion_comp_inclusion] + simp + | rel => + simp only [Realize, freeVarFinset.eq_3, Finset.biUnion_val] + congr! + erw [Set.inclusion_comp_inclusion _ h] + simp + | imp _ _ ih1 ih2 => + simp only [Realize, freeVarFinset.eq_4] + rw [Set.inclusion_comp_inclusion, Set.inclusion_comp_inclusion] + simp [ih1, ih2] + | all _ ih3 => simp [restrictFreeVar, Realize, ih3] theorem realize_constantsVarsEquiv [L[[α]].Structure M] [(lhomWithConstants L α).IsExpansionOn M] {n} {φ : L[[α]].BoundedFormula β n} {v : β → M} {xs : Fin n → M} : @@ -476,15 +480,15 @@ open BoundedFormula theorem realize_onBoundedFormula [L'.Structure M] (φ : L →ᴸ L') [φ.IsExpansionOn M] {n : ℕ} (ψ : L.BoundedFormula α n) {v : α → M} {xs : Fin n → M} : (φ.onBoundedFormula ψ).Realize v xs ↔ ψ.Realize v xs := by - induction' ψ with _ _ _ _ _ _ _ _ _ _ _ ih1 ih2 _ _ ih3 - · rfl - · simp only [onBoundedFormula, realize_bdEqual, realize_onTerm] - rfl - · simp only [onBoundedFormula, realize_rel, LHom.map_onRelation, + induction ψ with + | falsum => rfl + | equal => simp only [onBoundedFormula, realize_bdEqual, realize_onTerm]; rfl + | rel => + simp only [onBoundedFormula, realize_rel, LHom.map_onRelation, Function.comp_apply, realize_onTerm] rfl - · simp only [onBoundedFormula, ih1, ih2, realize_imp] - · simp only [onBoundedFormula, ih3, realize_all] + | imp _ _ ih1 ih2 => simp only [onBoundedFormula, ih1, ih2, realize_imp] + | all _ ih3 => simp only [onBoundedFormula, ih3, realize_all] end LHom @@ -698,8 +702,12 @@ theorem model_union_iff {T' : L.Theory} : M ⊨ T ∪ T' ↔ M ⊨ T ∧ M ⊨ T ⟨fun h => ⟨h.mono Set.subset_union_left, h.mono Set.subset_union_right⟩, fun h => h.1.union h.2⟩ +@[simp] theorem model_singleton_iff {φ : L.Sentence} : M ⊨ ({φ} : L.Theory) ↔ M ⊨ φ := by simp +theorem model_insert_iff {φ : L.Sentence} : M ⊨ insert φ T ↔ M ⊨ φ ∧ M ⊨ T := by + rw [Set.insert_eq, model_union_iff, model_singleton_iff] + theorem model_iff_subset_completeTheory : M ⊨ T ↔ T ⊆ L.completeTheory M := T.model_iff @@ -752,12 +760,12 @@ theorem _root_.FirstOrder.Language.Formula.realize_iAlls ∀ (i : γ → M), φ.Realize (fun a => Sum.elim v i (f a)) := by let e := Classical.choice (Classical.choose_spec (Finite.exists_equiv_fin γ)) rw [Formula.iAlls] - simp only [Nat.add_zero, realize_alls, realize_relabel, Function.comp, + simp only [Nat.add_zero, realize_alls, realize_relabel, Function.comp_def, castAdd_zero, finCongr_refl, OrderIso.refl_apply, Sum.elim_map, id_eq] refine Equiv.forall_congr ?_ ?_ · exact ⟨fun v => v ∘ e, fun v => v ∘ e.symm, - fun _ => by simp [Function.comp], - fun _ => by simp [Function.comp]⟩ + fun _ => by simp [Function.comp_def], + fun _ => by simp [Function.comp_def]⟩ · intro x rw [Formula.Realize, iff_iff_eq] congr @@ -778,13 +786,13 @@ theorem _root_.FirstOrder.Language.Formula.realize_iExs ∃ (i : γ → M), φ.Realize (fun a => Sum.elim v i (f a)) := by let e := Classical.choice (Classical.choose_spec (Finite.exists_equiv_fin γ)) rw [Formula.iExs] - simp only [Nat.add_zero, realize_exs, realize_relabel, Function.comp, + simp only [Nat.add_zero, realize_exs, realize_relabel, Function.comp_def, castAdd_zero, finCongr_refl, OrderIso.refl_apply, Sum.elim_map, id_eq] rw [← not_iff_not, not_exists, not_exists] refine Equiv.forall_congr ?_ ?_ · exact ⟨fun v => v ∘ e, fun v => v ∘ e.symm, - fun _ => by simp [Function.comp], - fun _ => by simp [Function.comp]⟩ + fun _ => by simp [Function.comp_def], + fun _ => by simp [Function.comp_def]⟩ · intro x rw [Formula.Realize, iff_iff_eq] congr @@ -801,18 +809,20 @@ theorem realize_iExs [Finite γ] {f : α → β ⊕ γ} @[simp] theorem realize_toFormula (φ : L.BoundedFormula α n) (v : α ⊕ (Fin n) → M) : φ.toFormula.Realize v ↔ φ.Realize (v ∘ Sum.inl) (v ∘ Sum.inr) := by - induction' φ with _ _ _ _ _ _ _ _ _ _ _ ih1 ih2 _ _ ih3 a8 a9 a0 - · rfl - · simp [BoundedFormula.Realize] - · simp [BoundedFormula.Realize] - · rw [toFormula, Formula.Realize, realize_imp, ← Formula.Realize, ih1, ← Formula.Realize, ih2, + induction φ with + | falsum => rfl + | equal => simp [BoundedFormula.Realize] + | rel => simp [BoundedFormula.Realize] + | imp _ _ ih1 ih2 => + rw [toFormula, Formula.Realize, realize_imp, ← Formula.Realize, ih1, ← Formula.Realize, ih2, realize_imp] - · rw [toFormula, Formula.Realize, realize_all, realize_all] + | all _ ih3 => + rw [toFormula, Formula.Realize, realize_all, realize_all] refine forall_congr' fun a => ?_ have h := ih3 (Sum.elim (v ∘ Sum.inl) (snoc (v ∘ Sum.inr) a)) simp only [Sum.elim_comp_inl, Sum.elim_comp_inr] at h rw [← h, realize_relabel, Formula.Realize, iff_iff_eq] - simp only [Function.comp] + simp only [Function.comp_def] congr with x · cases' x with _ x · simp @@ -842,44 +852,53 @@ theorem realize_iInf (s : Finset β) (f : β → L.BoundedFormula α n) end BoundedFormula -namespace Equiv +namespace StrongHomClass + +variable {F : Type*} [EquivLike F M N] [StrongHomClass L F M N] (g : F) @[simp] -theorem realize_boundedFormula (g : M ≃[L] N) (φ : L.BoundedFormula α n) {v : α → M} +theorem realize_boundedFormula (φ : L.BoundedFormula α n) {v : α → M} {xs : Fin n → M} : φ.Realize (g ∘ v) (g ∘ xs) ↔ φ.Realize v xs := by - induction' φ with _ _ _ _ _ _ _ _ _ _ _ ih1 ih2 _ _ ih3 - · rfl - · simp only [BoundedFormula.Realize, ← Sum.comp_elim, Equiv.realize_term, g.injective.eq_iff] - · simp only [BoundedFormula.Realize, ← Sum.comp_elim, Equiv.realize_term] - exact g.map_rel _ _ - · rw [BoundedFormula.Realize, ih1, ih2, BoundedFormula.Realize] - · rw [BoundedFormula.Realize, BoundedFormula.Realize] + induction φ with + | falsum => rfl + | equal => + simp only [BoundedFormula.Realize, ← Sum.comp_elim, HomClass.realize_term, + EmbeddingLike.apply_eq_iff_eq g] + | rel => + simp only [BoundedFormula.Realize, ← Sum.comp_elim, HomClass.realize_term] + exact StrongHomClass.map_rel g _ _ + | imp _ _ ih1 ih2 => rw [BoundedFormula.Realize, ih1, ih2, BoundedFormula.Realize] + | all _ ih3 => + rw [BoundedFormula.Realize, BoundedFormula.Realize] constructor · intro h a have h' := h (g a) rw [← Fin.comp_snoc, ih3] at h' exact h' · intro h a - have h' := h (g.symm a) - rw [← ih3, Fin.comp_snoc, g.apply_symm_apply] at h' + have h' := h (EquivLike.inv g a) + rw [← ih3, Fin.comp_snoc, EquivLike.apply_inv_apply g] at h' exact h' @[simp] -theorem realize_formula (g : M ≃[L] N) (φ : L.Formula α) {v : α → M} : +theorem realize_formula (φ : L.Formula α) {v : α → M} : φ.Realize (g ∘ v) ↔ φ.Realize v := by - rw [Formula.Realize, Formula.Realize, ← g.realize_boundedFormula φ, iff_eq_eq, + rw [Formula.Realize, Formula.Realize, ← realize_boundedFormula g φ, iff_eq_eq, Unique.eq_default (g ∘ default)] -theorem realize_sentence (g : M ≃[L] N) (φ : L.Sentence) : M ⊨ φ ↔ N ⊨ φ := by - rw [Sentence.Realize, Sentence.Realize, ← g.realize_formula, Unique.eq_default (g ∘ default)] +include g + +theorem realize_sentence (φ : L.Sentence) : M ⊨ φ ↔ N ⊨ φ := by + rw [Sentence.Realize, Sentence.Realize, ← realize_formula g, + Unique.eq_default (g ∘ default)] -theorem theory_model (g : M ≃[L] N) [M ⊨ T] : N ⊨ T := - ⟨fun φ hφ => (g.realize_sentence φ).1 (Theory.realize_sentence_of_mem T hφ)⟩ +theorem theory_model [M ⊨ T] : N ⊨ T := + ⟨fun φ hφ => (realize_sentence g φ).1 (Theory.realize_sentence_of_mem T hφ)⟩ -theorem elementarilyEquivalent (g : M ≃[L] N) : M ≅[L] N := - elementarilyEquivalent_iff.2 g.realize_sentence +theorem elementarilyEquivalent : M ≅[L] N := + elementarilyEquivalent_iff.2 (realize_sentence g) -end Equiv +end StrongHomClass namespace Relations @@ -927,7 +946,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/Skolem.lean b/Mathlib/ModelTheory/Skolem.lean index eefcbc6d811c1..0ff7aa3c3c2b8 100644 --- a/Mathlib/ModelTheory/Skolem.lean +++ b/Mathlib/ModelTheory/Skolem.lean @@ -82,11 +82,11 @@ theorem skolem₁_reduct_isElementary (S : (L.sum L.skolem₁).Substructure M) : apply (LHom.sumInl.substructureReduct S).isElementary_of_exists intro n φ x a h let φ' : (L.sum L.skolem₁).Functions n := LHom.sumInr.onFunction φ - exact - ⟨⟨funMap φ' ((↑) ∘ x), S.fun_mem (LHom.sumInr.onFunction φ) ((↑) ∘ x) (by - exact fun i => (x i).2)⟩, - by exact Classical.epsilon_spec (p := fun a => BoundedFormula.Realize φ default - (Fin.snoc (Subtype.val ∘ x) a)) ⟨a, h⟩⟩ + use ⟨funMap φ' ((↑) ∘ x), ?_⟩ + · exact Classical.epsilon_spec (p := fun a => BoundedFormula.Realize φ default + (Fin.snoc (Subtype.val ∘ x) a)) ⟨a, h⟩ + · exact S.fun_mem (LHom.sumInr.onFunction φ) ((↑) ∘ x) (by + exact fun i => (x i).2) /-- Any `L.sum L.skolem₁`-substructure is an elementary `L`-substructure. -/ noncomputable def elementarySkolem₁Reduct (S : (L.sum L.skolem₁).Substructure M) : @@ -116,7 +116,7 @@ variable {M} /-- The **Downward Löwenheim–Skolem theorem** : If `s` is a set in an `L`-structure `M` and `κ` an infinite cardinal such that `max (#s, L.card) ≤ κ` and `κ ≤ # M`, then `M` has an elementary substructure containing `s` of - cardinality `κ`. -/ + cardinality `κ`. -/ theorem exists_elementarySubstructure_card_eq (s : Set M) (κ : Cardinal.{w'}) (h1 : ℵ₀ ≤ κ) (h2 : Cardinal.lift.{w'} #s ≤ Cardinal.lift.{w} κ) (h3 : Cardinal.lift.{w'} L.card ≤ Cardinal.lift.{max u v} κ) diff --git a/Mathlib/ModelTheory/Substructures.lean b/Mathlib/ModelTheory/Substructures.lean index b08cea3eb212d..0fc0993999295 100644 --- a/Mathlib/ModelTheory/Substructures.lean +++ b/Mathlib/ModelTheory/Substructures.lean @@ -3,6 +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, Gabin Kolly -/ +import Mathlib.Data.Fintype.Order import Mathlib.Order.Closure import Mathlib.ModelTheory.Semantics import Mathlib.ModelTheory.Encoding @@ -288,8 +289,28 @@ theorem lift_card_closure_le : refine lift_card_closure_le_card_term.trans (Term.card_le.trans ?_) rw [mk_sum, lift_umax.{w, u}] +lemma mem_closed_iff (s : Set M) : + s ∈ (closure L).closed ↔ ∀ {n}, ∀ f : L.Functions n, ClosedUnder f s := by + refine ⟨fun h n f => ?_, fun h => ?_⟩ + · rw [← h] + exact Substructure.fun_mem _ _ + · have h' : closure L s = ⟨s, h⟩ := closure_eq_of_le (refl _) subset_closure + exact congr_arg _ h' + variable (L) +lemma mem_closed_of_isRelational [L.IsRelational] (s : Set M) : s ∈ (closure L).closed := + (mem_closed_iff s).2 isEmptyElim + +@[simp] +lemma closure_eq_of_isRelational [L.IsRelational] (s : Set M) : closure L s = s := + LowerAdjoint.closure_eq_self_of_mem_closed _ (mem_closed_of_isRelational L 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_eq_of_isRelational] + theorem _root_.Set.Countable.substructure_closure [Countable (Σl, L.Functions l)] (h : s.Countable) : Countable.{w + 1} (closure L s) := by haveI : Countable s := h.to_subtype @@ -341,14 +362,55 @@ theorem closure_univ : closure L (univ : Set M) = ⊤ := theorem closure_union (s t : Set M) : closure L (s ∪ t) = closure L s ⊔ closure L t := (Substructure.gi L M).gc.l_sup -theorem closure_unionᵢ {ι} (s : ι → Set M) : closure L (⋃ i, s i) = ⨆ i, closure L (s i) := +theorem closure_iUnion {ι} (s : ι → Set M) : closure L (⋃ i, s i) = ⨆ i, closure L (s i) := (Substructure.gi L M).gc.l_iSup +theorem closure_insert (s : Set M) (m : M) : closure L (insert m s) = closure L {m} ⊔ closure L s := + closure_union {m} s + instance small_bot : Small.{u} (⊥ : L.Substructure M) := by rw [← closure_empty] haveI : Small.{u} (∅ : Set M) := small_subsingleton _ exact Substructure.small_closure +theorem iSup_eq_closure {ι : Sort*} (S : ι → L.Substructure M) : + ⨆ i, S i = closure L (⋃ i, (S i : Set M)) := by simp_rw [closure_iUnion, closure_eq] + +-- This proof uses the fact that `Substructure.closure` is finitary. +theorem mem_iSup_of_directed {ι : Type*} [hι : Nonempty ι] {S : ι → L.Substructure M} + (hS : Directed (· ≤ ·) S) {x : M} : + x ∈ ⨆ i, S i ↔ ∃ i, x ∈ S i := by + refine ⟨?_, fun ⟨i, hi⟩ ↦ le_iSup S i hi⟩ + suffices x ∈ closure L (⋃ 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) (fun f v hC ↦ ?_) + simp_rw [Set.mem_setOf] at * + have ⟨i, hi⟩ := hS.finite_le (fun i ↦ Classical.choose (hC i)) + refine ⟨i, (S i).fun_mem f v (fun j ↦ hi j (Classical.choose_spec (hC j)))⟩ + +-- This proof uses the fact that `Substructure.closure` is finitary. +theorem mem_sSup_of_directedOn {S : Set (L.Substructure M)} (Sne : S.Nonempty) + (hS : DirectedOn (· ≤ ·) S) {x : M} : + x ∈ sSup S ↔ ∃ s ∈ S, x ∈ s := by + haveI : Nonempty S := Sne.to_subtype + simp only [sSup_eq_iSup', mem_iSup_of_directed hS.directed_val, Subtype.exists, exists_prop] + +variable (L) (M) + +instance [IsEmpty L.Constants] : IsEmpty (⊥ : L.Substructure M) := by + refine (isEmpty_subtype _).2 (fun x => ?_) + have h : (∅ : Set M) ∈ (closure L).closed := by + rw [mem_closed_iff] + intro n f + cases n + · exact isEmptyElim f + · intro x hx + simp only [mem_empty_iff_false, forall_const] at hx + rw [← closure_empty, ← SetLike.mem_coe, h] + exact Set.not_mem_empty _ + +variable {L} {M} + /-! ### `comap` and `map` -/ @@ -437,7 +499,7 @@ theorem map_sup (S T : L.Substructure M) (f : M →[L] N) : (S ⊔ T).map f = S. (gc_map_comap f).l_sup theorem map_iSup {ι : Sort*} (f : M →[L] N) (s : ι → L.Substructure M) : - (iSup s).map f = ⨆ i, (s i).map f := + (⨆ i, s i).map f = ⨆ i, (s i).map f := (gc_map_comap f).l_iSup theorem comap_inf (S T : L.Substructure N) (f : M →[L] N) : @@ -445,7 +507,7 @@ theorem comap_inf (S T : L.Substructure N) (f : M →[L] N) : (gc_map_comap f).u_inf theorem comap_iInf {ι : Sort*} (f : M →[L] N) (s : ι → L.Substructure N) : - (iInf s).comap f = ⨅ i, (s i).comap f := + (⨅ i, s i).comap f = ⨅ i, (s i).comap f := (gc_map_comap f).u_iInf @[simp] @@ -458,7 +520,7 @@ theorem comap_top (f : M →[L] N) : (⊤ : L.Substructure N).comap f = ⊤ := @[simp] theorem map_id (S : L.Substructure M) : S.map (Hom.id L M) = S := - ext fun _ => ⟨fun ⟨_, h, rfl⟩ => h, fun h => ⟨_, h, rfl⟩⟩ + SetLike.coe_injective <| Set.image_id _ theorem map_closure (f : M →[L] N) (s : Set M) : (closure L s).map f = closure L (f '' s) := Eq.symm <| @@ -493,14 +555,14 @@ theorem comap_inf_map_of_injective (S T : L.Substructure M) : (S.map f ⊓ T.map (gciMapComap hf).u_inf_l _ _ theorem comap_iInf_map_of_injective (S : ι → L.Substructure M) : - (⨅ i, (S i).map f).comap f = iInf S := + (⨅ i, (S i).map f).comap f = ⨅ i, S i := (gciMapComap hf).u_iInf_l _ theorem comap_sup_map_of_injective (S T : L.Substructure M) : (S.map f ⊔ T.map f).comap f = S ⊔ T := (gciMapComap hf).u_sup_l _ _ theorem comap_iSup_map_of_injective (S : ι → L.Substructure M) : - (⨆ i, (S i).map f).comap f = iSup S := + (⨆ i, (S i).map f).comap f = ⨆ i, S i := (gciMapComap hf).u_iSup_l _ theorem map_le_map_iff_of_injective {S T : L.Substructure M} : S.map f ≤ T.map f ↔ S ≤ T := @@ -536,7 +598,7 @@ theorem map_inf_comap_of_surjective (S T : L.Substructure N) : (giMapComap hf).l_inf_u _ _ theorem map_iInf_comap_of_surjective (S : ι → L.Substructure N) : - (⨅ i, (S i).comap f).map f = iInf S := + (⨅ i, (S i).comap f).map f = ⨅ i, S i := (giMapComap hf).l_iInf_u _ theorem map_sup_comap_of_surjective (S T : L.Substructure N) : @@ -544,7 +606,7 @@ theorem map_sup_comap_of_surjective (S T : L.Substructure N) : (giMapComap hf).l_sup_u _ _ theorem map_iSup_comap_of_surjective (S : ι → L.Substructure N) : - (⨆ i, (S i).comap f).map f = iSup S := + (⨆ i, (S i).comap f).map f = ⨆ i, S i := (giMapComap hf).l_iSup_u _ theorem comap_le_comap_iff_of_surjective {S T : L.Substructure N} : S.comap f ≤ T.comap f ↔ S ≤ T := @@ -584,13 +646,13 @@ theorem coe_topEquiv : theorem realize_boundedFormula_top {α : Type*} {n : ℕ} {φ : L.BoundedFormula α n} {v : α → (⊤ : L.Substructure M)} {xs : Fin n → (⊤ : L.Substructure M)} : φ.Realize v xs ↔ φ.Realize (((↑) : _ → M) ∘ v) ((↑) ∘ xs) := by - rw [← Substructure.topEquiv.realize_boundedFormula φ] + rw [← StrongHomClass.realize_boundedFormula Substructure.topEquiv φ] simp @[simp] theorem realize_formula_top {α : Type*} {φ : L.Formula α} {v : α → (⊤ : L.Substructure M)} : φ.Realize v ↔ φ.Realize (((↑) : (⊤ : L.Substructure M) → M) ∘ v) := by - rw [← Substructure.topEquiv.realize_formula φ] + rw [← StrongHomClass.realize_formula Substructure.topEquiv φ] simp /-- A dependent version of `Substructure.closure_induction`. -/ @@ -677,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 @@ -841,7 +903,7 @@ theorem subtype_substructureEquivMap (f : M ↪[L] N) (s : L.Substructure M) : ext; rfl /-- The equivalence between the domain and the range of an embedding `f`. -/ -noncomputable def equivRange (f : M ↪[L] N) : M ≃[L] f.toHom.range where +@[simps toEquiv_apply] noncomputable def equivRange (f : M ↪[L] N) : M ≃[L] f.toHom.range where toFun := codRestrict f.toHom.range f f.toHom.mem_range_self invFun n := Classical.choose n.2 left_inv m := @@ -864,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 @@ -890,6 +952,10 @@ theorem range_subtype (S : L.Substructure M) : S.subtype.toHom.range = S := by rintro ⟨⟨y, hy⟩, rfl⟩ exact hy +@[simp] +lemma subtype_comp_inclusion {S T : L.Substructure M} (h : S ≤ T) : + T.subtype.comp (inclusion h) = S.subtype := rfl + end Substructure end Language diff --git a/Mathlib/ModelTheory/Syntax.lean b/Mathlib/ModelTheory/Syntax.lean index d77cfb5bd2104..7fa52ce76edb5 100644 --- a/Mathlib/ModelTheory/Syntax.lean +++ b/Mathlib/ModelTheory/Syntax.lean @@ -79,6 +79,18 @@ variable {L} namespace Term +instance instDecidableEq [DecidableEq α] [∀ n, DecidableEq (L.Functions n)] : DecidableEq (L.Term α) + | .var a, .var b => decidable_of_iff (a = b) <| by simp + | @Term.func _ _ m f xs, @Term.func _ _ n g ys => + if h : m = n then + 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] + else + .isFalse <| by simp [h] + | .var _, .func _ _ | .func _ _, .var _ => .isFalse <| by simp + open Finset /-- The `Finset` of variables used in a given term. -/ @@ -102,9 +114,9 @@ def relabel (g : α → β) : L.Term α → L.Term β | func f ts => func f fun {i} => (ts i).relabel g theorem relabel_id (t : L.Term α) : t.relabel id = t := by - induction' t with _ _ _ _ ih - · rfl - · simp [ih] + induction t with + | var => rfl + | func _ _ ih => simp [ih] @[simp] theorem relabel_id_eq_id : (Term.relabel id : L.Term α → L.Term α) = id := @@ -113,9 +125,9 @@ theorem relabel_id_eq_id : (Term.relabel id : L.Term α → L.Term α) = id := @[simp] theorem relabel_relabel (f : α → β) (g : β → γ) (t : L.Term α) : (t.relabel f).relabel g = t.relabel (g ∘ f) := by - induction' t with _ _ _ _ ih - · rfl - · simp [ih] + induction t with + | var => rfl + | func _ _ ih => simp [ih] @[simp] theorem relabel_comp_relabel (f : α → β) (g : β → γ) : @@ -185,9 +197,10 @@ def varsToConstants : L.Term (γ ⊕ α) → L[[γ]].Term α def constantsVarsEquiv : L[[γ]].Term α ≃ L.Term (γ ⊕ α) := ⟨constantsToVars, varsToConstants, by intro t - induction' t with _ n f _ ih - · rfl - · cases n + induction t with + | var => rfl + | @func n f _ ih => + cases n · cases f · simp [constantsToVars, varsToConstants, ih] · simp [constantsToVars, varsToConstants, Constants.term, eq_iff_true_of_subsingleton] @@ -248,19 +261,17 @@ def onTerm (φ : L →ᴸ L') : L.Term α → L'.Term α @[simp] theorem id_onTerm : ((LHom.id L).onTerm : L.Term α → L.Term α) = id := by ext t - induction' t with _ _ _ _ ih - · rfl - · simp_rw [onTerm, ih] - rfl + induction t with + | var => rfl + | func _ _ ih => simp_rw [onTerm, ih]; rfl @[simp] theorem comp_onTerm {L'' : Language} (φ : L' →ᴸ L'') (ψ : L →ᴸ L') : ((φ.comp ψ).onTerm : L.Term α → L''.Term α) = φ.onTerm ∘ ψ.onTerm := by ext t - induction' t with _ _ _ _ ih - · rfl - · simp_rw [onTerm, ih] - rfl + induction t with + | var => rfl + | func _ _ ih => simp_rw [onTerm, ih]; rfl end LHom @@ -390,25 +401,27 @@ def castLE : ∀ {m n : ℕ} (_h : m ≤ n), L.BoundedFormula α m → L.Bounded @[simp] theorem castLE_rfl {n} (h : n ≤ n) (φ : L.BoundedFormula α n) : φ.castLE h = φ := by - induction' φ with _ _ _ _ _ _ _ _ _ _ _ ih1 ih2 _ _ ih3 - · rfl - · simp [Fin.castLE_of_eq] - · simp [Fin.castLE_of_eq] - · simp [Fin.castLE_of_eq, ih1, ih2] - · simp [Fin.castLE_of_eq, ih3] + induction φ with + | falsum => rfl + | equal => simp [Fin.castLE_of_eq] + | rel => simp [Fin.castLE_of_eq] + | imp _ _ ih1 ih2 => simp [Fin.castLE_of_eq, ih1, ih2] + | all _ ih3 => simp [Fin.castLE_of_eq, ih3] @[simp] theorem castLE_castLE {k m n} (km : k ≤ m) (mn : m ≤ n) (φ : L.BoundedFormula α k) : (φ.castLE km).castLE mn = φ.castLE (km.trans mn) := by revert m n - induction' φ with _ _ _ _ _ _ _ _ _ _ _ ih1 ih2 _ _ ih3 <;> intro m n km mn - · rfl - · simp - · simp only [castLE, eq_self_iff_true, heq_iff_eq, true_and_iff] - rw [← Function.comp.assoc, Term.relabel_comp_relabel] + induction φ with + | falsum => intros; rfl + | equal => simp + | rel => + intros + simp only [castLE, eq_self_iff_true, heq_iff_eq] + rw [← Function.comp_assoc, Term.relabel_comp_relabel] simp - · simp [ih1, ih2] - · simp only [castLE, ih3] + | imp _ _ ih1 ih2 => simp [ih1, ih2] + | all _ ih3 => intros; simp only [castLE, ih3] @[simp] theorem castLE_comp_castLE {k m n} (km : k ≤ m) (mn : m ≤ n) : @@ -471,22 +484,22 @@ theorem mapTermRel_mapTermRel {L'' : Language} (fr' : ∀ n, L'.Relations n → L''.Relations n) {n} (φ : L.BoundedFormula α n) : ((φ.mapTermRel ft fr fun _ => id).mapTermRel ft' fr' fun _ => id) = φ.mapTermRel (fun _ => ft' _ ∘ ft _) (fun _ => fr' _ ∘ fr _) fun _ => id := by - induction' φ with _ _ _ _ _ _ _ _ _ _ _ ih1 ih2 _ _ ih3 - · rfl - · simp [mapTermRel] - · simp [mapTermRel] - · simp [mapTermRel, ih1, ih2] - · simp [mapTermRel, ih3] + induction φ with + | falsum => rfl + | equal => simp [mapTermRel] + | rel => simp [mapTermRel] + | imp _ _ ih1 ih2 => simp [mapTermRel, ih1, ih2] + | all _ ih3 => simp [mapTermRel, ih3] @[simp] theorem mapTermRel_id_id_id {n} (φ : L.BoundedFormula α n) : (φ.mapTermRel (fun _ => id) (fun _ => id) fun _ => id) = φ := by - induction' φ with _ _ _ _ _ _ _ _ _ _ _ ih1 ih2 _ _ ih3 - · rfl - · simp [mapTermRel] - · simp [mapTermRel] - · simp [mapTermRel, ih1, ih2] - · simp [mapTermRel, ih3] + induction φ with + | falsum => rfl + | equal => simp [mapTermRel] + | rel => simp [mapTermRel] + | imp _ _ ih1 ih2 => simp [mapTermRel, ih1, ih2] + | all _ ih3 => simp [mapTermRel, ih3] /-- An equivalence of bounded formulas given by an equivalence of terms and an equivalence of relations. -/ @@ -559,12 +572,12 @@ theorem relabel_ex (g : α → β ⊕ (Fin n)) {k} (φ : L.BoundedFormula α (k theorem relabel_sum_inl (φ : L.BoundedFormula α n) : (φ.relabel Sum.inl : L.BoundedFormula α (0 + n)) = φ.castLE (ge_of_eq (zero_add n)) := by simp only [relabel, relabelAux_sum_inl] - induction' φ with _ _ _ _ _ _ _ _ _ _ _ ih1 ih2 _ _ ih3 - · rfl - · simp [Fin.natAdd_zero, castLE_of_eq, mapTermRel] - · simp [Fin.natAdd_zero, castLE_of_eq, mapTermRel]; rfl - · simp [mapTermRel, ih1, ih2] - · simp [mapTermRel, ih3, castLE] + induction φ with + | 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_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 := @@ -615,26 +628,25 @@ def onBoundedFormula (g : L →ᴸ L') : ∀ {k : ℕ}, L.BoundedFormula α k theorem id_onBoundedFormula : ((LHom.id L).onBoundedFormula : L.BoundedFormula α n → L.BoundedFormula α n) = id := by ext f - induction' f with _ _ _ _ _ _ _ _ _ _ _ ih1 ih2 _ _ ih3 - · rfl - · rw [onBoundedFormula, LHom.id_onTerm, id, id, id, Term.bdEqual] - · rw [onBoundedFormula, LHom.id_onTerm] - rfl - · rw [onBoundedFormula, ih1, ih2, id, id, id] - · rw [onBoundedFormula, ih3, id, id] + induction f with + | falsum => rfl + | equal => rw [onBoundedFormula, LHom.id_onTerm, id, id, id, Term.bdEqual] + | rel => rw [onBoundedFormula, LHom.id_onTerm]; rfl + | imp _ _ ih1 ih2 => rw [onBoundedFormula, ih1, ih2, id, id, id] + | all _ ih3 => rw [onBoundedFormula, ih3, id, id] @[simp] theorem comp_onBoundedFormula {L'' : Language} (φ : L' →ᴸ L'') (ψ : L →ᴸ L') : ((φ.comp ψ).onBoundedFormula : L.BoundedFormula α n → L''.BoundedFormula α n) = φ.onBoundedFormula ∘ ψ.onBoundedFormula := by ext f - induction' f with _ _ _ _ _ _ _ _ _ _ _ ih1 ih2 _ _ ih3 - · rfl - · simp only [onBoundedFormula, comp_onTerm, Function.comp_apply] - · simp only [onBoundedFormula, comp_onRelation, comp_onTerm, Function.comp_apply] - rfl - · simp only [onBoundedFormula, Function.comp_apply, ih1, ih2, eq_self_iff_true, and_self_iff] - · simp only [ih3, onBoundedFormula, Function.comp_apply] + induction f with + | falsum => rfl + | equal => simp only [onBoundedFormula, comp_onTerm, Function.comp_apply] + | rel => simp only [onBoundedFormula, comp_onRelation, comp_onTerm, Function.comp_apply]; rfl + | imp _ _ ih1 ih2 => + simp only [onBoundedFormula, Function.comp_apply, ih1, ih2, eq_self_iff_true, and_self_iff] + | all _ ih3 => simp only [ih3, onBoundedFormula, Function.comp_apply] /-- Maps a formula's symbols along a language map. -/ def onFormula (g : L →ᴸ L') : L.Formula α → L'.Formula α := diff --git a/Mathlib/ModelTheory/Ultraproducts.lean b/Mathlib/ModelTheory/Ultraproducts.lean index efe11fdadc8cd..63dbaa42f715d 100644 --- a/Mathlib/ModelTheory/Ultraproducts.lean +++ b/Mathlib/ModelTheory/Ultraproducts.lean @@ -94,23 +94,27 @@ theorem boundedFormula_realize_cast {β : Type*} {n : ℕ} (φ : L.BoundedFormul (fun i => (v i : (u : Filter α).Product M))) ↔ ∀ᶠ a : α in u, φ.Realize (fun i : β => x i a) fun i => v i a := by letI := (u : Filter α).productSetoid M - induction' φ with _ _ _ _ _ _ _ _ m _ _ ih ih' k φ ih - · simp only [BoundedFormula.Realize, eventually_const] - · have h2 : ∀ a : α, (Sum.elim (fun i : β => x i a) fun i => v i a) = fun i => Sum.elim x v i a := + induction φ with + | falsum => simp only [BoundedFormula.Realize, eventually_const] + | equal => + have h2 : ∀ a : α, (Sum.elim (fun i : β => x i a) fun i => v i a) = fun i => Sum.elim x v i a := fun a => funext fun i => Sum.casesOn i (fun i => rfl) fun i => rfl simp only [BoundedFormula.Realize, h2, term_realize_cast] erw [(Sum.comp_elim ((↑) : (∀ a, M a) → (u : Filter α).Product M) x v).symm, term_realize_cast, term_realize_cast] exact Quotient.eq'' - · have h2 : ∀ a : α, (Sum.elim (fun i : β => x i a) fun i => v i a) = fun i => Sum.elim x v i a := + | rel => + have h2 : ∀ a : α, (Sum.elim (fun i : β => x i a) fun i => v i a) = fun i => Sum.elim x v i a := fun a => funext fun i => Sum.casesOn i (fun i => rfl) fun i => rfl simp only [BoundedFormula.Realize, h2] erw [(Sum.comp_elim ((↑) : (∀ a, M a) → (u : Filter α).Product M) x v).symm] conv_lhs => enter [2, i]; erw [term_realize_cast] apply relMap_quotient_mk' - · simp only [BoundedFormula.Realize, ih v, ih' v] + | imp _ _ ih ih' => + simp only [BoundedFormula.Realize, ih v, ih' v] rw [Ultrafilter.eventually_imp] - · simp only [BoundedFormula.Realize] + | @all k φ ih => + simp only [BoundedFormula.Realize] apply Iff.trans (b := ∀ m : ∀ a : α, M a, φ.Realize (fun i : β => (x i : (u : Filter α).Product M)) (Fin.snoc (((↑) : (∀ a, M a) → (u : Filter α).Product M) ∘ v) @@ -124,7 +128,7 @@ theorem boundedFormula_realize_cast {β : Type*} {n : ℕ} (φ : L.BoundedFormul · simp only [Fin.snoc_last] · simp only [Fin.snoc_castSucc] simp only [← Fin.comp_snoc] - simp only [Function.comp, ih, h'] + simp only [Function.comp_def, ih, h'] refine ⟨fun h => ?_, fun h m => ?_⟩ · contrapose! h simp_rw [← Ultrafilter.eventually_not, not_forall] at h @@ -149,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 ffd2563801e40..9e6e2e67edaef 100644 --- a/Mathlib/NumberTheory/ArithmeticFunction.lean +++ b/Mathlib/NumberTheory/ArithmeticFunction.lean @@ -390,7 +390,7 @@ instance {M : Type*} [Semiring R] [AddCommMonoid M] [Module R M] : section Zeta -/-- `ζ 0 = 0`, otherwise `ζ x = 1`. The Dirichlet Series is the Riemann `ζ`. -/ +/-- `ζ 0 = 0`, otherwise `ζ x = 1`. The Dirichlet Series is the Riemann `ζ`. -/ def zeta : ArithmeticFunction ℕ := ⟨fun x => ite (x = 0) 0 1, rfl⟩ @@ -625,7 +625,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 @@ -776,7 +776,7 @@ end IsMultiplicative section SpecialFunctions -/-- The identity on `ℕ` as an `ArithmeticFunction`. -/ +/-- The identity on `ℕ` as an `ArithmeticFunction`. -/ nonrec -- Porting note (#11445): added def id : ArithmeticFunction ℕ := ⟨id, rfl⟩ diff --git a/Mathlib/NumberTheory/Bernoulli.lean b/Mathlib/NumberTheory/Bernoulli.lean index e6c6d64dc34d4..bda018aa1e2ea 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 @@ -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] @@ -293,7 +289,7 @@ theorem sum_range_pow (n p : ℕ) : apply sum_congr rfl intros m h simp only [f, exp_pow_eq_rescale_exp, rescale, one_div, coeff_mk, RingHom.coe_mk, coeff_exp, - RingHom.id_apply, cast_mul, algebraMap_rat_rat] + RingHom.id_apply, cast_mul, Algebra.id.map_eq_id] -- manipulate factorials and binomial coefficients simp? at h says simp only [succ_eq_add_one, mem_range] at h rw [choose_eq_factorial_div_factorial h.le, eq_comm, div_eq_iff (hne q.succ), succ_eq_add_one, diff --git a/Mathlib/NumberTheory/BernoulliPolynomials.lean b/Mathlib/NumberTheory/BernoulliPolynomials.lean index 4c666ceb7e29f..f333c35443ce6 100644 --- a/Mathlib/NumberTheory/BernoulliPolynomials.lean +++ b/Mathlib/NumberTheory/BernoulliPolynomials.lean @@ -175,8 +175,7 @@ theorem bernoulli_succ_eval (n p : ℕ) : (bernoulli p.succ).eval (n : ℚ) = theorem bernoulli_eval_one_add (n : ℕ) (x : ℚ) : (bernoulli n).eval (1 + x) = (bernoulli n).eval x + n * x ^ (n - 1) := by refine Nat.strong_induction_on n fun d hd => ?_ - have nz : ((d.succ : ℕ) : ℚ) ≠ 0 := by - norm_cast + have nz : ((d.succ : ℕ) : ℚ) ≠ 0 := by norm_cast apply (mul_right_inj' nz).1 rw [← smul_eq_mul, ← eval_smul, bernoulli_eq_sub_sum, mul_add, ← smul_eq_mul, ← eval_smul, bernoulli_eq_sub_sum, eval_sub, eval_finset_sum] diff --git a/Mathlib/NumberTheory/Bertrand.lean b/Mathlib/NumberTheory/Bertrand.lean index 487d4660f924d..f35408c70ebe0 100644 --- a/Mathlib/NumberTheory/Bertrand.lean +++ b/Mathlib/NumberTheory/Bertrand.lean @@ -122,7 +122,7 @@ theorem bertrand_main_inequality {n : ℕ} (n_large : 512 ≤ n) : · exact cast_div_le.trans (by norm_cast) /-- A lemma that tells us that, in the case where Bertrand's postulate does not hold, the prime -factorization of the central binomial coefficent only has factors at most `2 * n / 3 + 1`. +factorization of the central binomial coefficient only has factors at most `2 * n / 3 + 1`. -/ theorem centralBinom_factorization_small (n : ℕ) (n_large : 2 < n) (no_prime : ¬∃ p : ℕ, p.Prime ∧ n < p ∧ p ≤ 2 * n) : @@ -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 ed4273a3b101f..3c95d15cc13ee 100644 --- a/Mathlib/NumberTheory/Cyclotomic/Basic.lean +++ b/Mathlib/NumberTheory/Cyclotomic/Basic.lean @@ -3,10 +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.Init.Core import Mathlib.RingTheory.Polynomial.Cyclotomic.Roots import Mathlib.NumberTheory.NumberField.Basic -import Mathlib.FieldTheory.Galois +import Mathlib.FieldTheory.Galois.Basic /-! # Cyclotomic extensions @@ -59,7 +58,7 @@ included in the `Cyclotomic` locale. -/ -open Polynomial Algebra FiniteDimensional Set +open Polynomial Algebra Module Set universe u v w z diff --git a/Mathlib/NumberTheory/Cyclotomic/CyclotomicCharacter.lean b/Mathlib/NumberTheory/Cyclotomic/CyclotomicCharacter.lean index 1f7a73c505206..fad2bbc131b52 100644 --- a/Mathlib/NumberTheory/Cyclotomic/CyclotomicCharacter.lean +++ b/Mathlib/NumberTheory/Cyclotomic/CyclotomicCharacter.lean @@ -105,7 +105,8 @@ theorem toFun_spec (g : L ≃+* L) {n : ℕ+} (t : rootsOfUnity n L) : g (t : Lˣ) = (t ^ (χ₀ n g).val : Lˣ) := by rw [ModularCyclotomicCharacter_aux_spec g n t, ← zpow_natCast, ModularCyclotomicCharacter.toFun, ZMod.val_intCast, ← Subgroup.coe_zpow] - exact Units.ext_iff.1 <| SetCoe.ext_iff.2 <| zpow_eq_zpow_emod _ pow_card_eq_one + exact Units.ext_iff.1 <| SetCoe.ext_iff.2 <| + zpow_eq_zpow_emod _ pow_card_eq_one (G := rootsOfUnity n L) theorem toFun_spec' (g : L ≃+* L) {n : ℕ+} {t : Lˣ} (ht : t ∈ rootsOfUnity n L) : g t = t ^ (χ₀ n g).val := @@ -195,7 +196,7 @@ lemma spec (g : L ≃+* L) {t : Lˣ} (ht : t ∈ rootsOfUnity n L) : congr 1 exact (ZMod.ringEquivCongr_val _ _).symm -lemma unique (g : L ≃+* L) {c : ZMod n} (hc : ∀ t ∈ rootsOfUnity n L, g t = t ^ c.val) : +lemma unique (g : L ≃+* L) {c : ZMod n} (hc : ∀ t ∈ rootsOfUnity n L, g t = t ^ c.val) : c = ModularCyclotomicCharacter L hn g := by change c = (ZMod.ringEquivCongr hn) (toFun n g) rw [← toFun_unique' n g (ZMod.ringEquivCongr hn.symm c) diff --git a/Mathlib/NumberTheory/Cyclotomic/Discriminant.lean b/Mathlib/NumberTheory/Cyclotomic/Discriminant.lean index 3ca7d4838404a..c4b31c98a929a 100644 --- a/Mathlib/NumberTheory/Cyclotomic/Discriminant.lean +++ b/Mathlib/NumberTheory/Cyclotomic/Discriminant.lean @@ -168,7 +168,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 @@ -189,7 +189,7 @@ theorem discr_prime_pow_eq_unit_mul_pow [IsCyclotomicExtension {p ^ k} K L] by_cases heven : Even ((p ^ k : ℕ).totient / 2) · exact ⟨1, (p : ℕ) ^ (k - 1) * ((p - 1) * k - 1), by rw [heven.neg_one_pow]; norm_num⟩ · exact ⟨-1, (p : ℕ) ^ (k - 1) * ((p - 1) * k - 1), by - rw [(odd_iff_not_even.2 heven).neg_one_pow]; norm_num⟩ + rw [(not_even_iff_odd.1 heven).neg_one_pow]; norm_num⟩ /-- If `p` is an odd prime and `IsCyclotomicExtension {p} K L`, then `discr K (hζ.powerBasis K).basis = (-1) ^ ((p - 1) / 2) * p ^ (p - 2)` if diff --git a/Mathlib/NumberTheory/Cyclotomic/Embeddings.lean b/Mathlib/NumberTheory/Cyclotomic/Embeddings.lean index b3d2a56cf11a2..642d6933fad59 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] diff --git a/Mathlib/NumberTheory/Cyclotomic/Gal.lean b/Mathlib/NumberTheory/Cyclotomic/Gal.lean index 003aa4ddd67fb..fb381459d36cf 100644 --- a/Mathlib/NumberTheory/Cyclotomic/Gal.lean +++ b/Mathlib/NumberTheory/Cyclotomic/Gal.lean @@ -85,12 +85,12 @@ noncomputable def Aut.commGroup : CommGroup (L ≃ₐ[K] L) := ((zeta_spec n K L).autToPow_injective K).commGroup _ (map_one _) (map_mul _) (map_inv _) (map_div _) (map_pow _) (map_zpow _) -variable (h : Irreducible (cyclotomic n K)) {K} (L) +variable {K} (L) /-- The `MulEquiv` that takes an automorphism `f` to the element `k : (ZMod n)ˣ` such that `f μ = μ ^ k` for any root of unity `μ`. A strengthening of `IsPrimitiveRoot.autToPow`. -/ @[simps] -noncomputable def autEquivPow : (L ≃ₐ[K] L) ≃* (ZMod n)ˣ := +noncomputable def autEquivPow (h : Irreducible (cyclotomic n K)) : (L ≃ₐ[K] L) ≃* (ZMod n)ˣ := let hζ := zeta_spec n K L let hμ t := hζ.pow_of_coprime _ (ZMod.val_coe_unit_coprime t) { (zeta_spec n K L).autToPow K with @@ -131,7 +131,7 @@ noncomputable def autEquivPow : (L ≃ₐ[K] L) ≃* (ZMod n)ˣ := simp only [ZMod.natCast_val, ZMod.cast_id', id] at key exact Units.ext key } -variable {L} +variable (h : Irreducible (cyclotomic n K)) {L} /-- Maps `μ` to the `AlgEquiv` that sends `IsCyclotomicExtension.zeta` to `μ`. -/ noncomputable def fromZetaAut : L ≃ₐ[K] L := diff --git a/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean b/Mathlib/NumberTheory/Cyclotomic/PrimitiveRoots.lean index 14303f635d275..e4a82b6a04edb 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 @@ -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) @@ -243,7 +244,7 @@ theorem exists_neg_pow_of_isOfFinOrder [IsCyclotomicExtension {n} ℚ K] convert IsPrimitiveRoot.orderOf (-ζ) rw [neg_eq_neg_one_mul, (Commute.all _ _).orderOf_mul_eq_mul_orderOf_of_coprime] · simp [hζ.eq_orderOf] - · simp [← hζ.eq_orderOf, Nat.odd_iff_not_even.1 hno] + · simp [← hζ.eq_orderOf, hno] obtain ⟨k, hkpos, hkn⟩ := isOfFinOrder_iff_pow_eq_one.1 hx obtain ⟨l, hl, hlroot⟩ := (isRoot_of_unity_iff hkpos _).1 hkn have hlzero : NeZero l := ⟨fun h ↦ by simp [h] at hl⟩ @@ -291,7 +292,7 @@ theorem norm_eq_one [IsDomain L] [IsCyclotomicExtension {n} K L] (hn : n ≠ 2) · replace h1 : 2 ≤ n := by by_contra! h exact h1 (PNat.eq_one_of_lt_two h) --- Porting note: specyfing the type of `cyclotomic_coeff_zero K h1` was not needed. +-- Porting note: specifying the type of `cyclotomic_coeff_zero K h1` was not needed. rw [← hζ.powerBasis_gen K, PowerBasis.norm_gen_eq_coeff_zero_minpoly, hζ.powerBasis_gen K, ← hζ.minpoly_eq_cyclotomic_of_irreducible hirr, (cyclotomic_coeff_zero K h1 : coeff (cyclotomic n K) 0 = 1), mul_one, @@ -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 1 [← 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, diff --git a/Mathlib/NumberTheory/Cyclotomic/Rat.lean b/Mathlib/NumberTheory/Cyclotomic/Rat.lean index 5c6aee417a142..39cdf61a38935 100644 --- a/Mathlib/NumberTheory/Cyclotomic/Rat.lean +++ b/Mathlib/NumberTheory/Cyclotomic/Rat.lean @@ -225,7 +225,8 @@ unity and `K` is a `p`-th cyclotomic extension of `ℚ`. -/ noncomputable def _root_.IsPrimitiveRoot.adjoinEquivRingOfIntegers' [hcycl : IsCyclotomicExtension {p} ℚ K] (hζ : IsPrimitiveRoot ζ p) : adjoin ℤ ({ζ} : Set K) ≃ₐ[ℤ] 𝓞 K := - @adjoinEquivRingOfIntegers p 1 K _ _ _ _ (by convert hcycl; rw [pow_one]) (by rwa [pow_one]) + have : IsCyclotomicExtension {p ^ 1} ℚ K := by convert hcycl; rw [pow_one] + adjoinEquivRingOfIntegers (p := p) (k := 1) (ζ := ζ) (by rwa [pow_one]) /-- The ring of integers of a `p`-th cyclotomic extension of `ℚ` is a cyclotomic extension. -/ instance _root_.IsCyclotomicExtension.ring_of_integers' [IsCyclotomicExtension {p} ℚ K] : @@ -237,18 +238,19 @@ instance _root_.IsCyclotomicExtension.ring_of_integers' [IsCyclotomicExtension { cyclotomic extension of `ℚ`. -/ noncomputable def integralPowerBasis' [hcycl : IsCyclotomicExtension {p} ℚ K] (hζ : IsPrimitiveRoot ζ p) : PowerBasis ℤ (𝓞 K) := - @integralPowerBasis p 1 K _ _ _ _ (by convert hcycl; rw [pow_one]) (by rwa [pow_one]) + have : IsCyclotomicExtension {p ^ 1} ℚ K := by convert hcycl; rw [pow_one] + integralPowerBasis (p := p) (k := 1) (ζ := ζ) (by rwa [pow_one]) @[simp] theorem integralPowerBasis'_gen [hcycl : IsCyclotomicExtension {p} ℚ K] (hζ : IsPrimitiveRoot ζ p) : hζ.integralPowerBasis'.gen = hζ.toInteger := - @integralPowerBasis_gen p 1 K _ _ _ _ (by convert hcycl; rw [pow_one]) (by rwa [pow_one]) + integralPowerBasis_gen (hcycl := by rwa [pow_one]) (by rwa [pow_one]) @[simp] theorem power_basis_int'_dim [hcycl : IsCyclotomicExtension {p} ℚ K] (hζ : IsPrimitiveRoot ζ p) : hζ.integralPowerBasis'.dim = φ p := by - erw [@integralPowerBasis_dim p 1 K _ _ _ _ (by convert hcycl; rw [pow_one]) (by rwa [pow_one]), - pow_one] + erw [integralPowerBasis_dim (hcycl := by rwa [pow_one]) (by rwa [pow_one]), pow_one] + /-- The integral `PowerBasis` of `𝓞 K` given by `ζ - 1`, where `K` is a `p ^ k` cyclotomic extension of `ℚ`. -/ @@ -259,9 +261,7 @@ noncomputable def subOneIntegralPowerBasis [IsCyclotomicExtension {p ^ k} ℚ K] simp only [integralPowerBasis_gen, toInteger] convert Subalgebra.add_mem _ (self_mem_adjoin_singleton ℤ (⟨ζ - 1, _⟩ : 𝓞 K)) (Subalgebra.one_mem _) --- Porting note: `simp` was able to finish the proof. - · simp only [Subsemiring.coe_add, Subalgebra.coe_toSubsemiring, - OneMemClass.coe_one, sub_add_cancel] + · simp · exact Subalgebra.sub_mem _ (hζ.isIntegral (by simp)) (Subalgebra.one_mem _)) @[simp] @@ -273,15 +273,18 @@ theorem subOneIntegralPowerBasis_gen [IsCyclotomicExtension {p ^ k} ℚ K] /-- The integral `PowerBasis` of `𝓞 K` given by `ζ - 1`, where `K` is a `p`-th cyclotomic extension of `ℚ`. -/ -noncomputable def subOneIntegralPowerBasis' [hcycl : IsCyclotomicExtension {p} ℚ K] +noncomputable def subOneIntegralPowerBasis' [IsCyclotomicExtension {p} ℚ K] (hζ : IsPrimitiveRoot ζ p) : PowerBasis ℤ (𝓞 K) := - @subOneIntegralPowerBasis p 1 K _ _ _ _ (by convert hcycl; rw [pow_one]) (by rwa [pow_one]) + have : IsCyclotomicExtension {p ^ 1} ℚ K := by rwa [pow_one] + subOneIntegralPowerBasis (p := p) (k := 1) (ζ := ζ) (by rwa [pow_one]) -@[simp] -theorem subOneIntegralPowerBasis'_gen [hcycl : IsCyclotomicExtension {p} ℚ K] +@[simp, nolint unusedHavesSuffices] +theorem subOneIntegralPowerBasis'_gen [IsCyclotomicExtension {p} ℚ K] (hζ : IsPrimitiveRoot ζ p) : hζ.subOneIntegralPowerBasis'.gen = hζ.toInteger - 1 := - @subOneIntegralPowerBasis_gen p 1 K _ _ _ _ (by convert hcycl; rw [pow_one]) (by rwa [pow_one]) + -- The `unusedHavesSuffices` linter incorrectly thinks this `have` is unnecessary. + have : IsCyclotomicExtension {p ^ 1} ℚ K := by rwa [pow_one] + subOneIntegralPowerBasis_gen (by rwa [pow_one]) /-- `ζ - 1` is prime if `p ≠ 2` and `ζ` is a primitive `p ^ (k + 1)`-th root of unity. See `zeta_sub_one_prime` for a general statement. -/ @@ -290,7 +293,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, @@ -309,7 +312,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, @@ -318,12 +321,12 @@ theorem zeta_sub_one_prime_of_two_pow [IsCyclotomicExtension {(2 : ℕ+) ^ (k + · convert Prime.neg Int.prime_two apply RingHom.injective_int (algebraMap ℤ ℚ) rw [← Algebra.norm_localization (Sₘ := K) ℤ (nonZeroDivisors ℤ)] - simp only [Nat.zero_eq, PNat.pow_coe, id.map_eq_id, RingHomCompTriple.comp_eq, RingHom.coe_coe, + simp only [PNat.pow_coe, id.map_eq_id, RingHomCompTriple.comp_eq, RingHom.coe_coe, Subalgebra.coe_val, algebraMap_int_eq, map_neg, map_ofNat] - simpa only [zero_add, pow_one, AddSubgroupClass.coe_sub, OneMemClass.coe_one, Nat.zero_eq, + simpa only [zero_add, pow_one, AddSubgroupClass.coe_sub, OneMemClass.coe_one, pow_zero] using hζ.norm_pow_sub_one_two (cyclotomic.irreducible_rat - (by simp only [Nat.zero_eq, zero_add, pow_one, Nat.ofNat_pos])) + (by simp only [zero_add, pow_one, Nat.ofNat_pos])) convert Int.prime_two apply RingHom.injective_int (algebraMap ℤ ℚ) rw [← Algebra.norm_localization (Sₘ := K) ℤ (nonZeroDivisors ℤ)] @@ -450,7 +453,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 @@ -495,7 +498,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 674ecffb62b68..721b81b5271ba 100644 --- a/Mathlib/NumberTheory/Dioph.lean +++ b/Mathlib/NumberTheory/Dioph.lean @@ -439,14 +439,15 @@ open Vector3 open scoped Vector3 -- Porting note: Fails because declaration is in an imported module --- attribute [local reducible] Vector3 +set_option allowUnsafeReducibility true in +attribute [local reducible] Vector3 theorem diophFn_vec_comp1 {S : Set (Vector3 ℕ (succ n))} (d : Dioph S) {f : Vector3 ℕ n → ℕ} (df : DiophFn f) : Dioph {v : Vector3 ℕ n | (f v::v) ∈ S} := Dioph.ext (diophFn_comp1 (reindex_dioph _ (none::some) d) df) (fun v => by dsimp -- Porting note: `congr` use to be enough here - refine iff_of_eq (congrFun (congrArg Membership.mem ?_) S) + suffices ((f v ::ₒ v) ∘ none :: some) = f v :: v by rw [this]; rfl ext x; cases x <;> rfl) theorem vec_ex1_dioph (n) {S : Set (Vector3 ℕ (succ n))} (d : Dioph S) : @@ -470,7 +471,7 @@ theorem diophFn_compn : ext (reindex_dioph _ (id ⊗ Fin2.elim0) d) fun v => by dsimp -- Porting note: `congr` use to be enough here - refine iff_of_eq (congrFun (congrArg Membership.mem ?_) S) + suffices v ∘ (id ⊗ elim0) = v ⊗ fun i ↦ f i v by rw [this] ext x; obtain _ | _ | _ := x; rfl | succ n, S, d, f => f.consElim fun f fl => by @@ -482,14 +483,15 @@ theorem diophFn_compn : fun v => by dsimp -- Porting note: `congr` use to be enough here - refine iff_of_eq (congrFun (congrArg Membership.mem ?_) S) + suffices (f (v ∘ inl) ::ₒ v) ∘ (some ∘ inl ⊗ none :: some ∘ inr) = + v ∘ inl ⊗ f (v ∘ inl) :: v ∘ inr by rw [this] ext x; obtain _ | _ | _ := x <;> rfl have : Dioph {v | (v ⊗ f v::fun i : Fin2 n => fl i v) ∈ S} := @diophFn_compn n (fun v => S (v ∘ inl ⊗ f (v ∘ inl)::v ∘ inr)) this _ dfl ext this fun v => by dsimp -- Porting note: `congr` use to be enough here - refine iff_of_eq (congrFun (congrArg Membership.mem ?_) S) + suffices (v ⊗ f v :: fun i ↦ fl i v) = v ⊗ fun i ↦ (f :: fl) i v by rw [this] ext x; obtain _ | _ | _ := x <;> rfl theorem dioph_comp {S : Set (Vector3 ℕ n)} (d : Dioph S) (f : Vector3 ((α → ℕ) → ℕ) n) diff --git a/Mathlib/NumberTheory/DiophantineApproximation.lean b/Mathlib/NumberTheory/DiophantineApproximation.lean index 0e5d09c4d8fa2..1d052c7a9f81e 100644 --- a/Mathlib/NumberTheory/DiophantineApproximation.lean +++ b/Mathlib/NumberTheory/DiophantineApproximation.lean @@ -93,7 +93,7 @@ theorem exists_int_int_abs_mul_sub_le (ξ : ℝ) {n : ℕ} (n_pos : 0 < n) : let f : ℤ → ℤ := fun m => ⌊fract (ξ * m) * (n + 1)⌋ have hn : 0 < (n : ℝ) + 1 := mod_cast Nat.succ_pos _ have hfu := fun m : ℤ => mul_lt_of_lt_one_left hn <| fract_lt_one (ξ * ↑m) - conv in |_| ≤ _ => rw [mul_comm, le_div_iff hn, ← abs_of_pos hn, ← abs_mul] + conv in |_| ≤ _ => rw [mul_comm, le_div_iff₀ hn, ← abs_of_pos hn, ← abs_mul] let D := Icc (0 : ℤ) n by_cases H : ∃ m ∈ D, f m = n · obtain ⟨m, hm, hf⟩ := H @@ -153,7 +153,7 @@ theorem exists_rat_abs_sub_le_and_den_le (ξ : ℝ) {n : ℕ} (n_pos : 0 < n) : convert le_of_dvd hk₀ (Rat.den_dvd j k) exact Rat.intCast_div_eq_divInt _ _ refine ⟨j / k, ?_, Nat.cast_le.mp (hden.trans hk₁)⟩ - rw [← div_div, le_div_iff (Nat.cast_pos.mpr <| Rat.pos _ : (0 : ℝ) < _)] + rw [← div_div, le_div_iff₀ (Nat.cast_pos.mpr <| Rat.pos _ : (0 : ℝ) < _)] refine (mul_le_mul_of_nonneg_left (Int.cast_le.mpr hden : _ ≤ (k : ℝ)) (abs_nonneg _)).trans ?_ rwa [← abs_of_pos hk₀', Rat.cast_div, Rat.cast_intCast, Rat.cast_intCast, ← abs_mul, sub_mul, div_mul_cancel₀ _ hk₀'.ne', mul_comm] @@ -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] @@ -341,14 +341,14 @@ theorem convergent_succ (ξ : ℝ) (n : ℕ) : @[simp] theorem convergent_of_zero (n : ℕ) : convergent 0 n = 0 := by induction' n with n ih - · simp only [Nat.zero_eq, convergent_zero, floor_zero, cast_zero] + · simp only [convergent_zero, floor_zero, cast_zero] · simp only [ih, convergent_succ, floor_zero, cast_zero, fract_zero, add_zero, inv_zero] /-- If `ξ` is an integer, all its convergents equal `ξ`. -/ @[simp] theorem convergent_of_int {ξ : ℤ} (n : ℕ) : convergent ξ n = ξ := by cases n - · simp only [Nat.zero_eq, convergent_zero, floor_intCast] + · simp only [convergent_zero, floor_intCast] · simp only [convergent_succ, floor_intCast, fract_intCast, convergent_of_zero, add_zero, inv_zero] @@ -363,7 +363,7 @@ open GenContFract theorem convs_eq_convergent (ξ : ℝ) (n : ℕ) : (GenContFract.of ξ).convs n = ξ.convergent n := by induction' n with n ih generalizing ξ - · simp only [Nat.zero_eq, zeroth_conv_eq_h, of_h_eq_floor, convergent_zero, Rat.cast_intCast] + · simp only [zeroth_conv_eq_h, of_h_eq_floor, convergent_zero, Rat.cast_intCast] · rw [convs_succ, ih (fract ξ)⁻¹, convergent_succ, one_div] norm_cast @@ -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..9fbae12e56bcd 100644 --- a/Mathlib/NumberTheory/DirichletCharacter/Basic.lean +++ b/Mathlib/NumberTheory/DirichletCharacter/Basic.lean @@ -161,7 +161,7 @@ noncomputable instance : Unique (DirichletCharacter R 1) := Unique.mk' (Dirichle 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χ₀⟩ ↦ ?_, diff --git a/Mathlib/NumberTheory/Divisors.lean b/Mathlib/NumberTheory/Divisors.lean index 78221e801b0c2..0c98cefad6ecd 100644 --- a/Mathlib/NumberTheory/Divisors.lean +++ b/Mathlib/NumberTheory/Divisors.lean @@ -82,7 +82,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 +109,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 +130,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 := diff --git a/Mathlib/NumberTheory/EllipticDivisibilitySequence.lean b/Mathlib/NumberTheory/EllipticDivisibilitySequence.lean index bca41d94b0569..b48aa4e66e245 100644 --- a/Mathlib/NumberTheory/EllipticDivisibilitySequence.lean +++ b/Mathlib/NumberTheory/EllipticDivisibilitySequence.lean @@ -119,7 +119,7 @@ def preNormEDS' (b c d : R) : ℕ → R 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 - (Nat.div_lt_self (Nat.odd_iff_not_even.mpr hn).pos <| Nat.lt_succ_self 1) 5 + (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/DirichletLSeries.lean b/Mathlib/NumberTheory/EulerProduct/DirichletLSeries.lean index 82d366d734cee..ba72ec28fdfcd 100644 --- a/Mathlib/NumberTheory/EulerProduct/DirichletLSeries.lean +++ b/Mathlib/NumberTheory/EulerProduct/DirichletLSeries.lean @@ -77,12 +77,8 @@ lemma summable_dirichletSummand {N : ℕ} (χ : DirichletCharacter ℂ N) (hs : open scoped LSeries.notation in lemma tsum_dirichletSummand {N : ℕ} (χ : DirichletCharacter ℂ N) (hs : 1 < s.re) : ∑' (n : ℕ), dirichletSummandHom χ (ne_zero_of_one_lt_re hs) n = L ↗χ s := by - simp only [LSeries, LSeries.term, dirichletSummandHom] - refine tsum_congr (fun n ↦ ?_) - rcases eq_or_ne n 0 with rfl | hn - · simp only [map_zero, ↓reduceIte] - · simp only [cpow_neg, MonoidWithZeroHom.coe_mk, ZeroHom.coe_mk, hn, ↓reduceIte, - Field.div_eq_mul_inv] + simp only [dirichletSummandHom, cpow_neg, MonoidWithZeroHom.coe_mk, ZeroHom.coe_mk, LSeries, + LSeries.term_of_ne_zero' (ne_zero_of_one_lt_re hs), div_eq_mul_inv] open Filter Nat Topology EulerProduct diff --git a/Mathlib/NumberTheory/FLT/Basic.lean b/Mathlib/NumberTheory/FLT/Basic.lean index 49253dbdcc2fd..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`. -/ @@ -175,7 +229,7 @@ lemma fermatLastTheoremWith_of_fermatLastTheoremWith_coprime {n : ℕ} {R : Type rw [← Finset.gcd_mul_left, gcd_eq_gcd_image, image_insert, image_insert, image_singleton, id_eq, id_eq, id_eq, ← hA, ← hB, ← hC] -lemma dvd_c_of_prime_of_dvd_a_of_dvd_b_of_FLT {n : ℕ} {p : ℤ} (hp : Prime p) {a b c : ℤ} +lemma dvd_c_of_prime_of_dvd_a_of_dvd_b_of_FLT {n : ℕ} {p : ℤ} (hp : Prime p) {a b c : ℤ} (hpa : p ∣ a) (hpb : p ∣ b) (HF : a ^ n + b ^ n + c ^ n = 0) : p ∣ c := by rcases eq_or_ne n 0 with rfl | hn · simp at HF diff --git a/Mathlib/NumberTheory/FLT/Three.lean b/Mathlib/NumberTheory/FLT/Three.lean index 68fcc6a03f0ea..555bad3224e64 100644 --- a/Mathlib/NumberTheory/FLT/Three.lean +++ b/Mathlib/NumberTheory/FLT/Three.lean @@ -116,7 +116,7 @@ private lemma fermatLastTheoremThree_of_dvd_a_of_gcd_eq_one_of_case2 {a b c : open Finset Int in /-- - To prove Fermat's Last Theorem for `n = 3`, it is enough to show that that for all `a`, `b`, `c` + To prove Fermat's Last Theorem for `n = 3`, it is enough to show that for all `a`, `b`, `c` in `ℤ` such that `c ≠ 0`, `¬ 3 ∣ a`, `¬ 3 ∣ b`, `a` and `b` are coprime and `3 ∣ c`, we have `a ^ 3 + b ^ 3 ≠ c ^ 3`. -/ @@ -241,7 +241,7 @@ lemma Solution.exists_minimal : ∃ (S₁ : Solution hζ), S₁.isMinimal := by end DecidableRel /-- Given `S' : Solution'`, then `S'.a` and `S'.b` are both congruent to `1` modulo `λ ^ 4` or are -both congruent to `-1`. -/ +both congruent to `-1`. -/ lemma a_cube_b_cube_congr_one_or_neg_one : λ ^ 4 ∣ S'.a ^ 3 - 1 ∧ λ ^ 4 ∣ S'.b ^ 3 + 1 ∨ λ ^ 4 ∣ S'.a ^ 3 + 1 ∧ λ ^ 4 ∣ S'.b ^ 3 - 1 := by obtain ⟨z, hz⟩ := S'.hcdvd 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..0fcd105b0a600 --- /dev/null +++ b/Mathlib/NumberTheory/Fermat.lean @@ -0,0 +1,77 @@ +/- +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.Star.Basic +import Mathlib.Data.Nat.Prime.Defs +import Mathlib.Tactic.Ring.RingNF + +/-! +# 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 +open scoped BigOperators + +/-- 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 _ + +/-- +**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 94de3820f0adb..69740e0014839 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`. @@ -69,9 +69,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] @@ -213,7 +213,7 @@ theorem inftyValuation.polynomial {p : Fq[X]} (hp : p ≠ 0) : inftyValuationDef Fq (algebraMap Fq[X] (RatFunc Fq) p) = Multiplicative.ofAdd (p.natDegree : ℤ) := by have hp' : algebraMap Fq[X] (RatFunc Fq) p ≠ 0 := by - rw [Ne, RatFunc.algebraMap_eq_zero_iff]; exact hp + rw [Ne, NoZeroSMulDivisors.algebraMap_eq_zero_iff]; exact hp rw [inftyValuationDef, if_neg hp', RatFunc.intDegree_polynomial] /-- The valued field `Fq(t)` with the valuation at infinity. -/ 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/EulerMascheroni.lean b/Mathlib/NumberTheory/Harmonic/EulerMascheroni.lean index 92a72fe1377c1..e61b195e807ac 100644 --- a/Mathlib/NumberTheory/Harmonic/EulerMascheroni.lean +++ b/Mathlib/NumberTheory/Harmonic/EulerMascheroni.lean @@ -84,7 +84,7 @@ lemma strictAnti_eulerMascheroniSeq' : StrictAnti eulerMascheroniSeq' := by refine strictAnti_nat_of_succ_lt (fun n ↦ ?_) rcases Nat.eq_zero_or_pos n with rfl | hn · simp [eulerMascheroniSeq'] - simp_rw [eulerMascheroniSeq', eq_false_intro hn.ne', if_false] + simp_rw [eulerMascheroniSeq', eq_false_intro hn.ne', reduceCtorEq, if_false] rw [← sub_pos, sub_sub_sub_comm, harmonic_succ, Rat.cast_add, ← sub_sub, sub_self, zero_sub, sub_eq_add_neg, neg_sub, ← sub_eq_neg_add, sub_pos, ← log_div (by positivity) (by positivity), ← neg_lt_neg_iff, diff --git a/Mathlib/NumberTheory/Harmonic/GammaDeriv.lean b/Mathlib/NumberTheory/Harmonic/GammaDeriv.lean index 35d6bf5409607..90e05ffd8ff51 100644 --- a/Mathlib/NumberTheory/Harmonic/GammaDeriv.lean +++ b/Mathlib/NumberTheory/Harmonic/GammaDeriv.lean @@ -4,12 +4,13 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: David Loeffler -/ -import Mathlib.NumberTheory.Harmonic.EulerMascheroni +import Mathlib.Analysis.Convex.Deriv import Mathlib.Analysis.SpecialFunctions.Gamma.Deligne import Mathlib.Data.Nat.Factorial.Basic +import Mathlib.NumberTheory.Harmonic.EulerMascheroni /-! -# Derivative of Γ at positive integers +# Derivative of Γ at positive integers We prove the formula for the derivative of `Real.Gamma` at a positive integer: @@ -46,7 +47,7 @@ lemma deriv_Gamma_nat (n : ℕ) : exact fun m ↦ ne_of_gt (by linarith) -- Express derivative at general `n` in terms of value at `1` using recurrence relation have hder_rec (x : ℝ) (hx : 0 < x) : deriv f (x + 1) = deriv f x + 1 / x := by - rw [← deriv_comp_add_const _ _ (hder <| by positivity), one_div, ← deriv_log, + rw [← deriv_comp_add_const, one_div, ← deriv_log, ← deriv_add (hder <| by positivity) (differentiableAt_log hx.ne')] apply EventuallyEq.deriv_eq filter_upwards [eventually_gt_nhds hx] using h_rec @@ -108,7 +109,6 @@ lemma hasDerivAt_Gamma_one_half : HasDerivAt Gamma (-√π * (γ + 2 * log 2)) ( (by norm_num : 1/2 + 1/2 = (1 : ℝ)), Gamma_one, mul_one, eulerMascheroniConstant_eq_neg_deriv, add_neg_cancel, mul_zero, add_zero] · apply h_diff; norm_num -- s = 1 - · apply h_diff; norm_num -- s = 1/2 · exact ((h_diff (by norm_num)).hasDerivAt.comp_add_const).differentiableAt -- s = 1 _ = (deriv (fun s ↦ Gamma (2 * s) * 2 ^ (1 - 2 * s) * √π) (1 / 2)) + √π * γ := by rw [funext Gamma_mul_Gamma_add_half] 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 e18b71b7b04b6..99e63c94ec211 100644 --- a/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean +++ b/Mathlib/NumberTheory/Harmonic/ZetaAsymp.lean @@ -37,7 +37,7 @@ namespace ZetaAsymptotics -- since the intermediate lemmas are of little interest in themselves we put them in a namespace /-! -## Definitions +## Definitions -/ /-- Auxiliary function used in studying zeta-function asymptotics. -/ @@ -127,8 +127,8 @@ lemma term_tsum_one : HasSum (fun n ↦ term (n + 1) 1) (1 - γ) := by simp_rw [term_sum_one, sub_eq_neg_add] refine Tendsto.add ?_ tendsto_const_nhds have := (tendsto_eulerMascheroniSeq'.comp (tendsto_add_atTop_nat 1)).neg - refine this.congr' (eventually_of_forall (fun n ↦ ?_)) - simp_rw [Function.comp_apply, eulerMascheroniSeq', if_false] + refine this.congr' (Eventually.of_forall (fun n ↦ ?_)) + simp_rw [Function.comp_apply, eulerMascheroniSeq', reduceCtorEq, if_false] push_cast abel diff --git a/Mathlib/NumberTheory/JacobiSum/Basic.lean b/Mathlib/NumberTheory/JacobiSum/Basic.lean new file mode 100644 index 0000000000000..a936f799462ca --- /dev/null +++ b/Mathlib/NumberTheory/JacobiSum/Basic.lean @@ -0,0 +1,336 @@ +/- +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.GaussSum +import Mathlib.NumberTheory.MulChar.Lemmas +import Mathlib.RingTheory.RootsOfUnity.Lemmas + +/-! +# Jacobi Sums + +This file defines the *Jacobi sum* of two multiplicative characters `χ` and `ψ` on a finite +commutative ring `R` with values in another commutative ring `R'`: + +`jacobiSum χ ψ = ∑ x : R, χ x * ψ (1 - x)` + +(see `jacobiSum`) and provides some basic results and API lemmas on Jacobi sums. + +## References + +We essentially follow +* [K. Ireland, M. Rosen, *A classical introduction to modern number theory* + (Section 8.3)][IrelandRosen1990] + +but generalize where appropriate. + +This is based on Lean code written as part of the bachelor's thesis of Alexander Spahl. +-/ + +open BigOperators Finset + +/-! +### Jacobi sums: definition and first properties +-/ + +section Def + +-- need `Fintype` instead of `Finite` to make `jacobiSum` computable. +variable {R R' : Type*} [CommRing R] [Fintype R] [CommRing R'] + +/-- The *Jacobi sum* of two multiplicative characters on a finite commutative ring. -/ +def jacobiSum (χ ψ : MulChar R R') : R' := + ∑ x : R, χ x * ψ (1 - x) + +lemma jacobiSum_comm (χ ψ : MulChar R R') : jacobiSum χ ψ = jacobiSum ψ χ := by + simp only [jacobiSum, mul_comm (χ _)] + rw [← (Equiv.subLeft 1).sum_comp] + simp only [Equiv.subLeft_apply, sub_sub_cancel] + +/-- The Jacobi sum is compatible with ring homomorphisms. -/ +lemma jacobiSum_ringHomComp {R'' : Type*} [CommRing R''] (χ ψ : MulChar R R') (f : R' →+* R'') : + jacobiSum (χ.ringHomComp f) (ψ.ringHomComp f) = f (jacobiSum χ ψ) := by + simp only [jacobiSum, MulChar.ringHomComp, MulChar.coe_mk, MonoidHom.coe_mk, OneHom.coe_mk, + map_sum, map_mul] + +end Def + +/-! +### Jacobi sums over finite fields +-/ + +section CommRing + +variable {F R : Type*} [CommRing F] [Nontrivial F] [Fintype F] [DecidableEq F] [CommRing R] + +/-- 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, 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 + + ∑ x ∈ univ \ {0, 1}, (χ x - 1) * (ψ (1 - x) - 1) := by + rw [jacobiSum] + conv => + enter [1, 2, x] + rw [show ∀ x y : R, x * y = x + y - 1 + (x - 1) * (y - 1) by intros; ring] + rw [sum_add_distrib, sum_sub_distrib, sum_add_distrib] + conv => enter [1, 1, 1, 2, 2, x]; rw [← Equiv.subLeft_apply 1] + rw [(Equiv.subLeft 1).sum_comp ψ, Fintype.card_eq_sum_ones, Nat.cast_sum, Nat.cast_one, + sum_sdiff_eq_sub (subset_univ _), ← sub_zero (_ - _ + _), add_sub_assoc] + 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 + rw [← map_mul, MulChar.trivial_apply, if_pos] + simp only [mem_sdiff, mem_univ, mem_insert, mem_singleton, not_or, ← ne_eq, true_and] at hx + 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 + _ = 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] + +/-- If `1` is the trivial multiplicative character on a finite field `F`, then `J(1,1) = #F-2`. -/ +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 747f0b3cbec26..b93799f8bfa38 100644 --- a/Mathlib/NumberTheory/KummerDedekind.lean +++ b/Mathlib/NumberTheory/KummerDedekind.lean @@ -111,9 +111,9 @@ variable {I : Ideal R} theorem prod_mem_ideal_map_of_mem_conductor {p : R} {z : S} (hp : p ∈ Ideal.comap (algebraMap R S) (conductor R x)) (hz' : z ∈ I.map (algebraMap R S)) : algebraMap R S p * z ∈ algebraMap R S '' ↑(I.map (algebraMap R R)) := by - rw [Ideal.map, Ideal.span, Finsupp.mem_span_image_iff_total] at hz' + rw [Ideal.map, Ideal.span, Finsupp.mem_span_image_iff_linearCombination] at hz' obtain ⟨l, H, H'⟩ := hz' - rw [Finsupp.total_apply] at H' + rw [Finsupp.linearCombination_apply] at H' rw [← H', mul_comm, Finsupp.sum_mul] have lem : ∀ {a : R}, a ∈ I → l a • algebraMap R S a * algebraMap R S p ∈ algebraMap R S '' I.map (algebraMap R R) := by @@ -168,7 +168,8 @@ theorem comap_map_eq_map_adjoin_of_coprime_conductor obtain ⟨x₁, hx₁, hx₂⟩ := (Set.mem_image _ _ _).mp h have : x₁ = ⟨z, hz⟩ := by apply h_alg - simp [hx₂, algebraMap_eq_smul_one] + simp only [hx₂, algebraMap_eq_smul_one] + rw [Submonoid.mk_smul, smul_eq_mul, mul_one] rwa [← this] · -- The converse inclusion is trivial have : algebraMap R S = (algebraMap _ S).comp (algebraMap R R) := by ext; rfl @@ -282,8 +283,8 @@ theorem normalizedFactors_ideal_map_eq_normalizedFactors_min_poly_mk_map (hI : I by_cases hJ : J ∈ normalizedFactors (I.map (algebraMap R S)) swap · rw [Multiset.count_eq_zero.mpr hJ, eq_comm, Multiset.count_eq_zero, Multiset.mem_map] - simp only [Multiset.mem_attach, true_and_iff, not_exists] - rintro J' rfl + simp only [not_exists] + rintro J' ⟨_, rfl⟩ exact hJ ((normalizedFactorsMapEquivNormalizedFactorsMinPolyMk hI hI' hx hx').symm J').prop -- Then we just have to compare the multiplicities, which we already proved are equal. diff --git a/Mathlib/NumberTheory/LSeries/AbstractFuncEq.lean b/Mathlib/NumberTheory/LSeries/AbstractFuncEq.lean index 14bfeef13fb1d..64d09847b3f9e 100644 --- a/Mathlib/NumberTheory/LSeries/AbstractFuncEq.lean +++ b/Mathlib/NumberTheory/LSeries/AbstractFuncEq.lean @@ -145,7 +145,7 @@ lemma hf_zero (P : WeakFEPair E) (r : ℝ) : specialize hC' hx simp_rw [Function.comp_apply, ← one_div, P.h_feq' _ hx] at hC' rw [← ((mul_inv_cancel₀ h_nv).symm ▸ one_smul ℂ P.g₀ :), mul_smul _ _ P.g₀, ← smul_sub, norm_smul, - ← le_div_iff' (lt_of_le_of_ne (norm_nonneg _) (norm_ne_zero_iff.mpr h_nv).symm)] at hC' + ← le_div_iff₀' (lt_of_le_of_ne (norm_nonneg _) (norm_ne_zero_iff.mpr h_nv).symm)] at hC' convert hC' using 1 · congr 3 rw [rpow_neg hx.le] @@ -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 @@ -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 4087714eb2195..7221b06b0360f 100644 --- a/Mathlib/NumberTheory/LSeries/Basic.lean +++ b/Mathlib/NumberTheory/LSeries/Basic.lean @@ -77,6 +77,16 @@ lemma term_of_ne_zero {n : ℕ} (hn : n ≠ 0) (f : ℕ → ℂ) (s : ℂ) : term f s n = f n / n ^ s := if_neg hn +/-- +If `s ≠ 0`, then the `if .. then .. else` construction in `LSeries.term` isn't needed, since +`0 ^ s = 0`. +-/ +lemma term_of_ne_zero' {s : ℂ} (hs : s ≠ 0) (f : ℕ → ℂ) (n : ℕ) : + term f s n = f n / n ^ s := by + rcases eq_or_ne n 0 with rfl | hn + · rw [term_zero, Nat.cast_zero, zero_cpow hs, div_zero] + · rw [term_of_ne_zero hn] + lemma term_congr {f g : ℕ → ℂ} (h : ∀ {n}, n ≠ 0 → f n = g n) (s : ℂ) (n : ℕ) : term f s n = term g s n := by rcases eq_or_ne n 0 with hn | hn <;> simp [hn, h] @@ -282,7 +292,7 @@ lemma LSeriesSummable.le_const_mul_rpow {f : ℕ → ℂ} {s : ℂ} (h : LSeries obtain ⟨n, hn₀, hn⟩ := H (tsum fun n ↦ ‖term f s n‖) have := le_tsum h n fun _ _ ↦ norm_nonneg _ rw [norm_term_eq, if_neg hn₀, - div_le_iff <| Real.rpow_pos_of_pos (Nat.cast_pos.mpr <| Nat.pos_of_ne_zero hn₀) _] at this + div_le_iff₀ <| Real.rpow_pos_of_pos (Nat.cast_pos.mpr <| Nat.pos_of_ne_zero hn₀) _] at this exact (this.trans_lt hn).false.elim open Filter in @@ -320,7 +330,7 @@ lemma LSeriesSummable_of_le_const_mul_rpow {f : ℕ → ℂ} {x : ℝ} {s : ℂ} · simp only [term_zero, norm_zero] exact norm_nonneg _ have hn' : 0 < (n : ℝ) ^ s.re := Real.rpow_pos_of_pos (Nat.cast_pos.mpr hn) _ - simp_rw [term_of_ne_zero hn.ne', norm_div, norm_natCast_cpow_of_pos hn, div_le_iff hn', + simp_rw [term_of_ne_zero hn.ne', norm_div, norm_natCast_cpow_of_pos hn, div_le_iff₀ hn', norm_eq_abs (C : ℂ), abs_ofReal, _root_.abs_of_nonneg hC₀, div_eq_mul_inv, mul_assoc, ← Real.rpow_neg <| Nat.cast_nonneg _, ← Real.rpow_add <| Nat.cast_pos.mpr hn] simp only [add_re, sub_re, one_re, ofReal_re, neg_add_rev, neg_sub, neg_add_cancel_right] @@ -344,7 +354,7 @@ lemma LSeriesSummable_of_isBigO_rpow {f : ℕ → ℂ} {x : ℝ} {s : ℂ} (hs : gcongr rw [Real.norm_eq_abs, abs_rpow_of_nonneg hn₀, _root_.abs_of_nonneg hn₀] · have hn' : 0 < n := Nat.pos_of_ne_zero hn₀ - refine (div_le_iff <| rpow_pos_of_pos (cast_pos.mpr hn') _).mp ?_ + refine (div_le_iff₀ <| rpow_pos_of_pos (cast_pos.mpr hn') _).mp ?_ refine (le_max' _ _ <| mem_insert_of_mem ?_).trans <| le_max_right .. exact mem_image.mpr ⟨n, mem_range.mpr hn, rfl⟩ diff --git a/Mathlib/NumberTheory/LSeries/Convolution.lean b/Mathlib/NumberTheory/LSeries/Convolution.lean index 4e4d8dd78c86e..5063a90643a41 100644 --- a/Mathlib/NumberTheory/LSeries/Convolution.lean +++ b/Mathlib/NumberTheory/LSeries/Convolution.lean @@ -109,7 +109,7 @@ lemma term_convolution (f g : ℕ → ℂ) (s : ℂ) (n : ℕ) : open Set in /-- We give an expression of the `LSeries.term` of the convolution of two functions -in terms of an a priori infinte sum over all pairs `(k, m)` with `k * m = n` +in terms of an a priori infinite sum over all pairs `(k, m)` with `k * m = n` (the set we sum over is infinite when `n = 0`). This is the version needed for the proof that `L (f ⍟ g) = L f * L g`. -/ lemma term_convolution' (f g : ℕ → ℂ) (s : ℂ) : diff --git a/Mathlib/NumberTheory/LSeries/Deriv.lean b/Mathlib/NumberTheory/LSeries/Deriv.lean index 3960fca45e188..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 @@ -122,7 +122,7 @@ is the same as that of `f`. -/ lemma LSeries.absicssaOfAbsConv_logPowMul {f : ℕ → ℂ} {m : ℕ} : abscissaOfAbsConv (logMul^[m] f) = abscissaOfAbsConv f := by induction' m with n ih - · simp only [Nat.zero_eq, Function.iterate_zero, id_eq] + · simp only [Function.iterate_zero, id_eq] · simp only [ih, Function.iterate_succ', Function.comp_def, abscissaOfAbsConv_logMul] /-- If `re s` is greater than the abscissa of absolute convergence of `f`, then @@ -130,7 +130,7 @@ the `m`th derivative of this L-series is `(-1)^m` times the L-series of `log^m * lemma LSeries_iteratedDeriv {f : ℕ → ℂ} (m : ℕ) {s : ℂ} (h : abscissaOfAbsConv f < s.re) : iteratedDeriv m (LSeries f) s = (-1) ^ m * LSeries (logMul^[m] f) s := by induction' m with m ih generalizing s - · simp only [Nat.zero_eq, iteratedDeriv_zero, pow_zero, Function.iterate_zero, id_eq, one_mul] + · simp only [iteratedDeriv_zero, pow_zero, Function.iterate_zero, id_eq, one_mul] · have ih' : {s | abscissaOfAbsConv f < re s}.EqOn (iteratedDeriv m (LSeries f)) ((-1) ^ m * LSeries (logMul^[m] f)) := fun _ hs ↦ ih hs have := derivWithin_congr ih' (ih h) @@ -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 2ee009cb3d46a..6e6fed2c20936 100644 --- a/Mathlib/NumberTheory/LSeries/Dirichlet.lean +++ b/Mathlib/NumberTheory/LSeries/Dirichlet.lean @@ -137,7 +137,7 @@ lemma convolution_mul_moebius {n : ℕ} (χ : DirichletCharacter ℂ n) : ↗χ lemma modZero_eq_delta {χ : DirichletCharacter ℂ 0} : ↗χ = δ := by ext n rcases eq_or_ne n 0 with rfl | hn - · simp_rw [cast_zero, χ.map_nonunit not_isUnit_zero, delta, if_false] + · simp_rw [cast_zero, χ.map_nonunit not_isUnit_zero, delta, reduceCtorEq, if_false] rcases eq_or_ne n 1 with rfl | hn' · simp only [cast_one, map_one, delta, ↓reduceIte] have : ¬ IsUnit (n : ZMod 0) := fun h ↦ hn' <| ZMod.eq_one_of_isUnit_natCast h diff --git a/Mathlib/NumberTheory/LSeries/DirichletContinuation.lean b/Mathlib/NumberTheory/LSeries/DirichletContinuation.lean new file mode 100644 index 0000000000000..dd4b132bc5130 --- /dev/null +++ b/Mathlib/NumberTheory/LSeries/DirichletContinuation.lean @@ -0,0 +1,70 @@ +/- +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.NumberTheory.LSeries.ZMod +import Mathlib.NumberTheory.DirichletCharacter.Basic + +/-! +# 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). + +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. + +## 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. +-/ + +open Complex + +namespace DirichletCharacter + +variable {N : ℕ} [NeZero N] + +/-- +The unique meromorphic function `ℂ → ℂ` which agrees with `∑' n : ℕ, χ n / n ^ s` wherever the +latter is convergent. This is constructed as a linear combination of Hurwitz zeta functions. + +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`. + -/ +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`.) -/ +@[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] + +/-- +For `1 < re s` the L-function of a Dirichlet character agrees with the sum of the naive Dirichlet +series. +-/ +lemma LFunction_eq_LSeries (χ : DirichletCharacter ℂ N) {s : ℂ} (hs : 1 < re s) : + LFunction χ s = LSeries (χ ·) s := + ZMod.LFunction_eq_LSeries χ hs + +/-- +The L-function of a Dirichlet character is differentiable, except at `s = 1` if the character is +trivial. +-/ +lemma differentiableAt_LFunction (χ : DirichletCharacter ℂ N) (s : ℂ) (hs : s ≠ 1 ∨ χ ≠ 1) : + DifferentiableAt ℂ (LFunction χ) s := + ZMod.differentiableAt_LFunction χ s (hs.imp_right χ.sum_eq_zero_of_ne_one) + +/-- The L-function of a non-trivial Dirichlet character is differentiable everywhere. -/ +lemma differentiable_LFunction {χ : DirichletCharacter ℂ N} (hχ : χ ≠ 1) : + Differentiable ℂ (LFunction χ) := + (differentiableAt_LFunction _ · <| Or.inr hχ) + +end DirichletCharacter diff --git a/Mathlib/NumberTheory/LSeries/HurwitzZeta.lean b/Mathlib/NumberTheory/LSeries/HurwitzZeta.lean index 79f23403685fc..69091d6315bba 100644 --- a/Mathlib/NumberTheory/LSeries/HurwitzZeta.lean +++ b/Mathlib/NumberTheory/LSeries/HurwitzZeta.lean @@ -142,11 +142,9 @@ lemma differentiable_expZeta_of_ne_zero {a : UnitAddCircle} (ha : a ≠ 0) : /-- Reformulation of `hasSum_expZeta_of_one_lt_re` using `LSeriesHasSum`. -/ lemma LSeriesHasSum_exp (a : ℝ) {s : ℂ} (hs : 1 < re s) : - LSeriesHasSum (cexp <| 2 * π * I * a * ·) s (expZeta a s) := by - refine (hasSum_expZeta_of_one_lt_re a hs).congr_fun (fun n ↦ ?_) - rcases eq_or_ne n 0 with rfl | hn - · rw [LSeries.term_zero, Nat.cast_zero, zero_cpow (ne_zero_of_one_lt_re hs), div_zero] - · apply LSeries.term_of_ne_zero hn + LSeriesHasSum (cexp <| 2 * π * I * a * ·) s (expZeta a s) := + (hasSum_expZeta_of_one_lt_re a hs).congr_fun + (LSeries.term_of_ne_zero' (ne_zero_of_one_lt_re hs) _) /-! ## The functional equation diff --git a/Mathlib/NumberTheory/LSeries/HurwitzZetaEven.lean b/Mathlib/NumberTheory/LSeries/HurwitzZetaEven.lean index 48fb9b87f7ce9..ac307e2324e77 100644 --- a/Mathlib/NumberTheory/LSeries/HurwitzZetaEven.lean +++ b/Mathlib/NumberTheory/LSeries/HurwitzZetaEven.lean @@ -768,12 +768,9 @@ lemma hasSum_nat_cosZeta (a : ℝ) {s : ℂ} (hs : 1 < re s) : /-- Reformulation of `hasSum_nat_cosZeta` using `LSeriesHasSum`. -/ lemma LSeriesHasSum_cos (a : ℝ) {s : ℂ} (hs : 1 < re s) : - LSeriesHasSum (Real.cos <| 2 * π * a * ·) s (cosZeta a s) := by - refine (hasSum_nat_cosZeta a hs).congr_fun (fun n ↦ ?_) - rcases eq_or_ne n 0 with rfl | hn - · rw [LSeries.term_zero, Nat.cast_zero, Nat.cast_zero, zero_cpow (ne_zero_of_one_lt_re hs), - div_zero] - · apply LSeries.term_of_ne_zero hn + LSeriesHasSum (Real.cos <| 2 * π * a * ·) s (cosZeta a s) := + (hasSum_nat_cosZeta a hs).congr_fun + (LSeries.term_of_ne_zero' (ne_zero_of_one_lt_re hs) _) /-! ## Functional equations for the un-completed zetas diff --git a/Mathlib/NumberTheory/LSeries/HurwitzZetaOdd.lean b/Mathlib/NumberTheory/LSeries/HurwitzZetaOdd.lean index e14ca16ba1108..cf70f0a830ee7 100644 --- a/Mathlib/NumberTheory/LSeries/HurwitzZetaOdd.lean +++ b/Mathlib/NumberTheory/LSeries/HurwitzZetaOdd.lean @@ -547,11 +547,9 @@ lemma hasSum_nat_sinZeta (a : ℝ) {s : ℂ} (hs : 1 < re s) : /-- Reformulation of `hasSum_nat_sinZeta` using `LSeriesHasSum`. -/ lemma LSeriesHasSum_sin (a : ℝ) {s : ℂ} (hs : 1 < re s) : - LSeriesHasSum (Real.sin <| 2 * π * a * ·) s (sinZeta a s) := by - refine (hasSum_nat_sinZeta a hs).congr_fun (fun n ↦ ?_) - rcases eq_or_ne n 0 with rfl | hn - · rw [LSeries.term_zero, Nat.cast_zero, mul_zero, Real.sin_zero, ofReal_zero, zero_div] - · apply LSeries.term_of_ne_zero hn + LSeriesHasSum (Real.sin <| 2 * π * a * ·) s (sinZeta a s) := + (hasSum_nat_sinZeta a hs).congr_fun + (LSeries.term_of_ne_zero' (ne_zero_of_one_lt_re hs) _) /-- The trivial zeroes of the odd Hurwitz zeta function. -/ theorem hurwitzZetaOdd_neg_two_mul_nat_sub_one (a : UnitAddCircle) (n : ℕ) : diff --git a/Mathlib/NumberTheory/LSeries/Linearity.lean b/Mathlib/NumberTheory/LSeries/Linearity.lean index 163fb8337bcce..edf33f6916742 100644 --- a/Mathlib/NumberTheory/LSeries/Linearity.lean +++ b/Mathlib/NumberTheory/LSeries/Linearity.lean @@ -48,7 +48,7 @@ lemma LSeries_add {f g : ℕ → ℂ} {s : ℂ} (hf : LSeriesSummable f s) (hg : lemma LSeries.term_neg (f : ℕ → ℂ) (s : ℂ) : term (-f) s = -term f s := by ext ⟨- | n⟩ - · simp only [Nat.zero_eq, term_zero, Pi.neg_apply, neg_zero] + · simp only [term_zero, Pi.neg_apply, neg_zero] · simp only [term_of_ne_zero (Nat.succ_ne_zero _), Pi.neg_apply, Nat.cast_succ, neg_div] lemma LSeries.term_neg_apply (f : ℕ → ℂ) (s : ℂ) (n : ℕ) : term (-f) s n = -term f s n := by @@ -105,7 +105,7 @@ lemma LSeries_sub {f g : ℕ → ℂ} {s : ℂ} (hf : LSeriesSummable f s) (hg : lemma LSeries.term_smul (f : ℕ → ℂ) (c s : ℂ) : term (c • f) s = c • term f s := by ext ⟨- | n⟩ - · simp only [Nat.zero_eq, term_zero, Pi.smul_apply, smul_eq_mul, mul_zero] + · simp only [term_zero, Pi.smul_apply, smul_eq_mul, mul_zero] · simp only [term_of_ne_zero (Nat.succ_ne_zero _), Pi.smul_apply, smul_eq_mul, Nat.cast_succ, mul_div_assoc] diff --git a/Mathlib/NumberTheory/LSeries/RiemannZeta.lean b/Mathlib/NumberTheory/LSeries/RiemannZeta.lean index 0afac073a7aa4..bcc35496bf6f6 100644 --- a/Mathlib/NumberTheory/LSeries/RiemannZeta.lean +++ b/Mathlib/NumberTheory/LSeries/RiemannZeta.lean @@ -158,7 +158,7 @@ def RiemannHypothesis : Prop := ∀ (s : ℂ) (_ : riemannZeta s = 0) (_ : ¬∃ n : ℕ, s = -2 * (n + 1)) (_ : s ≠ 1), s.re = 1 / 2 /-! -## Relating the Mellin transform to the Dirichlet series +## Relating the Mellin transform to the Dirichlet series -/ theorem completedZeta_eq_tsum_of_one_lt_re {s : ℂ} (hs : 1 < re s) : @@ -182,7 +182,7 @@ theorem zeta_eq_tsum_one_div_nat_cpow {s : ℂ} (hs : 1 < re s) : ofReal_one] using (hasSum_nat_cosZeta 0 hs).tsum_eq.symm /-- Alternate formulation of `zeta_eq_tsum_one_div_nat_cpow` with a `+ 1` (to avoid relying -on mathlib's conventions for `0 ^ s`). -/ +on mathlib's conventions for `0 ^ s`). -/ theorem zeta_eq_tsum_one_div_nat_add_one_cpow {s : ℂ} (hs : 1 < re s) : riemannZeta s = ∑' n : ℕ, 1 / (n + 1 : ℂ) ^ s := by have := zeta_eq_tsum_one_div_nat_cpow hs @@ -202,7 +202,7 @@ 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 -/- naming scheme was changed from from `riemannCompletedZeta` to `completedRiemannZeta`; add +/- 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 new file mode 100644 index 0000000000000..2ef6c910b132d --- /dev/null +++ b/Mathlib/NumberTheory/LSeries/ZMod.lean @@ -0,0 +1,522 @@ +/- +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.Analysis.Fourier.ZMod +import Mathlib.Analysis.NormedSpace.Connected +import Mathlib.NumberTheory.LSeries.RiemannZeta + +/-! +# 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`) 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 +`Mathlib.NumberTheory.LSeries.DirichletContinuation`. + +## 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 Set + +open scoped Real + +namespace ZMod + +variable {N : ℕ} [NeZero N] + +/-- If `Φ` is a periodic function, then the L-series of `Φ` converges for `1 < re s`. -/ +lemma LSeriesSummable_of_one_lt_re (Φ : ZMod N → ℂ) {s : ℂ} (hs : 1 < re s) : + LSeriesSummable (Φ ·) s := by + let c := max' _ <| univ_nonempty.image (Complex.abs ∘ Φ) + refine LSeriesSummable_of_bounded_of_one_lt_re (fun n _ ↦ le_max' _ _ ?_) (m := c) hs + exact mem_image_of_mem _ (mem_univ _) + +/-- +The unique meromorphic function `ℂ → ℂ` which agrees with `∑' n : ℕ, Φ n / n ^ s` wherever the +latter is convergent. This is constructed as a linear combination of Hurwitz zeta functions. + +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`. + -/ +noncomputable def LFunction (Φ : ZMod N → ℂ) (s : ℂ) : ℂ := + N ^ (-s) * ∑ j : ZMod N, Φ j * hurwitzZeta (toAddCircle j) s + +/-- The L-function of a function on `ZMod 1` is a scalar multiple of the Riemann zeta function. -/ +lemma LFunction_modOne_eq (Φ : ZMod 1 → ℂ) (s : ℂ) : + LFunction Φ s = Φ 0 * riemannZeta s := by + simp only [LFunction, Nat.cast_one, one_cpow, ← singleton_eq_univ (0 : ZMod 1), sum_singleton, + map_zero, hurwitzZeta_zero, one_mul] + +/-- For `1 < re s` the congruence L-function agrees with the sum of the Dirichlet series. -/ +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 := 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] + congr 1 with m + -- The following manipulation is slightly delicate because `(x * y) ^ s = x ^ s * y ^ s` is + -- false for general complex `x`, `y`, but it is true if `x` and `y` are non-negative reals, so + -- we have to carefully juggle coercions `ℕ → ℝ → ℂ`. + calc N ^ (-s) * Φ j * (1 / (m + (j.val / N : ℝ)) ^ s) + _ = Φ j * (N ^ (-s) * (1 / (m + (j.val / N : ℝ)) ^ s)) := by + rw [← mul_assoc, mul_comm _ (Φ _)] + _ = Φ j * (1 / (N : ℝ) ^ s * (1 / ((j.val + N * m) / N : ℝ) ^ s)) := by + simp only [cpow_neg, ← one_div, ofReal_div, ofReal_natCast, add_comm, add_div, ofReal_add, + ofReal_mul, mul_div_cancel_left₀ (m : ℂ) (Nat.cast_ne_zero.mpr (NeZero.ne N))] + _ = Φ j / ((N : ℝ) * ((j.val + N * m) / N : ℝ)) ^ s := by -- this is the delicate step! + rw [one_div_mul_one_div, mul_one_div, mul_cpow_ofReal_nonneg] <;> positivity + _ = Φ j / (N * (j.val + N * m) / N) ^ s := by + simp only [ofReal_natCast, ofReal_div, ofReal_add, ofReal_mul, mul_div_assoc] + _ = Φ j / (j.val + N * m) ^ s := by + rw [mul_div_cancel_left₀ _ (Nat.cast_ne_zero.mpr (NeZero.ne N))] + _ = Φ ↑(j.val + N * m) / (↑(j.val + N * m)) ^ s := by + simp only [Nat.cast_add, Nat.cast_mul, natCast_zmod_val, natCast_self, zero_mul, add_zero] + _ = LSeries.term (Φ ·) s (j.val + N * m) := by + rw [LSeries.term_of_ne_zero' (ne_zero_of_one_lt_re hs)] + +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 + 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 _ ↦ + (differentiableAt_hurwitzZeta_sub_one_div (toAddCircle j)).const_mul (Φ j) + simpa only [mul_sub, sum_sub_distrib, ← sum_mul, hs.neg_resolve_left rfl, zero_mul, sub_zero] + +lemma differentiable_LFunction_of_sum_zero {Φ : ZMod N → ℂ} (hΦ : ∑ j, Φ j = 0) : + Differentiable ℂ (LFunction Φ) := + fun s ↦ differentiableAt_LFunction Φ s (Or.inr hΦ) + +/-- The L-function of `Φ` has a residue at `s = 1` equal to the average value of `Φ`. -/ +lemma LFunction_residue_one (Φ : ZMod N → ℂ) : + Tendsto (fun s ↦ (s - 1) * LFunction Φ s) (𝓝[≠] 1) (𝓝 (∑ j, Φ j / N)) := by + simp only [sum_div, LFunction, mul_sum] + refine tendsto_finset_sum _ fun j _ ↦ ?_ + rw [(by ring : Φ j / N = Φ j * (1 / N * 1)), one_div, ← cpow_neg_one] + simp only [show ∀ a b c d : ℂ, a * (b * (c * d)) = c * (b * (a * d)) by intros; ring] + refine tendsto_const_nhds.mul (.mul ?_ <| hurwitzZeta_residue_one _) + 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)`. + +Note this is not at all obvious from the definitions, and we prove it by analytic continuation +from the convergence range. +-/ +lemma LFunction_stdAddChar_eq_expZeta (j : ZMod N) (s : ℂ) (hjs : j ≠ 0 ∨ s ≠ 1) : + 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 + · simpa only [h, ↓reduceIte, U] using isOpen_compl_singleton + · 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 [mem_ite_univ_right, U]; tauto + -- hypotheses for uniqueness of analytic continuation + 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 : 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 + by_cases h : j = 0 + · simpa only [h, ↓reduceIte, U] using + (isConnected_compl_singleton_of_one_lt_rank (by simp) _).isPreconnected + · simpa only [h, ↓reduceIte, U] using isPreconnected_univ + have hV : V ∈ 𝓝 2 := (continuous_re.isOpen_preimage _ isOpen_Ioi).mem_nhds (by simp) + have hUmem : 2 ∈ U := by simp [U] + have hUmem' : s ∈ U := hU.mpr hjs.symm + -- 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 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 : Φ 0 = 0 ∨ s ≠ 1) : + LFunction (𝓕 Φ) s = ∑ j : ZMod N, Φ j * expZeta (toAddCircle (-j)) s := by + 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' : Φ 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] + 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'.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_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 (differentiable_neg.const_cpow <| .inl <| NeZero.ne _).mul (.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 ((differentiable_neg.const_cpow <| .inl <| NeZero.ne _) s).mul (hs₀.elim ?_ ?_) + · exact fun h ↦ (differentiableAt_const _).div differentiableAt_id h + · exact fun h ↦ by simp only [h, funext zero_div, differentiableAt_const] + · -- term with `1 / (1 - s)` + refine ((differentiable_neg.const_cpow <| .inl <| NeZero.ne _) s).mul (hs₁.elim ?_ ?_) + · exact fun h ↦ (differentiableAt_const _).div (by fun_prop) (by rwa [sub_ne_zero, ne_comm]) + · 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 32524bd59090a..edf39ca7e1be8 100644 --- a/Mathlib/NumberTheory/LegendreSymbol/GaussEisensteinLemmas.lean +++ b/Mathlib/NumberTheory/LegendreSymbol/GaussEisensteinLemmas.lean @@ -4,7 +4,7 @@ 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.Basic +import Mathlib.Analysis.Normed.Field.Lemmas /-! # Lemmas of Gauss and Eisenstein @@ -34,7 +34,7 @@ theorem Ico_map_valMinAbs_natAbs_eq_Ico_map_id (p : ℕ) [hp : Fact p.Prime] (a lt_of_le_of_lt (he hx).2 (Nat.div_lt_self hp.1.pos (by decide)) have hpe : ∀ {x}, x ∈ Ico 1 (p / 2).succ → ¬p ∣ x := fun hx hpx => not_lt_of_ge (le_of_dvd (Nat.pos_of_ne_zero (he hx).1) hpx) (hep hx) - have hmem : ∀ (x : ℕ) (hx : x ∈ Ico 1 (p / 2).succ), + have hmem : ∀ (x : ℕ) (_ : x ∈ Ico 1 (p / 2).succ), (a * x : ZMod p).valMinAbs.natAbs ∈ Ico 1 (p / 2).succ := by intro x hx simp [hap, CharP.cast_eq_zero_iff (ZMod p) p, hpe hx, Nat.lt_succ_iff, succ_le_iff, @@ -49,9 +49,9 @@ 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 @@ -205,7 +205,7 @@ 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) = diff --git a/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean b/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean index 7002957721377..c4b313daf7c59 100644 --- a/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean +++ b/Mathlib/NumberTheory/LegendreSymbol/JacobiSymbol.lean @@ -156,6 +156,10 @@ theorem mul_left (a₁ a₂ : ℤ) (b : ℕ) : J(a₁ * a₂ | b) = J(a₁ | b) (f := fun x ↦ @legendreSym x {out := prime_of_mem_primeFactorsList x.2} a₁) (g := fun x ↦ @legendreSym x {out := prime_of_mem_primeFactorsList x.2} a₂) +#adaptation_note +/-- +After nightly-2024-09-06 we can remove the `_root_` prefixes below. +-/ /-- The symbol `J(a | b)` vanishes iff `a` and `b` are not coprime (assuming `b ≠ 0`). -/ theorem eq_zero_iff_not_coprime {a : ℤ} {b : ℕ} [NeZero b] : J(a | b) = 0 ↔ a.gcd b ≠ 1 := List.prod_eq_zero_iff.trans @@ -165,7 +169,7 @@ theorem eq_zero_iff_not_coprime {a : ℤ} {b : ℕ} [NeZero b] : J(a | b) = 0 -- 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]) + _root_.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 +218,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 +313,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`. -/ @@ -529,7 +533,7 @@ decreasing_by private theorem fastJacobiSymAux.eq_jacobiSym {a b : ℕ} {flip : Bool} {ha0 : a > 0} (hb2 : b % 2 = 1) (hb1 : b > 1) : fastJacobiSymAux a b flip ha0 = if flip then -J(a | b) else J(a | b) := by - induction' a using Nat.strongInductionOn with a IH generalizing b flip + induction' a using Nat.strongRecOn with a IH generalizing b flip unfold fastJacobiSymAux split <;> rename_i ha4 · rw [IH (a / 4) (a.div_lt_self ha0 (by decide)) hb2 hb1] @@ -569,7 +573,7 @@ private def fastJacobiSym (a : ℤ) (b : ℕ) : ℤ := @[csimp] private theorem fastJacobiSym.eq : jacobiSym = fastJacobiSym := by ext a b - induction' b using Nat.strongInductionOn with b IH + induction' b using Nat.strongRecOn with b IH unfold fastJacobiSym split_ifs with hb0 hb2 ha2 hb1 hab · rw [hb0, zero_right] diff --git a/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/Basic.lean b/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/Basic.lean index b9a2c36a497c9..9ba104ca9690a 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] @@ -137,7 +137,7 @@ theorem quadraticChar_zero : quadraticChar F 0 = 0 := by theorem quadraticChar_one_iff_isSquare {a : F} (ha : a ≠ 0) : quadraticChar F a = 1 ↔ IsSquare a := by simp only [quadraticChar_apply, quadraticCharFun, ha, if_false, ite_eq_left_iff, - (by omega : (-1 : ℤ) ≠ 1), imp_false, not_not] + (by omega : (-1 : ℤ) ≠ 1), imp_false, not_not, reduceCtorEq] /-- The quadratic character takes the value `1` on nonzero squares. -/ theorem quadraticChar_sq_one' {a : F} (ha : a ≠ 0) : quadraticChar F (a ^ 2) = 1 := by @@ -213,7 +213,7 @@ when the domain has odd characteristic. -/ theorem quadraticChar_ne_one (hF : ringChar F ≠ 2) : quadraticChar F ≠ 1 := by rcases quadraticChar_exists_neg_one' hF with ⟨a, ha⟩ intro hχ - simp only [hχ, one_apply a.isUnit, one_ne_zero] at ha + simp only [hχ, one_apply a.isUnit, one_ne_zero, reduceCtorEq] at ha set_option linter.deprecated false in @[deprecated quadraticChar_ne_one (since := "2024-06-16")] @@ -247,7 +247,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 +284,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 @@ -292,7 +292,7 @@ theorem FiniteField.isSquare_neg_one_iff : IsSquare (-1 : F) ↔ Fintype.card F rw [← quadraticChar_one_iff_isSquare (neg_ne_zero.mpr (one_ne_zero' F)), quadraticChar_neg_one hF, χ₄_nat_eq_if_mod_four, h₁] simp only [Nat.one_ne_zero, if_false, ite_eq_left_iff, (by omega : (-1 : ℤ) ≠ 1), imp_false, - not_not, Ne] + not_not, Ne, reduceCtorEq] exact ⟨fun h ↦ ne_of_eq_of_ne h (by omega), (Nat.odd_mod_four_iff.mp h₁).resolve_right⟩ end SpecialValues 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 33994e47db69f..04403810047a7 100644 --- a/Mathlib/NumberTheory/Liouville/Basic.lean +++ b/Mathlib/NumberTheory/Liouville/Basic.lean @@ -108,7 +108,7 @@ theorem exists_one_le_pow_mul_dist {Z N R : Type*} [PseudoMetricSpace R] {d : N · -- `j z a = z / (a + 1)`: we prove that this ratio is close to `α` have : j z a ∈ closedBall α ε := by refine mem_closedBall'.mp (le_trans ?_ ((one_div_le me0 e0).mpr (le_max_left _ _))) - exact (le_div_iff me0).mpr (not_le.mp dm1).le + exact (le_div_iff₀ me0).mpr (not_le.mp dm1).le -- use the "separation from `1`" (assumption `L`) for numerators, refine (L this).trans ?_ -- remove a common factor and use the Lipschitz assumption `B` @@ -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 ?_ @@ -207,7 +207,7 @@ protected theorem transcendental {x : ℝ} (lx : Liouville x) : Transcendental · lift b to ℕ using zero_le_one.trans b1.le specialize h a b.pred rwa [← Nat.cast_succ, Nat.succ_pred_eq_of_pos (zero_lt_one.trans _), ← mul_assoc, ← - div_le_iff hA] at h + div_le_iff₀ hA] at h exact Int.ofNat_lt.mp b1 end Liouville diff --git a/Mathlib/NumberTheory/Liouville/LiouvilleNumber.lean b/Mathlib/NumberTheory/Liouville/LiouvilleNumber.lean index 2a8dad8fad8f5..49a8325713112 100644 --- a/Mathlib/NumberTheory/Liouville/LiouvilleNumber.lean +++ b/Mathlib/NumberTheory/Liouville/LiouvilleNumber.lean @@ -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 ac2e9e02f07f7..26c83fc23c3a5 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', @@ -100,10 +100,10 @@ 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. -/ +/-- The product of a Liouville number and a nonzero rational number is again a Liouville number. -/ theorem mul_rat (h : LiouvilleWith p x) (hr : r ≠ 0) : LiouvilleWith p (x * r) := by rcases h.exists_pos with ⟨C, _hC₀, hC⟩ refine ⟨r.den ^ p * (|r| * C), (tendsto_id.nsmul_atTop r.pos).frequently (hC.mono ?_)⟩ diff --git a/Mathlib/NumberTheory/Liouville/Measure.lean b/Mathlib/NumberTheory/Liouville/Measure.lean index c6bd2d0a641c4..618b456b25505 100644 --- a/Mathlib/NumberTheory/Liouville/Measure.lean +++ b/Mathlib/NumberTheory/Liouville/Measure.lean @@ -97,7 +97,7 @@ theorem volume_iUnion_setOf_liouvilleWith : _ = _ := by have : 1 - r ≠ 0 := by linarith rw [ENNReal.coe_inj] - simp [add_mul, div_eq_mul_inv, NNReal.rpow_neg, NNReal.rpow_sub' _ this, mul_add, + simp [add_mul, div_eq_mul_inv, NNReal.rpow_neg, NNReal.rpow_sub' this, mul_add, mul_left_comm] refine ne_top_of_le_ne_top (ENNReal.tsum_coe_ne_top_iff_summable.2 ?_) (ENNReal.tsum_le_tsum this) refine (Summable.add ?_ ?_).mul_left _ <;> simp only [NNReal.summable_rpow] <;> linarith diff --git a/Mathlib/NumberTheory/Liouville/Residual.lean b/Mathlib/NumberTheory/Liouville/Residual.lean index 4d72a848d850a..38feb5335e927 100644 --- a/Mathlib/NumberTheory/Liouville/Residual.lean +++ b/Mathlib/NumberTheory/Liouville/Residual.lean @@ -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 13cbbcc14f54e..fd4fbbd8441a4 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. @@ -59,6 +52,12 @@ theorem mersenne_le_mersenne {p q : ℕ} : mersenne p ≤ mersenne q ↔ p ≤ q @[simp] theorem mersenne_zero : mersenne 0 = 0 := rfl +@[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₀ 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) namespace Mathlib.Meta.Positivity @@ -88,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 @@ -450,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 _⟩ diff --git a/Mathlib/NumberTheory/LucasPrimality.lean b/Mathlib/NumberTheory/LucasPrimality.lean index ac590aca60046..2f2f71e0b2bae 100644 --- a/Mathlib/NumberTheory/LucasPrimality.lean +++ b/Mathlib/NumberTheory/LucasPrimality.lean @@ -7,9 +7,10 @@ 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 +19,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 +37,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/Modular.lean b/Mathlib/NumberTheory/Modular.lean index e14a58682b9f1..d27a687df5826 100644 --- a/Mathlib/NumberTheory/Modular.lean +++ b/Mathlib/NumberTheory/Modular.lean @@ -289,7 +289,7 @@ theorem exists_max_im : ∃ g : SL(2, ℤ), ∀ g' : SL(2, ℤ), (g' • z).im · exact normSq_denom_pos g z /-- Given `z : ℍ` and a bottom row `(c,d)`, among the `g : SL(2,ℤ)` with this bottom row, minimize - `|(g•z).re|`. -/ + `|(g•z).re|`. -/ theorem exists_row_one_eq_and_min_re {cd : Fin 2 → ℤ} (hcd : IsCoprime (cd 0) (cd 1)) : ∃ g : SL(2, ℤ), (↑ₘg) 1 = cd ∧ ∀ g' : SL(2, ℤ), (↑ₘg) 1 = (↑ₘg') 1 → |(g • z).re| ≤ |(g' • z).re| := by @@ -351,13 +351,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 +380,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 +465,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/EisensteinSeries/Defs.lean b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/Defs.lean index 91bae3555b311..ce4577936eb32 100644 --- a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/Defs.lean +++ b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/Defs.lean @@ -64,7 +64,7 @@ lemma vecMul_SL2_mem_gammaSet {v : Fin 2 → ℤ} (hv : v ∈ gammaSet N a) (γ refine ⟨?_, hv.2.vecMulSL γ⟩ have := RingHom.map_vecMul (m := Fin 2) (n := Fin 2) (Int.castRingHom (ZMod N)) γ v simp only [eq_intCast, Int.coe_castRingHom] at this - simp_rw [Function.comp, this, hv.1] + simp_rw [Function.comp_def, this, hv.1] simp variable (a) in diff --git a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/MDifferentiable.lean b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/MDifferentiable.lean index 209318f22a221..1ac2a1db2ed96 100644 --- a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/MDifferentiable.lean +++ b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/MDifferentiable.lean @@ -23,7 +23,7 @@ open UpperHalfPlane Filter Function Complex Manifold CongruenceSubgroup namespace EisensteinSeries -/-- Auxilary lemma showing that for any `k : ℤ` the function `z → 1/(c*z+d)^k` is +/-- Auxiliary lemma showing that for any `k : ℤ` the function `z → 1/(c*z+d)^k` is differentiable on `{z : ℂ | 0 < z.im}`. -/ lemma div_linear_zpow_differentiableOn (k : ℤ) (a : Fin 2 → ℤ) : DifferentiableOn ℂ (fun z : ℂ => (a 0 * z + a 1) ^ (-k)) {z : ℂ | 0 < z.im} := by @@ -36,7 +36,7 @@ lemma div_linear_zpow_differentiableOn (k : ℤ) (a : Fin 2 → ℤ) : · simp only [Fin.isValue, Pi.zero_apply, Int.cast_zero, zero_mul, add_zero, one_div] apply differentiableOn_const -/-- Auxilary lemma showing that for any `k : ℤ` and `(a : Fin 2 → ℤ)` +/-- Auxiliary lemma showing that for any `k : ℤ` and `(a : Fin 2 → ℤ)` the extension of `eisSummand` is differentiable on `{z : ℂ | 0 < z.im}`.-/ lemma eisSummand_extension_differentiableOn (k : ℤ) (a : Fin 2 → ℤ) : DifferentiableOn ℂ (↑ₕeisSummand k a) {z : ℂ | 0 < z.im} := by @@ -55,7 +55,7 @@ theorem eisensteinSeries_SIF_MDifferentiable {k : ℤ} {N : ℕ} (hk : 3 ≤ k) refine DifferentiableOn.differentiableAt ?_ ((isOpen_lt continuous_const Complex.continuous_im).mem_nhds τ.2) exact (eisensteinSeries_tendstoLocallyUniformlyOn hk a).differentiableOn - (eventually_of_forall fun s ↦ DifferentiableOn.sum + (Eventually.of_forall fun s ↦ DifferentiableOn.sum fun _ _ ↦ eisSummand_extension_differentiableOn _ _) (isOpen_lt continuous_const continuous_im) diff --git a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/UniformConvergence.lean b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/UniformConvergence.lean index ed9f6bb7e6f15..7268d68dd4275 100644 --- a/Mathlib/NumberTheory/ModularForms/EisensteinSeries/UniformConvergence.lean +++ b/Mathlib/NumberTheory/ModularForms/EisensteinSeries/UniformConvergence.lean @@ -56,14 +56,14 @@ lemma r1_pos : 0 < r1 z := by dsimp only [r1] positivity -/-- For `c, d ∈ ℝ` with `1 ≤ d ^ 2`, we have `r1 z ≤ |c * z + d| ^ 2`. -/ +/-- For `c, d ∈ ℝ` with `1 ≤ d ^ 2`, we have `r1 z ≤ |c * z + d| ^ 2`. -/ lemma r1_aux_bound (c : ℝ) {d : ℝ} (hd : 1 ≤ d ^ 2) : r1 z ≤ (c * z.re + d) ^ 2 + (c * z.im) ^ 2 := by have H1 : (c * z.re + d) ^ 2 + (c * z.im) ^ 2 = c ^ 2 * (z.re ^ 2 + z.im ^ 2) + d * 2 * c * z.re + d ^ 2 := by ring have H2 : (c ^ 2 * (z.re ^ 2 + z.im ^ 2) + d * 2 * c * z.re + d ^ 2) * (z.re ^ 2 + z.im ^ 2) - z.im ^ 2 = (c * (z.re ^ 2 + z.im ^ 2) + d * z.re) ^ 2 + (d ^ 2 - 1) * z.im ^ 2 := by ring - rw [r1, H1, div_le_iff (by positivity), ← sub_nonneg, H2] + rw [r1, H1, div_le_iff₀ (by positivity), ← sub_nonneg, H2] exact add_nonneg (sq_nonneg _) (mul_nonneg (sub_nonneg.mpr hd) (sq_nonneg _)) /-- This function is used to give an upper bound on the summands in Eisenstein series; it is @@ -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 diff --git a/Mathlib/NumberTheory/ModularForms/JacobiTheta/Bounds.lean b/Mathlib/NumberTheory/ModularForms/JacobiTheta/Bounds.lean index f1931f2f1bb78..5af4baf5ed34a 100644 --- a/Mathlib/NumberTheory/ModularForms/JacobiTheta/Bounds.lean +++ b/Mathlib/NumberTheory/ModularForms/JacobiTheta/Bounds.lean @@ -7,7 +7,7 @@ Authors: David Loeffler import Mathlib.NumberTheory.ModularForms.JacobiTheta.TwoVariable /-! -# Asymptotic bounds for Jacobi theta functions +# Asymptotic bounds for Jacobi theta functions The goal of this file is to establish some technical lemmas about the asymptotics of the sums diff --git a/Mathlib/NumberTheory/ModularForms/JacobiTheta/TwoVariable.lean b/Mathlib/NumberTheory/ModularForms/JacobiTheta/TwoVariable.lean index 10883cf58e5b4..fb58da50e6f50 100644 --- a/Mathlib/NumberTheory/ModularForms/JacobiTheta/TwoVariable.lean +++ b/Mathlib/NumberTheory/ModularForms/JacobiTheta/TwoVariable.lean @@ -285,7 +285,7 @@ lemma jacobiTheta₂'_undef (z : ℂ) {τ : ℂ} (hτ : im τ ≤ 0) : jacobiThe exact not_lt.mpr hτ /-! -## Derivatives and continuity +## Derivatives and continuity -/ lemma hasFDerivAt_jacobiTheta₂ (z : ℂ) {τ : ℂ} (hτ : 0 < im τ) : @@ -373,7 +373,7 @@ lemma continuousAt_jacobiTheta₂' (z : ℂ) {τ : ℂ} (hτ : 0 < im τ) : · exact norm_jacobiTheta₂'_term_le hT (le_of_lt hz') (le_of_lt hτ') n /-! -## Periodicity and conjugation +## Periodicity and conjugation -/ /-- The two-variable Jacobi theta function is periodic in `τ` with period 2. -/ @@ -462,7 +462,7 @@ lemma jacobiTheta₂'_conj (z τ : ℂ) : ## Functional equations -/ -/-- The functional equation for the Jacobi theta function: `jacobiTheta₂ z τ` is an explict factor +/-- The functional equation for the Jacobi theta function: `jacobiTheta₂ z τ` is an explicit factor times `jacobiTheta₂ (z / τ) (-1 / τ)`. This is the key lemma behind the proof of the functional equation for L-series of even Dirichlet characters. -/ theorem jacobiTheta₂_functional_equation (z τ : ℂ) : jacobiTheta₂ z τ = diff --git a/Mathlib/NumberTheory/MulChar/Basic.lean b/Mathlib/NumberTheory/MulChar/Basic.lean index f9a5760d1bcda..e4ed0932f9876 100644 --- a/Mathlib/NumberTheory/MulChar/Basic.lean +++ b/Mathlib/NumberTheory/MulChar/Basic.lean @@ -159,14 +159,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] @@ -454,7 +454,7 @@ lemma injective_ringHomComp {f : R' →+* R''} (hf : Function.Injective f) : lemma ringHomComp_eq_one_iff {f : R' →+* R''} (hf : Function.Injective f) {χ : MulChar R R'} : χ.ringHomComp f = 1 ↔ χ = 1 := by - conv_lhs => rw [← (show (1 : MulChar R R').ringHomComp f = 1 by ext; simp)] + conv_lhs => rw [← (show (1 : MulChar R R').ringHomComp f = 1 by ext; simp)] exact (injective_ringHomComp hf).eq_iff lemma ringHomComp_ne_one_iff {f : R' →+* R''} (hf : Function.Injective f) {χ : MulChar R R'} : @@ -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/MulChar/Lemmas.lean b/Mathlib/NumberTheory/MulChar/Lemmas.lean index b0e6da9769998..d4ac05321aeb8 100644 --- a/Mathlib/NumberTheory/MulChar/Lemmas.lean +++ b/Mathlib/NumberTheory/MulChar/Lemmas.lean @@ -111,7 +111,7 @@ noncomputable def equiv_rootsOfUnity [inst_cyc : IsCyclic Mˣ] : ext simp only [toUnitHom_eq, coe_equivToUnitHom, ofRootOfUnity_spec] map_mul' x y := by - simp only [toUnitHom_eq, equivToUnitHom_mul_apply, Submonoid.mk_mul_mk] + simp only [toUnitHom_eq, equivToUnitHom_mul_apply, MulMemClass.mk_mul_mk] end IsCyclic diff --git a/Mathlib/NumberTheory/Multiplicity.lean b/Mathlib/NumberTheory/Multiplicity.lean index 15ef0f0e6656e..43de4a819a527 100644 --- a/Mathlib/NumberTheory/Multiplicity.lean +++ b/Mathlib/NumberTheory/Multiplicity.lean @@ -6,8 +6,9 @@ Authors: Tian Chen, Mantas Bakšys import Mathlib.Algebra.GeomSum import Mathlib.Algebra.Order.Ring.Basic import Mathlib.Algebra.Ring.Int -import Mathlib.NumberTheory.Padics.PadicVal +import Mathlib.NumberTheory.Padics.PadicVal.Defs import Mathlib.RingTheory.Ideal.Quotient +import Mathlib.Data.Nat.Prime.Basic /-! # Multiplicity in Number Theory @@ -51,7 +52,7 @@ theorem dvd_geom_sum₂_self {x y : R} (h : ↑n ∣ x - y) : theorem sq_dvd_add_pow_sub_sub (p x : R) (n : ℕ) : p ^ 2 ∣ (x + p) ^ n - x ^ (n - 1) * p * n - x ^ n := by cases' n with n n - · simp only [pow_zero, Nat.cast_zero, sub_zero, sub_self, dvd_zero, Nat.zero_eq, mul_zero] + · simp only [pow_zero, Nat.cast_zero, sub_zero, sub_self, dvd_zero, mul_zero] · simp only [Nat.succ_sub_succ_eq_sub, tsub_zero, Nat.cast_succ, add_pow, Finset.sum_range_succ, Nat.choose_self, Nat.succ_sub _, tsub_self, pow_one, Nat.choose_succ_self_right, pow_zero, mul_one, Nat.cast_zero, zero_add, Nat.succ_eq_add_one, add_tsub_cancel_left] @@ -189,7 +190,7 @@ include hp hp1 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 cases' n with n - · simp only [multiplicity.zero, add_top, pow_zero, sub_self, Nat.zero_eq] + · 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 [Nat.succ_eq_add_one] at h rcases eq_coe_iff.mp (PartENat.natCast_get h).symm with ⟨⟨k, hk⟩, hpn⟩ @@ -239,7 +240,7 @@ end CommRing theorem pow_two_pow_sub_pow_two_pow [CommRing R] {x y : R} (n : ℕ) : x ^ 2 ^ n - y ^ 2 ^ n = (∏ i ∈ Finset.range n, (x ^ 2 ^ i + y ^ 2 ^ i)) * (x - y) := by induction' n with d hd - · simp only [pow_zero, pow_one, range_zero, prod_empty, one_mul, Nat.zero_eq] + · simp only [pow_zero, pow_one, range_zero, prod_empty, one_mul] · suffices x ^ 2 ^ d.succ - y ^ 2 ^ d.succ = (x ^ 2 ^ d + y ^ 2 ^ d) * (x ^ 2 ^ d - y ^ 2 ^ d) by rw [this, hd, Finset.prod_range_succ, ← mul_assoc, mul_comm (x ^ 2 ^ d + y ^ 2 ^ d)] rw [Nat.succ_eq_add_one] @@ -256,7 +257,7 @@ theorem Int.sq_mod_four_eq_one_of_odd {x : ℤ} : Odd x → x ^ 2 % 4 = 1 := by 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 - have hx_odd : Odd x := by rwa [Int.odd_iff_not_even, even_iff_two_dvd] + 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 ⟨?_, ?_⟩ @@ -286,11 +287,11 @@ theorem Int.two_pow_two_pow_sub_pow_two_pow {x y : ℤ} (n : ℕ) (hxy : 4 ∣ x 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 - have hx_odd : Odd x := by rwa [Int.odd_iff_not_even, even_iff_two_dvd] + 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, Nat.zero_eq, add_top] + · 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 [Nat.succ_eq_add_one] at h rcases multiplicity.eq_coe_iff.mp (PartENat.natCast_get h).symm with ⟨⟨k, hk⟩, hpn⟩ @@ -299,7 +300,7 @@ theorem Int.two_pow_sub_pow' {x y : ℤ} (n : ℕ) (hxy : 4 ∣ x - y) (hx : ¬2 · norm_cast · 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.odd_iff_not_even] using hx_odd.pow + · simpa only [even_iff_two_dvd, ← Int.not_even_iff_odd] using hx_odd.pow erw [Int.natCast_dvd_natCast] -- `erw` to deal with `2 : ℤ` vs `(2 : ℕ) : ℤ` contrapose! hpn @@ -312,7 +313,7 @@ theorem Int.two_pow_sub_pow {x y : ℤ} {n : ℕ} (hxy : 2 ∣ x - y) (hx : ¬2 multiplicity 2 (x ^ n - y ^ n) + 1 = multiplicity 2 (x + y) + multiplicity 2 (x - y) + multiplicity (2 : ℤ) n := by have hy : Odd y := by - rw [← even_iff_two_dvd, ← Int.odd_iff_not_even] at hx + 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) convert Even.add_odd hxy hx abel @@ -323,7 +324,7 @@ theorem Int.two_pow_sub_pow {x y : ℤ} {n : ℕ} (hxy : 2 ∣ x - y) (hx : ¬2 rw [Int.dvd_iff_emod_eq_zero, Int.sub_emod, Int.sq_mod_four_eq_one_of_odd _, Int.sq_mod_four_eq_one_of_odd hy] · norm_num - · simp only [Int.odd_iff_not_even, even_iff_two_dvd, hx, not_false_iff] + · 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] @@ -332,9 +333,9 @@ theorem Int.two_pow_sub_pow {x y : ℤ} {n : ℕ} (hxy : 2 ∣ x - y) (hx : ¬2 · apply Prime.not_unit simp only [← Nat.prime_iff, Nat.prime_two] · exact two_ne_zero - · rw [← even_iff_two_dvd, ← Int.odd_iff_not_even] + · rw [← even_iff_two_dvd, Int.not_even_iff_odd] apply Odd.pow - simp only [Int.odd_iff_not_even, even_iff_two_dvd, hx, not_false_iff] + 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 = @@ -388,7 +389,7 @@ theorem pow_add_pow (hxy : p ∣ x + y) (hx : ¬p ∣ x) {n : ℕ} (hn : Odd n) iterate 3 rw [padicValNat_def, PartENat.natCast_get] · 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 e7031b91989cc..cd142c881c370 100644 --- a/Mathlib/NumberTheory/NumberField/Basic.lean +++ b/Mathlib/NumberTheory/NumberField/Basic.lean @@ -134,22 +134,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. @@ -164,7 +197,7 @@ lemma coe_injective : Function.Injective (algebraMap (𝓞 K) K) := This is a convenient abbreviation for `map_eq_zero_iff` applied to `NoZeroSMulDivisors.algebraMap_injective`. -/ -@[simp] lemma coe_eq_zero_iff {x : 𝓞 K} : algebraMap _ K x = 0 ↔ x = 0 := +lemma coe_eq_zero_iff {x : 𝓞 K} : algebraMap _ K x = 0 ↔ x = 0 := map_eq_zero_iff _ coe_injective /-- The canonical map from `𝓞 K` to `K` is injective. @@ -274,7 +307,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 5e0cd9a7ebdb7..c62e465bc30d5 100644 --- a/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/Basic.lean +++ b/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/Basic.lean @@ -3,9 +3,9 @@ Copyright (c) 2022 Xavier Roblot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Xavier Roblot -/ -import Mathlib.Algebra.Module.Zlattice.Basic -import Mathlib.NumberTheory.NumberField.Embeddings +import Mathlib.Algebra.Module.ZLattice.Basic import Mathlib.NumberTheory.NumberField.FractionalIdeal +import Mathlib.NumberTheory.NumberField.Units.Basic /-! # Canonical embedding of a number field @@ -24,11 +24,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 +39,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 φ => φ @@ -102,7 +100,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] : @@ -178,18 +176,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,7 +205,7 @@ 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, @@ -212,7 +220,7 @@ 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 +244,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 +278,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 +308,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 +328,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 +336,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 +360,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 +369,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, @@ -403,32 +427,34 @@ noncomputable section stdBasis open scoped Classical -open Complex MeasureTheory MeasureTheory.Measure Zspan Matrix ComplexConjugate +open Complex MeasureTheory MeasureTheory.Measure ZSpan Matrix ComplexConjugate 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 +491,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} @@ -547,9 +573,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` @@ -571,7 +601,7 @@ 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 rw [show Set.range (latticeBasis K) = @@ -582,6 +612,20 @@ 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 (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) + 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] @@ -611,8 +655,8 @@ variable (I : (FractionalIdeal (𝓞 K)⁰ K)ˣ) /-- 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 +672,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 +694,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) = diff --git a/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/ConvexBody.lean b/Mathlib/NumberTheory/NumberField/CanonicalEmbedding/ConvexBody.lean index f34495bae5580..36a06aabe738b 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,9 +77,9 @@ open scoped Classical variable [NumberField K] -instance : IsAddHaarMeasure (volume : Measure (E K)) := prod.instIsAddHaarMeasure volume volume +instance : IsAddHaarMeasure (volume : Measure (mixedSpace K)) := prod.instIsAddHaarMeasure _ _ -instance : NoAtoms (volume : Measure (E K)) := by +instance : NoAtoms (volume : Measure (mixedSpace K)) := by obtain ⟨w⟩ := (inferInstance : Nonempty (InfinitePlace K)) by_cases hw : IsReal w · exact @prod.instNoAtoms_fst _ _ _ _ volume volume _ (pi_noAtoms ⟨w, hw⟩) @@ -98,8 +94,7 @@ 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`. -/ @@ -160,7 +155,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))) @@ -170,21 +165,24 @@ theorem convexBodyLT'_mem {x : K} : (∀ w : InfinitePlace K, w ≠ w₀ → w x < f w) ∧ |(w₀.val.embedding x).re| < 1 ∧ |(w₀.val.embedding x).im| < (f w₀ : ℝ) ^ 2 := by simp_rw [mixedEmbedding, RingHom.prod_apply, Set.mem_prod, Set.mem_pi, Set.mem_univ, - forall_true_left, Pi.ringHom_apply, apply_ite, mem_ball_zero_iff, ← Complex.norm_real, - embedding_of_isReal_apply, norm_embedding_eq, Subtype.forall, Set.mem_setOf_eq] + forall_true_left, Pi.ringHom_apply, mem_ball_zero_iff, ← Complex.norm_real, + embedding_of_isReal_apply, norm_embedding_eq, Subtype.forall] refine ⟨fun ⟨h₁, h₂⟩ ↦ ⟨fun w h_ne ↦ ?_, ?_⟩, fun ⟨h₁, h₂⟩ ↦ ⟨fun w hw ↦ ?_, fun w hw ↦ ?_⟩⟩ · by_cases hw : IsReal w · exact norm_embedding_eq w _ ▸ h₁ w hw · specialize h₂ w (not_isReal_iff_isComplex.mp hw) + rw [apply_ite (w.embedding x ∈ ·), Set.mem_setOf_eq, + mem_ball_zero_iff, norm_embedding_eq] at h₂ rwa [if_neg (by exact Subtype.coe_ne_coe.1 h_ne)] at h₂ · simpa [if_true] using h₂ w₀.val w₀.prop · exact h₁ w (ne_of_isReal_isComplex hw w₀.prop) · by_cases h_ne : w = w₀ · simpa [h_ne] · rw [if_neg (by exact Subtype.coe_ne_coe.1 h_ne)] + 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 ⊢ @@ -195,8 +193,8 @@ theorem convexBodyLT'_convex : Convex ℝ (convexBodyLT' K f w₀) := by refine Convex.prod (convex_pi (fun _ _ => convex_ball _ _)) (convex_pi (fun _ _ => ?_)) split_ifs · simp_rw [abs_lt] - refine Convex.inter ((convex_halfspace_re_gt _).inter (convex_halfspace_re_lt _)) - ((convex_halfspace_im_gt _).inter (convex_halfspace_im_lt _)) + refine Convex.inter ((convex_halfspace_re_gt _).inter (convex_halfspace_re_lt _)) + ((convex_halfspace_im_gt _).inter (convex_halfspace_im_lt _)) · exact convex_ball _ _ open MeasureTheory MeasureTheory.Measure @@ -213,8 +211,7 @@ 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 @@ -274,14 +271,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, @@ -293,35 +290,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)] @@ -333,16 +330,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 @@ -363,7 +360,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 @@ -406,7 +403,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 @@ -414,13 +411,13 @@ 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) = + 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, @@ -453,7 +450,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 @@ -465,7 +462,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)) = @@ -483,12 +481,12 @@ theorem volume_fundamentalDomain_fractionalIdealLatticeBasis : theorem minkowskiBound_lt_top : minkowskiBound K I < ⊤ := by refine ENNReal.mul_lt_top ?_ ?_ - · exact ne_of_lt (fundamentalDomain_isBounded _).measure_lt_top - · exact ne_of_lt (ENNReal.pow_lt_top (lt_top_iff_ne_top.mpr ENNReal.two_ne_top) _) + · exact (fundamentalDomain_isBounded _).measure_lt_top + · exact ENNReal.pow_lt_top (lt_top_iff_ne_top.mpr ENNReal.two_ne_top) _ theorem minkowskiBound_pos : 0 < minkowskiBound K I := by refine zero_lt_iff.mpr (mul_ne_zero ?_ ?_) - · exact Zspan.measure_fundamentalDomain_ne_zero _ + · exact ZSpan.measure_fundamentalDomain_ne_zero _ · exact ENNReal.pow_ne_zero two_ne_zero _ variable {f : InfinitePlace K → ℝ≥0} (I : (FractionalIdeal (𝓞 K)⁰ K)ˣ) @@ -500,9 +498,9 @@ 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)) : Set (E K)) + change Countable (span ℤ (Set.range (fractionalIdealLatticeBasis K I))) infer_instance obtain ⟨⟨x, hx⟩, h_nz, h_mem⟩ := exists_ne_zero_mem_lattice_of_measure_mul_two_pow_lt_measure h_fund (convexBodyLT_neg_mem K f) (convexBodyLT_convex K f) h @@ -516,9 +514,9 @@ 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)) : Set (E K)) + change Countable (span ℤ (Set.range (fractionalIdealLatticeBasis K I))) infer_instance obtain ⟨⟨x, hx⟩, h_nz, h_mem⟩ := exists_ne_zero_mem_lattice_of_measure_mul_two_pow_lt_measure h_fund (convexBodyLT'_neg_mem K f w₀) (convexBodyLT'_convex K f w₀) h @@ -604,9 +602,9 @@ 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)) : Set (E K)) + change Countable (span ℤ (Set.range (fractionalIdealLatticeBasis K I))) infer_instance obtain ⟨⟨x, hx⟩, h_nz, h_mem⟩ := exists_ne_zero_mem_lattice_of_measure_mul_two_pow_le_measure h_fund (fun _ ↦ convexBodySum_neg_mem K B) (convexBodySum_convex K B) @@ -616,9 +614,9 @@ theorem exists_ne_zero_mem_ideal_of_norm_le {B : ℝ} refine ⟨a, ha, by simpa using h_nz, ?_⟩ rw [← rpow_natCast, ← rpow_le_rpow_iff (by simp only [Rat.cast_abs, abs_nonneg]) (rpow_nonneg h2 _) h1, ← rpow_mul h2, mul_inv_cancel₀ (Nat.cast_ne_zero.mpr - (ne_of_gt finrank_pos)), rpow_one, le_div_iff' (Nat.cast_pos.mpr finrank_pos)] + (ne_of_gt finrank_pos)), rpow_one, le_div_iff₀' (Nat.cast_pos.mpr finrank_pos)] refine le_trans ?_ ((convexBodySum_mem K B).mp h_mem) - rw [← le_div_iff' (Nat.cast_pos.mpr finrank_pos), ← sum_mult_eq, Nat.cast_sum] + rw [← le_div_iff₀' (Nat.cast_pos.mpr finrank_pos), ← sum_mult_eq, Nat.cast_sum] refine le_trans ?_ (geom_mean_le_arith_mean Finset.univ _ _ (fun _ _ => Nat.cast_nonneg _) ?_ (fun _ _ => AbsoluteValue.nonneg _ _)) · simp_rw [← prod_eq_abs_norm, rpow_natCast] 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..06ed53e2b5316 100644 --- a/Mathlib/NumberTheory/NumberField/ClassNumber.lean +++ b/Mathlib/NumberTheory/NumberField/ClassNumber.lean @@ -41,7 +41,7 @@ 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 @@ -75,7 +75,7 @@ theorem _root_.RingOfIntegers.isPrincipalIdealRing_of_abs_discr_lt ((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.lean index a1d88ada36d6b..52a08d5551c4a 100644 --- a/Mathlib/NumberTheory/NumberField/Discriminant.lean +++ b/Mathlib/NumberTheory/NumberField/Discriminant.lean @@ -32,7 +32,7 @@ number field, discriminant namespace NumberField -open FiniteDimensional NumberField NumberField.InfinitePlace Matrix +open Module NumberField NumberField.InfinitePlace Matrix open scoped Classical Real nonZeroDivisors @@ -66,7 +66,7 @@ theorem discr_eq_discr_of_algEquiv {L : Type*} [Field L] [NumberField L] (f : K Basis.map_apply] rfl -open MeasureTheory MeasureTheory.Measure Zspan NumberField.mixedEmbedding +open MeasureTheory MeasureTheory.Measure ZSpan NumberField.mixedEmbedding NumberField.InfinitePlace ENNReal NNReal Complex theorem _root_.NumberField.mixedEmbedding.volume_fundamentalDomain_latticeBasis : @@ -95,7 +95,7 @@ theorem _root_.NumberField.mixedEmbedding.volume_fundamentalDomain_latticeBasis coe_inv two_ne_zero, coe_ofNat, nnnorm_pow, NNReal.sqrt_sq] _ = (2 : ℝ≥0∞)⁻¹ ^ Fintype.card { w // IsComplex w } * NNReal.sqrt ‖discr K‖₊ := by rw [← Algebra.discr_eq_det_embeddingsMatrixReindex_pow_two, Algebra.discr_reindex, - ← coe_discr, map_intCast, ← Complex.nnnorm_int] + ← coe_discr, map_intCast, ← Complex.nnnorm_intCast] ext : 2 dsimp only [M] rw [Matrix.map_apply, Basis.toMatrix_apply, Basis.coe_reindex, Function.comp_apply, @@ -173,7 +173,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 @@ -194,7 +194,7 @@ theorem abs_discr_ge (h : 1 < finrank ℚ K) : convert_to _ ≤ (a m) * (1 + 1 / m : ℝ) ^ (2 * m) / (4 / π) · simp_rw [a, add_mul, one_mul, pow_succ, Nat.factorial_succ] field_simp; ring - · rw [_root_.le_div_iff (by positivity), pow_succ] + · rw [_root_.le_div_iff₀ (by positivity), pow_succ] convert (mul_le_mul h_m this (by positivity) (by positivity)) using 1 field_simp; ring refine le_trans (le_of_eq (by field_simp; norm_num)) (one_add_mul_le_pow ?_ (2 * m)) @@ -233,7 +233,7 @@ Thus it follows from `mixedEmbedding.exists_primitive_element_lt_of_isComplex` a `x` of `K` such that `K = ℚ(x)` and the conjugates of `x` are all bounded by some quantity depending only on `N`. -Since the primitive element `x` is constructed differently depending on wether `K` has a infinite +Since the primitive element `x` is constructed differently depending on whether `K` has a infinite real place or not, the theorem is proved in two parts. -/ @@ -277,7 +277,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 @@ -291,8 +291,8 @@ theorem rank_le_rankOfDiscrBdd : rw [Real.rpow_logb (lt_trans zero_lt_one h₂) (ne_of_gt h₂) (by positivity), ← mul_assoc, ← inv_div, inv_mul_cancel₀ (by norm_num), one_mul, Int.cast_natCast] · refine div_nonneg (Real.log_nonneg ?_) (Real.log_nonneg (le_of_lt h₂)) - rw [mul_comm, ← mul_div_assoc, _root_.le_div_iff (by positivity), one_mul, - ← _root_.div_le_iff (by positivity)] + rw [mul_comm, ← mul_div_assoc, _root_.le_div_iff₀ (by positivity), one_mul, + ← _root_.div_le_iff₀ (by positivity)] exact le_trans (by norm_num) (Nat.one_le_cast.mpr (Nat.one_le_iff_ne_zero.mpr h_nz)) · exact le_max_of_le_left h @@ -307,7 +307,7 @@ 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) + · 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, NNReal.coe_natCast, ← Int.cast_natCast, Int.cast_le] · exact one_le_two @@ -337,6 +337,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 @@ -360,12 +362,15 @@ theorem finite_of_discr_bdd_of_isReal : · refine mem_rootSet.mpr ⟨minpoly.ne_zero hx, ?_⟩ exact (aeval_algebraMap_eq_zero_iff _ _ _).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 +385,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 @@ -404,7 +411,9 @@ theorem finite_of_discr_bdd_of_isComplex : · refine mem_rootSet.mpr ⟨minpoly.ne_zero hx, ?_⟩ exact (aeval_algebraMap_eq_zero_iff _ _ _).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 +428,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₀ diff --git a/Mathlib/NumberTheory/NumberField/Embeddings.lean b/Mathlib/NumberTheory/NumberField/Embeddings.lean index 7df0582059f8b..d713d6bce1442 100644 --- a/Mathlib/NumberTheory/NumberField/Embeddings.lean +++ b/Mathlib/NumberTheory/NumberField/Embeddings.lean @@ -38,7 +38,7 @@ 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 _ _ @@ -450,7 +450,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 @@ -483,13 +483,13 @@ section NumberField variable [NumberField K] /-- The infinite part of the product formula : for `x ∈ K`, we have `Π_w ‖x‖_w = |norm(x)|` where -`‖·‖_w` is the normalized absolute value for `w`. -/ +`‖·‖_w` is the normalized absolute value for `w`. -/ theorem prod_eq_abs_norm (x : K) : ∏ w : InfinitePlace K, w x ^ mult w = abs (Algebra.norm ℚ x) := by convert (congr_arg Complex.abs (@Algebra.norm_eq_prod_embeddings ℚ _ _ _ _ ℂ _ _ _ _ _ x)).symm · rw [map_prod, ← 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))] + rw [← Finset.prod_fiberwise Finset.univ 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φ @@ -505,7 +505,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 +546,7 @@ theorem _root_.NumberField.adjoin_eq_top_of_infinitePlace_lt {x : 𝓞 K} {w : I end NumberField -open Fintype FiniteDimensional +open Fintype Module variable (K) @@ -1021,15 +1021,15 @@ variable {K} lemma IsUnramifiedAtInfinitePlaces_of_odd_card_aut [IsGalois k K] [FiniteDimensional k K] (h : Odd (Fintype.card <| K ≃ₐ[k] K)) : IsUnramifiedAtInfinitePlaces k K := - ⟨fun _ ↦ not_not.mp (Nat.odd_iff_not_even.mp h ∘ InfinitePlace.even_card_aut_of_not_isUnramified)⟩ + ⟨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 := - ⟨fun _ ↦ not_not.mp (Nat.odd_iff_not_even.mp h ∘ InfinitePlace.even_finrank_of_not_isUnramified)⟩ + (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 diff --git a/Mathlib/NumberTheory/NumberField/EquivReindex.lean b/Mathlib/NumberTheory/NumberField/EquivReindex.lean index 67fc4926a8307..0226ce9f8e5d5 100644 --- a/Mathlib/NumberTheory/NumberField/EquivReindex.lean +++ b/Mathlib/NumberTheory/NumberField/EquivReindex.lean @@ -21,7 +21,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 371f141943b5f..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, @@ -103,7 +103,7 @@ open Module /-- The absolute value of the determinant of the base change from `integralBasis` to `basisOfFractionalIdeal I` is equal to the norm of `I`. -/ -theorem det_basisOfFractionalIdeal_eq_absNorm (I : (FractionalIdeal (𝓞 K)⁰ K)ˣ) +theorem det_basisOfFractionalIdeal_eq_absNorm (I : (FractionalIdeal (𝓞 K)⁰ K)ˣ) (e : (Free.ChooseBasisIndex ℤ (𝓞 K)) ≃ (Free.ChooseBasisIndex ℤ I)) : |(integralBasis K).det ((basisOfFractionalIdeal K I).reindex e.symm)| = FractionalIdeal.absNorm I.1 := by diff --git a/Mathlib/NumberTheory/NumberField/House.lean b/Mathlib/NumberTheory/NumberField/House.lean index 7cceb1f1e7e7c..d56eb4d18c668 100644 --- a/Mathlib/NumberTheory/NumberField/House.lean +++ b/Mathlib/NumberTheory/NumberField/House.lean @@ -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 @@ -149,7 +149,7 @@ private theorem asiegel_ne_0 : asiegel K a ≠ 0 := by variable {p q : ℕ} (h0p : 0 < p) (hpq : p < q) (x : β × (K →+* ℂ) → ℤ) (hxl : x ≠ 0) -/-- `ξ` is the the product of `x (l, r)` and the `r`-th basis element of the newBasis of `K`. -/ +/-- `ξ` is the product of `x (l, r)` and the `r`-th basis element of the newBasis of `K`. -/ private def ξ : β → 𝓞 K := fun l => ∑ r : K →+* ℂ, x (l, r) * (newBasis K r) include hxl in diff --git a/Mathlib/NumberTheory/NumberField/Norm.lean b/Mathlib/NumberTheory/NumberField/Norm.lean index 2b99550a8a94e..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 @@ -40,7 +40,7 @@ namespace RingOfIntegers variable {L : Type*} (K : Type*) [Field K] [Field L] [Algebra K L] [FiniteDimensional K L] -/-- `Algebra.norm` as a morphism betwen the rings of integers. -/ +/-- `Algebra.norm` as a morphism between the rings of integers. -/ noncomputable def norm [Algebra.IsSeparable K L] : 𝓞 L →* 𝓞 K := RingOfIntegers.restrict_monoidHom ((Algebra.norm K).comp (algebraMap (𝓞 L) L : (𝓞 L) →* L)) diff --git a/Mathlib/NumberTheory/NumberField/Units/Basic.lean b/Mathlib/NumberTheory/NumberField/Units/Basic.lean index 84ab8c9274a4e..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 @@ -102,7 +103,7 @@ def torsion : Subgroup (𝓞 K)ˣ := CommGroup.torsion (𝓞 K)ˣ theorem mem_torsion {x : (𝓞 K)ˣ} [NumberField K] : x ∈ torsion K ↔ ∀ w : InfinitePlace K, w x = 1 := by rw [eq_iff_eq (x : K) 1, torsion, CommGroup.mem_torsion] - refine ⟨fun hx φ ↦ (((φ.comp $ algebraMap (𝓞 K) K).toMonoidHom.comp $ + refine ⟨fun hx φ ↦ (((φ.comp <| algebraMap (𝓞 K) K).toMonoidHom.comp <| Units.coeHom _).isOfFinOrder hx).norm_eq_one, fun h ↦ isOfFinOrder_iff_pow_eq_one.2 ?_⟩ obtain ⟨n, hn, hx⟩ := Embeddings.pow_eq_one_of_norm_eq_one K ℂ x.val.isIntegral_coe h exact ⟨n, hn, by ext; rw [NumberField.RingOfIntegers.coe_eq_algebraMap, coe_pow, hx, @@ -121,7 +122,7 @@ instance [NumberField K] : Fintype (torsion K) := by instance : Nonempty (torsion K) := One.instNonempty -/-- The torsion subgroup is cylic. -/ +/-- The torsion subgroup is cyclic. -/ instance [NumberField K] : IsCyclic (torsion K) := subgroup_units_cyclic _ /-- The order of the torsion subgroup as a positive integer. -/ diff --git a/Mathlib/NumberTheory/NumberField/Units/DirichletTheorem.lean b/Mathlib/NumberTheory/NumberField/Units/DirichletTheorem.lean index 33f35ed619614..12b15e1ddd7d7 100644 --- a/Mathlib/NumberTheory/NumberField/Units/DirichletTheorem.lean +++ b/Mathlib/NumberTheory/NumberField/Units/DirichletTheorem.lean @@ -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] @@ -302,7 +304,7 @@ theorem exists_unit (w₁ : InfinitePlace K) : _ = 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] + rw [map_inv₀, mul_inv_lt_iff₀ (pos_iff.mpr (seq_ne_zero K w₁ hB n)), one_mul] exact seq_decreasing K w₁ hB hnm w hw refine Set.Finite.exists_lt_map_eq_of_forall_mem (t := { I : Ideal (𝓞 K) | 1 ≤ Ideal.absNorm I ∧ Ideal.absNorm I ≤ B }) @@ -320,13 +322,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 +354,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 @@ -368,7 +370,7 @@ instance instDiscrete_unitLattice : DiscreteTopology (unitLattice K) := by rintro ⟨x, hx, rfl⟩ exact ⟨Subtype.mem x, hx⟩ -instance instZlattice_unitLattice : IsZlattice ℝ (unitLattice K) where +instance instZLattice_unitLattice : IsZLattice ℝ (unitLattice K) where span_top := unitLattice_span_eq_top K protected theorem finrank_eq_rank : @@ -379,7 +381,7 @@ protected theorem finrank_eq_rank : @[simp] theorem unitLattice_rank : finrank ℤ (unitLattice K) = Units.rank K := by - rw [← Units.finrank_eq_rank, Zlattice.rank ℝ] + rw [← Units.finrank_eq_rank, ZLattice.rank ℝ] /-- The map obtained by quotienting by the kernel of `logEmbedding`. -/ def logEmbeddingQuot : @@ -389,12 +391,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 +422,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 x ↦ 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 +462,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 +481,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 +524,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 6f0d5731d2ffe..34d7ce2339491 100644 --- a/Mathlib/NumberTheory/NumberField/Units/Regulator.lean +++ b/Mathlib/NumberTheory/NumberField/Units/Regulator.lean @@ -3,7 +3,7 @@ Copyright (c) 2024 Xavier Roblot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Xavier Roblot -/ -import Mathlib.Algebra.Module.Zlattice.Covolume +import Mathlib.Algebra.Module.ZLattice.Covolume import Mathlib.LinearAlgebra.Matrix.Determinant.Misc import Mathlib.NumberTheory.NumberField.Units.DirichletTheorem @@ -37,12 +37,12 @@ open MeasureTheory Classical BigOperators NumberField.InfinitePlace variable [NumberField K] -/-- The regulator of a number fied `K`. -/ -def regulator : ℝ := Zlattice.covolume (unitLattice K) +/-- The regulator of a number field `K`. -/ +def regulator : ℝ := ZLattice.covolume (unitLattice K) -theorem regulator_ne_zero : regulator K ≠ 0 := Zlattice.covolume_ne_zero (unitLattice K) volume +theorem regulator_ne_zero : regulator K ≠ 0 := ZLattice.covolume_ne_zero (unitLattice K) volume -theorem regulator_pos : 0 < regulator K := Zlattice.covolume_pos (unitLattice K) volume +theorem regulator_pos : 0 < regulator K := ZLattice.covolume_pos (unitLattice K) volume #adaptation_note /-- @@ -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 - simp_rw [regulator, Zlattice.covolume_eq_det _ + 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, 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 c41547159ecef..de32a03798da5 100644 --- a/Mathlib/NumberTheory/Ostrowski.lean +++ b/Mathlib/NumberTheory/Ostrowski.lean @@ -6,7 +6,7 @@ María Inés de Frutos-Fernández, Sam van Gool, Silvain Rideau-Kikuchi, Amos Tu Francesco Veneziano -/ -import Mathlib.Analysis.Normed.Field.Basic +import Mathlib.Analysis.Normed.Field.Lemmas import Mathlib.Analysis.SpecialFunctions.Log.Base import Mathlib.Analysis.SpecialFunctions.Pow.Real import Mathlib.Analysis.Normed.Ring.Seminorm diff --git a/Mathlib/NumberTheory/Padics/Hensel.lean b/Mathlib/NumberTheory/Padics/Hensel.lean index d32fe3c1f17a2..05f97027ce268 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 = @@ -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 2076ea8bd3206..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] @@ -162,7 +162,8 @@ def inv : ℤ_[p] → ℤ_[p] | ⟨k, _⟩ => if h : ‖k‖ = 1 then ⟨k⁻¹, by simp [h]⟩ else 0 instance : CharZero ℤ_[p] where - cast_injective m n h := Nat.cast_injective (by rw [Subtype.ext_iff] at h; norm_cast at h) + cast_injective m n h := + Nat.cast_injective (R := ℚ_[p]) (by rw [Subtype.ext_iff] at h; norm_cast at h) @[norm_cast] -- @[simp] -- Porting note: not in simpNF theorem intCast_eq (z1 z2 : ℤ) : (z1 : ℤ_[p]) = z2 ↔ z1 = z2 := by @@ -303,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 @@ -333,7 +334,7 @@ theorem norm_int_le_pow_iff_dvd {k : ℤ} {n : ℕ} : /-! ### Valuation on `ℤ_[p]` -/ -/-- `PadicInt.valuation` lifts the `p`-adic valuation on `ℚ` to `ℤ_[p]`. -/ +/-- `PadicInt.valuation` lifts the `p`-adic valuation on `ℚ` to `ℤ_[p]`. -/ def valuation (x : ℤ_[p]) := Padic.valuation (x : ℚ_[p]) @@ -355,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 @@ -372,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 @@ -432,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] @@ -467,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 @@ -493,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] @@ -527,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 @@ -568,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 fb022f982f49c..311b2e21e81be 100644 --- a/Mathlib/NumberTheory/Padics/PadicNorm.lean +++ b/Mathlib/NumberTheory/Padics/PadicNorm.lean @@ -3,8 +3,7 @@ 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 +import Mathlib.NumberTheory.Padics.PadicVal.Basic /-! # p-adic norm @@ -92,7 +91,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 +142,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 +161,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,7 +225,7 @@ 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, @@ -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 3297fc932dd26..33559d1491dfe 100644 --- a/Mathlib/NumberTheory/Padics/PadicNumbers.lean +++ b/Mathlib/NumberTheory/Padics/PadicNumbers.lean @@ -5,7 +5,7 @@ Authors: Robert Y. Lewis -/ import Mathlib.RingTheory.Valuation.Basic import Mathlib.NumberTheory.Padics.PadicNorm -import Mathlib.Analysis.Normed.Field.Basic +import Mathlib.Analysis.Normed.Field.Lemmas import Mathlib.Tactic.Peel import Mathlib.Topology.MetricSpace.Ultra.Basic @@ -37,9 +37,6 @@ We use the same concrete Cauchy sequence construction that is used to construct The extension of the norm on `ℚ` to `ℚ_[p]` is *not* analogous to extending the absolute value to `ℝ` and hence the proof that `ℚ_[p]` is complete is different from the proof that ℝ is complete. -A small special-purpose simplification tactic, `padic_index_simp`, is used to manipulate sequence -indices in the proof that the norm extends. - `padicNormE` is the rational-valued `p`-adic norm on `ℚ_[p]`. To instantiate `ℚ_[p]` as a normed field, we must cast this into an `ℝ`-valued norm. The `ℝ`-valued norm, using notation `‖ ‖` from normed spaces, @@ -152,7 +149,8 @@ theorem not_limZero_const_of_nonzero {q : ℚ} (hq : q ≠ 0) : ¬LimZero (const fun h' ↦ hq <| const_limZero.1 h' theorem not_equiv_zero_const_of_nonzero {q : ℚ} (hq : q ≠ 0) : ¬const (padicNorm p) q ≈ 0 := - fun h : LimZero (const (padicNorm p) q - 0) ↦ not_limZero_const_of_nonzero hq <| by simpa using h + fun h : LimZero (const (padicNorm p) q - 0) ↦ + not_limZero_const_of_nonzero (p := p) hq <| by simpa using h theorem norm_nonneg (f : PadicSeq p) : 0 ≤ f.norm := by classical exact if hf : f ≈ 0 then by simp [hf, norm] else by simp [norm, hf, padicNorm.nonneg] @@ -213,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 @@ -267,8 +265,8 @@ theorem norm_mul (f g : PadicSeq p) : (f * g).norm = f.norm * g.norm := by simp only [hf, hg, norm, dif_pos, mul_zero] else by unfold norm - split_ifs with hfg - · exact (mul_not_equiv_zero hf hg hfg).elim + have hfg := mul_not_equiv_zero hf hg + simp only [hfg, hf, hg, dite_false] -- Porting note: originally `padic_index_simp [hfg, hf, hg]` rw [lift_index_left_left hfg, lift_index_left hf, lift_index_right hg] apply padicNorm.mul @@ -277,7 +275,7 @@ theorem eq_zero_iff_equiv_zero (f : PadicSeq p) : mk f = 0 ↔ f ≈ 0 := mk_eq theorem ne_zero_iff_nequiv_zero (f : PadicSeq p) : mk f ≠ 0 ↔ ¬f ≈ 0 := - not_iff_not.2 (eq_zero_iff_equiv_zero _) + eq_zero_iff_equiv_zero _ |>.not theorem norm_const (q : ℚ) : norm (const (padicNorm p) q) = padicNorm p q := if hq : q = 0 then by @@ -320,15 +318,12 @@ private theorem norm_eq_of_equiv_aux {f g : PadicSeq p} (hf : ¬f ≈ 0) (hg : private theorem norm_eq_of_equiv {f g : PadicSeq p} (hf : ¬f ≈ 0) (hg : ¬g ≈ 0) (hfg : f ≈ g) : padicNorm p (f (stationaryPoint hf)) = padicNorm p (g (stationaryPoint hg)) := by by_contra h - cases' - Decidable.em - (padicNorm p (g (stationaryPoint hg)) < padicNorm p (f (stationaryPoint hf))) with - hlt hnlt - · exact norm_eq_of_equiv_aux hf hg hfg h hlt - · apply norm_eq_of_equiv_aux hg hf (Setoid.symm hfg) (Ne.symm h) - apply lt_of_le_of_ne - · apply le_of_not_gt hnlt - · apply h + cases lt_or_le (padicNorm p (g (stationaryPoint hg))) (padicNorm p (f (stationaryPoint hf))) with + | inl hlt => + exact norm_eq_of_equiv_aux hf hg hfg h hlt + | inr hle => + apply norm_eq_of_equiv_aux hg hf (Setoid.symm hfg) (Ne.symm h) + exact lt_of_le_of_ne hle h theorem norm_equiv {f g : PadicSeq p} (hfg : f ≈ g) : f.norm = g.norm := by classical @@ -566,9 +561,11 @@ theorem defn (f : PadicSeq p) {ε : ℚ} (hε : 0 < ε) : exact not_lt_of_ge hge hε unfold PadicSeq.norm at hge; split_ifs at hge apply not_le_of_gt _ hge - cases' _root_.em (N ≤ stationaryPoint hne) with hgen hngen - · apply hN _ hgen _ hi - · have := stationaryPoint_spec hne le_rfl (le_of_not_le hngen) + cases _root_.le_total N (stationaryPoint hne) with + | inl hgen => + exact hN _ hgen _ hi + | inr hngen => + have := stationaryPoint_spec hne le_rfl hngen rw [← this] exact hN _ le_rfl _ hi @@ -638,10 +635,10 @@ theorem exi_rat_seq_conv {ε : ℚ} (hε : 0 < ε) : ∃ N, ∀ i ≥ N, padicNormE (f i - (limSeq f i : ℚ_[p]) : ℚ_[p]) < ε := by refine (exists_nat_gt (1 / ε)).imp fun N hN i hi ↦ ?_ have h := Classical.choose_spec (rat_dense' (f i) (div_nat_pos i)) - refine lt_of_lt_of_le h ((div_le_iff' <| mod_cast succ_pos _).mpr ?_) + refine lt_of_lt_of_le h ((div_le_iff₀' <| mod_cast succ_pos _).mpr ?_) rw [right_distrib] apply le_add_of_le_of_nonneg - · exact (div_le_iff hε).mp (le_trans (le_of_lt hN) (mod_cast hi)) + · exact (div_le_iff₀ hε).mp (le_trans (le_of_lt hN) (mod_cast hi)) · apply le_of_lt simpa @@ -782,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)] @@ -836,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 @@ -863,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 @@ -915,19 +910,11 @@ instance complete : CauSeq.IsComplete ℚ_[p] norm where theorem padicNormE_lim_le {f : CauSeq ℚ_[p] norm} {a : ℝ} (ha : 0 < a) (hf : ∀ i, ‖f i‖ ≤ a) : ‖f.lim‖ ≤ a := by - -- Porting note: `Setoid.symm` cannot work out which `Setoid` to use, so instead swap the order - -- now, I use a rewrite to swap it later - obtain ⟨N, hN⟩ := (CauSeq.equiv_lim f) _ ha - rw [← sub_add_cancel f.lim (f N)] - refine le_trans (padicNormE.nonarchimedean _ _) ?_ - rw [norm_sub_rev] - exact max_le (le_of_lt (hN _ le_rfl)) (hf _) - -- Porting note: the following nice `calc` block does not work - -- exact calc - -- ‖f.lim‖ = ‖f.lim - f N + f N‖ := sorry - -- ‖f.lim - f N + f N‖ ≤ max ‖f.lim - f N‖ ‖f N‖ := sorry -- (padicNormE.nonarchimedean _ _) - -- max ‖f.lim - f N‖ ‖f N‖ = max ‖f N - f.lim‖ ‖f N‖ := sorry -- by congr; rw [norm_sub_rev] - -- max ‖f N - f.lim‖ ‖f N‖ ≤ a := sorry -- max_le (le_of_lt (hN _ le_rfl)) (hf _) + obtain ⟨N, hN⟩ := Setoid.symm (CauSeq.equiv_lim f) _ ha + calc + ‖f.lim‖ = ‖f.lim - f N + f N‖ := by simp + _ ≤ max ‖f.lim - f N‖ ‖f N‖ := padicNormE.nonarchimedean _ _ + _ ≤ a := max_le (le_of_lt (hN _ le_rfl)) (hf _) open Filter Set @@ -963,9 +950,8 @@ 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 - intro H - erw [const_equiv p] at H - exact one_ne_zero H + rw [← const_zero, const_equiv p] + exact one_ne_zero rw [dif_neg h] simp @@ -985,7 +971,7 @@ theorem norm_eq_pow_val {x : ℚ_[p]} : x ≠ 0 → ‖x‖ = (p : ℝ) ^ (-x.va @[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 ?_) + refine neg_injective ((zpow_right_strictMono₀ h).injective <| (norm_eq_pow_val ?_).symm.trans ?_) · exact mod_cast (Fact.out : p.Prime).ne_zero · simp @@ -1001,8 +987,9 @@ theorem valuation_map_add {x y : ℚ_[p]} (hxy : x + y ≠ 0) : 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 + rwa [norm_eq_pow_val hx, norm_eq_pow_val hy, norm_eq_pow_val hxy, le_max_iff, + zpow_le_zpow_iff_right₀ hp_one, zpow_le_zpow_iff_right₀ hp_one, neg_le_neg_iff, + neg_le_neg_iff, ← min_le_iff] at h_norm @[simp] theorem valuation_map_mul {x y : ℚ_[p]} (hx : x ≠ 0) (hy : y ≠ 0) : @@ -1015,7 +1002,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 @@ -1025,7 +1012,7 @@ def addValuationDef : ℚ_[p] → WithTop ℤ := @[simp] theorem AddValuation.map_zero : addValuationDef (0 : ℚ_[p]) = ⊤ := by - rw [addValuationDef, if_pos (Eq.refl _)] + rw [addValuationDef, if_pos rfl] @[simp] theorem AddValuation.map_one : addValuationDef (1 : ℚ_[p]) = 0 := by @@ -1035,9 +1022,9 @@ theorem AddValuation.map_mul (x y : ℚ_[p]) : addValuationDef (x * y : ℚ_[p]) = addValuationDef x + addValuationDef y := by simp only [addValuationDef] by_cases hx : x = 0 - · rw [hx, if_pos (Eq.refl _), zero_mul, if_pos (Eq.refl _), WithTop.top_add] + · rw [hx, if_pos rfl, zero_mul, if_pos rfl, WithTop.top_add] · by_cases hy : y = 0 - · rw [hy, if_pos (Eq.refl _), mul_zero, if_pos (Eq.refl _), WithTop.add_top] + · rw [hy, if_pos rfl, mul_zero, if_pos rfl, WithTop.add_top] · rw [if_neg hx, if_neg hy, if_neg (mul_ne_zero hx hy), ← WithTop.coe_add, WithTop.coe_eq_coe, valuation_map_mul hx hy] @@ -1045,13 +1032,13 @@ theorem AddValuation.map_add (x y : ℚ_[p]) : min (addValuationDef x) (addValuationDef y) ≤ addValuationDef (x + y : ℚ_[p]) := by simp only [addValuationDef] by_cases hxy : x + y = 0 - · rw [hxy, if_pos (Eq.refl _)] + · rw [hxy, if_pos rfl] exact le_top · by_cases hx : x = 0 - · rw [hx, if_pos (Eq.refl _), min_eq_right, zero_add] + · rw [hx, if_pos rfl, min_eq_right, zero_add] exact le_top · by_cases hy : y = 0 - · rw [hy, if_pos (Eq.refl _), min_eq_left, add_zero] + · rw [hy, if_pos rfl, min_eq_left, add_zero] exact le_top · rw [if_neg hx, if_neg hy, if_neg hxy, ← WithTop.coe_min, WithTop.coe_le_coe] exact valuation_map_add hxy @@ -1073,14 +1060,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 : ℤ) : @@ -1090,7 +1075,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.lean b/Mathlib/NumberTheory/Padics/PadicVal/Basic.lean similarity index 92% rename from Mathlib/NumberTheory/Padics/PadicVal.lean rename to Mathlib/NumberTheory/Padics/PadicVal/Basic.lean index 368932b6dad66..a50d9d73886f6 100644 --- a/Mathlib/NumberTheory/Padics/PadicVal.lean +++ b/Mathlib/NumberTheory/Padics/PadicVal/Basic.lean @@ -4,10 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Robert Y. Lewis, Matthew Robert Ballard -/ import Mathlib.NumberTheory.Divisors -import Mathlib.Data.Nat.Digits +import Mathlib.NumberTheory.Padics.PadicVal.Defs import Mathlib.Data.Nat.MaxPowDiv import Mathlib.Data.Nat.Multiplicity -import Mathlib.Tactic.IntervalCases /-! # `p`-adic Valuation @@ -68,29 +67,12 @@ open Rat open multiplicity -/-- For `p ≠ 1`, the `p`-adic valuation of a natural `n ≠ 0` is the largest natural number `k` such -that `p^k` divides `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 - namespace padicValNat open multiplicity variable {p : ℕ} -/-- `padicValNat p 0` is `0` for any `p`. -/ -@[simp] -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 - /-- If `p ≠ 0` and `p ≠ 1`, then `padicValNat p p` is `1`. -/ @[simp] theorem self (hp : 1 < p) : padicValNat p p = 1 := by @@ -98,11 +80,6 @@ theorem self (hp : 1 < p) : padicValNat p p = 1 := by have eq_zero_false : p = 0 ↔ False := iff_false_intro (zero_lt_one.trans hp).ne' simp [padicValNat, neq_one, eq_zero_false] -@[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] - theorem eq_zero_of_not_dvd {n : ℕ} (h : ¬p ∣ n) : padicValNat p n = 0 := eq_zero_iff.2 <| Or.inr <| Or.inr h @@ -247,15 +224,6 @@ theorem zero_le_padicValRat_of_nat (n : ℕ) : 0 ≤ padicValRat p n := by simp @[norm_cast] theorem padicValRat_of_nat (n : ℕ) : ↑(padicValNat p n) = padicValRat p n := by simp -/-- 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⟩ - -theorem padicValNat_def' {n : ℕ} (hp : p ≠ 1) (hn : 0 < n) : - ↑(padicValNat p n) = multiplicity p n := by simp [padicValNat, hp, hn] - @[simp] theorem padicValNat_self [Fact p.Prime] : padicValNat p p = 1 := by rw [padicValNat_def (@Fact.out p.Prime).pos] @@ -271,28 +239,6 @@ theorem dvd_iff_padicValNat_ne_zero {p n : ℕ} [Fact p.Prime] (hn0 : n ≠ 0) : ⟨fun h => one_le_iff_ne_zero.mp (one_le_padicValNat_of_dvd hn0.bot_lt h), fun h => Classical.not_not.1 (mt padicValNat.eq_zero_of_not_dvd h)⟩ -open List - -theorem le_multiplicity_iff_replicate_subperm_primeFactorsList {a b : ℕ} {n : ℕ} (ha : a.Prime) - (hb : b ≠ 0) : - ↑n ≤ multiplicity a b ↔ replicate n a <+~ b.primeFactorsList := - (replicate_subperm_primeFactorsList_iff ha hb).trans - multiplicity.pow_dvd_iff_le_multiplicity |>.symm - -@[deprecated (since := "2024-07-17")] -alias le_multiplicity_iff_replicate_subperm_factors := - le_multiplicity_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] - -@[deprecated (since := "2024-07-17")] -alias le_padicValNat_iff_replicate_subperm_factors := - le_padicValNat_iff_replicate_subperm_primeFactorsList - end padicValNat namespace padicValRat diff --git a/Mathlib/NumberTheory/Padics/PadicVal/Defs.lean b/Mathlib/NumberTheory/Padics/PadicVal/Defs.lean new file mode 100644 index 0000000000000..1a6910baae3ae --- /dev/null +++ b/Mathlib/NumberTheory/Padics/PadicVal/Defs.lean @@ -0,0 +1,88 @@ +/- +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, Matthew Robert Ballard +-/ +import Mathlib.RingTheory.Multiplicity +import Mathlib.Data.Nat.Factors + +/-! +# `p`-adic Valuation + +This file defines the `p`-adic valuation on `ℕ`, `ℤ`, and `ℚ`. + +The `p`-adic valuation on `ℚ` is the difference of the multiplicities of `p` in the numerator and +denominator of `q`. This function obeys the standard properties of a valuation, with the appropriate +assumptions on `p`. The `p`-adic valuations on `ℕ` and `ℤ` agree with that on `ℚ`. + +The valuation induces a norm on `ℚ`. This norm is defined in padicNorm.lean. +-/ + +universe u + +open Nat + +open multiplicity + +variable {p : ℕ} + +/-- For `p ≠ 1`, the `p`-adic valuation of a natural `n ≠ 0` is the largest natural number `k` such +that `p^k` divides `n`. If `n = 0` or `p = 1`, then `padicValNat p q` defaults to `0`. -/ +def padicValNat (p : ℕ) (n : ℕ) : ℕ := + if h : p ≠ 1 ∧ 0 < n then (multiplicity p n).get (multiplicity.finite_nat_iff.2 h) else 0 + +/-- 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⟩ + +theorem padicValNat_def' {n : ℕ} (hp : p ≠ 1) (hn : 0 < n) : + ↑(padicValNat p n) = multiplicity p n := by simp [padicValNat, hp, hn] + +namespace padicValNat + +open multiplicity + +open List + +/-- `padicValNat p 0` is `0` for any `p`. -/ +@[simp] +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 + +@[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] + +end padicValNat + +open List + +theorem le_multiplicity_iff_replicate_subperm_primeFactorsList {a b : ℕ} {n : ℕ} (ha : a.Prime) + (hb : b ≠ 0) : + ↑n ≤ multiplicity a b ↔ replicate n a <+~ b.primeFactorsList := + (replicate_subperm_primeFactorsList_iff ha hb).trans + multiplicity.pow_dvd_iff_le_multiplicity |>.symm + +@[deprecated (since := "2024-07-17")] +alias le_multiplicity_iff_replicate_subperm_factors := + le_multiplicity_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] + +@[deprecated (since := "2024-07-17")] +alias le_padicValNat_iff_replicate_subperm_factors := + le_padicValNat_iff_replicate_subperm_primeFactorsList diff --git a/Mathlib/NumberTheory/Padics/ProperSpace.lean b/Mathlib/NumberTheory/Padics/ProperSpace.lean new file mode 100644 index 0000000000000..5aeae0f7642ee --- /dev/null +++ b/Mathlib/NumberTheory/Padics/ProperSpace.lean @@ -0,0 +1,67 @@ +/- +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 +-/ + +import Mathlib.Analysis.Normed.Field.ProperSpace +import Mathlib.NumberTheory.Padics.RingHoms + +/-! +# Properness of the p-adic numbers + +In this file, we prove that `ℤ_[p]` is totally bounded and compact, +and that `ℚ_[p]` is proper. + +## Main results + +- `PadicInt.totallyBounded_univ` : The set of p-adic integers `ℤ_[p]` is totally bounded. +- `PadicInt.compactSpace` : The set of p-adic integers `ℤ_[p]` is a compact topological space. +- `Padic.instProperSpace` : The field of p-adic numbers `ℚ_[p]` is a proper metric space. + +## Notation + + - `p` : Is a natural prime. + +## References + +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)] + +namespace PadicInt + +/-- The set of p-adic integers `ℤ_[p]` is totally bounded. -/ +theorem totallyBounded_univ : TotallyBounded (Set.univ : Set ℤ_[p]) := by + refine Metric.totallyBounded_iff.mpr (fun ε hε ↦ ?_) + obtain ⟨k, hk⟩ := exists_pow_neg_lt p hε + refine ⟨Nat.cast '' Finset.range (p ^ k), Set.toFinite _, fun z _ ↦ ?_⟩ + simp only [PadicInt, Set.mem_iUnion, Metric.mem_ball, exists_prop, Set.exists_mem_image] + refine ⟨z.appr k, ?_, ?_⟩ + · simpa only [Finset.mem_coe, Finset.mem_range] using z.appr_lt k + · exact (((z - z.appr k).norm_le_pow_iff_mem_span_pow k).mpr (z.appr_spec k)).trans_lt hk + +/-- The set of p-adic integers `ℤ_[p]` is a compact topological space. -/ +instance compactSpace : CompactSpace ℤ_[p] := by + rw [← isCompact_univ_iff, isCompact_iff_totallyBounded_isComplete] + exact ⟨totallyBounded_univ p, complete_univ⟩ + +end PadicInt + +namespace Padic + +/-- The field of p-adic numbers `ℚ_[p]` is a proper metric space. -/ +instance : ProperSpace ℚ_[p] := by + 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 + simpa only [isCompact_iff_compactSpace] using PadicInt.compactSpace p + +end Padic 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 d6a8d14bb8b9e..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 @@ -254,7 +254,7 @@ theorem y_mul_pos {a b : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) (hbx : 0 have positive `x`. -/ theorem x_pow_pos {a : Solution₁ d} (hax : 0 < a.x) (n : ℕ) : 0 < (a ^ n).x := by induction' n with n ih - · simp only [Nat.zero_eq, pow_zero, x_one, zero_lt_one] + · simp only [pow_zero, x_one, zero_lt_one] · rw [pow_succ] exact x_mul_pos ih hax @@ -263,7 +263,7 @@ natural exponents have positive `y`. -/ theorem y_pow_succ_pos {a : Solution₁ d} (hax : 0 < a.x) (hay : 0 < a.y) (n : ℕ) : 0 < (a ^ n.succ).y := by induction' n with n ih - · simp only [Nat.zero_eq, ← Nat.one_eq_succ_zero, hay, pow_one] + · simp only [pow_one, hay] · rw [pow_succ'] exact y_mul_pos hax hay (x_pow_pos hax _) ih @@ -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 66f902be634a1..d53d6039949db 100644 --- a/Mathlib/NumberTheory/PellMatiyasevic.lean +++ b/Mathlib/NumberTheory/PellMatiyasevic.lean @@ -182,7 +182,7 @@ theorem pellZd_im (n : ℕ) : (pellZd a1 n).im = yn a1 n := theorem isPell_nat {x y : ℕ} : IsPell (⟨x, y⟩ : ℤ√(d a1)) ↔ x * x - d a1 * y * y = 1 := ⟨fun h => - Nat.cast_inj.1 + (Nat.cast_inj (R := ℤ)).1 (by rw [Int.ofNat_sub (Int.le_of_ofNat_le_ofNat <| Int.le.intro_sub _ h)]; exact h), fun h => show ((x * x : ℕ) - (d a1 * y * y : ℕ) : ℤ) = 1 by @@ -211,7 +211,7 @@ theorem pell_eq (n : ℕ) : xn a1 n * xn a1 n - d a1 * yn a1 n * yn a1 n = 1 := repeat' rw [Int.ofNat_mul]; exact pn have hl : d a1 * yn a1 n * yn a1 n ≤ xn a1 n * xn a1 n := Nat.cast_le.1 <| Int.le.intro _ <| add_eq_of_eq_sub' <| Eq.symm h - Nat.cast_inj.1 (by rw [Int.ofNat_sub hl]; exact h) + (Nat.cast_inj (R := ℤ)).1 (by rw [Int.ofNat_sub hl]; exact h) instance dnsq : Zsqrtd.Nonsquare (d a1) := ⟨fun n h => @@ -273,14 +273,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 @@ -708,10 +708,7 @@ theorem eq_of_xn_modEq' {i j n} (ipos : 0 < i) (hin : i ≤ n) (j4n : j ≤ 4 * _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] - have j42n : 4 * n - j ≤ 2 * n := - Nat.le_of_add_le_add_right <| by - rw [tsub_add_cancel_of_le j4n, show 4 * n = 2 * n + 2 * n from right_distrib 2 2 n] - exact Nat.add_le_add_left (le_of_lt j2n) _ + have j42n : 4 * n - j ≤ 2 * n := by omega eq_of_xn_modEq a1 i2n j42n (h.symm.trans <| by let t := xn_modEq_x4n_sub a1 j42n @@ -753,7 +750,7 @@ theorem xy_modEq_of_modEq {a b c} (a1 : 1 < a) (b1 : 1 < b) (h : a ≡ b [MOD c] ⟨(xy_modEq_of_modEq a1 b1 h n).left.add_right_cancel <| by rw [xn_succ_succ a1, xn_succ_succ b1] exact (h.mul_left _).mul (xy_modEq_of_modEq _ _ h (n + 1)).left, - (xy_modEq_of_modEq _ _ h n).right.add_right_cancel <| by + (xy_modEq_of_modEq a1 b1 h n).right.add_right_cancel <| by rw [yn_succ_succ a1, yn_succ_succ b1] exact (h.mul_left _).mul (xy_modEq_of_modEq _ _ h (n + 1)).right⟩ diff --git a/Mathlib/NumberTheory/PrimeCounting.lean b/Mathlib/NumberTheory/PrimeCounting.lean index e49c213d69742..3005d0cb7165a 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.Totient import Mathlib.Data.Nat.Nth +import Mathlib.Data.Nat.Totient import Mathlib.NumberTheory.SmoothNumbers /-! @@ -27,7 +27,7 @@ are not prime, and so only at most `φ(k)/k` fraction of the numbers from `k` to ## Notation -Wtih `open scoped Nat.Prime`, we use the standard notation `π` to represent the prime counting +With `open scoped Nat.Prime`, we use the standard notation `π` to represent the prime counting function (and `π'` to represent the reindexed version). -/ @@ -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,38 @@ theorem monotone_primeCounting : Monotone primeCounting := theorem primeCounting'_nth_eq (n : ℕ) : π' (nth Prime n) = n := count_nth_of_infinite infinite_setOf_prime _ +@[simp] +theorem zeroth_prime_eq_two : nth Prime 0 = 2 := nth_count prime_two + +/-- The `n`th prime is greater or equal to `n + 2`. -/ +theorem add_two_le_nth_prime (n : ℕ) : n + 2 ≤ nth Prime n := + zeroth_prime_eq_two ▸ (nth_strictMono infinite_setOf_prime).add_le_nat n 0 + +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 _ /-- 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.card = primeCounting' n := by simp only [primesBelow, primeCounting'] exact (count_eq_card_filter_range Prime n).symm @@ -98,11 +127,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 e97e2a02e51de..8bc67a5f611f7 100644 --- a/Mathlib/NumberTheory/Primorial.lean +++ b/Mathlib/NumberTheory/Primorial.lean @@ -41,7 +41,7 @@ theorem primorial_pos (n : ℕ) : 0 < n# := theorem primorial_succ {n : ℕ} (hn1 : n ≠ 1) (hn : Odd n) : (n + 1)# = n# := by refine prod_congr ?_ fun _ _ ↦ rfl - rw [range_succ, filter_insert, if_neg fun h ↦ odd_iff_not_even.mp hn _] + rw [range_succ, filter_insert, if_neg fun h ↦ not_even_iff_odd.2 hn _] exact fun h ↦ h.even_sub_one <| mt succ.inj hn1 theorem primorial_add (m n : ℕ) : diff --git a/Mathlib/NumberTheory/PythagoreanTriples.lean b/Mathlib/NumberTheory/PythagoreanTriples.lean index a9e537bc9d8e7..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 @@ -528,7 +527,7 @@ theorem isPrimitiveClassified_of_coprime_of_odd_of_pos (hc : Int.gcd x y = 1) (h apply Rat.div_int_inj hzpos _ (h.coprime_of_coprime hc) h1.2.2.2 · show w = _ rw [← Rat.divInt_eq_div, ← Rat.divInt_mul_right (by norm_num : (2 : ℤ) ≠ 0)] - rw [Int.ediv_mul_cancel h1.1, Int.ediv_mul_cancel h1.2.1, hw2] + rw [Int.ediv_mul_cancel h1.1, Int.ediv_mul_cancel h1.2.1, hw2, Rat.divInt_eq_div] norm_cast · apply (mul_lt_mul_right (by norm_num : 0 < (2 : ℤ))).mp rw [Int.ediv_mul_cancel h1.1, zero_mul] diff --git a/Mathlib/NumberTheory/RamificationInertia.lean b/Mathlib/NumberTheory/RamificationInertia.lean index c059ce200afdd..10d1ba5cf00ef 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 @@ -476,7 +476,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 @@ -699,7 +699,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 +793,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 efa4c9a35de90..0e29615583c61 100644 --- a/Mathlib/NumberTheory/Rayleigh.lean +++ b/Mathlib/NumberTheory/Rayleigh.lean @@ -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`. -/ @@ -102,7 +102,7 @@ private theorem hit_or_miss' (h : r > 0) : j ∈ {beattySeq' r k | k} ∨ ∃ k : ℤ, k ≤ j / r ∧ (j + 1) / r < k + 1 := by -- for both cases, the candidate is `k = ⌊(j + 1) / r⌋` cases le_or_gt (⌊(j + 1) / r⌋ * r) j - · exact Or.inr ⟨⌊(j + 1) / r⌋, (le_div_iff h).2 ‹_›, Int.lt_floor_add_one _⟩ + · exact Or.inr ⟨⌊(j + 1) / r⌋, (le_div_iff₀ h).2 ‹_›, Int.lt_floor_add_one _⟩ · refine Or.inl ⟨⌊(j + 1) / r⌋, ?_⟩ rw [beattySeq', sub_eq_iff_eq_add, Int.ceil_eq_iff, Int.cast_add, Int.cast_one] constructor 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/SumTwoSquares.lean b/Mathlib/NumberTheory/SumTwoSquares.lean index ac1c6735ecf20..4c8c1a2799082 100644 --- a/Mathlib/NumberTheory/SumTwoSquares.lean +++ b/Mathlib/NumberTheory/SumTwoSquares.lean @@ -5,7 +5,7 @@ Authors: Chris Hughes, Michael Stoll -/ import Mathlib.Data.Nat.Squarefree import Mathlib.NumberTheory.Zsqrtd.QuadraticReciprocity -import Mathlib.Tactic.LinearCombination +import Mathlib.NumberTheory.Padics.PadicVal.Basic /-! # Sums of two squares @@ -216,7 +216,7 @@ theorem Nat.eq_sq_add_sq_iff {n : ℕ} : exact even_two_mul _ · obtain ⟨b, a, hb₀, ha₀, hab, hb⟩ := Nat.sq_mul_squarefree_of_pos hn₀ refine ⟨a, b, hab.symm, (ZMod.isSquare_neg_one_iff hb).mpr fun {q} hqp hqb hq4 => ?_⟩ - refine Nat.odd_iff_not_even.mp ?_ (H hqp hq4) + refine Nat.not_even_iff_odd.2 ?_ (H hqp hq4) have hqb' : padicValNat q b = 1 := b.factorization_def hqp ▸ le_antisymm (hb.natFactorization_le_one _) ((hqp.dvd_iff_one_le_factorization hb₀.ne').mp hqb) diff --git a/Mathlib/NumberTheory/WellApproximable.lean b/Mathlib/NumberTheory/WellApproximable.lean index 69b68a0ebfab8..7b72f49ff60e8 100644 --- a/Mathlib/NumberTheory/WellApproximable.lean +++ b/Mathlib/NumberTheory/WellApproximable.lean @@ -10,7 +10,7 @@ import Mathlib.MeasureTheory.Covering.LiminfLimsup # Well-approximable numbers and Gallagher's ergodic theorem Gallagher's ergodic theorem is a result in metric number theory. It thus belongs to that branch of -mathematics concerning arithmetic properties of real numbers which hold almost eveywhere with +mathematics concerning arithmetic properties of real numbers which hold almost everywhere with respect to the Lebesgue measure. Gallagher's theorem concerns the approximation of real numbers by rational numbers. The input is a @@ -248,7 +248,7 @@ theorem addWellApproximable_ae_empty_or_univ (δ : ℕ → ℝ) (hδ : Tendsto let f : 𝕊 → 𝕊 := fun y => (p : ℕ) • y suffices f '' A p ⊆ blimsup (fun n => approxAddOrderOf 𝕊 n (p * δ n)) atTop fun n => 0 < n ∧ p∤n by - apply (ergodic_nsmul hp.one_lt).ae_empty_or_univ_of_image_ae_le (hA₀ p) + apply (ergodic_nsmul hp.one_lt).ae_empty_or_univ_of_image_ae_le (hA₀ p).nullMeasurableSet apply (HasSubset.Subset.eventuallyLE this).congr EventuallyEq.rfl exact blimsup_thickening_mul_ae_eq μ (fun n => 0 < n ∧ p∤n) (fun n => {y | addOrderOf y = n}) (Nat.cast_pos.mpr hp.pos) _ hδ @@ -261,7 +261,8 @@ theorem addWellApproximable_ae_empty_or_univ (δ : ℕ → ℝ) (hδ : Tendsto let f : 𝕊 → 𝕊 := fun y => p • y + x suffices f '' B p ⊆ blimsup (fun n => approxAddOrderOf 𝕊 n (p * δ n)) atTop fun n => 0 < n ∧ p∣∣n by - apply (ergodic_nsmul_add x hp.one_lt).ae_empty_or_univ_of_image_ae_le (hB₀ p) + apply (ergodic_nsmul_add x hp.one_lt).ae_empty_or_univ_of_image_ae_le + (hB₀ p).nullMeasurableSet apply (HasSubset.Subset.eventuallyLE this).congr EventuallyEq.rfl exact blimsup_thickening_mul_ae_eq μ (fun n => 0 < n ∧ p∣∣n) (fun n => {y | addOrderOf y = n}) (Nat.cast_pos.mpr hp.pos) _ hδ @@ -289,7 +290,7 @@ theorem addWellApproximable_ae_empty_or_univ (δ : ℕ → ℝ) (hδ : Tendsto let e := (AddAction.toPerm (u p) : Equiv.Perm 𝕊).toOrderIsoSet change e (C p) = C p rw [OrderIso.apply_blimsup e, ← hu₀ p] - exact blimsup_congr (eventually_of_forall fun n hn => + exact blimsup_congr (Eventually.of_forall fun n hn => approxAddOrderOf.vadd_eq_of_mul_dvd (δ n) hn.1 hn.2) by_cases h : ∀ p : Nat.Primes, A p =ᵐ[μ] (∅ : Set 𝕊) ∧ B p =ᵐ[μ] (∅ : Set 𝕊) · replace h : ∀ p : Nat.Primes, (u p +ᵥ E : Set _) =ᵐ[μ] E := by diff --git a/Mathlib/NumberTheory/Zsqrtd/Basic.lean b/Mathlib/NumberTheory/Zsqrtd/Basic.lean index a697ad60f1bbe..c73a74bb7a6b6 100644 --- a/Mathlib/NumberTheory/Zsqrtd/Basic.lean +++ b/Mathlib/NumberTheory/Zsqrtd/Basic.lean @@ -476,13 +476,13 @@ theorem norm_eq_mul_conj (n : ℤ√d) : (norm n : ℤ√d) = n * star n := by theorem norm_neg (x : ℤ√d) : (-x).norm = x.norm := -- Porting note: replaced `simp` with `rw` -- See https://github.com/leanprover-community/mathlib4/issues/5026 - Int.cast_inj.1 <| by rw [norm_eq_mul_conj, star_neg, neg_mul_neg, norm_eq_mul_conj] + (Int.cast_inj (α := ℤ√d)).1 <| by rw [norm_eq_mul_conj, star_neg, neg_mul_neg, norm_eq_mul_conj] @[simp] theorem norm_conj (x : ℤ√d) : (star x).norm = x.norm := -- Porting note: replaced `simp` with `rw` -- See https://github.com/leanprover-community/mathlib4/issues/5026 - Int.cast_inj.1 <| by rw [norm_eq_mul_conj, star_star, mul_comm, norm_eq_mul_conj] + (Int.cast_inj (α := ℤ√d)).1 <| by rw [norm_eq_mul_conj, star_star, mul_comm, norm_eq_mul_conj] theorem norm_nonneg (hd : d ≤ 0) (n : ℤ√d) : 0 ≤ n.norm := add_nonneg (mul_self_nonneg _) @@ -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 _) diff --git a/Mathlib/NumberTheory/Zsqrtd/QuadraticReciprocity.lean b/Mathlib/NumberTheory/Zsqrtd/QuadraticReciprocity.lean index a22d6696a31a2..4847518e1ce0e 100644 --- a/Mathlib/NumberTheory/Zsqrtd/QuadraticReciprocity.lean +++ b/Mathlib/NumberTheory/Zsqrtd/QuadraticReciprocity.lean @@ -5,7 +5,7 @@ Authors: Chris Hughes -/ import Mathlib.NumberTheory.Zsqrtd.GaussianInt import Mathlib.NumberTheory.LegendreSymbol.Basic -import Mathlib.Analysis.Normed.Field.Basic +import Mathlib.Analysis.Normed.Field.Lemmas /-! # Facts about the gaussian integers relying on quadratic reciprocity. @@ -86,7 +86,7 @@ theorem prime_of_nat_prime_of_mod_four_eq_three (p : ℕ) [hp : Fact p.Prime] (h 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 7350341af87c7..cdfcbf4009f47 100644 --- a/Mathlib/Order/Antichain.lean +++ b/Mathlib/Order/Antichain.lean @@ -283,11 +283,11 @@ variable [PartialOrder α] [PartialOrder β] {f : α → β} {s : Set α} lemma IsAntichain.of_strictMonoOn_antitoneOn (hf : StrictMonoOn f s) (hf' : AntitoneOn f s) : IsAntichain (· ≤ ·) s := - fun _a ha _b hb hab' hab ↦ (hf ha hb $ hab.lt_of_ne hab').not_le (hf' ha hb hab) + fun _a ha _b hb hab' hab ↦ (hf ha hb <| hab.lt_of_ne hab').not_le (hf' ha hb hab) lemma IsAntichain.of_monotoneOn_strictAntiOn (hf : MonotoneOn f s) (hf' : StrictAntiOn f s) : IsAntichain (· ≤ ·) s := - fun _a ha _b hb hab' hab ↦ (hf ha hb hab).not_lt (hf' ha hb $ hab.lt_of_ne hab') + fun _a ha _b hb hab' hab ↦ (hf ha hb hab).not_lt (hf' ha hb <| hab.lt_of_ne hab') end General diff --git a/Mathlib/Order/Antisymmetrization.lean b/Mathlib/Order/Antisymmetrization.lean index e5205df7dc3be..8dae92170d4dd 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 : 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 49a46ba6bb698..08b21b2de4986 100644 --- a/Mathlib/Order/Basic.lean +++ b/Mathlib/Order/Basic.lean @@ -3,14 +3,13 @@ Copyright (c) 2014 Jeremy Avigad. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Mario Carneiro -/ -import Mathlib.Init.Order.LinearOrder import Mathlib.Data.Prod.Basic import Mathlib.Data.Subtype +import Mathlib.Order.Defs +import Mathlib.Order.Notation import Mathlib.Tactic.Spread import Mathlib.Tactic.Convert import Mathlib.Tactic.SimpRw -import Mathlib.Tactic.Cases -import Mathlib.Order.Notation import Batteries.Data.Sum.Lemmas import Batteries.Tactic.Classical @@ -187,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. -/ @@ -287,87 +286,67 @@ protected theorem GT.gt.lt [LT α] {x y : α} (h : x > y) : y < x := theorem ge_of_eq [Preorder α] {a b : α} (h : a = b) : a ≥ b := h.ge -theorem not_le_of_lt [Preorder α] {a b : α} (h : a < b) : ¬b ≤ a := - (le_not_le_of_lt h).right - -alias LT.lt.not_le := not_le_of_lt - -theorem not_lt_of_le [Preorder α] {a b : α} (h : a ≤ b) : ¬b < a := fun hba ↦ hba.not_le h - -alias LE.le.not_lt := not_lt_of_le - theorem ne_of_not_le [Preorder α] {a b : α} (h : ¬a ≤ b) : a ≠ b := fun hab ↦ h (le_of_eq hab) +section PartialOrder +variable [PartialOrder α] {a b : α} + -- See Note [decidable namespace] -protected theorem Decidable.le_iff_eq_or_lt [PartialOrder α] [@DecidableRel α (· ≤ ·)] {a b : α} : - a ≤ b ↔ a = b ∨ a < b := +protected theorem Decidable.le_iff_eq_or_lt [@DecidableRel α (· ≤ ·)] : a ≤ b ↔ a = b ∨ a < b := Decidable.le_iff_lt_or_eq.trans or_comm -theorem le_iff_eq_or_lt [PartialOrder α] {a b : α} : a ≤ b ↔ a = b ∨ a < b := - le_iff_lt_or_eq.trans or_comm +theorem le_iff_eq_or_lt : a ≤ b ↔ a = b ∨ a < b := le_iff_lt_or_eq.trans or_comm -theorem lt_iff_le_and_ne [PartialOrder α] {a b : α} : a < b ↔ a ≤ b ∧ a ≠ b := +theorem lt_iff_le_and_ne : a < b ↔ a ≤ b ∧ a ≠ b := ⟨fun h ↦ ⟨le_of_lt h, ne_of_lt h⟩, fun ⟨h1, h2⟩ ↦ h1.lt_of_ne h2⟩ -theorem eq_iff_not_lt_of_le [PartialOrder α] {x y : α} : x ≤ y → y = x ↔ ¬x < y := by - rw [lt_iff_le_and_ne, not_and, Classical.not_not, eq_comm] +lemma eq_iff_not_lt_of_le (hab : a ≤ b) : a = b ↔ ¬ a < b := by simp [hab, lt_iff_le_and_ne] + +alias LE.le.eq_iff_not_lt := eq_iff_not_lt_of_le -- See Note [decidable namespace] -protected theorem Decidable.eq_iff_le_not_lt [PartialOrder α] [@DecidableRel α (· ≤ ·)] {a b : α} : +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 [PartialOrder α] {a b : α} : a = b ↔ a ≤ b ∧ ¬a < b := +theorem eq_iff_le_not_lt : a = b ↔ a ≤ b ∧ ¬a < b := haveI := Classical.dec Decidable.eq_iff_le_not_lt -theorem eq_or_lt_of_le [PartialOrder α] {a b : α} (h : a ≤ b) : a = b ∨ a < b := - h.lt_or_eq.symm - -theorem eq_or_gt_of_le [PartialOrder α] {a b : α} (h : a ≤ b) : b = a ∨ a < b := - h.lt_or_eq.symm.imp Eq.symm id - -theorem gt_or_eq_of_le [PartialOrder α] {a b : α} (h : a ≤ b) : a < b ∨ b = a := - (eq_or_gt_of_le h).symm +theorem eq_or_lt_of_le (h : a ≤ b) : a = b ∨ a < b := h.lt_or_eq.symm +theorem eq_or_gt_of_le (h : a ≤ b) : b = a ∨ a < b := h.lt_or_eq.symm.imp Eq.symm id +theorem gt_or_eq_of_le (h : a ≤ b) : a < b ∨ b = a := (eq_or_gt_of_le h).symm alias LE.le.eq_or_lt_dec := Decidable.eq_or_lt_of_le - alias LE.le.eq_or_lt := eq_or_lt_of_le - alias LE.le.eq_or_gt := eq_or_gt_of_le - alias LE.le.gt_or_eq := gt_or_eq_of_le -- Porting note: no `decidable_classical` linter -- attribute [nolint decidable_classical] LE.le.eq_or_lt_dec -theorem eq_of_le_of_not_lt [PartialOrder α] {a b : α} (hab : a ≤ b) (hba : ¬a < b) : a = b := - hab.eq_or_lt.resolve_right hba - -theorem eq_of_ge_of_not_gt [PartialOrder α] {a b : α} (hab : a ≤ b) (hba : ¬a < b) : b = a := - (hab.eq_or_lt.resolve_right hba).symm +theorem eq_of_le_of_not_lt (hab : a ≤ b) (hba : ¬a < b) : a = b := hab.eq_or_lt.resolve_right hba +theorem eq_of_ge_of_not_gt (hab : a ≤ b) (hba : ¬a < b) : b = a := (eq_of_le_of_not_lt hab hba).symm alias LE.le.eq_of_not_lt := eq_of_le_of_not_lt - alias LE.le.eq_of_not_gt := eq_of_ge_of_not_gt -theorem Ne.le_iff_lt [PartialOrder α] {a b : α} (h : a ≠ b) : a ≤ b ↔ a < b := - ⟨fun h' ↦ lt_of_le_of_ne h' h, fun h ↦ h.le⟩ +theorem Ne.le_iff_lt (h : a ≠ b) : a ≤ b ↔ a < b := ⟨fun h' ↦ lt_of_le_of_ne h' h, fun h ↦ h.le⟩ -theorem Ne.not_le_or_not_le [PartialOrder α] {a b : α} (h : a ≠ b) : ¬a ≤ b ∨ ¬b ≤ a := - not_and_or.1 <| le_antisymm_iff.not.1 h +theorem Ne.not_le_or_not_le (h : a ≠ b) : ¬a ≤ b ∨ ¬b ≤ a := not_and_or.1 <| le_antisymm_iff.not.1 h -- See Note [decidable namespace] -protected theorem Decidable.ne_iff_lt_iff_le [PartialOrder α] [DecidableEq α] {a b : α} : - (a ≠ b ↔ a < b) ↔ a ≤ b := +protected theorem Decidable.ne_iff_lt_iff_le [DecidableEq α] : (a ≠ b ↔ a < b) ↔ a ≤ b := ⟨fun h ↦ Decidable.byCases le_of_eq (le_of_lt ∘ h.mp), fun h ↦ ⟨lt_of_le_of_ne h, ne_of_lt⟩⟩ @[simp] -theorem ne_iff_lt_iff_le [PartialOrder α] {a b : α} : (a ≠ b ↔ a < b) ↔ a ≤ b := +theorem ne_iff_lt_iff_le : (a ≠ b ↔ a < b) ↔ a ≤ b := haveI := Classical.dec Decidable.ne_iff_lt_iff_le +end PartialOrder + -- Variant of `min_def` with the branches reversed. theorem min_def' [LinearOrder α] (a b : α) : min a b = if b ≤ a then b else a := by rw [min_def] @@ -411,7 +390,7 @@ lemma exists_forall_ge_and [LinearOrder α] {p q : α → Prop} : (∃ i, ∀ j ≥ i, p j) → (∃ i, ∀ j ≥ i, q j) → ∃ i, ∀ j ≥ i, p j ∧ q j | ⟨a, ha⟩, ⟨b, hb⟩ => let ⟨c, hac, hbc⟩ := exists_ge_of_linear a b - ⟨c, fun _d hcd ↦ ⟨ha _ $ hac.trans hcd, hb _ $ hbc.trans hcd⟩⟩ + ⟨c, fun _d hcd ↦ ⟨ha _ <| hac.trans hcd, hb _ <| hbc.trans hcd⟩⟩ theorem lt_imp_lt_of_le_imp_le {β} [LinearOrder α] [Preorder β] {a b : α} {c d : β} (H : a ≤ b → c ≤ d) (h : d < c) : b < a := @@ -463,7 +442,7 @@ theorem eq_of_forall_lt_iff [LinearOrder α] {a b : α} (h : ∀ c, c < a ↔ c theorem eq_of_forall_gt_iff [LinearOrder α] {a b : α} (h : ∀ c, a < c ↔ b < c) : a = b := (le_of_forall_lt' fun _ ↦ (h _).2).antisymm <| le_of_forall_lt' fun _ ↦ (h _).1 -/-- A symmetric relation implies two values are equal, when it implies they're less-equal. -/ +/-- A symmetric relation implies two values are equal, when it implies they're less-equal. -/ theorem rel_imp_eq_of_rel_imp_le [PartialOrder β] (r : α → α → Prop) [IsSymm α r] {f : α → β} (h : ∀ a b, r a b → f a ≤ f b) {a b : α} : r a b → f a = f b := fun hab ↦ le_antisymm (h a b hab) (h b a <| symm hab) @@ -484,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 @@ -731,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 := @@ -1121,7 +1105,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 @@ -1211,6 +1196,12 @@ instance OrderDual.denselyOrdered (α : Type*) [LT α] [h : DenselyOrdered α] : theorem denselyOrdered_orderDual [LT α] : DenselyOrdered αᵒᵈ ↔ DenselyOrdered α := ⟨by convert @OrderDual.denselyOrdered αᵒᵈ _, @OrderDual.denselyOrdered α _⟩ +/-- Any ordered subsingleton is densely ordered. Not an instance to avoid a heavy subsingleton +typeclass search. -/ +lemma Subsingleton.instDenselyOrdered {X : Type*} [Subsingleton X] [Preorder X] : + DenselyOrdered X := + ⟨fun _ _ h ↦ (not_lt_of_subsingleton h).elim⟩ + instance [Preorder α] [Preorder β] [DenselyOrdered α] [DenselyOrdered β] : DenselyOrdered (α × β) := ⟨fun a b ↦ by simp_rw [Prod.lt_iff] @@ -1263,8 +1254,9 @@ lemma eq_or_eq_or_eq_of_forall_not_lt_lt [LinearOrder α] (h : ∀ ⦃x y z : α⦄, x < y → y < z → False) (x y z : α) : x = y ∨ y = z ∨ x = z := by by_contra hne simp only [not_or, ← Ne.eq_def] at hne - cases' hne.1.lt_or_lt with h₁ h₁ <;> cases' hne.2.1.lt_or_lt with h₂ h₂ <;> - cases' hne.2.2.lt_or_lt with h₃ h₃ + rcases hne.1.lt_or_lt with h₁ | h₁ <;> + rcases hne.2.1.lt_or_lt with h₂ | h₂ <;> + rcases hne.2.2.lt_or_lt with h₃ | h₃ exacts [h h₁ h₂, h h₂ h₃, h h₃ h₂, h h₃ h₁, h h₁ h₃, h h₂ h₃, h h₁ h₃, h h₂ h₁] namespace PUnit diff --git a/Mathlib/Order/BooleanAlgebra.lean b/Mathlib/Order/BooleanAlgebra.lean index 942a70f8f6bec..24e867d0ac354 100644 --- a/Mathlib/Order/BooleanAlgebra.lean +++ b/Mathlib/Order/BooleanAlgebra.lean @@ -745,8 +745,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. -/ @@ -767,7 +767,7 @@ protected abbrev Function.Injective.booleanAlgebra [Sup α] [Inf α] [Top α] [B sdiff_eq a b := by refine hf ((map_sdiff _ _).trans (sdiff_eq.trans ?_)) rw [map_inf, map_compl] - himp_eq a b := hf $ (map_himp _ _).trans $ himp_eq.trans $ by rw [map_sup, map_compl] + himp_eq a b := hf <| (map_himp _ _).trans <| himp_eq.trans <| by rw [map_sup, map_compl] end lift diff --git a/Mathlib/Order/Booleanisation.lean b/Mathlib/Order/Booleanisation.lean index dd3aa408d0c38..aa7f7370581b4 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 `α` diff --git a/Mathlib/Order/Bounded.lean b/Mathlib/Order/Bounded.lean index 4ec049678f991..2a70d6afbe227 100644 --- a/Mathlib/Order/Bounded.lean +++ b/Mathlib/Order/Bounded.lean @@ -92,8 +92,8 @@ theorem unbounded_lt_of_unbounded_le [Preorder α] (h : Unbounded (· ≤ ·) s) theorem bounded_le_iff_bounded_lt [Preorder α] [NoMaxOrder α] : Bounded (· ≤ ·) s ↔ Bounded (· < ·) s := by refine ⟨fun h => ?_, bounded_le_of_bounded_lt⟩ - cases' h with a ha - cases' exists_gt a with b hb + obtain ⟨a, ha⟩ := h + obtain ⟨b, hb⟩ := exists_gt a exact ⟨b, fun c hc => lt_of_le_of_lt (ha c hc) hb⟩ theorem unbounded_lt_iff_unbounded_le [Preorder α] [NoMaxOrder α] : @@ -247,7 +247,7 @@ theorem bounded_inter_not (H : ∀ a b, ∃ m, ∀ c, r c a ∨ r c b → r c m) Bounded r (s ∩ { b | ¬r b a }) ↔ Bounded r s := by refine ⟨?_, Bounded.mono inter_subset_left⟩ rintro ⟨b, hb⟩ - cases' H a b with m hm + obtain ⟨m, hm⟩ := H a b exact ⟨m, fun c hc => hm c (or_iff_not_imp_left.2 fun hca => hb c ⟨hc, hca⟩)⟩ theorem unbounded_inter_not (H : ∀ a b, ∃ m, ∀ c, r c a ∨ r c b → r c m) (a : α) : diff --git a/Mathlib/Order/BoundedOrder.lean b/Mathlib/Order/BoundedOrder.lean index d4039a093f12d..a28c66b0685a2 100644 --- a/Mathlib/Order/BoundedOrder.lean +++ b/Mathlib/Order/BoundedOrder.lean @@ -33,7 +33,7 @@ open Function OrderDual universe u v -variable {α : Type u} {β : Type v} {γ δ : Type*} +variable {α : Type u} {β : Type v} /-! ### Top, bottom element -/ @@ -84,6 +84,11 @@ 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 + end Preorder variable [PartialOrder α] [OrderTop α] [Preorder β] {f : α → β} {a b : α} @@ -144,6 +149,9 @@ theorem StrictMono.apply_eq_top_iff (hf : StrictMono f) : f a = f ⊤ ↔ a = theorem StrictAnti.apply_eq_top_iff (hf : StrictAnti f) : f a = f ⊤ ↔ a = ⊤ := ⟨fun h => not_lt_top_iff.1 fun ha => (hf ha).ne' h, congr_arg _⟩ +lemma top_not_mem_iff {s : Set α} : ⊤ ∉ s ↔ ∀ x ∈ s, x < ⊤ := + ⟨fun h x hx ↦ Ne.lt_top (fun hx' : x = ⊤ ↦ h (hx' ▸ hx)), fun h h₀ ↦ (h ⊤ h₀).false⟩ + variable [Nontrivial α] theorem not_isMin_top : ¬IsMin (⊤ : α) := fun h => @@ -250,6 +258,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 : α} @@ -313,6 +326,9 @@ theorem StrictMono.apply_eq_bot_iff (hf : StrictMono f) : f a = f ⊥ ↔ a = theorem StrictAnti.apply_eq_bot_iff (hf : StrictAnti f) : f a = f ⊥ ↔ a = ⊥ := hf.dual.apply_eq_top_iff +lemma bot_not_mem_iff {s : Set α} : ⊥ ∉ s ↔ ∀ x ∈ s, ⊥ < x := + top_not_mem_iff (α := αᵒᵈ) + variable [Nontrivial α] theorem not_isMax_bot : ¬IsMax (⊥ : α) := @@ -337,7 +353,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 = ⊤ := @@ -384,7 +400,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 diff --git a/Mathlib/Order/Bounds/Basic.lean b/Mathlib/Order/Bounds/Basic.lean index e1b7a921c750f..86984514ba3e7 100644 --- a/Mathlib/Order/Bounds/Basic.lean +++ b/Mathlib/Order/Bounds/Basic.lean @@ -466,7 +466,7 @@ theorem le_glb_Ioi (a : α) (hb : IsGLB (Ioi a) b) : a ≤ b := theorem lub_Iio_eq_self_or_Iio_eq_Iic [PartialOrder γ] {j : γ} (i : γ) (hj : IsLUB (Iio i) j) : j = i ∨ Iio i = Iic j := by - cases' eq_or_lt_of_le (lub_Iio_le i hj) with hj_eq_i hj_lt_i + rcases eq_or_lt_of_le (lub_Iio_le i hj) with hj_eq_i | hj_lt_i · exact Or.inl hj_eq_i · right exact Set.ext fun k => ⟨fun hk_lt => hj.1 hk_lt, fun hk_le_j => lt_of_le_of_lt hk_le_j hj_lt_i⟩ @@ -609,7 +609,7 @@ 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 - cases' eq_or_lt_of_le (le_sup_right : a ≤ x ⊔ a) with h₁ h₂ + 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₂ apply (not_lt_of_le (sup_le (hx ⟨lty, ylt.trans_le (sup_le _ h.le)⟩) lty.le) ylt).elim @@ -759,7 +759,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 +769,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) := @@ -1430,31 +1430,3 @@ lemma BddBelow.range_comp {γ : Type*} [Preorder β] [Preorder γ] {f : α → (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 - -section ScottContinuous -variable [Preorder α] [Preorder β] {f : α → β} {a : α} - -/-- A function between preorders is said to be Scott continuous if it preserves `IsLUB` on directed -sets. It can be shown that a function is Scott continuous if and only if it is continuous wrt the -Scott topology. - -The dual notion - -```lean -∀ ⦃d : Set α⦄, d.Nonempty → DirectedOn (· ≥ ·) d → ∀ ⦃a⦄, IsGLB d a → IsGLB (f '' d) (f a) -``` - -does not appear to play a significant role in the literature, so is omitted here. --/ -def ScottContinuous (f : α → β) : Prop := - ∀ ⦃d : Set α⦄, d.Nonempty → DirectedOn (· ≤ ·) d → ∀ ⦃a⦄, IsLUB d a → IsLUB (f '' d) (f a) - -protected theorem ScottContinuous.monotone (h : ScottContinuous f) : Monotone f := by - refine fun a b hab => - (h (insert_nonempty _ _) (directedOn_pair le_refl hab) ?_).1 - (mem_image_of_mem _ <| mem_insert _ _) - rw [IsLUB, upperBounds_insert, upperBounds_singleton, - inter_eq_self_of_subset_right (Ici_subset_Ici.2 hab)] - exact isLeast_Ici - -end ScottContinuous diff --git a/Mathlib/Order/Category/BoolAlg.lean b/Mathlib/Order/Category/BoolAlg.lean index 3afeb442490cf..e90e6e55aed90 100644 --- a/Mathlib/Order/Category/BoolAlg.lean +++ b/Mathlib/Order/Category/BoolAlg.lean @@ -106,6 +106,6 @@ theorem boolAlg_dual_comp_forget_to_bddDistLat : /-- The powerset functor. `Set` as a contravariant functor. -/ @[simps] def typeToBoolAlgOp : Type u ⥤ BoolAlgᵒᵖ where - obj X := op $ BoolAlg.of (Set X) + obj X := op <| BoolAlg.of (Set X) map {X Y} f := Quiver.Hom.op (CompleteLatticeHom.setPreimage f : BoundedLatticeHom (Set Y) (Set X)) diff --git a/Mathlib/Order/Category/FinPartOrd.lean b/Mathlib/Order/Category/FinPartOrd.lean index 07c4af377d9b9..5b90c8fa7d59d 100644 --- a/Mathlib/Order/Category/FinPartOrd.lean +++ b/Mathlib/Order/Category/FinPartOrd.lean @@ -86,11 +86,12 @@ def dual : FinPartOrd ⥤ FinPartOrd where map {X Y} := OrderHom.dual /-- The equivalence between `FinPartOrd` and itself induced by `OrderDual` both ways. -/ -@[simps! functor inverse] -def dualEquiv : FinPartOrd ≌ FinPartOrd := - CategoryTheory.Equivalence.mk dual dual - (NatIso.ofComponents fun X => Iso.mk <| OrderIso.dualDual X) - (NatIso.ofComponents fun X => Iso.mk <| OrderIso.dualDual X) +@[simps] +def dualEquiv : FinPartOrd ≌ FinPartOrd where + functor := dual + inverse := dual + unitIso := NatIso.ofComponents fun X => Iso.mk <| OrderIso.dualDual X + counitIso := NatIso.ofComponents fun X => Iso.mk <| OrderIso.dualDual X end FinPartOrd diff --git a/Mathlib/Order/Category/NonemptyFinLinOrd.lean b/Mathlib/Order/Category/NonemptyFinLinOrd.lean index 02b1bfe0adc42..3c6d13dec2f73 100644 --- a/Mathlib/Order/Category/NonemptyFinLinOrd.lean +++ b/Mathlib/Order/Category/NonemptyFinLinOrd.lean @@ -235,3 +235,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 d5b3f6975277c..c92cacfbb73ae 100644 --- a/Mathlib/Order/Category/OmegaCompletePartialOrder.lean +++ b/Mathlib/Order/Category/OmegaCompletePartialOrder.lean @@ -120,7 +120,8 @@ def isEqualizer {X Y : ωCPO.{v}} (f g : X ⟶ Y) : IsLimit (equalizer f g) := -- 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 - cont := fun x => Subtype.ext (s.ι.continuous x) }, by ext; rfl, fun hm => by + 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.congr_fun hm⟩ diff --git a/Mathlib/Order/Chain.lean b/Mathlib/Order/Chain.lean index 2f086f7f4f276..f8f5ce2631f67 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 _ diff --git a/Mathlib/Order/Closure.lean b/Mathlib/Order/Closure.lean index 4005f3290f47d..53f361b143e1e 100644 --- a/Mathlib/Order/Closure.lean +++ b/Mathlib/Order/Closure.lean @@ -248,7 +248,7 @@ 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!] diff --git a/Mathlib/Order/CompactlyGenerated/Basic.lean b/Mathlib/Order/CompactlyGenerated/Basic.lean index 5a2890bd05342..4fb6ec86d8fa8 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) : @@ -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 1c64ab9fca995..0fc1605e23a0d 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 @@ -110,20 +92,21 @@ theorem Compares.inj [Preorder α] {o₁} : theorem compares_iff_of_compares_impl [LinearOrder α] [Preorder β] {a b : α} {a' b' : β} (h : ∀ {o}, Compares o a b → Compares o a' b') (o) : Compares o a b ↔ Compares o a' b' := by refine ⟨h, fun ho => ?_⟩ - cases' lt_trichotomy a b with hab hab + rcases lt_trichotomy a b with hab | hab | hab · have hab : Compares Ordering.lt a b := hab rwa [ho.inj (h hab)] - · cases' hab with hab hab - · have hab : Compares Ordering.eq a b := hab - rwa [ho.inj (h hab)] - · have hab : Compares Ordering.gt a b := hab - rwa [ho.inj (h hab)] + · have hab : Compares Ordering.eq a b := hab + rwa [ho.inj (h hab)] + · 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/CompleteLattice.lean b/Mathlib/Order/CompleteLattice.lean index 8dcff462eddbf..9e2df5ddb29f1 100644 --- a/Mathlib/Order/CompleteLattice.lean +++ b/Mathlib/Order/CompleteLattice.lean @@ -326,40 +326,44 @@ open OrderDual section -variable [CompleteLattice α] {s t : Set α} {a b : α} +section OrderDual @[simp] -theorem toDual_sSup (s : Set α) : toDual (sSup s) = sInf (ofDual ⁻¹' s) := +theorem toDual_sSup [SupSet α] (s : Set α) : toDual (sSup s) = sInf (ofDual ⁻¹' s) := rfl @[simp] -theorem toDual_sInf (s : Set α) : toDual (sInf s) = sSup (ofDual ⁻¹' s) := +theorem toDual_sInf [InfSet α] (s : Set α) : toDual (sInf s) = sSup (ofDual ⁻¹' s) := rfl @[simp] -theorem ofDual_sSup (s : Set αᵒᵈ) : ofDual (sSup s) = sInf (toDual ⁻¹' s) := +theorem ofDual_sSup [InfSet α] (s : Set αᵒᵈ) : ofDual (sSup s) = sInf (toDual ⁻¹' s) := rfl @[simp] -theorem ofDual_sInf (s : Set αᵒᵈ) : ofDual (sInf s) = sSup (toDual ⁻¹' s) := +theorem ofDual_sInf [SupSet α] (s : Set αᵒᵈ) : ofDual (sInf s) = sSup (toDual ⁻¹' s) := rfl @[simp] -theorem toDual_iSup (f : ι → α) : toDual (⨆ i, f i) = ⨅ i, toDual (f i) := +theorem toDual_iSup [SupSet α] (f : ι → α) : toDual (⨆ i, f i) = ⨅ i, toDual (f i) := rfl @[simp] -theorem toDual_iInf (f : ι → α) : toDual (⨅ i, f i) = ⨆ i, toDual (f i) := +theorem toDual_iInf [InfSet α] (f : ι → α) : toDual (⨅ i, f i) = ⨆ i, toDual (f i) := rfl @[simp] -theorem ofDual_iSup (f : ι → αᵒᵈ) : ofDual (⨆ i, f i) = ⨅ i, ofDual (f i) := +theorem ofDual_iSup [InfSet α] (f : ι → αᵒᵈ) : ofDual (⨆ i, f i) = ⨅ i, ofDual (f i) := rfl @[simp] -theorem ofDual_iInf (f : ι → αᵒᵈ) : ofDual (⨅ i, f i) = ⨆ i, ofDual (f i) := +theorem ofDual_iInf [SupSet α] (f : ι → αᵒᵈ) : ofDual (⨅ i, f i) = ⨆ i, ofDual (f i) := rfl +end OrderDual + +variable [CompleteLattice α] {s t : Set α} {a b : α} + theorem sInf_le_sSup (hs : s.Nonempty) : sInf s ≤ sSup s := isGLB_le_isLUB (isGLB_sInf s) (isLUB_sSup s) hs @@ -753,6 +757,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 _ _ @@ -866,6 +876,9 @@ theorem iSup_eq_bot : iSup s = ⊥ ↔ ∀ i, s i = ⊥ := theorem iInf_eq_top : iInf s = ⊤ ↔ ∀ i, s i = ⊤ := sInf_eq_top.trans forall_mem_range +@[simp] lemma bot_lt_iSup : ⊥ < ⨆ i, s i ↔ ∃ i, ⊥ < s i := by simp [bot_lt_iff_ne_bot] +@[simp] lemma iInf_lt_top : ⨅ i, s i < ⊤ ↔ ∃ i, s i < ⊤ := by simp [lt_top_iff_ne_top] + theorem iSup₂_eq_bot {f : ∀ i, κ i → α} : ⨆ (i) (j), f i j = ⊥ ↔ ∀ i j, f i j = ⊥ := by simp @@ -1025,7 +1038,7 @@ lemma le_biSup {ι : Type*} {s : Set ι} (f : ι → α) {i : ι} (hi : i ∈ s) begin apply @le_antisymm, - safe, pose h := f a ⊓ g a, begin [smt] ematch, ematch end + safe, pose h := f a ⊓ g a, begin [smt] ematch, ematch end end -/ theorem iSup_sup [Nonempty ι] {f : ι → α} {a : α} : (⨆ x, f x) ⊔ a = ⨆ x, f x ⊔ a := by @@ -1273,12 +1286,24 @@ theorem iInf_sigma {p : β → Type*} {f : Sigma p → α} : ⨅ x, f x = ⨅ (i @iSup_sigma αᵒᵈ _ _ _ _ lemma iSup_sigma' {κ : β → Type*} (f : ∀ i, κ i → α) : - (⨆ i, ⨆ j, f i j) = ⨆ x : Σ i, κ i, f x.1 x.2 := -(iSup_sigma (f := fun x ↦ f x.1 x.2)).symm + (⨆ i, ⨆ j, f i j) = ⨆ x : Σ i, κ i, f x.1 x.2 := (iSup_sigma (f := fun x ↦ f x.1 x.2)).symm lemma iInf_sigma' {κ : β → Type*} (f : ∀ i, κ i → α) : - (⨅ i, ⨅ j, f i j) = ⨅ x : Σ i, κ i, f x.1 x.2 := -(iInf_sigma (f := fun x ↦ f x.1 x.2)).symm + (⨅ i, ⨅ j, f i j) = ⨅ x : Σ i, κ i, f x.1 x.2 := (iInf_sigma (f := fun x ↦ f x.1 x.2)).symm + +lemma iSup_psigma {ι : Sort*} {κ : ι → Sort*} (f : (Σ' i, κ i) → α) : + ⨆ ij, f ij = ⨆ i, ⨆ j, f ⟨i, j⟩ := + eq_of_forall_ge_iff fun c ↦ by simp only [iSup_le_iff, PSigma.forall] + +lemma iInf_psigma {ι : Sort*} {κ : ι → Sort*} (f : (Σ' i, κ i) → α) : + ⨅ ij, f ij = ⨅ i, ⨅ j, f ⟨i, j⟩ := + eq_of_forall_le_iff fun c ↦ by simp only [le_iInf_iff, PSigma.forall] + +lemma iSup_psigma' {ι : Sort*} {κ : ι → Sort*} (f : ∀ i, κ i → α) : + (⨆ i, ⨆ j, f i j) = ⨆ ij : Σ' i, κ i, f ij.1 ij.2 := (iSup_psigma fun x ↦ f x.1 x.2).symm + +lemma iInf_psigma' {ι : Sort*} {κ : ι → Sort*} (f : ∀ i, κ i → α) : + (⨅ i, ⨅ j, f i j) = ⨅ ij : Σ' i, κ i, f ij.1 ij.2 := (iInf_psigma fun x ↦ f x.1 x.2).symm theorem iSup_prod {f : β × γ → α} : ⨆ x, f x = ⨆ (i) (j), f (i, j) := eq_of_forall_ge_iff fun c => by simp only [iSup_le_iff, Prod.forall] @@ -1412,6 +1437,12 @@ theorem iSup_eq_top (f : ι → α) : iSup f = ⊤ ↔ ∀ b < ⊤, ∃ i, b < f theorem iInf_eq_bot (f : ι → α) : iInf f = ⊥ ↔ ∀ b > ⊥, ∃ i, f i < b := by simp only [← sInf_range, sInf_eq_bot, Set.exists_range_iff] +lemma iSup₂_eq_top (f : ∀ i, κ i → α) : ⨆ i, ⨆ j, f i j = ⊤ ↔ ∀ b < ⊤, ∃ i j, b < f i j := by + simp_rw [iSup_psigma', iSup_eq_top, PSigma.exists] + +lemma iInf₂_eq_bot (f : ∀ i, κ i → α) : ⨅ i, ⨅ j, f i j = ⊥ ↔ ∀ b > ⊥, ∃ i j, f i j < b := by + simp_rw [iInf_psigma', iInf_eq_bot, PSigma.exists] + end CompleteLinearOrder /-! @@ -1575,7 +1606,7 @@ theorem snd_iInf [InfSet α] [InfSet β] (f : ι → α × β) : (iInf f).snd = congr_arg sInf (range_comp _ _).symm theorem swap_iInf [InfSet α] [InfSet β] (f : ι → α × β) : (iInf f).swap = ⨅ i, (f i).swap := by - simp_rw [iInf, swap_sInf, ← range_comp, Function.comp] -- Porting note: need to unfold `∘` + simp_rw [iInf, swap_sInf, ← range_comp, comp_def] -- Porting note: need to unfold `∘` theorem iInf_mk [InfSet α] [InfSet β] (f : ι → α) (g : ι → β) : ⨅ i, (f i, g i) = (⨅ i, f i, ⨅ i, g i) := @@ -1588,7 +1619,7 @@ theorem snd_iSup [SupSet α] [SupSet β] (f : ι → α × β) : (iSup f).snd = congr_arg sSup (range_comp _ _).symm theorem swap_iSup [SupSet α] [SupSet β] (f : ι → α × β) : (iSup f).swap = ⨆ i, (f i).swap := by - simp_rw [iSup, swap_sSup, ← range_comp, Function.comp] -- Porting note: need to unfold `∘` + simp_rw [iSup, swap_sSup, ← range_comp, comp_def] -- Porting note: need to unfold `∘` theorem iSup_mk [SupSet α] [SupSet β] (f : ι → α) (g : ι → β) : ⨆ i, (f i, g i) = (⨆ i, f i, ⨆ i, g i) := @@ -1719,3 +1750,5 @@ instance instCompleteLinearOrder : CompleteLinearOrder PUnit where top_sdiff := by intros; trivial end PUnit + +set_option linter.style.longFile 1900 diff --git a/Mathlib/Order/CompleteLattice/Finset.lean b/Mathlib/Order/CompleteLattice/Finset.lean new file mode 100644 index 0000000000000..b96b173756c62 --- /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.Order.Minimal + +/-! +# 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 44fa32da464fc..149df0ed5225d 100644 --- a/Mathlib/Order/CompleteLatticeIntervals.lean +++ b/Mathlib/Order/CompleteLatticeIntervals.lean @@ -52,7 +52,7 @@ theorem subset_sSup_def [Inhabited s] : rfl theorem subset_sSup_of_within [Inhabited s] {t : Set s} - (h' : t.Nonempty) (h'' : BddAbove t) (h : sSup ((↑) '' t : Set α) ∈ s) : + (h' : t.Nonempty) (h'' : BddAbove t) (h : sSup ((↑) '' t : Set α) ∈ s) : sSup ((↑) '' t : Set α) = (@sSup s _ t : α) := by simp [dif_pos, h, h', h''] theorem subset_sSup_emptyset [Inhabited s] : diff --git a/Mathlib/Order/CompleteSublattice.lean b/Mathlib/Order/CompleteSublattice.lean index 908ecea1281e8..cabb0e732606e 100644 --- a/Mathlib/Order/CompleteSublattice.lean +++ b/Mathlib/Order/CompleteSublattice.lean @@ -66,10 +66,10 @@ instance instTop : Top L where top := ⟨⊤, by simpa using L.sInfClosed' <| empty_subset _⟩ instance instSupSet : SupSet L where - sSup s := ⟨sSup s, L.sSupClosed' image_val_subset⟩ + sSup s := ⟨sSup <| (↑) '' s, L.sSupClosed' image_val_subset⟩ instance instInfSet : InfSet L where - sInf s := ⟨sInf s, L.sInfClosed' image_val_subset⟩ + sInf s := ⟨sInf <| (↑) '' s, L.sInfClosed' image_val_subset⟩ theorem sSupClosed {s : Set α} (h : s ⊆ L) : sSup s ∈ L := L.sSupClosed' h @@ -89,6 +89,10 @@ theorem coe_sSup' (S : Set L) : (↑(sSup S) : α) = ⨆ N ∈ S, (N : α) := by theorem coe_sInf' (S : Set L) : (↑(sInf S) : α) = ⨅ N ∈ S, (N : α) := by rw [coe_sInf, ← Set.image, sInf_image] +-- Redeclaring to get proper keys for these instances +instance : Sup {x // x ∈ L} := Sublattice.instSupCoe +instance : Inf {x // x ∈ L} := Sublattice.instInfCoe + instance instCompleteLattice : CompleteLattice L := Subtype.coe_injective.completeLattice _ Sublattice.coe_sup Sublattice.coe_inf coe_sSup' coe_sInf' coe_top coe_bot diff --git a/Mathlib/Order/Concept.lean b/Mathlib/Order/Concept.lean index b4818c18d6fc2..ea202e9b33def 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 -/ diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean b/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean index 783720c3aa7e9..9f80770bcdc85 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean @@ -155,7 +155,7 @@ every nonempty subset which is bounded below has an infimum. Typical examples are real numbers or natural numbers. To differentiate the statements from the corresponding statements in (unconditional) -complete lattices, we prefix sInf and subₛ by a c everywhere. The same statements should +complete lattices, we prefix `sInf` and `sSup` by a `c` everywhere. The same statements should hold in both worlds, sometimes with additional assumptions of nonemptiness or boundedness. -/ class ConditionallyCompleteLattice (α : Type*) extends Lattice α, SupSet α, InfSet α where @@ -175,7 +175,7 @@ every nonempty subset which is bounded below has an infimum. Typical examples are real numbers or natural numbers. To differentiate the statements from the corresponding statements in (unconditional) -complete linear orders, we prefix sInf and sSup by a c everywhere. The same statements should +complete linear orders, we prefix `sInf` and `sSup` by a `c` everywhere. The same statements should hold in both worlds, sometimes with additional assumptions of nonemptiness or boundedness. -/ class ConditionallyCompleteLinearOrder (α : Type*) extends ConditionallyCompleteLattice α where @@ -215,7 +215,7 @@ every nonempty subset which is bounded above has a supremum, and every nonempty bounded below) has an infimum. A typical example is the natural numbers. To differentiate the statements from the corresponding statements in (unconditional) -complete linear orders, we prefix `sInf` and `sSup` by a c everywhere. The same statements should +complete linear orders, we prefix `sInf` and `sSup` by a `c` everywhere. The same statements should hold in both worlds, sometimes with additional assumptions of nonemptiness or boundedness. -/ class ConditionallyCompleteLinearOrderBot (α : Type*) extends ConditionallyCompleteLinearOrder α, @@ -251,8 +251,8 @@ instance (priority := 100) CompleteLinearOrder.toConditionallyCompleteLinearOrde open scoped Classical in /-- A well founded linear order is conditionally complete, with a bottom element. -/ -noncomputable abbrev IsWellOrder.conditionallyCompleteLinearOrderBot (α : Type*) - [i₁ : _root_.LinearOrder α] [i₂ : OrderBot α] [h : IsWellOrder α (· < ·)] : +noncomputable abbrev WellFoundedLT.conditionallyCompleteLinearOrderBot (α : Type*) + [i₁ : LinearOrder α] [i₂ : OrderBot α] [h : WellFoundedLT α] : ConditionallyCompleteLinearOrderBot α := { i₁, i₂, LinearOrder.toLattice with sInf := fun s => if hs : s.Nonempty then h.wf.min s hs else ⊥ @@ -539,14 +539,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)) @@ -591,12 +597,12 @@ theorem exists_between_of_forall_le (sne : s.Nonempty) (tne : t.Nonempty) (hst : ∀ x ∈ s, ∀ y ∈ t, x ≤ y) : (upperBounds s ∩ lowerBounds t).Nonempty := ⟨sInf t, fun x hx => le_csInf tne <| hst x hx, fun _ hy => csInf_le (sne.mono hst) hy⟩ -/-- The supremum of a singleton is the element of the singleton-/ +/-- The supremum of a singleton is the element of the singleton -/ @[simp] theorem csSup_singleton (a : α) : sSup {a} = a := isGreatest_singleton.csSup_eq -/-- The infimum of a singleton is the element of the singleton-/ +/-- The infimum of a singleton is the element of the singleton -/ @[simp] theorem csInf_singleton (a : α) : sInf {a} = a := isLeast_singleton.csInf_eq @@ -698,18 +704,18 @@ 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-/ +/-- 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-/ +/-- 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 supremum of two functions are comparable if the functions are pointwise comparable-/ +/-- 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 ι @@ -720,15 +726,15 @@ theorem le_ciSup_set {f : β → α} {s : Set β} (H : BddAbove (f '' s)) {c : 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-/ +/-- 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-/ +/-- 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-/ +/-- 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 @@ -1106,7 +1112,7 @@ theorem cbiInf_eq_of_not_forall {p : ι → Prop} {f : Subtype p → α} (hp : open Function -variable [IsWellOrder α (· < ·)] +variable [WellFoundedLT α] theorem sInf_eq_argmin_on (hs : s.Nonempty) : sInf s = argminOn id wellFounded_lt s hs := IsLeast.csInf_eq ⟨argminOn_mem _ _ _ _, fun _ ha => argminOn_le id _ _ ha⟩ @@ -1206,6 +1212,9 @@ theorem exists_lt_of_lt_ciSup' {f : ι → α} {a : α} (h : a < ⨆ i, f i) : contrapose! h exact ciSup_le' h +theorem not_mem_of_lt_csInf' {x : α} {s : Set α} (h : x < sInf s) : x ∉ s := + not_mem_of_lt_csInf h (OrderBot.bddBelow s) + theorem ciSup_mono' {ι'} {f : ι → α} {g : ι' → α} (hg : BddAbove (range g)) (h : ∀ i, ∃ i', f i ≤ g i') : iSup f ≤ iSup g := ciSup_le' fun i => Exists.elim (h i) (le_ciSup_of_le hg) @@ -1213,6 +1222,12 @@ theorem ciSup_mono' {ι'} {f : ι → α} {g : ι' → α} (hg : BddAbove (range 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₂ +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₂ + 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 @@ -1639,3 +1654,5 @@ lemma iInf_coe_lt_top : ⨅ i, (f i : WithTop α) < ⊤ ↔ Nonempty ι := by 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 7c3aa9e1c8185..c493a2324fc8c 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Finset.lean @@ -46,6 +46,143 @@ theorem Set.Finite.csSup_lt_iff (hs : s.Finite) (h : s.Nonempty) : sSup s < a theorem Set.Finite.lt_csInf_iff (hs : s.Finite) (h : s.Nonempty) : a < sInf s ↔ ∀ x ∈ s, a < x := @Set.Finite.csSup_lt_iff αᵒᵈ _ _ _ hs h +variable (f : ι → α) + +theorem Finset.ciSup_eq_max'_image {s : Finset ι} (h : ∃ x ∈ s, sSup ∅ ≤ f x) + (h' : (s.image f).Nonempty := by classical exact image_nonempty.mpr (h.imp fun _ ↦ And.left)) : + ⨆ i ∈ s, f i = (s.image f).max' h' := by + classical + rw [iSup, ← h'.csSup_eq_max', coe_image] + refine csSup_eq_csSup_of_forall_exists_le ?_ ?_ + · simp only [ciSup_eq_ite, dite_eq_ite, Set.mem_range, Set.mem_image, mem_coe, + exists_exists_and_eq_and, forall_exists_index, forall_apply_eq_imp_iff] + intro i + split_ifs + · exact ⟨_, by assumption, le_rfl⟩ + · obtain ⟨a, ha, ha'⟩ := h + exact ⟨a, ha, ha'⟩ + · simp only [Set.mem_image, mem_coe, ciSup_eq_ite, dite_eq_ite, Set.mem_range, + exists_exists_eq_and, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂] + intro i hi + refine ⟨i, ?_⟩ + simp [hi] + +theorem Finset.ciInf_eq_min'_image {s : Finset ι} (h : ∃ x ∈ s, f x ≤ sInf ∅) + (h' : (s.image f).Nonempty := by classical exact image_nonempty.mpr (h.imp fun _ ↦ And.left)) : + ⨅ i ∈ s, f i = (s.image f).min' h' := by + classical + rw [← OrderDual.toDual_inj, toDual_min', toDual_iInf] + simp only [Function.comp_apply, toDual_iInf] + rw [ciSup_eq_max'_image _ h] + simp only [image_image] + congr + +theorem Finset.ciSup_mem_image {s : Finset ι} (h : ∃ x ∈ s, sSup ∅ ≤ f x) : + ⨆ i ∈ s, f i ∈ s.image f := by + rw [ciSup_eq_max'_image _ h] + exact max'_mem (image f s) _ + +theorem Finset.ciInf_mem_image {s : Finset ι} (h : ∃ x ∈ s, f x ≤ sInf ∅) : + ⨅ i ∈ s, f i ∈ s.image f := by + rw [ciInf_eq_min'_image _ h] + exact min'_mem (image f s) _ + +theorem Set.Finite.ciSup_mem_image {s : Set ι} (hs : s.Finite) (h : ∃ x ∈ s, sSup ∅ ≤ f x) : + ⨆ i ∈ s, f i ∈ f '' s := by + lift s to Finset ι using hs + simp only [Finset.mem_coe] at h + simpa using Finset.ciSup_mem_image f h + +theorem Set.Finite.ciInf_mem_image {s : Set ι} (hs : s.Finite) (h : ∃ x ∈ s, f x ≤ sInf ∅) : + ⨅ i ∈ s, f i ∈ f '' s := by + lift s to Finset ι using hs + simp only [Finset.mem_coe] at h + simpa using Finset.ciInf_mem_image f h + +theorem Set.Finite.ciSup_lt_iff {s : Set ι} {f : ι → α} (hs : s.Finite) + (h : ∃ x ∈ s, sSup ∅ ≤ f x) : + ⨆ i ∈ s, f i < a ↔ ∀ x ∈ s, f x < a := by + constructor + · intro h x hx + refine h.trans_le' (le_csSup ?_ ?_) + · classical + refine (((hs.image f).union (finite_singleton (sSup ∅))).subset ?_).bddAbove + intro + simp only [ciSup_eq_ite, dite_eq_ite, mem_range, union_singleton, mem_insert_iff, mem_image, + forall_exists_index] + intro x hx + split_ifs at hx + · exact Or.inr ⟨_, by assumption, hx⟩ + · simp_all + · simp only [mem_range] + refine ⟨x, ?_⟩ + simp [hx] + · intro H + have := hs.ciSup_mem_image _ h + simp only [mem_image] at this + obtain ⟨_, hmem, hx⟩ := this + rw [← hx] + exact H _ hmem + +theorem Set.Finite.lt_ciInf_iff {s : Set ι} {f : ι → α} (hs : s.Finite) + (h : ∃ x ∈ s, f x ≤ sInf ∅) : + a < ⨅ i ∈ s, f i ↔ ∀ x ∈ s, a < f x := by + constructor + · intro h x hx + refine h.trans_le (csInf_le ?_ ?_) + · classical + refine (((hs.image f).union (finite_singleton (sInf ∅))).subset ?_).bddBelow + intro + simp only [ciInf_eq_ite, dite_eq_ite, mem_range, union_singleton, mem_insert_iff, mem_image, + forall_exists_index] + intro x hx + split_ifs at hx + · exact Or.inr ⟨_, by assumption, hx⟩ + · simp_all + · simp only [mem_range] + refine ⟨x, ?_⟩ + simp [hx] + · intro H + have := hs.ciInf_mem_image _ h + simp only [mem_image] at this + obtain ⟨_, hmem, hx⟩ := this + rw [← hx] + exact H _ hmem + +section ListMultiset + +lemma List.iSup_mem_map_of_exists_sSup_empty_le {l : List ι} (f : ι → α) + (h : ∃ x ∈ l, sSup ∅ ≤ f x) : + ⨆ x ∈ l, f x ∈ l.map f := by + classical + simpa using l.toFinset.ciSup_mem_image f (by simpa using h) + +lemma List.iInf_mem_map_of_exists_le_sInf_empty {l : List ι} (f : ι → α) + (h : ∃ x ∈ l, f x ≤ sInf ∅) : + ⨅ x ∈ l, f x ∈ l.map f := by + classical + simpa using l.toFinset.ciInf_mem_image f (by simpa using h) + +lemma Multiset.iSup_mem_map_of_exists_sSup_empty_le {s : Multiset ι} (f : ι → α) + (h : ∃ x ∈ s, sSup ∅ ≤ f x) : + ⨆ x ∈ s, f x ∈ s.map f := by + classical + simpa using s.toFinset.ciSup_mem_image f (by simpa using h) + +lemma Multiset.iInf_mem_map_of_exists_le_sInf_empty {s : Multiset ι} (f : ι → α) + (h : ∃ x ∈ s, f x ≤ sInf ∅) : + ⨅ x ∈ s, f x ∈ s.map f := by + classical + simpa using s.toFinset.ciInf_mem_image f (by simpa using h) + +theorem exists_eq_ciSup_of_finite [Nonempty ι] [Finite ι] {f : ι → α} : ∃ i, f i = ⨆ i, f i := + Nonempty.csSup_mem (range_nonempty f) (finite_range f) + +theorem exists_eq_ciInf_of_finite [Nonempty ι] [Finite ι] {f : ι → α} : ∃ i, f i = ⨅ i, f i := + Nonempty.csInf_mem (range_nonempty f) (finite_range f) + +end ListMultiset + end ConditionallyCompleteLinearOrder /-! @@ -96,3 +233,38 @@ lemma sup_univ_eq_ciSup [Fintype ι] (f : ι → α) : univ.sup f = ⨆ i, f i : end ConditionallyCompleteLinearOrderBot end Finset + +section ConditionallyCompleteLinearOrderBot + +variable [ConditionallyCompleteLinearOrderBot α] (f : ι → α) + +theorem Finset.Nonempty.ciSup_eq_max'_image {s : Finset ι} (h : s.Nonempty) + (h' : (s.image f).Nonempty := h.image f) : + ⨆ i ∈ s, f i = (s.image f).max' h' := + s.ciSup_eq_max'_image _ (h.imp (by simp)) _ + +theorem Finset.Nonempty.ciSup_mem_image {s : Finset ι} (h : s.Nonempty) : + ⨆ i ∈ s, f i ∈ s.image f := + s.ciSup_mem_image _ (h.imp (by simp)) + +theorem Set.Nonempty.ciSup_mem_image {s : Set ι} (h : s.Nonempty) (hs : s.Finite) : + ⨆ i ∈ s, f i ∈ f '' s := + hs.ciSup_mem_image _ (h.imp (by simp)) + +theorem Set.Nonempty.ciSup_lt_iff {s : Set ι} {a : α} {f : ι → α} (h : s.Nonempty) (hs : s.Finite) : + ⨆ i ∈ s, f i < a ↔ ∀ x ∈ s, f x < a := + hs.ciSup_lt_iff (h.imp (by simp)) + +section ListMultiset + +lemma List.iSup_mem_map_of_ne_nil {l : List ι} (f : ι → α) (h : l ≠ []) : + ⨆ x ∈ l, f x ∈ l.map f := + l.iSup_mem_map_of_exists_sSup_empty_le _ (by simpa using exists_mem_of_ne_nil _ h) + +lemma Multiset.iSup_mem_map_of_ne_zero {s : Multiset ι} (f : ι → α) (h : s ≠ 0) : + ⨆ x ∈ s, f x ∈ s.map f := + s.iSup_mem_map_of_exists_sSup_empty_le _ (by simpa using exists_mem_of_ne_zero h) + +end ListMultiset + +end ConditionallyCompleteLinearOrderBot diff --git a/Mathlib/Order/CountableDenseLinearOrder.lean b/Mathlib/Order/CountableDenseLinearOrder.lean index 0e43df278296d..1ab3a1faebbc2 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_not_mem_of_mem_insert hy hyS + simp only [hxS, hyS, ↓reduceDIte] + exact hb _ (Finset.mem_image_of_mem _ (Finset.mem_filter.2 ⟨Finset.mem_attach _ _, hxy⟩)) + else + obtain rfl := Finset.eq_of_not_mem_of_mem_insert hx hxS + if hyS : y ∈ S + then + simp only [hxS, hyS, ↓reduceDIte] + exact hb' _ (Finset.mem_image_of_mem _ (Finset.mem_filter.2 ⟨Finset.mem_attach _ _, hxy⟩)) + else simp only [Finset.eq_of_not_mem_of_mem_insert hy hyS, lt_self_iff_false] at hxy + · 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 28127f44875d2..cf13cbab95f7f 100644 --- a/Mathlib/Order/Cover.lean +++ b/Mathlib/Order/Cover.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies, Violeta Hernández Palacios, Grayson Burton, Floris van Doorn -/ import Mathlib.Order.Interval.Set.OrdConnected +import Mathlib.Order.Interval.Set.WithBotTop import Mathlib.Order.Antisymmetrization /-! @@ -79,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⟩ @@ -126,6 +127,19 @@ alias ⟨_, WCovBy.toDual⟩ := toDual_wcovBy_toDual_iff alias ⟨_, WCovBy.ofDual⟩ := ofDual_wcovBy_ofDual_iff +theorem OrderEmbedding.wcovBy_of_apply {α β : Type*} [Preorder α] [Preorder β] + (f : α ↪o β) {x y : α} (h : f x ⩿ f y) : x ⩿ y := by + use f.le_iff_le.1 h.1 + intro a + rw [← f.lt_iff_lt, ← f.lt_iff_lt] + apply h.2 + +theorem OrderIso.map_wcovBy {α β : Type*} [Preorder α] [Preorder β] + (f : α ≃o β) {x y : α} : f x ⩿ f y ↔ x ⩿ y := by + use f.toOrderEmbedding.wcovBy_of_apply + conv_lhs => rw [← f.symm_apply_apply x, ← f.symm_apply_apply y] + exact f.symm.toOrderEmbedding.wcovBy_of_apply + end Preorder section PartialOrder @@ -194,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 @@ -312,6 +326,19 @@ theorem apply_covBy_apply_iff {E : Type*} [EquivLike E α β] [OrderIsoClass E theorem covBy_of_eq_or_eq (hab : a < b) (h : ∀ c, a ≤ c → c ≤ b → c = a ∨ c = b) : a ⋖ b := ⟨hab, fun c ha hb => (h c ha.le hb.le).elim ha.ne' hb.ne⟩ +theorem OrderEmbedding.covBy_of_apply {α β : Type*} [Preorder α] [Preorder β] + (f : α ↪o β) {x y : α} (h : f x ⋖ f y) : x ⋖ y := by + use f.lt_iff_lt.1 h.1 + intro a + rw [← f.lt_iff_lt, ← f.lt_iff_lt] + apply h.2 + +theorem OrderIso.map_covBy {α β : Type*} [Preorder α] [Preorder β] + (f : α ≃o β) {x y : α} : f x ⋖ f y ↔ x ⋖ y := by + use f.toOrderEmbedding.covBy_of_apply + conv_lhs => rw [← f.symm_apply_apply x, ← f.symm_apply_apply y] + exact f.symm.toOrderEmbedding.covBy_of_apply + end Preorder section PartialOrder @@ -522,3 +549,61 @@ theorem covBy_iff : x ⋖ y ↔ x.1 ⋖ y.1 ∧ x.2 = y.2 ∨ x.2 ⋖ y.2 ∧ x. exact mk_covBy_mk_iff end Prod + +namespace WithTop + +variable [Preorder α] {a b : α} + +@[simp, norm_cast] lemma coe_wcovBy_coe : (a : WithTop α) ⩿ b ↔ a ⩿ b := + Set.OrdConnected.apply_wcovBy_apply_iff OrderEmbedding.withTopCoe <| by + simp [WithTop.range_coe, ordConnected_Iio] + +@[simp, norm_cast] lemma coe_covBy_coe : (a : WithTop α) ⋖ b ↔ a ⋖ b := + Set.OrdConnected.apply_covBy_apply_iff OrderEmbedding.withTopCoe <| by + simp [WithTop.range_coe, ordConnected_Iio] + +@[simp] lemma coe_covBy_top : (a : WithTop α) ⋖ ⊤ ↔ IsMax a := by + simp only [covBy_iff_Ioo_eq, ← image_coe_Ioi, coe_lt_top, image_eq_empty, + true_and, Ioi_eq_empty_iff] + +@[simp] lemma coe_wcovBy_top : (a : WithTop α) ⩿ ⊤ ↔ IsMax a := by + simp only [wcovBy_iff_Ioo_eq, ← image_coe_Ioi, le_top, image_eq_empty, true_and, Ioi_eq_empty_iff] + +end WithTop + +namespace WithBot + +variable [Preorder α] {a b : α} + +@[simp, norm_cast] lemma coe_wcovBy_coe : (a : WithBot α) ⩿ b ↔ a ⩿ b := + Set.OrdConnected.apply_wcovBy_apply_iff OrderEmbedding.withBotCoe <| by + simp [WithBot.range_coe, ordConnected_Ioi] + +@[simp, norm_cast] lemma coe_covBy_coe : (a : WithBot α) ⋖ b ↔ a ⋖ b := + Set.OrdConnected.apply_covBy_apply_iff OrderEmbedding.withBotCoe <| by + simp [WithBot.range_coe, ordConnected_Ioi] + +@[simp] lemma bot_covBy_coe : ⊥ ⋖ (a : WithBot α) ↔ IsMin a := by + simp only [covBy_iff_Ioo_eq, ← image_coe_Iio, bot_lt_coe, image_eq_empty, + true_and, Iio_eq_empty_iff] + +@[simp] lemma bot_wcovBy_coe : ⊥ ⩿ (a : WithBot α) ↔ IsMin a := by + 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 ebc2f957c77e3..a6a6ffa250fe6 100644 --- a/Mathlib/Order/Defs.lean +++ b/Mathlib/Order/Defs.lean @@ -3,11 +3,12 @@ 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 Mathlib.Init.Algebra.Classes +import Batteries.Classes.Order import Mathlib.Data.Ordering.Basic +import Mathlib.Tactic.Lemma +import Mathlib.Tactic.Relation.Trans import Mathlib.Tactic.SplitIfs import Mathlib.Tactic.TypeStar -import Batteries.Classes.Order /-! # Orders @@ -16,8 +17,176 @@ Defines classes for preorders, partial orders, and linear orders and proves some basic lemmas about them. -/ -universe u -variable {α : Type u} +/-! ### Unbundled classes -/ + +/-- 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). -/ +class IsIrrefl (α : Sort*) (r : α → α → Prop) : Prop where + irrefl : ∀ a, ¬r a a + +/-- `IsRefl X r` means the binary relation `r` on `X` is reflexive. -/ +class IsRefl (α : Sort*) (r : α → α → Prop) : Prop where + refl : ∀ a, r a a + +/-- `IsSymm X r` means the binary relation `r` on `X` is symmetric. -/ +class IsSymm (α : Sort*) (r : α → α → Prop) : Prop where + symm : ∀ a b, r a b → r b a + +/-- `IsAsymm X r` means that the binary relation `r` on `X` is asymmetric, that is, +`r a b → ¬ r b a`. -/ +class IsAsymm (α : Sort*) (r : α → α → Prop) : Prop where + asymm : ∀ a b, r a b → ¬r b a + +/-- `IsAntisymm X r` means the binary relation `r` on `X` is antisymmetric. -/ +class IsAntisymm (α : Sort*) (r : α → α → Prop) : Prop where + antisymm : ∀ a b, r a b → r b a → a = b + +instance (priority := 100) IsAsymm.toIsAntisymm {α : Sort*} (r : α → α → Prop) [IsAsymm α r] : + IsAntisymm α r where + antisymm _ _ hx hy := (IsAsymm.asymm _ _ hx hy).elim + +/-- `IsTrans X r` means the binary relation `r` on `X` is transitive. -/ +class IsTrans (α : Sort*) (r : α → α → Prop) : Prop where + trans : ∀ a b c, r a b → r b c → r a c + +instance {α : Sort*} {r : α → α → Prop} [IsTrans α r] : Trans r r r := + ⟨IsTrans.trans _ _ _⟩ + +instance (priority := 100) {α : Sort*} {r : α → α → Prop} [Trans r r r] : IsTrans α r := + ⟨fun _ _ _ => Trans.trans⟩ + +/-- `IsTotal X r` means that the binary relation `r` on `X` is total, that is, that for any +`x y : X` we have `r x y` or `r y x`. -/ +class IsTotal (α : Sort*) (r : α → α → Prop) : Prop where + total : ∀ a b, r a b ∨ r b a + +/-- `IsPreorder X r` means that the binary relation `r` on `X` is a pre-order, that is, reflexive +and transitive. -/ +class IsPreorder (α : Sort*) (r : α → α → Prop) extends IsRefl α r, IsTrans α r : Prop + +/-- `IsPartialOrder X r` means that the binary relation `r` on `X` is a partial order, that is, +`IsPreorder X r` and `IsAntisymm X r`. -/ +class IsPartialOrder (α : Sort*) (r : α → α → Prop) extends IsPreorder α r, IsAntisymm α r : Prop + +/-- `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*) (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`. -/ +class IsEquiv (α : Sort*) (r : α → α → Prop) extends IsPreorder α r, IsSymm α r : Prop + +/-- `IsStrictOrder X r` means that the binary relation `r` on `X` is a strict order, that is, +`IsIrrefl X r` and `IsTrans X r`. -/ +class IsStrictOrder (α : Sort*) (r : α → α → Prop) extends IsIrrefl α r, IsTrans α r : Prop + +/-- `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*) (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, +either `lt a b` or `a = b` or `lt b a` for any `a` and `b`. -/ +class IsTrichotomous (α : Sort*) (lt : α → α → Prop) : Prop where + trichotomous : ∀ a b, lt a b ∨ a = b ∨ lt b a + +/-- `IsStrictTotalOrder X lt` means that the binary relation `lt` on `X` is a strict total order, +that is, `IsTrichotomous X lt` and `IsStrictOrder X lt`. -/ +class IsStrictTotalOrder (α : Sort*) (lt : α → α → Prop) extends IsTrichotomous α lt, + IsStrictOrder α lt : Prop + +/-- Equality is an equivalence relation. -/ +instance eq_isEquiv (α : Sort*) : IsEquiv α (· = ·) where + symm := @Eq.symm _ + trans := @Eq.trans _ + refl := Eq.refl + +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 +lemma refl [IsRefl α r] (a : α) : a ≺ a := IsRefl.refl a +lemma trans [IsTrans α r] : a ≺ b → b ≺ c → a ≺ c := IsTrans.trans _ _ _ +lemma symm [IsSymm α r] : a ≺ b → b ≺ a := IsSymm.symm _ _ +lemma antisymm [IsAntisymm α r] : a ≺ b → b ≺ a → a = b := IsAntisymm.antisymm _ _ +lemma asymm [IsAsymm α r] : a ≺ b → ¬b ≺ a := IsAsymm.asymm _ _ + +lemma trichotomous [IsTrichotomous α r] : ∀ a b : α, a ≺ b ∨ a = b ∨ b ≺ a := + IsTrichotomous.trichotomous + +instance (priority := 90) isAsymm_of_isTrans_of_isIrrefl [IsTrans α r] [IsIrrefl α r] : + IsAsymm α r := + ⟨fun a _b h₁ h₂ => absurd (_root_.trans h₁ h₂) (irrefl a)⟩ + +variable (r) + +@[elab_without_expected_type] lemma irrefl_of [IsIrrefl α r] (a : α) : ¬a ≺ a := irrefl a +@[elab_without_expected_type] lemma refl_of [IsRefl α r] (a : α) : a ≺ a := refl a +@[elab_without_expected_type] lemma trans_of [IsTrans α r] : a ≺ b → b ≺ c → a ≺ c := _root_.trans +@[elab_without_expected_type] lemma symm_of [IsSymm α r] : a ≺ b → b ≺ a := symm +@[elab_without_expected_type] lemma asymm_of [IsAsymm α r] : a ≺ b → ¬b ≺ a := asymm + +@[elab_without_expected_type] +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 + +/-! ### Bundled classes -/ + +variable {α : Type*} section Preorder @@ -26,90 +195,68 @@ 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 lt_iff_le_not_le : ∀ a b : α, a < b ↔ a ≤ b ∧ ¬b ≤ a := by intros; rfl -variable [Preorder α] +variable [Preorder α] {a b c : α} /-- The relation `≤` on a preorder is reflexive. -/ -@[refl] -theorem le_refl : ∀ a : α, a ≤ a := - Preorder.le_refl +@[refl] lemma le_refl : ∀ a : α, a ≤ a := Preorder.le_refl /-- A version of `le_refl` where the argument is implicit -/ -theorem le_rfl {a : α} : a ≤ a := - le_refl a +lemma le_rfl : a ≤ a := le_refl a /-- The relation `≤` on a preorder is transitive. -/ -@[trans] -theorem le_trans : ∀ {a b c : α}, a ≤ b → b ≤ c → a ≤ c := - Preorder.le_trans _ _ _ +@[trans] lemma le_trans : a ≤ b → b ≤ c → a ≤ c := Preorder.le_trans _ _ _ -theorem lt_iff_le_not_le : ∀ {a b : α}, a < b ↔ a ≤ b ∧ ¬b ≤ a := - Preorder.lt_iff_le_not_le _ _ +lemma lt_iff_le_not_le : a < b ↔ a ≤ b ∧ ¬b ≤ a := Preorder.lt_iff_le_not_le _ _ -theorem lt_of_le_not_le : ∀ {a b : α}, a ≤ b → ¬b ≤ a → a < b - | _a, _b, hab, hba => lt_iff_le_not_le.mpr ⟨hab, hba⟩ +lemma lt_of_le_not_le (hab : a ≤ b) (hba : ¬ b ≤ a) : a < b := lt_iff_le_not_le.2 ⟨hab, hba⟩ +@[deprecated (since := "2024-07-30")] theorem le_not_le_of_lt : ∀ {a b : α}, a < b → a ≤ b ∧ ¬b ≤ a | _a, _b, hab => lt_iff_le_not_le.mp hab -theorem le_of_eq {a b : α} : a = b → a ≤ b := fun h => h ▸ le_refl a - -@[trans] -theorem ge_trans : ∀ {a b c : α}, a ≥ b → b ≥ c → a ≥ c := fun h₁ h₂ => le_trans h₂ h₁ - -theorem lt_irrefl : ∀ a : α, ¬a < a - | _a, haa => - match le_not_le_of_lt haa with - | ⟨h1, h2⟩ => h2 h1 +lemma le_of_eq (hab : a = b) : a ≤ b := by rw [hab] +lemma le_of_lt (hab : a < b) : a ≤ b := (lt_iff_le_not_le.1 hab).1 +lemma not_le_of_lt (hab : a < b) : ¬ b ≤ a := (lt_iff_le_not_le.1 hab).2 +lemma not_le_of_gt (hab : a > b) : ¬a ≤ b := not_le_of_lt hab +lemma not_lt_of_le (hab : a ≤ b) : ¬ b < a := imp_not_comm.1 not_le_of_lt hab +lemma not_lt_of_ge (hab : a ≥ b) : ¬a < b := not_lt_of_le hab -theorem gt_irrefl : ∀ a : α, ¬a > a := - lt_irrefl +alias LT.lt.not_le := not_le_of_lt +alias LE.le.not_lt := not_lt_of_le -@[trans] -theorem lt_trans : ∀ {a b c : α}, a < b → b < c → a < c - | _a, _b, _c, hab, hbc => - match le_not_le_of_lt hab, le_not_le_of_lt hbc with - | ⟨hab, _hba⟩, ⟨hbc, hcb⟩ => - lt_of_le_not_le (le_trans hab hbc) fun hca => hcb (le_trans hca hab) +@[trans] lemma ge_trans : a ≥ b → b ≥ c → a ≥ c := fun h₁ h₂ => le_trans h₂ h₁ -@[trans] -theorem gt_trans : ∀ {a b c : α}, a > b → b > c → a > c := fun h₁ h₂ => lt_trans h₂ h₁ +lemma lt_irrefl (a : α) : ¬a < a := fun h ↦ not_le_of_lt h le_rfl +lemma gt_irrefl (a : α) : ¬a > a := lt_irrefl _ -theorem ne_of_lt {a b : α} (h : a < b) : a ≠ b := fun he => absurd h (he ▸ lt_irrefl a) +@[trans] lemma lt_of_lt_of_le (hab : a < b) (hbc : b ≤ c) : a < c := + lt_of_le_not_le (le_trans (le_of_lt hab) hbc) fun hca ↦ not_le_of_lt hab (le_trans hbc hca) -theorem ne_of_gt {a b : α} (h : b < a) : a ≠ b := fun he => absurd h (he ▸ lt_irrefl a) +@[trans] lemma lt_of_le_of_lt (hab : a ≤ b) (hbc : b < c) : a < c := + lt_of_le_not_le (le_trans hab (le_of_lt hbc)) fun hca ↦ not_le_of_lt hbc (le_trans hca hab) -theorem lt_asymm {a b : α} (h : a < b) : ¬b < a := fun h1 : b < a => lt_irrefl a (lt_trans h h1) +@[trans] lemma gt_of_gt_of_ge (h₁ : a > b) (h₂ : b ≥ c) : a > c := lt_of_le_of_lt h₂ h₁ +@[trans] lemma gt_of_ge_of_gt (h₁ : a ≥ b) (h₂ : b > c) : a > c := lt_of_lt_of_le h₂ h₁ -theorem le_of_lt : ∀ {a b : α}, a < b → a ≤ b - | _a, _b, hab => (le_not_le_of_lt hab).left +@[trans] lemma lt_trans (hab : a < b) (hbc : b < c) : a < c := lt_of_lt_of_le hab (le_of_lt hbc) +@[trans] lemma gt_trans : a > b → b > c → a > c := fun h₁ h₂ => lt_trans h₂ h₁ -@[trans] -theorem lt_of_lt_of_le : ∀ {a b c : α}, a < b → b ≤ c → a < c - | _a, _b, _c, hab, hbc => - let ⟨hab, hba⟩ := le_not_le_of_lt hab - lt_of_le_not_le (le_trans hab hbc) fun hca => hba (le_trans hbc hca) +lemma ne_of_lt (h : a < b) : a ≠ b := fun he => absurd h (he ▸ lt_irrefl a) +lemma ne_of_gt (h : b < a) : a ≠ b := fun he => absurd h (he ▸ lt_irrefl a) +lemma lt_asymm (h : a < b) : ¬b < a := fun h1 : b < a => lt_irrefl a (lt_trans h h1) -@[trans] -theorem lt_of_le_of_lt : ∀ {a b c : α}, a ≤ b → b < c → a < c - | _a, _b, _c, hab, hbc => - let ⟨hbc, hcb⟩ := le_not_le_of_lt hbc - lt_of_le_not_le (le_trans hab hbc) fun hca => hcb (le_trans hca hab) +alias not_lt_of_gt := lt_asymm +alias not_lt_of_lt := lt_asymm -@[trans] -theorem gt_of_gt_of_ge {a b c : α} (h₁ : a > b) (h₂ : b ≥ c) : a > c := - lt_of_le_of_lt h₂ h₁ +lemma le_of_lt_or_eq (h : a < b ∨ a = b) : a ≤ b := h.elim le_of_lt le_of_eq +lemma le_of_eq_or_lt (h : a = b ∨ a < b) : a ≤ b := h.elim le_of_eq le_of_lt -@[trans] -theorem gt_of_ge_of_gt {a b c : α} (h₁ : a ≥ b) (h₂ : b > c) : a > c := - lt_of_lt_of_le h₂ h₁ - --- Porting note (#10754): new instance instance (priority := 900) : @Trans α α α LE.le LE.le LE.le := ⟨le_trans⟩ instance (priority := 900) : @Trans α α α LT.lt LT.lt LT.lt := ⟨lt_trans⟩ instance (priority := 900) : @Trans α α α LT.lt LE.le LT.lt := ⟨lt_of_lt_of_le⟩ @@ -119,18 +266,6 @@ instance (priority := 900) : @Trans α α α GT.gt GT.gt GT.gt := ⟨gt_trans⟩ instance (priority := 900) : @Trans α α α GT.gt GE.ge GT.gt := ⟨gt_of_gt_of_ge⟩ instance (priority := 900) : @Trans α α α GE.ge GT.gt GT.gt := ⟨gt_of_ge_of_gt⟩ -theorem not_le_of_gt {a b : α} (h : a > b) : ¬a ≤ b := - (le_not_le_of_lt h).right - -theorem not_lt_of_ge {a b : α} (h : a ≥ b) : ¬a < b := fun hab => not_le_of_gt hab h - -theorem le_of_lt_or_eq : ∀ {a b : α}, a < b ∨ a = b → a ≤ b - | _a, _b, Or.inl hab => le_of_lt hab - | _a, _b, Or.inr hab => hab ▸ le_refl _ - -theorem le_of_eq_or_lt {a b : α} (h : a = b ∨ a < b) : a ≤ b := - Or.elim h le_of_eq le_of_lt - /-- `<` is decidable if `≤` is. -/ def decidableLTOfDecidableLE [@DecidableRel α (· ≤ ·)] : @DecidableRel α (· < ·) | a, b => @@ -148,20 +283,19 @@ 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 α] +variable [PartialOrder α] {a b : α} -theorem le_antisymm : ∀ {a b : α}, a ≤ b → b ≤ a → a = b := - PartialOrder.le_antisymm _ _ +lemma le_antisymm : a ≤ b → b ≤ a → a = b := PartialOrder.le_antisymm _ _ alias eq_of_le_of_le := le_antisymm -theorem le_antisymm_iff {a b : α} : a = b ↔ a ≤ b ∧ b ≤ a := +lemma le_antisymm_iff : a = b ↔ a ≤ b ∧ b ≤ a := ⟨fun e => ⟨le_of_eq e, le_of_eq e.symm⟩, fun ⟨h1, h2⟩ => le_antisymm h1 h2⟩ -theorem lt_of_le_of_ne {a b : α} : a ≤ b → a ≠ b → a < b := fun h₁ h₂ => +lemma lt_of_le_of_ne : a ≤ b → a ≠ b → a < b := fun h₁ h₂ => lt_of_le_not_le h₁ <| mt (le_antisymm h₁) h₂ /-- Equality is decidable if `≤` is. -/ @@ -175,24 +309,21 @@ namespace Decidable variable [@DecidableRel α (· ≤ ·)] -theorem lt_or_eq_of_le {a b : α} (hab : a ≤ b) : a < b ∨ a = b := +lemma lt_or_eq_of_le (hab : a ≤ b) : a < b ∨ a = b := if hba : b ≤ a then Or.inr (le_antisymm hab hba) else Or.inl (lt_of_le_not_le hab hba) -theorem eq_or_lt_of_le {a b : α} (hab : a ≤ b) : a = b ∨ a < b := +lemma eq_or_lt_of_le (hab : a ≤ b) : a = b ∨ a < b := (lt_or_eq_of_le hab).symm -theorem le_iff_lt_or_eq {a b : α} : a ≤ b ↔ a < b ∨ a = b := +lemma le_iff_lt_or_eq : a ≤ b ↔ a < b ∨ a = b := ⟨lt_or_eq_of_le, le_of_lt_or_eq⟩ end Decidable attribute [local instance] Classical.propDecidable -theorem lt_or_eq_of_le {a b : α} : a ≤ b → a < b ∨ a = b := - Decidable.lt_or_eq_of_le - -theorem le_iff_lt_or_eq {a b : α} : a ≤ b ↔ a < b ∨ a = b := - Decidable.le_iff_lt_or_eq +lemma lt_or_eq_of_le : a ≤ b → a < b ∨ a = b := Decidable.lt_or_eq_of_le +lemma le_iff_lt_or_eq : a ≤ b ↔ a < b ∨ a = b := Decidable.le_iff_lt_or_eq end PartialOrder @@ -203,11 +334,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 @@ -226,7 +357,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. -/ @@ -247,23 +378,17 @@ class LinearOrder (α : Type u) extends PartialOrder α, Min α, Max α, Ord α compare_eq_compareOfLessAndEq : ∀ a b, compare a b = compareOfLessAndEq a b := by compareOfLessAndEq_rfl -variable [LinearOrder α] +variable [LinearOrder α] {a b c : α} attribute [local instance] LinearOrder.decidableLE -theorem le_total : ∀ a b : α, a ≤ b ∨ b ≤ a := - LinearOrder.le_total - -theorem le_of_not_ge {a b : α} : ¬a ≥ b → a ≤ b := - Or.resolve_left (le_total b a) +lemma le_total : ∀ a b : α, a ≤ b ∨ b ≤ a := LinearOrder.le_total -theorem le_of_not_le {a b : α} : ¬a ≤ b → b ≤ a := - Or.resolve_left (le_total a b) +lemma le_of_not_ge : ¬a ≥ b → a ≤ b := (le_total b a).resolve_left +lemma le_of_not_le : ¬a ≤ b → b ≤ a := (le_total a b).resolve_left +lemma lt_of_not_ge (h : ¬a ≥ b) : a < b := lt_of_le_not_le (le_of_not_ge h) h -theorem not_lt_of_gt {a b : α} (h : a > b) : ¬a < b := - lt_asymm h - -theorem lt_trichotomy (a b : α) : a < b ∨ a = b ∨ b < a := +lemma lt_trichotomy (a b : α) : a < b ∨ a = b ∨ b < a := Or.elim (le_total a b) (fun h : a ≤ b => Or.elim (Decidable.lt_or_eq_of_le h) (fun h : a < b => Or.inl h) fun h : a = b => @@ -272,73 +397,40 @@ theorem lt_trichotomy (a b : α) : a < b ∨ a = b ∨ b < a := Or.elim (Decidable.lt_or_eq_of_le h) (fun h : b < a => Or.inr (Or.inr h)) fun h : b = a => Or.inr (Or.inl h.symm) -theorem le_of_not_lt {a b : α} (h : ¬b < a) : a ≤ b := +lemma le_of_not_lt (h : ¬b < a) : a ≤ b := match lt_trichotomy a b with | Or.inl hlt => le_of_lt hlt | Or.inr (Or.inl HEq) => HEq ▸ le_refl a | Or.inr (Or.inr hgt) => absurd hgt h -theorem le_of_not_gt {a b : α} : ¬a > b → a ≤ b := - le_of_not_lt - -theorem lt_of_not_ge {a b : α} (h : ¬a ≥ b) : a < b := - lt_of_le_not_le ((le_total _ _).resolve_right h) h +lemma le_of_not_gt : ¬a > b → a ≤ b := le_of_not_lt -theorem lt_or_le (a b : α) : a < b ∨ b ≤ a := +lemma lt_or_le (a b : α) : a < b ∨ b ≤ a := if hba : b ≤ a then Or.inr hba else Or.inl <| lt_of_not_ge hba -theorem le_or_lt (a b : α) : a ≤ b ∨ b < a := - (lt_or_le b a).symm - -theorem lt_or_ge : ∀ a b : α, a < b ∨ a ≥ b := - lt_or_le - -theorem le_or_gt : ∀ a b : α, a ≤ b ∨ a > b := - le_or_lt - -theorem lt_or_gt_of_ne {a b : α} (h : a ≠ b) : a < b ∨ a > b := - match lt_trichotomy a b with - | Or.inl hlt => Or.inl hlt - | Or.inr (Or.inl HEq) => absurd HEq h - | Or.inr (Or.inr hgt) => Or.inr hgt +lemma le_or_lt (a b : α) : a ≤ b ∨ b < a := (lt_or_le b a).symm +lemma lt_or_ge : ∀ a b : α, a < b ∨ a ≥ b := lt_or_le +lemma le_or_gt : ∀ a b : α, a ≤ b ∨ a > b := le_or_lt -theorem ne_iff_lt_or_gt {a b : α} : a ≠ b ↔ a < b ∨ a > b := - ⟨lt_or_gt_of_ne, fun o => Or.elim o ne_of_lt ne_of_gt⟩ +lemma lt_or_gt_of_ne (h : a ≠ b) : a < b ∨ a > b := by simpa [h] using lt_trichotomy a b -theorem lt_iff_not_ge (x y : α) : x < y ↔ ¬x ≥ y := - ⟨not_le_of_gt, lt_of_not_ge⟩ +lemma ne_iff_lt_or_gt : a ≠ b ↔ a < b ∨ a > b := ⟨lt_or_gt_of_ne, (Or.elim · ne_of_lt ne_of_gt)⟩ -@[simp] -theorem not_lt {a b : α} : ¬a < b ↔ b ≤ a := - ⟨le_of_not_gt, not_lt_of_ge⟩ +lemma lt_iff_not_ge (x y : α) : x < y ↔ ¬x ≥ y := ⟨not_le_of_gt, lt_of_not_ge⟩ -@[simp] -theorem not_le {a b : α} : ¬a ≤ b ↔ b < a := - (lt_iff_not_ge _ _).symm +@[simp] lemma not_lt : ¬a < b ↔ b ≤ a := ⟨le_of_not_gt, not_lt_of_ge⟩ +@[simp] lemma not_le : ¬a ≤ b ↔ b < a := (lt_iff_not_ge _ _).symm -instance (priority := 900) (a b : α) : Decidable (a < b) := - LinearOrder.decidableLT a b +instance (priority := 900) (a b : α) : Decidable (a < b) := LinearOrder.decidableLT a b +instance (priority := 900) (a b : α) : Decidable (a ≤ b) := LinearOrder.decidableLE a b +instance (priority := 900) (a b : α) : Decidable (a = b) := LinearOrder.decidableEq a b -instance (priority := 900) (a b : α) : Decidable (a ≤ b) := - LinearOrder.decidableLE a b - -instance (priority := 900) (a b : α) : Decidable (a = b) := - LinearOrder.decidableEq a b - -theorem eq_or_lt_of_not_lt {a b : α} (h : ¬a < b) : a = b ∨ b < a := +lemma eq_or_lt_of_not_lt (h : ¬a < b) : a = b ∨ b < a := if h₁ : a = b then Or.inl h₁ else Or.inr (lt_of_not_ge fun hge => h (lt_of_le_of_ne hge h₁)) -instance : IsTotalPreorder α (· ≤ ·) where - trans := @le_trans _ _ - total := le_total - --- TODO(Leo): decide whether we should keep this instance or not -instance isStrictWeakOrder_of_linearOrder : IsStrictWeakOrder α (· < ·) := - have : IsTotalPreorder α (· ≤ ·) := by infer_instance -- Porting note: added - isStrictWeakOrder_of_isTotalPreorder lt_iff_not_ge - -- TODO(Leo): decide whether we should keep this instance or not instance isStrictTotalOrder_of_linearOrder : IsStrictTotalOrder α (· < ·) where + irrefl := lt_irrefl trichotomous := lt_trichotomy /-- Perform a case-split on the ordering of `x` and `y` in a decidable linear order. -/ @@ -346,50 +438,174 @@ def ltByCases (x y : α) {P : Sort*} (h₁ : x < y → P) (h₂ : x = y → P) ( if h : x < y then h₁ h else if h' : y < x then h₃ h' else h₂ (le_antisymm (le_of_not_gt h') (le_of_not_gt h)) +namespace Nat + +/-! Deprecated properties of inequality on `Nat` -/ + +@[deprecated (since := "2024-08-23")] +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*} (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₁) + +end Nat + theorem le_imp_le_of_lt_imp_lt {α β} [Preorder α] [LinearOrder β] {a b : α} {c d : β} (H : d < c → b < a) (h : a ≤ b) : c ≤ d := le_of_not_lt fun h' => not_le_of_gt (H h') h --- Porting note: new +lemma min_def (a b : α) : min a b = if a ≤ b then a else b := by rw [LinearOrder.min_def a] +lemma max_def (a b : α) : max a b = if a ≤ b then b else a := by rw [LinearOrder.max_def a] + +-- Porting note: no `min_tac` tactic in the following series of lemmas + +lemma min_le_left (a b : α) : min a b ≤ a := by + if h : a ≤ b + then simp [min_def, if_pos h, le_refl] + else simp [min_def, if_neg h]; exact le_of_not_le h + +lemma min_le_right (a b : α) : min a b ≤ b := by + if h : a ≤ b + then simp [min_def, if_pos h]; exact h + else simp [min_def, if_neg h, le_refl] + +lemma le_min (h₁ : c ≤ a) (h₂ : c ≤ b) : c ≤ min a b := by + if h : a ≤ b + then simp [min_def, if_pos h]; exact h₁ + else simp [min_def, if_neg h]; exact h₂ + +lemma le_max_left (a b : α) : a ≤ max a b := by + if h : a ≤ b + then simp [max_def, if_pos h]; exact h + else simp [max_def, if_neg h, le_refl] + +lemma le_max_right (a b : α) : b ≤ max a b := by + if h : a ≤ b + then simp [max_def, if_pos h, le_refl] + else simp [max_def, if_neg h]; exact le_of_not_le h + +lemma max_le (h₁ : a ≤ c) (h₂ : b ≤ c) : max a b ≤ c := by + if h : a ≤ b + then simp [max_def, if_pos h]; exact h₂ + else simp [max_def, if_neg h]; exact h₁ + +lemma eq_min (h₁ : c ≤ a) (h₂ : c ≤ b) (h₃ : ∀ {d}, d ≤ a → d ≤ b → d ≤ c) : c = min a b := + le_antisymm (le_min h₁ h₂) (h₃ (min_le_left a b) (min_le_right a b)) + +lemma min_comm (a b : α) : min a b = min b a := + eq_min (min_le_right a b) (min_le_left a b) fun h₁ h₂ => le_min h₂ h₁ + +lemma min_assoc (a b c : α) : min (min a b) c = min a (min b c) := by + apply eq_min + · 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) := by + rw [← min_assoc, min_comm a, min_assoc] + +@[simp] lemma min_self (a : α) : min a a = a := by simp [min_def] + +lemma min_eq_left (h : a ≤ b) : min a b = a := by + apply Eq.symm; apply eq_min (le_refl _) h; intros; assumption + +lemma min_eq_right (h : b ≤ a) : min a b = b := min_comm b a ▸ min_eq_left h + +lemma eq_max (h₁ : a ≤ c) (h₂ : b ≤ c) (h₃ : ∀ {d}, a ≤ d → b ≤ d → c ≤ d) : + c = max a b := + le_antisymm (h₃ (le_max_left a b) (le_max_right a b)) (max_le h₁ h₂) + +lemma max_comm (a b : α) : max a b = max b a := + eq_max (le_max_right a b) (le_max_left a b) fun h₁ h₂ => max_le h₂ h₁ + +lemma max_assoc (a b c : α) : max (max a b) c = max a (max b c) := by + apply eq_max + · 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) := by + rw [← max_assoc, max_comm a, max_assoc] + +@[simp] lemma max_self (a : α) : max a a = a := by simp [max_def] + +lemma max_eq_left (h : b ≤ a) : max a b = a := by + apply Eq.symm; apply eq_max (le_refl _) h; intros; assumption + +lemma max_eq_right (h : a ≤ b) : max a b = b := max_comm b a ▸ max_eq_left h + +lemma min_eq_left_of_lt (h : a < b) : min a b = a := min_eq_left (le_of_lt h) +lemma min_eq_right_of_lt (h : b < a) : min a b = b := min_eq_right (le_of_lt h) +lemma max_eq_left_of_lt (h : b < a) : max a b = a := max_eq_left (le_of_lt h) +lemma max_eq_right_of_lt (h : a < b) : max a b = b := max_eq_right (le_of_lt h) + +lemma lt_min (h₁ : a < b) (h₂ : a < c) : a < min b c := by + cases le_total b c <;> simp [min_eq_left, min_eq_right, *] + +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 -theorem compare_lt_iff_lt {a b : α} : (compare a b = .lt) ↔ a < b := by +lemma compare_lt_iff_lt : compare a b = .lt ↔ a < b := by rw [LinearOrder.compare_eq_compareOfLessAndEq, compareOfLessAndEq] - split_ifs <;> simp only [*, lt_irrefl] + split_ifs <;> simp only [*, lt_irrefl, reduceCtorEq] -theorem compare_gt_iff_gt {a b : α} : (compare a b = .gt) ↔ a > b := by +lemma compare_gt_iff_gt : compare a b = .gt ↔ a > b := by rw [LinearOrder.compare_eq_compareOfLessAndEq, compareOfLessAndEq] - split_ifs <;> simp only [*, lt_irrefl, not_lt_of_gt] + 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] -theorem compare_eq_iff_eq {a b : α} : (compare a b = .eq) ↔ a = b := by +lemma compare_eq_iff_eq : compare a b = .eq ↔ a = b := by rw [LinearOrder.compare_eq_compareOfLessAndEq, compareOfLessAndEq] - split_ifs <;> try simp only - case _ h => exact false_iff_iff.2 <| ne_iff_lt_or_gt.2 <| .inl h - case _ _ h => exact true_iff_iff.2 h - case _ _ h => exact false_iff_iff.2 h + split_ifs <;> try simp only [reduceCtorEq] + case _ h => rw [false_iff]; exact ne_iff_lt_or_gt.2 <| .inl h + case _ _ h => rwa [true_iff] + case _ _ h => rwa [false_iff] -theorem compare_le_iff_le {a b : α} : (compare a b ≠ .gt) ↔ a ≤ b := by +lemma compare_le_iff_le : compare a b ≠ .gt ↔ a ≤ b := by cases h : compare a b <;> simp · exact le_of_lt <| compare_lt_iff_lt.1 h · exact le_of_eq <| compare_eq_iff_eq.1 h · exact compare_gt_iff_gt.1 h -theorem compare_ge_iff_ge {a b : α} : (compare a b ≠ .lt) ↔ a ≥ b := by +lemma compare_ge_iff_ge : compare a b ≠ .lt ↔ a ≥ b := by cases h : compare a b <;> simp · exact compare_lt_iff_lt.1 h · exact le_of_eq <| (·.symm) <| compare_eq_iff_eq.1 h · exact le_of_lt <| compare_gt_iff_gt.1 h -theorem compare_iff (a b : α) {o : Ordering} : 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 @@ -398,6 +614,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 22dbc59d0d72e..29285fca18124 100644 --- a/Mathlib/Order/Directed.lean +++ b/Mathlib/Order/Directed.lean @@ -17,8 +17,6 @@ directed iff each pair of elements has a shared upper bound. * `DirectedOn r s`: Predicate stating that the set `s` is `r`-directed. * `IsDirected α r`: Prop-valued mixin stating that `α` is `r`-directed. Follows the style of the unbundled relation classes such as `IsTotal`. -* `ScottContinuous`: Predicate stating that a function between preorders preserves `IsLUB` on - directed sets. ## TODO @@ -40,7 +38,7 @@ variable {α : Type u} {β : Type v} {ι : Sort w} (r r' s : α → α → Prop) local infixl:50 " ≼ " => r /-- A family of elements of α is directed (with respect to a relation `≼` on α) - if there is a member of the family `≼`-above any pair in the family. -/ + if there is a member of the family `≼`-above any pair in the family. -/ def Directed (f : ι → α) := ∀ x y, ∃ z, f x ≼ f z ∧ f y ≼ f z @@ -110,7 +108,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 α} @@ -169,7 +167,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 := @@ -250,18 +248,48 @@ theorem isBot_iff_isMin [IsDirected α (· ≥ ·)] : IsBot a ↔ IsMin a := theorem isTop_iff_isMax [IsDirected α (· ≤ ·)] : IsTop a ↔ IsMax a := ⟨IsTop.isMax, IsMax.isTop⟩ -variable (β) [PartialOrder β] +end Preorder + +section PartialOrder + +variable [PartialOrder β] -theorem exists_lt_of_directed_ge [IsDirected β (· ≥ ·)] [Nontrivial β] : ∃ a b : β, a < b := by +section Nontrivial + +variable [Nontrivial β] + +variable (β) in +theorem exists_lt_of_directed_ge [IsDirected β (· ≥ ·)] : + ∃ a b : β, a < b := by rcases exists_pair_ne β with ⟨a, b, hne⟩ rcases isBot_or_exists_lt a with (ha | ⟨c, hc⟩) exacts [⟨a, b, (ha b).lt_of_ne hne⟩, ⟨_, _, hc⟩] -theorem exists_lt_of_directed_le [IsDirected β (· ≤ ·)] [Nontrivial β] : ∃ a b : β, a < b := +variable (β) in +theorem exists_lt_of_directed_le [IsDirected β (· ≤ ·)] : + ∃ a b : β, a < b := let ⟨a, b, h⟩ := exists_lt_of_directed_ge βᵒᵈ ⟨b, a, h⟩ -variable {f : α → β} {s : Set α} +protected theorem IsMin.not_isMax [IsDirected β (· ≥ ·)] {b : β} (hb : IsMin b) : ¬ IsMax b := by + intro hb' + obtain ⟨a, c, hac⟩ := exists_lt_of_directed_ge β + have := hb.isBot a + obtain rfl := (hb' <| this).antisymm this + exact hb'.not_lt hac + +protected theorem IsMin.not_isMax' [IsDirected β (· ≤ ·)] {b : β} (hb : IsMin b) : ¬ IsMax b := + fun hb' ↦ hb'.toDual.not_isMax hb.toDual + +protected theorem IsMax.not_isMin [IsDirected β (· ≤ ·)] {b : β} (hb : IsMax b) : ¬ IsMin b := + fun hb' ↦ hb.toDual.not_isMax hb'.toDual + +protected theorem IsMax.not_isMin' [IsDirected β (· ≥ ·)] {b : β} (hb : IsMax b) : ¬ IsMin b := + fun hb' ↦ hb'.toDual.not_isMin hb.toDual + +end Nontrivial + +variable [Preorder α] {f : α → β} {s : Set α} -- TODO: Generalise the following two lemmas to connected orders @@ -269,16 +297,16 @@ variable {f : α → β} {s : Set α} lemma constant_of_monotone_antitone [IsDirected α (· ≤ ·)] (hf : Monotone f) (hf' : Antitone f) (a b : α) : f a = f b := by obtain ⟨c, hac, hbc⟩ := exists_ge_ge a b - exact le_antisymm ((hf hac).trans $ hf' hbc) ((hf hbc).trans $ hf' hac) + exact le_antisymm ((hf hac).trans <| hf' hbc) ((hf hbc).trans <| hf' hac) /-- If `f` is monotone and antitone on a directed set `s`, then `f` is constant on `s`. -/ lemma constant_of_monotoneOn_antitoneOn (hf : MonotoneOn f s) (hf' : AntitoneOn f s) (hs : DirectedOn (· ≤ ·) s) : ∀ ⦃a⦄, a ∈ s → ∀ ⦃b⦄, b ∈ s → f a = f b := by rintro a ha b hb obtain ⟨c, hc, hac, hbc⟩ := hs _ ha _ hb - exact le_antisymm ((hf ha hc hac).trans $ hf' hb hc hbc) ((hf hb hc hbc).trans $ hf' ha hc hac) + exact le_antisymm ((hf ha hc hac).trans <| hf' hb hc hbc) ((hf hb hc hbc).trans <| hf' ha hc hac) -end Preorder +end PartialOrder -- see Note [lower instance priority] instance (priority := 100) SemilatticeSup.to_isDirected_le [SemilatticeSup α] : diff --git a/Mathlib/Order/Disjoint.lean b/Mathlib/Order/Disjoint.lean index 29678782f984f..959e072e1b1b6 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₂⟩ diff --git a/Mathlib/Order/Estimator.lean b/Mathlib/Order/Estimator.lean index 6ce851d7cff48..29676a5330f47 100644 --- a/Mathlib/Order/Estimator.lean +++ b/Mathlib/Order/Estimator.lean @@ -1,9 +1,9 @@ /- -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.Defs +import Mathlib.Data.Set.Operations import Mathlib.Order.Heyting.Basic import Mathlib.Order.RelClasses import Mathlib.Order.Hom.Basic diff --git a/Mathlib/Order/Filter/AtTopBot.lean b/Mathlib/Order/Filter/AtTopBot.lean index 692f4d4c39e72..f393265bd856c 100644 --- a/Mathlib/Order/Filter/AtTopBot.lean +++ b/Mathlib/Order/Filter/AtTopBot.lean @@ -3,18 +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, 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.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 -import Mathlib.Algebra.Order.Field.Unbundled.Basic +import Mathlib.Order.Filter.Prod +import Mathlib.Order.Interval.Set.Disjoint /-! # `Filter.atTop` and `Filter.atBot` filters on preorders, monoids and groups. @@ -185,6 +178,12 @@ instance (priority := 200) atBot.isCountablyGenerated [Preorder α] [Countable (atBot : Filter <| α).IsCountablyGenerated := isCountablyGenerated_seq _ +instance _root_.OrderDual.instIsCountablyGeneratedAtTop [Preorder α] + [IsCountablyGenerated (atBot : Filter α)] : IsCountablyGenerated (atTop : Filter αᵒᵈ) := ‹_› + +instance _root_.OrderDual.instIsCountablyGeneratedAtBot [Preorder α] + [IsCountablyGenerated (atTop : Filter α)] : IsCountablyGenerated (atBot : Filter αᵒᵈ) := ‹_› + theorem _root_.IsTop.atTop_eq [Preorder α] {a : α} (ha : IsTop a) : atTop = 𝓟 (Ici a) := (iInf_le _ _).antisymm <| le_iInf fun b ↦ principal_mono.2 <| Ici_subset_Ici.2 <| ha b @@ -215,6 +214,19 @@ theorem tendsto_atBot_pure [PartialOrder α] [OrderBot α] (f : α → β) : Tendsto f atBot (pure <| f ⊥) := @tendsto_atTop_pure αᵒᵈ _ _ _ _ +theorem atTop_eq_generate_Ici [Preorder α] : atTop = generate (range (Ici (α := α))) := by + simp only [generate_eq_biInf, atTop, iInf_range] + +theorem Frequently.forall_exists_of_atTop [Preorder α] {p : α → Prop} + (h : ∃ᶠ x in atTop, p x) (a : α) : ∃ b ≥ a, p b := by + rw [Filter.Frequently] at h + contrapose! h + exact (eventually_ge_atTop a).mono h + +theorem Frequently.forall_exists_of_atBot [Preorder α] {p : α → Prop} + (h : ∃ᶠ x in atBot, p x) (a : α) : ∃ b ≤ a, p b := + Frequently.forall_exists_of_atTop (α := αᵒᵈ) h _ + section IsDirected variable [Preorder α] [IsDirected α (· ≤ ·)] {p : α → Prop} @@ -224,11 +236,6 @@ theorem hasAntitoneBasis_atTop [Nonempty α] : (@atTop α _).HasAntitoneBasis Ic theorem atTop_basis [Nonempty α] : (@atTop α _).HasBasis (fun _ => True) Ici := hasAntitoneBasis_atTop.1 -theorem atTop_eq_generate_Ici : atTop = generate (range (Ici (α := α))) := by - rcases isEmpty_or_nonempty α with hα|hα - · simp only [eq_iff_true_of_subsingleton] - · simp [(atTop_basis (α := α)).eq_generate, range] - lemma atTop_basis_Ioi [Nonempty α] [NoMaxOrder α] : (@atTop α _).HasBasis (fun _ => True) Ioi := atTop_basis.to_hasBasis (fun a ha => ⟨a, ha, Ioi_subset_Ici_self⟩) fun a ha => (exists_gt a).imp fun _b hb => ⟨ha, Ici_subset_Ioi.2 hb⟩ @@ -240,7 +247,7 @@ lemma atTop_basis_Ioi' [NoMaxOrder α] (a : α) : atTop.HasBasis (a < ·) Ioi := obtain ⟨d, hcd⟩ := exists_gt c exact ⟨d, hac.trans_lt hcd, Ioi_subset_Ioi (hbc.trans hcd.le)⟩ -theorem atTop_basis' (a : α) : (@atTop α _).HasBasis (fun x => a ≤ x) Ici := by +theorem atTop_basis' (a : α) : atTop.HasBasis (a ≤ ·) Ici := by have : Nonempty α := ⟨a⟩ refine atTop_basis.to_hasBasis (fun b _ ↦ ?_) fun b _ ↦ ⟨b, trivial, Subset.rfl⟩ obtain ⟨c, hac, hbc⟩ := exists_ge_ge a b @@ -251,8 +258,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 @@ -260,7 +276,6 @@ theorem frequently_atTop : (∃ᶠ x in atTop, p x) ↔ ∀ a, ∃ b ≥ a, p b atTop_basis.frequently_iff.trans <| by simp alias ⟨Eventually.exists_forall_of_atTop, _⟩ := eventually_atTop -alias ⟨Frequently.forall_exists_of_atTop, _⟩ := frequently_atTop lemma exists_eventually_atTop {r : α → β → Prop} : (∃ b, ∀ᶠ a in atTop, r a b) ↔ ∀ᶠ a₀ in atTop, ∃ b, ∀ a ≥ a₀, r a b := by @@ -305,13 +320,10 @@ lemma atBot_basis : (@atBot α _).HasBasis (fun _ => True) Iic := atTop_basis ( theorem frequently_atBot : (∃ᶠ x in atBot, p x) ↔ ∀ a, ∃ b ≤ a, p b := frequently_atTop (α := αᵒᵈ) alias ⟨Eventually.exists_forall_of_atBot, _⟩ := eventually_atBot -alias ⟨Frequently.forall_exists_of_atBot, _⟩ := frequently_atBot lemma exists_eventually_atBot {r : α → β → Prop} : - (∃ b, ∀ᶠ a in atBot, r a b) ↔ ∀ᶠ a₀ in atBot, ∃ b, ∀ a ≤ a₀, r a b := by - simp_rw [eventually_atBot, ← exists_swap (α := α)] - exact exists_congr fun a ↦ .symm <| forall_le_iff <| Antitone.exists fun _ _ _ hb H n hn ↦ - H n (hn.trans hb) + (∃ b, ∀ᶠ a in atBot, r a b) ↔ ∀ᶠ a₀ in atBot, ∃ b, ∀ a ≤ a₀, r a b := + exists_eventually_atTop (α := αᵒᵈ) theorem map_atBot_eq {f : α → β} : atBot.map f = ⨅ a, 𝓟 (f '' { a' | a' ≤ a }) := map_atTop_eq (α := αᵒᵈ) @@ -343,7 +355,7 @@ theorem tendsto_atBot_mono' [Preorder β] (l : Filter α) ⦃f₁ f₂ : α → theorem tendsto_atTop_mono [Preorder β] {l : Filter α} {f g : α → β} (h : ∀ n, f n ≤ g n) : Tendsto f l atTop → Tendsto g l atTop := - tendsto_atTop_mono' l <| eventually_of_forall h + tendsto_atTop_mono' l <| Eventually.of_forall h theorem tendsto_atBot_mono [Preorder β] {l : Filter α} {f g : α → β} (h : ∀ n, f n ≤ g n) : Tendsto g l atBot → Tendsto f l atBot := @@ -563,616 +575,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 [(· ∘ ·), 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 [(· ∘ ·), 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 => @@ -1322,10 +724,32 @@ theorem prod_atTop_atTop_eq [Preorder α] [Preorder β] : · subsingleton simpa [atTop, prod_iInf_left, prod_iInf_right, iInf_prod] using iInf_comm +instance instIsCountablyGeneratedAtTopProd [Preorder α] [IsCountablyGenerated (atTop : Filter α)] + [Preorder β] [IsCountablyGenerated (atTop : Filter β)] : + IsCountablyGenerated (atTop : Filter (α × β)) := by + rw [← prod_atTop_atTop_eq] + infer_instance + +lemma tendsto_finset_prod_atTop : + Tendsto (fun (p : Finset ι × Finset ι') ↦ p.1 ×ˢ p.2) atTop atTop := by + classical + apply Monotone.tendsto_atTop_atTop + · intro p q hpq + simpa using Finset.product_subset_product hpq.1 hpq.2 + · intro b + use (Finset.image Prod.fst b, Finset.image Prod.snd b) + exact Finset.subset_product + theorem prod_atBot_atBot_eq [Preorder α] [Preorder β] : (atBot : Filter α) ×ˢ (atBot : Filter β) = (atBot : Filter (α × β)) := @prod_atTop_atTop_eq αᵒᵈ βᵒᵈ _ _ +instance instIsCountablyGeneratedAtBotProd [Preorder α] [IsCountablyGenerated (atBot : Filter α)] + [Preorder β] [IsCountablyGenerated (atBot : Filter β)] : + IsCountablyGenerated (atBot : Filter (α × β)) := by + rw [← prod_atBot_atBot_eq] + infer_instance + theorem prod_map_atTop_eq {α₁ α₂ β₁ β₂ : Type*} [Preorder β₁] [Preorder β₂] (u₁ : β₁ → α₁) (u₂ : β₂ → α₂) : map u₁ atTop ×ˢ map u₂ atTop = map (Prod.map u₁ u₂) atTop := by rw [prod_map_map_eq, prod_atTop_atTop_eq, Prod.map_def] @@ -1398,132 +822,167 @@ theorem eventually_atBot_curry [Preorder α] [Preorder β] {p : α × β → Pro /-- A function `f` maps upwards closed sets (atTop sets) to upwards closed sets when it is a Galois insertion. The Galois "insertion" and "connection" is weakened to only require it to be an -insertion and a connection above `b'`. -/ -theorem map_atTop_eq_of_gc [SemilatticeSup α] [SemilatticeSup β] {f : α → β} (g : β → α) (b' : β) - (hf : Monotone f) (gc : ∀ a, ∀ b ≥ b', f a ≤ b ↔ a ≤ g b) (hgi : ∀ b ≥ b', b ≤ f (g b)) : - map f atTop = atTop := by - refine - le_antisymm - (hf.tendsto_atTop_atTop fun b => ⟨g (b ⊔ b'), le_sup_left.trans <| hgi _ le_sup_right⟩) ?_ - have : Nonempty α := ⟨g b'⟩ - rw [map_atTop_eq] - refine le_iInf fun a => iInf_le_of_le (f a ⊔ b') <| principal_mono.2 fun b hb => ?_ - rw [mem_Ici, sup_le_iff] at hb - exact ⟨g b, (gc _ _ hb.2).1 hb.1, le_antisymm ((gc _ _ hb.2).2 le_rfl) (hgi _ hb.2)⟩ - -theorem map_atBot_eq_of_gc [SemilatticeInf α] [SemilatticeInf β] {f : α → β} (g : β → α) (b' : β) +insertion and a connection above `b`. -/ +theorem map_atTop_eq_of_gc_preorder + [Preorder α] [IsDirected α (· ≤ ·)] [Preorder β] [IsDirected β (· ≤ ·)] {f : α → β} + (hf : Monotone f) (b : β) + (hgi : ∀ c ≥ b, ∃ x, f x = c ∧ ∀ a, f a ≤ c ↔ a ≤ x) : map f atTop = atTop := by + have : Nonempty α := (hgi b le_rfl).nonempty + choose! g hfg hgle using hgi + refine le_antisymm (hf.tendsto_atTop_atTop fun c ↦ ?_) ?_ + · rcases exists_ge_ge c b with ⟨d, hcd, hbd⟩ + exact ⟨g d, hcd.trans (hfg d hbd).ge⟩ + · have : Nonempty α := ⟨g b⟩ + rw [(atTop_basis.map f).ge_iff] + intro a _ + filter_upwards [eventually_ge_atTop (f a), eventually_ge_atTop b] with c hac hbc + exact ⟨g c, (hgle _ hbc _).1 hac, hfg _ hbc⟩ + + +/-- A function `f` maps upwards closed sets (atTop sets) to upwards closed sets when it is a +Galois insertion. The Galois "insertion" and "connection" is weakened to only require it to be an +insertion and a connection above `b`. -/ +theorem map_atTop_eq_of_gc + [Preorder α] [IsDirected α (· ≤ ·)] [PartialOrder β] [IsDirected β (· ≤ ·)] + {f : α → β} (g : β → α) (b : β) (hf : Monotone f) + (gc : ∀ a, ∀ c ≥ b, f a ≤ c ↔ a ≤ g c) (hgi : ∀ c ≥ b, c ≤ f (g c)) : + map f atTop = atTop := + map_atTop_eq_of_gc_preorder hf b fun c hc ↦ + ⟨g c, le_antisymm ((gc _ _ hc).2 le_rfl) (hgi c hc), (gc · c hc)⟩ + +theorem map_atBot_eq_of_gc_preorder + [Preorder α] [IsDirected α (· ≥ ·)] [Preorder β] [IsDirected β (· ≥ ·)] {f : α → β} + (hf : Monotone f) (b : β) + (hgi : ∀ c ≤ b, ∃ x, f x = c ∧ ∀ a, c ≤ f a ↔ x ≤ a) : map f atBot = atBot := + map_atTop_eq_of_gc_preorder (α := αᵒᵈ) (β := βᵒᵈ) hf.dual _ hgi + +theorem map_atBot_eq_of_gc [Preorder α] [IsDirected α (· ≥ ·)] + [PartialOrder β] [IsDirected β (· ≥ ·)] {f : α → β} (g : β → α) (b' : β) (hf : Monotone f) (gc : ∀ a, ∀ b ≤ b', b ≤ f a ↔ g b ≤ a) (hgi : ∀ b ≤ b', f (g b) ≤ b) : map f atBot = atBot := - @map_atTop_eq_of_gc αᵒᵈ βᵒᵈ _ _ _ _ _ hf.dual gc hgi - -theorem map_val_atTop_of_Ici_subset [SemilatticeSup α] {a : α} {s : Set α} (h : Ici a ⊆ s) : - map ((↑) : s → α) atTop = atTop := by - haveI : Nonempty s := ⟨⟨a, h le_rfl⟩⟩ - have : Directed (· ≥ ·) fun x : s => 𝓟 (Ici x) := fun x y ↦ by - use ⟨x ⊔ y ⊔ a, h le_sup_right⟩ - simp only [principal_mono, Ici_subset_Ici, ← Subtype.coe_le_coe, Subtype.coe_mk] - exact ⟨le_sup_left.trans le_sup_left, le_sup_right.trans le_sup_left⟩ - simp only [le_antisymm_iff, atTop, le_iInf_iff, le_principal_iff, mem_map, mem_setOf_eq, - map_iInf_eq this, map_principal] - constructor - · intro x - refine mem_of_superset (mem_iInf_of_mem ⟨x ⊔ a, h le_sup_right⟩ (mem_principal_self _)) ?_ - rintro _ ⟨y, hy, rfl⟩ - exact le_trans le_sup_left (Subtype.coe_le_coe.2 hy) - · intro x - filter_upwards [mem_atTop (↑x ⊔ a)] with b hb - exact ⟨⟨b, h <| le_sup_right.trans hb⟩, Subtype.coe_le_coe.1 (le_sup_left.trans hb), rfl⟩ + map_atTop_eq_of_gc (α := αᵒᵈ) (β := βᵒᵈ) _ _ hf.dual gc hgi + +theorem map_val_atTop_of_Ici_subset [Preorder α] [IsDirected α (· ≤ ·)] {a : α} {s : Set α} + (h : Ici a ⊆ s) : map ((↑) : s → α) atTop = atTop := by + choose f hl hr using exists_ge_ge (α := α) + have : DirectedOn (· ≤ ·) s := fun x _ y _ ↦ + ⟨f a (f x y), h <| hl _ _, (hl x y).trans (hr _ _), (hr x y).trans (hr _ _)⟩ + have : IsDirected s (· ≤ ·) := by + rw [directedOn_iff_directed] at this + rwa [← directed_id_iff] + refine map_atTop_eq_of_gc_preorder (Subtype.mono_coe _) a fun c hc ↦ ?_ + exact ⟨⟨c, h hc⟩, rfl, fun _ ↦ .rfl⟩ + +@[simp] +theorem _root_.Nat.map_cast_int_atTop : map ((↑) : ℕ → ℤ) atTop = atTop := by + refine map_atTop_eq_of_gc_preorder (fun _ _ ↦ Int.ofNat_le.2) 0 fun n hn ↦ ?_ + lift n to ℕ using hn + exact ⟨n, rfl, fun _ ↦ Int.ofNat_le⟩ /-- The image of the filter `atTop` on `Ici a` under the coercion equals `atTop`. -/ @[simp] -theorem map_val_Ici_atTop [SemilatticeSup α] (a : α) : map ((↑) : Ici a → α) atTop = atTop := - map_val_atTop_of_Ici_subset (Subset.refl _) +theorem map_val_Ici_atTop [Preorder α] [IsDirected α (· ≤ ·)] (a : α) : + map ((↑) : Ici a → α) atTop = atTop := + map_val_atTop_of_Ici_subset Subset.rfl /-- The image of the filter `atTop` on `Ioi a` under the coercion equals `atTop`. -/ @[simp] -theorem map_val_Ioi_atTop [SemilatticeSup α] [NoMaxOrder α] (a : α) : +theorem map_val_Ioi_atTop [Preorder α] [IsDirected α (· ≤ ·)] [NoMaxOrder α] (a : α) : map ((↑) : Ioi a → α) atTop = atTop := let ⟨_b, hb⟩ := exists_gt a map_val_atTop_of_Ici_subset <| Ici_subset_Ioi.2 hb /-- The `atTop` filter for an open interval `Ioi a` comes from the `atTop` filter in the ambient order. -/ -theorem atTop_Ioi_eq [SemilatticeSup α] (a : α) : atTop = comap ((↑) : Ioi a → α) atTop := by +theorem atTop_Ioi_eq [Preorder α] [IsDirected α (· ≤ ·)] (a : α) : + atTop = comap ((↑) : Ioi a → α) atTop := by rcases isEmpty_or_nonempty (Ioi a) with h|⟨⟨b, hb⟩⟩ · subsingleton · rw [← map_val_atTop_of_Ici_subset (Ici_subset_Ioi.2 hb), comap_map Subtype.coe_injective] /-- The `atTop` filter for an open interval `Ici a` comes from the `atTop` filter in the ambient order. -/ -theorem atTop_Ici_eq [SemilatticeSup α] (a : α) : atTop = comap ((↑) : Ici a → α) atTop := by +theorem atTop_Ici_eq [Preorder α] [IsDirected α (· ≤ ·)] (a : α) : + atTop = comap ((↑) : Ici a → α) atTop := by rw [← map_val_Ici_atTop a, comap_map Subtype.coe_injective] /-- The `atBot` filter for an open interval `Iio a` comes from the `atBot` filter in the ambient order. -/ @[simp] -theorem map_val_Iio_atBot [SemilatticeInf α] [NoMinOrder α] (a : α) : +theorem map_val_Iio_atBot [Preorder α] [IsDirected α (· ≥ ·)] [NoMinOrder α] (a : α) : map ((↑) : Iio a → α) atBot = atBot := - @map_val_Ioi_atTop αᵒᵈ _ _ _ + map_val_Ioi_atTop (OrderDual.toDual a) /-- The `atBot` filter for an open interval `Iio a` comes from the `atBot` filter in the ambient order. -/ -theorem atBot_Iio_eq [SemilatticeInf α] (a : α) : atBot = comap ((↑) : Iio a → α) atBot := - @atTop_Ioi_eq αᵒᵈ _ _ +theorem atBot_Iio_eq [Preorder α] [IsDirected α (· ≥ ·)] (a : α) : + atBot = comap ((↑) : Iio a → α) atBot := + atTop_Ioi_eq (OrderDual.toDual a) /-- The `atBot` filter for an open interval `Iic a` comes from the `atBot` filter in the ambient order. -/ @[simp] -theorem map_val_Iic_atBot [SemilatticeInf α] (a : α) : map ((↑) : Iic a → α) atBot = atBot := - @map_val_Ici_atTop αᵒᵈ _ _ +theorem map_val_Iic_atBot [Preorder α] [IsDirected α (· ≥ ·)] (a : α) : + map ((↑) : Iic a → α) atBot = atBot := + map_val_Ici_atTop (OrderDual.toDual a) /-- The `atBot` filter for an open interval `Iic a` comes from the `atBot` filter in the ambient order. -/ -theorem atBot_Iic_eq [SemilatticeInf α] (a : α) : atBot = comap ((↑) : Iic a → α) atBot := - @atTop_Ici_eq αᵒᵈ _ _ +theorem atBot_Iic_eq [Preorder α] [IsDirected α (· ≥ ·)] (a : α) : + atBot = comap ((↑) : Iic a → α) atBot := + atTop_Ici_eq (OrderDual.toDual a) -theorem tendsto_Ioi_atTop [SemilatticeSup α] {a : α} {f : β → Ioi a} {l : Filter β} : +theorem tendsto_Ioi_atTop [Preorder α] [IsDirected α (· ≤ ·)] + {a : α} {f : β → Ioi a} {l : Filter β} : Tendsto f l atTop ↔ Tendsto (fun x => (f x : α)) l atTop := by rw [atTop_Ioi_eq, tendsto_comap_iff, Function.comp_def] -theorem tendsto_Iio_atBot [SemilatticeInf α] {a : α} {f : β → Iio a} {l : Filter β} : - Tendsto f l atBot ↔ Tendsto (fun x => (f x : α)) l atBot := by - rw [atBot_Iio_eq, tendsto_comap_iff, Function.comp_def] +theorem tendsto_Iio_atBot [Preorder α] [IsDirected α (· ≥ ·)] + {a : α} {f : β → Iio a} {l : Filter β} : + Tendsto f l atBot ↔ Tendsto (fun x => (f x : α)) l atBot := + tendsto_Ioi_atTop (α := αᵒᵈ) -theorem tendsto_Ici_atTop [SemilatticeSup α] {a : α} {f : β → Ici a} {l : Filter β} : +theorem tendsto_Ici_atTop [Preorder α] [IsDirected α (· ≤ ·)] + {a : α} {f : β → Ici a} {l : Filter β} : Tendsto f l atTop ↔ Tendsto (fun x => (f x : α)) l atTop := by rw [atTop_Ici_eq, tendsto_comap_iff, Function.comp_def] -theorem tendsto_Iic_atBot [SemilatticeInf α] {a : α} {f : β → Iic a} {l : Filter β} : - Tendsto f l atBot ↔ Tendsto (fun x => (f x : α)) l atBot := by - rw [atBot_Iic_eq, tendsto_comap_iff, Function.comp_def] +theorem tendsto_Iic_atBot [Preorder α] [IsDirected α (· ≥ ·)] + {a : α} {f : β → Iic a} {l : Filter β} : + Tendsto f l atBot ↔ Tendsto (fun x => (f x : α)) l atBot := + tendsto_Ici_atTop (α := αᵒᵈ) -@[simp, nolint simpNF] -- Porting note: linter claims that LHS doesn't simplify. It does. -theorem tendsto_comp_val_Ioi_atTop [SemilatticeSup α] [NoMaxOrder α] {a : α} {f : α → β} - {l : Filter β} : Tendsto (fun x : Ioi a => f x) atTop l ↔ Tendsto f atTop l := by +@[simp] +theorem tendsto_comp_val_Ioi_atTop [Preorder α] [IsDirected α (· ≤ ·)] [NoMaxOrder α] + {a : α} {f : α → β} {l : Filter β} : + Tendsto (fun x : Ioi a => f x) atTop l ↔ Tendsto f atTop l := by rw [← map_val_Ioi_atTop a, tendsto_map'_iff, Function.comp_def] -@[simp, nolint simpNF] -- Porting note: linter claims that LHS doesn't simplify. It does. -theorem tendsto_comp_val_Ici_atTop [SemilatticeSup α] {a : α} {f : α → β} {l : Filter β} : +@[simp] +theorem tendsto_comp_val_Ici_atTop [Preorder α] [IsDirected α (· ≤ ·)] + {a : α} {f : α → β} {l : Filter β} : Tendsto (fun x : Ici a => f x) atTop l ↔ Tendsto f atTop l := by rw [← map_val_Ici_atTop a, tendsto_map'_iff, Function.comp_def] -@[simp, nolint simpNF] -- Porting note: linter claims that LHS doesn't simplify. It does. -theorem tendsto_comp_val_Iio_atBot [SemilatticeInf α] [NoMinOrder α] {a : α} {f : α → β} - {l : Filter β} : Tendsto (fun x : Iio a => f x) atBot l ↔ Tendsto f atBot l := by - rw [← map_val_Iio_atBot a, tendsto_map'_iff, Function.comp_def] +@[simp] +theorem tendsto_comp_val_Iio_atBot [Preorder α] [IsDirected α (· ≥ ·)] [NoMinOrder α] + {a : α} {f : α → β} {l : Filter β} : + Tendsto (fun x : Iio a => f x) atBot l ↔ Tendsto f atBot l := + tendsto_comp_val_Ioi_atTop (α := αᵒᵈ) -@[simp, nolint simpNF] -- Porting note: linter claims that LHS doesn't simplify. It does. -theorem tendsto_comp_val_Iic_atBot [SemilatticeInf α] {a : α} {f : α → β} {l : Filter β} : - Tendsto (fun x : Iic a => f x) atBot l ↔ Tendsto f atBot l := by - rw [← map_val_Iic_atBot a, tendsto_map'_iff, Function.comp_def] +@[simp] +theorem tendsto_comp_val_Iic_atBot [Preorder α] [IsDirected α (· ≥ ·)] + {a : α} {f : α → β} {l : Filter β} : + Tendsto (fun x : Iic a => f x) atBot l ↔ Tendsto f atBot l := + tendsto_comp_val_Ici_atTop (α := αᵒᵈ) theorem map_add_atTop_eq_nat (k : ℕ) : map (fun a => a + k) atTop = atTop := - map_atTop_eq_of_gc (fun a => a - 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 a b h => Nat.add_le_add_right h k) + (fun a b h => (Nat.le_sub_iff_add_le h).symm) fun a h => by rw [Nat.sub_add_cancel h] theorem map_sub_atTop_eq_nat (k : ℕ) : map (fun a => a - k) atTop = atTop := - map_atTop_eq_of_gc (fun a => a + 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 a b h => Nat.sub_le_sub_right h _) + (fun a b _ => Nat.sub_le_iff_le_add) fun b _ => by rw [Nat.add_sub_cancel_right] theorem tendsto_add_atTop_nat (k : ℕ) : Tendsto (fun a => a + k) atTop atTop := le_of_eq (map_add_atTop_eq_nat k) @@ -1537,14 +996,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 a b 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`. -/ @@ -1611,25 +1066,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 @@ -1674,21 +1110,25 @@ theorem exists_seq_tendsto (f : Filter α) [IsCountablyGenerated f] [NeBot f] : choose x hx using fun n => Filter.nonempty_of_mem (h.mem n) exact ⟨x, h.tendsto hx⟩ -theorem exists_seq_monotone_tendsto_atTop_atTop (α : Type*) [SemilatticeSup α] [Nonempty α] - [(atTop : Filter α).IsCountablyGenerated] : +theorem exists_seq_monotone_tendsto_atTop_atTop (α : Type*) [Preorder α] [Nonempty α] + [IsDirected α (· ≤ ·)] [(atTop : Filter α).IsCountablyGenerated] : ∃ xs : ℕ → α, Monotone xs ∧ Tendsto xs atTop atTop := by obtain ⟨ys, h⟩ := exists_seq_tendsto (atTop : Filter α) - let xs : ℕ → α := fun n => Finset.sup' (Finset.range (n + 1)) Finset.nonempty_range_succ ys - have h_mono : Monotone xs := fun i j hij ↦ by - simp only [xs] -- Need to unfold `xs` and do alpha reduction, otherwise `gcongr` fails - gcongr - refine ⟨xs, h_mono, tendsto_atTop_mono (fun n ↦ Finset.le_sup' _ ?_) h⟩ - simp - -theorem exists_seq_antitone_tendsto_atTop_atBot (α : Type*) [SemilatticeInf α] [Nonempty α] - [h2 : (atBot : Filter α).IsCountablyGenerated] : + choose c hleft hright using exists_ge_ge (α := α) + set xs : ℕ → α := fun n => (List.range n).foldl (fun x n ↦ c x (ys n)) (ys 0) + have hsucc (n : ℕ) : xs (n + 1) = c (xs n) (ys n) := by simp [xs, List.range_succ] + refine ⟨xs, ?_, ?_⟩ + · refine monotone_nat_of_le_succ fun n ↦ ?_ + rw [hsucc] + apply hleft + · refine (tendsto_add_atTop_iff_nat 1).1 <| tendsto_atTop_mono (fun n ↦ ?_) h + rw [hsucc] + apply hright + +theorem exists_seq_antitone_tendsto_atTop_atBot (α : Type*) [Preorder α] [Nonempty α] + [IsDirected α (· ≥ ·)] [(atBot : Filter α).IsCountablyGenerated] : ∃ xs : ℕ → α, Antitone xs ∧ Tendsto xs atTop atBot := - @exists_seq_monotone_tendsto_atTop_atTop αᵒᵈ _ _ h2 + exists_seq_monotone_tendsto_atTop_atTop αᵒᵈ /-- An abstract version of continuity of sequentially continuous functions on metric spaces: if a filter `k` is countably generated then `Tendsto f k l` iff for every sequence `u` @@ -1737,7 +1177,7 @@ lemma frequently_iff_seq_forall {ι : Type*} {l : Filter ι} {p : ι → Prop} [l.IsCountablyGenerated] : (∃ᶠ n in l, p n) ↔ ∃ ns : ℕ → ι, Tendsto ns atTop l ∧ ∀ n, p (ns n) := ⟨exists_seq_forall_of_frequently, fun ⟨_ns, hnsl, hpns⟩ ↦ - hnsl.frequently <| frequently_of_forall hpns⟩ + hnsl.frequently <| Frequently.of_forall hpns⟩ /-- A sequence converges if every subsequence has a convergent subsequence. -/ theorem tendsto_of_subseq_tendsto {ι : Type*} {x : ι → α} {f : Filter α} {l : Filter ι} @@ -1766,21 +1206,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 : α) : @@ -1801,34 +1226,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 +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 82% rename from Mathlib/Order/Filter/ModEq.lean rename to Mathlib/Order/Filter/AtTopBot/ModEq.lean index 5014ac919f8fd..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 @@ -21,7 +24,7 @@ namespace Nat /-- Infinitely many natural numbers are equal to `d` mod `n`. -/ theorem frequently_modEq {n : ℕ} (h : n ≠ 0) (d : ℕ) : ∃ᶠ m in atTop, m ≡ d [MOD n] := ((tendsto_add_atTop_nat d).comp (tendsto_id.nsmul_atTop h.bot_lt)).frequently <| - frequently_of_forall fun m => by simp [Nat.modEq_iff_dvd, ← sub_sub] + Frequently.of_forall fun m => by simp [Nat.modEq_iff_dvd, ← sub_sub] theorem frequently_mod_eq {d n : ℕ} (h : d < n) : ∃ᶠ m in atTop, m % n = d := by simpa only [Nat.ModEq, mod_eq_of_lt h] using frequently_modEq h.ne_bot d 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 dee2d71c9f043..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 @@ -100,7 +99,7 @@ instance FilterBasis.nonempty_sets (B : FilterBasis α) : Nonempty B.sets := /-- If `B` is a filter basis on `α`, and `U` a subset of `α` then we can write `U ∈ B` as on paper. -/ instance {α : Type*} : Membership (Set α) (FilterBasis α) := - ⟨fun U B => U ∈ B.sets⟩ + ⟨fun B U => U ∈ B.sets⟩ @[simp] theorem FilterBasis.mem_sets {s : Set α} {B : FilterBasis α} : s ∈ B.sets ↔ s ∈ B := Iff.rfl @@ -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,10 +663,10 @@ 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)`. -/ +of `⨅ i, 𝓟 (s i)`. -/ theorem hasBasis_iInf_principal_finite {ι : Type*} (s : ι → Set α) : (⨅ i, 𝓟 (s i)).HasBasis (fun t : Set ι => t.Finite) fun t => ⋂ i ∈ t, s i := by refine ⟨fun U => (mem_iInf_finite _).trans ?_⟩ @@ -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 a4e53468a767d..85fed348f7035 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 @@ -82,65 +73,26 @@ 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 U F => 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] - /-- 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₁ -theorem inter_mem {s t : Set α} (hs : s ∈ f) (ht : t ∈ f) : s ∩ t ∈ f := - f.inter_sets hs ht +instance : Trans Membership.mem (· ⊆ ·) (Membership.mem : Filter α → Set α → Prop) where + trans h₁ h₂ := mem_of_superset h₁ h₂ @[simp] theorem inter_mem_iff {s t : Set α} : s ∩ t ∈ f ↔ s ∈ f ∧ t ∈ f := @@ -150,27 +102,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 := @@ -214,100 +151,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`. -/ @@ -375,23 +229,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 @@ -414,19 +251,6 @@ 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, @@ -449,16 +273,6 @@ 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 @@ -503,10 +317,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 @@ -520,7 +330,7 @@ theorem mem_sSup {x : Set α} {s : Set (Filter α)} : x ∈ sSup s ↔ ∀ f ∈ @[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 @@ -533,20 +343,21 @@ theorem mem_iInf_of_mem {f : ι → Filter α} (i : ι) {s} (hs : s ∈ f i) : s iInf_le f i hs theorem mem_iInf_of_iInter {ι} {s : ι → Filter α} {U : Set α} {I : Set ι} (I_fin : I.Finite) - {V : I → Set α} (hV : ∀ i, V i ∈ s i) (hU : ⋂ i, V i ⊆ U) : U ∈ ⨅ i, s i := by + {V : I → Set α} (hV : ∀ (i : I), V i ∈ s i) (hU : ⋂ i, V i ⊆ U) : U ∈ ⨅ i, s i := by haveI := I_fin.fintype refine mem_of_superset (iInter_mem.2 fun i => ?_) hU exact mem_iInf_of_mem (i : ι) (hV _) theorem mem_iInf {ι} {s : ι → Filter α} {U : Set α} : - (U ∈ ⨅ i, s i) ↔ ∃ I : Set ι, I.Finite ∧ ∃ V : I → Set α, (∀ i, V i ∈ s i) ∧ U = ⋂ i, V i := by + (U ∈ ⨅ i, s i) ↔ + ∃ I : Set ι, I.Finite ∧ ∃ V : I → Set α, (∀ (i : I), V i ∈ s i) ∧ U = ⋂ i, V i := by constructor · rw [iInf_eq_generate, mem_generate_iff] rintro ⟨t, tsub, tfin, tinter⟩ rcases eq_finite_iUnion_of_finite_subset_iUnion tfin tsub with ⟨I, Ifin, σ, σfin, σsub, rfl⟩ rw [sInter_iUnion] at tinter set V := fun i => U ∪ ⋂₀ σ i with hV - have V_in : ∀ i, V i ∈ s i := by + have V_in : ∀ (i : I), V i ∈ s i := by rintro i have : ⋂₀ σ i ∈ s i := by rw [sInter_mem (σfin _)] @@ -568,10 +379,10 @@ theorem mem_iInf' {ι} {s : ι → Filter α} {U : Set α} : refine ⟨I, If, fun i => if hi : i ∈ I then V ⟨i, hi⟩ else univ, fun i => ?_, fun i hi => ?_, ?_⟩ · dsimp only split_ifs - exacts [hV _, univ_mem] + 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 := @@ -591,7 +402,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 @@ -707,7 +518,7 @@ theorem eq_sInf_of_mem_iff_exists_mem {S : Set (Filter α)} {l : Filter α} theorem eq_iInf_of_mem_iff_exists_mem {f : ι → Filter α} {l : Filter α} (h : ∀ {s}, s ∈ l ↔ ∃ i, s ∈ f i) : l = iInf f := - eq_sInf_of_mem_iff_exists_mem <| h.trans exists_range_iff.symm + eq_sInf_of_mem_iff_exists_mem <| h.trans (exists_range_iff (p := (_ ∈ ·))).symm theorem eq_biInf_of_mem_iff_exists_mem {f : ι → Filter α} {p : ι → Prop} {l : Filter α} (h : ∀ {s}, s ∈ l ↔ ∃ i, p i ∧ s ∈ f i) : l = ⨅ (i) (_ : p i), f i := by @@ -781,7 +592,8 @@ 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 @@ -945,14 +757,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 @@ -978,9 +782,11 @@ protected theorem Eventually.and {p q : α → Prop} {f : Filter α} : @[simp] theorem eventually_true (f : Filter α) : ∀ᶠ _ in f, True := univ_mem -theorem eventually_of_forall {p : α → Prop} {f : Filter α} (hp : ∀ x, p x) : ∀ᶠ x in f, p x := +theorem Eventually.of_forall {p : α → Prop} {f : Filter α} (hp : ∀ x, p x) : ∀ᶠ x in f, p x := univ_mem' hp +@[deprecated (since := "2024-08-02")] alias eventually_of_forall := Eventually.of_forall + @[simp] theorem eventually_false_iff_eq_bot {f : Filter α} : (∀ᶠ _ in f, False) ↔ f = ⊥ := empty_mem_iff_bot @@ -1003,7 +809,7 @@ theorem Eventually.mp {p q : α → Prop} {f : Filter α} (hp : ∀ᶠ x in f, p theorem Eventually.mono {p q : α → Prop} {f : Filter α} (hp : ∀ᶠ x in f, p x) (hq : ∀ x, p x → q x) : ∀ᶠ x in f, q x := - hp.mp (eventually_of_forall hq) + hp.mp (Eventually.of_forall hq) theorem forall_eventually_of_eventually_forall {f : Filter α} {p : α → β → Prop} (h : ∀ᶠ x in f, ∀ y, p x y) : ∀ y, ∀ᶠ x in f, p x y := @@ -1099,21 +905,15 @@ 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 -theorem frequently_of_forall {f : Filter α} [NeBot f] {p : α → Prop} (h : ∀ x, p x) : +theorem Frequently.of_forall {f : Filter α} [NeBot f] {p : α → Prop} (h : ∀ x, p x) : ∃ᶠ x in f, p x := - Eventually.frequently (eventually_of_forall h) + Eventually.frequently (Eventually.of_forall h) + +@[deprecated (since := "2024-08-02")] alias frequently_of_forall := Frequently.of_forall theorem Frequently.mp {p q : α → Prop} {f : Filter α} (h : ∃ᶠ x in f, p x) (hpq : ∀ᶠ x in f, p x → q x) : ∃ᶠ x in f, q x := @@ -1125,7 +925,7 @@ theorem Frequently.filter_mono {p : α → Prop} {f g : Filter α} (h : ∃ᶠ x theorem Frequently.mono {p q : α → Prop} {f : Filter α} (h : ∃ᶠ x in f, p x) (hpq : ∀ x, p x → q x) : ∃ᶠ x in f, q x := - h.mp (eventually_of_forall hpq) + h.mp (Eventually.of_forall hpq) theorem Frequently.and_eventually {p q : α → Prop} {f : Filter α} (hp : ∃ᶠ x in f, p x) (hq : ∀ᶠ x in f, q x) : ∃ᶠ x in f, p x ∧ q x := by @@ -1138,7 +938,7 @@ theorem Eventually.and_frequently {p q : α → Prop} {f : Filter α} (hp : ∀ theorem Frequently.exists {p : α → Prop} {f : Filter α} (hp : ∃ᶠ x in f, p x) : ∃ x, p x := by by_contra H - replace H : ∀ᶠ x in f, ¬p x := eventually_of_forall (not_exists.1 H) + replace H : ∀ᶠ x in f, ¬p x := Eventually.of_forall (not_exists.1 H) exact hp H theorem Eventually.exists {p : α → Prop} {f : Filter α} [NeBot f] (hp : ∀ᶠ x in f, p x) : @@ -1257,24 +1057,19 @@ 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) := hf.congr <| h.mono fun _ hx => hx ▸ Iff.rfl theorem eventuallyEq_set {s t : Set α} {l : Filter α} : s =ᶠ[l] t ↔ ∀ᶠ x in l, x ∈ s ↔ x ∈ t := - eventually_congr <| eventually_of_forall fun _ ↦ eq_iff_iff + eventually_congr <| Eventually.of_forall fun _ ↦ eq_iff_iff alias ⟨EventuallyEq.mem_iff, Eventually.set_eq⟩ := eventuallyEq_set @@ -1300,15 +1095,20 @@ theorem EventuallyEq.filter_mono {l l' : Filter α} {f g : α → β} (h₁ : f @[refl, simp] theorem EventuallyEq.refl (l : Filter α) (f : α → β) : f =ᶠ[l] f := - eventually_of_forall fun _ => rfl + Eventually.of_forall fun _ => rfl protected theorem EventuallyEq.rfl {l : Filter α} {f : α → β} : f =ᶠ[l] f := EventuallyEq.refl l f +theorem EventuallyEq.of_eq {l : Filter α} {f g : α → β} (h : f = g) : f =ᶠ[l] g := h ▸ .rfl +alias _root_.Eq.eventuallyEq := EventuallyEq.of_eq + @[symm] theorem EventuallyEq.symm {f g : α → β} {l : Filter α} (H : f =ᶠ[l] g) : g =ᶠ[l] f := H.mono fun _ => Eq.symm +lemma eventuallyEq_comm {f g : α → β} {l : Filter α} : f =ᶠ[l] g ↔ g =ᶠ[l] f := ⟨.symm, .symm⟩ + @[trans] theorem EventuallyEq.trans {l : Filter α} {f g h : α → β} (H₁ : f =ᶠ[l] g) (H₂ : g =ᶠ[l] h) : f =ᶠ[l] h := @@ -1432,13 +1232,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 @@ -1606,7 +1399,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 @@ -1631,17 +1424,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 @@ -1706,20 +1494,6 @@ 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 := @@ -1790,37 +1564,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 @@ -2258,13 +2001,6 @@ theorem comap_eval_neBot {ι : Type*} {α : ι → Type*} [∀ j, Nonempty (α j (f : Filter (α i)) [NeBot f] : (comap (eval i) f).NeBot := comap_eval_neBot_iff.2 ‹_› -theorem comap_inf_principal_neBot_of_image_mem {f : Filter β} {m : α → β} (hf : NeBot f) {s : Set α} - (hs : m '' s ∈ f) : NeBot (comap m f ⊓ 𝓟 s) := by - refine ⟨compl_compl s ▸ mt mem_of_eq_bot ?_⟩ - rintro ⟨t, ht, hts⟩ - rcases hf.nonempty_of_mem (inter_mem hs ht) with ⟨_, ⟨x, hxs, rfl⟩, hxt⟩ - exact absurd hxs (hts hxt) - theorem comap_coe_neBot_of_le_principal {s : Set γ} {l : Filter γ} [h : NeBot l] (h' : l ≤ 𝓟 s) : NeBot (comap ((↑) : s → γ) l) := h.comap_of_range_mem <| (@Subtype.range_coe γ s).symm ▸ h' (mem_principal_self s) @@ -2396,6 +2132,27 @@ protected theorem push_pull (f : α → β) (F : Filter α) (G : Filter β) : protected theorem push_pull' (f : α → β) (F : Filter α) (G : Filter β) : map f (comap f G ⊓ F) = G ⊓ map f F := by simp only [Filter.push_pull, inf_comm] +theorem disjoint_comap_iff_map {f : α → β} {F : Filter α} {G : Filter β} : + Disjoint F (comap f G) ↔ Disjoint (map f F) G := by + simp only [disjoint_iff, ← Filter.push_pull, map_eq_bot_iff] + +theorem disjoint_comap_iff_map' {f : α → β} {F : Filter α} {G : Filter β} : + Disjoint (comap f G) F ↔ Disjoint G (map f F) := by + simp only [disjoint_iff, ← Filter.push_pull', map_eq_bot_iff] + +theorem neBot_inf_comap_iff_map {f : α → β} {F : Filter α} {G : Filter β} : + NeBot (F ⊓ comap f G) ↔ NeBot (map f F ⊓ G) := by + rw [← map_neBot_iff, Filter.push_pull] + +theorem neBot_inf_comap_iff_map' {f : α → β} {F : Filter α} {G : Filter β} : + NeBot (comap f G ⊓ F) ↔ NeBot (G ⊓ map f F) := by + rw [← map_neBot_iff, Filter.push_pull'] + +theorem comap_inf_principal_neBot_of_image_mem {f : Filter β} {m : α → β} (hf : NeBot f) {s : Set α} + (hs : m '' s ∈ f) : NeBot (comap m f ⊓ 𝓟 s) := by + rw [neBot_inf_comap_iff_map', map_principal, ← frequently_mem_iff_neBot] + exact Eventually.frequently hs + theorem principal_eq_map_coe_top (s : Set α) : 𝓟 s = map ((↑) : s → α) ⊤ := by simp theorem inf_principal_eq_bot_iff_comap {F : Filter α} {s : Set α} : @@ -2423,7 +2180,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 := @@ -2563,12 +2320,6 @@ 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 @@ -2605,6 +2356,12 @@ theorem Tendsto.frequently_map {l₁ : Filter α} {l₂ : Filter β} {p : α → @[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 β} @@ -2713,7 +2470,7 @@ theorem map_eq_of_inverse {f : Filter α} {g : Filter β} {φ : α → β} (ψ : 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] + 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 := @@ -2730,7 +2487,7 @@ theorem Tendsto.inf {f : α → β} {x₁ x₂ : Filter α} {y₁ y₂ : Filter @[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] + 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 := @@ -2830,7 +2587,7 @@ theorem Set.EqOn.eventuallyEq_of_mem {α β} {s : Set α} {l : Filter α} {f g : h.eventuallyEq.filter_mono <| Filter.le_principal_iff.2 hl theorem HasSubset.Subset.eventuallyLE {α} {l : Filter α} {s t : Set α} (h : s ⊆ t) : s ≤ᶠ[l] t := - Filter.eventually_of_forall h + Filter.Eventually.of_forall h theorem Set.MapsTo.tendsto {α β} {s : Set α} {t : Set β} {f : α → β} (h : MapsTo f s t) : Filter.Tendsto f (𝓟 s) (𝓟 t) := @@ -2882,23 +2639,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 diff --git a/Mathlib/Order/Filter/CardinalInter.lean b/Mathlib/Order/Filter/CardinalInter.lean index 7462de92c6dd8..def8ba80b0a80 100644 --- a/Mathlib/Order/Filter/CardinalInter.lean +++ b/Mathlib/Order/Filter/CardinalInter.lean @@ -5,7 +5,7 @@ Authors: Josha Dekker -/ import Mathlib.Order.Filter.Basic import Mathlib.Order.Filter.CountableInter -import Mathlib.SetTheory.Cardinal.Ordinal +import Mathlib.SetTheory.Cardinal.Arithmetic import Mathlib.SetTheory.Cardinal.Cofinality /-! @@ -300,16 +300,19 @@ theorem mem_cardinaleGenerate_iff {s : Set α} {hreg : c.IsRegular} : s ∈ cardinalGenerate g (IsRegular.nat_lt hreg 2) ↔ ∃ S : Set (Set α), S ⊆ g ∧ (#S < c) ∧ ⋂₀ S ⊆ s := by constructor <;> intro h - · induction' h with s hs s t _ st ih S Sct _ ih - · refine ⟨{s}, singleton_subset_iff.mpr hs, ?_⟩ + · induction h with + | @basic s hs => + refine ⟨{s}, singleton_subset_iff.mpr hs, ?_⟩ simpa [subset_refl] using IsRegular.nat_lt hreg 1 - · exact ⟨∅, ⟨empty_subset g, mk_eq_zero (∅ : Set <| Set α) ▸ IsRegular.nat_lt hreg 0, by simp⟩⟩ - · exact Exists.imp (by tauto) ih - choose T Tg Tct hT using ih - refine ⟨⋃ (s) (H : s ∈ S), T s H, by simpa, - (Cardinal.card_biUnion_lt_iff_forall_of_isRegular hreg Sct).2 Tct, ?_⟩ - apply subset_sInter - apply fun s H => subset_trans (sInter_subset_sInter (subset_iUnion₂ s H)) (hT s H) + | univ => + exact ⟨∅, ⟨empty_subset g, mk_eq_zero (∅ : Set <| Set α) ▸ IsRegular.nat_lt hreg 0, by simp⟩⟩ + | superset _ _ ih => exact Exists.imp (by tauto) ih + | @sInter S Sct _ ih => + choose T Tg Tct hT using ih + refine ⟨⋃ (s) (H : s ∈ S), T s H, by simpa, + (Cardinal.card_biUnion_lt_iff_forall_of_isRegular hreg Sct).2 Tct, ?_⟩ + apply subset_sInter + apply fun s H => subset_trans (sInter_subset_sInter (subset_iUnion₂ s H)) (hT s H) rcases h with ⟨S, Sg, Sct, hS⟩ have : CardinalInterFilter (cardinalGenerate g (IsRegular.nat_lt hreg 2)) c := cardinalInter_ofCardinalGenerate _ _ diff --git a/Mathlib/Order/Filter/Cocardinal.lean b/Mathlib/Order/Filter/Cocardinal.lean index ede785eb18061..b0fed85fce86e 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 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 ea7172ae2ea14..b9d5d1ef60f8d 100644 --- a/Mathlib/Order/Filter/CountableInter.lean +++ b/Mathlib/Order/Filter/CountableInter.lean @@ -242,16 +242,16 @@ it contains a countable intersection of elements of `g`. -/ theorem mem_countableGenerate_iff {s : Set α} : s ∈ countableGenerate g ↔ ∃ S : Set (Set α), S ⊆ g ∧ S.Countable ∧ ⋂₀ S ⊆ s := by constructor <;> intro h - · induction' h with s hs s t _ st ih S Sct _ ih - · exact ⟨{s}, by simp [hs, subset_refl]⟩ - · exact ⟨∅, by simp⟩ - · refine Exists.imp (fun S => ?_) ih - tauto - choose T Tg Tct hT using ih - refine ⟨⋃ (s) (H : s ∈ S), T s H, by simpa, Sct.biUnion Tct, ?_⟩ - apply subset_sInter - intro s H - exact subset_trans (sInter_subset_sInter (subset_iUnion₂ s H)) (hT s H) + · induction h with + | @basic s hs => exact ⟨{s}, by simp [hs, subset_refl]⟩ + | univ => exact ⟨∅, by simp⟩ + | superset _ _ ih => refine Exists.imp (fun S => ?_) ih; tauto + | @sInter S Sct _ ih => + choose T Tg Tct hT using ih + refine ⟨⋃ (s) (H : s ∈ S), T s H, by simpa, Sct.biUnion Tct, ?_⟩ + apply subset_sInter + intro s H + exact subset_trans (sInter_subset_sInter (subset_iUnion₂ s H)) (hT s H) rcases h with ⟨S, Sg, Sct, hS⟩ refine mem_of_superset ((countable_sInter_mem Sct).mpr ?_) hS intro s H @@ -262,11 +262,11 @@ theorem le_countableGenerate_iff_of_countableInterFilter {f : Filter α} [Counta constructor <;> intro h · exact subset_trans (fun s => CountableGenerateSets.basic) h intro s hs - induction' hs with s hs s t _ st ih S Sct _ ih - · exact h hs - · exact univ_mem - · exact mem_of_superset ih st - exact (countable_sInter_mem Sct).mpr ih + induction hs with + | basic hs => exact h hs + | univ => exact univ_mem + | superset _ st ih => exact mem_of_superset ih st + | sInter Sct _ ih => exact (countable_sInter_mem Sct).mpr ih variable (g) diff --git a/Mathlib/Order/Filter/CountableSeparatingOn.lean b/Mathlib/Order/Filter/CountableSeparatingOn.lean index affcf2f203ee0..b1f268cda8419 100644 --- a/Mathlib/Order/Filter/CountableSeparatingOn.lean +++ b/Mathlib/Order/Filter/CountableSeparatingOn.lean @@ -127,13 +127,13 @@ theorem HasCountableSeparatingOn.subtype_iff {α : Type*} {p : Set α → Prop} HasCountableSeparatingOn t (fun u ↦ ∃ v, p v ∧ (↑) ⁻¹' v = u) univ ↔ HasCountableSeparatingOn α p t := by constructor <;> intro h - · exact h.of_subtype $ fun s ↦ id + · exact h.of_subtype <| fun s ↦ id rcases h with ⟨S, Sct, Sp, hS⟩ use {Subtype.val ⁻¹' s | s ∈ S}, Sct.image _, ?_, ?_ · rintro u ⟨t, tS, rfl⟩ exact ⟨t, Sp _ tS, rfl⟩ rintro x - y - hxy - exact Subtype.val_injective $ hS _ (Subtype.coe_prop _) _ (Subtype.coe_prop _) + exact Subtype.val_injective <| hS _ (Subtype.coe_prop _) _ (Subtype.coe_prop _) fun s hs ↦ hxy (Subtype.val ⁻¹' s) ⟨s, hs, rfl⟩ namespace Filter diff --git a/Mathlib/Order/Filter/Curry.lean b/Mathlib/Order/Filter/Curry.lean index 4652e9981ebdf..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 @@ -79,11 +72,11 @@ theorem frequently_curry_prod_iff {α β : Type*} {l : Filter α} {m : Filter β refine ⟨fun h => ?_, fun ⟨hs, ht⟩ => ?_⟩ · exact frequently_prod_and.mp (Frequently.filter_mono h curry_le_prod) rw [frequently_curry_iff] - exact Frequently.mono hs $ fun x hx => Frequently.mono ht (by simp[hx]) + exact Frequently.mono hs <| fun x hx => Frequently.mono ht (by simp [hx]) theorem prod_mem_curry {α β : Type*} {l : Filter α} {m : Filter β} {s : Set α} {t : Set β} (hs : s ∈ l) (ht : t ∈ m) : s ×ˢ t ∈ l.curry m := - curry_le_prod $ prod_mem_prod hs ht + curry_le_prod <| prod_mem_prod hs ht theorem eventually_curry_prod_iff {α β : Type*} {l : Filter α} {m : Filter β} [NeBot l] [NeBot m] (s : Set α) (t : Set β) : diff --git a/Mathlib/Order/Filter/Defs.lean b/Mathlib/Order/Filter/Defs.lean new file mode 100644 index 0000000000000..cd23371bb3f2f --- /dev/null +++ b/Mathlib/Order/Filter/Defs.lean @@ -0,0 +1,378 @@ +/- +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.Data.Set.Basic +import Mathlib.Order.SetNotation + +/-! +# 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 + +/-- 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 : 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] + +instance : Bot (Filter α) where + bot := + { sets := univ + univ_sets := trivial + sets_of_superset := fun _ _ ↦ trivial + inter_sets := fun _ _ ↦ trivial } + +@[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 : 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 : Sup (Filter α) where + sup f g := + { sets := {s | s ∈ f ∧ s ∈ g} + univ_sets := ⟨univ_mem, univ_mem⟩ + sets_of_superset := fun h₁ h₂ ↦ ⟨mem_of_superset h₁.1 h₂, mem_of_superset h₁.2 h₂⟩ + inter_sets := fun h₁ h₂ ↦ ⟨inter_mem h₁.1 h₂.1, inter_mem h₁.2 h₂.2⟩ } + +/-- 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 + +/-- `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 + +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 3c8f70423bc95..8acfdf4fae082 100644 --- a/Mathlib/Order/Filter/ENNReal.lean +++ b/Mathlib/Order/Filter/ENNReal.lean @@ -82,6 +82,6 @@ theorem limsup_liminf_le_liminf_limsup {β} [Countable β] {f : Filter α} [Coun have h1 : ∀ᶠ a in f, ∀ b, u a b ≤ f.limsup fun a' => u a' b := by rw [eventually_countable_forall] exact fun b => ENNReal.eventually_le_limsup fun a => u a b - sInf_le <| h1.mono fun x hx => Filter.liminf_le_liminf (Filter.eventually_of_forall hx) + sInf_le <| h1.mono fun x hx => Filter.liminf_le_liminf (Filter.Eventually.of_forall hx) end ENNReal diff --git a/Mathlib/Order/Filter/EventuallyConst.lean b/Mathlib/Order/Filter/EventuallyConst.lean index 5ab7e4b3e49cd..be981a5e72142 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 /-! @@ -133,7 +134,7 @@ variable [One β] {s : Set α} {c : β} @[to_additive] lemma of_mulIndicator_const (h : EventuallyConst (s.mulIndicator fun _ ↦ c) l) (hc : c ≠ 1) : EventuallyConst s l := by - simpa [(· ∘ ·), hc, imp_false] using h.comp (· = c) + simpa [Function.comp_def, hc, imp_false] using h.comp (· = c) @[to_additive] theorem mulIndicator_const (h : EventuallyConst s l) (c : β) : diff --git a/Mathlib/Order/Filter/Extr.lean b/Mathlib/Order/Filter/Extr.lean index b46294e1e6f5c..aa4829ffbd4a4 100644 --- a/Mathlib/Order/Filter/Extr.lean +++ b/Mathlib/Order/Filter/Extr.lean @@ -577,3 +577,34 @@ theorem IsMinOn.iInf_eq (hx₀ : x₀ ∈ s) (h : IsMinOn f s x₀) : ⨅ x : s, @IsMaxOn.iSup_eq αᵒᵈ β _ _ _ _ hx₀ h end ConditionallyCompleteLinearOrder + +/-! ### Value of `Finset.sup` / `Finset.inf` -/ + +section SemilatticeSup + +variable [SemilatticeSup β] [OrderBot β] {D : α → β} {s : Finset α} + +theorem sup_eq_of_isMaxOn {a : α} (hmem : a ∈ s) (hmax : IsMaxOn D s a) : s.sup D = D a := + (Finset.sup_le hmax).antisymm (Finset.le_sup hmem) + +theorem sup_eq_of_max [Nonempty α] {b : β} (hb : b ∈ Set.range D) (hmem : D.invFun b ∈ s) + (hmax : ∀ a ∈ s, D a ≤ b) : s.sup D = b := by + obtain ⟨a, rfl⟩ := hb + rw [← Function.apply_invFun_apply (f := D)] + apply sup_eq_of_isMaxOn hmem; intro + rw [Function.apply_invFun_apply (f := D)]; apply hmax + +end SemilatticeSup + +section SemilatticeInf + +variable [SemilatticeInf β] [OrderTop β] {D : α → β} {s : Finset α} + +theorem inf_eq_of_isMinOn {a : α} (hmem : a ∈ s) (hmax : IsMinOn D s a) : s.inf D = D a := + sup_eq_of_isMaxOn (α := αᵒᵈ) (β := βᵒᵈ) hmem hmax.dual + +theorem inf_eq_of_min [Nonempty α] {b : β} (hb : b ∈ Set.range D) (hmem : D.invFun b ∈ s) + (hmin : ∀ a ∈ s, b ≤ D a) : s.inf D = b := + sup_eq_of_max (α := αᵒᵈ) (β := βᵒᵈ) hb hmem hmin + +end SemilatticeInf diff --git a/Mathlib/Order/Filter/FilterProduct.lean b/Mathlib/Order/Filter/FilterProduct.lean index 827c876602408..4e69166e08aea 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 @@ -38,7 +40,7 @@ instance instGroupWithZero [GroupWithZero β] : GroupWithZero β* where __ := 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₀ - inv_zero := coe_eq.2 <| by simp only [Function.comp, inv_zero, EventuallyEq.rfl] + inv_zero := coe_eq.2 <| by simp only [Function.comp_def, inv_zero, EventuallyEq.rfl] instance instDivisionSemiring [DivisionSemiring β] : DivisionSemiring β* where toSemiring := instSemiring @@ -79,7 +81,7 @@ theorem lt_def [Preorder β] : ((· < ·) : β* → β* → Prop) = LiftRel (· instance isTotal [LE β] [IsTotal β (· ≤ ·)] : IsTotal β* (· ≤ ·) := ⟨fun f g => - inductionOn₂ f g fun _f _g => eventually_or.1 <| eventually_of_forall fun _x => total_of _ _ _⟩ + inductionOn₂ f g fun _f _g => eventually_or.1 <| Eventually.of_forall fun _x => total_of _ _ _⟩ open Classical in /-- If `φ` is an ultrafilter then the ultraproduct is a linear order. -/ diff --git a/Mathlib/Order/Filter/Germ/Basic.lean b/Mathlib/Order/Filter/Germ/Basic.lean index 52f1af5d388e6..ec0c18e57cedf 100644 --- a/Mathlib/Order/Filter/Germ/Basic.lean +++ b/Mathlib/Order/Filter/Germ/Basic.lean @@ -74,7 +74,7 @@ def Germ (l : Filter α) (β : Type*) : Type _ := def productSetoid (l : Filter α) (ε : α → Type*) : Setoid ((a : _) → ε a) where r f g := ∀ᶠ a in l, f a = g a iseqv := - ⟨fun _ => eventually_of_forall fun _ => rfl, fun h => h.mono fun _ => Eq.symm, + ⟨fun _ => Eventually.of_forall fun _ => rfl, fun h => h.mono fun _ => Eq.symm, fun h1 h2 => h1.congr (h2.mono fun _ hx => hx ▸ Iff.rfl)⟩ /-- The filter product `(a : α) → ε a` at a filter `l`. This is a dependent version of @@ -118,7 +118,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 @@ -291,7 +291,7 @@ theorem liftPred_coe {p : β → Prop} {f : α → β} : LiftPred p (f : Germ l Iff.rfl theorem liftPred_const {p : β → Prop} {x : β} (hx : p x) : LiftPred p (↑x : Germ l β) := - eventually_of_forall fun _y => hx + Eventually.of_forall fun _y => hx @[simp] theorem liftPred_const_iff [NeBot l] {p : β → Prop} {x : β} : LiftPred p (↑x : Germ l β) ↔ p x := @@ -309,7 +309,7 @@ theorem liftRel_coe {r : β → γ → Prop} {f : α → β} {g : α → γ} : theorem liftRel_const {r : β → γ → Prop} {x : β} {y : γ} (h : r x y) : LiftRel r (↑x : Germ l β) ↑y := - eventually_of_forall fun _ => h + Eventually.of_forall fun _ => h @[simp] theorem liftRel_const_iff [NeBot l] {r : β → γ → Prop} {x : β} {y : γ} : @@ -512,7 +512,7 @@ instance instAddGroupWithOne [AddGroupWithOne G] : AddGroupWithOne (Germ l G) wh __ := instAddMonoidWithOne __ := instAddGroup intCast_ofNat _ := congrArg ofFun <| by simp - intCast_negSucc _ := congrArg ofFun <| by simp [Function.comp]; rfl + intCast_negSucc _ := congrArg ofFun <| by simp [Function.comp_def]; rfl end Monoid @@ -707,10 +707,10 @@ theorem const_top [Top β] : (↑(⊤ : β) : Germ l β) = ⊤ := rfl instance instOrderBot [LE β] [OrderBot β] : OrderBot (Germ l β) where - bot_le f := inductionOn f fun _ => eventually_of_forall fun _ => bot_le + bot_le f := inductionOn f fun _ => Eventually.of_forall fun _ => bot_le instance instOrderTop [LE β] [OrderTop β] : OrderTop (Germ l β) where - le_top f := inductionOn f fun _ => eventually_of_forall fun _ => le_top + le_top f := inductionOn f fun _ => Eventually.of_forall fun _ => le_top instance instBoundedOrder [LE β] [BoundedOrder β] : BoundedOrder (Germ l β) where __ := instOrderBot @@ -728,13 +728,13 @@ theorem const_inf [Inf β] (a b : β) : ↑(a ⊓ b) = (↑a ⊓ ↑b : Germ l rfl instance instSemilatticeSup [SemilatticeSup β] : SemilatticeSup (Germ l β) where - le_sup_left f g := inductionOn₂ f g fun _f _g => eventually_of_forall fun _x ↦ le_sup_left - le_sup_right f g := inductionOn₂ f g fun _f _g ↦ eventually_of_forall fun _x ↦ le_sup_right + le_sup_left f g := inductionOn₂ f g fun _f _g => Eventually.of_forall fun _x ↦ le_sup_left + le_sup_right f g := inductionOn₂ f g fun _f _g ↦ Eventually.of_forall fun _x ↦ le_sup_right sup_le f₁ f₂ g := inductionOn₃ f₁ f₂ g fun _f₁ _f₂ _g h₁ h₂ ↦ h₂.mp <| h₁.mono fun _x ↦ sup_le instance instSemilatticeInf [SemilatticeInf β] : SemilatticeInf (Germ l β) where - inf_le_left f g := inductionOn₂ f g fun _f _g ↦ eventually_of_forall fun _x ↦ inf_le_left - inf_le_right f g := inductionOn₂ f g fun _f _g ↦ eventually_of_forall fun _x ↦ inf_le_right + inf_le_left f g := inductionOn₂ f g fun _f _g ↦ Eventually.of_forall fun _x ↦ inf_le_left + inf_le_right f g := inductionOn₂ f g fun _f _g ↦ Eventually.of_forall fun _x ↦ inf_le_right le_inf f₁ f₂ g := inductionOn₃ f₁ f₂ g fun _f₁ _f₂ _g h₁ h₂ ↦ h₂.mp <| h₁.mono fun _x ↦ le_inf instance instLattice [Lattice β] : Lattice (Germ l β) where @@ -742,7 +742,7 @@ instance instLattice [Lattice β] : Lattice (Germ l β) where __ := instSemilatticeInf instance instDistribLattice [DistribLattice β] : DistribLattice (Germ l β) where - le_sup_inf f g h := inductionOn₃ f g h fun _f _g _h ↦ eventually_of_forall fun _ ↦ le_sup_inf + le_sup_inf f g h := inductionOn₃ f g h fun _f _g _h ↦ Eventually.of_forall fun _ ↦ le_sup_inf @[to_additive] instance instExistsMulOfLE [Mul β] [LE β] [ExistsMulOfLE β] : ExistsMulOfLE (Germ l β) where diff --git a/Mathlib/Order/Filter/Germ/OrderedMonoid.lean b/Mathlib/Order/Filter/Germ/OrderedMonoid.lean index f2d7d62077b7e..a3446d9e484a3 100644 --- a/Mathlib/Order/Filter/Germ/OrderedMonoid.lean +++ b/Mathlib/Order/Filter/Germ/OrderedMonoid.lean @@ -39,6 +39,6 @@ instance instOrderedCancelCommMonoid [OrderedCancelCommMonoid β] : instance instCanonicallyOrderedCommMonoid [CanonicallyOrderedCommMonoid β] : CanonicallyOrderedCommMonoid (Germ l β) where __ := instExistsMulOfLE - le_self_mul x y := inductionOn₂ x y fun _ _ ↦ eventually_of_forall fun _ ↦ le_self_mul + le_self_mul x y := inductionOn₂ x y fun _ _ ↦ Eventually.of_forall fun _ ↦ le_self_mul end Filter.Germ diff --git a/Mathlib/Order/Filter/IndicatorFunction.lean b/Mathlib/Order/Filter/IndicatorFunction.lean index 9bc67a4c136d9..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 /-! @@ -120,7 +121,7 @@ theorem Filter.EventuallyEq.of_mulIndicator [One β] {l : Filter α} {f : α → @[to_additive] theorem Filter.EventuallyEq.of_mulIndicator_const [One β] {l : Filter α} {c : β} (hc : c ≠ 1) {s t : Set α} (h : s.mulIndicator (fun _ ↦ c) =ᶠ[l] t.mulIndicator fun _ ↦ c) : s =ᶠ[l] t := - .of_mulIndicator (eventually_of_forall fun _ ↦ hc) h + .of_mulIndicator (Eventually.of_forall fun _ ↦ hc) h @[to_additive] theorem Filter.mulIndicator_const_eventuallyEq [One β] {l : Filter α} {c : β} (hc : c ≠ 1) diff --git a/Mathlib/Order/Filter/Interval.lean b/Mathlib/Order/Filter/Interval.lean index 0bb96d5502cad..02a5a679d0685 100644 --- a/Mathlib/Order/Filter/Interval.lean +++ b/Mathlib/Order/Filter/Interval.lean @@ -18,7 +18,7 @@ from the left or from the right, or it could also be infinity, and "around this to these directed neighborhoods. Therefore, the above theorem has many variants. Instead of stating all these variants, one can look for the common abstraction and have a single version. One has to be careful: if one considers convergence along a sequence, then the function may tend to infinity -but have a derivative which is small along the sequence (with big jumps inbetween), so in the end +but have a derivative which is small along the sequence (with big jumps in between), so in the end the derivative may be integrable on a neighborhood of the sequence. What really matters for such calculus issues in terms of derivatives is that whole intervals are included in the sets we consider. @@ -110,7 +110,7 @@ theorem tendstoIxxClass_inf {l₁ l₁' l₂ l₂' : Filter α} {Ixx} [h : Tends theorem tendstoIxxClass_of_subset {l₁ l₂ : Filter α} {Ixx Ixx' : α → α → Set α} (h : ∀ a b, Ixx a b ⊆ Ixx' a b) [h' : TendstoIxxClass Ixx' l₁ l₂] : TendstoIxxClass Ixx l₁ l₂ := - ⟨h'.1.smallSets_mono <| eventually_of_forall <| Prod.forall.2 h⟩ + ⟨h'.1.smallSets_mono <| Eventually.of_forall <| Prod.forall.2 h⟩ theorem HasBasis.tendstoIxxClass {ι : Type*} {p : ι → Prop} {s} {l : Filter α} (hl : l.HasBasis p s) {Ixx : α → α → Set α} diff --git a/Mathlib/Order/Filter/Ker.lean b/Mathlib/Order/Filter/Ker.lean index 64eecf4a76499..84ab8db20e0cf 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 @@ -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 6a193e98904ff..95e8d4708a1be 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 /-! @@ -249,7 +250,7 @@ theorem lift'_cong (hh : ∀ s ∈ f, h₁ s = h₂ s) : f.lift' h₁ = f.lift' theorem map_lift'_eq {m : β → γ} (hh : Monotone h) : map m (f.lift' h) = f.lift' (image m ∘ h) := calc map m (f.lift' h) = f.lift (map m ∘ 𝓟 ∘ h) := map_lift_eq <| monotone_principal.comp hh - _ = f.lift' (image m ∘ h) := by simp only [comp, Filter.lift', map_principal] + _ = f.lift' (image m ∘ h) := by simp only [comp_def, Filter.lift', map_principal] theorem lift'_map_le {g : Set β → Set γ} {m : α → β} : (map m f).lift' g ≤ f.lift' (g ∘ image m) := lift_map_le @@ -259,7 +260,7 @@ theorem map_lift'_eq2 {g : Set β → Set γ} {m : α → β} (hg : Monotone g) map_lift_eq2 <| monotone_principal.comp hg theorem comap_lift'_eq {m : γ → β} : comap m (f.lift' h) = f.lift' (preimage m ∘ h) := by - simp only [Filter.lift', comap_lift_eq, (· ∘ ·), comap_principal] + simp only [Filter.lift', comap_lift_eq, comp_def, comap_principal] theorem comap_lift'_eq2 {m : β → α} {g : Set β → Set γ} (hg : Monotone g) : (comap m f).lift' g = f.lift' (g ∘ preimage m) := @@ -362,7 +363,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 86955a76f0930..747639ad50753 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 @@ -59,7 +59,7 @@ 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⟩ }, λ h, image2_mem_map₂ h.1 h.2⟩ +-- exact ⟨mem_of_superset hu h.1, mem_of_superset hv h.2⟩ }, fun h ↦ image2_mem_map₂ h.1 h.2⟩ theorem map₂_mono (hf : f₁ ≤ f₂) (hg : g₁ ≤ g₂) : map₂ m f₁ g₁ ≤ map₂ m f₂ g₂ := fun _ ⟨s, hs, t, ht, hst⟩ => ⟨s, hf hs, t, hg ht, hst⟩ @@ -145,7 +145,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] @@ -168,7 +168,7 @@ theorem map₂_assoc {m : δ → γ → ε} {n : α → β → δ} {m' : α → map₂ m (map₂ n f g) h = map₂ m' f (map₂ n' g h) := by rw [← map_prod_eq_map₂ n, ← map_prod_eq_map₂ n', map₂_map_left, map₂_map_right, ← map_prod_eq_map₂, ← map_prod_eq_map₂, ← prod_assoc, map_map] - simp only [h_assoc, Function.comp, Equiv.prodAssoc_apply] + simp only [h_assoc, Function.comp_def, Equiv.prodAssoc_apply] theorem map₂_comm {n : β → α → γ} (h_comm : ∀ a b, m a b = n b a) : map₂ m f g = map₂ n g f := (map₂_swap _ _ _).trans <| by simp_rw [h_comm] diff --git a/Mathlib/Order/Filter/Pointwise.lean b/Mathlib/Order/Filter/Pointwise.lean index b8be6d1b0884c..a1c46ad3a9f3f 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 @@ -86,6 +88,12 @@ theorem one_mem_one : (1 : Set α) ∈ (1 : Filter α) := theorem pure_one : pure 1 = (1 : Filter α) := rfl +@[to_additive (attr := simp) zero_prod] +theorem one_prod {l : Filter β} : (1 : Filter α) ×ˢ l = map (1, ·) l := pure_prod + +@[to_additive (attr := simp) prod_zero] +theorem prod_one {l : Filter β} : l ×ˢ (1 : Filter α) = map (·, 1) l := prod_pure + @[to_additive (attr := simp)] theorem principal_one : 𝓟 1 = (1 : Filter α) := principal_singleton _ @@ -116,10 +124,12 @@ theorem eventually_one {p : α → Prop} : (∀ᶠ x in 1, p x) ↔ p 1 := theorem tendsto_one {a : Filter β} {f : β → α} : Tendsto f a 1 ↔ ∀ᶠ x in a, f x = 1 := tendsto_pure -@[to_additive (attr := simp)] +@[to_additive zero_prod_zero] theorem one_prod_one [One β] : (1 : Filter α) ×ˢ (1 : Filter β) = 1 := prod_pure_pure +@[deprecated (since := "2024-08-16")] alias zero_sum_zero := zero_prod_zero + /-- `pure` as a `OneHom`. -/ @[to_additive "`pure` as a `ZeroHom`."] def pureOneHom : OneHom α (Filter α) where @@ -541,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 @@ -587,7 +597,7 @@ variable [DivisionMonoid α] {f g : Filter α} @[to_additive] protected theorem mul_eq_one_iff : f * g = 1 ↔ ∃ a b, f = pure a ∧ g = pure b ∧ a * b = 1 := by refine ⟨fun hfg => ?_, ?_⟩ - · obtain ⟨t₁, h₁, t₂, h₂, h⟩ : (1 : Set α) ∈ f * g := hfg.symm.subst one_mem_one + · obtain ⟨t₁, h₁, t₂, h₂, h⟩ : (1 : Set α) ∈ f * g := hfg.symm ▸ one_mem_one have hfg : (f * g).NeBot := hfg.symm.subst one_neBot rw [(hfg.nonempty_of_mem <| mul_mem_mul h₁ h₂).subset_one_iff, Set.mul_eq_one_iff] at h obtain ⟨a, b, rfl, rfl, h⟩ := h @@ -598,9 +608,8 @@ protected theorem mul_eq_one_iff : f * g = 1 ↔ ∃ a b, f = pure a ∧ g = pur rw [pure_mul_pure, h, pure_one] /-- `Filter α` is a division monoid under pointwise operations if `α` is. -/ -@[to_additive subtractionMonoid "`Filter α` is a subtraction monoid under pointwise operations if +@[to_additive "`Filter α` is a subtraction monoid under pointwise operations if `α` is."] --- Porting note: `to_additive` guessed `divisionAddMonoid` 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 @@ -706,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 +1050,7 @@ protected def mulAction [Monoid α] [MulAction α β] : MulAction (Filter α) (F @[to_additive "An additive action of an additive monoid on a type `β` gives an additive action on `Filter β`."] protected def mulActionFilter [Monoid α] [MulAction α β] : MulAction α (Filter β) where - mul_smul a b f := by simp only [← Filter.map_smul, map_map, Function.comp, ← mul_smul] + mul_smul a b f := by simp only [← Filter.map_smul, map_map, Function.comp_def, ← mul_smul] one_smul f := by simp only [← Filter.map_smul, one_smul, map_id'] scoped[Pointwise] attribute [instance] Filter.mulAction Filter.addAction Filter.mulActionFilter diff --git a/Mathlib/Order/Filter/Prod.lean b/Mathlib/Order/Filter/Prod.lean index 0202f4d85b27e..b2af14e42295d 100644 --- a/Mathlib/Order/Filter/Prod.lean +++ b/Mathlib/Order/Filter/Prod.lean @@ -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] @@ -229,10 +229,11 @@ theorem prod_mono_right (f : Filter α) {g₁ g₂ : Filter β} (hf : g₁ ≤ g theorem prod_comap_comap_eq.{u, v, w, x} {α₁ : Type u} {α₂ : Type v} {β₁ : Type w} {β₂ : Type x} {f₁ : Filter α₁} {f₂ : Filter α₂} {m₁ : β₁ → α₁} {m₂ : β₂ → α₂} : comap m₁ f₁ ×ˢ comap m₂ f₂ = comap (fun p : β₁ × β₂ => (m₁ p.1, m₂ p.2)) (f₁ ×ˢ f₂) := by - simp only [SProd.sprod, Filter.prod, comap_comap, comap_inf, (· ∘ ·)] + simp only [SProd.sprod, Filter.prod, comap_comap, comap_inf, Function.comp_def] theorem prod_comm' : f ×ˢ g = comap Prod.swap (g ×ˢ f) := by - simp only [SProd.sprod, Filter.prod, comap_comap, (· ∘ ·), inf_comm, Prod.swap, comap_inf] + simp only [SProd.sprod, Filter.prod, comap_comap, Function.comp_def, inf_comm, Prod.swap, + comap_inf] theorem prod_comm : f ×ˢ g = map (fun p : β × α => (p.2, p.1)) (g ×ˢ f) := by rw [prod_comm', ← map_swap_eq_comap_swap] @@ -279,13 +280,13 @@ theorem eventually_swap_iff {p : α × β → Prop} : theorem prod_assoc (f : Filter α) (g : Filter β) (h : Filter γ) : map (Equiv.prodAssoc α β γ) ((f ×ˢ g) ×ˢ h) = f ×ˢ (g ×ˢ h) := by - simp_rw [← comap_equiv_symm, SProd.sprod, Filter.prod, comap_inf, comap_comap, inf_assoc, (· ∘ ·), - Equiv.prodAssoc_symm_apply] + simp_rw [← comap_equiv_symm, SProd.sprod, Filter.prod, comap_inf, comap_comap, inf_assoc, + Function.comp_def, Equiv.prodAssoc_symm_apply] theorem prod_assoc_symm (f : Filter α) (g : Filter β) (h : Filter γ) : map (Equiv.prodAssoc α β γ).symm (f ×ˢ (g ×ˢ h)) = (f ×ˢ g) ×ˢ h := by simp_rw [map_equiv_symm, SProd.sprod, Filter.prod, comap_inf, comap_comap, inf_assoc, - Function.comp, Equiv.prodAssoc_apply] + Function.comp_def, Equiv.prodAssoc_apply] theorem tendsto_prodAssoc {h : Filter γ} : Tendsto (Equiv.prodAssoc α β γ) ((f ×ˢ g) ×ˢ h) (f ×ˢ (g ×ˢ h)) := @@ -408,13 +409,13 @@ 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 dsimp only [SProd.sprod] unfold Filter.prod - simp only [tendsto_inf, tendsto_comap_iff, (· ∘ ·)] + simp only [tendsto_inf, tendsto_comap_iff, Function.comp_def] theorem le_prod {f : Filter (α × β)} {g : Filter α} {g' : Filter β} : (f ≤ g ×ˢ g') ↔ Tendsto Prod.fst f g ∧ Tendsto Prod.snd f g' := @@ -428,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 d4431d4758418..3a1e434b51dd2 100644 --- a/Mathlib/Order/Filter/Ring.lean +++ b/Mathlib/Order/Filter/Ring.lean @@ -33,7 +33,7 @@ theorem EventuallyLE.mul_nonneg [OrderedSemiring β] {l : Filter α} {f g : α theorem eventually_sub_nonneg [OrderedRing β] {l : Filter α} {f g : α → β} : 0 ≤ᶠ[l] g - f ↔ f ≤ᶠ[l] g := - eventually_congr <| eventually_of_forall fun _ => sub_nonneg + eventually_congr <| Eventually.of_forall fun _ => sub_nonneg namespace Germ diff --git a/Mathlib/Order/Filter/SmallSets.lean b/Mathlib/Order/Filter/SmallSets.lean index fba0431ca4a38..fe284b82bd719 100644 --- a/Mathlib/Order/Filter/SmallSets.lean +++ b/Mathlib/Order/Filter/SmallSets.lean @@ -109,7 +109,7 @@ theorem smallSets_principal (s : Set α) : (𝓟 s).smallSets = 𝓟 (𝒫 s) := theorem smallSets_comap_eq_comap_image (l : Filter β) (f : α → β) : (comap f l).smallSets = comap (image f) l.smallSets := by refine (gc_map_comap _).u_comm_of_l_comm (gc_map_comap _) bind_smallSets_gc bind_smallSets_gc ?_ - simp [Function.comp, map_bind, bind_map] + simp [Function.comp_def, map_bind, bind_map] theorem smallSets_comap (l : Filter β) (f : α → β) : (comap f l).smallSets = l.lift' (powerset ∘ preimage f) := diff --git a/Mathlib/Order/Filter/Ultrafilter.lean b/Mathlib/Order/Filter/Ultrafilter.lean index 7d061cff74cf6..6f238409f1d35 100644 --- a/Mathlib/Order/Filter/Ultrafilter.lean +++ b/Mathlib/Order/Filter/Ultrafilter.lean @@ -19,16 +19,12 @@ In this file we define * `hyperfilter`: the ultrafilter extending the cofinite filter. -/ - universe u v variable {α : Type u} {β : Type v} {γ : Type*} open Set Filter Function -open scoped Classical -open Filter - /-- `Filter α` is an atomic type: for every filter there exists an ultrafilter that is less than or equal to this filter. -/ instance : IsAtomic (Filter α) := @@ -54,7 +50,7 @@ instance : CoeTC (Ultrafilter α) (Filter α) := ⟨Ultrafilter.toFilter⟩ instance : Membership (Set α) (Ultrafilter α) := - ⟨fun s f => s ∈ (f : Filter α)⟩ + ⟨fun f s => s ∈ (f : Filter α)⟩ theorem unique (f : Ultrafilter α) {g : Filter α} (h : g ≤ f) (hne : NeBot g := by infer_instance) : g = f := @@ -119,7 +115,7 @@ theorem diff_mem_iff (f : Ultrafilter α) : s \ t ∈ f ↔ s ∈ f ∧ t ∉ f inter_mem_iff.trans <| and_congr Iff.rfl compl_mem_iff_not_mem /-- If `sᶜ ∉ f ↔ s ∈ f`, then `f` is an ultrafilter. The other implication is given by -`Ultrafilter.compl_not_mem_iff`. -/ +`Ultrafilter.compl_not_mem_iff`. -/ def ofComplNotMemIff (f : Filter α) (h : ∀ s, sᶜ ∉ f ↔ s ∈ f) : Ultrafilter α where toFilter := f neBot' := ⟨fun hf => by simp [hf] at h⟩ @@ -469,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 3327656123b53..1f92421e88291 100644 --- a/Mathlib/Order/Fin/Tuple.lean +++ b/Mathlib/Order/Fin/Tuple.lean @@ -25,7 +25,7 @@ lemma pi_lex_lt_cons_cons {x₀ y₀ : α 0} {x y : ∀ i : Fin n, α i.succ} (s : ∀ {i : Fin n.succ}, α i → α i → Prop) : Pi.Lex (· < ·) (@s) (Fin.cons x₀ x) (Fin.cons y₀ y) ↔ s x₀ y₀ ∨ x₀ = y₀ ∧ Pi.Lex (· < ·) (@fun i : Fin n ↦ @s i.succ) x y := by - simp_rw [Pi.Lex, Fin.exists_fin_succ, Fin.cons_succ, Fin.cons_zero, Fin.forall_fin_succ] + simp_rw [Pi.Lex, Fin.exists_fin_succ, Fin.cons_succ, Fin.cons_zero, Fin.forall_iff_succ] simp [and_assoc, exists_and_left] variable [∀ i, Preorder (α i)] @@ -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 @@ -54,7 +54,7 @@ variable {α : Type*} lemma liftFun_vecCons {n : ℕ} (r : α → α → Prop) [IsTrans α r] {f : Fin (n + 1) → α} {a : α} : ((· < ·) ⇒ r) (vecCons a f) (vecCons a f) ↔ r a (f 0) ∧ ((· < ·) ⇒ r) f f := by - simp only [liftFun_iff_succ r, forall_fin_succ, cons_val_succ, cons_val_zero, ← succ_castSucc, + simp only [liftFun_iff_succ r, forall_iff_succ, cons_val_succ, cons_val_zero, ← succ_castSucc, castSucc_zero] variable [Preorder α] {n : ℕ} {f : Fin (n + 1) → α} {a : α} @@ -112,11 +112,54 @@ def OrderIso.piFinTwoIso (α : Fin 2 → Type*) [∀ i, Preorder (α i)] : (∀ def OrderIso.finTwoArrowIso (α : Type*) [Preorder α] : (Fin 2 → α) ≃o α × α := { OrderIso.piFinTwoIso fun _ => α with toEquiv := finTwoArrowEquiv α } +namespace Fin + +/-- Order isomorphism between tuples of length `n + 1` and pairs of an element and a tuple of length +`n` given by separating out the first element of the tuple. + +This is `Fin.cons` as an `OrderIso`. -/ +@[simps!, simps toEquiv] +def consOrderIso (α : Fin (n + 1) → Type*) [∀ i, LE (α i)] : + α 0 × (∀ i, α (succ i)) ≃o ∀ i, α i where + toEquiv := consEquiv α + map_rel_iff' := forall_iff_succ + +/-- Order isomorphism between tuples of length `n + 1` and pairs of an element and a tuple of length +`n` given by separating out the last element of the tuple. + +This is `Fin.snoc` as an `OrderIso`. -/ +@[simps!, simps toEquiv] +def snocOrderIso (α : Fin (n + 1) → Type*) [∀ i, LE (α i)] : + α (last n) × (∀ i, α (castSucc i)) ≃o ∀ i, α i where + toEquiv := snocEquiv α + map_rel_iff' := by simp [Pi.le_def, Prod.le_def, forall_iff_castSucc] + +/-- Order isomorphism between tuples of length `n + 1` and pairs of an element and a tuple of length +`n` given by separating out the `p`-th element of the tuple. + +This is `Fin.insertNth` as an `OrderIso`. -/ +@[simps!, simps toEquiv] +def insertNthOrderIso (α : Fin (n + 1) → Type*) [∀ i, LE (α i)] (p : Fin (n + 1)) : + α p × (∀ i, α (p.succAbove i)) ≃o ∀ i, α i where + toEquiv := insertNthEquiv α p + map_rel_iff' := by simp [Pi.le_def, Prod.le_def, p.forall_iff_succAbove] + +@[simp] lemma insertNthOrderIso_zero (α : Fin (n + 1) → Type*) [∀ i, LE (α i)] : + insertNthOrderIso α 0 = consOrderIso α := by ext; simp [insertNthOrderIso] + +/-- Note this lemma can only be written about non-dependent tuples as `insertNth (last n) = snoc` is +not a definitional equality. -/ +@[simp] lemma insertNthOrderIso_last (n : ℕ) (α : Type*) [LE α] : + insertNthOrderIso (fun _ ↦ α) (last n) = snocOrderIso (fun _ ↦ α) := by ext; simp + +end Fin + /-- Order isomorphism between `Π j : Fin (n + 1), α j` and `α i × Π j : Fin n, α (Fin.succAbove i j)`. -/ +@[deprecated Fin.insertNthOrderIso (since := "2024-07-12")] def OrderIso.piFinSuccAboveIso (α : Fin (n + 1) → Type*) [∀ i, LE (α i)] (i : Fin (n + 1)) : (∀ j, α j) ≃o α i × ∀ j, α (i.succAbove j) where - toEquiv := Equiv.piFinSuccAbove α i + toEquiv := (Fin.insertNthEquiv α i).symm map_rel_iff' := Iff.symm i.forall_iff_succAbove /-- `Fin.succAbove` as an order isomorphism between `Fin n` and `{x : Fin (n + 1) // x ≠ p}`. -/ diff --git a/Mathlib/Order/FixedPoints.lean b/Mathlib/Order/FixedPoints.lean index 1f7d10d048fae..e6f40735b5ddc 100644 --- a/Mathlib/Order/FixedPoints.lean +++ b/Mathlib/Order/FixedPoints.lean @@ -5,6 +5,7 @@ Authors: Johannes Hölzl, Kenny Lau, Yury Kudryashov -/ import Mathlib.Dynamics.FixedPoints.Basic import Mathlib.Order.Hom.Order +import Mathlib.Order.OmegaCompletePartialOrder /-! # Fixed point construction on complete lattices @@ -275,4 +276,22 @@ instance completeLattice : CompleteLattice (fixedPoints f) where le_top x := f.le_gfp x.2.ge bot_le x := f.lfp_le x.2.le +open OmegaCompletePartialOrder fixedPoints + +/-- **Kleene's fixed point Theorem**: The least fixed point in a complete lattice is +the supremum of iterating a function on bottom arbitrary often. -/ +theorem lfp_eq_sSup_iterate (h : ωScottContinuous f) : + lfp f = ⨆ n, f^[n] ⊥ := by + apply le_antisymm + · apply lfp_le_fixed + exact Function.mem_fixedPoints.mp (ωSup_iterate_mem_fixedPoint + ⟨f, h.map_ωSup_of_orderHom⟩ ⊥ bot_le) + · apply le_lfp + intro a h_a + exact ωSup_iterate_le_prefixedPoint ⟨f, h.map_ωSup_of_orderHom⟩ ⊥ bot_le h_a bot_le + +theorem gfp_eq_sInf_iterate (h : ωScottContinuous (OrderHom.dual f)) : + gfp f = ⨅ n, f^[n] ⊤ := + lfp_eq_sSup_iterate (OrderHom.dual f) h + end fixedPoints 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..199354c730cff 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 @@ -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 := @@ -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..6b0940817f6d3 100644 --- a/Mathlib/Order/Heyting/Hom.lean +++ b/Mathlib/Order/Heyting/Hom.lean @@ -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 diff --git a/Mathlib/Order/Heyting/Regular.lean b/Mathlib/Order/Heyting/Regular.lean index ed41e246a1c47..98043e41c3ecf 100644 --- a/Mathlib/Order/Heyting/Regular.lean +++ b/Mathlib/Order/Heyting/Regular.lean @@ -76,7 +76,7 @@ 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 => diff --git a/Mathlib/Order/Hom/Basic.lean b/Mathlib/Order/Hom/Basic.lean index 5b9b773385b2c..96b44c3f6a264 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 @@ -173,6 +174,10 @@ theorem map_inv_le_iff (f : F) {a : α} {b : β} : EquivLike.inv f b ≤ a ↔ b convert (map_le_map_iff f (a := EquivLike.inv f b) (b := a)).symm exact (EquivLike.right_inv f _).symm +theorem map_inv_le_map_inv_iff (f : F) {a b : β} : + EquivLike.inv f b ≤ EquivLike.inv f a ↔ b ≤ a := by + simp + -- Porting note: needed to add explicit arguments to map_le_map_iff @[simp] theorem le_map_inv_iff (f : F) {a : α} {b : β} : a ≤ EquivLike.inv f b ↔ f a ≤ b := by @@ -191,6 +196,10 @@ theorem map_inv_lt_iff (f : F) {a : α} {b : β} : EquivLike.inv f b < a ↔ b < rw [← map_lt_map_iff f] simp only [EquivLike.apply_inv_apply] +theorem map_inv_lt_map_inv_iff (f : F) {a b : β} : + EquivLike.inv f b < EquivLike.inv f a ↔ b < a := by + simp + @[simp] theorem lt_map_inv_iff (f : F) {a : α} {b : β} : a < EquivLike.inv f b ↔ f a < b := by rw [← map_lt_map_iff f] @@ -426,7 +435,7 @@ def coeFnHom : (α →o β) →o α → β where monotone' _ _ h := h /-- Function application `fun f => f a` (for fixed `a`) is a monotone function from the -monotone function space `α →o β` to `β`. See also `Pi.evalOrderHom`. -/ +monotone function space `α →o β` to `β`. See also `Pi.evalOrderHom`. -/ @[simps! (config := .asFn)] def apply (x : α) : (α →o β) →o β := (Pi.evalOrderHom x).comp coeFnHom @@ -447,7 +456,7 @@ def piIso : (α →o ∀ i, π i) ≃o ∀ i, α →o π i where right_inv _ := rfl map_rel_iff' := forall_swap -/-- `Subtype.val` as a bundled monotone function. -/ +/-- `Subtype.val` as a bundled monotone function. -/ @[simps (config := .asFn)] def Subtype.val (p : α → Prop) : Subtype p →o α := ⟨_root_.Subtype.val, fun _ _ h => h⟩ @@ -591,6 +600,18 @@ protected def withBotMap (f : α ↪o β) : WithBot α ↪o WithBot β := protected def withTopMap (f : α ↪o β) : WithTop α ↪o WithTop β := { f.dual.withBotMap.dual with toFun := WithTop.map f } +/-- Coercion `α → WithBot α` as an `OrderEmbedding`. -/ +@[simps (config := .asFn)] +protected def withBotCoe : α ↪o WithBot α where + toFun := .some + inj' := Option.some_injective _ + map_rel_iff' := WithBot.coe_le_coe + +/-- Coercion `α → WithTop α` as an `OrderEmbedding`. -/ +@[simps (config := .asFn)] +protected def withTopCoe : α ↪o WithTop α := + { (OrderEmbedding.withBotCoe (α := αᵒᵈ)).dual with toFun := .some } + /-- To define an order embedding from a partial order to a preorder it suffices to give a function together with a proof that it satisfies `f a ≤ f b ↔ a ≤ b`. -/ @@ -774,9 +795,7 @@ theorem symm_apply_eq (e : α ≃o β) {x : α} {y : β} : e.symm y = x ↔ y = e.toEquiv.symm_apply_eq @[simp] -theorem symm_symm (e : α ≃o β) : e.symm.symm = e := by - ext - rfl +theorem symm_symm (e : α ≃o β) : e.symm.symm = e := rfl theorem symm_bijective : Function.Bijective (OrderIso.symm : (α ≃o β) → β ≃o α) := Function.bijective_iff_has_inverse.mpr ⟨_, symm_symm, symm_symm⟩ @@ -896,7 +915,7 @@ 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 := @@ -910,7 +929,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 @@ -1034,7 +1053,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)] @@ -1087,6 +1106,18 @@ theorem OrderIso.map_sup [SemilatticeSup α] [SemilatticeSup β] (f : α ≃o β f (x ⊔ y) = f x ⊔ f y := f.dual.map_inf x y +theorem OrderIso.isMax_apply {α β : Type*} [Preorder α] [Preorder β] (f : α ≃o β) {x : α} : + IsMax (f x) ↔ IsMax x := by + refine ⟨f.strictMono.isMax_of_apply, ?_⟩ + conv_lhs => rw [← f.symm_apply_apply x] + exact f.symm.strictMono.isMax_of_apply + +theorem OrderIso.isMin_apply {α β : Type*} [Preorder α] [Preorder β] (f : α ≃o β) {x : α} : + IsMin (f x) ↔ IsMin x := by + refine ⟨f.strictMono.isMin_of_apply, ?_⟩ + conv_lhs => rw [← f.symm_apply_apply x] + exact f.symm.strictMono.isMin_of_apply + /-- Note that this goal could also be stated `(Disjoint on f) a b` -/ theorem Disjoint.map_orderIso [SemilatticeInf α] [OrderBot α] [SemilatticeInf β] [OrderBot β] {a b : α} (f : α ≃o β) (ha : Disjoint a b) : Disjoint (f a) (f b) := by @@ -1141,6 +1172,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 @@ -1172,6 +1210,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 @@ -1241,3 +1286,20 @@ theorem OrderIso.complementedLattice_iff (f : α ≃o β) : end BoundedOrder end LatticeIsos + +section DenselyOrdered + +lemma denselyOrdered_iff_of_orderIsoClass {X Y F : Type*} [Preorder X] [Preorder Y] + [EquivLike F X Y] [OrderIsoClass F X Y] (f : F) : + DenselyOrdered X ↔ DenselyOrdered Y := by + constructor + · intro H + refine ⟨fun a b h ↦ ?_⟩ + obtain ⟨c, hc⟩ := exists_between ((map_inv_lt_map_inv_iff f).mpr h) + exact ⟨f c, by simpa using hc⟩ + · intro H + refine ⟨fun a b h ↦ ?_⟩ + obtain ⟨c, hc⟩ := exists_between ((map_lt_map_iff f).mpr h) + exact ⟨EquivLike.inv f c, by simpa using hc⟩ + +end DenselyOrdered 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 004c9a77b9bef..8fecfd2875b9b 100644 --- a/Mathlib/Order/Hom/CompleteLattice.lean +++ b/Mathlib/Order/Hom/CompleteLattice.lean @@ -118,13 +118,13 @@ section Hom variable [FunLike F α β] @[simp] theorem map_iSup [SupSet α] [SupSet β] [sSupHomClass F α β] (f : F) (g : ι → α) : - f (⨆ i, g i) = ⨆ i, f (g i) := by simp [iSup, ← Set.range_comp, Function.comp] + f (⨆ i, g i) = ⨆ i, f (g i) := by simp [iSup, ← Set.range_comp, Function.comp_def] theorem map_iSup₂ [SupSet α] [SupSet β] [sSupHomClass F α β] (f : F) (g : ∀ i, κ i → α) : f (⨆ (i) (j), g i j) = ⨆ (i) (j), f (g i j) := by simp_rw [map_iSup] @[simp] theorem map_iInf [InfSet α] [InfSet β] [sInfHomClass F α β] (f : F) (g : ι → α) : - f (⨅ i, g i) = ⨅ i, f (g i) := by simp [iInf, ← Set.range_comp, Function.comp] + f (⨅ i, g i) = ⨅ i, f (g i) := by simp [iInf, ← Set.range_comp, Function.comp_def] theorem map_iInf₂ [InfSet α] [InfSet β] [sInfHomClass F α β] (f : F) (g : ∀ i, κ i → α) : f (⨅ (i) (j), g i j) = ⨅ (i) (j), f (g i j) := by simp_rw [map_iInf] diff --git a/Mathlib/Order/Hom/Lattice.lean b/Mathlib/Order/Hom/Lattice.lean index a6513d866da90..94af3f7566504 100644 --- a/Mathlib/Order/Hom/Lattice.lean +++ b/Mathlib/Order/Hom/Lattice.lean @@ -474,6 +474,24 @@ theorem bot_apply [Bot β] (a : α) : (⊥ : SupHom α β) a = ⊥ := theorem top_apply [Top β] (a : α) : (⊤ : SupHom α β) a = ⊤ := rfl +/-- `Subtype.val` as a `SupHom`. -/ +def subtypeVal {P : β → Prop} + (Psup : ∀ ⦃x y : β⦄, P x → P y → P (x ⊔ y)) : + letI := Subtype.semilatticeSup Psup + SupHom {x : β // P x} β := + letI := Subtype.semilatticeSup Psup + .mk Subtype.val (by simp) + +@[simp] +lemma subtypeVal_apply {P : β → Prop} + (Psup : ∀ ⦃x y : β⦄, P x → P y → P (x ⊔ y)) (x : {x : β // P x}) : + subtypeVal Psup x = x := rfl + +@[simp] +lemma subtypeVal_coe {P : β → Prop} + (Psup : ∀ ⦃x y : β⦄, P x → P y → P (x ⊔ y)) : + ⇑(subtypeVal Psup) = Subtype.val := rfl + end SupHom /-! ### Infimum homomorphisms -/ @@ -632,6 +650,24 @@ theorem bot_apply [Bot β] (a : α) : (⊥ : InfHom α β) a = ⊥ := theorem top_apply [Top β] (a : α) : (⊤ : InfHom α β) a = ⊤ := rfl +/-- `Subtype.val` as an `InfHom`. -/ +def subtypeVal {P : β → Prop} + (Pinf : ∀ ⦃x y : β⦄, P x → P y → P (x ⊓ y)) : + letI := Subtype.semilatticeInf Pinf + InfHom {x : β // P x} β := + letI := Subtype.semilatticeInf Pinf + .mk Subtype.val (by simp) + +@[simp] +lemma subtypeVal_apply {P : β → Prop} + (Pinf : ∀ ⦃x y : β⦄, P x → P y → P (x ⊓ y)) (x : {x : β // P x}) : + subtypeVal Pinf x = x := rfl + +@[simp] +lemma subtypeVal_coe {P : β → Prop} + (Pinf : ∀ ⦃x y : β⦄, P x → P y → P (x ⊓ y)) : + ⇑(subtypeVal Pinf) = Subtype.val := rfl + end InfHom /-! ### Finitary supremum homomorphisms -/ @@ -762,6 +798,26 @@ theorem sup_apply (f g : SupBotHom α β) (a : α) : (f ⊔ g) a = f a ⊔ g a : theorem bot_apply (a : α) : (⊥ : SupBotHom α β) a = ⊥ := rfl +/-- `Subtype.val` as a `SupBotHom`. -/ +def subtypeVal {P : β → Prop} + (Pbot : P ⊥) (Psup : ∀ ⦃x y : β⦄, P x → P y → P (x ⊔ y)) : + letI := Subtype.orderBot Pbot + letI := Subtype.semilatticeSup Psup + SupBotHom {x : β // P x} β := + letI := Subtype.orderBot Pbot + letI := Subtype.semilatticeSup Psup + .mk (SupHom.subtypeVal Psup) (by simp [Subtype.coe_bot Pbot]) + +@[simp] +lemma subtypeVal_apply {P : β → Prop} + (Pbot : P ⊥) (Psup : ∀ ⦃x y : β⦄, P x → P y → P (x ⊔ y)) (x : {x : β // P x}) : + subtypeVal Pbot Psup x = x := rfl + +@[simp] +lemma subtypeVal_coe {P : β → Prop} + (Pbot : P ⊥) (Psup : ∀ ⦃x y : β⦄, P x → P y → P (x ⊔ y)) : + ⇑(subtypeVal Pbot Psup) = Subtype.val := rfl + end SupBotHom /-! ### Finitary infimum homomorphisms -/ @@ -893,6 +949,26 @@ theorem inf_apply (f g : InfTopHom α β) (a : α) : (f ⊓ g) a = f a ⊓ g a : theorem top_apply (a : α) : (⊤ : InfTopHom α β) a = ⊤ := rfl +/-- `Subtype.val` as an `InfTopHom`. -/ +def subtypeVal {P : β → Prop} + (Ptop : P ⊤) (Pinf : ∀ ⦃x y : β⦄, P x → P y → P (x ⊓ y)) : + letI := Subtype.orderTop Ptop + letI := Subtype.semilatticeInf Pinf + InfTopHom {x : β // P x} β := + letI := Subtype.orderTop Ptop + letI := Subtype.semilatticeInf Pinf + .mk (InfHom.subtypeVal Pinf) (by simp [Subtype.coe_top Ptop]) + +@[simp] +lemma subtypeVal_apply {P : β → Prop} + (Ptop : P ⊤) (Pinf : ∀ ⦃x y : β⦄, P x → P y → P (x ⊓ y)) (x : {x : β // P x}) : + subtypeVal Ptop Pinf x = x := rfl + +@[simp] +lemma subtypeVal_coe {P : β → Prop} + (Ptop : P ⊤) (Pinf : ∀ ⦃x y : β⦄, P x → P y → P (x ⊓ y)) : + ⇑(subtypeVal Ptop Pinf) = Subtype.val := rfl + end InfTopHom /-! ### Lattice homomorphisms -/ @@ -1013,6 +1089,25 @@ theorem cancel_left {g : LatticeHom β γ} {f₁ f₂ : LatticeHom α β} (hg : ⟨fun h => LatticeHom.ext fun a => hg <| by rw [← LatticeHom.comp_apply, h, LatticeHom.comp_apply], congr_arg _⟩ +/-- `Subtype.val` as a `LatticeHom`. -/ +def subtypeVal {P : β → Prop} + (Psup : ∀ ⦃x y⦄, P x → P y → P (x ⊔ y)) (Pinf : ∀ ⦃x y⦄, P x → P y → P (x ⊓ y)) : + letI := Subtype.lattice Psup Pinf + LatticeHom {x : β // P x} β := + letI := Subtype.lattice Psup Pinf + .mk (SupHom.subtypeVal Psup) (by simp) + +@[simp] +lemma subtypeVal_apply {P : β → Prop} + (Psup : ∀ ⦃x y⦄, P x → P y → P (x ⊔ y)) (Pinf : ∀ ⦃x y⦄, P x → P y → P (x ⊓ y)) + (x : {x : β // P x}) : + subtypeVal Psup Pinf x = x := rfl + +@[simp] +lemma subtypeVal_coe {P : β → Prop} + (Psup : ∀ ⦃x y⦄, P x → P y → P (x ⊔ y)) (Pinf : ∀ ⦃x y⦄, P x → P y → P (x ⊓ y)) : + ⇑(subtypeVal Psup Pinf) = Subtype.val := rfl + end LatticeHom namespace OrderHomClass @@ -1184,6 +1279,27 @@ theorem cancel_left {g : BoundedLatticeHom β γ} {f₁ f₂ : BoundedLatticeHom g.comp f₁ = g.comp f₂ ↔ f₁ = f₂ := ⟨fun h => ext fun a => hg <| by rw [← comp_apply, h, comp_apply], congr_arg _⟩ +/-- `Subtype.val` as a `BoundedLatticeHom`. -/ +def subtypeVal {P : β → Prop} (Pbot : P ⊥) (Ptop : P ⊤) + (Psup : ∀ ⦃x y⦄, P x → P y → P (x ⊔ y)) (Pinf : ∀ ⦃x y⦄, P x → P y → P (x ⊓ y)) : + letI := Subtype.lattice Psup Pinf + letI := Subtype.boundedOrder Pbot Ptop + BoundedLatticeHom {x : β // P x} β := + letI := Subtype.lattice Psup Pinf + letI := Subtype.boundedOrder Pbot Ptop + .mk (.subtypeVal Psup Pinf) (by simp [Subtype.coe_top Ptop]) (by simp [Subtype.coe_bot Pbot]) + +@[simp] +lemma subtypeVal_apply {P : β → Prop} + (Pbot : P ⊥) (Ptop : P ⊤) (Psup : ∀ ⦃x y⦄, P x → P y → P (x ⊔ y)) + (Pinf : ∀ ⦃x y⦄, P x → P y → P (x ⊓ y)) (x : {x : β // P x}) : + subtypeVal Pbot Ptop Psup Pinf x = x := rfl + +@[simp] +lemma subtypeVal_coe {P : β → Prop} (Pbot : P ⊥) (Ptop : P ⊤) + (Psup : ∀ ⦃x y⦄, P x → P y → P (x ⊔ y)) (Pinf : ∀ ⦃x y⦄, P x → P y → P (x ⊓ y)) : + ⇑(subtypeVal Pbot Ptop Psup Pinf) = Subtype.val := rfl + end BoundedLatticeHom /-! ### Dual homs -/ @@ -1660,3 +1776,5 @@ def withTopWithBot' [BoundedOrder β] (f : LatticeHom α β) : map_bot' := rfl end LatticeHom + +set_option linter.style.longFile 1800 diff --git a/Mathlib/Order/Hom/Order.lean b/Mathlib/Order/Hom/Order.lean index 668022c2fa728..c2db9e632bb02 100644 --- a/Mathlib/Order/Hom/Order.lean +++ b/Mathlib/Order/Hom/Order.lean @@ -130,9 +130,11 @@ theorem iterate_sup_le_sup_iff {α : Type*} [SemilatticeSup α] (f : α →o α) · intro n₁ n₂ a₁ a₂ have h' : ∀ n a₁ a₂, f^[n] (a₁ ⊔ a₂) ≤ f^[n] a₁ ⊔ a₂ := by intro n - induction' n with n ih <;> intro a₁ a₂ - · rfl - · calc + induction n with + | zero => intro a₁ a₂; rfl + | succ n ih => + intro a₁ a₂ + calc f^[n + 1] (a₁ ⊔ a₂) = f^[n] (f (a₁ ⊔ a₂)) := Function.iterate_succ_apply f n _ _ ≤ f^[n] (f a₁ ⊔ a₂) := f.mono.iterate n (h a₁ a₂) _ ≤ f^[n] (f a₁) ⊔ a₂ := ih _ _ diff --git a/Mathlib/Order/Hom/Set.lean b/Mathlib/Order/Hom/Set.lean index 6838a14b4bba9..382a2354e4f5d 100644 --- a/Mathlib/Order/Hom/Set.lean +++ b/Mathlib/Order/Hom/Set.lean @@ -5,7 +5,9 @@ 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 /-! # Order homomorphisms and sets @@ -14,13 +16,13 @@ import Mathlib.Data.Set.Image open OrderDual -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 +58,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 +121,46 @@ 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' _ + +end OrderIso + section BooleanAlgebra variable (α) [BooleanAlgebra α] diff --git a/Mathlib/Order/Ideal.lean b/Mathlib/Order/Ideal.lean index f10e971e09067..3e6b195981b8f 100644 --- a/Mathlib/Order/Ideal.lean +++ b/Mathlib/Order/Ideal.lean @@ -476,7 +476,7 @@ instance : Inhabited (Cofinal P) := mem_gt := fun x ↦ ⟨x, trivial, le_rfl⟩ }⟩ instance : Membership P (Cofinal P) := - ⟨fun x D ↦ x ∈ D.carrier⟩ + ⟨fun D x ↦ x ∈ D.carrier⟩ variable (D : Cofinal P) (x : P) diff --git a/Mathlib/Order/InitialSeg.lean b/Mathlib/Order/InitialSeg.lean index 8ab6a88adb7ee..cfc294fcbe01c 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,18 +103,27 @@ 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⟩ +@[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 := ⟨f, fun _ b _ => ⟨f.symm b, RelIso.apply_symm_apply f _⟩⟩ @@ -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) := @@ -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,24 +269,49 @@ 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 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 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 /-- 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 := + ⟨f, _, Classical.choose_spec (f.eq_or_principal.resolve_left hf)⟩ + +@[simp] +theorem _root_.InitialSeg.toPrincipalSeg_apply [IsWellOrder β s] (f : r ≼i s) + (hf : ¬ Surjective f) (x : α) : f.toPrincipalSeg hf x = f x := + rfl theorem irrefl {r : α → α → Prop} [IsWellOrder α r] (f : r ≺i r) : False := by have h := f.lt_top f.top @@ -260,8 +324,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) := @@ -287,17 +350,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) := @@ -315,7 +378,7 @@ 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 ⟩ @@ -323,14 +386,17 @@ instance [IsWellOrder β s] : Subsingleton (r ≺i s) := 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] @@ -346,7 +412,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 @@ -360,15 +426,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⟩ := @@ -382,7 +445,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,7 +472,7 @@ theorem wellFounded_iff_wellFounded_subrel {β : Type*} {s : β → β → Prop} ⟨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) + obtain ⟨b', rfl⟩ := f.mem_range_of_rel_top ((PrincipalSeg.ofElement_top s b).symm ▸ hb') exact (f.acc b').mp ((wf b).apply b') theorem wellFounded_iff_principalSeg.{u} {β : Type u} {s : β → β → Prop} [IsTrans β s] : @@ -420,36 +483,37 @@ 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) - · have h' : _ := (InitialSeg.eq_or_principal f).resolve_left h - exact Sum.inl ⟨f, Classical.choose h', Classical.choose_spec 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] + 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 namespace RelEmbedding @@ -498,5 +562,100 @@ theorem collapse_apply [IsWellOrder β s] (f : r ↪r s) (a) : collapse f a = (c rfl end RelEmbedding + +/-- 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⟩ + 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 : α Icc s.fst s.snd⟩ instance (priority := 100) : Membership α (NonemptyInterval α) := - ⟨fun a s => a ∈ (s : Set α)⟩ + ⟨fun s a => a ∈ (s : Set α)⟩ @[simp] theorem mem_mk {hx : x.1 ≤ x.2} : a ∈ mk x hx ↔ x.1 ≤ a ∧ a ≤ x.2 := @@ -189,7 +188,7 @@ end Preorder section PartialOrder -variable [PartialOrder α] [PartialOrder β] {s t : NonemptyInterval α} {x : α × α} {a b : α} +variable [PartialOrder α] [PartialOrder β] {s t : NonemptyInterval α} {a b : α} instance : PartialOrder (NonemptyInterval α) := PartialOrder.lift _ toDualProd_injective @@ -272,7 +271,7 @@ namespace Interval section LE -variable [LE α] {s t : Interval α} +variable [LE α] -- Porting note: previously found using `deriving` instance : Inhabited (Interval α) := WithBot.inhabited diff --git a/Mathlib/Order/Interval/Finset/Basic.lean b/Mathlib/Order/Interval/Finset/Basic.lean index 5d9683aba67b6..53ccb40f79265 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 @@ -113,19 +122,19 @@ theorem Ioo_eq_empty_of_le (h : b ≤ a) : Ioo a b = ∅ := -- 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] @@ -331,9 +340,18 @@ 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 + +theorem Ioi_subset_Ioi (h : a ≤ b) : Ioi b ⊆ Ioi a := by + simpa [← coe_subset] using Set.Ioi_subset_Ioi h + variable [LocallyFiniteOrder α] theorem Icc_subset_Ici_self : Icc a b ⊆ Ici a := by @@ -360,8 +378,19 @@ 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 + +theorem Iio_subset_Iio (h : a ≤ b) : Iio a ⊆ Iio b := by + simpa [← coe_subset] using Set.Iio_subset_Iio h variable [LocallyFiniteOrder α] @@ -654,7 +683,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 @@ -761,7 +790,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 _ _ @@ -833,7 +862,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] @@ -844,7 +873,7 @@ theorem eq_of_mem_uIcc_of_mem_uIcc' : b ∈ [[a, c]] → c ∈ [[a, b]] → b = exact Set.eq_of_mem_uIcc_of_mem_uIcc' theorem uIcc_injective_right (a : α) : Injective fun b => [[b, a]] := fun b c h => by - rw [ext_iff] at h + rw [Finset.ext_iff] at h exact eq_of_mem_uIcc_of_mem_uIcc ((h _).1 left_mem_uIcc) ((h _).2 left_mem_uIcc) theorem uIcc_injective_left (a : α) : Injective (uIcc a) := by @@ -854,7 +883,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 diff --git a/Mathlib/Order/Interval/Finset/Box.lean b/Mathlib/Order/Interval/Finset/Box.lean index ac0328f341edb..ae26532a1a735 100644 --- a/Mathlib/Order/Interval/Finset/Box.lean +++ b/Mathlib/Order/Interval/Finset/Box.lean @@ -68,7 +68,9 @@ variable {α β : Type*} [OrderedRing α] [OrderedRing β] [LocallyFiniteOrder (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 - rw [box_succ_eq_sdiff, card_sdiff (Icc_neg_mono n.le_succ), Prod.card_Icc, Prod.card_Icc]; rfl + rw [box_succ_eq_sdiff, card_sdiff (Icc_neg_mono n.le_succ), Finset.card_Icc_prod, + Finset.card_Icc_prod] + rfl end Prod diff --git a/Mathlib/Order/Interval/Finset/Defs.lean b/Mathlib/Order/Interval/Finset/Defs.lean index 3a70b721e212a..d81c2dec0066c 100644 --- a/Mathlib/Order/Interval/Finset/Defs.lean +++ b/Mathlib/Order/Interval/Finset/Defs.lean @@ -271,23 +271,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 +329,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 +359,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 := @@ -452,6 +452,51 @@ end Lattice end Finset +namespace Mathlib.Meta +open Lean Elab Term Meta Batteries.ExtendedBinder + +/-- Elaborate set builder notation for `Finset`. + +* `{x ≤ a | p x}` is elaborated as `Finset.filter (fun x ↦ p x) (Finset.Iic a)` if the expected type + is `Finset ?α`. +* `{x ≥ a | p x}` is elaborated as `Finset.filter (fun x ↦ p x) (Finset.Ici a)` if the expected type + is `Finset ?α`. +* `{x < a | p x}` is elaborated as `Finset.filter (fun x ↦ p x) (Finset.Iio a)` if the expected type + is `Finset ?α`. +* `{x > a | p x}` is elaborated as `Finset.filter (fun x ↦ p x) (Finset.Ioi a)` if the expected type + is `Finset ?α`. + +See also +* `Data.Set.Defs` for the `Set` builder notation elaborator that this elaborator partly overrides. +* `Data.Finset.Basic` for the `Finset` builder notation elaborator partly overriding this one for + syntax of the form `{x ∈ s | p x}`. +* `Data.Fintype.Basic` for the `Finset` builder notation elaborator handling syntax of the form + `{x | p x}`, `{x : α | p x}`, `{x ∉ s | p x}`, `{x ≠ a | p x}`. + +TODO: Write a delaborator +-/ +@[term_elab setBuilder] +def elabFinsetBuilderIxx : TermElab + | `({ $x:ident ≤ $a | $p }), expectedType? => do + -- If the expected type is not known to be `Finset ?α`, give up. + unless ← knownToBeFinsetNotSet expectedType? do throwUnsupportedSyntax + elabTerm (← `(Finset.filter (fun $x:ident ↦ $p) (Finset.Iic $a))) expectedType? + | `({ $x:ident ≥ $a | $p }), expectedType? => do + -- If the expected type is not known to be `Finset ?α`, give up. + unless ← knownToBeFinsetNotSet expectedType? do throwUnsupportedSyntax + elabTerm (← `(Finset.filter (fun $x:ident ↦ $p) (Finset.Ici $a))) expectedType? + | `({ $x:ident < $a | $p }), expectedType? => do + -- If the expected type is not known to be `Finset ?α`, give up. + unless ← knownToBeFinsetNotSet expectedType? do throwUnsupportedSyntax + elabTerm (← `(Finset.filter (fun $x:ident ↦ $p) (Finset.Iio $a))) expectedType? + | `({ $x:ident > $a | $p }), expectedType? => do + -- If the expected type is not known to be `Finset ?α`, give up. + unless ← knownToBeFinsetNotSet expectedType? do throwUnsupportedSyntax + elabTerm (← `(Finset.filter (fun $x:ident ↦ $p) (Finset.Ioi $a))) expectedType? + | _, _ => throwUnsupportedSyntax + +end Mathlib.Meta + /-! ### Finiteness of `Set` intervals -/ @@ -616,6 +661,8 @@ protected noncomputable def OrderEmbedding.locallyFiniteOrder [LocallyFiniteOrde finset_mem_Ioc a b x := by rw [mem_preimage, mem_Ioc, f.lt_iff_lt, f.le_iff_le] finset_mem_Ioo a b x := by rw [mem_preimage, mem_Ioo, f.lt_iff_lt, f.lt_iff_lt] +/-! ### `OrderDual` -/ + open OrderDual section LocallyFiniteOrder @@ -639,26 +686,30 @@ instance OrderDual.instLocallyFiniteOrder : LocallyFiniteOrder αᵒᵈ where finset_mem_Ioc _ _ _ := (mem_Ico (α := α)).trans and_comm finset_mem_Ioo _ _ _ := (mem_Ioo (α := α)).trans and_comm -theorem Icc_toDual : Icc (toDual a) (toDual b) = (Icc b a).map toDual.toEmbedding := map_refl.symm - -theorem Ico_toDual : Ico (toDual a) (toDual b) = (Ioc b a).map toDual.toEmbedding := map_refl.symm - -theorem Ioc_toDual : Ioc (toDual a) (toDual b) = (Ico b a).map toDual.toEmbedding := map_refl.symm - -theorem Ioo_toDual : Ioo (toDual a) (toDual b) = (Ioo b a).map toDual.toEmbedding := map_refl.symm - -theorem Icc_ofDual (a b : αᵒᵈ) : Icc (ofDual a) (ofDual b) = (Icc b a).map ofDual.toEmbedding := +lemma Finset.Icc_toDual : Icc (toDual a) (toDual b) = (Icc b a).map toDual.toEmbedding := map_refl.symm -theorem Ico_ofDual (a b : αᵒᵈ) : Ico (ofDual a) (ofDual b) = (Ioc b a).map ofDual.toEmbedding := +lemma Finset.Ico_toDual : Ico (toDual a) (toDual b) = (Ioc b a).map toDual.toEmbedding := map_refl.symm -theorem Ioc_ofDual (a b : αᵒᵈ) : Ioc (ofDual a) (ofDual b) = (Ico b a).map ofDual.toEmbedding := +lemma Finset.Ioc_toDual : Ioc (toDual a) (toDual b) = (Ico b a).map toDual.toEmbedding := map_refl.symm -theorem Ioo_ofDual (a b : αᵒᵈ) : Ioo (ofDual a) (ofDual b) = (Ioo b a).map ofDual.toEmbedding := +lemma Finset.Ioo_toDual : Ioo (toDual a) (toDual b) = (Ioo b a).map toDual.toEmbedding := map_refl.symm +lemma Finset.Icc_ofDual (a b : αᵒᵈ) : + Icc (ofDual a) (ofDual b) = (Icc b a).map ofDual.toEmbedding := map_refl.symm + +lemma Finset.Ico_ofDual (a b : αᵒᵈ) : + Ico (ofDual a) (ofDual b) = (Ioc b a).map ofDual.toEmbedding := map_refl.symm + +lemma Finset.Ioc_ofDual (a b : αᵒᵈ) : + Ioc (ofDual a) (ofDual b) = (Ico b a).map ofDual.toEmbedding := map_refl.symm + +lemma Finset.Ioo_ofDual (a b : αᵒᵈ) : + Ioo (ofDual a) (ofDual b) = (Ioo b a).map ofDual.toEmbedding := map_refl.symm + end LocallyFiniteOrder section LocallyFiniteOrderTop @@ -677,16 +728,16 @@ instance OrderDual.instLocallyFiniteOrderBot : LocallyFiniteOrderBot αᵒᵈ wh finset_mem_Iic _ _ := mem_Ici (α := α) finset_mem_Iio _ _ := mem_Ioi (α := α) -theorem Iic_toDual (a : α) : Iic (toDual a) = (Ici a).map toDual.toEmbedding := +lemma Finset.Iic_toDual (a : α) : Iic (toDual a) = (Ici a).map toDual.toEmbedding := map_refl.symm -theorem Iio_toDual (a : α) : Iio (toDual a) = (Ioi a).map toDual.toEmbedding := +lemma Finset.Iio_toDual (a : α) : Iio (toDual a) = (Ioi a).map toDual.toEmbedding := map_refl.symm -theorem Ici_ofDual (a : αᵒᵈ) : Ici (ofDual a) = (Iic a).map ofDual.toEmbedding := +lemma Finset.Ici_ofDual (a : αᵒᵈ) : Ici (ofDual a) = (Iic a).map ofDual.toEmbedding := map_refl.symm -theorem Ioi_ofDual (a : αᵒᵈ) : Ioi (ofDual a) = (Iio a).map ofDual.toEmbedding := +lemma Finset.Ioi_ofDual (a : αᵒᵈ) : Ioi (ofDual a) = (Iio a).map ofDual.toEmbedding := map_refl.symm end LocallyFiniteOrderTop @@ -707,78 +758,81 @@ instance OrderDual.instLocallyFiniteOrderTop : LocallyFiniteOrderTop αᵒᵈ wh finset_mem_Ici _ _ := mem_Iic (α := α) finset_mem_Ioi _ _ := mem_Iio (α := α) -theorem Ici_toDual (a : α) : Ici (toDual a) = (Iic a).map toDual.toEmbedding := +lemma Finset.Ici_toDual (a : α) : Ici (toDual a) = (Iic a).map toDual.toEmbedding := map_refl.symm -theorem Ioi_toDual (a : α) : Ioi (toDual a) = (Iio a).map toDual.toEmbedding := +lemma Finset.Ioi_toDual (a : α) : Ioi (toDual a) = (Iio a).map toDual.toEmbedding := map_refl.symm -theorem Iic_ofDual (a : αᵒᵈ) : Iic (ofDual a) = (Ici a).map ofDual.toEmbedding := +lemma Finset.Iic_ofDual (a : αᵒᵈ) : Iic (ofDual a) = (Ici a).map ofDual.toEmbedding := map_refl.symm -theorem Iio_ofDual (a : αᵒᵈ) : Iio (ofDual a) = (Ioi a).map ofDual.toEmbedding := +lemma Finset.Iio_ofDual (a : αᵒᵈ) : Iio (ofDual a) = (Ioi a).map ofDual.toEmbedding := map_refl.symm end LocallyFiniteOrderTop -namespace Prod +/-! ### `Prod` -/ + +section LocallyFiniteOrder +variable [LocallyFiniteOrder α] [LocallyFiniteOrder β] [@DecidableRel (α × β) (· ≤ ·)] -instance [LocallyFiniteOrder α] [LocallyFiniteOrder β] - [DecidableRel ((· ≤ ·) : α × β → α × β → Prop)] : LocallyFiniteOrder (α × β) := - LocallyFiniteOrder.ofIcc' (α × β) (fun a b => Icc a.fst b.fst ×ˢ Icc a.snd b.snd) fun a b x => by +instance Prod.instLocallyFiniteOrder : LocallyFiniteOrder (α × β) := + LocallyFiniteOrder.ofIcc' (α × β) (fun x y ↦ Icc x.1 y.1 ×ˢ Icc x.2 y.2) fun a b x => by rw [mem_product, mem_Icc, mem_Icc, and_and_and_comm, le_def, le_def] -instance [LocallyFiniteOrderTop α] [LocallyFiniteOrderTop β] - [DecidableRel ((· ≤ ·) : α × β → α × β → Prop)] : LocallyFiniteOrderTop (α × β) := - LocallyFiniteOrderTop.ofIci' (α × β) (fun a => Ici a.fst ×ˢ Ici a.snd) fun a x => by +lemma Finset.Icc_prod_def (x y : α × β) : Icc x y = Icc x.1 y.1 ×ˢ Icc x.2 y.2 := rfl + +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 _ _ + +end LocallyFiniteOrder + +section LocallyFiniteOrderTop +variable [LocallyFiniteOrderTop α] [LocallyFiniteOrderTop β] [@DecidableRel (α × β) (· ≤ ·)] + +instance Prod.instLocallyFiniteOrderTop : LocallyFiniteOrderTop (α × β) := + LocallyFiniteOrderTop.ofIci' (α × β) (fun x => Ici x.1 ×ˢ Ici x.2) fun a x => by rw [mem_product, mem_Ici, mem_Ici, le_def] -instance [LocallyFiniteOrderBot α] [LocallyFiniteOrderBot β] - [DecidableRel ((· ≤ ·) : α × β → α × β → Prop)] : LocallyFiniteOrderBot (α × β) := - LocallyFiniteOrderBot.ofIic' (α × β) (fun a => Iic a.fst ×ˢ Iic a.snd) fun a x => by - rw [mem_product, mem_Iic, mem_Iic, le_def] +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 := + card_product _ _ -theorem Icc_eq [LocallyFiniteOrder α] [LocallyFiniteOrder β] - [DecidableRel ((· ≤ ·) : α × β → α × β → Prop)] (p q : α × β) : - Finset.Icc p q = Finset.Icc p.1 q.1 ×ˢ Finset.Icc p.2 q.2 := - rfl +end LocallyFiniteOrderTop -@[simp] -theorem Icc_mk_mk [LocallyFiniteOrder α] [LocallyFiniteOrder β] - [DecidableRel ((· ≤ ·) : α × β → α × β → Prop)] (a₁ a₂ : α) (b₁ b₂ : β) : - Finset.Icc (a₁, b₁) (a₂, b₂) = Finset.Icc a₁ a₂ ×ˢ Finset.Icc b₁ b₂ := - rfl +section LocallyFiniteOrderBot +variable [LocallyFiniteOrderBot α] [LocallyFiniteOrderBot β] [@DecidableRel (α × β) (· ≤ ·)] -theorem card_Icc [LocallyFiniteOrder α] [LocallyFiniteOrder β] - [DecidableRel ((· ≤ ·) : α × β → α × β → Prop)] (p q : α × β) : - (Finset.Icc p q).card = (Finset.Icc p.1 q.1).card * (Finset.Icc p.2 q.2).card := - Finset.card_product _ _ +instance Prod.instLocallyFiniteOrderBot : LocallyFiniteOrderBot (α × β) := + LocallyFiniteOrderBot.ofIic' (α × β) (fun x ↦ Iic x.1 ×ˢ Iic x.2) fun a x ↦ by + rw [mem_product, mem_Iic, mem_Iic, le_def] -end Prod +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 _ _ +end LocallyFiniteOrderBot end Preorder -namespace Prod - -variable [Lattice α] [Lattice β] +section Lattice +variable [Lattice α] [Lattice β] [LocallyFiniteOrder α] [LocallyFiniteOrder β] + [@DecidableRel (α × β) (· ≤ ·)] -theorem uIcc_eq [LocallyFiniteOrder α] [LocallyFiniteOrder β] - [DecidableRel ((· ≤ ·) : α × β → α × β → Prop)] (p q : α × β) : - Finset.uIcc p q = Finset.uIcc p.1 q.1 ×ˢ Finset.uIcc p.2 q.2 := - rfl +lemma Finset.uIcc_prod_def (x y : α × β) : uIcc x y = uIcc x.1 y.1 ×ˢ uIcc x.2 y.2 := rfl -@[simp] -theorem uIcc_mk_mk [LocallyFiniteOrder α] [LocallyFiniteOrder β] - [DecidableRel ((· ≤ ·) : α × β → α × β → Prop)] (a₁ a₂ : α) (b₁ b₂ : β) : - Finset.uIcc (a₁, b₁) (a₂, b₂) = Finset.uIcc a₁ a₂ ×ˢ Finset.uIcc b₁ b₂ := - rfl +lemma Finset.uIcc_product_uIcc (a₁ a₂ : α) (b₁ b₂ : β) : + uIcc a₁ a₂ ×ˢ uIcc b₁ b₂ = uIcc (a₁, b₁) (a₂, b₂) := rfl -theorem card_uIcc [LocallyFiniteOrder α] [LocallyFiniteOrder β] - [DecidableRel ((· ≤ ·) : α × β → α × β → Prop)] (p q : α × β) : - (Finset.uIcc p q).card = (Finset.uIcc p.1 q.1).card * (Finset.uIcc p.2 q.2).card := - Prod.card_Icc _ _ +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 _ _ -end Prod +end Lattice /-! #### `WithTop`, `WithBot` @@ -830,7 +884,7 @@ instance locallyFiniteOrder : LocallyFiniteOrder (WithTop α) where rw [← some_eq_coe, some_mem_insertNone, mem_Ici] | (a : α), (b : α), ⊤ => by simp only [Embedding.some, mem_map, mem_Icc, and_false, exists_const, some, le_top, - top_le_iff] + top_le_iff, reduceCtorEq] | (a : α), (b : α), (x : α) => by simp only [le_eq_subset, Embedding.some, mem_map, mem_Icc, Embedding.coeFn_mk, coe_le_coe] -- This used to be in the above `simp` before leanprover/lean4#2644 diff --git a/Mathlib/Order/Interval/Finset/Nat.lean b/Mathlib/Order/Interval/Finset/Nat.lean index 94c2c0add091b..8be56194d6481 100644 --- a/Mathlib/Order/Interval/Finset/Nat.lean +++ b/Mathlib/Order/Interval/Finset/Nat.lean @@ -83,7 +83,7 @@ theorem card_Ioo : (Ioo a b).card = b - a - 1 := @[simp] theorem card_uIcc : (uIcc a b).card = (b - a : ℤ).natAbs + 1 := - (card_Icc _ _).trans $ by rw [← Int.natCast_inj, sup_eq_max, inf_eq_min, Int.ofNat_sub] <;> omega + (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] @@ -187,19 +187,19 @@ 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 - · simp only [zero_add, Nat.zero_eq, Ico_zero_eq_range] + · simp only [zero_add, Ico_zero_eq_range] rintro k hk l hl (hkl : k % a = l % a) simp only [Finset.mem_range, Finset.mem_coe] at hk hl rwa [mod_eq_of_lt hk, mod_eq_of_lt hl] at hkl rw [Ico_succ_left_eq_erase_Ico, succ_add, succ_eq_add_one, Ico_succ_right_eq_insert_Ico (by omega)] rintro k hk l hl (hkl : k % a = l % a) - have ha : 0 < a := Nat.pos_iff_ne_zero.2 $ by rintro rfl; simp at hk + have ha : 0 < a := Nat.pos_iff_ne_zero.2 <| by rintro rfl; simp at hk simp only [Finset.mem_coe, Finset.mem_insert, Finset.mem_erase] at hk hl rcases hk with ⟨hkn, rfl | hk⟩ <;> rcases hl with ⟨hln, rfl | hl⟩ · rfl diff --git a/Mathlib/Order/Interval/Set/Basic.lean b/Mathlib/Order/Interval/Set/Basic.lean index 9533bfe783faa..0be1e96eff231 100644 --- a/Mathlib/Order/Interval/Set/Basic.lean +++ b/Mathlib/Order/Interval/Set/Basic.lean @@ -38,35 +38,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 } @@ -566,11 +566,13 @@ theorem _root_.IsTop.Iic_eq (h : IsTop a) : Iic a = univ := theorem _root_.IsBot.Ici_eq (h : IsBot a) : Ici a = univ := eq_univ_of_forall h -theorem _root_.IsMax.Ioi_eq (h : IsMax a) : Ioi a = ∅ := - eq_empty_of_subset_empty fun _ => h.not_lt +theorem Ioi_eq_empty_iff : Ioi a = ∅ ↔ IsMax a := by + simp only [isMax_iff_forall_not_lt, eq_empty_iff_forall_not_mem, mem_Ioi] -theorem _root_.IsMin.Iio_eq (h : IsMin a) : Iio a = ∅ := - eq_empty_of_subset_empty fun _ => h.not_lt +theorem Iio_eq_empty_iff : Iio a = ∅ ↔ IsMin a := Ioi_eq_empty_iff (α := αᵒᵈ) + +alias ⟨_, _root_.IsMax.Ioi_eq⟩ := Ioi_eq_empty_iff +alias ⟨_, _root_.IsMin.Iio_eq⟩ := Iio_eq_empty_iff theorem Iic_inter_Ioc_of_le (h : a ≤ c) : Iic a ∩ Ioc b c = Ioc b a := ext fun _ => ⟨fun H => ⟨H.2.1, H.1⟩, fun H => ⟨H.2, H.1, H.2.trans h⟩⟩ @@ -618,8 +620,8 @@ theorem Icc_eq_singleton_iff : Icc a b = {c} ↔ a = c ∧ b = c := by refine ⟨fun h => ?_, ?_⟩ · have hab : a ≤ b := nonempty_Icc.1 (h.symm.subst <| singleton_nonempty c) exact - ⟨eq_of_mem_singleton <| h.subst <| left_mem_Icc.2 hab, - eq_of_mem_singleton <| h.subst <| right_mem_Icc.2 hab⟩ + ⟨eq_of_mem_singleton <| h ▸ left_mem_Icc.2 hab, + eq_of_mem_singleton <| h ▸ right_mem_Icc.2 hab⟩ · rintro ⟨rfl, rfl⟩ exact Icc_self _ @@ -952,7 +954,7 @@ theorem Ico_eq_Ico_iff (h : a₁ < b₁ ∨ a₂ < b₂) : Ico a₁ b₁ = Ico a ⟨fun e => by simp only [Subset.antisymm_iff] at e simp only [le_antisymm_iff] - cases' h with h h <;> + rcases h with h | h <;> simp only [gt_iff_lt, not_lt, Ico_subset_Ico_iff h] at e <;> [ rcases e with ⟨⟨h₁, h₂⟩, e'⟩; rcases e with ⟨e', ⟨h₁, h₂⟩⟩ ] <;> -- Porting note: restore `tauto` @@ -1121,7 +1123,7 @@ theorem Icc_union_Ici' (h₁ : c ≤ b) : Icc a b ∪ Ici c = Ici (min a c) := b theorem Icc_union_Ici (h : c ≤ max a b) : Icc a b ∪ Ici c = Ici (min a c) := by rcases le_or_lt a b with hab | hab <;> simp [hab] at h · exact Icc_union_Ici' h - · cases' h with h h + · rcases h with h | h · simp [*] · have hca : c ≤ a := h.trans hab.le simp [*] @@ -1190,7 +1192,7 @@ theorem Iic_union_Ioo_eq_Iio (h : a < b) : Iic a ∪ Ioo a b = Iio b := theorem Iio_union_Ioo' (h₁ : c < b) : Iio b ∪ Ioo c d = Iio (max b d) := by ext x - cases' lt_or_le x b with hba hba + rcases lt_or_le x b with hba | hba · simp [hba, h₁] · simp only [mem_Iio, mem_union, mem_Ioo, lt_max_iff] refine or_congr Iff.rfl ⟨And.right, ?_⟩ @@ -1221,7 +1223,7 @@ theorem Iic_union_Icc' (h₁ : c ≤ b) : Iic b ∪ Icc c d = Iic (max b d) := b theorem Iic_union_Icc (h : min c d ≤ b) : Iic b ∪ Icc c d = Iic (max b d) := by rcases le_or_lt c d with hcd | hcd <;> simp [hcd] at h · exact Iic_union_Icc' h - · cases' h with h h + · rcases h with h | h · have hdb : d ≤ b := hcd.le.trans h simp [*] · simp [*] @@ -1564,16 +1566,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 /-! @@ -1648,3 +1645,22 @@ instance : NoMaxOrder (Set.Iio x) := exact ⟨⟨b, hb₂⟩, hb₁⟩⟩ 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 98810e2ae65b4..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 @@ -431,18 +431,18 @@ lemma directedOn_le_Iic (b : α) : DirectedOn (· ≤ ·) (Iic b) := fun _x hx _y hy ↦ ⟨b, le_rfl, hx, hy⟩ lemma directedOn_le_Icc (a b : α) : DirectedOn (· ≤ ·) (Icc a b) := - fun _x hx _y hy ↦ ⟨b, right_mem_Icc.2 $ hx.1.trans hx.2, hx.2, hy.2⟩ + fun _x hx _y hy ↦ ⟨b, right_mem_Icc.2 <| hx.1.trans hx.2, hx.2, hy.2⟩ lemma directedOn_le_Ioc (a b : α) : DirectedOn (· ≤ ·) (Ioc a b) := - fun _x hx _y hy ↦ ⟨b, right_mem_Ioc.2 $ hx.1.trans_le hx.2, hx.2, hy.2⟩ + fun _x hx _y hy ↦ ⟨b, right_mem_Ioc.2 <| hx.1.trans_le hx.2, hx.2, hy.2⟩ lemma directedOn_ge_Ici (a : α) : DirectedOn (· ≥ ·) (Ici a) := fun _x hx _y hy ↦ ⟨a, le_rfl, hx, hy⟩ lemma directedOn_ge_Icc (a b : α) : DirectedOn (· ≥ ·) (Icc a b) := - fun _x hx _y hy ↦ ⟨a, left_mem_Icc.2 $ hx.1.trans hx.2, hx.1, hy.1⟩ + fun _x hx _y hy ↦ ⟨a, left_mem_Icc.2 <| hx.1.trans hx.2, hx.1, hy.1⟩ lemma directedOn_ge_Ico (a b : α) : DirectedOn (· ≥ ·) (Ico a b) := - fun _x hx _y hy ↦ ⟨a, left_mem_Ico.2 $ hx.1.trans_lt hx.2, hx.1, hy.1⟩ + fun _x hx _y hy ↦ ⟨a, left_mem_Ico.2 <| hx.1.trans_lt hx.2, hx.1, hy.1⟩ end Preorder diff --git a/Mathlib/Order/Interval/Set/Monotone.lean b/Mathlib/Order/Interval/Set/Monotone.lean index d195cedc05460..6b8430931f6c7 100644 --- a/Mathlib/Order/Interval/Set/Monotone.lean +++ b/Mathlib/Order/Interval/Set/Monotone.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Order.Interval.Set.Disjoint -import Mathlib.Order.SuccPred.Basic +import Mathlib.Order.SuccPred.Archimedean /-! # Monotonicity on intervals @@ -159,30 +159,7 @@ section SuccOrder open Order -variable {α β : Type*} [PartialOrder α] - -theorem StrictMonoOn.Iic_id_le [SuccOrder α] [IsSuccArchimedean α] [OrderBot α] {n : α} {φ : α → α} - (hφ : StrictMonoOn φ (Set.Iic n)) : ∀ m ≤ n, m ≤ φ m := by - revert hφ - refine - Succ.rec_bot (fun n => StrictMonoOn φ (Set.Iic n) → ∀ m ≤ n, m ≤ φ m) - (fun _ _ hm => hm.trans bot_le) ?_ _ - rintro k ih hφ m hm - by_cases hk : IsMax k - · rw [succ_eq_iff_isMax.2 hk] at hm - exact ih (hφ.mono <| Iic_subset_Iic.2 (le_succ _)) _ hm - obtain rfl | h := le_succ_iff_eq_or_le.1 hm - · specialize ih (StrictMonoOn.mono hφ fun x hx => le_trans hx (le_succ _)) k le_rfl - refine le_trans (succ_mono ih) (succ_le_of_lt (hφ (le_succ _) le_rfl ?_)) - rw [lt_succ_iff_eq_or_lt_of_not_isMax hk] - exact Or.inl rfl - · exact ih (StrictMonoOn.mono hφ fun x hx => le_trans hx (le_succ _)) _ h - -theorem StrictMonoOn.Ici_le_id [PredOrder α] [IsPredArchimedean α] [OrderTop α] {n : α} {φ : α → α} - (hφ : StrictMonoOn φ (Set.Ici n)) : ∀ m, n ≤ m → φ m ≤ m := - StrictMonoOn.Iic_id_le (α := αᵒᵈ) fun _ hi _ hj hij => hφ hj hi hij - -variable [Preorder β] {ψ : α → β} +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)`. -/ @@ -211,16 +188,61 @@ theorem strictMonoOn_Iic_of_lt_succ [SuccOrder α] [IsSuccArchimedean α] {n : refine hψ _ (lt_of_lt_of_le ?_ hy) rwa [Function.iterate_succ', Function.comp_apply, lt_succ_iff_not_isMax] +theorem strictMono_of_lt_succ [SuccOrder α] [IsSuccArchimedean α] + (hψ : ∀ m, ψ m < ψ (succ m)) : StrictMono ψ := fun _ _ h ↦ + (strictMonoOn_Iic_of_lt_succ fun m _ ↦ hψ m) h.le le_rfl h + theorem strictAntiOn_Iic_of_succ_lt [SuccOrder α] [IsSuccArchimedean α] {n : α} (hψ : ∀ m, m < n → ψ (succ m) < ψ m) : StrictAntiOn ψ (Set.Iic n) := fun i hi j hj hij => @strictMonoOn_Iic_of_lt_succ α βᵒᵈ _ _ ψ _ _ n hψ i hi j hj hij +theorem strictAnti_of_succ_lt [SuccOrder α] [IsSuccArchimedean α] + (hψ : ∀ m, ψ (succ m) < ψ m) : StrictAnti ψ := fun _ _ h ↦ + (strictAntiOn_Iic_of_succ_lt fun m _ ↦ hψ m) h.le le_rfl h + theorem strictMonoOn_Ici_of_pred_lt [PredOrder α] [IsPredArchimedean α] {n : α} (hψ : ∀ m, n < m → ψ (pred m) < ψ m) : StrictMonoOn ψ (Set.Ici n) := fun i hi j hj hij => @strictMonoOn_Iic_of_lt_succ αᵒᵈ βᵒᵈ _ _ ψ _ _ n hψ j hj i hi hij +theorem strictMono_of_pred_lt [PredOrder α] [IsPredArchimedean α] + (hψ : ∀ m, ψ (pred m) < ψ m) : StrictMono ψ := fun _ _ h ↦ + (strictMonoOn_Ici_of_pred_lt fun m _ ↦ hψ m) le_rfl h.le h + theorem strictAntiOn_Ici_of_lt_pred [PredOrder α] [IsPredArchimedean α] {n : α} (hψ : ∀ m, n < m → ψ m < ψ (pred m)) : StrictAntiOn ψ (Set.Ici n) := fun i hi j hj hij => @strictAntiOn_Iic_of_succ_lt αᵒᵈ βᵒᵈ _ _ ψ _ _ n hψ j hj i hi hij +theorem strictAnti_of_lt_pred [PredOrder α] [IsPredArchimedean α] + (hψ : ∀ m, ψ m < ψ (pred m)) : StrictAnti ψ := fun _ _ h ↦ + (strictAntiOn_Ici_of_lt_pred fun m _ ↦ hψ m) le_rfl h.le h + end SuccOrder + +section LinearOrder + +open Order + +variable {α : Type*} [LinearOrder α] + +theorem StrictMonoOn.Iic_id_le [SuccOrder α] [IsSuccArchimedean α] [OrderBot α] {n : α} {φ : α → α} + (hφ : StrictMonoOn φ (Set.Iic n)) : ∀ m ≤ n, m ≤ φ m := by + revert hφ + refine + Succ.rec_bot (fun n => StrictMonoOn φ (Set.Iic n) → ∀ m ≤ n, m ≤ φ m) + (fun _ _ hm => hm.trans bot_le) ?_ _ + rintro k ih hφ m hm + by_cases hk : IsMax k + · rw [succ_eq_iff_isMax.2 hk] at hm + exact ih (hφ.mono <| Iic_subset_Iic.2 (le_succ _)) _ hm + obtain rfl | h := le_succ_iff_eq_or_le.1 hm + · specialize ih (StrictMonoOn.mono hφ fun x hx => le_trans hx (le_succ _)) k le_rfl + refine le_trans (succ_mono ih) (succ_le_of_lt (hφ (le_succ _) le_rfl ?_)) + rw [lt_succ_iff_eq_or_lt_of_not_isMax hk] + exact Or.inl rfl + · exact ih (StrictMonoOn.mono hφ fun x hx => le_trans hx (le_succ _)) _ h + +theorem StrictMonoOn.Ici_le_id [PredOrder α] [IsPredArchimedean α] [OrderTop α] {n : α} {φ : α → α} + (hφ : StrictMonoOn φ (Set.Ici n)) : ∀ m, n ≤ m → φ m ≤ m := + StrictMonoOn.Iic_id_le (α := αᵒᵈ) fun _ hi _ hj hij => hφ hj hi hij + +end LinearOrder 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..ea241a7fbf3dc 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, @@ -134,7 +134,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 +155,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 +187,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 +294,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/Interval/Set/WithBotTop.lean b/Mathlib/Order/Interval/Set/WithBotTop.lean index d5f2e62b5a1b9..a742d1b937b80 100644 --- a/Mathlib/Order/Interval/Set/WithBotTop.lean +++ b/Mathlib/Order/Interval/Set/WithBotTop.lean @@ -5,6 +5,7 @@ Authors: Yury Kudryashov -/ import Mathlib.Data.Set.Image import Mathlib.Order.Interval.Set.Basic +import Mathlib.Order.WithBot /-! # Intervals in `WithTop α` and `WithBot α` diff --git a/Mathlib/Order/Irreducible.lean b/Mathlib/Order/Irreducible.lean index ecc3744d96ae4..12ebc35f11d80 100644 --- a/Mathlib/Order/Irreducible.lean +++ b/Mathlib/Order/Irreducible.lean @@ -251,7 +251,7 @@ end SemilatticeInf section DistribLattice -variable [DistribLattice α] {a b c : α} +variable [DistribLattice α] {a : α} @[simp] theorem supPrime_iff_supIrred : SupPrime a ↔ SupIrred a := diff --git a/Mathlib/Order/IsWellOrderLimitElement.lean b/Mathlib/Order/IsWellOrderLimitElement.lean index 1628b90dac2f6..2d6bde7b9282b 100644 --- a/Mathlib/Order/IsWellOrderLimitElement.lean +++ b/Mathlib/Order/IsWellOrderLimitElement.lean @@ -25,7 +25,7 @@ section variable [IsWellOrder α (· < ·)] /-- Given an element `a : α` in a well ordered set, this is the successor of `a`, -i.e. the smallest element stricly greater than `a` if it exists (or `a` itself otherwise). -/ +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 diff --git a/Mathlib/Order/Iterate.lean b/Mathlib/Order/Iterate.lean index 6e475b270ddfb..05f831756e6a4 100644 --- a/Mathlib/Order/Iterate.lean +++ b/Mathlib/Order/Iterate.lean @@ -39,16 +39,18 @@ lemmas in this section formalize this fact for different inequalities made stric theorem seq_le_seq (hf : Monotone f) (n : ℕ) (h₀ : x 0 ≤ y 0) (hx : ∀ k < n, x (k + 1) ≤ f (x k)) (hy : ∀ k < n, f (y k) ≤ y (k + 1)) : x n ≤ y n := by - induction' n with n ihn - · exact h₀ - · refine (hx _ n.lt_succ_self).trans ((hf <| ihn ?_ ?_).trans (hy _ n.lt_succ_self)) + induction n with + | zero => exact h₀ + | succ n ihn => + refine (hx _ n.lt_succ_self).trans ((hf <| ihn ?_ ?_).trans (hy _ n.lt_succ_self)) · exact fun k hk => hx _ (hk.trans n.lt_succ_self) · exact fun k hk => hy _ (hk.trans n.lt_succ_self) theorem seq_pos_lt_seq_of_lt_of_le (hf : Monotone f) {n : ℕ} (hn : 0 < n) (h₀ : x 0 ≤ y 0) (hx : ∀ k < n, x (k + 1) < f (x k)) (hy : ∀ k < n, f (y k) ≤ y (k + 1)) : x n < y n := by - induction' n with n ihn - · exact hn.false.elim + induction n with + | zero => exact hn.false.elim + | succ n ihn => suffices x n ≤ y n from (hx n n.lt_succ_self).trans_le ((hf this).trans <| hy n n.lt_succ_self) cases n with | zero => exact h₀ diff --git a/Mathlib/Order/KonigLemma.lean b/Mathlib/Order/KonigLemma.lean index 64ff1a4d6bd67..b38fa275198d5 100644 --- a/Mathlib/Order/KonigLemma.lean +++ b/Mathlib/Order/KonigLemma.lean @@ -69,7 +69,7 @@ theorem exists_orderEmbedding_covby_of_forall_covby_finite (hfin : ∀ (a : α), obtain ⟨f, hf⟩ := exists_seq_covby_of_forall_covby_finite hfin hb exact ⟨OrderEmbedding.ofStrictMono f (strictMono_nat_of_lt_succ (fun i ↦ (hf.2 i).lt)), hf⟩ -/-- A version of Kőnig's lemma where the sequence starts at the minimum of an infinite order. -/ +/-- A version of Kőnig's lemma where the sequence starts at the minimum of an infinite order. -/ theorem exists_orderEmbedding_covby_of_forall_covby_finite_of_bot [OrderBot α] [Infinite α] (hfin : ∀ (a : α), {x | a ⋖ x}.Finite) : ∃ f : ℕ ↪o α, f 0 = ⊥ ∧ ∀ i, f i ⋖ f (i+1) := exists_orderEmbedding_covby_of_forall_covby_finite hfin (by simpa using infinite_univ) @@ -79,8 +79,9 @@ theorem GradeMinOrder.exists_nat_orderEmbedding_of_forall_covby_finite ∃ f : ℕ ↪o α, f 0 = ⊥ ∧ (∀ i, f i ⋖ f (i+1)) ∧ ∀ i, grade ℕ (f i) = i := by obtain ⟨f, h0, hf⟩ := exists_orderEmbedding_covby_of_forall_covby_finite_of_bot hfin refine ⟨f, h0, hf, fun i ↦ ?_⟩ - induction' i with i ih; simp [h0] - simpa [Nat.covBy_iff_succ_eq, ih, eq_comm] using CovBy.grade ℕ <| hf i + induction' i with i ih + · simp [h0] + · simpa [Order.covBy_iff_add_one_eq, ih, eq_comm] using CovBy.grade ℕ <| hf i end Sequence diff --git a/Mathlib/Order/KrullDimension.lean b/Mathlib/Order/KrullDimension.lean index 6847b5762d6a8..4631e6250c4ba 100644 --- a/Mathlib/Order/KrullDimension.lean +++ b/Mathlib/Order/KrullDimension.lean @@ -1,26 +1,36 @@ /- Copyright (c) 2023 Jujian Zhang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Jujian Zhang, Fangming Li +Authors: Jujian Zhang, Fangming Li, Joachim Breitner -/ import Mathlib.Order.RelSeries -import Mathlib.Order.WithBot -import Mathlib.Data.Nat.Lattice +import Mathlib.Data.ENat.Lattice /-! -# Krull dimension of a preordered set +# Krull dimension of a preordered set and height of an element + +If `α` is a preordered set, then `krullDim α : WithBot ℕ∞` is defined to be +`sup {n | a₀ < a₁ < ... < aₙ}`. -If `α` is a preordered set, then `krullDim α` is defined to be `sup {n | a₀ < a₁ < ... < aₙ}`. In case that `α` is empty, then its Krull dimension is defined to be negative infinity; if the -length of all series `a₀ < a₁ < ... < aₙ` is unbounded, then its Krull dimension is defined to -be positive infinity. +length of all series `a₀ < a₁ < ... < aₙ` is unbounded, then its Krull dimension is defined to be +positive infinity. + +For `a : α`, its height (in `ℕ∞`) is defined to be `sup {n | a₀ < a₁ < ... < aₙ ≤ a}` while its +coheight is defined to be `sup {n | a ≤ a₀ < a₁ < ... < aₙ}` . + +## Main results + +* The Krull dimension is the same as that of the dual order (`krullDim_orderDual`). -For `a : α`, its height is defined to be the krull dimension of the subset `(-∞, a]` while its -coheight is defined to be the krull dimension of `[a, +∞)`. +* The Krull dimension is the supremum of the heights of the elements (`krullDim_eq_iSup_height`). -## Implementation notes -Krull dimensions are defined to take value in `WithBot (WithTop ℕ)` so that `(-∞) + (+∞)` is +* The height is monotone. + +## Design notes + +Krull dimensions are defined to take value in `WithBot ℕ∞` so that `(-∞) + (+∞)` is also negative infinity. This is because we want Krull dimensions to be additive with respect to product of varieties so that `-∞` being the Krull dimension of empty variety is equal to sum of `-∞` and the Krull dimension of any other varieties. @@ -30,40 +40,152 @@ in this file would generalize as well. But we don't think it would be useful, so Krull dimension of a preorder. -/ -section definitions +namespace Order -variable (α : Type*) [Preorder α] +section definitions /-- The **Krull dimension** of a preorder `α` is the supremum of the rightmost index of all relation -series of `α` order by `<`. If there is no series `a₀ < a₁ < ... < aₙ` in `α`, then its Krull +series of `α` ordered by `<`. If there is no series `a₀ < a₁ < ... < aₙ` in `α`, then its Krull dimension is defined to be negative infinity; if the length of all series `a₀ < a₁ < ... < aₙ` is unbounded, its Krull dimension is defined to be positive infinity. -/ -noncomputable def krullDim : WithBot (WithTop ℕ) := +noncomputable def krullDim (α : Type*) [Preorder α] : WithBot ℕ∞ := ⨆ (p : LTSeries α), p.length /-- -Height of an element `a` of a preordered set `α` is the Krull dimension of the subset `(-∞, a]` +The **height** of an element `a` in a preorder `α` is the supremum of the rightmost index of all +relation series of `α` ordered by `<` and ending below or at `a`. -/ -noncomputable def height (a : α) : WithBot (WithTop ℕ) := krullDim (Set.Iic a) +noncomputable def height {α : Type*} [Preorder α] (a : α) : ℕ∞ := + ⨆ (p : LTSeries α) (_ : p.last ≤ a), p.length /-- -Coheight of an element `a` of a pre-ordered set `α` is the Krull dimension of the subset `[a, +∞)` +The **coheight** of an element `a` in a preorder `α` is the supremum of the rightmost index of all +relation series of `α` ordered by `<` and beginning with `a`. + +The definition of `coheight` is via the `height` in the dual order, in order to easily transfer +theorems between `height` and `coheight`. -/ -noncomputable def coheight (a : α) : WithBot (WithTop ℕ) := krullDim (Set.Ici a) +noncomputable def coheight {α : Type*} [Preorder α] (a : α) : ℕ∞ := height (α := αᵒᵈ) a end definitions +/-! +## Height +-/ + +section height + +variable {α β : Type*} + +variable [Preorder α] [Preorder β] + +lemma height_le_iff {a : α} {n : ℕ∞} : + height a ≤ n ↔ ∀ ⦃p : LTSeries α⦄, p.last ≤ a → p.length ≤ n := by + rw [height, iSup₂_le_iff] + +lemma height_le {a : α} {n : ℕ∞} (h : ∀ (p : LTSeries α), p.last = a → p.length ≤ n) : + height a ≤ n := by + apply height_le_iff.mpr + intro p hlast + wlog hlenpos : p.length ≠ 0 + · simp_all + -- We replace the last element in the series with `a` + let p' := p.eraseLast.snoc a (lt_of_lt_of_le (p.eraseLast_last_rel_last (by simp_all)) hlast) + rw [show p.length = p'.length by simp [p']; omega] + apply h + simp [p'] + +lemma height_le_iff' {a : α} {n : ℕ∞} : + height a ≤ n ↔ ∀ ⦃p : LTSeries α⦄, p.last = a → p.length ≤ n := by + constructor + · rw [height_le_iff] + exact fun h p hlast => h (le_of_eq hlast) + · exact height_le + +/-- +Alternative definition of height, with the supremum ranging only over those series that end at `a`. +-/ +lemma height_eq_iSup_last_eq (a : α) : + height a = ⨆ (p : LTSeries α) (_ : p.last = a), ↑(p.length) := by + apply eq_of_forall_ge_iff + intro n + rw [height_le_iff', iSup₂_le_iff] + +lemma length_le_height {p : LTSeries α} {x : α} (hlast : p.last ≤ x) : + p.length ≤ height x := by + by_cases hlen0 : p.length ≠ 0 + · let p' := p.eraseLast.snoc x (by + apply lt_of_lt_of_le + · apply p.step ⟨p.length - 1, by omega⟩ + · convert hlast + simp only [Fin.succ_mk, Nat.succ_eq_add_one, RelSeries.last, Fin.last] + congr; omega) + suffices p'.length ≤ height x by + simp [p'] at this + convert this + norm_cast + omega + refine le_iSup₂_of_le p' ?_ le_rfl + simp [p'] + · simp_all + +/-- +The height of the last element in a series is larger or equal to the length of the series. +-/ +lemma length_le_height_last {p : LTSeries α} : p.length ≤ height p.last := + length_le_height le_rfl + +/-- +The height of an element in a series is larger or equal to its index in the series. +-/ +lemma index_le_height (p : LTSeries α) (i : Fin (p.length + 1)) : i ≤ height (p i) := + length_le_height_last (p := p.take i) + +/-- +In a maximally long series, i.e one as long as the height of the last element, the height of each +element is its index in the series. +-/ +lemma height_eq_index_of_length_eq_height_last {p : LTSeries α} (h : p.length = height p.last) + (i : Fin (p.length + 1)) : height (p i) = i := by + refine le_antisymm (height_le ?_) (index_le_height p i) + intro p' hp' + have hp'' := length_le_height_last (p := p'.smash (p.drop i) (by simpa)) + simp [← h] at hp''; clear h + norm_cast at * + omega + +lemma height_mono : Monotone (α := α) height := + fun _ _ hab ↦ biSup_mono (fun _ hla => hla.trans hab) + +@[gcongr] protected lemma _root_.GCongr.height_le_height (a b : α) (hab : a ≤ b) : + height a ≤ height b := height_mono hab + +end height + +/-! +## Krull dimension +-/ + section krullDim 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⟩ +/-- A definition of krullDim for nonempty `α` that avoids `WithBot` -/ +lemma krullDim_eq_iSup_length [Nonempty α] : + krullDim α = ⨆ (p : LTSeries α), (p.length : ℕ∞) := by + unfold krullDim + rw [WithBot.coe_iSup (OrderTop.bddAbove _)] + rfl + lemma krullDim_eq_bot_of_isEmpty [IsEmpty α] : krullDim α = ⊥ := WithBot.ciSup_empty _ lemma krullDim_eq_top_of_infiniteDimensionalOrder [InfiniteDimensionalOrder α] : @@ -81,9 +203,6 @@ lemma krullDim_eq_top_of_infiniteDimensionalOrder [InfiniteDimensionalOrder α] lemma krullDim_le_of_strictMono (f : α → β) (hf : StrictMono f) : krullDim α ≤ krullDim β := iSup_le <| fun p ↦ le_sSup ⟨p.map f hf, rfl⟩ -lemma height_mono {a b : α} (h : a ≤ b) : height α a ≤ height α b := - krullDim_le_of_strictMono (fun x ↦ ⟨x, le_trans x.2 h⟩) <| fun _ _ ↦ id - lemma krullDim_eq_length_of_finiteDimensionalOrder [FiniteDimensionalOrder α] : krullDim α = (LTSeries.longestOf α).length := le_antisymm @@ -97,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 α := @@ -106,15 +233,29 @@ lemma krullDim_eq_of_orderIso (f : α ≃o β) : krullDim α = krullDim β := le_antisymm (krullDim_le_of_strictMono _ f.strictMono) <| krullDim_le_of_strictMono _ f.symm.strictMono -lemma krullDim_eq_iSup_height : krullDim α = ⨆ (a : α), height α a := - le_antisymm - (iSup_le fun i ↦ le_iSup_of_le (i ⟨i.length, lt_add_one _⟩) <| - le_sSup ⟨⟨_, fun m ↦ ⟨i m, i.strictMono.monotone <| show m.1 ≤ i.length by omega⟩, - i.step⟩, rfl⟩) <| - iSup_le fun a ↦ krullDim_le_of_strictMono Subtype.val fun _ _ h ↦ h - @[simp] lemma krullDim_orderDual : krullDim αᵒᵈ = krullDim α := le_antisymm (iSup_le fun i ↦ le_sSup ⟨i.reverse, rfl⟩) <| iSup_le fun i ↦ le_sSup ⟨i.reverse, rfl⟩ +/-- +The Krull dimension is the supremum of the elements' heights. +-/ +lemma krullDim_eq_iSup_height : krullDim α = ⨆ (a : α), ↑(height a) := by + cases isEmpty_or_nonempty α with + | inl h => simp [krullDim_eq_bot_of_isEmpty] + | inr h => + rw [← WithBot.coe_iSup (OrderTop.bddAbove _)] + apply le_antisymm + · apply iSup_le + intro p + suffices p.length ≤ ⨆ (a : α), height a by + exact (WithBot.unbot'_le_iff fun _ => this).mp this + apply le_iSup_of_le p.last (length_le_height_last (p := p)) + · rw [krullDim_eq_iSup_length] + simp only [WithBot.coe_le_coe, iSup_le_iff] + intro x + exact height_le fun p _ ↦ le_iSup_of_le p le_rfl + end krullDim + +end Order diff --git a/Mathlib/Order/Lattice.lean b/Mathlib/Order/Lattice.lean index 9266523b8ef6a..8383d090d9c12 100644 --- a/Mathlib/Order/Lattice.lean +++ b/Mathlib/Order/Lattice.lean @@ -4,10 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl -/ import Mathlib.Data.Bool.Basic -import Mathlib.Order.Defs import Mathlib.Order.Monotone.Basic import Mathlib.Order.ULift -import Mathlib.Tactic.GCongr.Core +import Mathlib.Tactic.GCongr.CoreAttrs /-! # (Semi-)lattices @@ -197,7 +196,7 @@ instance : Std.Commutative (α := α) (· ⊔ ·) := ⟨sup_comm⟩ theorem sup_assoc (a b c : α) : a ⊔ b ⊔ c = a ⊔ (b ⊔ c) := eq_of_forall_ge_iff fun x => by simp only [sup_le_iff]; rw [and_assoc] -instance : Std.Associative (α := α) (· ⊔ ·) := ⟨sup_assoc⟩ +instance : Std.Associative (α := α) (· ⊔ ·) := ⟨sup_assoc⟩ theorem sup_left_right_swap (a b c : α) : a ⊔ b ⊔ c = c ⊔ b ⊔ a := by rw [sup_comm, sup_comm a, sup_assoc] @@ -529,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 @@ -902,9 +901,27 @@ theorem map_inf_le [SemilatticeInf α] [SemilatticeInf β] {f : α → β} (h : f (x ⊓ y) ≤ f x ⊓ f y := le_inf (h inf_le_left) (h inf_le_right) +theorem of_map_inf_le_left [SemilatticeInf α] [Preorder β] {f : α → β} + (h : ∀ x y, f (x ⊓ y) ≤ f x) : Monotone f := by + intro x y hxy + rw [← inf_eq_right.2 hxy] + apply h + +theorem of_map_inf_le [SemilatticeInf α] [SemilatticeInf β] {f : α → β} + (h : ∀ x y, f (x ⊓ y) ≤ f x ⊓ f y) : Monotone f := + of_map_inf_le_left fun x y ↦ (h x y).trans inf_le_left + theorem of_map_inf [SemilatticeInf α] [SemilatticeInf β] {f : α → β} (h : ∀ x y, f (x ⊓ y) = f x ⊓ f y) : Monotone f := - fun x y hxy => inf_eq_left.1 <| by rw [← h, inf_eq_left.2 hxy] + of_map_inf_le fun x y ↦ (h x y).le + +theorem of_left_le_map_sup [SemilatticeSup α] [Preorder β] {f : α → β} + (h : ∀ x y, f x ≤ f (x ⊔ y)) : Monotone f := + monotone_dual_iff.1 <| of_map_inf_le_left h + +theorem of_le_map_sup [SemilatticeSup α] [SemilatticeSup β] {f : α → β} + (h : ∀ x y, f x ⊔ f y ≤ f (x ⊔ y)) : Monotone f := + monotone_dual_iff.mp <| of_map_inf_le h theorem of_map_sup [SemilatticeSup α] [SemilatticeSup β] {f : α → β} (h : ∀ x y, f (x ⊔ y) = f x ⊔ f y) : Monotone f := diff --git a/Mathlib/Order/LiminfLimsup.lean b/Mathlib/Order/LiminfLimsup.lean index daf5f974aacdb..0d6faea4d46f6 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 @@ -63,7 +66,7 @@ theorem isBounded_iff : f.IsBounded r ↔ ∃ s ∈ f.sets, ∃ b, s ⊆ { x | r /-- A bounded function `u` is in particular eventually bounded. -/ theorem isBoundedUnder_of {f : Filter β} {u : β → α} : (∃ b, ∀ x, r (u x) b) → f.IsBoundedUnder r u - | ⟨b, hb⟩ => ⟨b, show ∀ᶠ x in f, r (u x) b from eventually_of_forall hb⟩ + | ⟨b, hb⟩ => ⟨b, show ∀ᶠ x in f, r (u x) b from Eventually.of_forall hb⟩ theorem isBounded_bot : IsBounded r ⊥ ↔ Nonempty α := by simp [IsBounded, exists_true_iff_nonempty] @@ -95,7 +98,7 @@ theorem IsBoundedUnder.mono_ge [Preorder β] {l : Filter α} {u v : α → β} IsBoundedUnder.mono_le (β := βᵒᵈ) hu hv theorem isBoundedUnder_const [IsRefl α r] {l : Filter β} {a : α} : IsBoundedUnder r l fun _ => a := - ⟨a, eventually_map.2 <| eventually_of_forall fun _ => refl _⟩ + ⟨a, eventually_map.2 <| Eventually.of_forall fun _ => refl _⟩ theorem IsBounded.isBoundedUnder {q : β → β → Prop} {u : α → β} (hu : ∀ a₀ a₁, r a₀ a₁ → q (u a₀) (u a₁)) : f.IsBounded r → f.IsBoundedUnder q u @@ -105,15 +108,36 @@ theorem IsBoundedUnder.comp {l : Filter γ} {q : β → β → Prop} {u : γ → (hv : ∀ a₀ a₁, r a₀ a₁ → q (v a₀) (v a₁)) : l.IsBoundedUnder r u → l.IsBoundedUnder q (v ∘ u) | ⟨a, h⟩ => ⟨v a, show ∀ᶠ x in map u l, q (v x) (v a) from h.mono fun x => hv x a⟩ +section Preorder +variable [Preorder α] {f : Filter β} {u : β → α} {s : Set β} + +lemma isBoundedUnder_iff_eventually_bddAbove : + f.IsBoundedUnder (· ≤ ·) u ↔ ∃ s, BddAbove (u '' s) ∧ ∀ᶠ x in f, x ∈ s := by + constructor + · rintro ⟨b, hb⟩ + exact ⟨{a | u a ≤ b}, ⟨b, by rintro _ ⟨a, ha, rfl⟩; exact ha⟩, hb⟩ + · rintro ⟨s, ⟨b, hb⟩, hs⟩ + exact ⟨b, hs.mono <| by simpa [upperBounds] using hb⟩ + +lemma isBoundedUnder_iff_eventually_bddBelow : + f.IsBoundedUnder (· ≥ ·) u ↔ ∃ s, BddBelow (u '' s) ∧ ∀ᶠ x in f, x ∈ s := + isBoundedUnder_iff_eventually_bddAbove (α := αᵒᵈ) + +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 [Preorder α] {f : Filter β} {u : β → α} : - BddAbove (Set.range u) → f.IsBoundedUnder (· ≤ ·) u - | ⟨b, hb⟩ => isBoundedUnder_of ⟨b, by simpa [mem_upperBounds] using hb⟩ +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 [Preorder α] {f : Filter β} {u : β → α} : - BddBelow (Set.range u) → f.IsBoundedUnder (· ≥ ·) u - | ⟨b, hb⟩ => isBoundedUnder_of ⟨b, by simpa [mem_lowerBounds] using hb⟩ +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 : γ → α} {v : α → β} (hv : Monotone v) (hl : l.IsBoundedUnder (· ≤ ·) u) : @@ -238,12 +262,12 @@ lemma isCoboundedUnder_ge_of_eventually_le [Preorder α] (l : Filter ι) [NeBot lemma isCoboundedUnder_le_of_le [Preorder α] (l : Filter ι) [NeBot l] {f : ι → α} {x : α} (hf : ∀ i, x ≤ f i) : IsCoboundedUnder (· ≤ ·) l f := - isCoboundedUnder_le_of_eventually_le l (eventually_of_forall hf) + isCoboundedUnder_le_of_eventually_le l (Eventually.of_forall hf) lemma isCoboundedUnder_ge_of_le [Preorder α] (l : Filter ι) [NeBot l] {f : ι → α} {x : α} (hf : ∀ i, f i ≤ x) : IsCoboundedUnder (· ≥ ·) l f := - isCoboundedUnder_ge_of_eventually_le l (eventually_of_forall hf) + isCoboundedUnder_ge_of_eventually_le l (Eventually.of_forall hf) theorem isCobounded_bot : IsCobounded r ⊥ ↔ ∃ b, ∀ x, r b x := by simp [IsCobounded] @@ -350,10 +374,10 @@ theorem isCobounded_ge_of_top [Preorder α] [OrderTop α] {f : Filter α} : f.Is ⟨⊤, fun _ _ => le_top⟩ theorem isBounded_le_of_top [Preorder α] [OrderTop α] {f : Filter α} : f.IsBounded (· ≤ ·) := - ⟨⊤, eventually_of_forall fun _ => le_top⟩ + ⟨⊤, Eventually.of_forall fun _ => le_top⟩ theorem isBounded_ge_of_bot [Preorder α] [OrderBot α] {f : Filter α} : f.IsBounded (· ≥ ·) := - ⟨⊥, eventually_of_forall fun _ => bot_le⟩ + ⟨⊥, Eventually.of_forall fun _ => bot_le⟩ @[simp] theorem _root_.OrderIso.isBoundedUnder_le_comp [Preorder α] [Preorder β] (e : α ≃o β) {l : Filter γ} @@ -388,8 +412,8 @@ theorem isBoundedUnder_le_sup [SemilatticeSup α] {f : Filter β} {u v : β → (f.IsBoundedUnder (· ≤ ·) fun a => u a ⊔ v a) ↔ f.IsBoundedUnder (· ≤ ·) u ∧ f.IsBoundedUnder (· ≤ ·) v := ⟨fun h => - ⟨h.mono_le <| eventually_of_forall fun _ => le_sup_left, - h.mono_le <| eventually_of_forall fun _ => le_sup_right⟩, + ⟨h.mono_le <| Eventually.of_forall fun _ => le_sup_left, + h.mono_le <| Eventually.of_forall fun _ => le_sup_right⟩, fun h => h.1.sup h.2⟩ theorem IsBoundedUnder.inf [SemilatticeInf α] {f : Filter β} {u v : β → α} : @@ -430,7 +454,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`, @@ -619,12 +643,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 @@ -728,7 +757,7 @@ theorem bliminf_false {f : Filter β} {u : β → α} : (bliminf u f fun _ => Fa @[simp] theorem limsup_const_bot {f : Filter β} : limsup (fun _ : β => (⊥ : α)) f = (⊥ : α) := by rw [limsup_eq, eq_bot_iff] - exact sInf_le (eventually_of_forall fun _ => le_rfl) + exact sInf_le (Eventually.of_forall fun _ => le_rfl) /-- Same as limsup_const applied to `⊤` but without the `NeBot f` assumption -/ @[simp] @@ -753,10 +782,10 @@ theorem limsInf_eq_iSup_sInf {f : Filter α} : limsInf f = ⨆ s ∈ f, sInf s : limsSup_eq_iInf_sSup (α := αᵒᵈ) theorem limsup_le_iSup {f : Filter β} {u : β → α} : limsup u f ≤ ⨆ n, u n := - limsup_le_of_le (by isBoundedDefault) (eventually_of_forall (le_iSup u)) + limsup_le_of_le (by isBoundedDefault) (Eventually.of_forall (le_iSup u)) theorem iInf_le_liminf {f : Filter β} {u : β → α} : ⨅ n, u n ≤ liminf u f := - le_liminf_of_le (by isBoundedDefault) (eventually_of_forall (iInf_le u)) + le_liminf_of_le (by isBoundedDefault) (Eventually.of_forall (iInf_le u)) /-- In a complete lattice, the limsup of a function is the infimum over sets `s` in the filter of the supremum of the function over `s` -/ @@ -773,6 +802,23 @@ 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] +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 simp only [blimsup_eq] @@ -890,13 +936,13 @@ theorem mono_blimsup' (h : ∀ᶠ x in f, p x → u x ≤ v x) : blimsup u f p sInf_le_sInf fun _ ha => (ha.and h).mono fun _ hx hx' => (hx.2 hx').trans (hx.1 hx') theorem mono_blimsup (h : ∀ x, p x → u x ≤ v x) : blimsup u f p ≤ blimsup v f p := - mono_blimsup' <| eventually_of_forall h + mono_blimsup' <| Eventually.of_forall h theorem mono_bliminf' (h : ∀ᶠ x in f, p x → u x ≤ v x) : bliminf u f p ≤ bliminf v f p := sSup_le_sSup fun _ ha => (ha.and h).mono fun _ hx hx' => (hx.1 hx').trans (hx.2 hx') theorem mono_bliminf (h : ∀ x, p x → u x ≤ v x) : bliminf u f p ≤ bliminf v f p := - mono_bliminf' <| eventually_of_forall h + mono_bliminf' <| Eventually.of_forall h theorem bliminf_antitone_filter (h : f ≤ g) : bliminf u g p ≤ bliminf u f p := sSup_le_sSup fun _ ha => ha.filter_mono h @@ -1075,11 +1121,11 @@ theorem liminf_sdiff [NeBot f] (a : α) : liminf u f \ a = liminf (fun b => u b theorem sdiff_limsup [NeBot f] (a : α) : a \ limsup u f = liminf (fun b => a \ u b) f := by rw [← compl_inj_iff] - simp only [sdiff_eq, liminf_compl, (· ∘ ·), compl_inf, compl_compl, sup_limsup] + simp only [sdiff_eq, liminf_compl, comp_def, compl_inf, compl_compl, sup_limsup] theorem sdiff_liminf (a : α) : a \ liminf u f = limsup (fun b => a \ u b) f := by rw [← compl_inj_iff] - simp only [sdiff_eq, limsup_compl, (· ∘ ·), compl_inf, compl_compl, sup_liminf] + simp only [sdiff_eq, limsup_compl, comp_def, compl_inf, compl_compl, sup_liminf] end CompleteBooleanAlgebra @@ -1113,12 +1159,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) : @@ -1476,8 +1522,8 @@ theorem limsup_max [ConditionallyCompleteLinearOrder β] {f : Filter α} {u v : have hv := eventually_lt_of_limsup_lt (lt_of_le_of_lt (le_max_right _ _) hb) h₄ refine mem_of_superset (inter_mem hu hv) (fun _ ↦ by simp) · exact max_le (c := limsup (fun a ↦ max (u a) (v a)) f) - (limsup_le_limsup (eventually_of_forall (fun a : α ↦ le_max_left (u a) (v a))) h₁ bddmax) - (limsup_le_limsup (eventually_of_forall (fun a : α ↦ le_max_right (u a) (v a))) h₂ bddmax) + (limsup_le_limsup (Eventually.of_forall (fun a : α ↦ le_max_left (u a) (v a))) h₁ bddmax) + (limsup_le_limsup (Eventually.of_forall (fun a : α ↦ le_max_right (u a) (v a))) h₂ bddmax) theorem liminf_min [ConditionallyCompleteLinearOrder β] {f : Filter α} {u v : α → β} (h₁ : f.IsCoboundedUnder (· ≥ ·) u := by isBoundedDefault) @@ -1558,7 +1604,7 @@ theorem limsup_finset_sup' [ConditionallyCompleteLinearOrder β] {f : Filter α} exact lt_of_le_of_lt (Finset.le_sup' (f := fun i ↦ limsup (F i) f) i_s) hb · simp only [mem_iInter, mem_setOf_eq, Finset.sup'_apply, sup'_lt_iff, imp_self, implies_true] · apply Finset.sup'_le hs (fun i ↦ limsup (F i) f) - refine fun i i_s ↦ limsup_le_limsup (eventually_of_forall (fun a ↦ ?_)) (h₁ i i_s) bddsup + refine fun i i_s ↦ limsup_le_limsup (Eventually.of_forall (fun a ↦ ?_)) (h₁ i i_s) bddsup simp only [Finset.sup'_apply, le_sup'_iff] use i, i_s @@ -1604,7 +1650,7 @@ lemma IsCobounded.frequently_ge [NeBot F] (cobdd : IsCobounded (· ≤ ·) F) : ∃ l, ∃ᶠ x in F, l ≤ x := by obtain ⟨t, ht⟩ := cobdd by_cases tbot : IsBot t - · refine ⟨t, frequently_of_forall fun r ↦ tbot r⟩ + · refine ⟨t, Frequently.of_forall fun r ↦ tbot r⟩ obtain ⟨t', ht'⟩ : ∃ t', t' < t := by by_contra! exact tbot this @@ -1690,3 +1736,5 @@ lemma Antitone.isCoboundedUnder_ge_of_isCobounded {f : R → S} (f_decr : Antito Monotone.isCoboundedUnder_le_of_isCobounded (S := Sᵒᵈ) f_decr cobdd end frequently_bounded + +set_option linter.style.longFile 1800 diff --git a/Mathlib/Order/Max.lean b/Mathlib/Order/Max.lean index 8938fb68ba6e2..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 @@ -332,11 +332,31 @@ protected theorem IsMax.eq_of_le (ha : IsMax a) (h : a ≤ b) : a = b := protected theorem IsMax.eq_of_ge (ha : IsMax a) (h : a ≤ b) : b = a := h.antisymm' <| ha h +protected theorem IsBot.lt_of_ne (ha : IsBot a) (h : a ≠ b) : a < b := + (ha b).lt_of_ne h + +protected theorem IsTop.lt_of_ne (ha : IsTop a) (h : b ≠ a) : b < a := + (ha b).lt_of_ne h + +protected theorem IsBot.not_isMax [Nontrivial α] (ha : IsBot a) : ¬ IsMax a := by + intro ha' + obtain ⟨b, hb⟩ := exists_ne a + exact hb <| ha'.eq_of_ge (ha.lt_of_ne hb.symm).le + +protected theorem IsTop.not_isMin [Nontrivial α] (ha : IsTop a) : ¬ IsMin a := + ha.toDual.not_isMax + +protected theorem IsBot.not_isTop [Nontrivial α] (ha : IsBot a) : ¬ IsTop a := + mt IsTop.isMax ha.not_isMax + +protected theorem IsTop.not_isBot [Nontrivial α] (ha : IsTop a) : ¬ IsBot a := + ha.toDual.not_isTop + 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..f815d61f44816 100644 --- a/Mathlib/Order/MinMax.lean +++ b/Mathlib/Order/MinMax.lean @@ -3,6 +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.Init.Logic +import Mathlib.Logic.OpClass import Mathlib.Order.Lattice /-! @@ -188,14 +190,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 +236,26 @@ 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 +theorem max_left_commutative : LeftCommutative (max : α → α → α) := ⟨max_left_comm⟩ +theorem min_left_commutative : LeftCommutative (min : α → α → α) := ⟨min_left_comm⟩ -instance : Std.Commutative (α := α) max where - comm := max_comm +section deprecated +set_option linter.deprecated false -instance : Std.Associative (α := α) max where - assoc := max_assoc +@[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 -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 +end deprecated end diff --git a/Mathlib/Order/Minimal.lean b/Mathlib/Order/Minimal.lean index eec9b8aea31ce..cfc38ab8c1e32 100644 --- a/Mathlib/Order/Minimal.lean +++ b/Mathlib/Order/Minimal.lean @@ -381,7 +381,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 +621,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 0f3392396dadb..7b2b7f77ae7f8 100644 --- a/Mathlib/Order/ModularLattice.lean +++ b/Mathlib/Order/ModularLattice.lean @@ -218,33 +218,30 @@ 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 γ] - (h₁ : WellFounded ((· < ·) : β → β → Prop)) (h₂ : WellFounded ((· < ·) : γ → γ → Prop)) (K : α) + [h₁ : WellFoundedLT β] [h₂ : WellFoundedLT γ] (K : α) (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) : - WellFounded ((· < ·) : α → α → Prop) := - 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₁.prod_lex h₂)) + WellFoundedLT α := + 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. -/ + `N` and `M / N` are both Noetherian, then `M` is Noetherian. -/ theorem wellFounded_gt_exact_sequence {β γ : Type*} [Preorder β] [PartialOrder γ] - (h₁ : WellFounded ((· > ·) : β → β → Prop)) (h₂ : WellFounded ((· > ·) : γ → γ → Prop)) (K : α) + [WellFoundedGT β] [WellFoundedGT γ] (K : α) (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) : - WellFounded ((· > ·) : α → α → Prop) := + WellFoundedGT α := wellFounded_lt_exact_sequence (α := αᵒᵈ) (β := γᵒᵈ) (γ := βᵒᵈ) - h₂ h₁ K g₁ g₂ f₁ f₂ gi.dual gci.dual hg hf + K g₁ g₂ f₁ f₂ gi.dual gci.dual hg hf /-- The diamond isomorphism between the intervals `[a ⊓ b, a]` and `[b, a ⊔ b]` -/ @[simps] @@ -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 21ba540d248fb..bafac4b6ac367 100644 --- a/Mathlib/Order/Monotone/Basic.lean +++ b/Mathlib/Order/Monotone/Basic.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Mario Carneiro, Yaël Dillies -/ import Mathlib.Logic.Function.Iterate -import Mathlib.Init.Data.Int.Order +import Mathlib.Data.Int.Order.Basic import Mathlib.Order.Compare import Mathlib.Order.Max import Mathlib.Order.RelClasses @@ -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 @@ -541,9 +540,10 @@ theorem StrictAnti.isMin_of_apply (hf : StrictAnti f) (ha : IsMax (f a)) : IsMin lemma StrictMono.add_le_nat {f : ℕ → ℕ} (hf : StrictMono f) (m n : ℕ) : m + f n ≤ f (m + n) := by rw [Nat.add_comm m, Nat.add_comm m] - induction' m with m ih - · rw [Nat.add_zero, Nat.add_zero] - · rw [← Nat.add_assoc, ← Nat.add_assoc, Nat.succ_le] + induction m with + | zero => rw [Nat.add_zero, Nat.add_zero] + | succ m ih => + rw [← Nat.add_assoc, ← Nat.add_assoc, Nat.succ_le] exact ih.trans_lt (hf (n + m).lt_succ_self) protected theorem StrictMono.ite' (hf : StrictMono f) (hg : StrictMono g) {p : α → Prop} @@ -876,8 +876,9 @@ variable [Preorder α] theorem Nat.rel_of_forall_rel_succ_of_le_of_lt (r : β → β → Prop) [IsTrans β r] {f : ℕ → β} {a : ℕ} (h : ∀ n, a ≤ n → r (f n) (f (n + 1))) ⦃b c : ℕ⦄ (hab : a ≤ b) (hbc : b < c) : r (f b) (f c) := by - induction' hbc with k b_lt_k r_b_k - exacts [h _ hab, _root_.trans r_b_k (h _ (hab.trans_lt b_lt_k).le)] + induction hbc with + | refl => exact h _ hab + | step b_lt_k r_b_k => exact _root_.trans r_b_k (h _ (hab.trans_lt b_lt_k).le) theorem Nat.rel_of_forall_rel_succ_of_le_of_le (r : β → β → Prop) [IsRefl β r] [IsTrans β r] {f : ℕ → β} {a : ℕ} (h : ∀ n, a ≤ n → r (f n) (f (n + 1))) @@ -937,11 +938,9 @@ theorem Int.rel_of_forall_rel_succ_of_lt (r : β → β → Prop) [IsTrans β r] (h : ∀ n, r (f n) (f (n + 1))) ⦃a b : ℤ⦄ (hab : a < b) : r (f a) (f b) := by rcases lt.dest hab with ⟨n, rfl⟩ clear hab - induction' n with n ihn - · rw [Int.ofNat_one] - apply h - · rw [Int.ofNat_succ, ← Int.add_assoc] - exact _root_.trans ihn (h _) + induction n with + | zero => rw [Int.ofNat_one]; apply h + | succ n ihn => rw [Int.ofNat_succ, ← Int.add_assoc]; exact _root_.trans ihn (h _) theorem Int.rel_of_forall_rel_succ_of_le (r : β → β → Prop) [IsRefl β r] [IsTrans β r] {f : ℤ → β} (h : ∀ n, r (f n) (f (n + 1))) ⦃a b : ℤ⦄ (hab : a ≤ b) : r (f a) (f b) := @@ -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 483265ced58b1..9dcfecb90a91f 100644 --- a/Mathlib/Order/Monotone/Monovary.lean +++ b/Mathlib/Order/Monotone/Monovary.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.Set.Defs +import Mathlib.Data.Set.Operations import Mathlib.Order.Lattice /-! @@ -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`. -/ @@ -249,7 +249,7 @@ end PartialOrder variable [LinearOrder ι] /- Porting note: Due to a bug in `alias`, many of the below lemmas have dot notation removed in the -proof-/ +proof -/ protected theorem Monotone.monovary (hf : Monotone f) (hg : Monotone g) : Monovary f g := fun _ _ hij => hf (hg.reflect_lt hij).le @@ -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/Notation.lean b/Mathlib/Order/Notation.lean index cccd2eb9733f8..3f7c605518e6d 100644 --- a/Mathlib/Order/Notation.lean +++ b/Mathlib/Order/Notation.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, Yaël Dillies -/ -import Mathlib.Tactic.Basic +import Mathlib.Tactic.TypeStar import Mathlib.Tactic.Simps.NotationClass /-! diff --git a/Mathlib/Order/OmegaCompletePartialOrder.lean b/Mathlib/Order/OmegaCompletePartialOrder.lean index 79843f6802093..911cd139607e1 100644 --- a/Mathlib/Order/OmegaCompletePartialOrder.lean +++ b/Mathlib/Order/OmegaCompletePartialOrder.lean @@ -1,12 +1,15 @@ /- Copyright (c) 2020 Simon Hudon. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Simon Hudon +Authors: Simon Hudon, Ira Fesefeldt -/ import Mathlib.Control.Monad.Basic +import Mathlib.Dynamics.FixedPoints.Basic import Mathlib.Order.Chain import Mathlib.Order.Hom.Order +import Mathlib.Order.Iterate import Mathlib.Order.Part +import Mathlib.Order.ScottContinuity /-! # Omega Complete Partial Orders @@ -54,6 +57,7 @@ supremum helps define the meaning of recursive procedures. assert_not_exists OrderedCommMonoid universe u v +variable {ι : Sort*} {α β γ δ : Type*} namespace OmegaCompletePartialOrder @@ -64,8 +68,6 @@ def Chain (α : Type u) [Preorder α] := ℕ →o α namespace Chain - -variable {α : Type u} {β : Type v} {γ : Type*} variable [Preorder α] [Preorder β] [Preorder γ] instance : FunLike (Chain α) ℕ α := inferInstanceAs <| FunLike (ℕ →o α) ℕ α @@ -76,7 +78,7 @@ instance [Inhabited α] : Inhabited (Chain α) := ⟨⟨default, fun _ _ _ => le_rfl⟩⟩ instance : Membership α (Chain α) := - ⟨fun a (c : ℕ →o α) => ∃ i, a = c i⟩ + ⟨fun (c : ℕ →o α) a => ∃ i, a = c i⟩ variable (c c' : Chain α) variable (f : α →o β) @@ -131,6 +133,23 @@ def zip (c₀ : Chain α) (c₁ : Chain β) : Chain (α × β) := @[simp] theorem zip_coe (c₀ : Chain α) (c₁ : Chain β) (n : ℕ) : c₀.zip c₁ n = (c₀ n, c₁ n) := rfl +/-- An example of a `Chain` constructed from an ordered pair. -/ +def pair (a b : α) (hab : a ≤ b) : Chain α where + toFun n := match n with + | 0 => a + | _ => b + monotone' _ _ _ := by aesop + +@[simp] lemma pair_zero (a b : α) (hab) : pair a b hab 0 = a := rfl +@[simp] lemma pair_succ (a b : α) (hab) (n : ℕ) : pair a b hab (n + 1) = b := rfl + +@[simp] lemma range_pair (a b : α) (hab) : Set.range (pair a b hab) = {a, b} := by + ext; exact Nat.or_exists_add_one.symm.trans (by aesop) + +@[simp] lemma pair_zip_pair (a₁ a₂ : α) (b₁ b₂ : β) (ha hb) : + (pair a₁ a₂ ha).zip (pair b₁ b₂ hb) = pair (a₁, b₁) (a₂, b₂) (Prod.le_def.2 ⟨ha, hb⟩) := by + unfold Chain; ext n : 2; cases n <;> rfl + end Chain end OmegaCompletePartialOrder @@ -154,8 +173,6 @@ class OmegaCompletePartialOrder (α : Type*) extends PartialOrder α where ωSup_le : ∀ (c : Chain α) (x), (∀ i, c i ≤ x) → ωSup c ≤ x namespace OmegaCompletePartialOrder - -variable {α : Type u} {β : Type v} {γ : Type*} variable [OmegaCompletePartialOrder α] /-- Transfer an `OmegaCompletePartialOrder` on `β` to an `OmegaCompletePartialOrder` on `α` @@ -186,7 +203,7 @@ theorem ωSup_le_ωSup_of_le {c₀ c₁ : Chain α} (h : c₀ ≤ c₁) : ωSup obtain ⟨_, h⟩ := h i exact le_trans h (le_ωSup _ _) -theorem ωSup_le_iff (c : Chain α) (x : α) : ωSup c ≤ x ↔ ∀ i, c i ≤ x := by +@[simp] theorem ωSup_le_iff {c : Chain α} {x : α} : ωSup c ≤ x ↔ ∀ i, c i ≤ x := by constructor <;> intros · trans ωSup c · exact le_ωSup _ _ @@ -226,6 +243,61 @@ open Chain variable [OmegaCompletePartialOrder β] variable [OmegaCompletePartialOrder γ] +variable {f : α → β} {g : β → γ} + +/-- A function `f` between `ω`-complete partial orders is `ωScottContinuous` if it is +Scott continuous over chains. -/ +def ωScottContinuous (f : α → β) : Prop := + ScottContinuousOn (Set.range fun c : Chain α => Set.range c) f + +lemma _root_.ScottContinuous.ωScottContinuous (hf : ScottContinuous f) : ωScottContinuous f := + hf.scottContinuousOn + +lemma ωScottContinuous.monotone (h : ωScottContinuous f) : Monotone f := + ScottContinuousOn.monotone _ (fun a b hab => by + use pair a b hab; exact range_pair a b hab) h + +lemma ωScottContinuous.isLUB {c : Chain α} (hf : ωScottContinuous f) : + IsLUB (Set.range (c.map ⟨f, hf.monotone⟩)) (f (ωSup c)) := by + simpa [map_coe, OrderHom.coe_mk, Set.range_comp] + using hf (by simp) (Set.range_nonempty _) (isChain_range c).directedOn (isLUB_range_ωSup c) + +lemma ωScottContinuous.id : ωScottContinuous (id : α → α) := ScottContinuousOn.id + +lemma ωScottContinuous.map_ωSup (hf : ωScottContinuous f) (c : Chain α) : + f (ωSup c) = ωSup (c.map ⟨f, hf.monotone⟩) := ωSup_eq_of_isLUB hf.isLUB + +/-- `ωScottContinuous f` asserts that `f` is both monotone and distributes over ωSup. -/ +lemma ωScottContinuous_iff_monotone_map_ωSup : + ωScottContinuous f ↔ ∃ hf : Monotone f, ∀ c : Chain α, f (ωSup c) = ωSup (c.map ⟨f, hf⟩) := by + refine ⟨fun hf ↦ ⟨hf.monotone, hf.map_ωSup⟩, ?_⟩ + intro hf _ ⟨c, hc⟩ _ _ _ hda + convert isLUB_range_ωSup (c.map { toFun := f, monotone' := hf.1 }) + · rw [map_coe, OrderHom.coe_mk, ← hc, ← (Set.range_comp f ⇑c)] + · rw [← hc] at hda + rw [← hf.2 c, ωSup_eq_of_isLUB hda] + +alias ⟨ωScottContinuous.monotone_map_ωSup, ωScottContinuous.of_monotone_map_ωSup⟩ := + ωScottContinuous_iff_monotone_map_ωSup + +/- A monotone function `f : α →o β` is ωScott continuous if and only if it distributes over ωSup. -/ +lemma ωScottContinuous_iff_map_ωSup_of_orderHom {f : α →o β} : + ωScottContinuous f ↔ ∀ c : Chain α, f (ωSup c) = ωSup (c.map f) := by + rw [ωScottContinuous_iff_monotone_map_ωSup] + exact exists_prop_of_true f.monotone' + +alias ⟨ωScottContinuous.map_ωSup_of_orderHom, ωScottContinuous.of_map_ωSup_of_orderHom⟩ := + ωScottContinuous_iff_map_ωSup_of_orderHom + +lemma ωScottContinuous.comp (hg : ωScottContinuous g) (hf : ωScottContinuous f) : + ωScottContinuous (g.comp f) := + ωScottContinuous.of_monotone_map_ωSup + ⟨hg.monotone.comp hf.monotone, by simp [hf.map_ωSup, hg.map_ωSup, map_comp]⟩ + +lemma ωScottContinuous.const {x : β} : ωScottContinuous (Function.const α x) := by + simp [ωScottContinuous, ScottContinuousOn, Set.range_nonempty] + +set_option linter.deprecated false /-- A monotone function `f : α →o β` is continuous if it distributes over ωSup. @@ -233,56 +305,67 @@ In order to distinguish it from the (more commonly used) continuity from topolog (see `Mathlib/Topology/Basic.lean`), the present definition is often referred to as "Scott-continuity" (referring to Dana Scott). It corresponds to continuity in Scott topological spaces (not defined here). -/ +@[deprecated ωScottContinuous (since := "2024-05-29")] def Continuous (f : α →o β) : Prop := ∀ c : Chain α, f (ωSup c) = ωSup (c.map f) /-- `Continuous' f` asserts that `f` is both monotone and continuous. -/ +@[deprecated ωScottContinuous (since := "2024-05-29")] def Continuous' (f : α → β) : Prop := ∃ hf : Monotone f, Continuous ⟨f, hf⟩ +@[deprecated ωScottContinuous.isLUB (since := "2024-05-29")] lemma isLUB_of_scottContinuous {c : Chain α} {f : α → β} (hf : ScottContinuous f) : - IsLUB (Set.range (Chain.map c ⟨f, (ScottContinuous.monotone hf)⟩)) (f (ωSup c)) := by - simp only [map_coe, OrderHom.coe_mk] - rw [(Set.range_comp f ↑c)] - exact hf (Set.range_nonempty ↑c) (IsChain.directedOn (isChain_range c)) (isLUB_range_ωSup c) + IsLUB (Set.range (Chain.map c ⟨f, (ScottContinuous.monotone hf)⟩)) (f (ωSup c)) := + ωScottContinuous.isLUB hf.scottContinuousOn +@[deprecated ScottContinuous.ωScottContinuous (since := "2024-05-29")] lemma ScottContinuous.continuous' {f : α → β} (hf : ScottContinuous f) : Continuous' f := by constructor · intro c rw [← (ωSup_eq_of_isLUB (isLUB_of_scottContinuous hf))] simp only [OrderHom.coe_mk] +@[deprecated ωScottContinuous.monotone (since := "2024-05-29")] theorem Continuous'.to_monotone {f : α → β} (hf : Continuous' f) : Monotone f := hf.fst +@[deprecated ωScottContinuous.of_monotone_map_ωSup (since := "2024-05-29")] theorem Continuous.of_bundled (f : α → β) (hf : Monotone f) (hf' : Continuous ⟨f, hf⟩) : Continuous' f := ⟨hf, hf'⟩ +@[deprecated ωScottContinuous.of_monotone_map_ωSup (since := "2024-05-29")] theorem Continuous.of_bundled' (f : α →o β) (hf' : Continuous f) : Continuous' f := ⟨f.mono, hf'⟩ +@[deprecated ωScottContinuous_iff_monotone_map_ωSup (since := "2024-05-29")] theorem Continuous'.to_bundled (f : α → β) (hf : Continuous' f) : Continuous ⟨f, hf.to_monotone⟩ := hf.snd -@[simp, norm_cast] +@[simp, norm_cast, deprecated ωScottContinuous_iff_monotone_map_ωSup (since := "2024-05-29")] theorem continuous'_coe : ∀ {f : α →o β}, Continuous' f ↔ Continuous f | ⟨_, hf⟩ => ⟨fun ⟨_, hc⟩ => hc, fun hc => ⟨hf, hc⟩⟩ variable (f : α →o β) (g : β →o γ) +@[deprecated ωScottContinuous.id (since := "2024-05-29")] theorem continuous_id : Continuous (@OrderHom.id α _) := by intro c; rw [c.map_id]; rfl +@[deprecated ωScottContinuous.comp (since := "2024-05-29")] theorem continuous_comp (hfc : Continuous f) (hgc : Continuous g) : Continuous (g.comp f) := by dsimp [Continuous] at *; intro rw [hfc, hgc, Chain.map_comp] +@[deprecated ωScottContinuous.id (since := "2024-05-29")] theorem id_continuous' : Continuous' (@id α) := continuous_id.of_bundled' _ +@[deprecated ωScottContinuous.const (since := "2024-05-29")] theorem continuous_const (x : β) : Continuous (OrderHom.const α x) := fun c => eq_of_forall_ge_iff fun z => by rw [ωSup_le_iff, Chain.map_coe, OrderHom.const_coe_coe]; simp +@[deprecated ωScottContinuous.const (since := "2024-05-29")] theorem const_continuous' (x : β) : Continuous' (Function.const α x) := Continuous.of_bundled' (OrderHom.const α x) (continuous_const x) @@ -292,8 +375,6 @@ end OmegaCompletePartialOrder namespace Part -variable {α : Type u} {β : Type v} {γ : Type*} - open OmegaCompletePartialOrder theorem eq_of_chain {c : Chain (Part α)} {a b : α} (ha : some a ∈ c) (hb : some b ∈ c) : a = b := by @@ -372,9 +453,9 @@ end Inst end Part -namespace Pi +section Pi -variable {α : Type*} {β : α → Type*} {γ : Type*} +variable {β : α → Type*} open OmegaCompletePartialOrder OmegaCompletePartialOrder.Chain @@ -391,11 +472,27 @@ namespace OmegaCompletePartialOrder variable [∀ x, OmegaCompletePartialOrder <| β x] variable [OmegaCompletePartialOrder γ] +variable {f : γ → ∀ x, β x} + +lemma ωScottContinuous.apply₂ (hf : ωScottContinuous f) (a : α) : ωScottContinuous (f · a) := + ωScottContinuous.of_monotone_map_ωSup + ⟨fun _ _ h ↦ hf.monotone h a, fun c ↦ congr_fun (hf.map_ωSup c) a⟩ + +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⟩ +lemma ωScottContinuous_iff_apply₂ : ωScottContinuous f ↔ ∀ a, ωScottContinuous (f · a) := + ⟨ωScottContinuous.apply₂, ωScottContinuous.of_apply₂⟩ + +set_option linter.deprecated false + +@[deprecated ωScottContinuous.apply₂ (since := "2024-05-29")] theorem flip₁_continuous' (f : ∀ x : α, γ → β x) (a : α) (hf : Continuous' fun x y => f y x) : Continuous' (f a) := Continuous.of_bundled _ (fun _ _ h => hf.to_monotone h a) fun c => congr_fun (hf.to_bundled _ c) a +@[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) @@ -409,7 +506,6 @@ namespace Prod open OmegaCompletePartialOrder -variable {α : Type*} {β : Type*} {γ : Type*} variable [OmegaCompletePartialOrder α] variable [OmegaCompletePartialOrder β] variable [OmegaCompletePartialOrder γ] @@ -435,8 +531,6 @@ open OmegaCompletePartialOrder namespace CompleteLattice -variable (α : Type u) - -- see Note [lower instance priority] /-- Any complete lattice has an `ω`-CPO structure where the countable supremum is a special case of arbitrary suprema. -/ @@ -446,20 +540,55 @@ instance (priority := 100) [CompleteLattice α] : OmegaCompletePartialOrder α w simp only [iSup_le_iff, OrderHom.coe_mk] at hs ⊢; intro i; apply hs i le_ωSup := fun ⟨c, _⟩ i => by simp only [OrderHom.coe_mk]; apply le_iSup_of_le i; rfl -variable {α} {β : Type v} [OmegaCompletePartialOrder α] [CompleteLattice β] +variable [OmegaCompletePartialOrder α] [CompleteLattice β] {f g : α → β} + +-- TODO Prove this result for `ScottContinuousOn` and deduce this as a special case +-- https://github.com/leanprover-community/mathlib4/pull/15412 +open Chain in +lemma ωScottContinuous.prodMk (hf : ωScottContinuous f) (hg : ωScottContinuous g) : + ωScottContinuous fun x => (f x, g x) := ScottContinuousOn.prodMk (fun a b hab => by + use pair a b hab; exact range_pair a b hab) hf hg + +lemma ωScottContinuous.iSup {f : ι → α → β} (hf : ∀ i, ωScottContinuous (f i)) : + ωScottContinuous (⨆ i, f i) := by + refine ωScottContinuous.of_monotone_map_ωSup + ⟨Monotone.iSup fun i ↦ (hf i).monotone, fun c ↦ eq_of_forall_ge_iff fun a ↦ ?_⟩ + simp (config := { contextual := true }) [ωSup_le_iff, (hf _).map_ωSup, @forall_swap ι] + +lemma ωScottContinuous.sSup {s : Set (α → β)} (hs : ∀ f ∈ s, ωScottContinuous f) : + ωScottContinuous (sSup s) := by + rw [sSup_eq_iSup]; exact ωScottContinuous.iSup fun f ↦ ωScottContinuous.iSup <| hs f + +lemma ωScottContinuous.sup (hf : ωScottContinuous f) (hg : ωScottContinuous g) : + ωScottContinuous (f ⊔ g) := by + rw [← sSup_pair] + apply ωScottContinuous.sSup + rintro f (rfl | rfl | _) <;> assumption + +lemma ωScottContinuous.top : ωScottContinuous (⊤ : α → β) := + ωScottContinuous.of_monotone_map_ωSup + ⟨monotone_const, fun c ↦ eq_of_forall_ge_iff fun a ↦ by simp⟩ + +lemma ωScottContinuous.bot : ωScottContinuous (⊥ : α → β) := by + rw [← sSup_empty]; exact ωScottContinuous.sSup (by simp) +set_option linter.deprecated false + +@[deprecated ωScottContinuous.sSup (since := "2024-05-29")] theorem sSup_continuous (s : Set <| α →o β) (hs : ∀ f ∈ s, Continuous f) : Continuous (sSup s) := by intro c apply eq_of_forall_ge_iff intro z - suffices (∀ f ∈ s, ∀ (n), (f : _) (c n) ≤ z) ↔ ∀ (n), ∀ f ∈ s, (f : _) (c n) ≤ z by + suffices (∀ f ∈ s, ∀ n, f (c n) ≤ z) ↔ ∀ n, ∀ f ∈ s, f (c n) ≤ z by simpa (config := { contextual := true }) [ωSup_le_iff, hs _ _ _] using this exact ⟨fun H n f hf => H f hf n, fun H f hf n => H n f hf⟩ +@[deprecated ωScottContinuous.iSup (since := "2024-05-29")] theorem iSup_continuous {ι : Sort*} {f : ι → α →o β} (h : ∀ i, Continuous (f i)) : Continuous (⨆ i, f i) := sSup_continuous _ <| Set.forall_mem_range.2 h +@[deprecated ωScottContinuous.sSup (since := "2024-05-29")] theorem sSup_continuous' (s : Set (α → β)) (hc : ∀ f ∈ s, Continuous' f) : Continuous' (sSup s) := by lift s to Set (α →o β) using fun f hf => (hc f hf).to_monotone @@ -468,16 +597,19 @@ theorem sSup_continuous' (s : Set (α → β)) (hc : ∀ f ∈ s, Continuous' f) norm_cast exact iSup_continuous fun f ↦ iSup_continuous fun hf ↦ hc hf +@[deprecated ωScottContinuous.sup (since := "2024-05-29")] theorem sup_continuous {f g : α →o β} (hf : Continuous f) (hg : Continuous g) : Continuous (f ⊔ g) := by rw [← sSup_pair]; apply sSup_continuous rintro f (rfl | rfl | _) <;> assumption +@[deprecated ωScottContinuous.top (since := "2024-05-29")] theorem top_continuous : Continuous (⊤ : α →o β) := by intro c; apply eq_of_forall_ge_iff; intro z simp only [OrderHom.instTopOrderHom_top, OrderHom.const_coe_coe, Function.const, top_le_iff, ωSup_le_iff, Chain.map_coe, Function.comp, forall_const] +@[deprecated ωScottContinuous.bot (since := "2024-05-29")] theorem bot_continuous : Continuous (⊥ : α →o β) := by rw [← sSup_empty] exact sSup_continuous _ fun f hf => hf.elim @@ -486,8 +618,27 @@ end CompleteLattice namespace CompleteLattice -variable {α β : Type*} [OmegaCompletePartialOrder α] [CompleteLinearOrder β] +variable [OmegaCompletePartialOrder α] [CompleteLinearOrder β] {f g : α → β} + +-- TODO Prove this result for `ScottContinuousOn` and deduce this as a special case +-- Also consider if it holds in greater generality (e.g. finite sets) +-- N.B. The Scott Topology coincides with the Upper Topology on a Complete Linear Order +-- `Topology.IsScott.scott_eq_upper_of_completeLinearOrder` +-- We have that the product topology coincides with the upper topology +-- https://github.com/leanprover-community/mathlib4/pull/12133 +lemma ωScottContinuous.inf (hf : ωScottContinuous f) (hg : ωScottContinuous g) : + ωScottContinuous (f ⊓ g) := by + refine ωScottContinuous.of_monotone_map_ωSup + ⟨hf.monotone.inf hg.monotone, fun c ↦ eq_of_forall_ge_iff fun a ↦ ?_⟩ + simp only [Pi.inf_apply, hf.map_ωSup c, hg.map_ωSup c, inf_le_iff, ωSup_le_iff, Chain.map_coe, + Function.comp, OrderHom.coe_mk, ← forall_or_left, ← forall_or_right] + exact ⟨fun h _ ↦ h _ _, fun h i j ↦ + (h (max j i)).imp (le_trans <| hf.monotone <| c.mono <| le_max_left _ _) + (le_trans <| hg.monotone <| c.mono <| le_max_right _ _)⟩ + +set_option linter.deprecated false +@[deprecated ωScottContinuous.inf (since := "2024-05-29")] theorem inf_continuous (f g : α →o β) (hf : Continuous f) (hg : Continuous g) : Continuous (f ⊓ g) := by refine fun c => eq_of_forall_ge_iff fun z => ?_ @@ -497,6 +648,7 @@ theorem inf_continuous (f g : α →o β) (hf : Continuous f) (hg : Continuous g (h (max j i)).imp (le_trans <| f.mono <| c.mono <| le_max_left _ _) (le_trans <| g.mono <| c.mono <| le_max_right _ _)⟩ +@[deprecated ωScottContinuous.inf (since := "2024-05-29")] theorem inf_continuous' {f g : α → β} (hf : Continuous' f) (hg : Continuous' g) : Continuous' (f ⊓ g) := ⟨_, inf_continuous _ _ hf.snd hg.snd⟩ @@ -504,11 +656,8 @@ theorem inf_continuous' {f g : α → β} (hf : Continuous' f) (hg : Continuous' end CompleteLattice namespace OmegaCompletePartialOrder - -variable {α : Type u} {α' : Type*} {β : Type v} {β' : Type*} {γ : Type*} {φ : Type*} variable [OmegaCompletePartialOrder α] [OmegaCompletePartialOrder β] -variable [OmegaCompletePartialOrder γ] [OmegaCompletePartialOrder φ] -variable [OmegaCompletePartialOrder α'] [OmegaCompletePartialOrder β'] +variable [OmegaCompletePartialOrder γ] [OmegaCompletePartialOrder δ] namespace OrderHom @@ -524,16 +673,13 @@ instance omegaCompletePartialOrder : OmegaCompletePartialOrder (α →o β) := end OrderHom -section - -variable (α β) - +variable (α β) in /-- A monotone function on `ω`-continuous partial orders is said to be continuous if for every chain `c : chain α`, `f (⊔ i, c i) = ⊔ i, f (c i)`. This is just the bundled version of `OrderHom.continuous`. -/ structure ContinuousHom extends OrderHom α β where /-- The underlying function of a `ContinuousHom` is continuous, i.e. it preserves `ωSup` -/ - cont : Continuous toOrderHom + protected map_ωSup' (c : Chain α) : toFun (ωSup c) = ωSup (c.map toOrderHom) attribute [nolint docBlame] ContinuousHom.toOrderHom @@ -552,14 +698,16 @@ instance : OrderHomClass (α →𝒄 β) α β where instance : PartialOrder (α →𝒄 β) := (PartialOrder.lift fun f => f.toOrderHom.toFun) <| by rintro ⟨⟨⟩⟩ ⟨⟨⟩⟩ h; congr -end - namespace ContinuousHom +protected lemma ωScottContinuous (f : α →𝒄 β) : ωScottContinuous f := + ωScottContinuous.of_map_ωSup_of_orderHom f.map_ωSup' + -- Not a `simp` lemma because in many cases projection is simpler than a generic coercion theorem toOrderHom_eq_coe (f : α →𝒄 β) : f.1 = f := rfl -@[simp] theorem coe_mk (f : α →o β) (hf : Continuous f) : ⇑(mk f hf) = f := rfl +@[simp] theorem coe_mk (f : α →o β) (hf) : ⇑(mk f hf) = f := rfl + @[simp] theorem coe_toOrderHom (f : α →𝒄 β) : ⇑f.1 = f := rfl /-- See Note [custom simps projection]. We specify this explicitly because we don't have a DFunLike @@ -583,6 +731,8 @@ protected theorem monotone (f : α →𝒄 β) : Monotone f := theorem apply_mono {f g : α →𝒄 β} {x y : α} (h₁ : f ≤ g) (h₂ : x ≤ y) : f x ≤ g y := OrderHom.apply_mono (show (f : α →o β) ≤ g from h₁) h₂ +set_option linter.deprecated false in +@[deprecated (since := "2024-07-27")] theorem ite_continuous' {p : Prop} [hp : Decidable p] (f g : α → β) (hf : Continuous' f) (hg : Continuous' g) : Continuous' fun x => if p then f x else g x := by split_ifs <;> simp [*] @@ -615,26 +765,48 @@ theorem ωSup_bind {β γ : Type v} (c : Chain α) (f : α →o Part β) (g : α · apply le_ωSup (c.map g) _ _ _ hb₁ · apply le_ωSup (c.map f) i _ hb₀ +-- TODO: We should move `ωScottContinuous` to the root namespace +lemma ωScottContinuous.bind {β γ} {f : α → Part β} {g : α → β → Part γ} (hf : ωScottContinuous f) + (hg : ωScottContinuous g) : ωScottContinuous fun x ↦ f x >>= g x := + ωScottContinuous.of_monotone_map_ωSup + ⟨hf.monotone.partBind hg.monotone, fun c ↦ by rw [hf.map_ωSup, hg.map_ωSup, ← ωSup_bind]; rfl⟩ + +lemma ωScottContinuous.map {β γ} {f : β → γ} {g : α → Part β} (hg : ωScottContinuous g) : + ωScottContinuous fun x ↦ f <$> g x := by + simpa only [map_eq_bind_pure_comp] using ωScottContinuous.bind hg ωScottContinuous.const + +lemma ωScottContinuous.seq {β γ} {f : α → Part (β → γ)} {g : α → Part β} (hf : ωScottContinuous f) + (hg : ωScottContinuous g) : ωScottContinuous fun x ↦ f x <*> g x := by + simp only [seq_eq_bind_map] + exact ωScottContinuous.bind hf <| ωScottContinuous.of_apply₂ fun _ ↦ ωScottContinuous.map hg + +set_option linter.deprecated false + +@[deprecated ωScottContinuous.bind (since := "2024-05-29")] theorem bind_continuous' {β γ : Type v} (f : α → Part β) (g : α → β → Part γ) : Continuous' f → Continuous' g → Continuous' fun x => f x >>= g x | ⟨hf, hf'⟩, ⟨hg, hg'⟩ => Continuous.of_bundled' (OrderHom.partBind ⟨f, hf⟩ ⟨g, hg⟩) (by intro c; rw [ωSup_bind, ← hf', ← hg']; rfl) +@[deprecated ωScottContinuous.map (since := "2024-05-29")] theorem map_continuous' {β γ : Type v} (f : β → γ) (g : α → Part β) (hg : Continuous' g) : Continuous' fun x => f <$> g x := by simp only [map_eq_bind_pure_comp]; apply bind_continuous' _ _ hg; apply const_continuous' +@[deprecated ωScottContinuous.seq (since := "2024-05-29")] theorem seq_continuous' {β γ : Type v} (f : α → Part (β → γ)) (g : α → Part β) (hf : Continuous' f) (hg : Continuous' g) : Continuous' fun x => f x <*> g x := by simp only [seq_eq_bind_map] apply bind_continuous' _ _ hf - apply Pi.OmegaCompletePartialOrder.flip₂_continuous' + apply OmegaCompletePartialOrder.flip₂_continuous' intro apply map_continuous' _ _ hg theorem continuous (F : α →𝒄 β) (C : Chain α) : F (ωSup C) = ωSup (C.map F) := - ContinuousHom.cont _ _ + F.ωScottContinuous.map_ωSup _ + +set_option linter.deprecated true /-- Construct a continuous function from a bare function, a continuous function, and a proof that they are equal. -/ @@ -642,17 +814,18 @@ they are equal. -/ @[simps!] def copy (f : α → β) (g : α →𝒄 β) (h : f = g) : α →𝒄 β where toOrderHom := g.1.copy f h - cont := by rw [OrderHom.copy_eq]; exact g.cont + map_ωSup' := by rw [OrderHom.copy_eq]; exact g.map_ωSup' -- Porting note: `of_mono` now defeq `mk` /-- The identity as a continuous function. -/ @[simps!] -def id : α →𝒄 α := ⟨OrderHom.id, continuous_id⟩ +def id : α →𝒄 α := ⟨OrderHom.id, ωScottContinuous.id.map_ωSup⟩ /-- The composition of continuous functions. -/ @[simps!] -def comp (f : β →𝒄 γ) (g : α →𝒄 β) : α →𝒄 γ := ⟨.comp f.1 g.1, continuous_comp _ _ g.cont f.cont⟩ +def comp (f : β →𝒄 γ) (g : α →𝒄 β) : α →𝒄 γ := + ⟨.comp f.1 g.1, (f.ωScottContinuous.comp g.ωScottContinuous).map_ωSup⟩ @[ext] protected theorem ext (f g : α →𝒄 β) (h : ∀ x, f x = g x) : f = g := DFunLike.ext f g h @@ -667,7 +840,7 @@ theorem comp_id (f : β →𝒄 γ) : f.comp id = f := rfl theorem id_comp (f : β →𝒄 γ) : id.comp f = f := rfl @[simp] -theorem comp_assoc (f : γ →𝒄 φ) (g : β →𝒄 γ) (h : α →𝒄 β) : f.comp (g.comp h) = (f.comp g).comp h := +theorem comp_assoc (f : γ →𝒄 δ) (g : β →𝒄 γ) (h : α →𝒄 β) : f.comp (g.comp h) = (f.comp g).comp h := rfl @[simp] @@ -676,7 +849,7 @@ theorem coe_apply (a : α) (f : α →𝒄 β) : (f : α →o β) a = f a := /-- `Function.const` is a continuous function. -/ @[simps!] -def const (x : β) : α →𝒄 β := ⟨.const _ x, continuous_const x⟩ +def const (x : β) : α →𝒄 β := ⟨.const _ x, ωScottContinuous.const.map_ωSup⟩ instance [Inhabited β] : Inhabited (α →𝒄 β) := ⟨const default⟩ @@ -713,12 +886,9 @@ theorem forall_forall_merge' (c₀ : Chain (α →𝒄 β)) (c₁ : Chain α) (z /-- The `ωSup` operator for continuous functions, which takes the pointwise countable supremum of the functions in the `ω`-chain. -/ @[simps!] -protected def ωSup (c : Chain (α →𝒄 β)) : α →𝒄 β := - .mk (ωSup <| c.map toMono) fun c' ↦ by - apply eq_of_forall_ge_iff; intro z - simp only [ωSup_le_iff, (c _).continuous, Chain.map_coe, OrderHom.apply_coe, toMono_coe, - OrderHom.omegaCompletePartialOrder_ωSup_coe, forall_forall_merge, OrderHomClass.coe_coe, - forall_forall_merge', (· ∘ ·), Function.eval] +protected def ωSup (c : Chain (α →𝒄 β)) : α →𝒄 β where + toOrderHom := ωSup <| c.map toMono + map_ωSup' c' := eq_of_forall_ge_iff fun a ↦ by simp [(c _).ωScottContinuous.map_ωSup] @[simps ωSup] instance : OmegaCompletePartialOrder (α →𝒄 β) := @@ -727,15 +897,14 @@ instance : OmegaCompletePartialOrder (α →𝒄 β) := namespace Prod -/-- The application of continuous functions as a continuous function. -/ +/-- The application of continuous functions as a continuous function. -/ @[simps] def apply : (α →𝒄 β) × α →𝒄 β where toFun f := f.1 f.2 monotone' x y h := by dsimp trans y.fst x.snd <;> [apply h.1; apply y.1.monotone h.2] - cont := by - intro c + map_ωSup' c := by apply le_antisymm · apply ωSup_le intro i @@ -768,7 +937,7 @@ theorem ωSup_apply_ωSup (c₀ : Chain (α →𝒄 β)) (c₁ : Chain α) : def flip {α : Type*} (f : α → β →𝒄 γ) : β →𝒄 α → γ where toFun x y := f y x monotone' x y h a := (f a).monotone h - cont := by intro _; ext x; change f _ _ = _; rw [(f _).continuous]; rfl + map_ωSup' _ := by ext x; change f _ _ = _; rw [(f _).continuous]; rfl /-- `Part.bind` as a continuous function. -/ @[simps! apply] -- Porting note: removed `(config := { rhsMd := reducible })` @@ -795,4 +964,62 @@ noncomputable def seq {β γ : Type v} (f : α →𝒄 Part (β → γ)) (g : α end ContinuousHom +namespace fixedPoints + +open Function + +/-- Iteration of a function on an initial element interpreted as a chain. -/ +def iterateChain (f : α →o α) (x : α) (h : x ≤ f x) : Chain α := + ⟨fun n => f^[n] x, f.monotone.monotone_iterate_of_le_map h⟩ + +variable (f : α →𝒄 α) (x : α) + +/-- The supremum of iterating a function on x arbitrary often is a fixed point -/ +theorem ωSup_iterate_mem_fixedPoint (h : x ≤ f x) : + ωSup (iterateChain f x h) ∈ fixedPoints f := by + rw [mem_fixedPoints, IsFixedPt, f.continuous] + apply le_antisymm + · apply ωSup_le + intro n + simp only [Chain.map_coe, OrderHomClass.coe_coe, comp_apply] + have : iterateChain f x h (n.succ) = f (iterateChain f x h n) := + Function.iterate_succ_apply' .. + rw [← this] + apply le_ωSup + · apply ωSup_le + rintro (_ | n) + · apply le_trans h + change ((iterateChain f x h).map f) 0 ≤ ωSup ((iterateChain f x h).map (f : α →o α)) + apply le_ωSup + · have : iterateChain f x h (n.succ) = (iterateChain f x h).map f n := + Function.iterate_succ_apply' .. + rw [this] + apply le_ωSup + +/-- The supremum of iterating a function on x arbitrary often is smaller than any prefixed point. + +A prefixed point is a value `a` with `f a ≤ a`. -/ +theorem ωSup_iterate_le_prefixedPoint (h : x ≤ f x) {a : α} + (h_a : f a ≤ a) (h_x_le_a : x ≤ a) : + ωSup (iterateChain f x h) ≤ a := by + apply ωSup_le + intro n + induction n with + | zero => exact h_x_le_a + | succ n h_ind => + have : iterateChain f x h (n.succ) = f (iterateChain f x h n) := + Function.iterate_succ_apply' .. + rw [this] + exact le_trans (f.monotone h_ind) h_a + +/-- The supremum of iterating a function on x arbitrary often is smaller than any fixed point. -/ +theorem ωSup_iterate_le_fixedPoint (h : x ≤ f x) {a : α} + (h_a : a ∈ fixedPoints f) (h_x_le_a : x ≤ a) : + ωSup (iterateChain f x h) ≤ a := by + rw [mem_fixedPoints] at h_a + obtain h_a := Eq.le h_a + exact ωSup_iterate_le_prefixedPoint f x h h_a h_x_le_a + +end fixedPoints + end OmegaCompletePartialOrder 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/Part.lean b/Mathlib/Order/Part.lean index 7b1dbb20f678d..095e4622ab550 100644 --- a/Mathlib/Order/Part.lean +++ b/Mathlib/Order/Part.lean @@ -47,10 +47,10 @@ section seq variable {β γ : Type _} {f : α → Part (β → γ)} {g : α → Part β} lemma Monotone.partSeq (hf : Monotone f) (hg : Monotone g) : Monotone fun x ↦ f x <*> g x := by - simpa only [seq_eq_bind_map] using hf.partBind $ Monotone.of_apply₂ fun _ ↦ hg.partMap + simpa only [seq_eq_bind_map] using hf.partBind <| Monotone.of_apply₂ fun _ ↦ hg.partMap lemma Antitone.partSeq (hf : Antitone f) (hg : Antitone g) : Antitone fun x ↦ f x <*> g x := by - simpa only [seq_eq_bind_map] using hf.partBind $ Antitone.of_apply₂ fun _ ↦ hg.partMap + simpa only [seq_eq_bind_map] using hf.partBind <| Antitone.of_apply₂ fun _ ↦ hg.partMap end seq diff --git a/Mathlib/Order/PartialSups.lean b/Mathlib/Order/PartialSups.lean index 188df49ffbced..5fbe0f73945d5 100644 --- a/Mathlib/Order/PartialSups.lean +++ b/Mathlib/Order/PartialSups.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.Finset.Lattice import Mathlib.Order.Hom.Basic @@ -94,6 +94,9 @@ theorem Monotone.partialSups_eq {f : ℕ → α} (hf : Monotone f) : (partialSup theorem partialSups_mono : Monotone (partialSups : (ℕ → α) → ℕ →o α) := fun _f _g h _n ↦ partialSups_le_iff.2 fun k hk ↦ (h k).trans (le_partialSups_of_le _ hk) +lemma partialSups_monotone (f : ℕ → α) : Monotone (partialSups f) := + fun n _ hnm ↦ partialSups_le f n _ (fun _ hm'n ↦ le_partialSups_of_le _ (hm'n.trans hnm)) + /-- `partialSups` forms a Galois insertion with the coercion from monotone functions to functions. -/ def partialSups.gi : GaloisInsertion (partialSups : (ℕ → α) → ℕ →o α) (↑) where @@ -157,11 +160,20 @@ end ConditionallyCompleteLattice section CompleteLattice -variable [CompleteLattice α] - -theorem partialSups_eq_biSup (f : ℕ → α) (n : ℕ) : partialSups f n = ⨆ i ≤ n, f i := by +theorem partialSups_eq_biSup [CompleteLattice α] (f : ℕ → α) (n : ℕ) : + partialSups f n = ⨆ i ≤ n, f i := by simpa only [iSup_subtype] using partialSups_eq_ciSup_Iic f n +lemma partialSups_eq_sUnion_image [DecidableEq (Set α)] (s : ℕ → Set α) (n : ℕ) : + partialSups s n = ⋃₀ ↑((Finset.range (n + 1)).image s) := by + ext; simp [partialSups_eq_biSup, Nat.lt_succ_iff] + +lemma partialSups_eq_biUnion_range (s : ℕ → Set α) (n : ℕ) : + partialSups s n = ⋃ i ∈ Finset.range (n + 1), s i := by + ext; simp [partialSups_eq_biSup, Nat.lt_succ] + +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/Finpartition.lean b/Mathlib/Order/Partition/Finpartition.lean index 13a431112afd8..91dbd15b3b57b 100644 --- a/Mathlib/Order/Partition/Finpartition.lean +++ b/Mathlib/Order/Partition/Finpartition.lean @@ -67,7 +67,7 @@ structure Finpartition [Lattice α] [OrderBot α] (a : α) where supIndep : parts.SupIndep id /-- The supremum of the partition is `a` -/ sup_parts : parts.sup id = a - /-- No element of the partition is bottom-/ + /-- No element of the partition is bottom -/ not_bot_mem : ⊥ ∉ parts deriving DecidableEq @@ -257,6 +257,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 @@ -465,7 +474,8 @@ def part (a : α) : Finset α := if ha : a ∈ s then choose (hp := P.existsUniq lemma part_mem (ha : a ∈ s) : P.part a ∈ P.parts := by simp [part, ha, choose_mem] -lemma mem_part (ha : a ∈ s) : a ∈ P.part a := by simp [part, ha, choose_property] +lemma mem_part (ha : a ∈ s) : a ∈ P.part a := by + simp [part, ha, choose_property (p := fun s => a ∈ s) P.parts (P.existsUnique_mem ha)] lemma part_eq_of_mem (ht : t ∈ P.parts) (hat : a ∈ t) : P.part a = t := by apply P.eq_of_mem_parts (P.part_mem _) ht (P.mem_part _) hat <;> exact mem_of_subset (P.le ht) hat @@ -547,6 +557,8 @@ lemma card_mod_card_parts_le : s.card % P.parts.card ≤ P.parts.card := by rw [h, h'] · exact (Nat.mod_lt _ h).le +section Setoid + variable [Fintype α] /-- A setoid over a finite type induces a finpartition of the type's elements, @@ -586,6 +598,8 @@ theorem mem_part_ofSetoid_iff_rel {s : Setoid α} [DecidableRel s.r] {b : α} : simp only [← hc, mem_univ, mem_filter, true_and] at this ⊢ exact ⟨s.trans (s.symm this), s.trans this⟩ +end Setoid + section Atomise /-- Cuts `s` along the finsets in `F`: Two elements of `s` will be in the same part if they are diff --git a/Mathlib/Order/RelClasses.lean b/Mathlib/Order/RelClasses.lean index 1a1ad02cbedff..be726cd3e66f4 100644 --- a/Mathlib/Order/RelClasses.lean +++ b/Mathlib/Order/RelClasses.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jeremy Avigad, Mario Carneiro, Yury Kudryashov -/ import Mathlib.Data.Nat.Defs +import Mathlib.Init.Algebra.Classes import Mathlib.Logic.IsEmpty import Mathlib.Order.Basic import Mathlib.Tactic.MkIffOfInductiveProp @@ -12,12 +13,13 @@ import Batteries.WF /-! # Unbundled relation classes -In this file we prove some properties of `Is*` classes defined in `Init.Algebra.Classes`. The main +In this file we prove some properties of `Is*` classes defined in `Order.Defs`. The main difference between these classes and the usual order classes (`Preorder` etc) is that usual classes extend `LE` and/or `LT` while these classes take a relation as an explicit argument. -/ +set_option linter.deprecated false universe u v @@ -40,21 +42,21 @@ theorem antisymm_iff [IsRefl α r] [IsAntisymm α r] {a b : α} : r a b ∧ r b /-- A version of `antisymm` with `r` explicit. -This lemma matches the lemmas from lean core in `Init.Algebra.Classes`, but is missing there. -/ +This lemma matches the lemmas from lean core in `Init.Algebra.Classes`, but is missing there. -/ @[elab_without_expected_type] theorem antisymm_of (r : α → α → Prop) [IsAntisymm α r] {a b : α} : r a b → r b a → a = b := antisymm /-- A version of `antisymm'` with `r` explicit. -This lemma matches the lemmas from lean core in `Init.Algebra.Classes`, but is missing there. -/ +This lemma matches the lemmas from lean core in `Init.Algebra.Classes`, but is missing there. -/ @[elab_without_expected_type] theorem antisymm_of' (r : α → α → Prop) [IsAntisymm α r] {a b : α} : r a b → r b a → b = a := antisymm' /-- A version of `comm` with `r` explicit. -This lemma matches the lemmas from lean core in `Init.Algebra.Classes`, but is missing there. -/ +This lemma matches the lemmas from lean core in `Init.Algebra.Classes`, but is missing there. -/ theorem comm_of (r : α → α → Prop) [IsSymm α r] {a b : α} : r a b ↔ r b a := comm @@ -88,9 +90,11 @@ 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 } @@ -167,7 +171,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. @@ -196,7 +200,7 @@ theorem IsStrictTotalOrder.swap (r) [IsStrictTotalOrder α r] : IsStrictTotalOrd /-- A connected order is one satisfying the condition `a < c → a < b ∨ b < c`. This is recognizable as an intuitionistic substitute for `a ≤ b ∨ b ≤ a` on the constructive reals, and is also known as negative transitivity, - since the contrapositive asserts transitivity of the relation `¬ a < b`. -/ + since the contrapositive asserts transitivity of the relation `¬ a < b`. -/ class IsOrderConnected (α : Type u) (lt : α → α → Prop) : Prop where /-- A connected order is one satisfying the condition `a < c → a < b ∨ b < c`. -/ conn : ∀ a b c, lt a c → lt a b ∨ lt b c @@ -219,6 +223,7 @@ instance (priority := 100) isStrictOrderConnected_of_isStrictTotalOrder [IsStric fun o ↦ o.elim (fun e ↦ e ▸ h) fun h' ↦ _root_.trans h' h⟩ -- see Note [lower instance priority] +@[deprecated (since := "2024-07-30")] instance (priority := 100) isStrictTotalOrder_of_isStrictTotalOrder [IsStrictTotalOrder α r] : IsStrictWeakOrder α r := { isStrictWeakOrder_of_isOrderConnected with } @@ -244,6 +249,31 @@ lemma WellFounded.prod_lex {ra : α → α → Prop} {rb : β → β → Prop} ( (hb : WellFounded rb) : WellFounded (Prod.Lex ra rb) := (Prod.lex ⟨_, ha⟩ ⟨_, hb⟩).wf +section PSigma + +open PSigma + +/-- The lexicographical order of well-founded relations is well-founded. -/ +theorem WellFounded.psigma_lex + {α : Sort*} {β : α → Sort*} {r : α → α → Prop} {s : ∀ a : α, β a → β a → Prop} + (ha : WellFounded r) (hb : ∀ x, WellFounded (s x)) : WellFounded (Lex r s) := + WellFounded.intro fun ⟨a, b⟩ => lexAccessible (WellFounded.apply ha a) hb b + +theorem WellFounded.psigma_revLex + {α : Sort*} {β : Sort*} {r : α → α → Prop} {s : β → β → Prop} + (ha : WellFounded r) (hb : WellFounded s) : WellFounded (RevLex r s) := + WellFounded.intro fun ⟨a, b⟩ => revLexAccessible (apply hb b) (WellFounded.apply ha) a + +theorem WellFounded.psigma_skipLeft (α : Type u) {β : Type v} {s : β → β → Prop} + (hb : WellFounded s) : WellFounded (SkipLeft α s) := + psigma_revLex emptyWf.wf hb + +@[deprecated (since := "2024-07-24")] alias PSigma.lex_wf := WellFounded.psigma_lex +@[deprecated (since := "2024-07-24")] alias PSigma.revLex_wf := WellFounded.psigma_revLex +@[deprecated (since := "2024-07-24")] alias PSigma.skipLeft_wf := WellFounded.psigma_skipLeft + +end PSigma + namespace IsWellFounded variable (r) [IsWellFounded α r] @@ -432,7 +462,7 @@ instance [IsWellOrder α r] [IsWellOrder β s] : IsWellOrder (α × β) (Prod.Le | Or.inr (Or.inr h) => Or.inr <| Or.inr <| Prod.Lex.right _ h | Or.inr (Or.inl (.refl _)) => Or.inr <| Or.inl rfl trans a b c h₁ h₂ := by - cases' h₁ with a₁ a₂ b₁ b₂ ab a₁ b₁ b₂ ab <;> cases' h₂ with _ _ c₁ c₂ bc _ _ c₂ bc + rcases h₁ with ⟨a₂, b₂, ab⟩ | ⟨a₁, ab⟩ <;> rcases h₂ with ⟨c₁, c₂, bc⟩ | ⟨c₂, bc⟩ exacts [.left _ _ (_root_.trans ab bc), .left _ _ ab, .left _ _ bc, .right _ (_root_.trans ab bc)] @@ -747,10 +777,8 @@ instance LE.isTotal [LinearOrder α] : IsTotal α (· ≤ ·) := instance [LinearOrder α] : IsTotal α (· ≥ ·) := IsTotal.swap _ --- Porting note: this was `by infer_instance` before -instance [LinearOrder α] : IsTotalPreorder α (· ≤ ·) where - -instance [LinearOrder α] : IsTotalPreorder α (· ≥ ·) where +@[deprecated (since := "2024-08-22")] instance [LinearOrder α] : IsTotalPreorder α (· ≤ ·) where +@[deprecated (since := "2024-08-22")] instance [LinearOrder α] : IsTotalPreorder α (· ≥ ·) where instance [LinearOrder α] : IsLinearOrder α (· ≤ ·) where @@ -772,8 +800,10 @@ 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 theorem transitive_le [Preorder α] : Transitive (@LE.le α _) := diff --git a/Mathlib/Order/RelIso/Basic.lean b/Mathlib/Order/RelIso/Basic.lean index fee223a097f83..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) @@ -81,13 +80,17 @@ protected theorem isAsymm [RelHomClass F r s] (f : F) : ∀ [IsAsymm β s], IsAs protected theorem acc [RelHomClass F r s] (f : F) (a : α) : Acc s (f a) → Acc r a := by generalize h : f a = b intro ac - induction' ac with _ H IH generalizing a + induction ac generalizing a with | intro _ H IH => ?_ subst h exact ⟨_, fun a' h => IH (f a') (map_rel f h) _ rfl⟩ protected theorem wellFounded [RelHomClass F r s] (f : F) : WellFounded s → WellFounded r | ⟨H⟩ => ⟨fun _ => RelHomClass.acc f _ (H _)⟩ +protected theorem isWellFounded [RelHomClass F r s] (f : F) [IsWellFounded β s] : + IsWellFounded α r := + ⟨RelHomClass.wellFounded f IsWellFounded.wf⟩ + end RelHomClass namespace RelHom @@ -198,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 ⟨⟨⟩⟩ @@ -323,7 +326,7 @@ protected theorem isStrictTotalOrder : ∀ (_ : r ↪r s) [IsStrictTotalOrder β protected theorem acc (f : r ↪r s) (a : α) : Acc s (f a) → Acc r a := by generalize h : f a = b intro ac - induction' ac with _ H IH generalizing a + induction ac generalizing a with | intro _ H IH => ?_ subst h exact ⟨_, fun a' h => IH (f a') (f.map_rel_iff.2 h) _ rfl⟩ @@ -346,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 => ?_ @@ -368,13 +371,13 @@ 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 · exact RelHomClass.acc (Quotient.mkRelHom H) a · intro ac - induction' ac with _ _ IH + induction ac with | intro _ _ IH => ?_ refine ⟨_, fun q h => ?_⟩ obtain ⟨a', rfl⟩ := q.exists_rep exact IH a' h @@ -386,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 @@ -533,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 @@ -567,8 +570,7 @@ theorem coe_fn_mk (f : α ≃ β) (o : ∀ ⦃a b⦄, s (f a) (f b) ↔ r a b) : theorem coe_fn_toEquiv (f : r ≃r s) : (f.toEquiv : α → β) = f := rfl -/-- The map `coe_fn : (r ≃r s) → (α → β)` is injective. Lean fails to parse -`Function.Injective (fun e : r ≃r s ↦ (e : α → β))`, so we use a trick to say the same. -/ +/-- The map `DFunLike.coe : (r ≃r s) → (α → β)` is injective. -/ theorem coe_fn_injective : Injective fun f : r ≃r s => (f : α → β) := DFunLike.coe_injective @@ -698,7 +700,7 @@ lexicographic orders on the sum. def sumLexCongr {α₁ α₂ β₁ β₂ r₁ r₂ s₁ s₂} (e₁ : @RelIso α₁ β₁ r₁ s₁) (e₂ : @RelIso α₂ β₂ r₂ s₂) : Sum.Lex r₁ r₂ ≃r Sum.Lex s₁ s₂ := ⟨Equiv.sumCongr e₁.toEquiv e₂.toEquiv, @fun a b => by - cases' e₁ with f hf; cases' e₂ with g hg; cases a <;> cases b <;> simp [hf, hg]⟩ + obtain ⟨f, hf⟩ := e₁; obtain ⟨g, hg⟩ := e₂; cases a <;> cases b <;> simp [hf, hg]⟩ /-- Given relation isomorphisms `r₁ ≃r s₁` and `r₂ ≃r s₂`, construct a relation isomorphism for the lexicographic orders on the product. diff --git a/Mathlib/Order/RelIso/Set.lean b/Mathlib/Order/RelIso/Set.lean index fbf5dd9ac208e..961b9773f5912 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 diff --git a/Mathlib/Order/RelSeries.lean b/Mathlib/Order/RelSeries.lean index 6b905496d8037..d01a0e54fc8ee 100644 --- a/Mathlib/Order/RelSeries.lean +++ b/Mathlib/Order/RelSeries.lean @@ -3,13 +3,11 @@ Copyright (c) 2023 Jujian Zhang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jujian Zhang, Fangming Li -/ -import Mathlib.Algebra.Ring.Int -import Mathlib.Data.List.Chain -import Mathlib.Data.List.OfFn +import Mathlib.Algebra.Order.Ring.Nat +import Mathlib.Data.Fintype.Card +import Mathlib.Data.Fintype.Pi +import Mathlib.Data.Fintype.Sigma import Mathlib.Data.Rel -import Mathlib.Order.Fin.Basic -import Mathlib.Tactic.Abel -import Mathlib.Tactic.Linarith /-! # Series of a relation @@ -102,7 +100,7 @@ lemma toList_chain' (x : RelSeries r) : x.toList.Chain' r := by lemma toList_ne_nil (x : RelSeries r) : x.toList ≠ [] := fun m => List.eq_nil_iff_forall_not_mem.mp m (x 0) <| (List.mem_ofFn _ _).mpr ⟨_, rfl⟩ -/-- Every nonempty list satisfying the chain condition gives a relation series-/ +/-- Every nonempty list satisfying the chain condition gives a relation series -/ @[simps] def fromListChain' (x : List α) (x_ne_nil : x ≠ []) (hx : x.Chain' r) : RelSeries r where length := x.length - 1 @@ -171,7 +169,7 @@ lemma nonempty_of_infiniteDimensional [r.InfiniteDimensional] : Nonempty α := ⟨RelSeries.withLength r 0 0⟩ instance membership : Membership α (RelSeries r) := - ⟨(· ∈ Set.range ·)⟩ + ⟨Function.swap (· ∈ Set.range ·)⟩ theorem mem_def : x ∈ s ↔ x ∈ Set.range s := Iff.rfl @@ -184,7 +182,7 @@ theorem subsingleton_of_length_eq_zero (hs : s.length = 0) : {x | x ∈ s}.Subsi exact finCongr (by rw [hs, zero_add]) |>.injective <| Subsingleton.elim (α := Fin 1) _ _ theorem length_ne_zero_of_nontrivial (h : {x | x ∈ s}.Nontrivial) : s.length ≠ 0 := - fun hs ↦ h.not_subsingleton $ subsingleton_of_length_eq_zero hs + fun hs ↦ h.not_subsingleton <| subsingleton_of_length_eq_zero hs theorem length_pos_of_nontrivial (h : {x | x ∈ s}.Nontrivial) : 0 < s.length := Nat.pos_iff_ne_zero.mpr <| length_ne_zero_of_nontrivial h @@ -237,7 +235,7 @@ such that `r aₙ b₀`, then there is a chain of length `n + m + 1` given by @[simps length] def append (p q : RelSeries r) (connect : r p.last q.head) : RelSeries r where length := p.length + q.length + 1 - toFun := Fin.append p q ∘ Fin.cast (by abel) + toFun := Fin.append p q ∘ Fin.cast (by omega) step i := by obtain hi | rfl | hi := lt_trichotomy i (Fin.castLE (by omega) (Fin.last _ : Fin (p.length + 1))) @@ -259,14 +257,14 @@ def append (p q : RelSeries r) (connect : r p.last q.head) : RelSeries r where rfl rw [hx, Fin.append_right, hy, Fin.append_right] convert q.step ⟨i - (p.length + 1), Nat.sub_lt_left_of_lt_add hi <| - by convert i.2 using 1; abel⟩ + by convert i.2 using 1; exact Nat.add_right_comm ..⟩ rw [Fin.succ_mk, Nat.sub_eq_iff_eq_add (le_of_lt hi : p.length ≤ i), Nat.add_assoc _ 1, add_comm 1, Nat.sub_add_cancel] exact hi lemma append_apply_left (p q : RelSeries r) (connect : r p.last q.head) (i : Fin (p.length + 1)) : - p.append q connect ((i.castAdd (q.length + 1)).cast (by dsimp; abel)) = p i := by + p.append q connect ((i.castAdd (q.length + 1)).cast (by dsimp; omega)) = p i := by delta append simp only [Function.comp_apply] convert Fin.append_left _ _ _ @@ -359,7 +357,7 @@ def insertNth (p : RelSeries r) (i : Fin p.length) (a : α) rw [Fin.insertNth_apply_above] swap · exact hm.trans (lt_add_one _) - simp only [Fin.val_succ, Nat.zero_eq, Fin.pred_succ, eq_rec_constant, Fin.succ_mk] + simp only [Fin.val_succ, Fin.pred_succ, eq_rec_constant, Fin.succ_mk] congr exact Fin.ext <| Eq.symm <| Nat.succ_pred_eq_of_pos (lt_trans (Nat.zero_lt_succ _) hm) · convert connect_next @@ -496,6 +494,14 @@ def eraseLast (p : RelSeries r) : RelSeries r where @[simp] lemma last_eraseLast (p : RelSeries r) : p.eraseLast.last = p ⟨p.length.pred, Nat.lt_succ_iff.2 (Nat.pred_le _)⟩ := rfl + +/-- In a non-trivial series `p`, the last element of `p.eraseLast` is related to `p.last` -/ +lemma eraseLast_last_rel_last (p : RelSeries r) (h : p.length ≠ 0) : + r p.eraseLast.last p.last := by + simp only [last, Fin.last, eraseLast_length, eraseLast_toFun] + convert p.step ⟨p.length - 1, by omega⟩ + simp only [Nat.succ_eq_add_one, Fin.succ_mk]; omega + /-- Given two series of the form `a₀ -r→ ... -r→ X` and `X -r→ b ---> ...`, then `a₀ -r→ ... -r→ X -r→ b ...` is another series obtained by combining the given two. @@ -674,6 +680,8 @@ lemma strictMono (x : LTSeries α) : StrictMono x := lemma monotone (x : LTSeries α) : Monotone x := x.strictMono.monotone +lemma head_le_last (x : LTSeries α) : x.head ≤ x.last := + LTSeries.monotone x (Fin.zero_le _) /-- An alternative constructor of `LTSeries` from a strictly monotone function. -/ @[simps] @@ -682,6 +690,22 @@ def mk (length : ℕ) (toFun : Fin (length + 1) → α) (strictMono : StrictMono toFun := toFun step i := strictMono <| lt_add_one i.1 +/-- An injection from the type of strictly monotone functions with limited length to `LTSeries`. -/ +def injStrictMono (n : ℕ) : + {f : (l : Fin n) × (Fin (l + 1) → α) // StrictMono f.2} ↪ LTSeries α where + toFun f := mk f.1.1 f.1.2 f.2 + inj' f g e := by + obtain ⟨⟨lf, f⟩, mf⟩ := f + obtain ⟨⟨lg, g⟩, mg⟩ := g + dsimp only at mf mg e + have leq := congr($(e).length) + rw [mk_length lf f mf, mk_length lg g mg, Fin.val_eq_val] at leq + subst leq + 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] + /-- For two preorders `α, β`, if `f : α → β` is strictly monotonic, then a strict chain of `α` can be pushed out to a strict chain of `β` by @@ -710,6 +734,85 @@ noncomputable def comap (p : LTSeries β) (f : α → β) LTSeries α := mk p.length (fun i ↦ (surjective (p i)).choose) (fun i j h ↦ comap (by simpa only [(surjective _).choose_spec] using p.strictMono h)) +/-- The strict series `0 < … < n` in `ℕ`. -/ +def range (n : ℕ) : LTSeries ℕ where + length := n + toFun := fun i => i + step i := Nat.lt_add_one i + +@[simp] lemma length_range (n : ℕ) : (range n).length = n := rfl + +@[simp] lemma range_apply (n : ℕ) (i : Fin (n+1)) : (range n) i = i := rfl + +@[simp] lemma head_range (n : ℕ) : (range n).head = 0 := rfl + +@[simp] lemma last_range (n : ℕ) : (range n).last = n := rfl + +/-- +In ℕ, two entries in an `LTSeries` differ by at least the difference of their indices. +(Expressed in a way that avoids subtraction). + -/ +lemma apply_add_index_le_apply_add_index_nat (p : LTSeries ℕ) (i j : Fin (p.length + 1)) + (hij : i ≤ j) : p i + j ≤ p j + i := by + have ⟨i, hi⟩ := i + have ⟨j, hj⟩ := j + simp only [Fin.mk_le_mk] at hij + simp only at * + induction j, hij using Nat.le_induction with + | base => simp + | succ j _hij ih => + specialize ih (Nat.lt_of_succ_lt hj) + have step : p ⟨j, _⟩ < p ⟨j + 1, _⟩ := p.step ⟨j, by omega⟩ + norm_cast at *; omega + +/-- +In ℤ, two entries in an `LTSeries` differ by at least the difference of their indices. +(Expressed in a way that avoids subtraction). +-/ +lemma apply_add_index_le_apply_add_index_int (p : LTSeries ℤ) (i j : Fin (p.length + 1)) + (hij : i ≤ j) : p i + j ≤ p j + i := by + -- The proof is identical to `LTSeries.apply_add_index_le_apply_add_index_nat`, but seemed easier + -- to copy rather than to abstract + have ⟨i, hi⟩ := i + have ⟨j, hj⟩ := j + simp only [Fin.mk_le_mk] at hij + simp only at * + induction j, hij using Nat.le_induction with + | base => simp + | succ j _hij ih => + specialize ih (Nat.lt_of_succ_lt hj) + have step : p ⟨j, _⟩ < p ⟨j + 1, _⟩:= p.step ⟨j, by omega⟩ + norm_cast at *; omega + +/-- In ℕ, the head and tail of an `LTSeries` differ at least by the length of the series -/ +lemma head_add_length_le_nat (p : LTSeries ℕ) : p.head + p.length ≤ p.last := + LTSeries.apply_add_index_le_apply_add_index_nat _ _ (Fin.last _) (Fin.zero_le _) + +/-- In ℤ, the head and tail of an `LTSeries` differ at least by the length of the series -/ +lemma head_add_length_le_int (p : LTSeries ℤ) : p.head + p.length ≤ p.last := by + simpa using LTSeries.apply_add_index_le_apply_add_index_int _ _ (Fin.last _) (Fin.zero_le _) + +section Fintype + +variable [Fintype α] + +lemma length_lt_card (s : LTSeries α) : s.length < Fintype.card α := by + by_contra! h + obtain ⟨i, j, hn, he⟩ := Fintype.exists_ne_map_eq_of_card_lt s (by rw [Fintype.card_fin]; omega) + wlog hl : i < j generalizing i j + · exact this j i hn.symm he.symm (by omega) + exact absurd he (s.strictMono hl).ne + +instance [DecidableRel ((· < ·) : α → α → Prop)] : Fintype (LTSeries α) where + elems := Finset.univ.map (injStrictMono (Fintype.card α)) + complete s := by + have bl := s.length_lt_card + obtain ⟨l, f, mf⟩ := s + simp_rw [Finset.mem_map, Finset.mem_univ, true_and, Subtype.exists] + use ⟨⟨l, bl⟩, f⟩, Fin.strictMono_iff_lt_succ.mpr mf; rfl + +end Fintype + end LTSeries end LTSeries 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 new file mode 100644 index 0000000000000..511092cd0a000 --- /dev/null +++ b/Mathlib/Order/ScottContinuity.lean @@ -0,0 +1,136 @@ +/- +Copyright (c) 2022 Christopher Hoskin. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christopher Hoskin +-/ +import Mathlib.Order.Bounds.Basic + +/-! +# Scott continuity + +A function `f : α → β` between preorders is Scott continuous (referring to Dana Scott) if it +distributes over `IsLUB`. Scott continuity corresponds to continuity in Scott topological spaces +(defined in `Mathlib/Topology/Order/ScottTopology.lean`). It is distinct from the (more commonly +used) continuity from topology (see `Mathlib/Topology/Basic.lean`). + +## Implementation notes + +Given a set `D` of directed sets, we define say `f` is `ScottContinuousOn D` if it distributes over +`IsLUB` for all elements of `D`. This allows us to consider Scott Continuity on all directed sets +in this file, and ωScott Continuity on chains later in +`Mathlib/Order/OmegaCompletePartialOrder.lean`. + +## References + +* [Abramsky and Jung, *Domain Theory*][abramsky_gabbay_maibaum_1994] +* [Gierz et al, *A Compendium of Continuous Lattices*][GierzEtAl1980] + +-/ + +open Set + +variable {α β : Type*} + +section ScottContinuous +variable [Preorder α] [Preorder β] {D D₁ D₂ : Set (Set α)} {E : Set (Set β)} + {f : α → β} {a : α} + +/-- 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`. + +The dual notion + +```lean +∀ ⦃d : Set α⦄, d ∈ D → d.Nonempty → DirectedOn (· ≥ ·) d → ∀ ⦃a⦄, IsGLB d a → IsGLB (f '' d) (f a) +``` + +does not appear to play a significant role in the literature, so is omitted here. +-/ +def ScottContinuousOn (D : Set (Set α)) (f : α → β) : Prop := + ∀ ⦃d : Set α⦄, d ∈ D → d.Nonempty → DirectedOn (· ≤ ·) d → ∀ ⦃a⦄, IsLUB d a → IsLUB (f '' d) (f a) + +lemma ScottContinuousOn.mono (hD : D₁ ⊆ D₂) (hf : ScottContinuousOn D₂ f) : + ScottContinuousOn D₁ f := fun _ hdD₁ hd₁ hd₂ _ hda => hf (hD hdD₁) hd₁ hd₂ hda + +protected theorem ScottContinuousOn.monotone (D : Set (Set α)) (hD : ∀ a b : α, a ≤ b → {a, b} ∈ D) + (h : ScottContinuousOn D f) : Monotone f := by + refine fun a b hab => + (h (hD a b hab) (insert_nonempty _ _) (directedOn_pair le_refl hab) ?_).1 + (mem_image_of_mem _ <| mem_insert _ _) + rw [IsLUB, upperBounds_insert, upperBounds_singleton, + inter_eq_self_of_subset_right (Ici_subset_Ici.2 hab)] + exact isLeast_Ici + +@[simp] lemma ScottContinuousOn.id : ScottContinuousOn D (id : α → α) := by simp [ScottContinuousOn] + +variable {g : α → β} + +lemma ScottContinuousOn.prodMk (hD : ∀ a b : α, a ≤ b → {a, b} ∈ D) + (hf : ScottContinuousOn D f) (hg : ScottContinuousOn D g) : + ScottContinuousOn D fun x => (f x, g x) := fun d hd₁ hd₂ hd₃ a hda => by + 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] + intro b hb + exact ⟨hf.monotone D hD (hda.1 hb), hg.monotone D hD (hda.1 hb)⟩ + · intro ⟨p₁, p₂⟩ hp + simp only [mem_image, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂, mem_setOf_eq, + Prod.mk_le_mk] at hp + constructor + · rw [isLUB_le_iff (hf hd₁ hd₂ hd₃ hda), upperBounds] + simp only [mem_image, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂, mem_setOf_eq] + intro _ hb + exact (hp _ hb).1 + · rw [isLUB_le_iff (hg hd₁ hd₂ hd₃ hda), upperBounds] + simp only [mem_image, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂, mem_setOf_eq] + intro _ hb + exact (hp _ hb).2 + +/-- A function between preorders is said to be Scott continuous if it preserves `IsLUB` on directed +sets. It can be shown that a function is Scott continuous if and only if it is continuous wrt the +Scott topology. +-/ +def ScottContinuous (f : α → β) : Prop := + ∀ ⦃d : Set α⦄, d.Nonempty → DirectedOn (· ≤ ·) d → ∀ ⦃a⦄, IsLUB d a → IsLUB (f '' d) (f a) + +@[simp] lemma scottContinuousOn_univ : ScottContinuousOn univ f ↔ ScottContinuous f := by + simp [ScottContinuousOn, ScottContinuous] + +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 _ _ _ ↦ mem_univ _) + +@[simp] lemma ScottContinuous.id : ScottContinuous (id : α → α) := by simp [ScottContinuous] + +end ScottContinuous + +section SemilatticeSup + +variable [Preorder α] [SemilatticeSup β] + +lemma ScottContinuousOn.sup₂ {D : Set (Set (β × β))} : + ScottContinuousOn D fun (a, b) => (a ⊔ b : β) := by + simp only + intro d _ _ _ ⟨p₁, p₂⟩ hdp + rw [IsLUB, IsLeast, upperBounds] at hdp + simp only [Prod.forall, mem_setOf_eq, Prod.mk_le_mk] at hdp + rw [IsLUB, IsLeast, upperBounds] + constructor + · simp only [mem_image, Prod.exists, forall_exists_index, and_imp, mem_setOf_eq] + intro a b₁ b₂ hbd hba + rw [← hba] + exact sup_le_sup (hdp.1 _ _ hbd).1 (hdp.1 _ _ hbd).2 + · simp only [mem_image, Prod.exists, forall_exists_index, and_imp] + intro b hb + simp only [sup_le_iff] + have e1 : (p₁, p₂) ∈ lowerBounds {x | ∀ (b₁ b₂ : β), (b₁, b₂) ∈ d → (b₁, b₂) ≤ x} := hdp.2 + rw [lowerBounds] at e1 + simp only [mem_setOf_eq, Prod.forall, Prod.mk_le_mk] at e1 + apply e1 + intro b₁ b₂ hb' + exact sup_le_iff.mp (hb b₁ b₂ hb' rfl) + +end SemilatticeSup diff --git a/Mathlib/Order/SemiconjSup.lean b/Mathlib/Order/SemiconjSup.lean index 835ea7b923fb9..ebadc1795ef66 100644 --- a/Mathlib/Order/SemiconjSup.lean +++ b/Mathlib/Order/SemiconjSup.lean @@ -96,7 +96,7 @@ theorem semiconj_of_isLUB [PartialOrder α] [Group G] (f₁ f₂ : G →* α ≃ refine fun y => (H _).unique ?_ have := (f₁ g).leftOrdContinuous (H y) rw [← range_comp, ← (Equiv.mulRight g).surjective.range_comp _] at this - simpa [(· ∘ ·)] using this + simpa [comp_def] using this /-- Consider two actions `f₁ f₂ : G → α → α` of a group on a complete lattice by order isomorphisms. Then the map `x ↦ ⨆ g : G, (f₁ g)⁻¹ (f₂ g x)` semiconjugates each `f₁ g'` to `f₂ g'`. diff --git a/Mathlib/Order/SetNotation.lean b/Mathlib/Order/SetNotation.lean index dc586e637b640..7feb44d478558 100644 --- a/Mathlib/Order/SetNotation.lean +++ b/Mathlib/Order/SetNotation.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, Patrick Massot, Yury Kudryashov -/ -import Mathlib.Data.Set.Defs +import Mathlib.Data.Set.Operations import Mathlib.Util.Notation3 /-! diff --git a/Mathlib/Order/SuccPred/Archimedean.lean b/Mathlib/Order/SuccPred/Archimedean.lean new file mode 100644 index 0000000000000..0db5ba2b12320 --- /dev/null +++ b/Mathlib/Order/SuccPred/Archimedean.lean @@ -0,0 +1,300 @@ +/- +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.Order.SuccPred.Basic + +/-! +# Archimedean successor and predecessor + +* `IsSuccArchimedean`: `SuccOrder` where `succ` iterated to an element gives all the greater + ones. +* `IsPredArchimedean`: `PredOrder` where `pred` iterated to an element gives all the smaller + ones. +-/ + +variable {α β : Type*} + +open Order Function + +/-- A `SuccOrder` is succ-archimedean if one can go from any two comparable elements by iterating +`succ` -/ +class IsSuccArchimedean (α : Type*) [Preorder α] [SuccOrder α] : Prop where + /-- If `a ≤ b` then one can get to `a` from `b` by iterating `succ` -/ + exists_succ_iterate_of_le {a b : α} (h : a ≤ b) : ∃ n, succ^[n] a = b + +/-- A `PredOrder` is pred-archimedean if one can go from any two comparable elements by iterating +`pred` -/ +class IsPredArchimedean (α : Type*) [Preorder α] [PredOrder α] : Prop where + /-- If `a ≤ b` then one can get to `b` from `a` by iterating `pred` -/ + exists_pred_iterate_of_le {a b : α} (h : a ≤ b) : ∃ n, pred^[n] b = a + +export IsSuccArchimedean (exists_succ_iterate_of_le) + +export IsPredArchimedean (exists_pred_iterate_of_le) + +section Preorder + +variable [Preorder α] + +section SuccOrder + +variable [SuccOrder α] [IsSuccArchimedean α] {a b : α} + +instance : IsPredArchimedean αᵒᵈ := + ⟨fun {a b} h => by convert exists_succ_iterate_of_le h.ofDual⟩ + +theorem LE.le.exists_succ_iterate (h : a ≤ b) : ∃ n, succ^[n] a = b := + exists_succ_iterate_of_le h + +theorem exists_succ_iterate_iff_le : (∃ n, succ^[n] a = b) ↔ a ≤ b := by + refine ⟨?_, exists_succ_iterate_of_le⟩ + rintro ⟨n, rfl⟩ + exact id_le_iterate_of_id_le le_succ n a + +/-- Induction principle on a type with a `SuccOrder` for all elements above a given element `m`. -/ +@[elab_as_elim] +theorem Succ.rec {P : α → Prop} {m : α} (h0 : P m) (h1 : ∀ n, m ≤ n → P n → P (succ n)) ⦃n : α⦄ + (hmn : m ≤ n) : P n := by + obtain ⟨n, rfl⟩ := hmn.exists_succ_iterate; clear hmn + induction' n with n ih + · exact h0 + · rw [Function.iterate_succ_apply'] + exact h1 _ (id_le_iterate_of_id_le le_succ n m) ih + +theorem Succ.rec_iff {p : α → Prop} (hsucc : ∀ a, p a ↔ p (succ a)) {a b : α} (h : a ≤ b) : + p a ↔ p b := by + 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 + +end SuccOrder + +section PredOrder + +variable [PredOrder α] [IsPredArchimedean α] {a b : α} + +instance : IsSuccArchimedean αᵒᵈ := + ⟨fun {a b} h => by convert exists_pred_iterate_of_le h.ofDual⟩ + +theorem LE.le.exists_pred_iterate (h : a ≤ b) : ∃ n, pred^[n] b = a := + exists_pred_iterate_of_le h + +theorem exists_pred_iterate_iff_le : (∃ n, pred^[n] b = a) ↔ a ≤ b := + exists_succ_iterate_iff_le (α := αᵒᵈ) + +/-- Induction principle on a type with a `PredOrder` for all elements below a given element `m`. -/ +@[elab_as_elim] +theorem Pred.rec {P : α → Prop} {m : α} (h0 : P m) (h1 : ∀ n, n ≤ m → P n → P (pred n)) ⦃n : α⦄ + (hmn : n ≤ m) : P n := + Succ.rec (α := αᵒᵈ) (P := P) h0 h1 hmn + +theorem Pred.rec_iff {p : α → Prop} (hsucc : ∀ a, p a ↔ p (pred a)) {a b : α} (h : a ≤ b) : + p a ↔ p b := + (Succ.rec_iff (α := αᵒᵈ) hsucc h).symm + +end PredOrder + +end Preorder + +section LinearOrder + +variable [LinearOrder α] + +section SuccOrder +variable [SuccOrder α] + +lemma succ_max (a b : α) : succ (max a b) = max (succ a) (succ b) := succ_mono.map_max +lemma succ_min (a b : α) : succ (min a b) = min (succ a) (succ b) := succ_mono.map_min + +variable [IsSuccArchimedean α] {a b : α} + +theorem exists_succ_iterate_or : (∃ n, succ^[n] a = b) ∨ ∃ n, succ^[n] b = a := + (le_total a b).imp exists_succ_iterate_of_le exists_succ_iterate_of_le + +theorem Succ.rec_linear {p : α → Prop} (hsucc : ∀ a, p a ↔ p (succ a)) (a b : α) : p a ↔ p b := + (le_total a b).elim (Succ.rec_iff hsucc) fun h => (Succ.rec_iff hsucc h).symm + +end SuccOrder + +section PredOrder +variable [PredOrder α] + +lemma pred_max (a b : α) : pred (max a b) = max (pred a) (pred b) := pred_mono.map_max +lemma pred_min (a b : α) : pred (min a b) = min (pred a) (pred b) := pred_mono.map_min + +variable [IsPredArchimedean α] {a b : α} + +theorem exists_pred_iterate_or : (∃ n, pred^[n] b = a) ∨ ∃ n, pred^[n] a = b := + (le_total a b).imp exists_pred_iterate_of_le exists_pred_iterate_of_le + +theorem Pred.rec_linear {p : α → Prop} (hsucc : ∀ a, p a ↔ p (pred a)) (a b : α) : p a ↔ p b := + (le_total a b).elim (Pred.rec_iff hsucc) fun h => (Pred.rec_iff hsucc h).symm + +end PredOrder + +end LinearOrder + +section bdd_range +variable [Preorder α] [Nonempty α] [Preorder β] {f : α → β} + +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 α› + suffices ∀ b, f a₀ ≤ b → ∃ a, b < f a by + obtain ⟨a, ha⟩ : ∃ a, m < f a := this m (hm' a₀) + exact ha.not_le (hm' a) + have h : ∀ a, ∃ a', f a < f a' := fun a ↦ (exists_gt a).imp (fun a' h ↦ hf h) + apply Succ.rec + · exact h a₀ + rintro b _ ⟨a, hba⟩ + exact (h a).imp (fun a' ↦ (succ_le_of_lt hba).trans_lt) + +@[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 + +@[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_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 + +section IsWellFounded + +variable [PartialOrder α] + +instance (priority := 100) WellFoundedLT.toIsPredArchimedean [h : WellFoundedLT α] + [PredOrder α] : IsPredArchimedean α := + ⟨fun {a b} => by + refine WellFounded.fix (C := fun b => a ≤ b → ∃ n, Nat.iterate pred n b = a) + h.wf ?_ b + intros b ih hab + replace hab := eq_or_lt_of_le hab + rcases hab with (rfl | hab) + · exact ⟨0, rfl⟩ + rcases eq_or_lt_of_le (pred_le b) with hb | hb + · cases (min_of_le_pred hb.ge).not_lt hab + dsimp at ih + obtain ⟨k, hk⟩ := ih (pred b) hb (le_pred_of_lt hab) + refine ⟨k + 1, ?_⟩ + rw [iterate_add_apply, iterate_one, hk]⟩ + +instance (priority := 100) WellFoundedGT.toIsSuccArchimedean [h : WellFoundedGT α] + [SuccOrder α] : IsSuccArchimedean α := + let h : IsPredArchimedean αᵒᵈ := by infer_instance + ⟨h.1⟩ + +end IsWellFounded + +section OrderBot + +variable [Preorder α] [OrderBot α] [SuccOrder α] [IsSuccArchimedean α] + +theorem Succ.rec_bot (p : α → Prop) (hbot : p ⊥) (hsucc : ∀ a, p a → p (succ a)) (a : α) : p a := + Succ.rec hbot (fun x _ h => hsucc x h) (bot_le : ⊥ ≤ a) + +end OrderBot + +section OrderTop + +variable [Preorder α] [OrderTop α] [PredOrder α] [IsPredArchimedean α] + +theorem Pred.rec_top (p : α → Prop) (htop : p ⊤) (hpred : ∀ a, p a → p (pred a)) (a : α) : p a := + Pred.rec htop (fun x _ h => hpred x h) (le_top : a ≤ ⊤) + +end OrderTop + +lemma SuccOrder.forall_ne_bot_iff + [Nontrivial α] [PartialOrder α] [OrderBot α] [SuccOrder α] [IsSuccArchimedean α] + (P : α → Prop) : + (∀ i, i ≠ ⊥ → P i) ↔ (∀ i, P (SuccOrder.succ i)) := by + refine ⟨fun h i ↦ h _ (Order.succ_ne_bot i), fun h i hi ↦ ?_⟩ + obtain ⟨j, rfl⟩ := exists_succ_iterate_of_le (bot_le : ⊥ ≤ i) + have hj : 0 < j := by apply Nat.pos_of_ne_zero; contrapose! hi; simp [hi] + 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 diff --git a/Mathlib/Order/SuccPred/Basic.lean b/Mathlib/Order/SuccPred/Basic.lean index bf1c20483de89..43142cc9da386 100644 --- a/Mathlib/Order/SuccPred/Basic.lean +++ b/Mathlib/Order/SuccPred/Basic.lean @@ -3,11 +3,9 @@ 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.Order.CompleteLattice +import Mathlib.Order.ConditionallyCompleteLattice.Basic import Mathlib.Order.Cover -import Mathlib.Order.GaloisConnection import Mathlib.Order.Iterate -import Mathlib.Order.WellFounded /-! # Successor and predecessor @@ -21,16 +19,12 @@ order... * `SuccOrder`: Order equipped with a sensible successor function. * `PredOrder`: Order equipped with a sensible predecessor function. -* `IsSuccArchimedean`: `SuccOrder` where `succ` iterated to an element gives all the greater - ones. -* `IsPredArchimedean`: `PredOrder` where `pred` iterated to an element gives all the smaller - ones. ## Implementation notes 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) @@ -44,7 +38,6 @@ The stricter condition of every element having a sensible successor can be obtai combination of `SuccOrder α` and `NoMaxOrder α`. -/ - open Function OrderDual Set variable {α β : Type*} @@ -52,30 +45,26 @@ variable {α β : Type*} /-- Order equipped with a sensible successor function. -/ @[ext] class SuccOrder (α : Type*) [Preorder α] where - /-- Successor function-/ + /-- Successor function -/ succ : α → α /-- Proof of basic ordering with respect to `succ`-/ le_succ : ∀ a, a ≤ succ a - /-- Proof of interaction between `succ` and maximal element-/ + /-- Proof of interaction between `succ` and maximal element -/ max_of_succ_le {a} : succ a ≤ a → IsMax a - /-- Proof that `succ` satisfies ordering invariants between `LT` and `LE`-/ + /-- Proof that `succ a` is the least element greater than `a`-/ succ_le_of_lt {a b} : a < b → succ a ≤ b - /-- Proof that `succ` satisfies ordering invariants between `LE` and `LT`-/ - le_of_lt_succ {a b} : a < succ b → a ≤ b /-- Order equipped with a sensible predecessor function. -/ @[ext] class PredOrder (α : Type*) [Preorder α] where - /-- Predecessor function-/ + /-- Predecessor function -/ pred : α → α /-- Proof of basic ordering with respect to `pred`-/ pred_le : ∀ a, pred a ≤ a - /-- Proof of interaction between `pred` and minimal element-/ + /-- Proof of interaction between `pred` and minimal element -/ min_of_le_pred {a} : a ≤ pred a → IsMin a - /-- Proof that `pred` satisfies ordering invariants between `LT` and `LE`-/ + /-- Proof that `pred b` is the greatest element less than `b`-/ le_pred_of_lt {a b} : a < b → a ≤ pred b - /-- Proof that `pred` satisfies ordering invariants between `LE` and `LT`-/ - le_of_pred_lt {a b} : pred a < b → a ≤ b instance [Preorder α] [SuccOrder α] : PredOrder αᵒᵈ where @@ -85,7 +74,6 @@ instance [Preorder α] [SuccOrder α] : SuccOrder.le_succ, implies_true] min_of_le_pred h := by apply SuccOrder.max_of_succ_le h le_pred_of_lt := by intro a b h; exact SuccOrder.succ_le_of_lt h - le_of_pred_lt := SuccOrder.le_of_lt_succ instance [Preorder α] [PredOrder α] : SuccOrder αᵒᵈ where @@ -95,29 +83,26 @@ instance [Preorder α] [PredOrder α] : PredOrder.pred_le, implies_true] max_of_succ_le h := by apply PredOrder.min_of_le_pred h succ_le_of_lt := by intro a b h; exact PredOrder.le_pred_of_lt h - le_of_lt_succ := PredOrder.le_of_pred_lt section Preorder variable [Preorder α] /-- A constructor for `SuccOrder α` usable when `α` has no maximal element. -/ -def SuccOrder.ofSuccLeIffOfLeLtSucc (succ : α → α) (hsucc_le_iff : ∀ {a b}, succ a ≤ b ↔ a < b) - (hle_of_lt_succ : ∀ {a b}, a < succ b → a ≤ b) : SuccOrder α := +def SuccOrder.ofSuccLeIff (succ : α → α) (hsucc_le_iff : ∀ {a b}, succ a ≤ b ↔ a < b) : + SuccOrder α := { succ le_succ := fun _ => (hsucc_le_iff.1 le_rfl).le max_of_succ_le := fun ha => (lt_irrefl _ <| hsucc_le_iff.1 ha).elim - succ_le_of_lt := fun h => hsucc_le_iff.2 h - le_of_lt_succ := fun h => hle_of_lt_succ h} + succ_le_of_lt := fun h => hsucc_le_iff.2 h } /-- A constructor for `PredOrder α` usable when `α` has no minimal element. -/ -def PredOrder.ofLePredIffOfPredLePred (pred : α → α) (hle_pred_iff : ∀ {a b}, a ≤ pred b ↔ a < b) - (hle_of_pred_lt : ∀ {a b}, pred a < b → a ≤ b) : PredOrder α := +def PredOrder.ofLePredIff (pred : α → α) (hle_pred_iff : ∀ {a b}, a ≤ pred b ↔ a < b) : + PredOrder α := { pred pred_le := fun _ => (hle_pred_iff.1 le_rfl).le min_of_le_pred := fun ha => (lt_irrefl _ <| hle_pred_iff.1 ha).elim - le_pred_of_lt := fun h => hle_pred_iff.2 h - le_of_pred_lt := fun h => hle_of_pred_lt h } + le_pred_of_lt := fun h => hle_pred_iff.2 h } end Preorder @@ -134,13 +119,11 @@ def SuccOrder.ofCore (succ : α → α) (hn : ∀ {a}, ¬IsMax a → ∀ b, a < by_cases (fun h hab => (hm a h).symm ▸ hab.le) fun h => (hn h b).mp le_succ := fun a => by_cases (fun h => (hm a h).symm.le) fun h => le_of_lt <| by simpa using (hn h a).not - le_of_lt_succ := fun {a b} hab => - by_cases (fun h => hm b h ▸ hab.le) fun h => by simpa [hab] using (hn h a).not max_of_succ_le := fun {a} => not_imp_not.mp fun h => by simpa using (hn h a).not } /-- A constructor for `PredOrder α` for `α` a linear order. -/ @[simps] -def PredOrder.ofCore {α} [LinearOrder α] (pred : α → α) +def PredOrder.ofCore (pred : α → α) (hn : ∀ {a}, ¬IsMin a → ∀ b, b ≤ pred a ↔ b < a) (hm : ∀ a, IsMin a → pred a = a) : PredOrder α := { pred @@ -148,32 +131,11 @@ def PredOrder.ofCore {α} [LinearOrder α] (pred : α → α) by_cases (fun h hab => (hm b h).symm ▸ hab.le) fun h => (hn h a).mpr pred_le := fun a => by_cases (fun h => (hm a h).le) fun h => le_of_lt <| by simpa using (hn h a).not - le_of_pred_lt := fun {a b} hab => - by_cases (fun h => hm a h ▸ hab.le) fun h => by simpa [hab] using (hn h b).not min_of_le_pred := fun {a} => not_imp_not.mp fun h => by simpa using (hn h a).not } -/-- A constructor for `SuccOrder α` usable when `α` is a linear order with no maximal element. -/ -def SuccOrder.ofSuccLeIff (succ : α → α) (hsucc_le_iff : ∀ {a b}, succ a ≤ b ↔ a < b) : - SuccOrder α := - { succ - le_succ := fun _ => (hsucc_le_iff.1 le_rfl).le - max_of_succ_le := fun ha => (lt_irrefl _ <| hsucc_le_iff.1 ha).elim - succ_le_of_lt := fun h => hsucc_le_iff.2 h - le_of_lt_succ := fun {_ _} h => le_of_not_lt ((not_congr hsucc_le_iff).1 h.not_le) } - -/-- A constructor for `PredOrder α` usable when `α` is a linear order with no minimal element. -/ -def PredOrder.ofLePredIff (pred : α → α) (hle_pred_iff : ∀ {a b}, a ≤ pred b ↔ a < b) : - PredOrder α := - { pred - pred_le := fun _ => (hle_pred_iff.1 le_rfl).le - min_of_le_pred := fun ha => (lt_irrefl _ <| hle_pred_iff.1 ha).elim - le_pred_of_lt := fun h => hle_pred_iff.2 h - le_of_pred_lt := fun {_ _} h => le_of_not_lt ((not_congr hle_pred_iff).1 h.not_le) } - -open scoped Classical - variable (α) +open Classical in /-- A well-order is a `SuccOrder`. -/ noncomputable def SuccOrder.ofLinearWellFoundedLT [WellFoundedLT α] : SuccOrder α := ofCore (fun a ↦ if h : (Ioi a).Nonempty then wellFounded_lt.min _ h else a) @@ -214,9 +176,6 @@ theorem succ_le_of_lt {a b : α} : a < b → succ a ≤ b := alias _root_.LT.lt.succ_le := succ_le_of_lt -theorem le_of_lt_succ {a b : α} : a < succ b → a ≤ b := - SuccOrder.le_of_lt_succ - @[simp] theorem succ_le_iff_isMax : succ a ≤ a ↔ IsMax a := ⟨max_of_succ_le, fun h => h <| le_succ _⟩ @@ -235,22 +194,14 @@ theorem wcovBy_succ (a : α) : a ⩿ succ a := theorem covBy_succ_of_not_isMax (h : ¬IsMax a) : a ⋖ succ a := (wcovBy_succ a).covBy_of_lt <| lt_succ_of_not_isMax h -theorem lt_succ_iff_of_not_isMax (ha : ¬IsMax a) : b < succ a ↔ b ≤ a := - ⟨le_of_lt_succ, fun h => h.trans_lt <| lt_succ_of_not_isMax ha⟩ +theorem lt_succ_of_le_of_not_isMax (hab : b ≤ a) (ha : ¬IsMax a) : b < succ a := + hab.trans_lt <| lt_succ_of_not_isMax ha theorem succ_le_iff_of_not_isMax (ha : ¬IsMax a) : succ a ≤ b ↔ a < b := ⟨(lt_succ_of_not_isMax ha).trans_le, succ_le_of_lt⟩ lemma succ_lt_succ_of_not_isMax (h : a < b) (hb : ¬ IsMax b) : succ a < succ b := - (lt_succ_iff_of_not_isMax hb).2 <| succ_le_of_lt h - -theorem succ_lt_succ_iff_of_not_isMax (ha : ¬IsMax a) (hb : ¬IsMax b) : - succ a < succ b ↔ a < b := by - rw [lt_succ_iff_of_not_isMax hb, succ_le_iff_of_not_isMax ha] - -theorem succ_le_succ_iff_of_not_isMax (ha : ¬IsMax a) (hb : ¬IsMax b) : - succ a ≤ succ b ↔ a ≤ b := by - rw [succ_le_iff_of_not_isMax ha, lt_succ_iff_of_not_isMax hb] + lt_succ_of_le_of_not_isMax (succ_le_of_lt h) hb @[simp, mono] theorem succ_le_succ (h : a ≤ b) : succ a ≤ succ b := by @@ -258,7 +209,8 @@ theorem succ_le_succ (h : a ≤ b) : succ a ≤ succ b := by · by_cases hba : b ≤ a · exact (hb <| hba.trans <| le_succ _).trans (le_succ _) · exact succ_le_of_lt ((h.lt_of_not_le hba).trans_le <| le_succ b) - · rwa [succ_le_iff_of_not_isMax fun ha => hb <| ha.mono h, lt_succ_iff_of_not_isMax hb] + · rw [succ_le_iff_of_not_isMax fun ha => hb <| ha.mono h] + apply lt_succ_of_le_of_not_isMax h hb theorem succ_mono : Monotone (succ : α → α) := fun _ _ => succ_le_succ @@ -266,20 +218,18 @@ theorem succ_mono : Monotone (succ : α → α) := fun _ _ => succ_le_succ lemma le_succ_of_wcovBy (h : a ⩿ b) : b ≤ succ a := by obtain hab | ⟨-, hba⟩ := h.covBy_or_le_and_le · by_contra hba - exact h.2 (lt_succ_of_not_isMax hab.lt.not_isMax) $ hab.lt.succ_le.lt_of_not_le hba + exact h.2 (lt_succ_of_not_isMax hab.lt.not_isMax) <| hab.lt.succ_le.lt_of_not_le hba · exact hba.trans (le_succ _) 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 @@ -290,17 +240,23 @@ theorem isMax_iterate_succ_of_eq_of_ne {n m : ℕ} (h_eq : succ^[n] a = succ^[m] · rw [h_eq] exact isMax_iterate_succ_of_eq_of_lt h_eq.symm (lt_of_le_of_ne h h_ne.symm) -theorem Iio_succ_of_not_isMax (ha : ¬IsMax a) : Iio (succ a) = Iic a := - Set.ext fun _ => lt_succ_iff_of_not_isMax ha +theorem Iic_subset_Iio_succ_of_not_isMax (ha : ¬IsMax a) : Iic a ⊆ Iio (succ a) := + fun _ => (lt_succ_of_le_of_not_isMax · ha) theorem Ici_succ_of_not_isMax (ha : ¬IsMax a) : Ici (succ a) = Ioi a := Set.ext fun _ => succ_le_iff_of_not_isMax ha -theorem Ico_succ_right_of_not_isMax (hb : ¬IsMax b) : Ico a (succ b) = Icc a b := by - rw [← Ici_inter_Iio, Iio_succ_of_not_isMax hb, Ici_inter_Iic] +theorem Icc_subset_Ico_succ_right_of_not_isMax (hb : ¬IsMax b) : Icc a b ⊆ Ico a (succ b) := by + rw [← Ici_inter_Iio, ← Ici_inter_Iic] + gcongr + intro _ h + apply lt_succ_of_le_of_not_isMax h hb -theorem Ioo_succ_right_of_not_isMax (hb : ¬IsMax b) : Ioo a (succ b) = Ioc a b := by - rw [← Ioi_inter_Iio, Iio_succ_of_not_isMax hb, Ioi_inter_Iic] +theorem Ioc_subset_Ioo_succ_right_of_not_isMax (hb : ¬IsMax b) : Ioc a b ⊆ Ioo a (succ b) := by + rw [← Ioi_inter_Iio, ← Ioi_inter_Iic] + gcongr + intro _ h + apply Iic_subset_Iio_succ_of_not_isMax hb h theorem Icc_succ_left_of_not_isMax (ha : ¬IsMax a) : Icc (succ a) b = Ioc a b := by rw [← Ici_inter_Iic, Ici_succ_of_not_isMax ha, Ioi_inter_Iic] @@ -316,20 +272,14 @@ theorem lt_succ (a : α) : a < succ a := lt_succ_of_not_isMax <| not_isMax a @[simp] -theorem lt_succ_iff : a < succ b ↔ a ≤ b := - lt_succ_iff_of_not_isMax <| not_isMax b +theorem lt_succ_of_le : a ≤ b → a < succ b := + (lt_succ_of_le_of_not_isMax · <| not_isMax b) @[simp] theorem succ_le_iff : succ a ≤ b ↔ a < b := succ_le_iff_of_not_isMax <| not_isMax a -theorem succ_le_succ_iff : succ a ≤ succ b ↔ a ≤ b := by simp - -theorem succ_lt_succ_iff : succ a < succ b ↔ a < b := by simp - -alias ⟨le_of_succ_le_succ, _⟩ := succ_le_succ_iff - -alias ⟨lt_of_succ_lt_succ, succ_lt_succ⟩ := succ_lt_succ_iff +@[gcongr] theorem succ_lt_succ (hab : a < b) : succ a < succ b := by simp [hab] theorem succ_strictMono : StrictMono (succ : α → α) := fun _ _ => succ_lt_succ @@ -337,20 +287,20 @@ theorem covBy_succ (a : α) : a ⋖ succ a := covBy_succ_of_not_isMax <| not_isMax a @[simp] -theorem Iio_succ (a : α) : Iio (succ a) = Iic a := - Iio_succ_of_not_isMax <| not_isMax _ +theorem Iic_subset_Iio_succ (a : α) : Iic a ⊆ Iio (succ a) := + Iic_subset_Iio_succ_of_not_isMax <| not_isMax _ @[simp] theorem Ici_succ (a : α) : Ici (succ a) = Ioi a := Ici_succ_of_not_isMax <| not_isMax _ @[simp] -theorem Ico_succ_right (a b : α) : Ico a (succ b) = Icc a b := - Ico_succ_right_of_not_isMax <| not_isMax _ +theorem Icc_subset_Ico_succ_right (a b : α) : Icc a b ⊆ Ico a (succ b) := + Icc_subset_Ico_succ_right_of_not_isMax <| not_isMax _ @[simp] -theorem Ioo_succ_right (a b : α) : Ioo a (succ b) = Ioc a b := - Ioo_succ_right_of_not_isMax <| not_isMax _ +theorem Ioc_subset_Ioo_succ_right (a b : α) : Ioc a b ⊆ Ioo a (succ b) := + Ioc_subset_Ioo_succ_right_of_not_isMax <| not_isMax _ @[simp] theorem Icc_succ_left (a b : α) : Icc (succ a) b = Ioc a b := @@ -374,11 +324,6 @@ theorem succ_eq_iff_isMax : succ a = a ↔ IsMax a := alias ⟨_, _root_.IsMax.succ_eq⟩ := succ_eq_iff_isMax -theorem succ_eq_succ_iff_of_not_isMax (ha : ¬IsMax a) (hb : ¬IsMax b) : - succ a = succ b ↔ a = b := by - rw [eq_iff_le_not_lt, eq_iff_le_not_lt, succ_le_succ_iff_of_not_isMax ha hb, - succ_lt_succ_iff_of_not_isMax ha hb] - theorem le_le_succ_iff : a ≤ b ∧ b ≤ succ a ↔ b = a ∨ b = succ a := by refine ⟨fun h => @@ -394,6 +339,84 @@ lemma succ_eq_of_covBy (h : a ⋖ b) : succ a = b := (succ_le_of_lt h.lt).antisy alias _root_.CovBy.succ_eq := succ_eq_of_covBy +theorem _root_.OrderIso.map_succ {β : Type*} [PartialOrder β] [SuccOrder β] (f : α ≃o β) (a : α) : + f (succ a) = succ (f a) := by + by_cases h : IsMax a + · rw [h.succ_eq, (f.isMax_apply.2 h).succ_eq] + · exact (f.map_covBy.2 <| covBy_succ_of_not_isMax h).succ_eq.symm + +section NoMaxOrder + +variable [NoMaxOrder α] + +theorem succ_eq_iff_covBy : succ a = b ↔ a ⋖ b := + ⟨by rintro rfl; exact covBy_succ _, CovBy.succ_eq⟩ + +end NoMaxOrder + +section OrderTop + +variable [OrderTop α] + +@[simp] +theorem succ_top : succ (⊤ : α) = ⊤ := by + rw [succ_eq_iff_isMax, isMax_iff_eq_top] + +theorem succ_le_iff_eq_top : succ a ≤ a ↔ a = ⊤ := + succ_le_iff_isMax.trans isMax_iff_eq_top + +theorem lt_succ_iff_ne_top : a < succ a ↔ a ≠ ⊤ := + lt_succ_iff_not_isMax.trans not_isMax_iff_ne_top + +end OrderTop + +section OrderBot + +variable [OrderBot α] [Nontrivial α] + +theorem bot_lt_succ (a : α) : ⊥ < succ a := + (lt_succ_of_not_isMax not_isMax_bot).trans_le <| succ_mono bot_le + +theorem succ_ne_bot (a : α) : succ a ≠ ⊥ := + (bot_lt_succ a).ne' + +end OrderBot + +end PartialOrder + +section LinearOrder + +variable [LinearOrder α] [SuccOrder α] {a b : α} + +theorem le_of_lt_succ {a b : α} : a < succ b → a ≤ b := fun h ↦ by + by_contra! nh + exact (h.trans_le (succ_le_of_lt nh)).false + +theorem lt_succ_iff_of_not_isMax (ha : ¬IsMax a) : b < succ a ↔ b ≤ a := + ⟨le_of_lt_succ, fun h => h.trans_lt <| lt_succ_of_not_isMax ha⟩ + +theorem succ_lt_succ_iff_of_not_isMax (ha : ¬IsMax a) (hb : ¬IsMax b) : + succ a < succ b ↔ a < b := by + rw [lt_succ_iff_of_not_isMax hb, succ_le_iff_of_not_isMax ha] + +theorem succ_le_succ_iff_of_not_isMax (ha : ¬IsMax a) (hb : ¬IsMax b) : + succ a ≤ succ b ↔ a ≤ b := by + rw [succ_le_iff_of_not_isMax ha, lt_succ_iff_of_not_isMax hb] + +theorem Iio_succ_of_not_isMax (ha : ¬IsMax a) : Iio (succ a) = Iic a := + Set.ext fun _ => lt_succ_iff_of_not_isMax ha + +theorem Ico_succ_right_of_not_isMax (hb : ¬IsMax b) : Ico a (succ b) = Icc a b := by + rw [← Ici_inter_Iio, Iio_succ_of_not_isMax hb, Ici_inter_Iic] + +theorem Ioo_succ_right_of_not_isMax (hb : ¬IsMax b) : Ioo a (succ b) = Ioc a b := by + rw [← Ioi_inter_Iio, Iio_succ_of_not_isMax hb, Ioi_inter_Iic] + +theorem succ_eq_succ_iff_of_not_isMax (ha : ¬IsMax a) (hb : ¬IsMax b) : + succ a = succ b ↔ a = b := by + rw [eq_iff_le_not_lt, eq_iff_le_not_lt, succ_le_succ_iff_of_not_isMax ha hb, + succ_lt_succ_iff_of_not_isMax ha hb] + theorem le_succ_iff_eq_or_le : a ≤ succ b ↔ a = succ b ∨ a ≤ b := by by_cases hb : IsMax b · rw [hb.succ_eq, or_iff_right_of_imp le_of_eq] @@ -402,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 @@ -426,6 +454,30 @@ section NoMaxOrder variable [NoMaxOrder α] +@[simp] +theorem lt_succ_iff : a < succ b ↔ a ≤ b := + lt_succ_iff_of_not_isMax <| not_isMax b + +theorem succ_le_succ_iff : succ a ≤ succ b ↔ a ≤ b := by simp +theorem succ_lt_succ_iff : succ a < succ b ↔ a < b := by simp + +alias ⟨le_of_succ_le_succ, _⟩ := succ_le_succ_iff +alias ⟨lt_of_succ_lt_succ, _⟩ := succ_lt_succ_iff + +-- TODO: prove for a succ-archimedean non-linear order with bottom +@[simp] +theorem Iio_succ (a : α) : Iio (succ a) = Iic a := + Iio_succ_of_not_isMax <| not_isMax _ + +@[simp] +theorem Ico_succ_right (a b : α) : Ico a (succ b) = Icc a b := + Ico_succ_right_of_not_isMax <| not_isMax _ + +-- TODO: prove for a succ-archimedean non-linear order +@[simp] +theorem Ioo_succ_right (a b : α) : Ioo a (succ b) = Ioc a b := + Ioo_succ_right_of_not_isMax <| not_isMax _ + @[simp] theorem succ_eq_succ_iff : succ a = succ b ↔ a = b := succ_eq_succ_iff_of_not_isMax (not_isMax a) (not_isMax b) @@ -440,11 +492,6 @@ alias ⟨_, succ_ne_succ⟩ := succ_ne_succ_iff theorem lt_succ_iff_eq_or_lt : a < succ b ↔ a = b ∨ a < b := lt_succ_iff.trans le_iff_eq_or_lt -theorem succ_eq_iff_covBy : succ a = b ↔ a ⋖ b := - ⟨by - rintro rfl - exact covBy_succ _, CovBy.succ_eq⟩ - theorem Iio_succ_eq_insert (a : α) : Iio (succ a) = insert a (Iio a) := Iio_succ_eq_insert_of_not_isMax <| not_isMax a @@ -456,45 +503,18 @@ theorem Ioo_succ_right_eq_insert (h : a < b) : Ioo a (succ b) = insert b (Ioo a end NoMaxOrder -section OrderTop - -variable [OrderTop α] - -@[simp] -theorem succ_top : succ (⊤ : α) = ⊤ := by - rw [succ_eq_iff_isMax, isMax_iff_eq_top] - --- Porting note (#10618): removing @[simp],`simp` can prove it -theorem succ_le_iff_eq_top : succ a ≤ a ↔ a = ⊤ := - succ_le_iff_isMax.trans isMax_iff_eq_top - --- Porting note (#10618): removing @[simp],`simp` can prove it -theorem lt_succ_iff_ne_top : a < succ a ↔ a ≠ ⊤ := - lt_succ_iff_not_isMax.trans not_isMax_iff_ne_top - -end OrderTop - section OrderBot variable [OrderBot α] --- Porting note (#10618): removing @[simp],`simp` can prove it theorem lt_succ_bot_iff [NoMaxOrder α] : a < succ ⊥ ↔ a = ⊥ := by rw [lt_succ_iff, le_bot_iff] theorem le_succ_bot_iff : a ≤ succ ⊥ ↔ a = ⊥ ∨ a = succ ⊥ := by rw [le_succ_iff_eq_or_le, le_bot_iff, or_comm] -variable [Nontrivial α] - -theorem bot_lt_succ (a : α) : ⊥ < succ a := - (lt_succ_of_not_isMax not_isMax_bot).trans_le <| succ_mono bot_le - -theorem succ_ne_bot (a : α) : succ a ≠ ⊥ := - (bot_lt_succ a).ne' - end OrderBot -end PartialOrder +end LinearOrder /-- There is at most one way to define the successors in a `PartialOrder`. -/ instance [PartialOrder α] : Subsingleton (SuccOrder α) := @@ -505,18 +525,21 @@ instance [PartialOrder α] : Subsingleton (SuccOrder α) := · exact (@IsMax.succ_eq _ _ h₀ _ ha).trans ha.succ_eq.symm · exact @CovBy.succ_eq _ _ h₀ _ _ (covBy_succ_of_not_isMax ha)⟩ -section CompleteLattice - -variable [CompleteLattice α] [SuccOrder α] - -theorem succ_eq_iInf (a : α) : succ a = ⨅ (b) (_ : a < b), b := by - refine le_antisymm (le_iInf fun b => le_iInf succ_le_of_lt) ?_ +theorem succ_eq_sInf [CompleteLattice α] [SuccOrder α] (a : α) : + succ a = sInf (Set.Ioi a) := by + apply (le_sInf fun b => succ_le_of_lt).antisymm obtain rfl | ha := eq_or_ne a ⊤ · rw [succ_top] exact le_top - exact iInf₂_le _ (lt_succ_iff_ne_top.2 ha) + · exact sInf_le (lt_succ_iff_ne_top.2 ha) + +theorem succ_eq_iInf [CompleteLattice α] [SuccOrder α] (a : α) : succ a = ⨅ b > a, b := by + rw [succ_eq_sInf, iInf_subtype', iInf, Subtype.range_coe_subtype, Ioi] -end CompleteLattice +theorem succ_eq_csInf [ConditionallyCompleteLattice α] [SuccOrder α] [NoMaxOrder α] (a : α) : + succ a = sInf (Set.Ioi a) := by + apply (le_csInf nonempty_Ioi fun b => succ_le_of_lt).antisymm + exact csInf_le ⟨a, fun b => le_of_lt⟩ <| lt_succ a /-! ### Predecessor order -/ @@ -540,9 +563,6 @@ theorem le_pred_of_lt {a b : α} : a < b → a ≤ pred b := alias _root_.LT.lt.le_pred := le_pred_of_lt -theorem le_of_pred_lt {a b : α} : pred a < b → a ≤ b := - PredOrder.le_of_pred_lt - @[simp] theorem le_pred_iff_isMin : a ≤ pred a ↔ IsMin a := ⟨min_of_le_pred, fun h => h <| pred_le _⟩ @@ -556,27 +576,24 @@ theorem pred_lt_iff_not_isMin : pred a < a ↔ ¬IsMin a := alias ⟨_, pred_lt_of_not_isMin⟩ := pred_lt_iff_not_isMin theorem pred_wcovBy (a : α) : pred a ⩿ a := - ⟨pred_le a, fun _ hb => (le_of_pred_lt hb).not_lt⟩ + ⟨pred_le a, fun _ hb nh => (le_pred_of_lt nh).not_lt hb⟩ theorem pred_covBy_of_not_isMin (h : ¬IsMin a) : pred a ⋖ a := (pred_wcovBy a).covBy_of_lt <| pred_lt_of_not_isMin h -theorem pred_lt_iff_of_not_isMin (ha : ¬IsMin a) : pred a < b ↔ a ≤ b := - ⟨le_of_pred_lt, (pred_lt_of_not_isMin ha).trans_le⟩ +theorem pred_lt_of_not_isMin_of_le (ha : ¬IsMin a) : a ≤ b → pred a < b := + (pred_lt_of_not_isMin ha).trans_le theorem le_pred_iff_of_not_isMin (ha : ¬IsMin a) : b ≤ pred a ↔ b < a := ⟨fun h => h.trans_lt <| pred_lt_of_not_isMin ha, le_pred_of_lt⟩ lemma pred_lt_pred_of_not_isMin (h : a < b) (ha : ¬ IsMin a) : pred a < pred b := - (pred_lt_iff_of_not_isMin ha).2 <| le_pred_of_lt h + pred_lt_of_not_isMin_of_le ha <| le_pred_of_lt h -theorem pred_lt_pred_iff_of_not_isMin (ha : ¬IsMin a) (hb : ¬IsMin b) : - pred a < pred b ↔ a < b := by - rw [pred_lt_iff_of_not_isMin ha, le_pred_iff_of_not_isMin hb] - -theorem pred_le_pred_iff_of_not_isMin (ha : ¬IsMin a) (hb : ¬IsMin b) : - pred a ≤ pred b ↔ a ≤ b := by - rw [le_pred_iff_of_not_isMin hb, pred_lt_iff_of_not_isMin ha] +theorem pred_le_pred_of_not_isMin_of_le (ha : ¬IsMin a) (hb : ¬IsMin b) : + a ≤ b → pred a ≤ pred b := by + rw [le_pred_iff_of_not_isMin hb] + apply pred_lt_of_not_isMin_of_le ha @[simp, mono] theorem pred_le_pred {a b : α} (h : a ≤ b) : pred a ≤ pred b := @@ -605,17 +622,21 @@ theorem isMin_iterate_pred_of_eq_of_ne {n m : ℕ} (h_eq : pred^[n] a = pred^[m] (h_ne : n ≠ m) : IsMin (pred^[n] a) := @isMax_iterate_succ_of_eq_of_ne αᵒᵈ _ _ _ _ _ h_eq h_ne -theorem Ioi_pred_of_not_isMin (ha : ¬IsMin a) : Ioi (pred a) = Ici a := - Set.ext fun _ => pred_lt_iff_of_not_isMin ha +theorem Ici_subset_Ioi_pred_of_not_isMin (ha : ¬IsMin a) : Ici a ⊆ Ioi (pred a) := + fun _ ↦ pred_lt_of_not_isMin_of_le ha theorem Iic_pred_of_not_isMin (ha : ¬IsMin a) : Iic (pred a) = Iio a := Set.ext fun _ => le_pred_iff_of_not_isMin ha -theorem Ioc_pred_left_of_not_isMin (ha : ¬IsMin a) : Ioc (pred a) b = Icc a b := by - rw [← Ioi_inter_Iic, Ioi_pred_of_not_isMin ha, Ici_inter_Iic] +theorem Icc_subset_Ioc_pred_left_of_not_isMin (ha : ¬IsMin a) : Icc a b ⊆ Ioc (pred a) b := by + rw [← Ioi_inter_Iic, ← Ici_inter_Iic] + gcongr + apply Ici_subset_Ioi_pred_of_not_isMin ha -theorem Ioo_pred_left_of_not_isMin (ha : ¬IsMin a) : Ioo (pred a) b = Ico a b := by - rw [← Ioi_inter_Iio, Ioi_pred_of_not_isMin ha, Ici_inter_Iio] +theorem Ico_subset_Ioo_pred_left_of_not_isMin (ha : ¬IsMin a) : Ico a b ⊆ Ioo (pred a) b := by + rw [← Ioi_inter_Iio, ← Ici_inter_Iio] + gcongr + apply Ici_subset_Ioi_pred_of_not_isMin ha theorem Icc_pred_right_of_not_isMin (ha : ¬IsMin b) : Icc a (pred b) = Ico a b := by rw [← Ici_inter_Iic, Iic_pred_of_not_isMin ha, Ici_inter_Iio] @@ -631,20 +652,16 @@ theorem pred_lt (a : α) : pred a < a := pred_lt_of_not_isMin <| not_isMin a @[simp] -theorem pred_lt_iff : pred a < b ↔ a ≤ b := - pred_lt_iff_of_not_isMin <| not_isMin a +theorem pred_lt_of_le : a ≤ b → pred a < b := + pred_lt_of_not_isMin_of_le <| not_isMin a @[simp] theorem le_pred_iff : a ≤ pred b ↔ a < b := le_pred_iff_of_not_isMin <| not_isMin b -theorem pred_le_pred_iff : pred a ≤ pred b ↔ a ≤ b := by simp - -theorem pred_lt_pred_iff : pred a < pred b ↔ a < b := by simp - -alias ⟨le_of_pred_le_pred, _⟩ := pred_le_pred_iff +theorem pred_le_pred_of_le : a ≤ b → pred a ≤ pred b := by intro; simp_all -alias ⟨lt_of_pred_lt_pred, pred_lt_pred⟩ := pred_lt_pred_iff +theorem pred_lt_pred : a < b → pred a < pred b := by intro; simp_all theorem pred_strictMono : StrictMono (pred : α → α) := fun _ _ => pred_lt_pred @@ -652,20 +669,20 @@ theorem pred_covBy (a : α) : pred a ⋖ a := pred_covBy_of_not_isMin <| not_isMin a @[simp] -theorem Ioi_pred (a : α) : Ioi (pred a) = Ici a := - Ioi_pred_of_not_isMin <| not_isMin a +theorem Ici_subset_Ioi_pred (a : α) : Ici a ⊆ Ioi (pred a) := + Ici_subset_Ioi_pred_of_not_isMin <| not_isMin a @[simp] theorem Iic_pred (a : α) : Iic (pred a) = Iio a := Iic_pred_of_not_isMin <| not_isMin a @[simp] -theorem Ioc_pred_left (a b : α) : Ioc (pred a) b = Icc a b := - Ioc_pred_left_of_not_isMin <| not_isMin _ +theorem Icc_subset_Ioc_pred_left (a b : α) : Icc a b ⊆ Ioc (pred a) b := + Icc_subset_Ioc_pred_left_of_not_isMin <| not_isMin _ @[simp] -theorem Ioo_pred_left (a b : α) : Ioo (pred a) b = Ico a b := - Ioo_pred_left_of_not_isMin <| not_isMin _ +theorem Ico_subset_Ioo_pred_left (a b : α) : Ico a b ⊆ Ioo (pred a) b := + Ico_subset_Ioo_pred_left_of_not_isMin <| not_isMin _ @[simp] theorem Icc_pred_right (a b : α) : Icc a (pred b) = Ico a b := @@ -689,11 +706,6 @@ theorem pred_eq_iff_isMin : pred a = a ↔ IsMin a := alias ⟨_, _root_.IsMin.pred_eq⟩ := pred_eq_iff_isMin -theorem pred_eq_pred_iff_of_not_isMin (ha : ¬IsMin a) (hb : ¬IsMin b) : - pred a = pred b ↔ a = b := by - rw [eq_iff_le_not_lt, eq_iff_le_not_lt, pred_le_pred_iff_of_not_isMin ha hb, - pred_lt_pred_iff_of_not_isMin ha hb] - theorem pred_le_le_iff {a b : α} : pred a ≤ b ∧ b ≤ a ↔ b = a ∨ b = pred a := by refine ⟨fun h => @@ -707,6 +719,84 @@ lemma pred_eq_of_covBy (h : a ⋖ b) : pred b = a := h.wcovBy.pred_le.antisymm ( alias _root_.CovBy.pred_eq := pred_eq_of_covBy +theorem _root_.OrderIso.map_pred {β : Type*} [PartialOrder β] [PredOrder β] (f : α ≃o β) (a : α) : + f (pred a) = pred (f a) := + f.dual.map_succ a + +section NoMinOrder + +variable [NoMinOrder α] + +theorem pred_eq_iff_covBy : pred b = a ↔ a ⋖ b := + ⟨by + rintro rfl + exact pred_covBy _, CovBy.pred_eq⟩ + +end NoMinOrder + +section OrderBot + +variable [OrderBot α] + +@[simp] +theorem pred_bot : pred (⊥ : α) = ⊥ := + isMin_bot.pred_eq + +theorem le_pred_iff_eq_bot : a ≤ pred a ↔ a = ⊥ := + @succ_le_iff_eq_top αᵒᵈ _ _ _ _ + +theorem pred_lt_iff_ne_bot : pred a < a ↔ a ≠ ⊥ := + @lt_succ_iff_ne_top αᵒᵈ _ _ _ _ + +end OrderBot + +section OrderTop + +variable [OrderTop α] [Nontrivial α] + +theorem pred_lt_top (a : α) : pred a < ⊤ := + (pred_mono le_top).trans_lt <| pred_lt_of_not_isMin not_isMin_top + +theorem pred_ne_top (a : α) : pred a ≠ ⊤ := + (pred_lt_top a).ne + +end OrderTop + +end PartialOrder + +section LinearOrder + +variable [LinearOrder α] [PredOrder α] {a b : α} + +theorem le_of_pred_lt {a b : α} : pred a < b → a ≤ b := fun h ↦ by + by_contra! nh + exact le_pred_of_lt nh |>.trans_lt h |>.false + +theorem pred_lt_iff_of_not_isMin (ha : ¬IsMin a) : pred a < b ↔ a ≤ b := + ⟨le_of_pred_lt, (pred_lt_of_not_isMin ha).trans_le⟩ + +theorem pred_lt_pred_iff_of_not_isMin (ha : ¬IsMin a) (hb : ¬IsMin b) : + pred a < pred b ↔ a < b := by + rw [pred_lt_iff_of_not_isMin ha, le_pred_iff_of_not_isMin hb] + +theorem pred_le_pred_iff_of_not_isMin (ha : ¬IsMin a) (hb : ¬IsMin b) : + pred a ≤ pred b ↔ a ≤ b := by + rw [le_pred_iff_of_not_isMin hb, pred_lt_iff_of_not_isMin ha] + +theorem Ioi_pred_of_not_isMin (ha : ¬IsMin a) : Ioi (pred a) = Ici a := + Set.ext fun _ => pred_lt_iff_of_not_isMin ha + +theorem Ioc_pred_left_of_not_isMin (ha : ¬IsMin a) : Ioc (pred a) b = Icc a b := by + rw [← Ioi_inter_Iic, Ioi_pred_of_not_isMin ha, Ici_inter_Iic] + +theorem Ioo_pred_left_of_not_isMin (ha : ¬IsMin a) : Ioo (pred a) b = Ico a b := by + rw [← Ioi_inter_Iio, Ioi_pred_of_not_isMin ha, Ici_inter_Iio] + +theorem pred_eq_pred_iff_of_not_isMin (ha : ¬IsMin a) (hb : ¬IsMin b) : + pred a = pred b ↔ a = b := by + rw [eq_iff_le_not_lt, eq_iff_le_not_lt, pred_le_pred_iff_of_not_isMin ha hb, + pred_lt_pred_iff_of_not_isMin ha hb] + theorem pred_le_iff_eq_or_le : pred a ≤ b ↔ b = pred a ∨ a ≤ b := by by_cases ha : IsMin a · rw [ha.pred_eq, or_iff_right_of_imp ge_of_eq] @@ -715,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 @@ -732,6 +825,32 @@ section NoMinOrder variable [NoMinOrder α] +@[simp] +theorem pred_lt_iff : pred a < b ↔ a ≤ b := + pred_lt_iff_of_not_isMin <| not_isMin a + +theorem pred_le_pred_iff : pred a ≤ pred b ↔ a ≤ b := by simp + +theorem pred_lt_pred_iff : pred a < pred b ↔ a < b := by simp + +alias ⟨le_of_pred_le_pred, _⟩ := pred_le_pred_iff + +alias ⟨lt_of_pred_lt_pred, _⟩ := pred_lt_pred_iff + +-- TODO: prove for a pred-archimedean non-linear order with top +@[simp] +theorem Ioi_pred (a : α) : Ioi (pred a) = Ici a := + Ioi_pred_of_not_isMin <| not_isMin a + +@[simp] +theorem Ioc_pred_left (a b : α) : Ioc (pred a) b = Icc a b := + Ioc_pred_left_of_not_isMin <| not_isMin _ + +-- TODO: prove for a pred-archimedean non-linear order +@[simp] +theorem Ioo_pred_left (a b : α) : Ioo (pred a) b = Ico a b := + Ioo_pred_left_of_not_isMin <| not_isMin _ + @[simp] theorem pred_eq_pred_iff : pred a = pred b ↔ a = b := by simp_rw [eq_iff_le_not_lt, pred_le_pred_iff, pred_lt_pred_iff] @@ -746,11 +865,6 @@ alias ⟨_, pred_ne_pred⟩ := pred_ne_pred_iff theorem pred_lt_iff_eq_or_lt : pred a < b ↔ a = b ∨ a < b := pred_lt_iff.trans le_iff_eq_or_lt -theorem pred_eq_iff_covBy : pred b = a ↔ a ⋖ b := - ⟨by - rintro rfl - exact pred_covBy _, CovBy.pred_eq⟩ - theorem Ioi_pred_eq_insert (a : α) : Ioi (pred a) = insert a (Ioi a) := ext fun _ => pred_lt_iff_eq_or_lt.trans <| or_congr_left eq_comm @@ -762,46 +876,19 @@ theorem Ioo_pred_right_eq_insert (h : a < b) : Ioo (pred a) b = insert a (Ioo a end NoMinOrder -section OrderBot - -variable [OrderBot α] - -@[simp] -theorem pred_bot : pred (⊥ : α) = ⊥ := - isMin_bot.pred_eq - --- Porting note (#10618): removing @[simp],`simp` can prove it -theorem le_pred_iff_eq_bot : a ≤ pred a ↔ a = ⊥ := - @succ_le_iff_eq_top αᵒᵈ _ _ _ _ - --- Porting note (#10618): removing @[simp],`simp` can prove it -theorem pred_lt_iff_ne_bot : pred a < a ↔ a ≠ ⊥ := - @lt_succ_iff_ne_top αᵒᵈ _ _ _ _ - -end OrderBot - section OrderTop variable [OrderTop α] --- Porting note (#10618): removing @[simp],`simp` can prove it theorem pred_top_lt_iff [NoMinOrder α] : pred ⊤ < a ↔ a = ⊤ := @lt_succ_bot_iff αᵒᵈ _ _ _ _ _ theorem pred_top_le_iff : pred ⊤ ≤ a ↔ a = ⊤ ∨ a = pred ⊤ := @le_succ_bot_iff αᵒᵈ _ _ _ _ -variable [Nontrivial α] - -theorem pred_lt_top (a : α) : pred a < ⊤ := - (pred_mono le_top).trans_lt <| pred_lt_of_not_isMin not_isMin_top - -theorem pred_ne_top (a : α) : pred a ≠ ⊤ := - (pred_lt_top a).ne - end OrderTop -end PartialOrder +end LinearOrder /-- There is at most one way to define the predecessors in a `PartialOrder`. -/ instance [PartialOrder α] : Subsingleton (PredOrder α) := @@ -812,18 +899,16 @@ instance [PartialOrder α] : Subsingleton (PredOrder α) := · exact (@IsMin.pred_eq _ _ h₀ _ ha).trans ha.pred_eq.symm · exact @CovBy.pred_eq _ _ h₀ _ _ (pred_covBy_of_not_isMin ha)⟩ -section CompleteLattice +theorem pred_eq_sSup [CompleteLattice α] [PredOrder α] : + ∀ a : α, pred a = sSup (Set.Iio a) := + succ_eq_sInf (α := αᵒᵈ) -variable [CompleteLattice α] [PredOrder α] +theorem pred_eq_iSup [CompleteLattice α] [PredOrder α] (a : α) : pred a = ⨆ b < a, b := + succ_eq_iInf (α := αᵒᵈ) a -theorem pred_eq_iSup (a : α) : pred a = ⨆ (b) (_ : b < a), b := by - refine le_antisymm ?_ (iSup_le fun b => iSup_le le_pred_of_lt) - obtain rfl | ha := eq_or_ne a ⊥ - · rw [pred_bot] - exact bot_le - · exact @le_iSup₂ _ _ (fun b => b < a) _ (fun a _ => a) (pred a) (pred_lt_iff_ne_bot.2 ha) - -end CompleteLattice +theorem pred_eq_csSup [ConditionallyCompleteLattice α] [PredOrder α] [NoMinOrder α] (a : α) : + pred a = sSup (Set.Iio a) := + succ_eq_csInf (α := αᵒᵈ) a /-! ### Successor-predecessor orders -/ @@ -842,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 := @@ -852,11 +937,9 @@ theorem succ_pred_of_not_isMin (h : ¬IsMin a) : succ (pred a) = a := theorem pred_succ_of_not_isMax (h : ¬IsMax a) : pred (succ a) = a := CovBy.pred_eq (covBy_succ_of_not_isMax h) --- Porting note (#10618): removing @[simp],`simp` can prove it theorem succ_pred [NoMinOrder α] (a : α) : succ (pred a) = a := CovBy.succ_eq (pred_covBy _) --- Porting note (#10618): removing @[simp],`simp` can prove it theorem pred_succ [NoMaxOrder α] (a : α) : pred (succ a) = a := CovBy.pred_eq (covBy_succ _) @@ -909,13 +992,13 @@ namespace WithTop section Succ -variable [DecidableEq α] [PartialOrder α] [OrderTop α] [SuccOrder α] +variable [DecidableEq α] [PartialOrder α] [SuccOrder α] instance : SuccOrder (WithTop α) where succ a := match a with | ⊤ => ⊤ - | Option.some a => ite (a = ⊤) ⊤ (some (succ a)) + | Option.some a => ite (succ a = a) ⊤ (some (succ a)) le_succ a := by cases' a with a a · exact le_top @@ -929,7 +1012,7 @@ instance : SuccOrder (WithTop α) where dsimp only at ha split_ifs at ha with ha' · exact (not_top_le_coe _ ha).elim - · rw [coe_le_coe, succ_le_iff_eq_top] at ha + · rw [coe_le_coe, succ_le_iff_isMax, ← succ_eq_iff_isMax] at ha exact (ha' ha).elim succ_le_of_lt {a b} h := by cases b @@ -939,27 +1022,20 @@ instance : SuccOrder (WithTop α) where rw [coe_lt_coe] at h change ite _ _ _ ≤ _ split_ifs with ha - · rw [ha] at h - exact (not_top_lt h).elim + · rw [succ_eq_iff_isMax] at ha + exact (ha.not_lt h).elim · exact coe_le_coe.2 (succ_le_of_lt h) - le_of_lt_succ {a b} h := by - cases a - · exact (not_top_lt h).elim - cases b - · exact le_top - dsimp only at h - rw [coe_le_coe] - split_ifs at h with hb - · rw [hb] - exact le_top - · exact le_of_lt_succ (coe_lt_coe.1 h) @[simp] -theorem succ_coe_top : succ ↑(⊤ : α) = (⊤ : WithTop α) := - dif_pos rfl +theorem succ_coe_of_isMax {a : α} (h : IsMax a) : succ ↑a = (⊤ : WithTop α) := + dif_pos (succ_eq_iff_isMax.2 h) + +theorem succ_coe_of_not_isMax {a : α} (h : ¬ IsMax a) : succ (↑a : WithTop α) = ↑(succ a) := + dif_neg (succ_eq_iff_isMax.not.2 h) -theorem succ_coe_of_ne_top {a : α} (h : a ≠ ⊤) : succ (↑a : WithTop α) = ↑(succ a) := - dif_neg h +@[simp] +theorem succ_coe [NoMaxOrder α] {a : α} : succ (↑a : WithTop α) = ↑(succ a) := + succ_coe_of_not_isMax <| not_isMax a end Succ @@ -986,12 +1062,6 @@ instance : PredOrder (WithTop α) where cases b · exact coe_le_coe.2 le_top exact coe_le_coe.2 (le_pred_of_lt <| coe_lt_coe.1 h) - le_of_pred_lt {a b} h := by - cases b - · exact le_top - cases a - · exact (not_top_lt <| coe_lt_coe.1 h).elim - · exact coe_le_coe.2 (le_of_pred_lt <| coe_lt_coe.1 h) @[simp] theorem pred_top : pred (⊤ : WithTop α) = ↑(⊤ : α) := @@ -1010,44 +1080,6 @@ theorem pred_untop : end Pred -/-! #### Adding a `⊤` to a `NoMaxOrder` -/ - -section Succ - -variable [Preorder α] [NoMaxOrder α] [SuccOrder α] - -instance succOrderOfNoMaxOrder : SuccOrder (WithTop α) where - succ a := - match a with - | ⊤ => ⊤ - | Option.some a => some (succ a) - le_succ a := by - cases' a with a a - · exact le_top - · exact coe_le_coe.2 (le_succ a) - max_of_succ_le {a} ha := by - cases a - · exact isMax_top - · exact (not_isMax _ <| max_of_succ_le <| coe_le_coe.1 ha).elim - succ_le_of_lt {a b} h := by - cases a - · exact (not_top_lt h).elim - cases b - · exact le_top - · exact coe_le_coe.2 (succ_le_of_lt <| coe_lt_coe.1 h) - le_of_lt_succ {a b} h := by - cases a - · exact (not_top_lt h).elim - cases b - · exact le_top - · exact coe_le_coe.2 (le_of_lt_succ <| coe_lt_coe.1 h) - -@[simp] -theorem succ_coe (a : α) : succ (↑a : WithTop α) = ↑(succ a) := - rfl - -end Succ - section Pred variable [Preorder α] [NoMaxOrder α] @@ -1059,7 +1091,7 @@ instance [hα : Nonempty α] : IsEmpty (PredOrder (WithTop α)) := · exact hα.elim fun a => (min_of_le_pred h.ge).not_lt <| coe_lt_top a · obtain ⟨c, hc⟩ := exists_gt a rw [← coe_lt_coe, ← h] at hc - exact (le_of_pred_lt hc).not_lt (coe_lt_top _)⟩ + exact (le_pred_of_lt (coe_lt_top c)).not_lt hc⟩ end Pred @@ -1092,12 +1124,6 @@ instance : SuccOrder (WithBot α) where cases a · exact coe_le_coe.2 bot_le · exact coe_le_coe.2 (succ_le_of_lt <| coe_lt_coe.1 h) - le_of_lt_succ {a b} h := by - cases a - · exact bot_le - cases b - · exact (not_lt_bot <| coe_lt_coe.1 h).elim - · exact coe_le_coe.2 (le_of_lt_succ <| coe_lt_coe.1 h) @[simp] theorem succ_bot : succ (⊥ : WithBot α) = ↑(⊥ : α) := @@ -1118,13 +1144,13 @@ end Succ section Pred -variable [DecidableEq α] [PartialOrder α] [OrderBot α] [PredOrder α] +variable [DecidableEq α] [PartialOrder α] [PredOrder α] instance : PredOrder (WithBot α) where pred a := match a with | ⊥ => ⊥ - | Option.some a => ite (a = ⊥) ⊥ (some (pred a)) + | Option.some a => ite (pred a = a) ⊥ (some (pred a)) pred_le a := by cases' a with a a · exact bot_le @@ -1138,7 +1164,7 @@ instance : PredOrder (WithBot α) where dsimp only at ha split_ifs at ha with ha' · exact (not_coe_le_bot _ ha).elim - · rw [coe_le_coe, le_pred_iff_eq_bot] at ha + · rw [coe_le_coe, le_pred_iff_isMin, ← pred_eq_iff_isMin] at ha exact (ha' ha).elim le_pred_of_lt {a b} h := by cases a @@ -1148,27 +1174,19 @@ instance : PredOrder (WithBot α) where rw [coe_lt_coe] at h change _ ≤ ite _ _ _ split_ifs with hb - · rw [hb] at h - exact (not_lt_bot h).elim + · rw [pred_eq_iff_isMin] at hb + exact (hb.not_lt h).elim · exact coe_le_coe.2 (le_pred_of_lt h) - le_of_pred_lt {a b} h := by - cases b - · exact (not_lt_bot h).elim - cases a - · exact bot_le - dsimp only at h - rw [coe_le_coe] - split_ifs at h with ha - · rw [ha] - exact bot_le - · exact le_of_pred_lt (coe_lt_coe.1 h) @[simp] -theorem pred_coe_bot : pred ↑(⊥ : α) = (⊥ : WithBot α) := - dif_pos rfl +theorem pred_coe_of_isMin {a : α} (h : IsMin a) : pred ↑a = (⊥ : WithBot α) := + dif_pos (pred_eq_iff_isMin.2 h) + +theorem pred_coe_of_not_isMin {a : α} (h : ¬ IsMin a) : pred (↑a : WithBot α) = ↑(pred a) := + dif_neg (pred_eq_iff_isMin.not.2 h) -theorem pred_coe_of_ne_bot {a : α} (h : a ≠ ⊥) : pred (↑a : WithBot α) = ↑(pred a) := - dif_neg h +theorem pred_coe [NoMinOrder α] {a : α} : pred (↑a : WithBot α) = ↑(pred a) := + pred_coe_of_not_isMin <| not_isMin a end Pred @@ -1185,247 +1203,37 @@ instance [hα : Nonempty α] : IsEmpty (SuccOrder (WithBot α)) := · exact hα.elim fun a => (max_of_succ_le h.le).not_lt <| bot_lt_coe a · obtain ⟨c, hc⟩ := exists_lt a rw [← coe_lt_coe, ← h] at hc - exact (le_of_lt_succ hc).not_lt (bot_lt_coe _)⟩ + exact (succ_le_of_lt (bot_lt_coe _)).not_lt hc⟩ end Succ -section Pred - -variable [Preorder α] [NoMinOrder α] [PredOrder α] - -instance predOrderOfNoMinOrder : PredOrder (WithBot α) where - pred a := - match a with - | ⊥ => ⊥ - | Option.some a => some (pred a) - pred_le a := by - cases' a with a a - · exact bot_le - · exact coe_le_coe.2 (pred_le a) - min_of_le_pred {a} ha := by - cases a - · exact isMin_bot - · exact (not_isMin _ <| min_of_le_pred <| coe_le_coe.1 ha).elim - le_pred_of_lt {a b} h := by - cases b - · exact (not_lt_bot h).elim - cases a - · exact bot_le - · exact coe_le_coe.2 (le_pred_of_lt <| coe_lt_coe.1 h) - le_of_pred_lt {a b} h := by - cases b - · exact (not_lt_bot h).elim - cases a - · exact bot_le - · exact coe_le_coe.2 (le_of_pred_lt <| coe_lt_coe.1 h) - -@[simp] -theorem pred_coe (a : α) : pred (↑a : WithBot α) = ↑(pred a) := - rfl - -end Pred - end WithBot -/-! ### Archimedeanness -/ - -/-- A `SuccOrder` is succ-archimedean if one can go from any two comparable elements by iterating -`succ` -/ -class IsSuccArchimedean (α : Type*) [Preorder α] [SuccOrder α] : Prop where - /-- If `a ≤ b` then one can get to `a` from `b` by iterating `succ` -/ - exists_succ_iterate_of_le {a b : α} (h : a ≤ b) : ∃ n, succ^[n] a = b - -/-- A `PredOrder` is pred-archimedean if one can go from any two comparable elements by iterating -`pred` -/ -class IsPredArchimedean (α : Type*) [Preorder α] [PredOrder α] : Prop where - /-- If `a ≤ b` then one can get to `b` from `a` by iterating `pred` -/ - exists_pred_iterate_of_le {a b : α} (h : a ≤ b) : ∃ n, pred^[n] b = a - -export IsSuccArchimedean (exists_succ_iterate_of_le) - -export IsPredArchimedean (exists_pred_iterate_of_le) - -section Preorder - -variable [Preorder α] - -section SuccOrder - -variable [SuccOrder α] [IsSuccArchimedean α] {a b : α} - -instance : IsPredArchimedean αᵒᵈ := - ⟨fun {a b} h => by convert exists_succ_iterate_of_le h.ofDual⟩ - -theorem LE.le.exists_succ_iterate (h : a ≤ b) : ∃ n, succ^[n] a = b := - exists_succ_iterate_of_le h - -theorem exists_succ_iterate_iff_le : (∃ n, succ^[n] a = b) ↔ a ≤ b := by - refine ⟨?_, exists_succ_iterate_of_le⟩ - rintro ⟨n, rfl⟩ - exact id_le_iterate_of_id_le le_succ n a - -/-- Induction principle on a type with a `SuccOrder` for all elements above a given element `m`. -/ -@[elab_as_elim] -theorem Succ.rec {P : α → Prop} {m : α} (h0 : P m) (h1 : ∀ n, m ≤ n → P n → P (succ n)) ⦃n : α⦄ - (hmn : m ≤ n) : P n := by - obtain ⟨n, rfl⟩ := hmn.exists_succ_iterate; clear hmn - induction' n with n ih - · exact h0 - · rw [Function.iterate_succ_apply'] - exact h1 _ (id_le_iterate_of_id_le le_succ n m) ih - -theorem Succ.rec_iff {p : α → Prop} (hsucc : ∀ a, p a ↔ p (succ a)) {a b : α} (h : a ≤ b) : - p a ↔ p b := by - 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 - -end SuccOrder - -section PredOrder - -variable [PredOrder α] [IsPredArchimedean α] {a b : α} - -instance : IsSuccArchimedean αᵒᵈ := - ⟨fun {a b} h => by convert exists_pred_iterate_of_le h.ofDual⟩ - -theorem LE.le.exists_pred_iterate (h : a ≤ b) : ∃ n, pred^[n] b = a := - exists_pred_iterate_of_le h - -theorem exists_pred_iterate_iff_le : (∃ n, pred^[n] b = a) ↔ a ≤ b := - exists_succ_iterate_iff_le (α := αᵒᵈ) - -/-- Induction principle on a type with a `PredOrder` for all elements below a given element `m`. -/ -@[elab_as_elim] -theorem Pred.rec {P : α → Prop} {m : α} (h0 : P m) (h1 : ∀ n, n ≤ m → P n → P (pred n)) ⦃n : α⦄ - (hmn : n ≤ m) : P n := - Succ.rec (α := αᵒᵈ) (P := P) h0 h1 hmn - -theorem Pred.rec_iff {p : α → Prop} (hsucc : ∀ a, p a ↔ p (pred a)) {a b : α} (h : a ≤ b) : - p a ↔ p b := - (Succ.rec_iff (α := αᵒᵈ) hsucc h).symm - -end PredOrder - -end Preorder - -section LinearOrder - -variable [LinearOrder α] - -section SuccOrder -variable [SuccOrder α] - -lemma succ_max (a b : α) : succ (max a b) = max (succ a) (succ b) := succ_mono.map_max -lemma succ_min (a b : α) : succ (min a b) = min (succ a) (succ b) := succ_mono.map_min - -variable [IsSuccArchimedean α] {a b : α} - -theorem exists_succ_iterate_or : (∃ n, succ^[n] a = b) ∨ ∃ n, succ^[n] b = a := - (le_total a b).imp exists_succ_iterate_of_le exists_succ_iterate_of_le - -theorem Succ.rec_linear {p : α → Prop} (hsucc : ∀ a, p a ↔ p (succ a)) (a b : α) : p a ↔ p b := - (le_total a b).elim (Succ.rec_iff hsucc) fun h => (Succ.rec_iff hsucc h).symm - -end SuccOrder - -section PredOrder -variable [PredOrder α] - -lemma pred_max (a b : α) : pred (max a b) = max (pred a) (pred b) := pred_mono.map_max -lemma pred_min (a b : α) : pred (min a b) = min (pred a) (pred b) := pred_mono.map_min - -variable [IsPredArchimedean α] {a b : α} - -theorem exists_pred_iterate_or : (∃ n, pred^[n] b = a) ∨ ∃ n, pred^[n] a = b := - (le_total a b).imp exists_pred_iterate_of_le exists_pred_iterate_of_le - -theorem Pred.rec_linear {p : α → Prop} (hsucc : ∀ a, p a ↔ p (pred a)) (a b : α) : p a ↔ p b := - (le_total a b).elim (Pred.rec_iff hsucc) fun h => (Pred.rec_iff hsucc h).symm - -end PredOrder - -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 - rintro ⟨m, hm⟩ - have hm' : ∀ a, f a ≤ m := fun a ↦ hm <| Set.mem_range_self _ - obtain ⟨a₀⟩ := ‹Nonempty α› - suffices ∀ b, f a₀ ≤ b → ∃ a, b < f a by - obtain ⟨a, ha⟩ : ∃ a, m < f a := this m (hm' a₀) - exact ha.not_le (hm' a) - have h : ∀ a, ∃ a', f a < f a' := fun a ↦ (exists_gt a).imp (fun a' h ↦ hf h) - apply Succ.rec - · exact h a₀ - 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 - -lemma StrictAnti.not_bddAbove_range [NoMinOrder α] [SuccOrder β] [IsSuccArchimedean β] - (hf : StrictAnti f) : ¬ BddAbove (Set.range f) := hf.dual_right.not_bddBelow_range - -lemma StrictAnti.not_bddBelow_range [NoMaxOrder α] [PredOrder β] [IsPredArchimedean β] - (hf : StrictAnti f) : ¬ BddBelow (Set.range f) := hf.dual_right.not_bddAbove_range - -end bdd_range - -section IsWellOrder - -variable [LinearOrder α] - -instance (priority := 100) IsWellOrder.toIsPredArchimedean [h : IsWellOrder α (· < ·)] - [PredOrder α] : IsPredArchimedean α := - ⟨fun {a b} => by - refine WellFounded.fix (C := fun b => a ≤ b → ∃ n, Nat.iterate pred n b = a) - h.wf ?_ b - intros b ih hab - replace hab := eq_or_lt_of_le hab - rcases hab with (rfl | hab) - · exact ⟨0, rfl⟩ - rcases le_or_lt b (pred b) with hb | hb - · cases (min_of_le_pred hb).not_lt hab - dsimp at ih - obtain ⟨k, hk⟩ := ih (pred b) hb (le_pred_of_lt hab) - refine ⟨k + 1, ?_⟩ - rw [iterate_add_apply, iterate_one, hk]⟩ - -instance (priority := 100) IsWellOrder.toIsSuccArchimedean [h : IsWellOrder α (· > ·)] - [SuccOrder α] : IsSuccArchimedean α := - let h : IsPredArchimedean αᵒᵈ := by infer_instance - ⟨h.1⟩ - -end IsWellOrder - -section OrderBot - -variable [Preorder α] [OrderBot α] [SuccOrder α] [IsSuccArchimedean α] - -theorem Succ.rec_bot (p : α → Prop) (hbot : p ⊥) (hsucc : ∀ a, p a → p (succ a)) (a : α) : p a := - Succ.rec hbot (fun x _ h => hsucc x h) (bot_le : ⊥ ≤ a) - -end OrderBot - -section OrderTop - -variable [Preorder α] [OrderTop α] [PredOrder α] [IsPredArchimedean α] - -theorem Pred.rec_top (p : α → Prop) (htop : p ⊤) (hpred : ∀ a, p a → p (pred a)) (a : α) : p a := - Pred.rec htop (fun x _ h => hpred x h) (le_top : a ≤ ⊤) - -end OrderTop - -lemma SuccOrder.forall_ne_bot_iff - [Nontrivial α] [PartialOrder α] [OrderBot α] [SuccOrder α] [IsSuccArchimedean α] - (P : α → Prop) : - (∀ i, i ≠ ⊥ → P i) ↔ (∀ i, P (SuccOrder.succ i)) := by - refine ⟨fun h i ↦ h _ (Order.succ_ne_bot i), fun h i hi ↦ ?_⟩ - obtain ⟨j, rfl⟩ := exists_succ_iterate_of_le (bot_le : ⊥ ≤ i) - have hj : 0 < j := by apply Nat.pos_of_ne_zero; contrapose! hi; simp [hi] - rw [← Nat.succ_pred_eq_of_pos hj] - simp only [Function.iterate_succ', Function.comp_apply] - apply h +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 diff --git a/Mathlib/Order/SuccPred/CompleteLinearOrder.lean b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean index 3496364a6b58f..6b8b1de8ce9f3 100644 --- a/Mathlib/Order/SuccPred/CompleteLinearOrder.lean +++ b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean @@ -8,7 +8,7 @@ import Mathlib.Order.ConditionallyCompleteLattice.Basic /-! -# Relation between `IsSuccLimit` and `iSup` in (conditionally) complete linear orders. +# Relation between `IsSuccPrelimit` and `iSup` in (conditionally) complete linear orders. -/ @@ -19,105 +19,180 @@ variable {ι α : Type*} section ConditionallyCompleteLinearOrder variable [ConditionallyCompleteLinearOrder α] [Nonempty ι] {f : ι → α} {s : Set α} {x : α} -lemma csSup_mem_of_not_isSuccLimit - (hne : s.Nonempty) (hbdd : BddAbove s) (hlim : ¬ IsSuccLimit (sSup s)) : +lemma csSup_mem_of_not_isSuccPrelimit + (hne : s.Nonempty) (hbdd : BddAbove s) (hlim : ¬ IsSuccPrelimit (sSup s)) : sSup s ∈ s := by obtain ⟨y, hy⟩ := not_forall_not.mp hlim obtain ⟨i, his, hi⟩ := exists_lt_of_lt_csSup hne hy.lt exact eq_of_le_of_not_lt (le_csSup hbdd his) (hy.2 hi) ▸ his -lemma csInf_mem_of_not_isPredLimit - (hne : s.Nonempty) (hbdd : BddBelow s) (hlim : ¬ IsPredLimit (sInf s)) : +@[deprecated csSup_mem_of_not_isSuccPrelimit (since := "2024-09-05")] +alias csSup_mem_of_not_isSuccLimit := csSup_mem_of_not_isSuccPrelimit + +lemma csInf_mem_of_not_isPredPrelimit + (hne : s.Nonempty) (hbdd : BddBelow s) (hlim : ¬ IsPredPrelimit (sInf s)) : sInf s ∈ s := by obtain ⟨y, hy⟩ := not_forall_not.mp hlim obtain ⟨i, his, hi⟩ := exists_lt_of_csInf_lt hne hy.lt exact eq_of_le_of_not_lt (csInf_le hbdd his) (hy.2 · hi) ▸ his -lemma exists_eq_ciSup_of_not_isSuccLimit - (hf : BddAbove (Set.range f)) (hf' : ¬ IsSuccLimit (⨆ i, f i)) : - ∃ i, f i = ⨆ i, f i := - csSup_mem_of_not_isSuccLimit (Set.range_nonempty f) hf hf' - -lemma exists_eq_ciInf_of_not_isPredLimit - (hf : BddBelow (Set.range f)) (hf' : ¬ IsPredLimit (⨅ i, f i)) : - ∃ i, f i = ⨅ i, f i := - csInf_mem_of_not_isPredLimit (Set.range_nonempty f) hf hf' - -lemma IsLUB.mem_of_nonempty_of_not_isSuccLimit - (hs : IsLUB s x) (hne : s.Nonempty) (hx : ¬ IsSuccLimit x) : x ∈ s := - hs.csSup_eq hne ▸ csSup_mem_of_not_isSuccLimit hne hs.bddAbove (hs.csSup_eq hne ▸ hx) +@[deprecated csInf_mem_of_not_isPredPrelimit (since := "2024-09-05")] +alias csInf_mem_of_not_isPredLimit := csInf_mem_of_not_isPredPrelimit -lemma IsGLB.mem_of_nonempty_of_not_isPredLimit - (hs : IsGLB s x) (hne : s.Nonempty) (hx : ¬ IsPredLimit x) : x ∈ s := - hs.csInf_eq hne ▸ csInf_mem_of_not_isPredLimit hne hs.bddBelow (hs.csInf_eq hne ▸ hx) +lemma exists_eq_ciSup_of_not_isSuccPrelimit + (hf : BddAbove (Set.range f)) (hf' : ¬ IsSuccPrelimit (⨆ i, f i)) : + ∃ i, f i = ⨆ i, f i := + csSup_mem_of_not_isSuccPrelimit (Set.range_nonempty f) hf hf' -lemma IsLUB.exists_of_nonempty_of_not_isSuccLimit - (hf : IsLUB (Set.range f) x) (hx : ¬ IsSuccLimit x) : - ∃ i, f i = x := hf.mem_of_nonempty_of_not_isSuccLimit (Set.range_nonempty f) hx +@[deprecated exists_eq_ciSup_of_not_isSuccPrelimit (since := "2024-09-05")] +alias exists_eq_ciSup_of_not_isSuccLimit := exists_eq_ciSup_of_not_isSuccPrelimit -lemma IsGLB.exists_of_nonempty_of_not_isPredLimit - (hf : IsGLB (Set.range f) x) (hx : ¬ IsPredLimit x) : - ∃ i, f i = x := hf.mem_of_nonempty_of_not_isPredLimit (Set.range_nonempty f) hx +lemma exists_eq_ciInf_of_not_isPredPrelimit + (hf : BddBelow (Set.range f)) (hf' : ¬ IsPredPrelimit (⨅ i, f i)) : + ∃ i, f i = ⨅ i, f i := + csInf_mem_of_not_isPredPrelimit (Set.range_nonempty f) hf hf' + +@[deprecated exists_eq_ciInf_of_not_isPredPrelimit (since := "2024-09-05")] +alias exists_eq_ciInf_of_not_isPredLimit := exists_eq_ciInf_of_not_isPredPrelimit + +lemma IsLUB.mem_of_nonempty_of_not_isSuccPrelimit + (hs : IsLUB s x) (hne : s.Nonempty) (hx : ¬ IsSuccPrelimit x) : x ∈ s := + hs.csSup_eq hne ▸ csSup_mem_of_not_isSuccPrelimit hne hs.bddAbove (hs.csSup_eq hne ▸ hx) + +@[deprecated IsLUB.mem_of_nonempty_of_not_isSuccPrelimit (since := "2024-09-05")] +alias IsLUB.mem_of_nonempty_of_not_isSuccLimit := IsLUB.mem_of_nonempty_of_not_isSuccPrelimit + +lemma IsGLB.mem_of_nonempty_of_not_isPredPrelimit + (hs : IsGLB s x) (hne : s.Nonempty) (hx : ¬ IsPredPrelimit x) : x ∈ s := + hs.csInf_eq hne ▸ csInf_mem_of_not_isPredPrelimit hne hs.bddBelow (hs.csInf_eq hne ▸ hx) + +@[deprecated IsGLB.mem_of_nonempty_of_not_isPredPrelimit (since := "2024-09-05")] +alias IsGLB.mem_of_nonempty_of_not_isPredLimit := IsGLB.mem_of_nonempty_of_not_isPredPrelimit + +lemma IsLUB.exists_of_nonempty_of_not_isSuccPrelimit + (hf : IsLUB (Set.range f) x) (hx : ¬ IsSuccPrelimit x) : + ∃ i, f i = x := hf.mem_of_nonempty_of_not_isSuccPrelimit (Set.range_nonempty f) hx + +@[deprecated IsLUB.exists_of_nonempty_of_not_isSuccPrelimit (since := "2024-09-05")] +alias IsLUB.exists_of_nonempty_of_not_isSuccLimit := IsLUB.exists_of_nonempty_of_not_isSuccPrelimit + +lemma IsGLB.exists_of_nonempty_of_not_isPredPrelimit + (hf : IsGLB (Set.range f) x) (hx : ¬ IsPredPrelimit x) : + ∃ i, f i = x := hf.mem_of_nonempty_of_not_isPredPrelimit (Set.range_nonempty f) hx + +@[deprecated IsGLB.exists_of_nonempty_of_not_isPredPrelimit (since := "2024-09-05")] +alias IsGLB.exists_of_nonempty_of_not_isPredLimit := IsGLB.exists_of_nonempty_of_not_isPredPrelimit + +open Classical in +/-- Every conditionally complete linear order with well-founded `<` is a successor order, by setting +the successor of an element to be the infimum of all larger elements. -/ +noncomputable def ConditionallyCompleteLinearOrder.toSuccOrder [WellFoundedLT α] : + SuccOrder α where + succ a := if IsMax a then a else sInf {b | a < b} + le_succ a := by + by_cases h : IsMax a + · simp [h] + · simp only [h, ↓reduceIte] + rw [not_isMax_iff] at h + exact le_csInf h (fun b => le_of_lt) + max_of_succ_le hs := by + by_contra h + simp [h] at hs + rw [not_isMax_iff] at h + exact hs.not_lt (csInf_mem h) + succ_le_of_lt {a b} ha := by + simp [ha.not_isMax] + exact csInf_le ⟨a, fun _ hc => hc.le⟩ ha end ConditionallyCompleteLinearOrder section ConditionallyCompleteLinearOrderBot variable [ConditionallyCompleteLinearOrderBot α] {f : ι → α} {s : Set α} {x : α} -/-- See `csSup_mem_of_not_isSuccLimit` for the `ConditionallyCompleteLinearOrder` version. -/ -lemma csSup_mem_of_not_isSuccLimit' - (hbdd : BddAbove s) (hlim : ¬ IsSuccLimit (sSup s)) : +/-- See `csSup_mem_of_not_isSuccPrelimit` for the `ConditionallyCompleteLinearOrder` version. -/ +lemma csSup_mem_of_not_isSuccPrelimit' + (hbdd : BddAbove s) (hlim : ¬ IsSuccPrelimit (sSup s)) : sSup s ∈ s := by obtain (rfl|hs) := s.eq_empty_or_nonempty - · simp [isSuccLimit_bot] at hlim - · exact csSup_mem_of_not_isSuccLimit hs hbdd hlim + · simp [isSuccPrelimit_bot] at hlim + · exact csSup_mem_of_not_isSuccPrelimit hs hbdd hlim -/-- See `exists_eq_ciSup_of_not_isSuccLimit` for the +@[deprecated csSup_mem_of_not_isSuccPrelimit' (since := "2024-09-05")] +alias csSup_mem_of_not_isSuccLimit' := csSup_mem_of_not_isSuccPrelimit' + +/-- See `exists_eq_ciSup_of_not_isSuccPrelimit` for the `ConditionallyCompleteLinearOrder` version. -/ -lemma exists_eq_ciSup_of_not_isSuccLimit' - (hf : BddAbove (Set.range f)) (hf' : ¬ IsSuccLimit (⨆ i, f i)) : +lemma exists_eq_ciSup_of_not_isSuccPrelimit' + (hf : BddAbove (Set.range f)) (hf' : ¬ IsSuccPrelimit (⨆ i, f i)) : ∃ i, f i = ⨆ i, f i := - csSup_mem_of_not_isSuccLimit' hf hf' + csSup_mem_of_not_isSuccPrelimit' hf hf' + +@[deprecated exists_eq_ciSup_of_not_isSuccPrelimit' (since := "2024-09-05")] +alias exists_eq_ciSup_of_not_isSuccLimit' := exists_eq_ciSup_of_not_isSuccPrelimit' -lemma IsLUB.mem_of_not_isSuccLimit (hs : IsLUB s x) (hx : ¬ IsSuccLimit x) : +lemma IsLUB.mem_of_not_isSuccPrelimit (hs : IsLUB s x) (hx : ¬ IsSuccPrelimit x) : x ∈ s := by obtain (rfl|hs') := s.eq_empty_or_nonempty - · simp [show x = ⊥ by simpa using hs, isSuccLimit_bot] at hx - · exact hs.mem_of_nonempty_of_not_isSuccLimit hs' hx + · simp [show x = ⊥ by simpa using hs, isSuccPrelimit_bot] at hx + · exact hs.mem_of_nonempty_of_not_isSuccPrelimit hs' hx -lemma IsLUB.exists_of_not_isSuccLimit (hf : IsLUB (Set.range f) x) (hx : ¬ IsSuccLimit x) : - ∃ i, f i = x := hf.mem_of_not_isSuccLimit hx +@[deprecated IsLUB.mem_of_not_isSuccPrelimit (since := "2024-09-05")] +alias IsLUB.mem_of_not_isSuccLimit := IsLUB.mem_of_not_isSuccPrelimit + +lemma IsLUB.exists_of_not_isSuccPrelimit (hf : IsLUB (Set.range f) x) (hx : ¬ IsSuccPrelimit x) : + ∃ i, f i = x := hf.mem_of_not_isSuccPrelimit hx + +@[deprecated IsLUB.exists_of_not_isSuccPrelimit (since := "2024-09-05")] +alias IsLUB.exists_of_not_isSuccLimit := IsLUB.exists_of_not_isSuccPrelimit end ConditionallyCompleteLinearOrderBot section CompleteLinearOrder variable [CompleteLinearOrder α] {s : Set α} {f : ι → α} {x : α} -lemma sSup_mem_of_not_isSuccLimit (hlim : ¬ IsSuccLimit (sSup s)) : +lemma sSup_mem_of_not_isSuccPrelimit (hlim : ¬ IsSuccPrelimit (sSup s)) : sSup s ∈ s := by obtain ⟨y, hy⟩ := not_forall_not.mp hlim obtain ⟨i, his, hi⟩ := lt_sSup_iff.mp hy.lt exact eq_of_le_of_not_lt (le_sSup his) (hy.2 hi) ▸ his -lemma sInf_mem_of_not_isPredLimit (hlim : ¬ IsPredLimit (sInf s)) : +@[deprecated sSup_mem_of_not_isSuccPrelimit (since := "2024-09-05")] +alias sSup_mem_of_not_isSuccLimit := sSup_mem_of_not_isSuccPrelimit + +lemma sInf_mem_of_not_isPredPrelimit (hlim : ¬ IsPredPrelimit (sInf s)) : sInf s ∈ s := by obtain ⟨y, hy⟩ := not_forall_not.mp hlim obtain ⟨i, his, hi⟩ := sInf_lt_iff.mp hy.lt exact eq_of_le_of_not_lt (sInf_le his) (hy.2 · hi) ▸ his -lemma exists_eq_iSup_of_not_isSuccLimit (hf : ¬ IsSuccLimit (⨆ i, f i)) : +@[deprecated sInf_mem_of_not_isPredPrelimit (since := "2024-09-05")] +alias sInf_mem_of_not_isPredLimit := sInf_mem_of_not_isPredPrelimit + +lemma exists_eq_iSup_of_not_isSuccPrelimit (hf : ¬ IsSuccPrelimit (⨆ i, f i)) : ∃ i, f i = ⨆ i, f i := - sSup_mem_of_not_isSuccLimit hf + sSup_mem_of_not_isSuccPrelimit hf -lemma exists_eq_iInf_of_not_isPredLimit (hf : ¬ IsPredLimit (⨅ i, f i)) : +@[deprecated exists_eq_iSup_of_not_isSuccPrelimit (since := "2024-09-05")] +alias exists_eq_iSup_of_not_isSuccLimit := exists_eq_iSup_of_not_isSuccPrelimit + +lemma exists_eq_iInf_of_not_isPredPrelimit (hf : ¬ IsPredPrelimit (⨅ i, f i)) : ∃ i, f i = ⨅ i, f i := - sInf_mem_of_not_isPredLimit hf + sInf_mem_of_not_isPredPrelimit hf + +@[deprecated exists_eq_iInf_of_not_isPredPrelimit (since := "2024-09-05")] +alias exists_eq_iInf_of_not_isPredLimit := exists_eq_iInf_of_not_isPredPrelimit -lemma IsGLB.mem_of_not_isPredLimit (hs : IsGLB s x) (hx : ¬ IsPredLimit x) : +lemma IsGLB.mem_of_not_isPredPrelimit (hs : IsGLB s x) (hx : ¬ IsPredPrelimit x) : x ∈ s := - hs.sInf_eq ▸ sInf_mem_of_not_isPredLimit (hs.sInf_eq ▸ hx) + hs.sInf_eq ▸ sInf_mem_of_not_isPredPrelimit (hs.sInf_eq ▸ hx) + +@[deprecated IsGLB.mem_of_not_isPredPrelimit (since := "2024-09-05")] +alias IsGLB.mem_of_not_isPredLimit := IsGLB.mem_of_not_isPredPrelimit + +lemma IsGLB.exists_of_not_isPredPrelimit (hf : IsGLB (Set.range f) x) (hx : ¬ IsPredPrelimit x) : + ∃ i, f i = x := hf.mem_of_not_isPredPrelimit hx -lemma IsGLB.exists_of_not_isPredLimit (hf : IsGLB (Set.range f) x) (hx : ¬ IsPredLimit x) : - ∃ i, f i = x := hf.mem_of_not_isPredLimit hx +@[deprecated IsGLB.exists_of_not_isPredPrelimit (since := "2024-09-05")] +alias IsGLB.exists_of_not_isPredLimit := IsGLB.exists_of_not_isPredPrelimit end CompleteLinearOrder diff --git a/Mathlib/Order/SuccPred/IntervalSucc.lean b/Mathlib/Order/SuccPred/IntervalSucc.lean index 96bbcd2e0b85a..4e11847ea9a33 100644 --- a/Mathlib/Order/SuccPred/IntervalSucc.lean +++ b/Mathlib/Order/SuccPred/IntervalSucc.lean @@ -5,7 +5,7 @@ Authors: Yury Kudryashov -/ import Mathlib.Data.Set.Pairwise.Basic import Mathlib.Data.Set.Lattice -import Mathlib.Order.SuccPred.Basic +import Mathlib.Order.SuccPred.Archimedean /-! # Intervals `Ixx (f x) (f (Order.succ x))` diff --git a/Mathlib/Order/SuccPred/Limit.lean b/Mathlib/Order/SuccPred/Limit.lean index f155e590cd460..45933dc60feb8 100644 --- a/Mathlib/Order/SuccPred/Limit.lean +++ b/Mathlib/Order/SuccPred/Limit.lean @@ -3,15 +3,19 @@ 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.Order.SuccPred.Basic +import Mathlib.Order.SuccPred.Archimedean import Mathlib.Order.BoundedOrder /-! # Successor and predecessor limits -We define the predicate `Order.IsSuccLimit` for "successor limits", values that don't cover any -others. They are so named since they can't be the successors of anything smaller. We define -`Order.IsPredLimit` analogously, and prove basic results. +We define the predicate `Order.IsSuccPrelimit` for "successor pre-limits", values that don't cover +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. + +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. ## TODO @@ -20,7 +24,7 @@ predicate `Order.IsSuccLimit`. -/ -variable {α : Type*} +variable {α : Type*} {a b : α} namespace Order @@ -33,49 +37,113 @@ section LT variable [LT α] -/-- A successor limit is a value that doesn't cover any other. +/-- A successor pre-limit is a value that 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. -/ -def IsSuccLimit (a : α) : Prop := +It's so named because in a successor order, a successor pre-limit can't be the successor of anything +smaller. + +Use `IsSuccLimit` if you want to exclude the case of a minimal element. -/ +def IsSuccPrelimit (a : α) : Prop := ∀ b, ¬b ⋖ a -theorem not_isSuccLimit_iff_exists_covBy (a : α) : ¬IsSuccLimit a ↔ ∃ b, b ⋖ a := by - simp [IsSuccLimit] +theorem not_isSuccPrelimit_iff_exists_covBy (a : α) : ¬IsSuccPrelimit a ↔ ∃ b, b ⋖ a := by + simp [IsSuccPrelimit] + +@[deprecated not_isSuccPrelimit_iff_exists_covBy (since := "2024-09-05")] +alias not_isSuccLimit_iff_exists_covBy := not_isSuccPrelimit_iff_exists_covBy @[simp] -theorem isSuccLimit_of_dense [DenselyOrdered α] (a : α) : IsSuccLimit a := fun _ => not_covBy +theorem isSuccPrelimit_of_dense [DenselyOrdered α] (a : α) : IsSuccPrelimit a := fun _ => not_covBy + +@[deprecated isSuccPrelimit_of_dense (since := "2024-09-05")] +alias isSuccLimit_of_dense := isSuccPrelimit_of_dense 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) -protected theorem _root_.IsMin.isSuccLimit : IsMin a → IsSuccLimit a := fun h _ hab => +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 -theorem isSuccLimit_bot [OrderBot α] : IsSuccLimit (⊥ : α) := - IsMin.isSuccLimit isMin_bot +@[deprecated _root_.IsMin.isSuccPrelimit (since := "2024-09-05")] +alias _root_.IsMin.isSuccLimit := _root_.IsMin.isSuccPrelimit + +theorem isSuccPrelimit_bot [OrderBot α] : IsSuccPrelimit (⊥ : α) := + 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 IsSuccLimit.isMax (h : IsSuccLimit (succ a)) : IsMax a := by +protected theorem IsSuccPrelimit.isMax (h : IsSuccPrelimit (succ a)) : IsMax a := by by_contra H exact h a (covBy_succ_of_not_isMax H) -theorem not_isSuccLimit_succ_of_not_isMax (ha : ¬IsMax a) : ¬IsSuccLimit (succ a) := by - contrapose! ha - exact ha.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) := + mt IsSuccPrelimit.isMax ha + +theorem not_isSuccLimit_succ_of_not_isMax (ha : ¬ IsMax a) : ¬ IsSuccLimit (succ a) := + mt IsSuccLimit.isMax ha section NoMaxOrder variable [NoMaxOrder α] -theorem IsSuccLimit.succ_ne (h : IsSuccLimit a) (b : α) : succ b ≠ a := by +theorem IsSuccPrelimit.succ_ne (h : IsSuccPrelimit a) (b : α) : succ b ≠ a := by rintro rfl exact not_isMax _ h.isMax +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 + @[simp] theorem not_isSuccLimit_succ (a : α) : ¬IsSuccLimit (succ a) := fun h => h.succ_ne _ rfl @@ -83,19 +151,30 @@ end NoMaxOrder section IsSuccArchimedean -variable [IsSuccArchimedean α] +variable [IsSuccArchimedean α] [NoMaxOrder α] -theorem IsSuccLimit.isMin_of_noMax [NoMaxOrder α] (h : IsSuccLimit a) : IsMin a := fun b hb => 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 · rw [iterate_succ_apply'] at h - exact (not_isSuccLimit_succ _ h).elim + exact (not_isSuccPrelimit_succ _ h).elim + +@[deprecated IsSuccPrelimit.isMin_of_noMax (since := "2024-09-05")] +alias IsSuccLimit.isMin_of_noMax := IsSuccPrelimit.isMin_of_noMax @[simp] -theorem isSuccLimit_iff_of_noMax [NoMaxOrder α] : IsSuccLimit a ↔ IsMin a := - ⟨IsSuccLimit.isMin_of_noMax, IsMin.isSuccLimit⟩ +theorem isSuccPrelimit_iff_of_noMax : IsSuccPrelimit a ↔ IsMin a := + ⟨IsSuccPrelimit.isMin_of_noMax, IsMin.isSuccPrelimit⟩ -theorem not_isSuccLimit_of_noMax [NoMinOrder α] [NoMaxOrder α] : ¬IsSuccLimit a := by simp +@[deprecated isSuccPrelimit_iff_of_noMax (since := "2024-09-05")] +alias isSuccLimit_iff_of_noMax := isSuccPrelimit_iff_of_noMax + +@[simp] +theorem not_isSuccLimit_of_noMax : ¬ IsSuccLimit a := + fun h ↦ h.not_isMin h.isSuccPrelimit.isMin_of_noMax + +theorem not_isSuccPrelimit_of_noMax [NoMinOrder α] : ¬ IsSuccPrelimit a := by simp end IsSuccArchimedean @@ -103,27 +182,48 @@ 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 isSuccLimit_of_succ_ne (h : ∀ b, succ b ≠ a) : IsSuccLimit a := fun b hba => +theorem isSuccPrelimit_of_succ_ne (h : ∀ b, succ b ≠ a) : IsSuccPrelimit a := fun b hba => h b (CovBy.succ_eq hba) -theorem not_isSuccLimit_iff : ¬IsSuccLimit a ↔ ∃ b, ¬IsMax b ∧ succ b = a := by - rw [not_isSuccLimit_iff_exists_covBy] +@[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 + 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 -/-- See `not_isSuccLimit_iff` for a version that states that `a` is a successor of a value other +/-- 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_isSuccLimit (h : ¬IsSuccLimit a) : a ∈ range (@succ α _ _) := by - cases' not_isSuccLimit_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⟩ -theorem isSuccLimit_of_succ_lt (H : ∀ a < b, succ a < b) : IsSuccLimit b := fun a hab => +@[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 := + or_iff_not_imp_right.2 <| mem_range_succ_of_not_isSuccPrelimit + +@[deprecated mem_range_succ_or_isSuccPrelimit (since := "2024-09-05")] +alias mem_range_succ_or_isSuccLimit := mem_range_succ_or_isSuccPrelimit + +theorem isSuccPrelimit_of_succ_lt (H : ∀ a < b, succ a < b) : IsSuccPrelimit b := fun a hab => (H a hab.lt).ne (CovBy.succ_eq hab) -theorem IsSuccLimit.succ_lt (hb : IsSuccLimit b) (ha : a < b) : succ a < b := by +@[deprecated isSuccPrelimit_of_succ_lt (since := "2024-09-05")] +alias isSuccLimit_of_succ_lt := isSuccPrelimit_of_succ_lt + +theorem IsSuccPrelimit.succ_lt (hb : IsSuccPrelimit b) (ha : a < b) : succ a < b := by by_cases h : IsMax a · rwa [h.succ_eq] · rw [lt_iff_le_and_ne, succ_le_iff_of_not_isMax h] @@ -131,86 +231,36 @@ theorem IsSuccLimit.succ_lt (hb : IsSuccLimit b) (ha : a < b) : succ a < b := by subst hab exact (h hb.isMax).elim -theorem IsSuccLimit.succ_lt_iff (hb : IsSuccLimit b) : succ a < b ↔ a < b := - ⟨fun h => (le_succ a).trans_lt h, hb.succ_lt⟩ - -theorem isSuccLimit_iff_succ_lt : IsSuccLimit b ↔ ∀ a < b, succ a < b := - ⟨fun hb _ => hb.succ_lt, isSuccLimit_of_succ_lt⟩ - -/-- A value can be built by building it on successors and successor limits. -/ -@[elab_as_elim] -noncomputable def isSuccLimitRecOn (b : α) (hs : ∀ a, ¬IsMax a → C (succ a)) - (hl : ∀ a, IsSuccLimit a → C a) : C b := by - by_cases hb : IsSuccLimit b - · exact hl b hb - · have H := Classical.choose_spec (not_isSuccLimit_iff.1 hb) - rw [← H.2] - exact hs _ H.1 - -theorem isSuccLimitRecOn_limit (hs : ∀ a, ¬IsMax a → C (succ a)) (hl : ∀ a, IsSuccLimit a → C a) - (hb : IsSuccLimit b) : @isSuccLimitRecOn α _ _ C b hs hl = hl b hb := by - classical exact dif_pos hb - -theorem isSuccLimitRecOn_succ' (hs : ∀ a, ¬IsMax a → C (succ a)) (hl : ∀ a, IsSuccLimit a → C a) - {b : α} (hb : ¬IsMax b) : @isSuccLimitRecOn α _ _ C (succ b) hs hl = hs b hb := by - have hb' := not_isSuccLimit_succ_of_not_isMax hb - have H := Classical.choose_spec (not_isSuccLimit_iff.1 hb') - rw [isSuccLimitRecOn] - 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 - -section limitRecOn +theorem IsSuccLimit.succ_lt (hb : IsSuccLimit b) (ha : a < b) : succ a < b := + hb.isSuccPrelimit.succ_lt ha -variable [WellFoundedLT α] - (H_succ : ∀ a, ¬IsMax a → C a → C (succ a)) - (H_lim : ∀ a, IsSuccLimit a → (∀ b < a, C b) → C a) - -open scoped Classical in -variable (a) in -/-- Recursion principle on a well-founded partial `SuccOrder`. -/ -@[elab_as_elim] noncomputable def _root_.SuccOrder.limitRecOn : C a := - wellFounded_lt.fix - (fun a IH ↦ if h : IsSuccLimit a then H_lim a h IH else - let x := Classical.indefiniteDescription _ (not_isSuccLimit_iff.mp h) - x.2.2 ▸ H_succ x x.2.1 (IH x <| x.2.2.subst <| lt_succ_of_not_isMax x.2.1)) - a +theorem IsSuccPrelimit.succ_lt_iff (hb : IsSuccPrelimit b) : succ a < b ↔ a < b := + ⟨fun h => (le_succ a).trans_lt h, hb.succ_lt⟩ -@[simp] -theorem _root_.SuccOrder.limitRecOn_succ (ha : ¬ IsMax a) : - SuccOrder.limitRecOn (succ a) H_succ H_lim - = H_succ a ha (SuccOrder.limitRecOn a H_succ H_lim) := by - have h := not_isSuccLimit_succ_of_not_isMax ha - rw [SuccOrder.limitRecOn, WellFounded.fix_eq, dif_neg h] - have {b c hb hc} {x : ∀ a, C a} (h : b = c) : - congr_arg succ h ▸ H_succ b hb (x b) = H_succ c hc (x c) := by subst h; rfl - let x := Classical.indefiniteDescription _ (not_isSuccLimit_iff.mp h) - exact this ((succ_eq_succ_iff_of_not_isMax x.2.1 ha).mp x.2.2) +theorem IsSuccLimit.succ_lt_iff (hb : IsSuccLimit b) : succ a < b ↔ a < b := + hb.isSuccPrelimit.succ_lt_iff -@[simp] -theorem _root_.SuccOrder.limitRecOn_limit (ha : IsSuccLimit a) : - SuccOrder.limitRecOn a H_succ H_lim - = H_lim a ha fun x _ ↦ SuccOrder.limitRecOn x H_succ H_lim := by - rw [SuccOrder.limitRecOn, WellFounded.fix_eq, dif_pos ha]; rfl +theorem isSuccPrelimit_iff_succ_lt : IsSuccPrelimit b ↔ ∀ a < b, succ a < b := + ⟨fun hb _ => hb.succ_lt, isSuccPrelimit_of_succ_lt⟩ -end limitRecOn +@[deprecated isSuccPrelimit_iff_succ_lt (since := "2024-09-05")] +alias isSuccLimit_iff_succ_lt := isSuccPrelimit_iff_succ_lt section NoMaxOrder variable [NoMaxOrder α] -@[simp] -theorem isSuccLimitRecOn_succ (hs : ∀ a, ¬IsMax a → C (succ a)) (hl : ∀ a, IsSuccLimit a → C a) - (b : α) : @isSuccLimitRecOn α _ _ C (succ b) hs hl = hs b (not_isMax b) := - isSuccLimitRecOn_succ' _ _ _ +theorem isSuccPrelimit_iff_succ_ne : IsSuccPrelimit a ↔ ∀ b, succ b ≠ a := + ⟨IsSuccPrelimit.succ_ne, isSuccPrelimit_of_succ_ne⟩ -theorem isSuccLimit_iff_succ_ne : IsSuccLimit a ↔ ∀ b, succ b ≠ a := - ⟨IsSuccLimit.succ_ne, isSuccLimit_of_succ_ne⟩ +@[deprecated isSuccPrelimit_iff_succ_ne (since := "2024-09-05")] +alias isSuccLimit_iff_succ_ne := isSuccPrelimit_iff_succ_ne -theorem not_isSuccLimit_iff' : ¬IsSuccLimit a ↔ a ∈ range (@succ α _ _) := by - simp_rw [isSuccLimit_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' end NoMaxOrder @@ -218,7 +268,7 @@ section IsSuccArchimedean variable [IsSuccArchimedean α] -protected theorem IsSuccLimit.isMin (h : IsSuccLimit a) : IsMin a := fun b hb => by +protected theorem IsSuccPrelimit.isMin (h : IsSuccPrelimit a) : IsMin a := fun b hb => by revert h refine Succ.rec (fun _ => le_rfl) (fun c _ H hc => ?_) hb have := hc.isMax.succ_eq @@ -226,33 +276,94 @@ protected theorem IsSuccLimit.isMin (h : IsSuccLimit a) : IsMin a := fun b hb => exact H hc @[simp] -theorem isSuccLimit_iff : IsSuccLimit a ↔ IsMin a := - ⟨IsSuccLimit.isMin, IsMin.isSuccLimit⟩ +theorem isSuccPrelimit_iff : IsSuccPrelimit a ↔ IsMin a := + ⟨IsSuccPrelimit.isMin, IsMin.isSuccPrelimit⟩ -theorem not_isSuccLimit [NoMinOrder α] : ¬IsSuccLimit a := by simp +@[simp] +theorem not_isSuccLimit : ¬ IsSuccLimit a := + fun h ↦ h.not_isMin <| h.isSuccPrelimit.isMin + +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 predecessor pre-limit is a value that isn't covered by any other. + +It's so named because in a predecessor order, a predecessor pre-limit can't be the predecessor of +anything smaller. + +Use `IsPredLimit` to exclude the case of a maximal element. -/ +def IsPredPrelimit (a : α) : Prop := + ∀ b, ¬ a ⋖ b + +theorem not_isPredPrelimit_iff_exists_covBy (a : α) : ¬IsPredPrelimit a ↔ ∃ b, a ⋖ b := by + simp [IsPredPrelimit] + +@[deprecated not_isPredPrelimit_iff_exists_covBy (since := "2024-09-05")] +alias not_isPredLimit_iff_exists_covBy := not_isPredPrelimit_iff_exists_covBy + +theorem isPredPrelimit_of_dense [DenselyOrdered α] (a : α) : IsPredPrelimit a := fun _ => not_covBy -/-- A predecessor limit is a value that isn't covered by any other. +@[deprecated isPredPrelimit_of_dense (since := "2024-09-05")] +alias isPredLimit_of_dense := isPredPrelimit_of_dense + +@[simp] +theorem isSuccPrelimit_toDual_iff : IsSuccPrelimit (toDual a) ↔ IsPredPrelimit a := by + simp [IsSuccPrelimit, IsPredPrelimit] + +@[simp] +theorem isPredPrelimit_toDual_iff : IsPredPrelimit (toDual a) ↔ IsSuccPrelimit a := by + simp [IsSuccPrelimit, IsPredPrelimit] + +alias ⟨_, IsPredPrelimit.dual⟩ := isSuccPrelimit_toDual_iff +alias ⟨_, IsSuccPrelimit.dual⟩ := isPredPrelimit_toDual_iff +@[deprecated IsPredPrelimit.dual (since := "2024-09-05")] +alias isPredLimit.dual := IsPredPrelimit.dual +@[deprecated IsSuccPrelimit.dual (since := "2024-09-05")] +alias isSuccLimit.dual := IsSuccPrelimit.dual + +end LT + +section Preorder + +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 greater. -/ -def IsPredLimit (a : α) : Prop := - ∀ b, ¬a ⋖ b +anything larger. -theorem not_isPredLimit_iff_exists_covBy (a : α) : ¬IsPredLimit a ↔ ∃ b, a ⋖ b := by - simp [IsPredLimit] +This previously allowed the element to be maximal. This usage is now covered by `IsPredPreLimit`. -/ +def IsPredLimit (a : α) : Prop := + ¬ IsMax a ∧ IsPredPrelimit a -theorem isPredLimit_of_dense [DenselyOrdered α] (a : α) : IsPredLimit a := fun _ => not_covBy +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 @@ -262,57 +373,104 @@ theorem isSuccLimit_toDual_iff : IsSuccLimit (toDual a) ↔ IsPredLimit a := by theorem isPredLimit_toDual_iff : IsPredLimit (toDual a) ↔ IsSuccLimit a := by simp [IsSuccLimit, IsPredLimit] -alias ⟨_, isPredLimit.dual⟩ := isSuccLimit_toDual_iff +alias ⟨_, IsPredLimit.dual⟩ := isSuccLimit_toDual_iff +alias ⟨_, IsSuccLimit.dual⟩ := isPredLimit_toDual_iff -alias ⟨_, isSuccLimit.dual⟩ := isPredLimit_toDual_iff +theorem IsPredPrelimit.isPredLimit_of_not_isMax (h : IsPredPrelimit a) (ha : ¬ IsMax a) : + IsPredLimit a := + ⟨ha, h⟩ -end LT +theorem IsPredPrelimit.isPredLimit [NoMaxOrder α] (h : IsPredPrelimit a) : IsPredLimit a := + h.isPredLimit_of_not_isMax (not_isMax a) -section Preorder +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) -variable [Preorder α] {a : α} +protected theorem _root_.IsMax.not_isPredLimit (h : IsMax a) : ¬ IsPredLimit a := + fun ha ↦ ha.not_isMax h -protected theorem _root_.IsMax.isPredLimit : IsMax a → IsPredLimit a := fun h _ hab => +protected theorem _root_.IsMax.isPredPrelimit : IsMax a → IsPredPrelimit a := fun h _ hab => not_isMax_of_lt hab.lt h -theorem isPredLimit_top [OrderTop α] : IsPredLimit (⊤ : α) := - IsMax.isPredLimit isMax_top +@[deprecated _root_.IsMax.isPredPrelimit (since := "2024-09-05")] +alias _root_.IsMax.isPredLimit := _root_.IsMax.isPredPrelimit + +theorem isPredPrelimit_top [OrderTop α] : IsPredPrelimit (⊤ : α) := + 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 IsPredLimit.isMin (h : IsPredLimit (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 -theorem not_isPredLimit_pred_of_not_isMin (ha : ¬IsMin a) : ¬IsPredLimit (pred a) := by - contrapose! ha - exact ha.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) := + mt IsPredPrelimit.isMin ha + +theorem not_isPredLimit_pred_of_not_isMin (ha : ¬ IsMin a) : ¬ IsPredLimit (pred a) := + mt IsPredLimit.isMin ha section NoMinOrder variable [NoMinOrder α] -theorem IsPredLimit.pred_ne (h : IsPredLimit 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 + +theorem IsPredLimit.pred_ne (h : IsPredLimit a) (b : α) : pred b ≠ a := + h.isPredPrelimit.pred_ne b @[simp] -theorem not_isPredLimit_pred (a : α) : ¬IsPredLimit (pred a) := fun h => h.pred_ne _ rfl +theorem not_isPredPrelimit_pred (a : α) : ¬ IsPredPrelimit (pred a) := fun h => h.pred_ne _ rfl + +@[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 IsPredLimit.isMax_of_noMin [NoMinOrder α] (h : IsPredLimit a) : IsMax a := - (isPredLimit.dual h).isMin_of_noMax +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 isPredLimit_iff_of_noMin [NoMinOrder α] : IsPredLimit a ↔ IsMax a := - isSuccLimit_toDual_iff.symm.trans isSuccLimit_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_isPredLimit_of_noMin [NoMinOrder α] [NoMaxOrder α] : ¬IsPredLimit a := by simp +theorem not_isPredPrelimit_of_noMin [NoMaxOrder α] : ¬ IsPredPrelimit a := by simp + +@[simp] +theorem not_isPredLimit_of_noMin : ¬ IsPredLimit a := + fun h ↦ h.not_isMax h.isPredPrelimit.isMax_of_noMin end IsPredArchimedean @@ -320,90 +478,72 @@ 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 isPredLimit_of_pred_ne (h : ∀ b, pred b ≠ a) : IsPredLimit a := fun b hba => +theorem isPredPrelimit_of_pred_ne (h : ∀ b, pred b ≠ a) : IsPredPrelimit a := fun b hba => h b (CovBy.pred_eq hba) -theorem not_isPredLimit_iff : ¬IsPredLimit a ↔ ∃ b, ¬IsMin b ∧ pred b = a := by - rw [← isSuccLimit_toDual_iff] - exact not_isSuccLimit_iff +@[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 + rw [← isSuccPrelimit_toDual_iff] + exact not_isSuccPrelimit_iff -/-- See `not_isPredLimit_iff` for a version that states that `a` is a successor of a value other +/-- 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_isPredLimit (h : ¬IsPredLimit a) : a ∈ range (@pred α _ _) := by - cases' not_isPredLimit_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⟩ -theorem isPredLimit_of_pred_lt (H : ∀ a > b, pred a < b) : IsPredLimit b := fun a hab => - (H a hab.lt).ne (CovBy.pred_eq hab) +@[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 IsPredLimit.lt_pred (h : IsPredLimit a) : a < b → a < pred b := - (isPredLimit.dual h).succ_lt +theorem mem_range_pred_or_isPredPrelimit (a) : a ∈ range (pred : α → α) ∨ IsPredPrelimit a := + or_iff_not_imp_right.2 <| mem_range_pred_of_not_isPredPrelimit -theorem IsPredLimit.lt_pred_iff (h : IsPredLimit a) : a < pred b ↔ a < b := - (isPredLimit.dual h).succ_lt_iff +@[deprecated mem_range_pred_or_isPredPrelimit (since := "2024-09-05")] +alias mem_range_pred_or_isPredLimit := mem_range_pred_or_isPredPrelimit -theorem isPredLimit_iff_lt_pred : IsPredLimit a ↔ ∀ ⦃b⦄, a < b → a < pred b := - isSuccLimit_toDual_iff.symm.trans isSuccLimit_iff_succ_lt +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 -/-- A value can be built by building it on predecessors and predecessor limits. -/ -@[elab_as_elim] -noncomputable def isPredLimitRecOn (b : α) (hs : ∀ a, ¬IsMin a → C (pred a)) - (hl : ∀ a, IsPredLimit a → C a) : C b := - @isSuccLimitRecOn αᵒᵈ _ _ _ _ hs fun _ ha => hl _ (isSuccLimit.dual ha) +@[deprecated isPredPrelimit_of_pred_lt (since := "2024-09-05")] +alias isPredLimit_of_pred_lt := isPredPrelimit_of_pred_lt -theorem isPredLimitRecOn_limit (hs : ∀ a, ¬IsMin a → C (pred a)) (hl : ∀ a, IsPredLimit a → C a) - (hb : IsPredLimit b) : @isPredLimitRecOn α _ _ C b hs hl = hl b hb := - isSuccLimitRecOn_limit _ _ (isPredLimit.dual hb) +theorem IsPredPrelimit.lt_pred (ha : IsPredPrelimit a) (hb : a < b) : a < pred b := + ha.dual.succ_lt hb -theorem isPredLimitRecOn_pred' (hs : ∀ a, ¬IsMin a → C (pred a)) (hl : ∀ a, IsPredLimit a → C a) - {b : α} (hb : ¬IsMin b) : @isPredLimitRecOn α _ _ C (pred b) hs hl = hs b hb := - isSuccLimitRecOn_succ' _ _ _ +theorem IsPredLimit.lt_pred (ha : IsPredLimit a) (hb : a < b) : a < pred b := + ha.isPredPrelimit.lt_pred hb -section limitRecOn +theorem IsPredPrelimit.lt_pred_iff (ha : IsPredPrelimit a) : a < pred b ↔ a < b := + ha.dual.succ_lt_iff -variable [WellFoundedGT α] - (H_pred : ∀ a, ¬IsMin a → C a → C (pred a)) - (H_lim : ∀ a, IsPredLimit a → (∀ b > a, C b) → C a) +theorem IsPredLimit.lt_pred_iff (ha : IsPredLimit a) : a < pred b ↔ a < b := + ha.dual.succ_lt_iff -open scoped Classical in -variable (a) in -/-- Recursion principle on a well-founded partial `PredOrder`. -/ -@[elab_as_elim] noncomputable def _root_.PredOrder.limitRecOn : C a := - wellFounded_gt.fix - (fun a IH ↦ if h : IsPredLimit a then H_lim a h IH else - let x := Classical.indefiniteDescription _ (not_isPredLimit_iff.mp h) - x.2.2 ▸ H_pred x x.2.1 (IH x <| x.2.2.subst <| pred_lt_of_not_isMin x.2.1)) - a - -@[simp] -theorem _root_.PredOrder.limitRecOn_pred (ha : ¬ IsMin a) : - PredOrder.limitRecOn (pred a) H_pred H_lim - = H_pred a ha (PredOrder.limitRecOn a H_pred H_lim) := by - have h := not_isPredLimit_pred_of_not_isMin ha - rw [PredOrder.limitRecOn, WellFounded.fix_eq, dif_neg h] - have {b c hb hc} {x : ∀ a, C a} (h : b = c) : - congr_arg pred h ▸ H_pred b hb (x b) = H_pred c hc (x c) := by subst h; rfl - let x := Classical.indefiniteDescription _ (not_isPredLimit_iff.mp h) - exact this ((pred_eq_pred_iff_of_not_isMin x.2.1 ha).mp x.2.2) - -@[simp] -theorem _root_.PredOrder.limitRecOn_limit (ha : IsPredLimit a) : - PredOrder.limitRecOn a H_pred H_lim - = H_lim a ha fun x _ ↦ PredOrder.limitRecOn x H_pred H_lim := by - rw [PredOrder.limitRecOn, WellFounded.fix_eq, dif_pos ha]; rfl +theorem isPredPrelimit_iff_lt_pred : IsPredPrelimit a ↔ ∀ b > a, a < pred b := + ⟨fun hb _ => hb.lt_pred, isPredPrelimit_of_pred_lt⟩ -end limitRecOn +@[deprecated isPredPrelimit_iff_lt_pred (since := "2024-09-05")] +alias isPredLimit_iff_lt_pred := isPredPrelimit_iff_lt_pred section NoMinOrder variable [NoMinOrder α] -@[simp] -theorem isPredLimitRecOn_pred (hs : ∀ a, ¬IsMin a → C (pred a)) (hl : ∀ a, IsPredLimit a → C a) - (b : α) : @isPredLimitRecOn α _ _ C (pred b) hs hl = hs b (not_isMin b) := - isSuccLimitRecOn_succ _ _ _ +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 @@ -411,17 +551,433 @@ section IsPredArchimedean variable [IsPredArchimedean α] -protected theorem IsPredLimit.isMax (h : IsPredLimit a) : IsMax a := - (isPredLimit.dual h).isMin +protected theorem IsPredPrelimit.isMax (h : IsPredPrelimit a) : IsMax a := + h.dual.isMin + +@[deprecated IsPredPrelimit.isMax (since := "2024-09-05")] +alias IsPredLimit.isMax := IsPredPrelimit.isMax @[simp] -theorem isPredLimit_iff : IsPredLimit a ↔ IsMax a := - isSuccLimit_toDual_iff.symm.trans isSuccLimit_iff +theorem isPredPrelimit_iff : IsPredPrelimit a ↔ IsMax a := + ⟨IsPredPrelimit.isMax, IsMax.isPredPrelimit⟩ -theorem not_isPredLimit [NoMaxOrder α] : ¬IsPredLimit a := by simp +@[simp] +theorem not_isPredLimit : ¬ IsPredLimit a := + fun h ↦ h.not_isMax <| h.isPredPrelimit.isMax + +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*} + +namespace Order + +section isSuccPrelimitRecOn + +section PartialOrder + +variable [PartialOrder α] [SuccOrder α] + (hs : ∀ a, ¬ IsMax a → C (succ a)) (hl : ∀ a, IsSuccPrelimit a → C a) + +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 : 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_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_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, 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_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 α] (b : α) : + isSuccPrelimitRecOn (succ b) hs hl = hs b (not_isMax b) := + isSuccPrelimitRecOn_succ_of_not_isMax _ _ _ + +end LinearOrder + +end isSuccPrelimitRecOn + +section isPredPrelimitRecOn + +section PartialOrder + +variable [PartialOrder α] [PredOrder α] + (hs : ∀ a, ¬ IsMin a → C (pred a)) (hl : ∀ a, IsPredPrelimit a → C a) + +variable (b) in +/-- A value can be built by building it on predecessors and predecessor pre-limits. -/ +@[elab_as_elim] +noncomputable def isPredPrelimitRecOn : C b := + isSuccPrelimitRecOn (α := αᵒᵈ) b hs (fun a ha ↦ hl a ha.dual) + +theorem isPredPrelimitRecOn_of_isPredPrelimit (hb : IsPredPrelimit b) : + isPredPrelimitRecOn b hs hl = hl b hb := + isSuccPrelimitRecOn_of_isSuccPrelimit _ _ hb.dual + +@[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 + +section LinearOrder + +variable [LinearOrder α] [PredOrder α] + (hs : ∀ a, ¬ IsMin a → C (pred a)) (hl : ∀ a, IsPredPrelimit a → C a) + +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_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 (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 + +namespace SuccOrder + +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) + +variable (b) in +open Classical in +/-- Recursion principle on a well-founded partial `SuccOrder`. -/ +@[elab_as_elim] noncomputable def prelimitRecOn : C b := + wellFounded_lt.fix + (fun a IH ↦ if h : IsSuccPrelimit a then hl a h IH else + 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 + +@[simp] +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_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 + +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) + +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 {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_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 + +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 : C b := + SuccOrder.prelimitRecOn (α := αᵒᵈ) b hp (fun a ha => hl a ha.dual) + +@[simp] +theorem prelimitRecOn_of_isPredPrelimit (hb : IsPredPrelimit b) : + prelimitRecOn b hp hl = hl b hb fun x _ ↦ prelimitRecOn x hp hl := + SuccOrder.prelimitRecOn_of_isSuccPrelimit _ _ hb.dual + +@[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 + +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) + +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_of_not_isMax _ _ _ + +@[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 d7540ab87b82e..e758ae8c0f2f4 100644 --- a/Mathlib/Order/SuccPred/LinearLocallyFinite.lean +++ b/Mathlib/Order/SuccPred/LinearLocallyFinite.lean @@ -5,7 +5,7 @@ Authors: Rémy Degenne -/ import Mathlib.Data.Countable.Basic import Mathlib.Logic.Encodable.Basic -import Mathlib.Order.SuccPred.Basic +import Mathlib.Order.SuccPred.Archimedean import Mathlib.Order.Interval.Finset.Defs import Mathlib.Algebra.Order.Ring.Nat @@ -56,6 +56,41 @@ open Order variable {ι : Type*} [LinearOrder ι] +namespace LinearOrder + +variable [SuccOrder ι] [PredOrder ι] + +instance (priority := 100) isPredArchimedean_of_isSuccArchimedean [IsSuccArchimedean ι] : + IsPredArchimedean ι where + exists_pred_iterate_of_le {i j} hij := by + have h_exists := exists_succ_iterate_of_le hij + obtain ⟨n, hn_eq, hn_lt_ne⟩ : ∃ n, succ^[n] i = j ∧ ∀ m < n, succ^[m] i ≠ j := + ⟨Nat.find h_exists, Nat.find_spec h_exists, fun m hmn ↦ Nat.find_min h_exists hmn⟩ + refine ⟨n, ?_⟩ + rw [← hn_eq] + 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_apply'] + exact le_succ _ + · rw [hn_eq] + exact hn_lt_ne _ (Nat.lt_succ_self n) + +instance isSuccArchimedean_of_isPredArchimedean [IsPredArchimedean ι] : IsSuccArchimedean ι := + inferInstanceAs (IsSuccArchimedean ιᵒᵈᵒᵈ) + +/-- In a linear `SuccOrder` that's also a `PredOrder`, `IsSuccArchimedean` and `IsPredArchimedean` +are equivalent. -/ +theorem isSuccArchimedean_iff_isPredArchimedean : IsSuccArchimedean ι ↔ IsPredArchimedean ι where + mp _ := isPredArchimedean_of_isSuccArchimedean + mpr _ := isSuccArchimedean_of_isPredArchimedean + +end LinearOrder + namespace LinearLocallyFiniteOrder /-- Successor in a linear order. This defines a true successor only when `i` is isolated from above, @@ -109,15 +144,11 @@ noncomputable instance (priority := 100) [LocallyFiniteOrder ι] : SuccOrder ι le_succ := le_succFn max_of_succ_le h := isMax_of_succFn_le _ h succ_le_of_lt h := succFn_le_of_lt _ _ h - le_of_lt_succ h := le_of_lt_succFn _ _ h noncomputable instance (priority := 100) [LocallyFiniteOrder ι] : PredOrder ι := - (inferInstance : PredOrder (OrderDual ιᵒᵈ)) + inferInstanceAs (PredOrder ιᵒᵈᵒᵈ) -end LinearLocallyFiniteOrder - -instance (priority := 100) LinearLocallyFiniteOrder.isSuccArchimedean [LocallyFiniteOrder ι] : - IsSuccArchimedean ι where +instance (priority := 100) [LocallyFiniteOrder ι] : IsSuccArchimedean ι where exists_succ_iterate_of_le := by intro i j hij rw [le_iff_lt_or_eq] at hij @@ -146,28 +177,14 @@ instance (priority := 100) LinearLocallyFiniteOrder.isSuccArchimedean [LocallyFi have h_max : IsMax (succ^[n] i) := isMax_iterate_succ_of_eq_of_ne h_eq hnm.ne exact not_le.mpr (h_lt n) (h_max (h_lt n).le) -instance (priority := 100) LinearOrder.isPredArchimedean_of_isSuccArchimedean [SuccOrder ι] - [PredOrder ι] [IsSuccArchimedean ι] : IsPredArchimedean ι where - exists_pred_iterate_of_le := by - intro i j hij - have h_exists := exists_succ_iterate_of_le hij - obtain ⟨n, hn_eq, hn_lt_ne⟩ : ∃ n, succ^[n] i = j ∧ ∀ m < n, succ^[m] i ≠ j := - ⟨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 [Nat.zero_eq, Function.iterate_zero, id] - · 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'] - exact le_succ _ - · rw [hn_eq] - exact hn_lt_ne _ (Nat.lt_succ_self n) +instance (priority := 100) [LocallyFiniteOrder ι] : IsPredArchimedean ι := + inferInstance + +end LinearLocallyFiniteOrder section toZ +-- Requiring either of `IsSuccArchimedean` or `IsPredArchimedean` is equivalent. variable [SuccOrder ι] [IsSuccArchimedean ι] [PredOrder ι] {i0 i : ι} -- For "to_Z" @@ -177,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] @@ -239,8 +257,8 @@ theorem toZ_iterate_succ_of_not_isMax (n : ℕ) (hn : ¬IsMax (succ^[n] i0)) : theorem toZ_iterate_pred_of_not_isMin (n : ℕ) (hn : ¬IsMin (pred^[n] i0)) : toZ i0 (pred^[n] i0) = -n := by - cases' n with n n - · simp only [Nat.zero_eq, Function.iterate_zero, id, toZ_of_eq, Nat.cast_zero, neg_zero]; rfl + cases' n with n + · simp have : pred^[n.succ] i0 < i0 := by refine lt_of_le_of_ne (pred_iterate_le _ _) fun h_pred_iterate_eq ↦ hn ?_ have h_pred_eq_pred : pred^[n.succ] i0 = pred^[0] i0 := by @@ -293,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/Relation.lean b/Mathlib/Order/SuccPred/Relation.lean index 3b9c6848d52a5..b54a6dd23a17f 100644 --- a/Mathlib/Order/SuccPred/Relation.lean +++ b/Mathlib/Order/SuccPred/Relation.lean @@ -3,7 +3,7 @@ Copyright (c) 2022 Floris van Doorn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn -/ -import Mathlib.Order.SuccPred.Basic +import Mathlib.Order.SuccPred.Archimedean /-! # Relations on types with a `SuccOrder` diff --git a/Mathlib/Order/SupClosed.lean b/Mathlib/Order/SupClosed.lean index 9008ccc271cbc..998929ca5eab3 100644 --- a/Mathlib/Order/SupClosed.lean +++ b/Mathlib/Order/SupClosed.lean @@ -315,8 +315,8 @@ protected lemma Set.Finite.supClosure (hs : s.Finite) : (supClosure s).Finite := @[simp] lemma supClosure_prod (s : Set α) (t : Set β) : supClosure (s ×ˢ t) = supClosure s ×ˢ supClosure t := - le_antisymm (supClosure_min (Set.prod_mono subset_supClosure subset_supClosure) $ - supClosed_supClosure.prod supClosed_supClosure) $ by + le_antisymm (supClosure_min (Set.prod_mono subset_supClosure subset_supClosure) <| + supClosed_supClosure.prod supClosed_supClosure) <| by rintro ⟨_, _⟩ ⟨⟨u, hu, hus, rfl⟩, v, hv, hvt, rfl⟩ refine ⟨u ×ˢ v, hu.product hv, ?_, ?_⟩ · simpa only [coe_product] using Set.prod_mono hus hvt @@ -387,8 +387,8 @@ protected lemma Set.Finite.infClosure (hs : s.Finite) : (infClosure s).Finite := @[simp] lemma infClosure_prod (s : Set α) (t : Set β) : infClosure (s ×ˢ t) = infClosure s ×ˢ infClosure t := - le_antisymm (infClosure_min (Set.prod_mono subset_infClosure subset_infClosure) $ - infClosed_infClosure.prod infClosed_infClosure) $ by + le_antisymm (infClosure_min (Set.prod_mono subset_infClosure subset_infClosure) <| + infClosed_infClosure.prod infClosed_infClosure) <| by rintro ⟨_, _⟩ ⟨⟨u, hu, hus, rfl⟩, v, hv, hvt, rfl⟩ refine ⟨u ×ˢ v, hu.product hv, ?_, ?_⟩ · simpa only [coe_product] using Set.prod_mono hus hvt diff --git a/Mathlib/Order/SupIndep.lean b/Mathlib/Order/SupIndep.lean index e3a967e7b0c55..cb3c3c12cac6a 100644 --- a/Mathlib/Order/SupIndep.lean +++ b/Mathlib/Order/SupIndep.lean @@ -131,14 +131,14 @@ 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]⟩ theorem supIndep_univ_bool (f : Bool → α) : (Finset.univ : Finset Bool).SupIndep f ↔ Disjoint (f false) (f true) := - haveI : true ≠ false := by simp only [Ne, not_false_iff] + haveI : true ≠ false := by simp only [Ne, not_false_iff, reduceCtorEq] (supIndep_pair this).trans disjoint_comm @[simp] @@ -174,7 +174,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 f16a508003350..fa8d23d3aa081 100644 --- a/Mathlib/Order/SymmDiff.lean +++ b/Mathlib/Order/SymmDiff.lean @@ -82,7 +82,7 @@ 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 @@ -397,7 +397,7 @@ theorem symmDiff_symmDiff_right : theorem symmDiff_assoc : a ∆ b ∆ c = a ∆ (b ∆ c) := by rw [symmDiff_symmDiff_left, symmDiff_symmDiff_right] -instance symmDiff_isAssociative : Std.Associative (α := α) (· ∆ ·) := +instance symmDiff_isAssociative : Std.Associative (α := α) (· ∆ ·) := ⟨symmDiff_assoc⟩ theorem symmDiff_left_comm : a ∆ (b ∆ c) = b ∆ (a ∆ c) := by diff --git a/Mathlib/Order/Synonym.lean b/Mathlib/Order/Synonym.lean index 70558d627478e..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 -/ @@ -44,11 +44,11 @@ namespace OrderDual instance [h : Nontrivial α] : Nontrivial αᵒᵈ := h -/-- `toDual` is the identity function to the `OrderDual` of a linear order. -/ +/-- `toDual` is the identity function to the `OrderDual` of a linear order. -/ def toDual : α ≃ αᵒᵈ := Equiv.refl _ -/-- `ofDual` is the identity function from the `OrderDual` of a linear order. -/ +/-- `ofDual` is the identity function from the `OrderDual` of a linear order. -/ def ofDual : αᵒᵈ ≃ α := Equiv.refl _ @@ -134,12 +134,12 @@ end OrderDual def Lex (α : Type*) := α -/-- `toLex` is the identity function to the `Lex` of a type. -/ +/-- `toLex` is the identity function to the `Lex` of a type. -/ @[match_pattern] def toLex : α ≃ Lex α := Equiv.refl _ -/-- `ofLex` is the identity function from the `Lex` of a type. -/ +/-- `ofLex` is the identity function from the `Lex` of a type. -/ @[match_pattern] def ofLex : Lex α ≃ α := Equiv.refl _ @@ -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/TypeTags.lean b/Mathlib/Order/TypeTags.lean new file mode 100644 index 0000000000000..37df7cf0f1e86 --- /dev/null +++ b/Mathlib/Order/TypeTags.lean @@ -0,0 +1,151 @@ +/- +Copyright (c) 2018 Mario Carneiro. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro, Simon Hudon, Yury Kudryashov +-/ +import Mathlib.Order.Notation +import Mathlib.Data.Nat.Notation + +/-! +# Order-related type synonyms + +In this file we define `WithBot`, `WithTop`, `ENat`, and `PNat`. +The definitions were moved to this file without any theory +so that, e.g., `Data/Countable/Basic` can prove `Countable ENat` +without exploding its imports. +-/ + +variable {α : Type*} + +/-- Attach `⊥` to a type. -/ +def WithBot (α : Type*) := Option α + +namespace WithBot + +instance [Repr α] : Repr (WithBot α) := + ⟨fun o _ => + match o with + | none => "⊥" + | some a => "↑" ++ repr a⟩ + +/-- The canonical map from `α` into `WithBot α` -/ +@[coe, match_pattern] def some : α → WithBot α := + Option.some + +-- Porting note: changed this from `CoeTC` to `Coe` but I am not 100% confident that's correct. +instance coe : Coe α (WithBot α) := + ⟨some⟩ + +instance bot : Bot (WithBot α) := + ⟨none⟩ + +instance inhabited : Inhabited (WithBot α) := + ⟨⊥⟩ + +/-- Recursor for `WithBot` using the preferred forms `⊥` and `↑a`. -/ +@[elab_as_elim, induction_eliminator, cases_eliminator] +def recBotCoe {C : WithBot α → Sort*} (bot : C ⊥) (coe : ∀ a : α, C a) : ∀ n : WithBot α, C n + | ⊥ => bot + | (a : α) => coe a + +@[simp] +theorem recBotCoe_bot {C : WithBot α → Sort*} (d : C ⊥) (f : ∀ a : α, C a) : + @recBotCoe _ C d f ⊥ = d := + rfl + +@[simp] +theorem recBotCoe_coe {C : WithBot α → Sort*} (d : C ⊥) (f : ∀ a : α, C a) (x : α) : + @recBotCoe _ C d f ↑x = f x := + rfl + +end WithBot + +--TODO(Mario): Construct using order dual on `WithBot` +/-- Attach `⊤` to a type. -/ +def WithTop (α : Type*) := + Option α + +namespace WithTop + +instance [Repr α] : Repr (WithTop α) := + ⟨fun o _ => + match o with + | none => "⊤" + | some a => "↑" ++ repr a⟩ + +/-- The canonical map from `α` into `WithTop α` -/ +@[coe, match_pattern] def some : α → WithTop α := + Option.some + +instance coeTC : CoeTC α (WithTop α) := + ⟨some⟩ + +instance top : Top (WithTop α) := + ⟨none⟩ + +instance inhabited : Inhabited (WithTop α) := + ⟨⊤⟩ + +/-- Recursor for `WithTop` using the preferred forms `⊤` and `↑a`. -/ +@[elab_as_elim, induction_eliminator, cases_eliminator] +def recTopCoe {C : WithTop α → Sort*} (top : C ⊤) (coe : ∀ a : α, C a) : ∀ n : WithTop α, C n + | none => top + | Option.some a => coe a + +@[simp] +theorem recTopCoe_top {C : WithTop α → Sort*} (d : C ⊤) (f : ∀ a : α, C a) : + @recTopCoe _ C d f ⊤ = d := + rfl + +@[simp] +theorem recTopCoe_coe {C : WithTop α → Sort*} (d : C ⊤) (f : ∀ a : α, C a) (x : α) : + @recTopCoe _ C d f ↑x = f x := + rfl + +end WithTop + +/-- Extended natural numbers `ℕ∞ = WithTop ℕ`. -/ +def ENat : Type := WithTop ℕ deriving Top, Inhabited + +@[inherit_doc] notation "ℕ∞" => ENat + +namespace ENat + +instance instNatCast : NatCast ℕ∞ := ⟨WithTop.some⟩ + +-- Porting note (#11445): new definition copied from `WithTop` +/-- Recursor for `ENat` using the preferred forms `⊤` and `↑a`. -/ +@[elab_as_elim, induction_eliminator, cases_eliminator] +def recTopCoe {C : ℕ∞ → Sort*} (top : C ⊤) (coe : ∀ a : ℕ, C a) : ∀ n : ℕ∞, C n + | none => top + | Option.some a => coe a + +@[simp] +theorem recTopCoe_top {C : ℕ∞ → Sort*} (d : C ⊤) (f : ∀ a : ℕ, C a) : + @recTopCoe C d f ⊤ = d := + rfl + +@[simp] +theorem recTopCoe_coe {C : ℕ∞ → Sort*} (d : C ⊤) (f : ∀ a : ℕ, C a) (x : ℕ) : + @recTopCoe C d f ↑x = f x := + rfl + +end ENat + +/-- `ℕ+` is the type of positive natural numbers. It is defined as a subtype, + and the VM representation of `ℕ+` is the same as `ℕ` because the proof + is not stored. -/ +def PNat := { n : ℕ // 0 < n } deriving DecidableEq + +@[inherit_doc] +notation "ℕ+" => PNat + +/-- The underlying natural number -/ +@[coe] +def PNat.val : ℕ+ → ℕ := Subtype.val + +instance coePNatNat : Coe ℕ+ ℕ := + ⟨PNat.val⟩ + +instance : Repr ℕ+ := + ⟨fun n n' => reprPrec n.1 n'⟩ diff --git a/Mathlib/Order/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 3e55eda001a9c..1c2dbcf53ed26 100644 --- a/Mathlib/Order/UpperLower/Basic.lean +++ b/Mathlib/Order/UpperLower/Basic.lean @@ -536,7 +536,7 @@ instance completeLattice : CompleteLattice (UpperSet α) := (fun _ _ => rfl) (fun _ => rfl) (fun _ => rfl) rfl rfl instance completelyDistribLattice : CompletelyDistribLattice (UpperSet α) := - .ofMinimalAxioms $ + .ofMinimalAxioms <| (toDual.injective.comp SetLike.coe_injective).completelyDistribLatticeMinimalAxioms .of _ (fun _ _ => rfl) (fun _ _ => rfl) (fun _ => rfl) (fun _ => rfl) rfl rfl @@ -671,7 +671,7 @@ instance completeLattice : CompleteLattice (LowerSet α) := (fun _ => rfl) rfl rfl instance completelyDistribLattice : CompletelyDistribLattice (LowerSet α) := - .ofMinimalAxioms $ SetLike.coe_injective.completelyDistribLatticeMinimalAxioms .of _ + .ofMinimalAxioms <| SetLike.coe_injective.completelyDistribLatticeMinimalAxioms .of _ (fun _ _ => rfl) (fun _ _ => rfl) (fun _ => rfl) (fun _ => rfl) rfl rfl instance : Inhabited (LowerSet α) := @@ -1802,3 +1802,5 @@ theorem lowerClosure_prod (s : Set α) (t : Set β) : simp [Prod.le_def, @and_and_and_comm _ (_ ∈ t)] end Preorder + +set_option linter.style.longFile 1900 diff --git a/Mathlib/Order/WellFounded.lean b/Mathlib/Order/WellFounded.lean index 107a3a70cbacc..613d28890f078 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.Basic /-! # 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 - cases' 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 @@ -280,3 +320,15 @@ theorem StrictAnti.wellFoundedGT [WellFoundedLT β] (hf : StrictAnti f) : WellFo StrictMono.wellFoundedLT (α := αᵒᵈ) (fun _ _ h ↦ hf h) end WellFoundedLT + +/-- A nonempty linear order with well-founded `<` has a bottom element. -/ +noncomputable def WellFoundedLT.toOrderBot {α} [LinearOrder α] [Nonempty α] [h : WellFoundedLT α] : + OrderBot α where + bot := h.wf.min _ Set.univ_nonempty + bot_le a := h.wf.min_le (Set.mem_univ a) + +/-- A nonempty linear order with well-founded `>` has a top element. -/ +noncomputable def WellFoundedGT.toOrderTop {α} [LinearOrder α] [Nonempty α] [WellFoundedGT α] : + OrderTop α := + have := WellFoundedLT.toOrderBot (α := αᵒᵈ) + inferInstanceAs (OrderTop αᵒᵈᵒᵈ) diff --git a/Mathlib/Order/WellFoundedSet.lean b/Mathlib/Order/WellFoundedSet.lean index fbe6f4b58728d..5c7e684d6af00 100644 --- a/Mathlib/Order/WellFoundedSet.lean +++ b/Mathlib/Order/WellFoundedSet.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.Init.Data.Sigma.Lex import Mathlib.Data.Prod.Lex import Mathlib.Data.Sigma.Lex import Mathlib.Order.Antichain @@ -135,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 @@ -168,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 @@ -311,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 := @@ -432,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 @@ -445,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 @@ -469,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 := @@ -696,7 +694,7 @@ theorem iff_not_exists_isMinBadSeq (rk : α → ℕ) {s : Set α} : /-- Higman's Lemma, which states that for any reflexive, transitive relation `r` which is partially well-ordered on a set `s`, the relation `List.SublistForall₂ r` is partially well-ordered on the set of lists of elements of `s`. That relation is defined so that - `List.SublistForall₂ r l₁ l₂` whenever `l₁` related pointwise by `r` to a sublist of `l₂`. -/ + `List.SublistForall₂ r l₁ l₂` whenever `l₁` related pointwise by `r` to a sublist of `l₂`. -/ theorem partiallyWellOrderedOn_sublistForall₂ (r : α → α → Prop) [IsRefl α r] [IsTrans α r] {s : Set α} (h : s.PartiallyWellOrderedOn r) : { l : List α | ∀ x, x ∈ l → x ∈ s }.PartiallyWellOrderedOn (List.SublistForall₂ r) := by @@ -828,7 +826,7 @@ we only require it to be well-founded on fibers of `f`. -/ theorem WellFounded.prod_lex_of_wellFoundedOn_fiber (hα : WellFounded (rα on f)) (hβ : ∀ a, (f ⁻¹' {a}).WellFoundedOn (rβ on g)) : WellFounded (Prod.Lex rα rβ on fun c => (f c, g c)) := by - refine ((PSigma.lex_wf (wellFoundedOn_range.2 hα) fun a => hβ a).onFun + refine ((psigma_lex (wellFoundedOn_range.2 hα) fun a => hβ a).onFun (f := fun c => ⟨⟨_, c, rfl⟩, c, rfl⟩)).mono fun c c' h => ?_ obtain h' | h' := Prod.lex_iff.1 h · exact PSigma.Lex.left _ _ h' @@ -853,7 +851,7 @@ require it to be well-founded on fibers of `f`. -/ theorem WellFounded.sigma_lex_of_wellFoundedOn_fiber (hι : WellFounded (rι on f)) (hπ : ∀ i, (f ⁻¹' {i}).WellFoundedOn (rπ i on g i)) : WellFounded (Sigma.Lex rι rπ on fun c => ⟨f c, g (f c) c⟩) := by - refine ((PSigma.lex_wf (wellFoundedOn_range.2 hι) fun a => hπ a).onFun + refine ((psigma_lex (wellFoundedOn_range.2 hι) fun a => hπ a).onFun (f := fun c => ⟨⟨_, c, rfl⟩, c, rfl⟩)).mono fun c c' h => ?_ obtain h' | ⟨h', h''⟩ := Sigma.lex_iff.1 h · exact PSigma.Lex.left _ _ h' diff --git a/Mathlib/Order/WithBot.lean b/Mathlib/Order/WithBot.lean index 364cc4b359466..c0f4154f4b647 100644 --- a/Mathlib/Order/WithBot.lean +++ b/Mathlib/Order/WithBot.lean @@ -3,10 +3,11 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl -/ -import Mathlib.Init.Algebra.Classes import Mathlib.Logic.Nontrivial.Basic import Mathlib.Order.BoundedOrder +import Mathlib.Order.TypeTags import Mathlib.Data.Option.NAry +import Mathlib.Tactic.Contrapose import Mathlib.Tactic.Lift import Mathlib.Data.Option.Basic @@ -23,34 +24,10 @@ Adding a `bot` or a `top` to an order. variable {α β γ δ : Type*} -/-- Attach `⊥` to a type. -/ -def WithBot (α : Type*) := - Option α - namespace WithBot variable {a b : α} -instance [Repr α] : Repr (WithBot α) := - ⟨fun o _ => - match o with - | none => "⊥" - | some a => "↑" ++ repr a⟩ - -/-- The canonical map from `α` into `WithBot α` -/ -@[coe, match_pattern] def some : α → WithBot α := - Option.some - --- Porting note: changed this from `CoeTC` to `Coe` but I am not 100% confident that's correct. -instance coe : Coe α (WithBot α) := - ⟨some⟩ - -instance bot : Bot (WithBot α) := - ⟨none⟩ - -instance inhabited : Inhabited (WithBot α) := - ⟨⊥⟩ - instance nontrivial [Nonempty α] : Nontrivial (WithBot α) := Option.nontrivial @@ -83,22 +60,6 @@ theorem bot_ne_coe : ⊥ ≠ (a : WithBot α) := theorem coe_ne_bot : (a : WithBot α) ≠ ⊥ := nofun -/-- Recursor for `WithBot` using the preferred forms `⊥` and `↑a`. -/ -@[elab_as_elim, induction_eliminator, cases_eliminator] -def recBotCoe {C : WithBot α → Sort*} (bot : C ⊥) (coe : ∀ a : α, C a) : ∀ n : WithBot α, C n - | ⊥ => bot - | (a : α) => coe a - -@[simp] -theorem recBotCoe_bot {C : WithBot α → Sort*} (d : C ⊥) (f : ∀ a : α, C a) : - @recBotCoe _ C d f ⊥ = d := - rfl - -@[simp] -theorem recBotCoe_coe {C : WithBot α → Sort*} (d : C ⊥) (f : ∀ a : α, C a) (x : α) : - @recBotCoe _ C d f ↑x = f x := - rfl - /-- Specialization of `Option.getD` to values in `WithBot α` that respects API boundaries. -/ def unbot' (d : α) (x : WithBot α) : α := @@ -340,13 +301,15 @@ instance preorder [Preorder α] : Preorder (WithBot α) where instance partialOrder [PartialOrder α] : PartialOrder (WithBot α) := { WithBot.preorder with - le_antisymm := fun o₁ o₂ h₁ h₂ => by - cases' o₁ with a - · cases' o₂ with b - · rfl - rcases h₂ b rfl with ⟨_, ⟨⟩, _⟩ - · rcases h₁ a rfl with ⟨b, ⟨⟩, h₁'⟩ - rcases h₂ b rfl with ⟨_, ⟨⟩, h₂'⟩ + le_antisymm := fun o₁ o₂ h₁ h₂ ↦ by + cases o₁ with + | bot => + cases o₂ with + | bot => rfl + | coe b => obtain ⟨_, ⟨⟩, _⟩ := h₂ b rfl + | coe a => + obtain ⟨b, ⟨⟩, h₁'⟩ := h₁ a rfl + obtain ⟨_, ⟨⟩, h₂'⟩ := h₂ b rfl rw [le_antisymm h₁' h₂'] } section Preorder @@ -416,12 +379,19 @@ instance semilatticeSup [SemilatticeSup α] : SemilatticeSup (WithBot α) where le_sup_left := fun o₁ o₂ a ha => by cases ha; cases o₂ <;> simp le_sup_right := fun o₁ o₂ a ha => by cases ha; cases o₁ <;> simp sup_le := fun o₁ o₂ o₃ h₁ h₂ a ha => by - cases' o₁ with b <;> cases' o₂ with c <;> cases ha - · exact h₂ a rfl - · exact h₁ a rfl - · rcases h₁ b rfl with ⟨d, ⟨⟩, h₁'⟩ - simp only [coe_le_coe] at h₂ - exact ⟨d, rfl, sup_le h₁' h₂⟩ + cases o₁ with + | bot => + cases o₂ with + | bot => exact h₁ a ha + | coe c => exact h₂ a ha + | coe b => + cases o₂ with + | bot => exact h₁ a ha + | coe c => + cases ha + obtain ⟨d, ⟨⟩, h₁'⟩ := h₁ b rfl + simp only [coe_le_coe] at h₂ + exact ⟨d, rfl, sup_le h₁' h₂⟩ theorem coe_sup [SemilatticeSup α] (a b : α) : ((a ⊔ b : α) : WithBot α) = (a : WithBot α) ⊔ b := rfl @@ -559,34 +529,10 @@ instance noMaxOrder [LT α] [NoMaxOrder α] [Nonempty α] : NoMaxOrder (WithBot end WithBot ---TODO(Mario): Construct using order dual on `WithBot` -/-- Attach `⊤` to a type. -/ -def WithTop (α : Type*) := - Option α - namespace WithTop variable {a b : α} -instance [Repr α] : Repr (WithTop α) := - ⟨fun o _ => - match o with - | none => "⊤" - | some a => "↑" ++ repr a⟩ - -/-- The canonical map from `α` into `WithTop α` -/ -@[coe, match_pattern] def some : α → WithTop α := - Option.some - -instance coeTC : CoeTC α (WithTop α) := - ⟨some⟩ - -instance top : Top (WithTop α) := - ⟨none⟩ - -instance inhabited : Inhabited (WithTop α) := - ⟨⊤⟩ - instance nontrivial [Nonempty α] : Nontrivial (WithTop α) := Option.nontrivial @@ -619,22 +565,6 @@ theorem top_ne_coe : ⊤ ≠ (a : WithTop α) := theorem coe_ne_top : (a : WithTop α) ≠ ⊤ := nofun -/-- Recursor for `WithTop` using the preferred forms `⊤` and `↑a`. -/ -@[elab_as_elim, induction_eliminator, cases_eliminator] -def recTopCoe {C : WithTop α → Sort*} (top : C ⊤) (coe : ∀ a : α, C a) : ∀ n : WithTop α, C n - | none => top - | Option.some a => coe a - -@[simp] -theorem recTopCoe_top {C : WithTop α → Sort*} (d : C ⊤) (f : ∀ a : α, C a) : - @recTopCoe _ C d f ⊤ = d := - rfl - -@[simp] -theorem recTopCoe_coe {C : WithTop α → Sort*} (d : C ⊤) (f : ∀ a : α, C a) (x : α) : - @recTopCoe _ C d f ↑x = f x := - rfl - /-- `WithTop.toDual` is the equivalence sending `⊤` to `⊥` and any `a : α` to `toDual a : αᵒᵈ`. See `WithTop.toDualBotEquiv` for the related order-iso. -/ @@ -973,11 +903,37 @@ theorem ofDual_map (f : αᵒᵈ → βᵒᵈ) (a : WithBot αᵒᵈ) : lemma forall_lt_iff_eq_bot [Preorder α] {x : WithBot α} : (∀ y : α, x < y) ↔ x = ⊥ := - ⟨fun h ↦ forall_ne_iff_eq_bot.mp (fun x ↦ (h x).ne'), fun h ↦ h ▸ fun y ↦ bot_lt_coe y⟩ + ⟨fun h ↦ forall_ne_iff_eq_bot.mp (fun x ↦ (h x).ne'), fun h y ↦ h ▸ bot_lt_coe y⟩ + +lemma forall_le_iff_eq_bot [Preorder α] [NoMinOrder α] {x : WithBot α} : + (∀ y : α, x ≤ y) ↔ x = ⊥ := by + refine ⟨fun h ↦ forall_lt_iff_eq_bot.1 fun y ↦ ?_, fun h _ ↦ h ▸ bot_le⟩ + obtain ⟨w, hw⟩ := exists_lt y + exact (h w).trans_lt (coe_lt_coe.2 hw) + +lemma le_of_forall_lt_iff_le [LinearOrder α] [DenselyOrdered α] [NoMinOrder α] + {x y : WithBot α} : (∀ z : α, x < z → y ≤ z) ↔ y ≤ x := by + refine ⟨fun h ↦ ?_, fun h z x_z ↦ h.trans x_z.le⟩ + induction x with + | bot => exact le_of_eq <| forall_le_iff_eq_bot.1 fun z ↦ h z (bot_lt_coe z) + | coe x => + rw [le_coe_iff] + rintro y rfl + exact le_of_forall_le_of_dense (by exact_mod_cast h) + +lemma ge_of_forall_gt_iff_ge [LinearOrder α] [DenselyOrdered α] [NoMinOrder α] + {x y : WithBot α} : (∀ z : α, z < x → z ≤ y) ↔ x ≤ y := by + apply Iff.intro _ (fun h _ x_z ↦ x_z.le.trans h) + induction y with + | bot => simpa using forall_le_iff_eq_bot.1 + | coe y => + rw [le_coe_iff] + rintro h x rfl + exact le_of_forall_ge_of_dense (by exact_mod_cast h) section LE -variable [LE α] {a b : α} +variable [LE α] theorem toDual_le_iff {a : WithBot α} {b : WithTop αᵒᵈ} : WithBot.toDual a ≤ b ↔ WithTop.ofDual b ≤ a := @@ -1007,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 := @@ -1132,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 := @@ -1142,11 +1098,22 @@ theorem coe_untop'_le (a : WithTop α) (b : α) : a.untop' b ≤ a := theorem coe_top_lt [OrderTop α] {x : WithTop α} : (⊤ : α) < x ↔ x = ⊤ := WithBot.lt_coe_bot (α := αᵒᵈ) -lemma forall_lt_iff_eq_top {x : WithTop α} : (∀ y : α, y < x) ↔ x = ⊤ := - ⟨fun h ↦ forall_ne_iff_eq_top.mp (fun x ↦ (h x).ne), fun h ↦ h ▸ fun y ↦ coe_lt_top y⟩ +lemma forall_gt_iff_eq_top {x : WithTop α} : (∀ y : α, y < x) ↔ x = ⊤ := + WithBot.forall_lt_iff_eq_bot (α := αᵒᵈ) + +lemma forall_ge_iff_eq_top [NoMaxOrder α] {x : WithTop α} : (∀ y : α, y ≤ x) ↔ x = ⊤ := + WithBot.forall_le_iff_eq_bot (α := αᵒᵈ) end Preorder +lemma le_of_forall_lt_iff_le [LinearOrder α] [DenselyOrdered α] [NoMaxOrder α] + {x y : WithTop α} : (∀ z : α, x < z → y ≤ z) ↔ y ≤ x := + WithBot.ge_of_forall_gt_iff_ge (α := αᵒᵈ) + +lemma ge_of_forall_gt_iff_ge [LinearOrder α] [DenselyOrdered α] [NoMaxOrder α] + {x y : WithTop α} : (∀ z : α, z < x → z ≤ y) ↔ x ≤ y := + WithBot.le_of_forall_lt_iff_le (α := αᵒᵈ) + instance semilatticeInf [SemilatticeInf α] : SemilatticeInf (WithTop α) := { WithTop.partialOrder with inf := Option.liftOrGet (· ⊓ ·), diff --git a/Mathlib/Order/Zorn.lean b/Mathlib/Order/Zorn.lean index e31a5347f9d81..8c519e1bbaec1 100644 --- a/Mathlib/Order/Zorn.lean +++ b/Mathlib/Order/Zorn.lean @@ -59,8 +59,6 @@ Originally ported from Isabelle/HOL. The Fleuriot, Tobias Nipkow, Christian Sternagel. -/ - -open scoped Classical open Set variable {α β : Type*} {r : α → α → Prop} {c : Set α} diff --git a/Mathlib/Probability/BorelCantelli.lean b/Mathlib/Probability/BorelCantelli.lean index fead097056f50..be4a2299f904e 100644 --- a/Mathlib/Probability/BorelCantelli.lean +++ b/Mathlib/Probability/BorelCantelli.lean @@ -29,7 +29,7 @@ open MeasureTheory namespace ProbabilityTheory -variable {Ω : Type*} {m0 : MeasurableSpace Ω} {μ : Measure Ω} [IsProbabilityMeasure μ] +variable {Ω : Type*} {m0 : MeasurableSpace Ω} {μ : Measure Ω} section BorelCantelli @@ -45,8 +45,9 @@ theorem iIndepFun.indep_comap_natural_of_lt (hf : ∀ i, StronglyMeasurable (f i theorem iIndepFun.condexp_natural_ae_eq_of_lt [SecondCountableTopology β] [CompleteSpace β] [NormedSpace ℝ β] (hf : ∀ i, StronglyMeasurable (f i)) (hfi : iIndepFun (fun _ => mβ) f μ) - (hij : i < j) : μ[f j|Filtration.natural f hf i] =ᵐ[μ] fun _ => μ[f j] := - condexp_indep_eq (hf j).measurable.comap_le (Filtration.le _ _) + (hij : i < j) : μ[f j|Filtration.natural f hf i] =ᵐ[μ] fun _ => μ[f j] := by + have : IsProbabilityMeasure μ := hfi.isProbabilityMeasure + exact condexp_indep_eq (hf j).measurable.comap_le (Filtration.le _ _) (comap_measurable <| f j).stronglyMeasurable (hfi.indep_comap_natural_of_lt hf hij) theorem iIndepSet.condexp_indicator_filtrationOfSet_ae_eq (hsm : ∀ n, MeasurableSet (s n)) @@ -63,6 +64,7 @@ open Filter `∑ n, μ sₙ = ∞`, `limsup sₙ` has measure 1. -/ theorem measure_limsup_eq_one {s : ℕ → Set Ω} (hsm : ∀ n, MeasurableSet (s n)) (hs : iIndepSet s μ) (hs' : (∑' n, μ (s n)) = ∞) : μ (limsup s atTop) = 1 := by + have : IsProbabilityMeasure μ := hs.isProbabilityMeasure rw [measure_congr (eventuallyEq_set.2 (ae_mem_limsup_atTop_iff μ <| measurableSet_filtrationOfSet' hsm) : (limsup s atTop : Set Ω) =ᵐ[μ] {ω | Tendsto (fun n => ∑ k ∈ Finset.range n, @@ -84,13 +86,13 @@ theorem measure_limsup_eq_one {s : ℕ → Set Ω} (hsm : ∀ n, MeasurableSet ( rw [← sub_nonneg, Finset.sum_range_succ_sub_sum] exact ENNReal.toReal_nonneg · rintro ⟨B, hB⟩ - refine not_eventually.2 (frequently_of_forall fun n => ?_) (htends B.toNNReal) + refine not_eventually.2 (Frequently.of_forall fun n => ?_) (htends B.toNNReal) rw [mem_upperBounds] at hB specialize hB (∑ k ∈ Finset.range n, μ (s (k + 1))).toReal _ · refine ⟨n, ?_⟩ rw [ENNReal.toReal_sum] exact fun _ _ => measure_ne_top _ _ - · rw [not_lt, ← ENNReal.toReal_le_toReal (ENNReal.sum_lt_top _).ne ENNReal.coe_ne_top] + · rw [not_lt, ← ENNReal.toReal_le_toReal (ENNReal.sum_ne_top.2 _) ENNReal.coe_ne_top] · exact hB.trans (by simp) · exact fun _ _ => measure_ne_top _ _ diff --git a/Mathlib/Probability/CDF.lean b/Mathlib/Probability/CDF.lean index f17cc568c2d9e..ae51880f7f115 100644 --- a/Mathlib/Probability/CDF.lean +++ b/Mathlib/Probability/CDF.lean @@ -70,7 +70,6 @@ lemma tendsto_cdf_atBot : Tendsto (cdf μ) atBot (𝓝 0) := tendsto_condCDF_atB lemma tendsto_cdf_atTop : Tendsto (cdf μ) atTop (𝓝 1) := tendsto_condCDF_atTop _ _ lemma ofReal_cdf [IsProbabilityMeasure μ] (x : ℝ) : ENNReal.ofReal (cdf μ x) = μ (Iic x) := by - have := IsProbabilityMeasure.toIsFiniteMeasure (Measure.prod (Measure.dirac ()) μ) have h := lintegral_condCDF ((Measure.dirac Unit.unit).prod μ) x simpa only [MeasureTheory.Measure.fst_prod, Measure.prod_prod, measure_univ, one_mul, lintegral_dirac] using h diff --git a/Mathlib/Probability/CondCount.lean b/Mathlib/Probability/CondCount.lean deleted file mode 100644 index 6eb8dc1795d29..0000000000000 --- a/Mathlib/Probability/CondCount.lean +++ /dev/null @@ -1,184 +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] - -@[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) := - { measure_univ := by - rw [condCount, cond_apply _ hs.measurableSet, Set.inter_univ, 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_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 e9c83057f3fe8..18a5ab72ec167 100644 --- a/Mathlib/Probability/ConditionalExpectation.lean +++ b/Mathlib/Probability/ConditionalExpectation.lean @@ -58,12 +58,12 @@ 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] - exact eventually_of_forall fun _ => (by trivial) + simp_rw [Submodule.coe_subtypeL', Submodule.coe_subtype] + exact Eventually.of_forall fun _ => (by trivial) refine isClosed_eq (Continuous.const_smul ?_ _) ?_ · rw [heq₁] exact continuous_integral.comp (ContinuousLinearMap.continuous _) diff --git a/Mathlib/Probability/ConditionalProbability.lean b/Mathlib/Probability/ConditionalProbability.lean index 7a9f4513f7f3a..aa9148f363412 100644 --- a/Mathlib/Probability/ConditionalProbability.lean +++ b/Mathlib/Probability/ConditionalProbability.lean @@ -97,11 +97,15 @@ is a probability measure. -/ theorem cond_isProbabilityMeasure [IsFiniteMeasure μ] (hcs : μ s ≠ 0) : IsProbabilityMeasure μ[|s] := cond_isProbabilityMeasure_of_finite μ hcs (measure_ne_top μ s) -instance cond_isFiniteMeasure : IsFiniteMeasure μ[|s] := by +instance : IsZeroOrProbabilityMeasure μ[|s] := by constructor - simp only [Measure.coe_smul, Pi.smul_apply, MeasurableSet.univ, Measure.restrict_apply, - Set.univ_inter, smul_eq_mul, ProbabilityTheory.cond, ← ENNReal.div_eq_inv_mul] - exact ENNReal.div_self_le_one.trans_lt ENNReal.one_lt_top + simp only [cond, Measure.coe_smul, Pi.smul_apply, MeasurableSet.univ, Measure.restrict_apply, + univ_inter, smul_eq_mul, ← ENNReal.div_eq_inv_mul] + rcases eq_or_ne (μ s) 0 with h | h + · simp [h] + rcases eq_or_ne (μ s) ∞ with h' | h' + · simp [h'] + simp [ENNReal.div_self h h'] theorem cond_toMeasurable_eq : μ[|(toMeasurable μ s)] = μ[|s] := by @@ -140,6 +144,9 @@ theorem cond_apply (hms : MeasurableSet s) (t : Set Ω) : μ[t|s] = (μ s)⁻¹ 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] +@[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] diff --git a/Mathlib/Probability/Distributions/Exponential.lean b/Mathlib/Probability/Distributions/Exponential.lean index ad5ce86b273a2..2a2c503ce5f51 100644 --- a/Mathlib/Probability/Distributions/Exponential.lean +++ b/Mathlib/Probability/Distributions/Exponential.lean @@ -73,7 +73,7 @@ lemma measurable_exponentialPDFReal (r : ℝ) : Measurable (exponentialPDFReal r lemma exponentialPDFReal_pos {x r : ℝ} (hr : 0 < r) (hx : 0 < x) : 0 < exponentialPDFReal r x := gammaPDFReal_pos zero_lt_one hr hx -/-- The exponential pdf is nonnegative-/ +/-- The exponential pdf is nonnegative -/ lemma exponentialPDFReal_nonneg {r : ℝ} (hr : 0 < r) (x : ℝ) : 0 ≤ exponentialPDFReal r x := gammaPDFReal_nonneg zero_lt_one hr x @@ -139,7 +139,7 @@ lemma lintegral_exponentialPDF_eq_antiDeriv {r : ℝ} (hr : 0 < r) (x : ℝ) : rw [setLIntegral_congr_fun measurableSet_Icc (ae_of_all _ (by intro a ⟨(hle : _ ≤ a), _⟩; rw [if_pos hle]))] rw [← ENNReal.toReal_eq_toReal _ ENNReal.ofReal_ne_top, ← integral_eq_lintegral_of_nonneg_ae - (eventually_of_forall fun _ ↦ le_of_lt (mul_pos hr (exp_pos _)))] + (Eventually.of_forall fun _ ↦ le_of_lt (mul_pos hr (exp_pos _)))] · have : ∫ a in uIoc 0 x, r * rexp (-(r * a)) = ∫ a in (0)..x, r * rexp (-(r * a)) := by rw [intervalIntegral.intervalIntegral_eq_integral_uIoc, smul_eq_mul, if_pos h, one_mul] rw [integral_Icc_eq_integral_Ioc, ← uIoc_of_le h, 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/Gaussian.lean b/Mathlib/Probability/Distributions/Gaussian.lean index b31dba6a5ddf3..10a5c010266d0 100644 --- a/Mathlib/Probability/Distributions/Gaussian.lean +++ b/Mathlib/Probability/Distributions/Gaussian.lean @@ -93,7 +93,7 @@ lemma integrable_gaussianPDFReal (μ : ℝ) (v : ℝ≥0) : field_simp exact Integrable.comp_sub_right hg μ -/-- The gaussian distribution pdf integrates to 1 when the variance is not zero. -/ +/-- The gaussian distribution pdf integrates to 1 when the variance is not zero. -/ lemma lintegral_gaussianPDFReal_eq_one (μ : ℝ) {v : ℝ≥0} (h : v ≠ 0) : ∫⁻ x, ENNReal.ofReal (gaussianPDFReal μ v x) = 1 := by rw [← ENNReal.toReal_eq_one_iff] @@ -112,7 +112,7 @@ lemma lintegral_gaussianPDFReal_eq_one (μ : ℝ) {v : ℝ≥0} (h : v ≠ 0) : ring · positivity -/-- The gaussian distribution pdf integrates to 1 when the variance is not zero. -/ +/-- The gaussian distribution pdf integrates to 1 when the variance is not zero. -/ lemma integral_gaussianPDFReal_eq_one (μ : ℝ) {v : ℝ≥0} (hv : v ≠ 0) : ∫ x, gaussianPDFReal μ v x = 1 := by have h := lintegral_gaussianPDFReal_eq_one μ hv @@ -283,7 +283,7 @@ lemma gaussianReal_map_const_mul (c : ℝ) : rw [Measure.map_const] simp only [ne_eq, measure_univ, one_smul, mul_eq_zero] convert (gaussianReal_zero_var 0).symm - simp only [ne_eq, zero_pow, mul_eq_zero, hv, or_false, not_false_eq_true] + simp only [ne_eq, zero_pow, mul_eq_zero, hv, or_false, not_false_eq_true, reduceCtorEq] rfl let e : ℝ ≃ᵐ ℝ := (Homeomorph.mulLeft₀ c hc).symm.toMeasurableEquiv have he' : ∀ x, HasDerivAt e ((fun _ ↦ c⁻¹) x) x := by 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 18d02e427ea51..c639f53703f5b 100644 --- a/Mathlib/Probability/Distributions/Uniform.lean +++ b/Mathlib/Probability/Distributions/Uniform.lean @@ -158,8 +158,8 @@ theorem mul_pdf_integrable (hcs : IsCompact s) (huX : IsUniform X s ℙ) : 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_lt_top (setLIntegral_lt_top_of_isCompact hnt.2 hcs continuous_nnnorm).ne - (ENNReal.inv_lt_top.2 (pos_iff_ne_zero.mpr hnt.1)).ne).ne + exact ENNReal.mul_ne_top (setLIntegral_lt_top_of_isCompact hnt.2 hcs continuous_nnnorm).ne + (ENNReal.inv_lt_top.2 (pos_iff_ne_zero.mpr hnt.1)).ne /-- A real uniform random variable `X` with support `s` has expectation `(λ s)⁻¹ * ∫ x in s, x ∂λ` where `λ` is the Lebesgue measure. -/ @@ -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 3ff422fb422f8..cf6f2aebad8a9 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 @@ -144,6 +146,9 @@ lemma iIndepSets.meas_biInter (h : iIndepSets π μ) (s : Finset ι) {f : ι → (hf : ∀ i, i ∈ s → f i ∈ π i) : μ (⋂ i ∈ s, f i) = ∏ i ∈ s, μ (f i) := (iIndepSets_iff _ _).1 h s hf +lemma iIndepSets.isProbabilityMeasure (h : iIndepSets π μ) : IsProbabilityMeasure μ := + ⟨by simpa using h ∅ (f := fun _ ↦ univ)⟩ + lemma iIndepSets.meas_iInter [Fintype ι] (h : iIndepSets π μ) (hs : ∀ i, s i ∈ π i) : μ (⋂ i, s i) = ∏ i, μ (s i) := by simp [← h.meas_biInter _ fun _i _ ↦ hs _] @@ -159,6 +164,9 @@ lemma iIndep.iIndepSets' {m : ι → MeasurableSpace Ω} {_ : MeasurableSpace Ω} {μ : Measure Ω} (hμ : iIndep m μ) : iIndepSets (fun x ↦ {s | MeasurableSet[m x] s}) μ := (iIndep_iff_iIndepSets _ _).1 hμ +lemma iIndep.isProbabilityMeasure (h : iIndep m μ) : IsProbabilityMeasure μ := + h.iIndepSets'.isProbabilityMeasure + lemma iIndep_iff (m : ι → MeasurableSpace Ω) {_mΩ : MeasurableSpace Ω} (μ : Measure Ω) : iIndep m μ ↔ ∀ (s : Finset ι) {f : ι → Set Ω} (_H : ∀ i, i ∈ s → MeasurableSet[m i] (f i)), μ (⋂ i ∈ s, f i) = ∏ i ∈ s, μ (f i) := by @@ -183,6 +191,9 @@ lemma iIndepSet_iff_iIndep (s : ι → Set Ω) (μ : Measure Ω) : iIndepSet s μ ↔ iIndep (fun i ↦ generateFrom {s i}) μ := by simp only [iIndepSet, iIndep, Kernel.iIndepSet] +lemma iIndepSet.isProbabilityMeasure (h : iIndepSet s μ) : IsProbabilityMeasure μ := + ((iIndepSet_iff_iIndep _ _).1 h).isProbabilityMeasure + lemma iIndepSet_iff (s : ι → Set Ω) (μ : Measure Ω) : iIndepSet s μ ↔ ∀ (s' : Finset ι) {f : ι → Set Ω} (_H : ∀ i, i ∈ s' → MeasurableSet[generateFrom {s i}] (f i)), @@ -253,15 +264,15 @@ theorem IndepSets.symm {s₁ s₂ : Set (Set Ω)} (h : IndepSets s₁ s₂ μ) : @[symm] theorem Indep.symm (h : Indep m₁ m₂ μ) : Indep m₂ m₁ μ := IndepSets.symm h -theorem indep_bot_right [IsProbabilityMeasure μ] : Indep m' ⊥ μ := +theorem indep_bot_right [IsZeroOrProbabilityMeasure μ] : Indep m' ⊥ μ := Kernel.indep_bot_right m' -theorem indep_bot_left [IsProbabilityMeasure μ] : Indep ⊥ m' μ := (indep_bot_right m').symm +theorem indep_bot_left [IsZeroOrProbabilityMeasure μ] : Indep ⊥ m' μ := (indep_bot_right m').symm -theorem indepSet_empty_right [IsProbabilityMeasure μ] (s : Set Ω) : IndepSet s ∅ μ := +theorem indepSet_empty_right [IsZeroOrProbabilityMeasure μ] (s : Set Ω) : IndepSet s ∅ μ := Kernel.indepSet_empty_right s -theorem indepSet_empty_left [IsProbabilityMeasure μ] (s : Set Ω) : IndepSet ∅ s μ := +theorem indepSet_empty_left [IsZeroOrProbabilityMeasure μ] (s : Set Ω) : IndepSet ∅ s μ := Kernel.indepSet_empty_left s theorem indepSets_of_indepSets_of_le_left {s₁ s₂ s₃ : Set (Set Ω)} @@ -327,7 +338,7 @@ end Indep section FromIndepToIndep -variable {m : ι → MeasurableSpace Ω} {_mΩ : MeasurableSpace Ω} {μ : Measure Ω} +variable {m : ι → MeasurableSpace Ω} {_mΩ : MeasurableSpace Ω} {μ : Measure Ω} theorem iIndepSets.indepSets {s : ι → Set (Set Ω)} (h_indep : iIndepSets s μ) {i j : ι} (hij : i ≠ j) : IndepSets (s i) (s j) μ := @@ -376,61 +387,62 @@ variable {m : ι → MeasurableSpace Ω} {m1 m2 _mΩ : MeasurableSpace Ω} {μ : /-! ### Independence of generating π-systems implies independence of measurable space structures -/ -theorem IndepSets.indep [IsProbabilityMeasure μ] +theorem IndepSets.indep [IsZeroOrProbabilityMeasure μ] {p1 p2 : Set (Set Ω)} (h1 : m1 ≤ _mΩ) (h2 : m2 ≤ _mΩ) (hp1 : IsPiSystem p1) (hp2 : IsPiSystem p2) (hpm1 : m1 = generateFrom p1) (hpm2 : m2 = generateFrom p2) (hyp : IndepSets p1 p2 μ) : Indep m1 m2 μ := Kernel.IndepSets.indep h1 h2 hp1 hp2 hpm1 hpm2 hyp -theorem IndepSets.indep' [IsProbabilityMeasure μ] +theorem IndepSets.indep' [IsZeroOrProbabilityMeasure μ] {p1 p2 : Set (Set Ω)} (hp1m : ∀ s ∈ p1, MeasurableSet s) (hp2m : ∀ s ∈ p2, MeasurableSet s) (hp1 : IsPiSystem p1) (hp2 : IsPiSystem p2) (hyp : IndepSets p1 p2 μ) : Indep (generateFrom p1) (generateFrom p2) μ := Kernel.IndepSets.indep' hp1m hp2m hp1 hp2 hyp -theorem indepSets_piiUnionInter_of_disjoint [IsProbabilityMeasure μ] {s : ι → Set (Set Ω)} +theorem indepSets_piiUnionInter_of_disjoint {s : ι → Set (Set Ω)} {S T : Set ι} (h_indep : iIndepSets s μ) (hST : Disjoint S T) : IndepSets (piiUnionInter s S) (piiUnionInter s T) μ := Kernel.indepSets_piiUnionInter_of_disjoint h_indep hST -theorem iIndepSet.indep_generateFrom_of_disjoint [IsProbabilityMeasure μ] {s : ι → Set Ω} +theorem iIndepSet.indep_generateFrom_of_disjoint {s : ι → Set Ω} (hsm : ∀ n, MeasurableSet (s n)) (hs : iIndepSet s μ) (S T : Set ι) (hST : Disjoint S T) : Indep (generateFrom { t | ∃ n ∈ S, s n = t }) (generateFrom { t | ∃ k ∈ T, s k = t }) μ := Kernel.iIndepSet.indep_generateFrom_of_disjoint hsm hs S T hST -theorem indep_iSup_of_disjoint [IsProbabilityMeasure μ] +theorem indep_iSup_of_disjoint (h_le : ∀ i, m i ≤ _mΩ) (h_indep : iIndep m μ) {S T : Set ι} (hST : Disjoint S T) : Indep (⨆ i ∈ S, m i) (⨆ i ∈ T, m i) μ := Kernel.indep_iSup_of_disjoint h_le h_indep hST theorem indep_iSup_of_directed_le - [IsProbabilityMeasure μ] (h_indep : ∀ i, Indep (m i) m1 μ) + [IsZeroOrProbabilityMeasure μ] (h_indep : ∀ i, Indep (m i) m1 μ) (h_le : ∀ i, m i ≤ _mΩ) (h_le' : m1 ≤ _mΩ) (hm : Directed (· ≤ ·) m) : Indep (⨆ i, m i) m1 μ := Kernel.indep_iSup_of_directed_le h_indep h_le h_le' hm -theorem iIndepSet.indep_generateFrom_lt [Preorder ι] [IsProbabilityMeasure μ] {s : ι → Set Ω} +theorem iIndepSet.indep_generateFrom_lt [Preorder ι] {s : ι → Set Ω} (hsm : ∀ n, MeasurableSet (s n)) (hs : iIndepSet s μ) (i : ι) : Indep (generateFrom {s i}) (generateFrom { t | ∃ j < i, s j = t }) μ := Kernel.iIndepSet.indep_generateFrom_lt hsm hs i -theorem iIndepSet.indep_generateFrom_le [LinearOrder ι] [IsProbabilityMeasure μ] {s : ι → Set Ω} +theorem iIndepSet.indep_generateFrom_le [LinearOrder ι] + {s : ι → Set Ω} (hsm : ∀ n, MeasurableSet (s n)) (hs : iIndepSet s μ) (i : ι) {k : ι} (hk : i < k) : Indep (generateFrom {s k}) (generateFrom { t | ∃ j ≤ i, s j = t }) μ := Kernel.iIndepSet.indep_generateFrom_le hsm hs i hk -theorem iIndepSet.indep_generateFrom_le_nat [IsProbabilityMeasure μ] {s : ℕ → Set Ω} +theorem iIndepSet.indep_generateFrom_le_nat {s : ℕ → Set Ω} (hsm : ∀ n, MeasurableSet (s n)) (hs : iIndepSet s μ) (n : ℕ) : Indep (generateFrom {s (n + 1)}) (generateFrom { t | ∃ k ≤ n, s k = t }) μ := Kernel.iIndepSet.indep_generateFrom_le_nat hsm hs n -theorem indep_iSup_of_monotone [SemilatticeSup ι] [IsProbabilityMeasure μ] +theorem indep_iSup_of_monotone [SemilatticeSup ι] [IsZeroOrProbabilityMeasure μ] (h_indep : ∀ i, Indep (m i) m1 μ) (h_le : ∀ i, m i ≤ _mΩ) (h_le' : m1 ≤ _mΩ) (hm : Monotone m) : Indep (⨆ i, m i) m1 μ := Kernel.indep_iSup_of_monotone h_indep h_le h_le' hm -theorem indep_iSup_of_antitone [SemilatticeInf ι] [IsProbabilityMeasure μ] +theorem indep_iSup_of_antitone [SemilatticeInf ι] [IsZeroOrProbabilityMeasure μ] (h_indep : ∀ i, Indep (m i) m1 μ) (h_le : ∀ i, m i ≤ _mΩ) (h_le' : m1 ≤ _mΩ) (hm : Antitone m) : Indep (⨆ i, m i) m1 μ := Kernel.indep_iSup_of_antitone h_indep h_le h_le' hm @@ -441,7 +453,7 @@ theorem iIndepSets.piiUnionInter_of_not_mem {π : ι → Set (Set Ω)} {a : ι} Kernel.iIndepSets.piiUnionInter_of_not_mem hp_ind haS /-- The measurable space structures generated by independent pi-systems are independent. -/ -theorem iIndepSets.iIndep [IsProbabilityMeasure μ] +theorem iIndepSets.iIndep (h_le : ∀ i, m i ≤ _mΩ) (π : ι → Set (Set Ω)) (h_pi : ∀ n, IsPiSystem (π n)) (h_generate : ∀ i, m i = generateFrom (π i)) (h_ind : iIndepSets π μ) : iIndep m μ := @@ -463,17 +475,21 @@ variable {m₁ m₂ _mΩ : MeasurableSpace Ω} {μ : Measure Ω} {s t : Set Ω} theorem indepSet_iff_indepSets_singleton (hs_meas : MeasurableSet s) (ht_meas : MeasurableSet t) (μ : Measure Ω := by volume_tac) - [IsProbabilityMeasure μ] : IndepSet s t μ ↔ IndepSets {s} {t} μ := + [IsZeroOrProbabilityMeasure μ] : IndepSet s t μ ↔ IndepSets {s} {t} μ := Kernel.indepSet_iff_indepSets_singleton hs_meas ht_meas _ _ theorem indepSet_iff_measure_inter_eq_mul (hs_meas : MeasurableSet s) (ht_meas : MeasurableSet t) (μ : Measure Ω := by volume_tac) - [IsProbabilityMeasure μ] : IndepSet s t μ ↔ μ (s ∩ t) = μ s * μ t := + [IsZeroOrProbabilityMeasure μ] : IndepSet s t μ ↔ μ (s ∩ t) = μ s * μ t := (indepSet_iff_indepSets_singleton hs_meas ht_meas μ).trans indepSets_singleton_iff +lemma IndepSet.measure_inter_eq_mul {μ : Measure Ω} (h : IndepSet s t μ) : + μ (s ∩ t) = μ s * μ t := by + simpa using Kernel.IndepSet.measure_inter_eq_mul _ _ h + theorem IndepSets.indepSet_of_mem (hs : s ∈ S) (ht : t ∈ T) (hs_meas : MeasurableSet s) (ht_meas : MeasurableSet t) - (μ : Measure Ω := by volume_tac) [IsProbabilityMeasure μ] + (μ : Measure Ω := by volume_tac) [IsZeroOrProbabilityMeasure μ] (h_indep : IndepSets S T μ) : IndepSet s t μ := Kernel.IndepSets.indepSet_of_mem _ _ hs ht hs_meas ht_meas _ _ h_indep @@ -498,7 +514,9 @@ theorem iIndepSets_singleton_iff {s : ι → Set Ω} : simp_rw [iIndepSets, Kernel.iIndepSets_singleton_iff, ae_dirac_eq, Filter.eventually_pure, Kernel.const_apply] -variable [IsProbabilityMeasure μ] +theorem iIndepSet.meas_biInter {f : ι → Set Ω} (h : iIndepSet f μ) (s : Finset ι) : + μ (⋂ i ∈ s, f i) = ∏ i ∈ s, μ (f i) := by + simpa using Kernel.iIndepSet.meas_biInter h s theorem iIndepSet_iff_iIndepSets_singleton {f : ι → Set Ω} (hf : ∀ i, MeasurableSet (f i)) : iIndepSet f μ ↔ iIndepSets (fun i ↦ {f i}) μ := @@ -533,16 +551,20 @@ theorem indepFun_iff_measure_inter_preimage_eq_mul {mβ : MeasurableSpace β} simp only [IndepFun, Kernel.indepFun_iff_measure_inter_preimage_eq_mul, ae_dirac_eq, Filter.eventually_pure, Kernel.const_apply] +alias ⟨IndepFun.measure_inter_preimage_eq_mul, _⟩ := indepFun_iff_measure_inter_preimage_eq_mul + theorem iIndepFun_iff_measure_inter_preimage_eq_mul {ι : Type*} {β : ι → Type*} - (m : ∀ x, MeasurableSpace (β x)) (f : ∀ i, Ω → β i) : + {m : ∀ x, MeasurableSpace (β x)} {f : ∀ i, Ω → β i} : iIndepFun m f μ ↔ ∀ (S : Finset ι) {sets : ∀ i : ι, Set (β i)} (_H : ∀ i, i ∈ S → MeasurableSet[m i] (sets i)), μ (⋂ i ∈ S, f i ⁻¹' sets i) = ∏ i ∈ S, μ (f i ⁻¹' sets i) := by simp only [iIndepFun, Kernel.iIndepFun_iff_measure_inter_preimage_eq_mul, ae_dirac_eq, Filter.eventually_pure, Kernel.const_apply] +alias ⟨iIndepFun.measure_inter_preimage_eq_mul, _⟩ := iIndepFun_iff_measure_inter_preimage_eq_mul + theorem indepFun_iff_indepSet_preimage {mβ : MeasurableSpace β} {mβ' : MeasurableSpace β'} - [IsProbabilityMeasure μ] (hf : Measurable f) (hg : Measurable g) : + [IsZeroOrProbabilityMeasure μ] (hf : Measurable f) (hg : Measurable g) : IndepFun f g μ ↔ ∀ s t, MeasurableSet s → MeasurableSet t → IndepSet (f ⁻¹' s) (g ⁻¹' t) μ := by simp only [IndepFun, IndepSet, Kernel.indepFun_iff_indepSet_preimage hf hg, ae_dirac_eq, @@ -604,13 +626,11 @@ tuple `(f i)_i` for `i ∈ T`. -/ lemma iIndepFun.indepFun_finset (S T : Finset ι) (hST : Disjoint S T) (hf_Indep : iIndepFun m f μ) (hf_meas : ∀ i, Measurable (f i)) : IndepFun (fun a (i : S) ↦ f i a) (fun a (i : T) ↦ f i a) μ := - have := hf_Indep.isProbabilityMeasure Kernel.iIndepFun.indepFun_finset S T hST hf_Indep hf_meas lemma iIndepFun.indepFun_prod_mk (hf_Indep : iIndepFun m f μ) (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hik : i ≠ k) (hjk : j ≠ k) : IndepFun (fun a => (f i a, f j a)) (f k) μ := - have := hf_Indep.isProbabilityMeasure Kernel.iIndepFun.indepFun_prod_mk hf_Indep hf_meas i j k hik hjk open Finset in @@ -632,14 +652,12 @@ variable {β : Type*} {m : MeasurableSpace β} [Mul β] [MeasurableMul₂ β] {f lemma iIndepFun.indepFun_mul_left (hf_indep : iIndepFun (fun _ ↦ m) f μ) (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hik : i ≠ k) (hjk : j ≠ k) : IndepFun (f i * f j) (f k) μ := - have := hf_indep.isProbabilityMeasure Kernel.iIndepFun.indepFun_mul_left hf_indep hf_meas i j k hik hjk @[to_additive] lemma iIndepFun.indepFun_mul_right (hf_indep : iIndepFun (fun _ ↦ m) f μ) (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hij : i ≠ j) (hik : i ≠ k) : IndepFun (f i) (f j * f k) μ := - have := hf_indep.isProbabilityMeasure Kernel.iIndepFun.indepFun_mul_right hf_indep hf_meas i j k hij hik @[to_additive] @@ -647,7 +665,6 @@ lemma iIndepFun.indepFun_mul_mul (hf_indep : iIndepFun (fun _ ↦ m) f μ) (hf_meas : ∀ i, Measurable (f i)) (i j k l : ι) (hik : i ≠ k) (hil : i ≠ l) (hjk : j ≠ k) (hjl : j ≠ l) : IndepFun (f i * f j) (f k * f l) μ := - have := hf_indep.isProbabilityMeasure Kernel.iIndepFun.indepFun_mul_mul hf_indep hf_meas i j k l hik hil hjk hjl end Mul @@ -659,14 +676,12 @@ variable {β : Type*} {m : MeasurableSpace β} [Div β] [MeasurableDiv₂ β] {f lemma iIndepFun.indepFun_div_left (hf_indep : iIndepFun (fun _ ↦ m) f μ) (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hik : i ≠ k) (hjk : j ≠ k) : IndepFun (f i / f j) (f k) μ := - have := hf_indep.isProbabilityMeasure Kernel.iIndepFun.indepFun_div_left hf_indep hf_meas i j k hik hjk @[to_additive] lemma iIndepFun.indepFun_div_right (hf_indep : iIndepFun (fun _ ↦ m) f μ) (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hij : i ≠ j) (hik : i ≠ k) : IndepFun (f i) (f j / f k) μ := - have := hf_indep.isProbabilityMeasure Kernel.iIndepFun.indepFun_div_right hf_indep hf_meas i j k hij hik @[to_additive] @@ -674,7 +689,6 @@ lemma iIndepFun.indepFun_div_div (hf_indep : iIndepFun (fun _ ↦ m) f μ) (hf_meas : ∀ i, Measurable (f i)) (i j k l : ι) (hik : i ≠ k) (hil : i ≠ l) (hjk : j ≠ k) (hjl : j ≠ l) : IndepFun (f i / f j) (f k / f l) μ := - have := hf_indep.isProbabilityMeasure Kernel.iIndepFun.indepFun_div_div hf_indep hf_meas i j k l hik hil hjk hjl end Div @@ -686,13 +700,11 @@ variable {β : Type*} {m : MeasurableSpace β} [CommMonoid β] [MeasurableMul₂ lemma iIndepFun.indepFun_finset_prod_of_not_mem (hf_Indep : iIndepFun (fun _ ↦ m) f μ) (hf_meas : ∀ i, Measurable (f i)) {s : Finset ι} {i : ι} (hi : i ∉ s) : IndepFun (∏ j ∈ s, f j) (f i) μ := - have := hf_Indep.isProbabilityMeasure Kernel.iIndepFun.indepFun_finset_prod_of_not_mem hf_Indep hf_meas hi @[to_additive] lemma iIndepFun.indepFun_prod_range_succ {f : ℕ → Ω → β} (hf_Indep : iIndepFun (fun _ ↦ m) f μ) (hf_meas : ∀ i, Measurable (f i)) (n : ℕ) : IndepFun (∏ j ∈ Finset.range n, f j) (f n) μ := - have := hf_Indep.isProbabilityMeasure Kernel.iIndepFun.indepFun_prod_range_succ hf_Indep hf_meas n end CommMonoid diff --git a/Mathlib/Probability/Independence/Conditional.lean b/Mathlib/Probability/Independence/Conditional.lean index e7f9c9211e252..6456d37f340cf 100644 --- a/Mathlib/Probability/Independence/Conditional.lean +++ b/Mathlib/Probability/Independence/Conditional.lean @@ -62,9 +62,7 @@ section Definitions section -variable (m' : MeasurableSpace Ω) - {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] [Nonempty Ω] - (hm' : m' ≤ mΩ) +variable (m' : MeasurableSpace Ω) {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] (hm' : m' ≤ mΩ) /-- A family of sets of sets `π : ι → Set (Set Ω)` is conditionally independent given `m'` with respect to a measure `μ` if for any finite set of indices `s = {i_1, ..., i_n}`, for any sets @@ -100,13 +98,13 @@ end `t₁ ∈ m₁, t₂ ∈ m₂`, `μ⟦t₁ ∩ t₂ | m'⟧ =ᵐ[μ] μ⟦t₁ | m'⟧ * μ⟦t₂ | m'⟧`. See `ProbabilityTheory.condIndep_iff`. -/ def CondIndep (m' m₁ m₂ : MeasurableSpace Ω) - {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] [Nonempty Ω] + {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] (hm' : m' ≤ mΩ) (μ : Measure Ω := by volume_tac) [IsFiniteMeasure μ] : Prop := Kernel.Indep m₁ m₂ (condexpKernel μ m') (μ.trim hm') section -variable (m' : MeasurableSpace Ω) {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] [Nonempty Ω] +variable (m' : MeasurableSpace Ω) {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] (hm' : m' ≤ mΩ) /-- A family of sets is conditionally independent if the family of measurable space structures they @@ -148,8 +146,7 @@ end Definitions section DefinitionLemmas section -variable (m' : MeasurableSpace Ω) {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] [Nonempty Ω] - (hm' : m' ≤ mΩ) +variable (m' : MeasurableSpace Ω) {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] (hm' : m' ≤ mΩ) lemma iCondIndepSets_iff (π : ι → Set (Set Ω)) (hπ : ∀ i s (_hs : s ∈ π i), MeasurableSet s) (μ : Measure Ω) [IsFiniteMeasure μ] : @@ -184,7 +181,7 @@ lemma iCondIndepSets_iff (π : ι → Set (Set Ω)) (hπ : ∀ i s (_hs : s ∈ have h_ne_top : condexpKernel μ m' ω (⋂ i ∈ s, f i) ≠ ∞ := (measure_ne_top (condexpKernel μ m' ω) _) have : (∏ i ∈ s, condexpKernel μ m' ω (f i)) ≠ ∞ := - (ENNReal.prod_lt_top (fun _ _ ↦ measure_ne_top (condexpKernel μ m' ω) _)).ne + ENNReal.prod_ne_top fun _ _ ↦ measure_ne_top (condexpKernel μ m' ω) _ rw [← ENNReal.ofReal_toReal h_ne_top, h_inter_eq, h, Finset.prod_apply, ← ENNReal.ofReal_toReal this, ENNReal.toReal_prod] congr 1 @@ -267,13 +264,13 @@ end section CondIndep lemma condIndep_iff_condIndepSets (m' m₁ m₂ : MeasurableSpace Ω) {mΩ : MeasurableSpace Ω} - [StandardBorelSpace Ω] [Nonempty Ω] (hm' : m' ≤ mΩ) (μ : Measure Ω ) [IsFiniteMeasure μ] : + [StandardBorelSpace Ω] (hm' : m' ≤ mΩ) (μ : Measure Ω ) [IsFiniteMeasure μ] : CondIndep m' m₁ m₂ hm' μ ↔ CondIndepSets m' hm' {s | MeasurableSet[m₁] s} {s | MeasurableSet[m₂] s} μ := by simp only [CondIndep, CondIndepSets, Kernel.Indep] lemma condIndep_iff (m' m₁ m₂ : MeasurableSpace Ω) - {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] [Nonempty Ω] + {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] (hm' : m' ≤ mΩ) (hm₁ : m₁ ≤ mΩ) (hm₂ : m₂ ≤ mΩ) (μ : Measure Ω) [IsFiniteMeasure μ] : CondIndep m' m₁ m₂ hm' μ ↔ ∀ t1 t2, MeasurableSet[m₁] t1 → MeasurableSet[m₂] t2 @@ -285,7 +282,7 @@ lemma condIndep_iff (m' m₁ m₂ : MeasurableSpace Ω) end CondIndep -variable (m' : MeasurableSpace Ω) {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] [Nonempty Ω] +variable (m' : MeasurableSpace Ω) {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] (hm' : m' ≤ mΩ) lemma iCondIndepSet_iff_iCondIndep (s : ι → Set Ω) (μ : Measure Ω) [IsFiniteMeasure μ] : @@ -352,7 +349,7 @@ end DefinitionLemmas section CondIndepSets -variable {m' : MeasurableSpace Ω} {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] [Nonempty Ω] +variable {m' : MeasurableSpace Ω} {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] {hm' : m' ≤ mΩ} {μ : Measure Ω} [IsFiniteMeasure μ] @[symm] @@ -410,7 +407,7 @@ end CondIndepSets section CondIndepSet -variable {m' : MeasurableSpace Ω} {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] [Nonempty Ω] +variable {m' : MeasurableSpace Ω} {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] {hm' : m' ≤ mΩ} {μ : Measure Ω} [IsFiniteMeasure μ] theorem condIndepSet_empty_right (s : Set Ω) : CondIndepSet m' hm' s ∅ μ := @@ -425,32 +422,32 @@ section CondIndep @[symm] theorem CondIndep.symm {m' m₁ m₂ : MeasurableSpace Ω} {mΩ : MeasurableSpace Ω} - [StandardBorelSpace Ω] [Nonempty Ω] {hm' : m' ≤ mΩ} {μ : Measure Ω} [IsFiniteMeasure μ] + [StandardBorelSpace Ω] {hm' : m' ≤ mΩ} {μ : Measure Ω} [IsFiniteMeasure μ] (h : CondIndep m' m₁ m₂ hm' μ) : CondIndep m' m₂ m₁ hm' μ := CondIndepSets.symm h theorem condIndep_bot_right (m₁ : MeasurableSpace Ω) {m' : MeasurableSpace Ω} - {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] [Nonempty Ω] + {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] {hm' : m' ≤ mΩ} {μ : Measure Ω} [IsFiniteMeasure μ] : CondIndep m' m₁ ⊥ hm' μ := Kernel.indep_bot_right m₁ theorem condIndep_bot_left (m₁ : MeasurableSpace Ω) {m' : MeasurableSpace Ω} - {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] [Nonempty Ω] + {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] {hm' : m' ≤ mΩ} {μ : Measure Ω} [IsFiniteMeasure μ] : CondIndep m' ⊥ m₁ hm' μ := (Kernel.indep_bot_right m₁).symm theorem condIndep_of_condIndep_of_le_left {m' m₁ m₂ m₃ : MeasurableSpace Ω} - {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] [Nonempty Ω] + {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] {hm' : m' ≤ mΩ} {μ : Measure Ω} [IsFiniteMeasure μ] (h_indep : CondIndep m' m₁ m₂ hm' μ) (h31 : m₃ ≤ m₁) : CondIndep m' m₃ m₂ hm' μ := Kernel.indep_of_indep_of_le_left h_indep h31 theorem condIndep_of_condIndep_of_le_right {m' m₁ m₂ m₃ : MeasurableSpace Ω} - {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] [Nonempty Ω] + {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] {hm' : m' ≤ mΩ} {μ : Measure Ω} [IsFiniteMeasure μ] (h_indep : CondIndep m' m₁ m₂ hm' μ) (h32 : m₃ ≤ m₂) : CondIndep m' m₁ m₃ hm' μ := @@ -464,7 +461,7 @@ end CondIndep section FromiCondIndepToCondIndep variable {m' : MeasurableSpace Ω} - {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] [Nonempty Ω] + {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] {hm' : m' ≤ mΩ} {μ : Measure Ω} [IsFiniteMeasure μ] theorem iCondIndepSets.condIndepSets {s : ι → Set (Set Ω)} @@ -499,7 +496,7 @@ section FromMeasurableSpacesToSetsOfSets generating π-systems -/ variable {m' : MeasurableSpace Ω} - {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] [Nonempty Ω] + {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] {hm' : m' ≤ mΩ} {μ : Measure Ω} [IsFiniteMeasure μ] theorem iCondIndep.iCondIndepSets {m : ι → MeasurableSpace Ω} @@ -520,7 +517,7 @@ section FromPiSystemsToMeasurableSpaces /-! ### Conditional independence of generating π-systems implies conditional independence of σ-algebras -/ -variable {m' m₁ m₂ : MeasurableSpace Ω} {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] [Nonempty Ω] +variable {m' m₁ m₂ : MeasurableSpace Ω} {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] {hm' : m' ≤ mΩ} {μ : Measure Ω} [IsFiniteMeasure μ] theorem CondIndepSets.condIndep @@ -608,7 +605,7 @@ section CondIndepSet -/ -variable {m' m₁ m₂ : MeasurableSpace Ω} {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] [Nonempty Ω] +variable {m' m₁ m₂ : MeasurableSpace Ω} {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] {hm' : m' ≤ mΩ} {s t : Set Ω} (S T : Set (Set Ω)) @@ -638,7 +635,7 @@ section CondIndepFun -/ variable {β β' : Type*} {m' : MeasurableSpace Ω} - {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] [Nonempty Ω] + {mΩ : MeasurableSpace Ω} [StandardBorelSpace Ω] {hm' : m' ≤ mΩ} {μ : Measure Ω} [IsFiniteMeasure μ] {f : Ω → β} {g : Ω → β'} @@ -737,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 μ) @@ -761,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 μ) @@ -785,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 8e6e7abb69925..146667d5bfbdb 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 @@ -118,13 +119,98 @@ section ByDefinition variable {β : ι → Type*} {mβ : ∀ i, MeasurableSpace (β i)} {_mα : MeasurableSpace α} {m : ι → MeasurableSpace Ω} {_mΩ : MeasurableSpace Ω} - {κ : Kernel α Ω} {μ : Measure α} + {κ η : Kernel α Ω} {μ : Measure α} {π : ι → Set (Set Ω)} {s : ι → Set Ω} {S : Finset ι} {f : ∀ x : ι, Ω → β x} + {s1 s2 : Set (Set Ω)} + +@[simp] lemma iIndepSets_zero_right : iIndepSets π κ 0 := by simp [iIndepSets] + +@[simp] lemma indepSets_zero_right : IndepSets s1 s2 κ 0 := by simp [IndepSets] + +@[simp] lemma indepSets_zero_left : IndepSets s1 s2 (0 : Kernel α Ω) μ := by simp [IndepSets] + +@[simp] lemma iIndep_zero_right : iIndep m κ 0 := by simp [iIndep] + +@[simp] lemma indep_zero_right {m₁ m₂ : MeasurableSpace Ω} {_mΩ : MeasurableSpace Ω} + {κ : Kernel α Ω} : Indep m₁ m₂ κ 0 := by simp [Indep] + +@[simp] lemma indep_zero_left {m₁ m₂ : MeasurableSpace Ω} {_mΩ : MeasurableSpace Ω} : + Indep m₁ m₂ (0 : Kernel α Ω) μ := by simp [Indep] + +@[simp] lemma iIndepSet_zero_right : iIndepSet s κ 0 := by simp [iIndepSet] + +@[simp] lemma indepSet_zero_right {s t : Set Ω} : IndepSet s t κ 0 := by simp [IndepSet] + +@[simp] lemma indepSet_zero_left {s t : Set Ω} : IndepSet s t (0 : Kernel α Ω) μ := by + simp [IndepSet] + +@[simp] lemma iIndepFun_zero_right {β : ι → Type*} {m : ∀ x : ι, MeasurableSpace (β x)} + {f : ∀ x : ι, Ω → β x} : iIndepFun m f κ 0 := by simp [iIndepFun] + +@[simp] lemma indepFun_zero_right {β γ} [MeasurableSpace β] [MeasurableSpace γ] + {f : Ω → β} {g : Ω → γ} : IndepFun f g κ 0 := by simp [IndepFun] + +@[simp] lemma indepFun_zero_left {β γ} [MeasurableSpace β] [MeasurableSpace γ] + {f : Ω → β} {g : Ω → γ} : IndepFun f g (0 : Kernel α Ω) μ := by simp [IndepFun] + +lemma iIndepSets_congr (h : κ =ᵐ[μ] η) : iIndepSets π κ μ ↔ iIndepSets π η μ := by + peel 3 + refine ⟨fun h' ↦ ?_, fun h' ↦ ?_⟩ <;> + · filter_upwards [h, h'] with a ha h'a + simpa [ha] using h'a + +alias ⟨iIndepSets.congr, _⟩ := iIndepSets_congr + +lemma indepSets_congr (h : κ =ᵐ[μ] η) : IndepSets s1 s2 κ μ ↔ IndepSets s1 s2 η μ := by + peel 4 + refine ⟨fun h' ↦ ?_, fun h' ↦ ?_⟩ <;> + · filter_upwards [h, h'] with a ha h'a + simpa [ha] using h'a + +alias ⟨IndepSets.congr, _⟩ := indepSets_congr + +lemma iIndep_congr (h : κ =ᵐ[μ] η) : iIndep m κ μ ↔ iIndep m η μ := + iIndepSets_congr h + +alias ⟨iIndep.congr, _⟩ := iIndep_congr + +lemma indep_congr {m₁ m₂ : MeasurableSpace Ω} {_mΩ : MeasurableSpace Ω} + {κ η : Kernel α Ω} (h : κ =ᵐ[μ] η) : Indep m₁ m₂ κ μ ↔ Indep m₁ m₂ η μ := + indepSets_congr h + +alias ⟨Indep.congr, _⟩ := indep_congr + +lemma iIndepSet_congr (h : κ =ᵐ[μ] η) : iIndepSet s κ μ ↔ iIndepSet s η μ := + iIndep_congr h + +alias ⟨iIndepSet.congr, _⟩ := iIndepSet_congr + +lemma indepSet_congr {s t : Set Ω} (h : κ =ᵐ[μ] η) : IndepSet s t κ μ ↔ IndepSet s t η μ := + indep_congr h + +alias ⟨indepSet.congr, _⟩ := indepSet_congr + +lemma iIndepFun_congr {β : ι → Type*} {m : ∀ x : ι, MeasurableSpace (β x)} + {f : ∀ x : ι, Ω → β x} (h : κ =ᵐ[μ] η) : iIndepFun m f κ μ ↔ iIndepFun m f η μ := + iIndep_congr h + +alias ⟨iIndepFun.congr, _⟩ := iIndepFun_congr + +lemma indepFun_congr {β γ} [MeasurableSpace β] [MeasurableSpace γ] + {f : Ω → β} {g : Ω → γ} (h : κ =ᵐ[μ] η) : IndepFun f g κ μ ↔ IndepFun f g η μ := + indep_congr h + +alias ⟨IndepFun.congr, _⟩ := indepFun_congr lemma iIndepSets.meas_biInter (h : iIndepSets π κ μ) (s : Finset ι) {f : ι → Set Ω} (hf : ∀ i, i ∈ s → f i ∈ π i) : ∀ᵐ a ∂μ, κ a (⋂ i ∈ s, f i) = ∏ i ∈ s, κ a (f i) := h s hf +lemma iIndepSets.ae_isProbabilityMeasure (h : iIndepSets π κ μ) : + ∀ᵐ a ∂μ, IsProbabilityMeasure (κ a) := by + filter_upwards [h.meas_biInter ∅ (f := fun _ ↦ Set.univ) (by simp)] with a ha + exact ⟨by simpa using ha⟩ + lemma iIndepSets.meas_iInter [Fintype ι] (h : iIndepSets π κ μ) (hs : ∀ i, s i ∈ π i) : ∀ᵐ a ∂μ, κ a (⋂ i, s i) = ∏ i, κ a (s i) := by filter_upwards [h.meas_biInter Finset.univ (fun _i _ ↦ hs _)] with a ha using by simp [← ha] @@ -132,6 +218,10 @@ lemma iIndepSets.meas_iInter [Fintype ι] (h : iIndepSets π κ μ) (hs : ∀ i, lemma iIndep.iIndepSets' (hμ : iIndep m κ μ) : iIndepSets (fun x ↦ {s | MeasurableSet[m x] s}) κ μ := hμ +lemma iIndep.ae_isProbabilityMeasure (h : iIndep m κ μ) : + ∀ᵐ a ∂μ, IsProbabilityMeasure (κ a) := + h.iIndepSets'.ae_isProbabilityMeasure + lemma iIndep.meas_biInter (hμ : iIndep m κ μ) (hs : ∀ i, i ∈ S → MeasurableSet[m i] (s i)) : ∀ᵐ a ∂μ, κ a (⋂ i ∈ S, s i) = ∏ i ∈ S, κ a (s i) := hμ _ hs @@ -143,6 +233,10 @@ lemma iIndep.meas_iInter [Fintype ι] (h : iIndep m κ μ) (hs : ∀ i, Measurab protected lemma iIndepFun.iIndep (hf : iIndepFun mβ f κ μ) : iIndep (fun x ↦ (mβ x).comap (f x)) κ μ := hf +lemma iIndepFun.ae_isProbabilityMeasure (h : iIndepFun mβ f κ μ) : + ∀ᵐ a ∂μ, IsProbabilityMeasure (κ a) := + h.iIndep.ae_isProbabilityMeasure + lemma iIndepFun.meas_biInter (hf : iIndepFun mβ f κ μ) (hs : ∀ i, i ∈ S → MeasurableSet[(mβ i).comap (f i)] (s i)) : ∀ᵐ a ∂μ, κ a (⋂ i ∈ S, s i) = ∏ i ∈ S, κ a (s i) := hf.iIndep.meas_biInter hs @@ -177,27 +271,29 @@ theorem Indep.symm {m₁ m₂ : MeasurableSpace Ω} {_mΩ : MeasurableSpace Ω} IndepSets.symm h theorem indep_bot_right (m' : MeasurableSpace Ω) {_mΩ : MeasurableSpace Ω} - {κ : Kernel α Ω} {μ : Measure α} [IsMarkovKernel κ] : + {κ : Kernel α Ω} {μ : Measure α} [IsZeroOrMarkovKernel κ] : Indep m' ⊥ κ μ := by intros s t _ ht rw [Set.mem_setOf_eq, MeasurableSpace.measurableSet_bot_iff] at ht - refine Filter.eventually_of_forall (fun a ↦ ?_) + rcases eq_zero_or_isMarkovKernel κ with rfl| h + · simp + refine Filter.Eventually.of_forall (fun a ↦ ?_) cases' ht with ht ht · rw [ht, Set.inter_empty, measure_empty, mul_zero] · rw [ht, Set.inter_univ, measure_univ, mul_one] theorem indep_bot_left (m' : MeasurableSpace Ω) {_mΩ : MeasurableSpace Ω} - {κ : Kernel α Ω} {μ : Measure α} [IsMarkovKernel κ] : + {κ : Kernel α Ω} {μ : Measure α} [IsZeroOrMarkovKernel κ] : Indep ⊥ m' κ μ := (indep_bot_right m').symm theorem indepSet_empty_right {_mΩ : MeasurableSpace Ω} - {κ : Kernel α Ω} {μ : Measure α} [IsMarkovKernel κ] (s : Set Ω) : + {κ : Kernel α Ω} {μ : Measure α} [IsZeroOrMarkovKernel κ] (s : Set Ω) : IndepSet s ∅ κ μ := by simp only [IndepSet, generateFrom_singleton_empty] exact indep_bot_right _ theorem indepSet_empty_left {_mΩ : MeasurableSpace Ω} {κ : Kernel α Ω} - {μ : Measure α} [IsMarkovKernel κ] (s : Set Ω) : + {μ : Measure α} [IsZeroOrMarkovKernel κ] (s : Set Ω) : IndepSet ∅ s κ μ := (indepSet_empty_right s).symm @@ -376,10 +472,12 @@ section FromPiSystemsToMeasurableSpaces variable {_mα : MeasurableSpace α} theorem IndepSets.indep_aux {m₂ m : MeasurableSpace Ω} - {κ : Kernel α Ω} {μ : Measure α} [IsMarkovKernel κ] {p1 p2 : Set (Set Ω)} (h2 : m₂ ≤ m) + {κ : Kernel α Ω} {μ : Measure α} [IsZeroOrMarkovKernel κ] {p1 p2 : Set (Set Ω)} (h2 : m₂ ≤ m) (hp2 : IsPiSystem p2) (hpm2 : m₂ = generateFrom p2) (hyp : IndepSets p1 p2 κ μ) {t1 t2 : Set Ω} (ht1 : t1 ∈ p1) (ht1m : MeasurableSet[m] t1) (ht2m : MeasurableSet[m₂] t2) : ∀ᵐ a ∂μ, κ a (t1 ∩ t2) = κ a t1 * κ a t2 := by + rcases eq_zero_or_isMarkovKernel κ with rfl | h + · simp refine @induction_on_inter _ (fun t ↦ ∀ᵐ a ∂μ, κ a (t1 ∩ t) = κ a t1 * κ a t) _ m₂ hpm2 hp2 ?_ ?_ ?_ ?_ t2 ht2m · simp only [Set.inter_empty, measure_empty, mul_zero, eq_self_iff_true, @@ -390,7 +488,8 @@ theorem IndepSets.indep_aux {m₂ m : MeasurableSpace Ω} have : t1 ∩ tᶜ = t1 \ (t1 ∩ t) := by rw [Set.diff_self_inter, Set.diff_eq_compl_inter, Set.inter_comm] rw [this, - measure_diff Set.inter_subset_left (ht1m.inter (h2 _ ht)) (measure_ne_top (κ a) _), + measure_diff Set.inter_subset_left (ht1m.inter (h2 _ ht)).nullMeasurableSet + (measure_ne_top (κ a) _), measure_compl (h2 _ ht) (measure_ne_top (κ a) t), measure_univ, ENNReal.mul_sub (fun _ _ ↦ measure_ne_top (κ a) _), mul_one, ha] · intros f hf_disj hf_meas h @@ -408,10 +507,12 @@ theorem IndepSets.indep_aux {m₂ m : MeasurableSpace Ω} /-- The measurable space structures generated by independent pi-systems are independent. -/ theorem IndepSets.indep {m1 m2 m : MeasurableSpace Ω} {κ : Kernel α Ω} {μ : Measure α} - [IsMarkovKernel κ] {p1 p2 : Set (Set Ω)} (h1 : m1 ≤ m) (h2 : m2 ≤ m) (hp1 : IsPiSystem p1) + [IsZeroOrMarkovKernel κ] {p1 p2 : Set (Set Ω)} (h1 : m1 ≤ m) (h2 : m2 ≤ m) (hp1 : IsPiSystem p1) (hp2 : IsPiSystem p2) (hpm1 : m1 = generateFrom p1) (hpm2 : m2 = generateFrom p2) (hyp : IndepSets p1 p2 κ μ) : Indep m1 m2 κ μ := by + rcases eq_zero_or_isMarkovKernel κ with rfl | h + · simp intros t1 t2 ht1 ht2 refine @induction_on_inter _ (fun t ↦ ∀ᵐ (a : α) ∂μ, κ a (t ∩ t2) = κ a t * κ a t2) _ m1 hpm1 hp1 ?_ ?_ ?_ ?_ _ ht1 @@ -428,7 +529,7 @@ theorem IndepSets.indep {m1 m2 m : MeasurableSpace Ω} {κ : Kernel α Ω} {μ : have : tᶜ ∩ t2 = t2 \ (t ∩ t2) := by rw [Set.inter_comm t, Set.diff_self_inter, Set.diff_eq_compl_inter] rw [this, Set.inter_comm t t2, - measure_diff Set.inter_subset_left ((h2 _ ht2).inter (h1 _ ht)) + measure_diff Set.inter_subset_left ((h2 _ ht2).inter (h1 _ ht)).nullMeasurableSet (measure_ne_top (κ a) _), Set.inter_comm, ha, measure_compl (h1 _ ht) (measure_ne_top (κ a) t), measure_univ, mul_comm (1 - κ a t), ENNReal.mul_sub (fun _ _ ↦ measure_ne_top (κ a) _), mul_one, mul_comm] @@ -446,7 +547,7 @@ theorem IndepSets.indep {m1 m2 m : MeasurableSpace Ω} {κ : Kernel α Ω} {μ : · exact fun i ↦ (h2 _ ht2).inter (h1 _ (hf_meas i)) theorem IndepSets.indep' {_mΩ : MeasurableSpace Ω} - {κ : Kernel α Ω} {μ : Measure α} [IsMarkovKernel κ] + {κ : Kernel α Ω} {μ : Measure α} [IsZeroOrMarkovKernel κ] {p1 p2 : Set (Set Ω)} (hp1m : ∀ s ∈ p1, MeasurableSet s) (hp2m : ∀ s ∈ p2, MeasurableSet s) (hp1 : IsPiSystem p1) (hp2 : IsPiSystem p2) (hyp : IndepSets p1 p2 κ μ) : Indep (generateFrom p1) (generateFrom p2) κ μ := @@ -454,7 +555,7 @@ theorem IndepSets.indep' {_mΩ : MeasurableSpace Ω} variable {_mΩ : MeasurableSpace Ω} {κ : Kernel α Ω} {μ : Measure α} -theorem indepSets_piiUnionInter_of_disjoint [IsMarkovKernel κ] {s : ι → Set (Set Ω)} +theorem indepSets_piiUnionInter_of_disjoint {s : ι → Set (Set Ω)} {S T : Set ι} (h_indep : iIndepSets s κ μ) (hST : Disjoint S T) : IndepSets (piiUnionInter s S) (piiUnionInter s T) κ μ := by rintro t1 t2 ⟨p1, hp1, f1, ht1_m, ht1_eq⟩ ⟨p2, hp2, f2, ht2_m, ht2_eq⟩ @@ -481,7 +582,8 @@ theorem indepSets_piiUnionInter_of_disjoint [IsMarkovKernel κ] {s : ι → Set ⟨fun i hi => (h i (Or.inl hi)).1 hi, fun i hi => (h i (Or.inr hi)).2 hi⟩⟩ filter_upwards [h_indep _ hgm] with a ha rw [ht1_eq, ht2_eq, h_p1_inter_p2, ← ha] - filter_upwards [h_P_inter, h_indep p1 ht1_m, h_indep p2 ht2_m] with a h_P_inter ha1 ha2 + filter_upwards [h_P_inter, h_indep p1 ht1_m, h_indep p2 ht2_m, h_indep.ae_isProbabilityMeasure] + with a h_P_inter ha1 ha2 h' have h_μg : ∀ n, κ a (g n) = (ite (n ∈ p1) (κ a (f1 n)) 1) * (ite (n ∈ p2) (κ a (f2 n)) 1) := by intro n dsimp only [g] @@ -493,9 +595,15 @@ theorem indepSets_piiUnionInter_of_disjoint [IsMarkovKernel κ] {s : ι → Set Finset.prod_ite_mem (p1 ∪ p2) p2 (fun x => κ a (f2 x)), Finset.union_inter_cancel_right, ht1_eq, ← ha1, ht2_eq, ← ha2] -theorem iIndepSet.indep_generateFrom_of_disjoint [IsMarkovKernel κ] {s : ι → Set Ω} +theorem iIndepSet.indep_generateFrom_of_disjoint {s : ι → Set Ω} (hsm : ∀ n, MeasurableSet (s n)) (hs : iIndepSet s κ μ) (S T : Set ι) (hST : Disjoint S T) : Indep (generateFrom { t | ∃ n ∈ S, s n = t }) (generateFrom { t | ∃ k ∈ T, s k = t }) κ μ := by + classical + rcases eq_or_ne μ 0 with rfl | hμ + · simp + obtain ⟨η, η_eq, hη⟩ : ∃ (η : Kernel α Ω), κ =ᵐ[μ] η ∧ IsMarkovKernel η := + exists_ae_eq_isMarkovKernel hs.ae_isProbabilityMeasure hμ + apply Indep.congr (Filter.EventuallyEq.symm η_eq) rw [← generateFrom_piiUnionInter_singleton_left, ← generateFrom_piiUnionInter_singleton_left] refine IndepSets.indep' @@ -505,21 +613,27 @@ theorem iIndepSet.indep_generateFrom_of_disjoint [IsMarkovKernel κ] {s : ι → · exact fun k => generateFrom_le fun t ht => (Set.mem_singleton_iff.1 ht).symm ▸ hsm k · exact isPiSystem_piiUnionInter _ (fun k => IsPiSystem.singleton _) _ · exact isPiSystem_piiUnionInter _ (fun k => IsPiSystem.singleton _) _ - · classical exact indepSets_piiUnionInter_of_disjoint (iIndep.iIndepSets (fun n => rfl) hs) hST + · exact indepSets_piiUnionInter_of_disjoint (iIndep.iIndepSets (fun n => rfl) (hs.congr η_eq)) hST -theorem indep_iSup_of_disjoint [IsMarkovKernel κ] {m : ι → MeasurableSpace Ω} +theorem indep_iSup_of_disjoint {m : ι → MeasurableSpace Ω} (h_le : ∀ i, m i ≤ _mΩ) (h_indep : iIndep m κ μ) {S T : Set ι} (hST : Disjoint S T) : Indep (⨆ i ∈ S, m i) (⨆ i ∈ T, m i) κ μ := by + classical + rcases eq_or_ne μ 0 with rfl | hμ + · simp + obtain ⟨η, η_eq, hη⟩ : ∃ (η : Kernel α Ω), κ =ᵐ[μ] η ∧ IsMarkovKernel η := + exists_ae_eq_isMarkovKernel h_indep.ae_isProbabilityMeasure hμ + apply Indep.congr (Filter.EventuallyEq.symm η_eq) refine IndepSets.indep (iSup₂_le fun i _ => h_le i) (iSup₂_le fun i _ => h_le i) ?_ ?_ (generateFrom_piiUnionInter_measurableSet m S).symm (generateFrom_piiUnionInter_measurableSet m T).symm ?_ · exact isPiSystem_piiUnionInter _ (fun n => @isPiSystem_measurableSet Ω (m n)) _ · exact isPiSystem_piiUnionInter _ (fun n => @isPiSystem_measurableSet Ω (m n)) _ - · classical exact indepSets_piiUnionInter_of_disjoint h_indep hST + · exact indepSets_piiUnionInter_of_disjoint (h_indep.congr η_eq) hST theorem indep_iSup_of_directed_le {Ω} {m : ι → MeasurableSpace Ω} {m' m0 : MeasurableSpace Ω} - {κ : Kernel α Ω} {μ : Measure α} [IsMarkovKernel κ] (h_indep : ∀ i, Indep (m i) m' κ μ) + {κ : Kernel α Ω} {μ : Measure α} [IsZeroOrMarkovKernel κ] (h_indep : ∀ i, Indep (m i) m' κ μ) (h_le : ∀ i, m i ≤ m0) (h_le' : m' ≤ m0) (hm : Directed (· ≤ ·) m) : Indep (⨆ i, m i) m' κ μ := by let p : ι → Set (Set Ω) := fun n => { t | MeasurableSet[m n] t } @@ -541,34 +655,34 @@ theorem indep_iSup_of_directed_le {Ω} {m : ι → MeasurableSpace Ω} {m' m0 : refine IndepSets.indep (iSup_le h_le) h_le' hp_supr_pi hp'_pi ?_ h_gen' h_pi_system_indep exact (generateFrom_iUnion_measurableSet _).symm -theorem iIndepSet.indep_generateFrom_lt [Preorder ι] [IsMarkovKernel κ] {s : ι → Set Ω} +theorem iIndepSet.indep_generateFrom_lt [Preorder ι] {s : ι → Set Ω} (hsm : ∀ n, MeasurableSet (s n)) (hs : iIndepSet s κ μ) (i : ι) : Indep (generateFrom {s i}) (generateFrom { t | ∃ j < i, s j = t }) κ μ := by convert iIndepSet.indep_generateFrom_of_disjoint hsm hs {i} { j | j < i } - (Set.disjoint_singleton_left.mpr (lt_irrefl _)) + (Set.disjoint_singleton_left.mpr (lt_irrefl _)) using 1 simp only [Set.mem_singleton_iff, exists_prop, exists_eq_left, Set.setOf_eq_eq_singleton'] -theorem iIndepSet.indep_generateFrom_le [LinearOrder ι] [IsMarkovKernel κ] {s : ι → Set Ω} +theorem iIndepSet.indep_generateFrom_le [LinearOrder ι] {s : ι → Set Ω} (hsm : ∀ n, MeasurableSet (s n)) (hs : iIndepSet s κ μ) (i : ι) {k : ι} (hk : i < k) : Indep (generateFrom {s k}) (generateFrom { t | ∃ j ≤ i, s j = t }) κ μ := by convert iIndepSet.indep_generateFrom_of_disjoint hsm hs {k} { j | j ≤ i } - (Set.disjoint_singleton_left.mpr hk.not_le) + (Set.disjoint_singleton_left.mpr hk.not_le) using 1 simp only [Set.mem_singleton_iff, exists_prop, exists_eq_left, Set.setOf_eq_eq_singleton'] -theorem iIndepSet.indep_generateFrom_le_nat [IsMarkovKernel κ] {s : ℕ → Set Ω} +theorem iIndepSet.indep_generateFrom_le_nat {s : ℕ → Set Ω} (hsm : ∀ n, MeasurableSet (s n)) (hs : iIndepSet s κ μ) (n : ℕ) : Indep (generateFrom {s (n + 1)}) (generateFrom { t | ∃ k ≤ n, s k = t }) κ μ := iIndepSet.indep_generateFrom_le hsm hs _ n.lt_succ_self theorem indep_iSup_of_monotone [SemilatticeSup ι] {Ω} {m : ι → MeasurableSpace Ω} - {m' m0 : MeasurableSpace Ω} {κ : Kernel α Ω} {μ : Measure α} [IsMarkovKernel κ] + {m' m0 : MeasurableSpace Ω} {κ : Kernel α Ω} {μ : Measure α} [IsZeroOrMarkovKernel κ] (h_indep : ∀ i, Indep (m i) m' κ μ) (h_le : ∀ i, m i ≤ m0) (h_le' : m' ≤ m0) (hm : Monotone m) : Indep (⨆ i, m i) m' κ μ := indep_iSup_of_directed_le h_indep h_le h_le' (Monotone.directed_le hm) theorem indep_iSup_of_antitone [SemilatticeInf ι] {Ω} {m : ι → MeasurableSpace Ω} - {m' m0 : MeasurableSpace Ω} {κ : Kernel α Ω} {μ : Measure α} [IsMarkovKernel κ] + {m' m0 : MeasurableSpace Ω} {κ : Kernel α Ω} {μ : Measure α} [IsZeroOrMarkovKernel κ] (h_indep : ∀ i, Indep (m i) m' κ μ) (h_le : ∀ i, m i ≤ m0) (h_le' : m' ≤ m0) (hm : Antitone m) : Indep (⨆ i, m i) m' κ μ := @@ -612,11 +726,16 @@ theorem iIndepSets.piiUnionInter_of_not_mem {π : ι → Set (Set Ω)} {a : ι} rw [ha2, Finset.prod_insert has, h_t2, mul_comm, ha1] /-- The measurable space structures generated by independent pi-systems are independent. -/ -theorem iIndepSets.iIndep [IsMarkovKernel κ] (m : ι → MeasurableSpace Ω) +theorem iIndepSets.iIndep (m : ι → MeasurableSpace Ω) (h_le : ∀ i, m i ≤ _mΩ) (π : ι → Set (Set Ω)) (h_pi : ∀ n, IsPiSystem (π n)) (h_generate : ∀ i, m i = generateFrom (π i)) (h_ind : iIndepSets π κ μ) : iIndep m κ μ := by classical + rcases eq_or_ne μ 0 with rfl | hμ + · simp + obtain ⟨η, η_eq, hη⟩ : ∃ (η : Kernel α Ω), κ =ᵐ[μ] η ∧ IsMarkovKernel η := + exists_ae_eq_isMarkovKernel h_ind.ae_isProbabilityMeasure hμ + apply iIndep.congr (Filter.EventuallyEq.symm η_eq) intro s f refine Finset.induction ?_ ?_ s · simp only [Finset.not_mem_empty, Set.mem_setOf_eq, IsEmpty.forall_iff, implies_true, @@ -626,12 +745,12 @@ theorem iIndepSets.iIndep [IsMarkovKernel κ] (m : ι → MeasurableSpace Ω) have hf_m_S : ∀ x ∈ S, MeasurableSet[m x] (f x) := fun x hx => hf_m x (by simp [hx]) let p := piiUnionInter π S set m_p := generateFrom p with hS_eq_generate - have h_indep : Indep m_p (m a) κ μ := by + have h_indep : Indep m_p (m a) η μ := by have hp : IsPiSystem p := isPiSystem_piiUnionInter π h_pi S have h_le' : ∀ i, generateFrom (π i) ≤ _mΩ := fun i ↦ (h_generate i).symm.trans_le (h_le i) have hm_p : m_p ≤ _mΩ := generateFrom_piiUnionInter_le π h_le' S exact IndepSets.indep hm_p (h_le a) hp (h_pi a) hS_eq_generate (h_generate a) - (iIndepSets.piiUnionInter_of_not_mem h_ind ha_notin_S) + (iIndepSets.piiUnionInter_of_not_mem (h_ind.congr η_eq) ha_notin_S) have h := h_indep.symm (f a) (⋂ n ∈ S, f n) (hf_m a (Finset.mem_insert_self a S)) ?_ · filter_upwards [h_rec hf_m_S, h] with a' ha' h' rwa [Finset.set_biInter_insert, Finset.prod_insert ha_notin_S, ← ha'] @@ -657,22 +776,25 @@ We prove the following equivalences on `IndepSet`, for measurable sets `s, t`. variable {_mα : MeasurableSpace α} theorem iIndepSet_iff_iIndepSets_singleton {_mΩ : MeasurableSpace Ω} {κ : Kernel α Ω} - [IsMarkovKernel κ] {μ : Measure α} {f : ι → Set Ω} - (hf : ∀ i, MeasurableSet (f i)) : + {μ : Measure α} {f : ι → Set Ω} (hf : ∀ i, MeasurableSet (f i)) : iIndepSet f κ μ ↔ iIndepSets (fun i ↦ {f i}) κ μ := ⟨iIndep.iIndepSets fun _ ↦ rfl, iIndepSets.iIndep _ (fun i ↦ generateFrom_le <| by rintro t (rfl : t = _); exact hf _) _ (fun _ ↦ IsPiSystem.singleton _) fun _ ↦ rfl⟩ +theorem iIndepSet.meas_biInter {_mΩ : MeasurableSpace Ω} {κ : Kernel α Ω} + {μ : Measure α} {f : ι → Set Ω} (h : iIndepSet f κ μ) (s : Finset ι) : + ∀ᵐ a ∂μ, κ a (⋂ i ∈ s, f i) = ∏ i ∈ s, κ a (f i) := + iIndep.iIndepSets (fun _ ↦ rfl) h _ (by simp) + theorem iIndepSet_iff_meas_biInter {_mΩ : MeasurableSpace Ω} {κ : Kernel α Ω} - [IsMarkovKernel κ] {μ : Measure α} {f : ι → Set Ω} (hf : ∀ i, MeasurableSet (f i)) : + {μ : Measure α} {f : ι → Set Ω} (hf : ∀ i, MeasurableSet (f i)) : iIndepSet f κ μ ↔ ∀ s, ∀ᵐ a ∂μ, κ a (⋂ i ∈ s, f i) = ∏ i ∈ s, κ a (f i) := (iIndepSet_iff_iIndepSets_singleton hf).trans iIndepSets_singleton_iff theorem iIndepSets.iIndepSet_of_mem {_mΩ : MeasurableSpace Ω} {κ : Kernel α Ω} - [IsMarkovKernel κ] {μ : Measure α} {π : ι → Set (Set Ω)} {f : ι → Set Ω} - (hfπ : ∀ i, f i ∈ π i) (hf : ∀ i, MeasurableSet (f i)) - (hπ : iIndepSets π κ μ) : + {μ : Measure α} {π : ι → Set (Set Ω)} {f : ι → Set Ω} + (hfπ : ∀ i, f i ∈ π i) (hf : ∀ i, MeasurableSet (f i)) (hπ : iIndepSets π κ μ) : iIndepSet f κ μ := (iIndepSet_iff_meas_biInter hf).2 fun _t ↦ hπ.meas_biInter _ fun _i _ ↦ hfπ _ @@ -680,7 +802,7 @@ variable {s t : Set Ω} (S T : Set (Set Ω)) theorem indepSet_iff_indepSets_singleton {m0 : MeasurableSpace Ω} (hs_meas : MeasurableSet s) (ht_meas : MeasurableSet t) (κ : Kernel α Ω) (μ : Measure α) - [IsMarkovKernel κ] : + [IsZeroOrMarkovKernel κ] : IndepSet s t κ μ ↔ IndepSets {s} {t} κ μ := ⟨Indep.indepSets, fun h => IndepSets.indep @@ -690,13 +812,17 @@ theorem indepSet_iff_indepSets_singleton {m0 : MeasurableSpace Ω} (hs_meas : Me theorem indepSet_iff_measure_inter_eq_mul {_m0 : MeasurableSpace Ω} (hs_meas : MeasurableSet s) (ht_meas : MeasurableSet t) (κ : Kernel α Ω) (μ : Measure α) - [IsMarkovKernel κ] : + [IsZeroOrMarkovKernel κ] : IndepSet s t κ μ ↔ ∀ᵐ a ∂μ, κ a (s ∩ t) = κ a s * κ a t := (indepSet_iff_indepSets_singleton hs_meas ht_meas κ μ).trans indepSets_singleton_iff +theorem IndepSet.measure_inter_eq_mul {_m0 : MeasurableSpace Ω} (κ : Kernel α Ω) (μ : Measure α) + (h : IndepSet s t κ μ) : ∀ᵐ a ∂μ, κ a (s ∩ t) = κ a s * κ a t := + Indep.indepSets h _ _ (by simp) (by simp) + theorem IndepSets.indepSet_of_mem {_m0 : MeasurableSpace Ω} (hs : s ∈ S) (ht : t ∈ T) (hs_meas : MeasurableSet s) (ht_meas : MeasurableSet t) - (κ : Kernel α Ω) (μ : Measure α) [IsMarkovKernel κ] + (κ : Kernel α Ω) (μ : Measure α) [IsZeroOrMarkovKernel κ] (h_indep : IndepSets S T κ μ) : IndepSet s t κ μ := (indepSet_iff_measure_inter_eq_mul hs_meas ht_meas κ μ).mpr (h_indep s t hs ht) @@ -746,6 +872,8 @@ theorem indepFun_iff_measure_inter_preimage_eq_mul {mβ : MeasurableSpace β} · refine fun s t hs ht => h (f ⁻¹' s) (g ⁻¹' t) ⟨s, hs, rfl⟩ ⟨t, ht, rfl⟩ · rintro _ _ ⟨s, hs, rfl⟩ ⟨t, ht, rfl⟩; exact h s t hs ht +alias ⟨IndepFun.measure_inter_preimage_eq_mul, _⟩ := indepFun_iff_measure_inter_preimage_eq_mul + theorem iIndepFun_iff_measure_inter_preimage_eq_mul {ι : Type*} {β : ι → Type*} (m : ∀ x, MeasurableSpace (β x)) (f : ∀ i, Ω → β i) : iIndepFun m f κ μ ↔ @@ -777,8 +905,10 @@ theorem iIndepFun_iff_measure_inter_preimage_eq_mul {ι : Type*} {β : ι → Ty filter_upwards [h S h_measβ] with a ha rw [h_left_eq a, h_right_eq a, ha] +alias ⟨iIndepFun.measure_inter_preimage_eq_mul, _⟩ := iIndepFun_iff_measure_inter_preimage_eq_mul + theorem indepFun_iff_indepSet_preimage {mβ : MeasurableSpace β} {mβ' : MeasurableSpace β'} - [IsMarkovKernel κ] (hf : Measurable f) (hg : Measurable g) : + [IsZeroOrMarkovKernel κ] (hf : Measurable f) (hg : Measurable g) : IndepFun f g κ μ ↔ ∀ s t, MeasurableSet s → MeasurableSet t → IndepSet (f ⁻¹' s) (g ⁻¹' t) κ μ := by refine indepFun_iff_measure_inter_preimage_eq_mul.trans ?_ @@ -828,16 +958,17 @@ lemma iIndepFun.of_subsingleton [IsMarkovKernel κ] [Subsingleton ι] : iIndepFu · have : s = {x} := by ext y; simp [Subsingleton.elim y x, hx] simp [this] -lemma iIndepFun.ae_isProbabilityMeasure (h : iIndepFun m f κ μ) : - ∀ᵐ a ∂μ, IsProbabilityMeasure (κ a) := by - simpa [isProbabilityMeasure_iff] using h.meas_biInter (S := ∅) (s := fun _ ↦ Set.univ) - /-- If `f` is a family of mutually independent random variables (`iIndepFun m f μ`) and `S, T` are two disjoint finite index sets, then the tuple formed by `f i` for `i ∈ S` is independent of the tuple `(f i)_i` for `i ∈ T`. -/ -theorem iIndepFun.indepFun_finset [IsMarkovKernel κ] (S T : Finset ι) (hST : Disjoint S T) +theorem iIndepFun.indepFun_finset (S T : Finset ι) (hST : Disjoint S T) (hf_Indep : iIndepFun m f κ μ) (hf_meas : ∀ i, Measurable (f i)) : IndepFun (fun a (i : S) => f i a) (fun a (i : T) => f i a) κ μ := by + rcases eq_or_ne μ 0 with rfl | hμ + · simp + obtain ⟨η, η_eq, hη⟩ : ∃ (η : Kernel α Ω), κ =ᵐ[μ] η ∧ IsMarkovKernel η := + exists_ae_eq_isMarkovKernel hf_Indep.ae_isProbabilityMeasure hμ + apply IndepFun.congr (Filter.EventuallyEq.symm η_eq) -- We introduce π-systems, built from the π-system of boxes which generates `MeasurableSpace.pi`. let πSβ := Set.pi (Set.univ : Set S) '' Set.pi (Set.univ : Set S) fun i => { s : Set (β i) | MeasurableSet[m i] s } @@ -889,6 +1020,7 @@ theorem iIndepFun.indepFun_finset [IsMarkovKernel κ] (S T : Finset ι) (hST : D constructor <;> intro h · intro i hi; simp_rw [sets_t', dif_pos hi]; exact h ⟨i, hi⟩ · rintro ⟨i, hi⟩; specialize h i hi; simp_rw [sets_t', dif_pos hi] at h; exact h + replace hf_Indep := hf_Indep.congr η_eq rw [iIndepFun_iff_measure_inter_preimage_eq_mul] at hf_Indep have h_Inter_inter : ((⋂ i ∈ S, f i ⁻¹' sets_s' i) ∩ ⋂ i ∈ T, f i ⁻¹' sets_t' i) = @@ -925,7 +1057,7 @@ theorem iIndepFun.indepFun_finset [IsMarkovKernel κ] (S T : Finset ι) (hST : D · refine Finset.prod_congr rfl fun i hi => ?_ rw [h_sets_s'_univ hi, Set.univ_inter] -theorem iIndepFun.indepFun_prod_mk [IsMarkovKernel κ] (hf_Indep : iIndepFun m f κ μ) +theorem iIndepFun.indepFun_prod_mk (hf_Indep : iIndepFun m f κ μ) (hf_meas : ∀ i, Measurable (f i)) (i j k : ι) (hik : i ≠ k) (hjk : j ≠ k) : IndepFun (fun a => (f i a, f j a)) (f k) κ μ := by classical @@ -952,7 +1084,7 @@ theorem iIndepFun.indepFun_prod_mk [IsMarkovKernel κ] (hf_Indep : iIndepFun m f exact ⟨hik.symm, hjk.symm⟩ open Finset in -lemma iIndepFun.indepFun_prod_mk_prod_mk [IsMarkovKernel κ] (hf_indep : iIndepFun m f κ μ) +lemma iIndepFun.indepFun_prod_mk_prod_mk (hf_indep : iIndepFun m f κ μ) (hf_meas : ∀ i, Measurable (f i)) (i j k l : ι) (hik : i ≠ k) (hil : i ≠ l) (hjk : j ≠ k) (hjl : j ≠ l) : IndepFun (fun a ↦ (f i a, f j a)) (fun a ↦ (f k a, f l a)) κ μ := by @@ -966,7 +1098,6 @@ end iIndepFun section Mul variable {β : Type*} {m : MeasurableSpace β} [Mul β] [MeasurableMul₂ β] {f : ι → Ω → β} - [IsMarkovKernel κ] @[to_additive] lemma iIndepFun.indepFun_mul_left (hf_indep : iIndepFun (fun _ ↦ m) f κ μ) @@ -994,7 +1125,6 @@ end Mul section Div variable {β : Type*} {m : MeasurableSpace β} [Div β] [MeasurableDiv₂ β] {f : ι → Ω → β} - [IsMarkovKernel κ] @[to_additive] lemma iIndepFun.indepFun_div_left (hf_indep : iIndepFun (fun _ ↦ m) f κ μ) @@ -1022,7 +1152,6 @@ end Div section CommMonoid variable {β : Type*} {m : MeasurableSpace β} [CommMonoid β] [MeasurableMul₂ β] {f : ι → Ω → β} - [IsMarkovKernel κ] @[to_additive] theorem iIndepFun.indepFun_finset_prod_of_not_mem (hf_Indep : iIndepFun (fun _ ↦ m) f κ μ) diff --git a/Mathlib/Probability/Independence/ZeroOne.lean b/Mathlib/Probability/Independence/ZeroOne.lean index 8af5f5af8b3e6..06403152bcee2 100644 --- a/Mathlib/Probability/Independence/ZeroOne.lean +++ b/Mathlib/Probability/Independence/ZeroOne.lean @@ -46,19 +46,24 @@ theorem measure_eq_zero_or_one_or_top_of_indepSet_self {t : Set Ω} simpa only [ae_dirac_eq, Filter.eventually_pure] using Kernel.measure_eq_zero_or_one_or_top_of_indepSet_self h_indep -theorem Kernel.measure_eq_zero_or_one_of_indepSet_self [∀ a, IsFiniteMeasure (κ a)] {t : Set Ω} - (h_indep : IndepSet t t κ μα) : +theorem Kernel.measure_eq_zero_or_one_of_indepSet_self' (h : ∀ᵐ a ∂μα, IsFiniteMeasure (κ a)) + {t : Set Ω} (h_indep : IndepSet t t κ μα) : ∀ᵐ a ∂μα, κ a t = 0 ∨ κ a t = 1 := by - filter_upwards [measure_eq_zero_or_one_or_top_of_indepSet_self h_indep] with a h_0_1_top + filter_upwards [measure_eq_zero_or_one_or_top_of_indepSet_self h_indep, h] with a h_0_1_top h' simpa only [measure_ne_top (κ a), or_false] using h_0_1_top +theorem Kernel.measure_eq_zero_or_one_of_indepSet_self [h : ∀ a, IsFiniteMeasure (κ a)] {t : Set Ω} + (h_indep : IndepSet t t κ μα) : + ∀ᵐ a ∂μα, κ a t = 0 ∨ κ a t = 1 := + Kernel.measure_eq_zero_or_one_of_indepSet_self' (ae_of_all μα h) h_indep + theorem measure_eq_zero_or_one_of_indepSet_self [IsFiniteMeasure μ] {t : Set Ω} (h_indep : IndepSet t t μ) : μ t = 0 ∨ μ t = 1 := by simpa only [ae_dirac_eq, Filter.eventually_pure] using Kernel.measure_eq_zero_or_one_of_indepSet_self h_indep theorem condexp_eq_zero_or_one_of_condIndepSet_self - [StandardBorelSpace Ω] [Nonempty Ω] + [StandardBorelSpace Ω] (hm : m ≤ m0) [hμ : IsFiniteMeasure μ] {t : Set Ω} (ht : MeasurableSet t) (h_indep : CondIndepSet m hm t t μ) : ∀ᵐ ω ∂μ, (μ⟦t | m⟧) ω = 0 ∨ (μ⟦t | m⟧) ω = 1 := by @@ -71,20 +76,17 @@ theorem condexp_eq_zero_or_one_of_condIndepSet_self | inl h => exact Or.inl (Or.inl h) | inr h => exact Or.inr h -variable [IsMarkovKernel κ] - open Filter theorem Kernel.indep_biSup_compl (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s κ μα) (t : Set ι) : Indep (⨆ n ∈ t, s n) (⨆ n ∈ tᶜ, s n) κ μα := indep_iSup_of_disjoint h_le h_indep disjoint_compl_right -theorem indep_biSup_compl [IsProbabilityMeasure μ] - (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s μ) (t : Set ι) : +theorem indep_biSup_compl (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s μ) (t : Set ι) : Indep (⨆ n ∈ t, s n) (⨆ n ∈ tᶜ, s n) μ := Kernel.indep_biSup_compl h_le h_indep t -theorem condIndep_biSup_compl [StandardBorelSpace Ω] [Nonempty Ω] +theorem condIndep_biSup_compl [StandardBorelSpace Ω] (hm : m ≤ m0) [IsFiniteMeasure μ] (h_le : ∀ n, s n ≤ m0) (h_indep : iCondIndep m hm s μ) (t : Set ι) : CondIndep m (⨆ n ∈ t, s n) (⨆ n ∈ tᶜ, s n) hm μ := @@ -92,7 +94,7 @@ theorem condIndep_biSup_compl [StandardBorelSpace Ω] [Nonempty Ω] section Abstract -variable {α : Type*} {p : Set ι → Prop} {f : Filter ι} {ns : α → Set ι} +variable {β : Type*} {p : Set ι → Prop} {f : Filter ι} {ns : β → Set ι} /-! We prove a version of Kolmogorov's 0-1 law for the σ-algebra `limsup s f` where `f` is a filter for which we can define the following two functions: @@ -112,13 +114,13 @@ theorem Kernel.indep_biSup_limsup (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s simp only [Set.mem_compl_iff, eventually_map] exact eventually_of_mem (hf t ht) le_iSup₂ -theorem indep_biSup_limsup [IsProbabilityMeasure μ] +theorem indep_biSup_limsup (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s μ) (hf : ∀ t, p t → tᶜ ∈ f) {t : Set ι} (ht : p t) : Indep (⨆ n ∈ t, s n) (limsup s f) μ := Kernel.indep_biSup_limsup h_le h_indep hf ht -theorem condIndep_biSup_limsup [StandardBorelSpace Ω] [Nonempty Ω] +theorem condIndep_biSup_limsup [StandardBorelSpace Ω] (hm : m ≤ m0) [IsFiniteMeasure μ] (h_le : ∀ n, s n ≤ m0) (h_indep : iCondIndep m hm s μ) (hf : ∀ t, p t → tᶜ ∈ f) {t : Set ι} (ht : p t) : @@ -128,6 +130,12 @@ theorem condIndep_biSup_limsup [StandardBorelSpace Ω] [Nonempty Ω] theorem Kernel.indep_iSup_directed_limsup (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s κ μα) (hf : ∀ t, p t → tᶜ ∈ f) (hns : Directed (· ≤ ·) ns) (hnsp : ∀ a, p (ns a)) : Indep (⨆ a, ⨆ n ∈ ns a, s n) (limsup s f) κ μα := by + rcases eq_or_ne μα 0 with rfl | hμ + · simp + obtain ⟨η, η_eq, hη⟩ : ∃ (η : Kernel α Ω), κ =ᵐ[μα] η ∧ IsMarkovKernel η := + exists_ae_eq_isMarkovKernel h_indep.ae_isProbabilityMeasure hμ + replace h_indep := h_indep.congr η_eq + apply Indep.congr (Filter.EventuallyEq.symm η_eq) apply indep_iSup_of_directed_le · exact fun a => indep_biSup_limsup h_le h_indep hf (hnsp a) · exact fun a => iSup₂_le fun n _ => h_le n @@ -138,14 +146,14 @@ theorem Kernel.indep_iSup_directed_limsup (h_le : ∀ n, s n ≤ m0) (h_indep : · exact hc.1 hn · exact hc.2 hn -theorem indep_iSup_directed_limsup [IsProbabilityMeasure μ] +theorem indep_iSup_directed_limsup (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s μ) (hf : ∀ t, p t → tᶜ ∈ f) (hns : Directed (· ≤ ·) ns) (hnsp : ∀ a, p (ns a)) : Indep (⨆ a, ⨆ n ∈ ns a, s n) (limsup s f) μ := Kernel.indep_iSup_directed_limsup h_le h_indep hf hns hnsp theorem condIndep_iSup_directed_limsup [StandardBorelSpace Ω] - [Nonempty Ω] (hm : m ≤ m0) [IsFiniteMeasure μ] + (hm : m ≤ m0) [IsFiniteMeasure μ] (h_le : ∀ n, s n ≤ m0) (h_indep : iCondIndep m hm s μ) (hf : ∀ t, p t → tᶜ ∈ f) (hns : Directed (· ≤ ·) ns) (hnsp : ∀ a, p (ns a)) : CondIndep m (⨆ a, ⨆ n ∈ ns a, s n) (limsup s f) hm μ := @@ -160,17 +168,17 @@ theorem Kernel.indep_iSup_limsup (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s exact indep_iSup_directed_limsup h_le h_indep hf hns hnsp rw [iSup_comm] refine iSup_congr fun n => ?_ - have h : ⨆ (i : α) (_ : n ∈ ns i), s n = ⨆ _ : ∃ i, n ∈ ns i, s n := by rw [iSup_exists] - haveI : Nonempty (∃ i : α, n ∈ ns i) := ⟨hns_univ n⟩ + have h : ⨆ (i : β) (_ : n ∈ ns i), s n = ⨆ _ : ∃ i, n ∈ ns i, s n := by rw [iSup_exists] + haveI : Nonempty (∃ i : β, n ∈ ns i) := ⟨hns_univ n⟩ rw [h, iSup_const] -theorem indep_iSup_limsup [IsProbabilityMeasure μ] +theorem indep_iSup_limsup (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s μ) (hf : ∀ t, p t → tᶜ ∈ f) (hns : Directed (· ≤ ·) ns) (hnsp : ∀ a, p (ns a)) (hns_univ : ∀ n, ∃ a, n ∈ ns a) : Indep (⨆ n, s n) (limsup s f) μ := Kernel.indep_iSup_limsup h_le h_indep hf hns hnsp hns_univ -theorem condIndep_iSup_limsup [StandardBorelSpace Ω] [Nonempty Ω] +theorem condIndep_iSup_limsup [StandardBorelSpace Ω] (hm : m ≤ m0) [IsFiniteMeasure μ] (h_le : ∀ n, s n ≤ m0) (h_indep : iCondIndep m hm s μ) (hf : ∀ t, p t → tᶜ ∈ f) (hns : Directed (· ≤ ·) ns) (hnsp : ∀ a, p (ns a)) (hns_univ : ∀ n, ∃ a, n ∈ ns a) : @@ -183,13 +191,13 @@ theorem Kernel.indep_limsup_self (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s Indep (limsup s f) (limsup s f) κ μα := indep_of_indep_of_le_left (indep_iSup_limsup h_le h_indep hf hns hnsp hns_univ) limsup_le_iSup -theorem indep_limsup_self [IsProbabilityMeasure μ] +theorem indep_limsup_self (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s μ) (hf : ∀ t, p t → tᶜ ∈ f) (hns : Directed (· ≤ ·) ns) (hnsp : ∀ a, p (ns a)) (hns_univ : ∀ n, ∃ a, n ∈ ns a) : Indep (limsup s f) (limsup s f) μ := Kernel.indep_limsup_self h_le h_indep hf hns hnsp hns_univ -theorem condIndep_limsup_self [StandardBorelSpace Ω] [Nonempty Ω] +theorem condIndep_limsup_self [StandardBorelSpace Ω] (hm : m ≤ m0) [IsFiniteMeasure μ] (h_le : ∀ n, s n ≤ m0) (h_indep : iCondIndep m hm s μ) (hf : ∀ t, p t → tᶜ ∈ f) (hns : Directed (· ≤ ·) ns) (hnsp : ∀ a, p (ns a)) (hns_univ : ∀ n, ∃ a, n ∈ ns a) : @@ -200,12 +208,13 @@ theorem Kernel.measure_zero_or_one_of_measurableSet_limsup (h_le : ∀ n, s n (h_indep : iIndep s κ μα) (hf : ∀ t, p t → tᶜ ∈ f) (hns : Directed (· ≤ ·) ns) (hnsp : ∀ a, p (ns a)) (hns_univ : ∀ n, ∃ a, n ∈ ns a) {t : Set Ω} (ht_tail : MeasurableSet[limsup s f] t) : - ∀ᵐ a ∂μα, κ a t = 0 ∨ κ a t = 1 := - measure_eq_zero_or_one_of_indepSet_self + ∀ᵐ a ∂μα, κ a t = 0 ∨ κ a t = 1 := by + apply measure_eq_zero_or_one_of_indepSet_self' ?_ ((indep_limsup_self h_le h_indep hf hns hnsp hns_univ).indepSet_of_measurableSet ht_tail ht_tail) + filter_upwards [h_indep.ae_isProbabilityMeasure] with a ha using by infer_instance -theorem measure_zero_or_one_of_measurableSet_limsup [IsProbabilityMeasure μ] +theorem measure_zero_or_one_of_measurableSet_limsup (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s μ) (hf : ∀ t, p t → tᶜ ∈ f) (hns : Directed (· ≤ ·) ns) (hnsp : ∀ a, p (ns a)) (hns_univ : ∀ n, ∃ a, n ∈ ns a) {t : Set Ω} (ht_tail : MeasurableSet[limsup s f] t) : @@ -214,7 +223,7 @@ theorem measure_zero_or_one_of_measurableSet_limsup [IsProbabilityMeasure μ] using Kernel.measure_zero_or_one_of_measurableSet_limsup h_le h_indep hf hns hnsp hns_univ ht_tail -theorem condexp_zero_or_one_of_measurableSet_limsup [StandardBorelSpace Ω] [Nonempty Ω] +theorem condexp_zero_or_one_of_measurableSet_limsup [StandardBorelSpace Ω] (hm : m ≤ m0) [IsFiniteMeasure μ] (h_le : ∀ n, s n ≤ m0) (h_indep : iCondIndep m hm s μ) (hf : ∀ t, p t → tᶜ ∈ f) (hns : Directed (· ≤ ·) ns) (hnsp : ∀ a, p (ns a)) @@ -249,12 +258,11 @@ theorem Kernel.indep_limsup_atTop_self (h_le : ∀ n, s n ≤ m0) (h_indep : iIn · exact Monotone.directed_le fun i j hij k hki => le_trans hki hij · exact fun n => ⟨n, le_rfl⟩ -theorem indep_limsup_atTop_self [IsProbabilityMeasure μ] - (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s μ) : +theorem indep_limsup_atTop_self (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s μ) : Indep (limsup s atTop) (limsup s atTop) μ := Kernel.indep_limsup_atTop_self h_le h_indep -theorem condIndep_limsup_atTop_self [StandardBorelSpace Ω] [Nonempty Ω] +theorem condIndep_limsup_atTop_self [StandardBorelSpace Ω] (hm : m ≤ m0) [IsFiniteMeasure μ] (h_le : ∀ n, s n ≤ m0) (h_indep : iCondIndep m hm s μ) : CondIndep m (limsup s atTop) (limsup s atTop) hm μ := @@ -262,21 +270,22 @@ theorem condIndep_limsup_atTop_self [StandardBorelSpace Ω] [Nonempty Ω] theorem Kernel.measure_zero_or_one_of_measurableSet_limsup_atTop (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s κ μα) {t : Set Ω} (ht_tail : MeasurableSet[limsup s atTop] t) : - ∀ᵐ a ∂μα, κ a t = 0 ∨ κ a t = 1 := - measure_eq_zero_or_one_of_indepSet_self + ∀ᵐ a ∂μα, κ a t = 0 ∨ κ a t = 1 := by + apply measure_eq_zero_or_one_of_indepSet_self' ?_ ((indep_limsup_atTop_self h_le h_indep).indepSet_of_measurableSet ht_tail ht_tail) + filter_upwards [h_indep.ae_isProbabilityMeasure] with a ha using by infer_instance /-- **Kolmogorov's 0-1 law** : any event in the tail σ-algebra of an independent sequence of sub-σ-algebras has probability 0 or 1. The tail σ-algebra `limsup s atTop` is the same as `⋂ n, ⋃ i ≥ n, s i`. -/ -theorem measure_zero_or_one_of_measurableSet_limsup_atTop [IsProbabilityMeasure μ] +theorem measure_zero_or_one_of_measurableSet_limsup_atTop (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s μ) {t : Set Ω} (ht_tail : MeasurableSet[limsup s atTop] t) : μ t = 0 ∨ μ t = 1 := by simpa only [ae_dirac_eq, Filter.eventually_pure] using Kernel.measure_zero_or_one_of_measurableSet_limsup_atTop h_le h_indep ht_tail -theorem condexp_zero_or_one_of_measurableSet_limsup_atTop [StandardBorelSpace Ω] [Nonempty Ω] +theorem condexp_zero_or_one_of_measurableSet_limsup_atTop [StandardBorelSpace Ω] (hm : m ≤ m0) [IsFiniteMeasure μ] (h_le : ∀ n, s n ≤ m0) (h_indep : iCondIndep m hm s μ) {t : Set Ω} (ht_tail : MeasurableSet[limsup s atTop] t) : ∀ᵐ ω ∂μ, (μ⟦t | m⟧) ω = 0 ∨ (μ⟦t | m⟧) ω = 1 := @@ -303,12 +312,12 @@ theorem Kernel.indep_limsup_atBot_self (h_le : ∀ n, s n ≤ m0) (h_indep : iIn · exact Antitone.directed_le fun _ _ ↦ Set.Ici_subset_Ici.2 · exact fun n => ⟨n, le_rfl⟩ -theorem indep_limsup_atBot_self [IsProbabilityMeasure μ] +theorem indep_limsup_atBot_self (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s μ) : Indep (limsup s atBot) (limsup s atBot) μ := Kernel.indep_limsup_atBot_self h_le h_indep -theorem condIndep_limsup_atBot_self [StandardBorelSpace Ω] [Nonempty Ω] +theorem condIndep_limsup_atBot_self [StandardBorelSpace Ω] (hm : m ≤ m0) [IsFiniteMeasure μ] (h_le : ∀ n, s n ≤ m0) (h_indep : iCondIndep m hm s μ) : CondIndep m (limsup s atBot) (limsup s atBot) hm μ := @@ -318,13 +327,14 @@ theorem condIndep_limsup_atBot_self [StandardBorelSpace Ω] [Nonempty Ω] sequence of sub-σ-algebras has probability 0 or 1 almost surely. -/ theorem Kernel.measure_zero_or_one_of_measurableSet_limsup_atBot (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s κ μα) {t : Set Ω} (ht_tail : MeasurableSet[limsup s atBot] t) : - ∀ᵐ a ∂μα, κ a t = 0 ∨ κ a t = 1 := - measure_eq_zero_or_one_of_indepSet_self + ∀ᵐ a ∂μα, κ a t = 0 ∨ κ a t = 1 := by + apply measure_eq_zero_or_one_of_indepSet_self' ?_ ((indep_limsup_atBot_self h_le h_indep).indepSet_of_measurableSet ht_tail ht_tail) + filter_upwards [h_indep.ae_isProbabilityMeasure] with a ha using by infer_instance /-- **Kolmogorov's 0-1 law** : any event in the tail σ-algebra of an independent sequence of sub-σ-algebras has probability 0 or 1. -/ -theorem measure_zero_or_one_of_measurableSet_limsup_atBot [IsProbabilityMeasure μ] +theorem measure_zero_or_one_of_measurableSet_limsup_atBot (h_le : ∀ n, s n ≤ m0) (h_indep : iIndep s μ) {t : Set Ω} (ht_tail : MeasurableSet[limsup s atBot] t) : μ t = 0 ∨ μ t = 1 := by @@ -332,8 +342,8 @@ theorem measure_zero_or_one_of_measurableSet_limsup_atBot [IsProbabilityMeasure using Kernel.measure_zero_or_one_of_measurableSet_limsup_atBot h_le h_indep ht_tail /-- **Kolmogorov's 0-1 law**, conditional version: any event in the tail σ-algebra of a -conditinoally independent sequence of sub-σ-algebras has conditional probability 0 or 1. -/ -theorem condexp_zero_or_one_of_measurableSet_limsup_atBot [StandardBorelSpace Ω] [Nonempty Ω] +conditionally independent sequence of sub-σ-algebras has conditional probability 0 or 1. -/ +theorem condexp_zero_or_one_of_measurableSet_limsup_atBot [StandardBorelSpace Ω] (hm : m ≤ m0) [IsFiniteMeasure μ] (h_le : ∀ n, s n ≤ m0) (h_indep : iCondIndep m hm s μ) {t : Set Ω} (ht_tail : MeasurableSet[limsup s atBot] t) : ∀ᵐ ω ∂μ, (μ⟦t | m⟧) ω = 0 ∨ (μ⟦t | m⟧) ω = 1 := diff --git a/Mathlib/Probability/Integration.lean b/Mathlib/Probability/Integration.lean index 9fd7234ccf87f..ad5bc0600a169 100644 --- a/Mathlib/Probability/Integration.lean +++ b/Mathlib/Probability/Integration.lean @@ -143,7 +143,7 @@ theorem IndepFun.integrable_mul {β : Type*} [MeasurableSpace β] {X Y : Ω → lintegral_mul_eq_lintegral_mul_lintegral_of_indepFun' hnX hnY hXY'' refine ⟨hX.1.mul hY.1, ?_⟩ simp_rw [HasFiniteIntegral, Pi.mul_apply, nnnorm_mul, ENNReal.coe_mul, hmul] - exact ENNReal.mul_lt_top hX.2.ne hY.2.ne + exact ENNReal.mul_lt_top hX.2 hY.2 /-- If the product of two independent real-valued random variables is integrable and the second one is not almost everywhere zero, then the first one is integrable. -/ diff --git a/Mathlib/Probability/Kernel/Basic.lean b/Mathlib/Probability/Kernel/Basic.lean index 5a8caec90e730..3fc42e7dc57d2 100644 --- a/Mathlib/Probability/Kernel/Basic.lean +++ b/Mathlib/Probability/Kernel/Basic.lean @@ -3,361 +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.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β - -initialize_simps_projections Kernel (toFun → apply) - -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' - -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 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 - -/-- 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 IsFiniteKernel.isFiniteMeasure [IsFiniteKernel κ] (a : α) : IsFiniteMeasure (κ a) := - ⟨(Kernel.measure_le_bound κ a Set.univ).trans_lt (IsFiniteKernel.bound_lt_top κ)⟩ - -instance (priority := 100) IsMarkovKernel.isFiniteKernel [IsMarkovKernel κ] : - IsFiniteKernel κ := - ⟨⟨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. -/ @@ -408,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 @@ -477,6 +130,13 @@ instance const.instIsMarkovKernel {μβ : Measure β} [hμβ : IsProbabilityMeas IsMarkovKernel (const α μβ) := ⟨fun _ => hμβ⟩ +instance const.instIsZeroOrMarkovKernel {μβ : Measure β} [hμβ : IsZeroOrProbabilityMeasure μβ] : + IsZeroOrMarkovKernel (const α μβ) := by + rcases eq_zero_or_isProbabilityMeasure μβ with rfl | h + · simp only [const_zero] + infer_instance + · infer_instance + lemma isSFiniteKernel_const [Nonempty α] {μβ : Measure β} : IsSFiniteKernel (const α μβ) ↔ SFinite μβ := ⟨fun h ↦ h.sFinite (Classical.arbitrary α), fun _ ↦ inferInstance⟩ @@ -492,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 β` @@ -551,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 @@ -683,20 +322,28 @@ 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 +end Piecewise -@[deprecated (since := "2024-04-17")] -alias set_integral_piecewise := setIntegral_piecewise +lemma exists_ae_eq_isMarkovKernel {μ : Measure α} + (h : ∀ᵐ a ∂μ, IsProbabilityMeasure (κ a)) (h' : μ ≠ 0) : + ∃ (η : Kernel α β), (κ =ᵐ[μ] η) ∧ IsMarkovKernel η := by + classical + obtain ⟨s, s_meas, μs, hs⟩ : ∃ s, MeasurableSet s ∧ μ s = 0 + ∧ ∀ a ∉ s, IsProbabilityMeasure (κ a) := by + refine ⟨toMeasurable μ {a | ¬ IsProbabilityMeasure (κ a)}, measurableSet_toMeasurable _ _, + by simpa [measure_toMeasurable] using h, ?_⟩ + intro a ha + contrapose! ha + exact subset_toMeasurable _ _ ha + obtain ⟨a, ha⟩ : sᶜ.Nonempty := by + contrapose! h'; simpa [μs, h'] using measure_univ_le_add_compl s (μ := μ) + refine ⟨Kernel.piecewise s_meas (Kernel.const _ (κ a)) κ, ?_, ?_⟩ + · filter_upwards [measure_zero_iff_ae_nmem.1 μs] with b hb + simp [hb, piecewise] + · refine ⟨fun b ↦ ?_⟩ + by_cases hb : b ∈ s + · simpa [hb, piecewise] using hs _ ha + · simpa [hb, piecewise] using hs _ hb -end Piecewise end Kernel end ProbabilityTheory diff --git a/Mathlib/Probability/Kernel/Composition.lean b/Mathlib/Probability/Kernel/Composition.lean index 412687e4436d6..513325918f94f 100644 --- a/Mathlib/Probability/Kernel/Composition.lean +++ b/Mathlib/Probability/Kernel/Composition.lean @@ -29,8 +29,8 @@ Kernels built from other kernels: * `compProd (κ : Kernel α β) (η : Kernel (α × β) γ) : Kernel α (β × γ)`: composition-product of 2 s-finite kernels. We define a notation `κ ⊗ₖ η = compProd κ η`. `∫⁻ bc, f bc ∂((κ ⊗ₖ η) a) = ∫⁻ b, ∫⁻ c, f (b, c) ∂(η (a, b)) ∂(κ a)` -* `map (κ : Kernel α β) (f : β → γ) (hf : Measurable f) : Kernel α γ` - `∫⁻ c, g c ∂(map κ f hf a) = ∫⁻ b, g (f b) ∂(κ a)` +* `map (κ : Kernel α β) (f : β → γ) : Kernel α γ` + `∫⁻ c, g c ∂(map κ f a) = ∫⁻ b, g (f b) ∂(κ a)` * `comap (κ : Kernel α β) (f : γ → α) (hf : Measurable f) : Kernel γ β` `∫⁻ b, g b ∂(comap κ f hf c) = ∫⁻ b, g b ∂(κ (f c))` * `comp (η : Kernel β γ) (κ : Kernel α β) : Kernel α γ`: composition of 2 kernels. @@ -96,16 +96,14 @@ theorem compProdFun_iUnion (κ : Kernel α β) (η : Kernel (α × β) γ) [IsSF (f : ℕ → Set (β × γ)) (hf_meas : ∀ i, MeasurableSet (f i)) (hf_disj : Pairwise (Disjoint on f)) : compProdFun κ η a (⋃ i, f i) = ∑' i, compProdFun κ η a (f i) := by - have h_Union : - (fun b => η (a, b) {c : γ | (b, c) ∈ ⋃ i, f i}) = fun b => - η (a, b) (⋃ i, {c : γ | (b, c) ∈ f i}) := by + have h_Union : (fun b ↦ η (a, b) {c : γ | (b, c) ∈ ⋃ i, f i}) + = fun b ↦ η (a, b) (⋃ i, {c : γ | (b, c) ∈ f i}) := by ext1 b congr with c simp only [Set.mem_iUnion, Set.iSup_eq_iUnion, Set.mem_setOf_eq] rw [compProdFun, h_Union] - have h_tsum : - (fun b => η (a, b) (⋃ i, {c : γ | (b, c) ∈ f i})) = fun b => - ∑' i, η (a, b) {c : γ | (b, c) ∈ f i} := by + have h_tsum : (fun b ↦ η (a, b) (⋃ i, {c : γ | (b, c) ∈ f i})) + = fun b ↦ ∑' i, η (a, b) {c : γ | (b, c) ∈ f i} := by ext1 b rw [measure_iUnion] · intro i j hij s hsi hsj c hcs @@ -113,11 +111,9 @@ theorem compProdFun_iUnion (κ : Kernel α β) (η : Kernel (α × β) γ) [IsSF have hbcj : {(b, c)} ⊆ f j := by rw [Set.singleton_subset_iff]; exact hsj hcs simpa only [Set.bot_eq_empty, Set.le_eq_subset, Set.singleton_subset_iff, Set.mem_empty_iff_false] using hf_disj hij hbci hbcj - · -- Porting note: behavior of `@` changed relative to lean 3, was - -- exact fun i => (@measurable_prod_mk_left β γ _ _ b) _ (hf_meas i) - exact fun i => (@measurable_prod_mk_left β γ _ _ b) (hf_meas i) + · 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) @@ -126,15 +122,13 @@ theorem compProdFun_iUnion (κ : Kernel α β) (η : Kernel (α × β) γ) [IsSF theorem compProdFun_tsum_right (κ : Kernel α β) (η : Kernel (α × β) γ) [IsSFiniteKernel η] (a : α) (hs : MeasurableSet s) : compProdFun κ η a s = ∑' n, compProdFun κ (seq η n) a s := by simp_rw [compProdFun, (measure_sum_seq η _).symm] - have : - ∫⁻ b, Measure.sum (fun n => seq η n (a, b)) {c : γ | (b, c) ∈ s} ∂κ a = - ∫⁻ b, ∑' n, seq η n (a, b) {c : γ | (b, c) ∈ s} ∂κ a := by - congr - ext1 b + have : ∫⁻ b, Measure.sum (fun n => seq η n (a, b)) {c : γ | (b, c) ∈ s} ∂κ a + = ∫⁻ b, ∑' n, seq η n (a, b) {c : γ | (b, c) ∈ s} ∂κ a := by + congr with b rw [Measure.sum_apply] exact measurable_prod_mk_left hs rw [this, lintegral_tsum] - exact fun n => ((measurable_kernel_prod_mk_left (κ := (seq η n)) + exact fun n ↦ ((measurable_kernel_prod_mk_left (κ := (seq η n)) ((measurable_fst.snd.prod_mk measurable_snd) hs)).comp measurable_prod_mk_left).aemeasurable theorem compProdFun_tsum_left (κ : Kernel α β) (η : Kernel (α × β) γ) [IsSFiniteKernel κ] (a : α) @@ -146,34 +140,21 @@ theorem compProdFun_eq_tsum (κ : Kernel α β) [IsSFiniteKernel κ] (η : Kerne compProdFun κ η a s = ∑' (n) (m), compProdFun (seq κ n) (seq η m) a s := by simp_rw [compProdFun_tsum_left κ η a s, compProdFun_tsum_right _ η a hs] -/-- Auxiliary lemma for `measurable_compProdFun`. -/ -theorem measurable_compProdFun_of_finite (κ : Kernel α β) [IsFiniteKernel κ] (η : Kernel (α × β) γ) - [IsFiniteKernel η] (hs : MeasurableSet s) : Measurable fun a => compProdFun κ η a s := by +theorem measurable_compProdFun (κ : Kernel α β) [IsSFiniteKernel κ] (η : Kernel (α × β) γ) + [IsSFiniteKernel η] (hs : MeasurableSet s) : + Measurable fun a ↦ compProdFun κ η a s := by simp only [compProdFun] have h_meas : Measurable (Function.uncurry fun a b => η (a, b) {c : γ | (b, c) ∈ s}) := by - have : - (Function.uncurry fun a b => η (a, b) {c : γ | (b, c) ∈ s}) = fun p => - η p {c : γ | (p.2, c) ∈ s} := by + have : (Function.uncurry fun a b => η (a, b) {c : γ | (b, c) ∈ s}) + = fun p ↦ η p {c : γ | (p.2, c) ∈ s} := by ext1 p rw [Function.uncurry_apply_pair] rw [this] exact measurable_kernel_prod_mk_left (measurable_fst.snd.prod_mk measurable_snd hs) exact h_meas.lintegral_kernel_prod_right -theorem measurable_compProdFun (κ : Kernel α β) [IsSFiniteKernel κ] (η : Kernel (α × β) γ) - [IsSFiniteKernel η] (hs : MeasurableSet s) : Measurable fun a => compProdFun κ η a s := by - simp_rw [compProdFun_tsum_right κ η _ hs] - refine Measurable.ennreal_tsum fun n => ?_ - simp only [compProdFun] - have h_meas : Measurable (Function.uncurry fun a b => seq η n (a, b) {c : γ | (b, c) ∈ s}) := by - have : - (Function.uncurry fun a b => seq η n (a, b) {c : γ | (b, c) ∈ s}) = fun p => - seq η n p {c : γ | (p.2, c) ∈ s} := by - ext1 p - rw [Function.uncurry_apply_pair] - rw [this] - exact measurable_kernel_prod_mk_left (measurable_fst.snd.prod_mk measurable_snd hs) - exact h_meas.lintegral_kernel_prod_right +@[deprecated (since := "2024-08-30")] +alias measurable_compProdFun_of_finite := measurable_compProdFun open scoped Classical @@ -182,24 +163,24 @@ open scoped Classical (see `ProbabilityTheory.Kernel.lintegral_compProd`). If either of the kernels is not s-finite, `compProd` is given the junk value 0. -/ noncomputable def compProd (κ : Kernel α β) (η : Kernel (α × β) γ) : Kernel α (β × γ) := -if h : IsSFiniteKernel κ ∧ IsSFiniteKernel η then -{ toFun := fun a ↦ - Measure.ofMeasurable (fun s _ => compProdFun κ η a s) (compProdFun_empty κ η a) - (@compProdFun_iUnion _ _ _ _ _ _ κ η h.2 a) - measurable' := by - have : IsSFiniteKernel κ := h.1 - have : IsSFiniteKernel η := h.2 - refine Measure.measurable_of_measurable_coe _ fun s hs => ?_ - have : - (fun a => - Measure.ofMeasurable (fun s _ => compProdFun κ η a s) (compProdFun_empty κ η a) - (compProdFun_iUnion κ η a) s) = - fun a => compProdFun κ η a s := by - ext1 a; rwa [Measure.ofMeasurable_apply] - rw [this] - exact measurable_compProdFun κ η hs } -else 0 - + if h : IsSFiniteKernel κ ∧ IsSFiniteKernel η then + { toFun := fun a ↦ + have : IsSFiniteKernel η := h.2 + Measure.ofMeasurable (fun s _ ↦ compProdFun κ η a s) (compProdFun_empty κ η a) + (compProdFun_iUnion κ η a) + measurable' := by + have : IsSFiniteKernel κ := h.1 + have : IsSFiniteKernel η := h.2 + refine Measure.measurable_of_measurable_coe _ fun s hs ↦ ?_ + have : (fun a ↦ Measure.ofMeasurable (fun s _ ↦ compProdFun κ η a s) (compProdFun_empty κ η a) + (compProdFun_iUnion κ η a) s) + = fun a ↦ compProdFun κ η a s := by + ext1 a; rwa [Measure.ofMeasurable_apply] + rw [this] + exact measurable_compProdFun κ η hs } + else 0 + +@[inherit_doc] scoped[ProbabilityTheory] infixl:100 " ⊗ₖ " => ProbabilityTheory.Kernel.compProd theorem compProd_apply_eq_compProdFun (κ : Kernel α β) [IsSFiniteKernel κ] (η : Kernel (α × β) γ) @@ -253,7 +234,7 @@ lemma compProd_zero_left (κ : Kernel (α × β) γ) : · 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 @@ -294,16 +275,21 @@ theorem ae_null_of_compProd_null (h : (κ ⊗ₖ η) a s = 0) : rw [Filter.eventuallyLE_antisymm_iff] exact ⟨Filter.EventuallyLE.trans_eq - (Filter.eventually_of_forall fun x => (measure_mono (Set.preimage_mono hst) : _)) ht, - Filter.eventually_of_forall fun x => zero_le _⟩ + (Filter.Eventually.of_forall fun x => (measure_mono (Set.preimage_mono hst) : _)) ht, + Filter.Eventually.of_forall fun x => zero_le _⟩ theorem ae_ae_of_ae_compProd {p : β × γ → Prop} (h : ∀ᵐ bc ∂(κ ⊗ₖ η) a, p bc) : ∀ᵐ b ∂κ a, ∀ᵐ c ∂η (a, b), p (b, c) := ae_null_of_compProd_null h -lemma ae_compProd_of_ae_ae {p : β × γ → Prop} (hp : MeasurableSet {x | p x}) +lemma ae_compProd_of_ae_ae {κ : Kernel α β} {η : Kernel (α × β) γ} + {p : β × γ → Prop} (hp : MeasurableSet {x | p x}) (h : ∀ᵐ b ∂κ a, ∀ᵐ c ∂η (a, b), p (b, c)) : ∀ᵐ bc ∂(κ ⊗ₖ η) a, p bc := by + by_cases hκ : IsSFiniteKernel κ + swap; · simp [compProd_of_not_isSFiniteKernel_left _ _ hκ] + by_cases hη : IsSFiniteKernel η + swap; · simp [compProd_of_not_isSFiniteKernel_right _ _ hη] simp_rw [ae_iff] at h ⊢ rw [compProd_null] · exact h @@ -334,9 +320,8 @@ 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] @@ -524,7 +509,7 @@ theorem compProd_apply_univ_le (κ : Kernel α β) (η : Kernel (α × β) γ) [ instance IsFiniteKernel.compProd (κ : Kernel α β) [IsFiniteKernel κ] (η : Kernel (α × β) γ) [IsFiniteKernel η] : IsFiniteKernel (κ ⊗ₖ η) := ⟨⟨IsFiniteKernel.bound κ * IsFiniteKernel.bound η, - ENNReal.mul_lt_top (IsFiniteKernel.bound_ne_top κ) (IsFiniteKernel.bound_ne_top η), fun a => + ENNReal.mul_lt_top (IsFiniteKernel.bound_lt_top κ) (IsFiniteKernel.bound_lt_top η), fun a => calc (κ ⊗ₖ η) a Set.univ ≤ κ a Set.univ * IsFiniteKernel.bound η := compProd_apply_univ_le κ η a _ ≤ IsFiniteKernel.bound κ * IsFiniteKernel.bound η := @@ -583,60 +568,92 @@ section MapComap variable {γ δ : Type*} {mγ : MeasurableSpace γ} {mδ : MeasurableSpace δ} {f : β → γ} {g : γ → α} -/-- The pushforward of a kernel along a measurable function. -We include measurability in the assumptions instead of using junk values -to make sure that typeclass inference can infer that the `map` of a Markov kernel -is again a Markov kernel. -/ -noncomputable def map (κ : Kernel α β) (f : β → γ) (hf : Measurable f) : Kernel α γ where +/-- The pushforward of a kernel along a measurable function. This is an implementation detail, +use `map κ f` instead. -/ +noncomputable def mapOfMeasurable (κ : Kernel α β) (f : β → γ) (hf : Measurable f) : + Kernel α γ where toFun a := (κ a).map f measurable' := (Measure.measurable_map _ hf).comp (Kernel.measurable κ) -theorem map_apply (κ : Kernel α β) (hf : Measurable f) (a : α) : map κ f hf a = (κ a).map f := - rfl +open Classical in +/-- The pushforward of a kernel along a function. +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 [MeasurableSpace γ] (κ : Kernel α β) (f : β → γ) : Kernel α γ := + if hf : Measurable f then mapOfMeasurable κ f hf else 0 + +theorem map_of_not_measurable (κ : Kernel α β) {f : β → γ} (hf : ¬(Measurable f)) : + map κ f = 0 := by + simp [map, hf] + +@[simp] theorem mapOfMeasurable_eq_map (κ : Kernel α β) {f : β → γ} (hf : Measurable f) : + mapOfMeasurable κ f hf = map κ f := by + simp [map, hf] + +theorem map_apply (κ : Kernel α β) (hf : Measurable f) (a : α) : map κ f a = (κ a).map f := by + simp only [map, hf, ↓reduceDIte, mapOfMeasurable, coe_mk] theorem map_apply' (κ : Kernel α β) (hf : Measurable f) (a : α) {s : Set γ} (hs : MeasurableSet s) : - map κ f hf a s = κ a (f ⁻¹' s) := by rw [map_apply, Measure.map_apply hf hs] + map κ f a s = κ a (f ⁻¹' s) := by rw [map_apply _ hf, Measure.map_apply hf hs] @[simp] -lemma map_zero (hf : Measurable f) : Kernel.map (0 : Kernel α β) f hf = 0 := by - ext; rw [Kernel.map_apply]; simp +lemma map_zero : Kernel.map (0 : Kernel α β) f = 0 := by + ext + by_cases hf : Measurable f + · simp [map_apply, hf] + · simp [map_of_not_measurable _ hf, map_apply] @[simp] -lemma map_id (κ : Kernel α β) : map κ id measurable_id = κ := by ext a; rw [map_apply]; simp +lemma map_id (κ : Kernel α β) : map κ id = κ := by + ext a + simp [map_apply, measurable_id] @[simp] -lemma map_id' (κ : Kernel α β) : map κ (fun a ↦ a) measurable_id = κ := map_id κ +lemma map_id' (κ : Kernel α β) : map κ (fun a ↦ a) = κ := map_id κ nonrec theorem lintegral_map (κ : Kernel α β) (hf : Measurable f) (a : α) {g' : γ → ℝ≥0∞} - (hg : Measurable g') : ∫⁻ b, g' b ∂map κ f hf a = ∫⁻ a, g' (f a) ∂κ a := by + (hg : Measurable g') : ∫⁻ b, g' b ∂map κ f a = ∫⁻ a, g' (f a) ∂κ a := by rw [map_apply _ hf, lintegral_map hg hf] -theorem sum_map_seq (κ : Kernel α β) [IsSFiniteKernel κ] (hf : Measurable f) : - (Kernel.sum fun n => map (seq κ n) f hf) = map κ f hf := by - ext a s hs - rw [Kernel.sum_apply, map_apply' κ hf a hs, Measure.sum_apply _ hs, ← measure_sum_seq κ, - Measure.sum_apply _ (hf hs)] - simp_rw [map_apply' _ hf _ hs] +theorem sum_map_seq (κ : Kernel α β) [IsSFiniteKernel κ] (f : β → γ) : + (Kernel.sum fun n => map (seq κ n) f) = map κ f := by + by_cases hf : Measurable f + · ext a s hs + rw [Kernel.sum_apply, map_apply' κ hf a hs, Measure.sum_apply _ hs, ← measure_sum_seq κ, + Measure.sum_apply _ (hf hs)] + simp_rw [map_apply' _ hf _ hs] + · simp [map_of_not_measurable _ hf] -instance IsMarkovKernel.map (κ : Kernel α β) [IsMarkovKernel κ] (hf : Measurable f) : - IsMarkovKernel (map κ f hf) := +lemma IsMarkovKernel.map (κ : Kernel α β) [IsMarkovKernel κ] (hf : Measurable f) : + IsMarkovKernel (map κ f) := ⟨fun a => ⟨by rw [map_apply' κ hf a MeasurableSet.univ, Set.preimage_univ, measure_univ]⟩⟩ -instance IsFiniteKernel.map (κ : Kernel α β) [IsFiniteKernel κ] (hf : Measurable f) : - IsFiniteKernel (map κ f hf) := by +instance IsZeroOrMarkovKernel.map (κ : Kernel α β) [IsZeroOrMarkovKernel κ] (f : β → γ) : + IsZeroOrMarkovKernel (map κ f) := by + by_cases hf : Measurable f + · rcases eq_zero_or_isMarkovKernel κ with rfl | h + · simp only [map_zero]; infer_instance + · have := IsMarkovKernel.map κ hf; infer_instance + · simp only [map_of_not_measurable _ hf]; infer_instance + +instance IsFiniteKernel.map (κ : Kernel α β) [IsFiniteKernel κ] (f : β → γ) : + IsFiniteKernel (map κ f) := by refine ⟨⟨IsFiniteKernel.bound κ, IsFiniteKernel.bound_lt_top κ, fun a => ?_⟩⟩ - rw [map_apply' κ hf a MeasurableSet.univ] - exact measure_le_bound κ a _ + by_cases hf : Measurable f + · rw [map_apply' κ hf a MeasurableSet.univ] + exact measure_le_bound κ a _ + · simp [map_of_not_measurable _ hf] -instance IsSFiniteKernel.map (κ : Kernel α β) [IsSFiniteKernel κ] (hf : Measurable f) : - IsSFiniteKernel (map κ f hf) := - ⟨⟨fun n => Kernel.map (seq κ n) f hf, inferInstance, (sum_map_seq κ hf).symm⟩⟩ +instance IsSFiniteKernel.map (κ : Kernel α β) [IsSFiniteKernel κ] (f : β → γ) : + IsSFiniteKernel (map κ f) := + ⟨⟨fun n => Kernel.map (seq κ n) f, inferInstance, (sum_map_seq κ f).symm⟩⟩ @[simp] lemma map_const (μ : Measure α) {f : α → β} (hf : Measurable f) : - map (const γ μ) f hf = const γ (μ.map f) := by + map (const γ μ) f = const γ (μ.map f) := by ext x s hs - rw [map_apply' _ _ _ hs, const_apply, const_apply, Measure.map_apply hf hs] + rw [map_apply' _ hf _ hs, const_apply, const_apply, Measure.map_apply hf hs] /-- Pullback of a kernel, such that for each set s `comap κ g hg c s = κ (g c) s`. We include measurability in the assumptions instead of using junk values @@ -690,9 +707,9 @@ instance IsSFiniteKernel.comap (κ : Kernel α β) [IsSFiniteKernel κ] (hg : Me lemma comap_map_comm (κ : Kernel β γ) {f : α → β} {g : γ → δ} (hf : Measurable f) (hg : Measurable g) : - comap (map κ g hg) f hf = map (comap κ f hf) g hg := by + comap (map κ g) f hf = map (comap κ f hf) g := by ext x s _ - rw [comap_apply, map_apply, map_apply, comap_apply] + rw [comap_apply, map_apply _ hg, map_apply _ hg, comap_apply] end MapComap @@ -778,13 +795,19 @@ lemma isSFiniteKernel_prodMkRight_unit {κ : Kernel α β} : change IsSFiniteKernel ((prodMkRight Unit κ).comap (fun a ↦ (a, ())) (by fun_prop)) infer_instance -lemma map_prodMkLeft (γ : Type*) [MeasurableSpace γ] (κ : Kernel α β) - {f : β → δ} (hf : Measurable f) : - map (prodMkLeft γ κ) f hf = prodMkLeft γ (map κ f hf) := rfl +lemma map_prodMkLeft (γ : Type*) [MeasurableSpace γ] (κ : Kernel α β) (f : β → δ) : + map (prodMkLeft γ κ) f = prodMkLeft γ (map κ f) := by + by_cases hf : Measurable f + · simp only [map, hf, ↓reduceDIte] + rfl + · simp [map_of_not_measurable _ hf] -lemma map_prodMkRight (κ : Kernel α β) (γ : Type*) [MeasurableSpace γ] - {f : β → δ} (hf : Measurable f) : - map (prodMkRight γ κ) f hf = prodMkRight γ (map κ f hf) := rfl +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] + rfl + · simp [map_of_not_measurable _ hf] /-- Define a `Kernel (β × α) γ` from a `Kernel (α × β) γ` by taking the comap of `Prod.swap`. -/ def swapLeft (κ : Kernel (α × β) γ) : Kernel (β × α) γ := @@ -809,15 +832,19 @@ 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`. -/ +/-- Define a `Kernel α (γ × β)` from a `Kernel α (β × γ)` by taking the map of `Prod.swap`. +We use `mapOfMeasurable` in the definition for better defeqs. -/ noncomputable def swapRight (κ : Kernel α (β × γ)) : Kernel α (γ × β) := - map κ Prod.swap measurable_swap + mapOfMeasurable κ Prod.swap measurable_swap + +lemma swapRight_eq (κ : Kernel α (β × γ)) : swapRight κ = map κ Prod.swap := by + simp [swapRight] theorem swapRight_apply (κ : Kernel α (β × γ)) (a : α) : swapRight κ a = (κ a).map Prod.swap := rfl @@ -828,20 +855,27 @@ theorem swapRight_apply' (κ : Kernel α (β × γ)) (a : α) {s : Set (γ × β theorem lintegral_swapRight (κ : Kernel α (β × γ)) (a : α) {g : γ × β → ℝ≥0∞} (hg : Measurable g) : ∫⁻ c, g c ∂swapRight κ a = ∫⁻ bc : β × γ, g bc.swap ∂κ a := by - rw [swapRight, lintegral_map _ measurable_swap a hg] + rw [swapRight_eq, lintegral_map _ measurable_swap a hg] instance IsMarkovKernel.swapRight (κ : Kernel α (β × γ)) [IsMarkovKernel κ] : - IsMarkovKernel (swapRight κ) := by rw [Kernel.swapRight]; infer_instance + IsMarkovKernel (swapRight κ) := by + rw [Kernel.swapRight_eq]; exact IsMarkovKernel.map _ measurable_swap + +instance IsZeroOrMarkovKernel.swapRight (κ : Kernel α (β × γ)) [IsZeroOrMarkovKernel κ] : + IsZeroOrMarkovKernel (swapRight κ) := by rw [Kernel.swapRight_eq]; infer_instance instance IsFiniteKernel.swapRight (κ : Kernel α (β × γ)) [IsFiniteKernel κ] : - IsFiniteKernel (swapRight κ) := by rw [Kernel.swapRight]; infer_instance + IsFiniteKernel (swapRight κ) := by rw [Kernel.swapRight_eq]; infer_instance instance IsSFiniteKernel.swapRight (κ : Kernel α (β × γ)) [IsSFiniteKernel κ] : - IsSFiniteKernel (swapRight κ) := by rw [Kernel.swapRight]; infer_instance + IsSFiniteKernel (swapRight κ) := by rw [Kernel.swapRight_eq]; infer_instance -/-- Define a `Kernel α β` from a `Kernel α (β × γ)` by taking the map of the first projection. -/ +/-- Define a `Kernel α β` from a `Kernel α (β × γ)` by taking the map of the first projection. +We use `mapOfMeasurable` for better defeqs. -/ noncomputable def fst (κ : Kernel α (β × γ)) : Kernel α β := - map κ Prod.fst measurable_fst + mapOfMeasurable κ Prod.fst measurable_fst + +theorem fst_eq (κ : Kernel α (β × γ)) : fst κ = map κ Prod.fst := by simp [fst] theorem fst_apply (κ : Kernel α (β × γ)) (a : α) : fst κ a = (κ a).map Prod.fst := rfl @@ -854,16 +888,20 @@ lemma fst_zero : fst (0 : Kernel α (β × γ)) = 0 := by simp [fst] theorem lintegral_fst (κ : Kernel α (β × γ)) (a : α) {g : β → ℝ≥0∞} (hg : Measurable g) : ∫⁻ c, g c ∂fst κ a = ∫⁻ bc : β × γ, g bc.fst ∂κ a := by - rw [fst, lintegral_map _ measurable_fst a hg] + rw [fst_eq, lintegral_map _ measurable_fst a hg] instance IsMarkovKernel.fst (κ : Kernel α (β × γ)) [IsMarkovKernel κ] : IsMarkovKernel (fst κ) := by - rw [Kernel.fst]; infer_instance + rw [Kernel.fst_eq]; exact IsMarkovKernel.map _ measurable_fst + +instance IsZeroOrMarkovKernel.fst (κ : Kernel α (β × γ)) [IsZeroOrMarkovKernel κ] : + IsZeroOrMarkovKernel (fst κ) := by + rw [Kernel.fst_eq]; infer_instance instance IsFiniteKernel.fst (κ : Kernel α (β × γ)) [IsFiniteKernel κ] : IsFiniteKernel (fst κ) := by - rw [Kernel.fst]; infer_instance + rw [Kernel.fst_eq]; infer_instance instance IsSFiniteKernel.fst (κ : Kernel α (β × γ)) [IsSFiniteKernel κ] : - IsSFiniteKernel (fst κ) := by rw [Kernel.fst]; infer_instance + IsSFiniteKernel (fst κ) := by rw [Kernel.fst_eq]; infer_instance instance (priority := 100) isFiniteKernel_of_isFiniteKernel_fst {κ : Kernel α (β × γ)} [h : IsFiniteKernel (fst κ)] : @@ -872,18 +910,21 @@ instance (priority := 100) isFiniteKernel_of_isFiniteKernel_fst {κ : Kernel α rw [fst_apply' _ _ MeasurableSet.univ] simp -lemma fst_map_prod (κ : Kernel α β) {f : β → γ} {g : β → δ} - (hf : Measurable f) (hg : Measurable g) : - fst (map κ (fun x ↦ (f x, g x)) (hf.prod_mk hg)) = map κ f hf := by - ext x s hs - rw [fst_apply' _ _ hs, map_apply', map_apply' _ _ _ hs] - · rfl - · exact measurable_fst hs +lemma fst_map_prod (κ : Kernel α β) {f : β → γ} {g : β → δ} (hg : Measurable g) : + 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] + · 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 + simp [map_of_not_measurable _ hf, map_of_not_measurable _ this] lemma fst_map_id_prod (κ : Kernel α β) {γ : Type*} {mγ : MeasurableSpace γ} {f : β → γ} (hf : Measurable f) : - fst (map κ (fun a ↦ (a, f a)) (measurable_id.prod_mk hf)) = κ := by - rw [fst_map_prod _ measurable_id' hf, Kernel.map_id'] + fst (map κ (fun a ↦ (a, f a))) = κ := by + rw [fst_map_prod _ hf, Kernel.map_id'] @[simp] lemma fst_compProd (κ : Kernel α β) (η : Kernel (α × β) γ) [IsSFiniteKernel κ] [IsMarkovKernel η] : @@ -905,9 +946,12 @@ lemma fst_prodMkLeft (δ : Type*) [MeasurableSpace δ] (κ : Kernel α (β × γ lemma fst_prodMkRight (κ : Kernel α (β × γ)) (δ : Type*) [MeasurableSpace δ] : fst (prodMkRight δ κ) = prodMkRight δ (fst κ) := rfl -/-- Define a `Kernel α γ` from a `Kernel α (β × γ)` by taking the map of the second projection. -/ +/-- Define a `Kernel α γ` from a `Kernel α (β × γ)` by taking the map of the second projection. +We use `mapOfMeasurable` for better defeqs. -/ noncomputable def snd (κ : Kernel α (β × γ)) : Kernel α γ := - map κ Prod.snd measurable_snd + mapOfMeasurable κ Prod.snd measurable_snd + +theorem snd_eq (κ : Kernel α (β × γ)) : snd κ = map κ Prod.snd := by simp [snd] theorem snd_apply (κ : Kernel α (β × γ)) (a : α) : snd κ a = (κ a).map Prod.snd := rfl @@ -920,16 +964,20 @@ lemma snd_zero : snd (0 : Kernel α (β × γ)) = 0 := by simp [snd] theorem lintegral_snd (κ : Kernel α (β × γ)) (a : α) {g : γ → ℝ≥0∞} (hg : Measurable g) : ∫⁻ c, g c ∂snd κ a = ∫⁻ bc : β × γ, g bc.snd ∂κ a := by - rw [snd, lintegral_map _ measurable_snd a hg] + rw [snd_eq, lintegral_map _ measurable_snd a hg] instance IsMarkovKernel.snd (κ : Kernel α (β × γ)) [IsMarkovKernel κ] : IsMarkovKernel (snd κ) := by - rw [Kernel.snd]; infer_instance + rw [Kernel.snd_eq]; exact IsMarkovKernel.map _ measurable_snd + +instance IsZeroOrMarkovKernel.snd (κ : Kernel α (β × γ)) [IsZeroOrMarkovKernel κ] : + IsZeroOrMarkovKernel (snd κ) := by + rw [Kernel.snd_eq]; infer_instance instance IsFiniteKernel.snd (κ : Kernel α (β × γ)) [IsFiniteKernel κ] : IsFiniteKernel (snd κ) := by - rw [Kernel.snd]; infer_instance + rw [Kernel.snd_eq]; infer_instance instance IsSFiniteKernel.snd (κ : Kernel α (β × γ)) [IsSFiniteKernel κ] : - IsSFiniteKernel (snd κ) := by rw [Kernel.snd]; infer_instance + IsSFiniteKernel (snd κ) := by rw [Kernel.snd_eq]; infer_instance instance (priority := 100) isFiniteKernel_of_isFiniteKernel_snd {κ : Kernel α (β × γ)} [h : IsFiniteKernel (snd κ)] : @@ -938,18 +986,21 @@ instance (priority := 100) isFiniteKernel_of_isFiniteKernel_snd {κ : Kernel α rw [snd_apply' _ _ MeasurableSet.univ] simp -lemma snd_map_prod (κ : Kernel α β) {f : β → γ} {g : β → δ} - (hf : Measurable f) (hg : Measurable g) : - snd (map κ (fun x ↦ (f x, g x)) (hf.prod_mk hg)) = map κ g hg := by - ext x s hs - rw [snd_apply' _ _ hs, map_apply', map_apply' _ _ _ hs] - · rfl - · exact measurable_snd hs +lemma snd_map_prod (κ : Kernel α β) {f : β → γ} {g : β → δ} (hf : Measurable f) : + snd (map κ (fun x ↦ (f x, g x))) = map κ g := by + by_cases hg : Measurable g + · ext x s hs + rw [snd_apply' _ _ hs, map_apply' _ (hf.prod hg), map_apply' _ hg _ hs] + · 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 + simp [map_of_not_measurable _ hg, map_of_not_measurable _ this] lemma snd_map_prod_id (κ : Kernel α β) {γ : Type*} {mγ : MeasurableSpace γ} {f : β → γ} (hf : Measurable f) : - snd (map κ (fun a ↦ (f a, a)) (hf.prod_mk measurable_id)) = κ := by - rw [snd_map_prod _ hf measurable_id', Kernel.map_id'] + snd (map κ (fun a ↦ (f a, a))) = κ := by + rw [snd_map_prod _ hf, Kernel.map_id'] lemma snd_prodMkLeft (δ : Type*) [MeasurableSpace δ] (κ : Kernel α (β × γ)) : snd (prodMkLeft δ κ) = prodMkLeft δ (snd κ) := rfl @@ -985,6 +1036,7 @@ noncomputable def comp (η : Kernel β γ) (κ : Kernel α β) : Kernel α γ wh toFun a := (κ a).bind η measurable' := (Measure.measurable_bind' η.measurable).comp κ.measurable +@[inherit_doc] scoped[ProbabilityTheory] infixl:100 " ∘ₖ " => ProbabilityTheory.Kernel.comp theorem comp_apply (η : Kernel β γ) (κ : Kernel α β) (a : α) : (η ∘ₖ κ) a = (κ a).bind η := @@ -1022,9 +1074,9 @@ theorem comp_assoc {δ : Type*} {mδ : MeasurableSpace δ} (ξ : Kernel γ δ) [ simp_rw [lintegral_comp _ _ _ hf, lintegral_comp _ _ _ hf.lintegral_kernel] theorem deterministic_comp_eq_map (hf : Measurable f) (κ : Kernel α β) : - deterministic f hf ∘ₖ κ = map κ f hf := by + deterministic f hf ∘ₖ κ = map κ f := by ext a s hs - simp_rw [map_apply' _ _ _ hs, comp_apply' _ _ _ hs, deterministic_apply' hf _ hs, + simp_rw [map_apply' _ hf _ hs, comp_apply' _ _ _ hs, deterministic_apply' hf _ hs, lintegral_indicator_const_comp hf hs, one_mul] theorem comp_deterministic_eq_comap (κ : Kernel α β) (hg : Measurable g) : @@ -1084,6 +1136,14 @@ theorem lintegral_prod (κ : Kernel α β) [IsSFiniteKernel κ] (η : Kernel α instance IsMarkovKernel.prod (κ : Kernel α β) [IsMarkovKernel κ] (η : Kernel α γ) [IsMarkovKernel η] : IsMarkovKernel (κ ×ₖ η) := by rw [Kernel.prod]; infer_instance +nonrec instance IsZeroOrMarkovKernel.prod (κ : Kernel α β) [h : IsZeroOrMarkovKernel κ] + (η : Kernel α γ) [IsZeroOrMarkovKernel η] : IsZeroOrMarkovKernel (κ ×ₖ η) := by + rcases eq_zero_or_isMarkovKernel κ with rfl | h + · simp only [prod, swapLeft_prodMkLeft, compProd_zero_left]; infer_instance + rcases eq_zero_or_isMarkovKernel η with rfl | h' + · simp only [prod, swapLeft, prodMkLeft_zero, comap_zero, compProd_zero_right]; infer_instance + infer_instance + instance IsFiniteKernel.prod (κ : Kernel α β) [IsFiniteKernel κ] (η : Kernel α γ) [IsFiniteKernel η] : IsFiniteKernel (κ ×ₖ η) := by rw [Kernel.prod]; infer_instance diff --git a/Mathlib/Probability/Kernel/CondDistrib.lean b/Mathlib/Probability/Kernel/CondDistrib.lean index b91377a2e288d..35ea2d1cf3e43 100644 --- a/Mathlib/Probability/Kernel/CondDistrib.lean +++ b/Mathlib/Probability/Kernel/CondDistrib.lean @@ -209,7 +209,7 @@ theorem condDistrib_ae_eq_condexp (hX : Measurable X) (hY : Measurable Y) (hs : · exact fun t _ _ => (integrable_toReal_condDistrib hX.aemeasurable hs).integrableOn · intro t ht _ rw [integral_toReal ((measurable_condDistrib hs).mono hX.comap_le le_rfl).aemeasurable - (eventually_of_forall fun ω => measure_lt_top (condDistrib Y X μ (X ω)) _), + (Eventually.of_forall fun ω => measure_lt_top (condDistrib Y X μ (X ω)) _), integral_indicator_const _ (hY hs), Measure.restrict_apply (hY hs), smul_eq_mul, mul_one, inter_comm, setLIntegral_condDistrib_of_measurableSet hX hY.aemeasurable hs ht] · refine (Measurable.stronglyMeasurable ?_).aeStronglyMeasurable' diff --git a/Mathlib/Probability/Kernel/Condexp.lean b/Mathlib/Probability/Kernel/Condexp.lean index 59fb17ba03c8b..b0d43c826a6c7 100644 --- a/Mathlib/Probability/Kernel/Condexp.lean +++ b/Mathlib/Probability/Kernel/Condexp.lean @@ -56,8 +56,9 @@ theorem _root_.MeasureTheory.Integrable.comp_snd_map_prod_id [NormedAddCommGroup end AuxLemmas variable {Ω F : Type*} {m : MeasurableSpace Ω} [mΩ : MeasurableSpace Ω] - [StandardBorelSpace Ω] [Nonempty Ω] {μ : Measure Ω} [IsFiniteMeasure μ] + [StandardBorelSpace Ω] {μ : Measure Ω} [IsFiniteMeasure μ] +open Classical in /-- Kernel associated with the conditional expectation with respect to a σ-algebra. It satisfies `μ[f | m] =ᵐ[μ] fun ω => ∫ y, f y ∂(condexpKernel μ m ω)`. It is defined as the conditional distribution of the identity given the identity, where the second @@ -66,14 +67,25 @@ We use `m ⊓ mΩ` instead of `m` to ensure that it is a sub-σ-algebra of `mΩ` `Kernel.comap` to get a kernel from `m` to `mΩ` instead of from `m ⊓ mΩ` to `mΩ`. -/ noncomputable irreducible_def condexpKernel (μ : Measure Ω) [IsFiniteMeasure μ] (m : MeasurableSpace Ω) : @Kernel Ω Ω m mΩ := - Kernel.comap (@condDistrib Ω Ω Ω mΩ _ _ mΩ (m ⊓ mΩ) id id μ _) id - (measurable_id'' (inf_le_left : m ⊓ mΩ ≤ m)) - -lemma condexpKernel_apply_eq_condDistrib {ω : Ω} : + if _h : Nonempty Ω then + Kernel.comap (@condDistrib Ω Ω Ω mΩ _ _ mΩ (m ⊓ mΩ) id id μ _) id + (measurable_id'' (inf_le_left : m ⊓ mΩ ≤ m)) + else 0 + +lemma condexpKernel_eq (μ : Measure Ω) [IsFiniteMeasure μ] [h : Nonempty Ω] + (m : MeasurableSpace Ω) : + condexpKernel (mΩ := mΩ) μ m = Kernel.comap (@condDistrib Ω Ω Ω mΩ _ _ mΩ (m ⊓ mΩ) id id μ _) id + (measurable_id'' (inf_le_left : m ⊓ mΩ ≤ m)) := by + simp [condexpKernel, h] + +lemma condexpKernel_apply_eq_condDistrib [Nonempty Ω] {ω : Ω} : condexpKernel μ m ω = @condDistrib Ω Ω Ω mΩ _ _ mΩ (m ⊓ mΩ) id id μ _ (id ω) := by - simp_rw [condexpKernel, Kernel.comap_apply] + simp [condexpKernel_eq, Kernel.comap_apply] -instance : IsMarkovKernel (condexpKernel μ m) := by simp only [condexpKernel]; infer_instance +instance : IsMarkovKernel (condexpKernel μ m) := by + rcases isEmpty_or_nonempty Ω with h | h + · exact ⟨fun a ↦ (IsEmpty.false a).elim⟩ + · simp [condexpKernel, h]; infer_instance section Measurability @@ -81,6 +93,7 @@ variable [NormedAddCommGroup F] {f : Ω → F} theorem measurable_condexpKernel {s : Set Ω} (hs : MeasurableSet s) : Measurable[m] fun ω => condexpKernel μ m ω s := by + nontriviality Ω simp_rw [condexpKernel_apply_eq_condDistrib] refine Measurable.mono ?_ (inf_le_left : m ⊓ mΩ ≤ m) le_rfl convert measurable_condDistrib (μ := μ) hs @@ -93,6 +106,7 @@ theorem stronglyMeasurable_condexpKernel {s : Set Ω} (hs : MeasurableSet s) : theorem _root_.MeasureTheory.AEStronglyMeasurable.integral_condexpKernel [NormedSpace ℝ F] (hf : AEStronglyMeasurable f μ) : AEStronglyMeasurable (fun ω => ∫ y, f y ∂condexpKernel μ m ω) μ := by + nontriviality Ω simp_rw [condexpKernel_apply_eq_condDistrib] exact AEStronglyMeasurable.integral_condDistrib (aemeasurable_id'' μ (inf_le_right : m ⊓ mΩ ≤ mΩ)) aemeasurable_id @@ -101,7 +115,8 @@ theorem _root_.MeasureTheory.AEStronglyMeasurable.integral_condexpKernel [Normed theorem aestronglyMeasurable'_integral_condexpKernel [NormedSpace ℝ F] (hf : AEStronglyMeasurable f μ) : AEStronglyMeasurable' m (fun ω => ∫ y, f y ∂condexpKernel μ m ω) μ := by - rw [condexpKernel] + nontriviality Ω + rw [condexpKernel_eq] have h := aestronglyMeasurable'_integral_condDistrib (aemeasurable_id'' μ (inf_le_right : m ⊓ mΩ ≤ mΩ)) aemeasurable_id (hf.comp_snd_map_prod_id (inf_le_right : m ⊓ mΩ ≤ mΩ)) @@ -116,14 +131,16 @@ variable [NormedAddCommGroup F] {f : Ω → F} theorem _root_.MeasureTheory.Integrable.condexpKernel_ae (hf_int : Integrable f μ) : ∀ᵐ ω ∂μ, Integrable f (condexpKernel μ m ω) := by - rw [condexpKernel] + nontriviality Ω + rw [condexpKernel_eq] convert Integrable.condDistrib_ae (aemeasurable_id'' μ (inf_le_right : m ⊓ mΩ ≤ mΩ)) aemeasurable_id (hf_int.comp_snd_map_prod_id (inf_le_right : m ⊓ mΩ ≤ mΩ)) using 1 theorem _root_.MeasureTheory.Integrable.integral_norm_condexpKernel (hf_int : Integrable f μ) : Integrable (fun ω => ∫ y, ‖f y‖ ∂condexpKernel μ m ω) μ := by - rw [condexpKernel] + nontriviality Ω + rw [condexpKernel_eq] convert Integrable.integral_norm_condDistrib (aemeasurable_id'' μ (inf_le_right : m ⊓ mΩ ≤ mΩ)) aemeasurable_id (hf_int.comp_snd_map_prod_id (inf_le_right : m ⊓ mΩ ≤ mΩ)) using 1 @@ -131,7 +148,8 @@ theorem _root_.MeasureTheory.Integrable.integral_norm_condexpKernel (hf_int : In theorem _root_.MeasureTheory.Integrable.norm_integral_condexpKernel [NormedSpace ℝ F] (hf_int : Integrable f μ) : Integrable (fun ω => ‖∫ y, f y ∂condexpKernel μ m ω‖) μ := by - rw [condexpKernel] + nontriviality Ω + rw [condexpKernel_eq] convert Integrable.norm_integral_condDistrib (aemeasurable_id'' μ (inf_le_right : m ⊓ mΩ ≤ mΩ)) aemeasurable_id (hf_int.comp_snd_map_prod_id (inf_le_right : m ⊓ mΩ ≤ mΩ)) using 1 @@ -139,20 +157,25 @@ theorem _root_.MeasureTheory.Integrable.norm_integral_condexpKernel [NormedSpace theorem _root_.MeasureTheory.Integrable.integral_condexpKernel [NormedSpace ℝ F] (hf_int : Integrable f μ) : Integrable (fun ω => ∫ y, f y ∂condexpKernel μ m ω) μ := by - rw [condexpKernel] + nontriviality Ω + rw [condexpKernel_eq] convert Integrable.integral_condDistrib (aemeasurable_id'' μ (inf_le_right : m ⊓ mΩ ≤ mΩ)) aemeasurable_id (hf_int.comp_snd_map_prod_id (inf_le_right : m ⊓ mΩ ≤ mΩ)) using 1 theorem integrable_toReal_condexpKernel {s : Set Ω} (hs : MeasurableSet s) : Integrable (fun ω => (condexpKernel μ m ω s).toReal) μ := by - rw [condexpKernel] + nontriviality Ω + rw [condexpKernel_eq] exact integrable_toReal_condDistrib (aemeasurable_id'' μ (inf_le_right : m ⊓ mΩ ≤ mΩ)) hs end Integrability lemma condexpKernel_ae_eq_condexp' {s : Set Ω} (hs : MeasurableSet s) : (fun ω ↦ (condexpKernel μ m ω s).toReal) =ᵐ[μ] μ⟦s | m ⊓ mΩ⟧ := by + rcases isEmpty_or_nonempty Ω with h | h + · have : μ = 0 := Measure.eq_zero_of_isEmpty μ + simpa [this] using trivial have h := condDistrib_ae_eq_condexp (μ := μ) (measurable_id'' (inf_le_right : m ⊓ mΩ ≤ mΩ)) measurable_id hs simp only [id_eq, MeasurableSpace.comap_id, preimage_id_eq] at h @@ -175,6 +198,9 @@ lemma condexpKernel_ae_eq_trim_condexp theorem condexp_ae_eq_integral_condexpKernel' [NormedAddCommGroup F] {f : Ω → F} [NormedSpace ℝ F] [CompleteSpace F] (hf_int : Integrable f μ) : μ[f|m ⊓ mΩ] =ᵐ[μ] fun ω => ∫ y, f y ∂condexpKernel μ m ω := by + rcases isEmpty_or_nonempty Ω with h | h + · have : μ = 0 := Measure.eq_zero_of_isEmpty μ + simpa [this] using trivial have hX : @Measurable Ω Ω mΩ (m ⊓ mΩ) id := measurable_id.mono le_rfl (inf_le_right : m ⊓ mΩ ≤ mΩ) simp_rw [condexpKernel_apply_eq_condDistrib] have h := condexp_ae_eq_integral_condDistrib_id hX hf_int diff --git a/Mathlib/Probability/Kernel/Defs.lean b/Mathlib/Probability/Kernel/Defs.lean new file mode 100644 index 0000000000000..707e45278f5bc --- /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*) {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⟩⟩ + +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/CDFToKernel.lean b/Mathlib/Probability/Kernel/Disintegration/CDFToKernel.lean index 2f7e71e4e8064..5f9e2e892db19 100644 --- a/Mathlib/Probability/Kernel/Disintegration/CDFToKernel.lean +++ b/Mathlib/Probability/Kernel/Disintegration/CDFToKernel.lean @@ -12,7 +12,7 @@ import Mathlib.Probability.Kernel.Disintegration.MeasurableStieltjes Let `κ : Kernel α (β × ℝ)` and `ν : Kernel α β` be two finite kernels. A function `f : α × β → StieltjesFunction` is called a conditional kernel CDF of `κ` with respect -to `ν` if it is measurable, tends to to 0 at -∞ and to 1 at +∞ for all `p : α × β`, +to `ν` if it is measurable, tends to 0 at -∞ and to 1 at +∞ for all `p : α × β`, `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`. @@ -24,7 +24,7 @@ denoted by `hf.toKernel f` such that `κ = ν ⊗ₖ hf.toKernel f`. Let `κ : Kernel α (β × ℝ)` and `ν : Kernel α β`. * `ProbabilityTheory.IsCondKernelCDF`: a function `f : α × β → StieltjesFunction` is called - a conditional kernel CDF of `κ` with respect to `ν` if it is measurable, tends to to 0 at -∞ and + a conditional kernel CDF of `κ` with respect to `ν` if it is measurable, tends to 0 at -∞ and to 1 at +∞ for all `p : α × β`, if `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`. @@ -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 + · 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 @@ -172,7 +173,7 @@ lemma setLIntegral_stieltjesOfMeasurableRat [IsFiniteKernel κ] (hf : IsRatCondK congr with y simp only [mem_iInter, mem_Iic, Subtype.forall, Subtype.coe_mk] exact ⟨le_of_forall_lt_rat_imp_le, fun hyx q hq ↦ hyx.trans hq.le⟩ - · exact fun i ↦ hs.prod measurableSet_Iic + · exact fun i ↦ (hs.prod measurableSet_Iic).nullMeasurableSet · refine Monotone.directed_ge fun i j hij ↦ ?_ refine prod_subset_prod_iff.mpr (Or.inl ⟨subset_rfl, Iic_subset_Iic.mpr ?_⟩) exact mod_cast hij @@ -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 @@ -355,7 +356,7 @@ lemma _root_.MeasureTheory.Measure.iInf_rat_gt_prod_Iic {ρ : Measure (α × ℝ · refine le_of_forall_lt_rat_imp_le fun q htq ↦ h q ?_ exact mod_cast htq · exact mod_cast hta.le - · exact fun _ => hs.prod measurableSet_Iic + · exact fun _ => (hs.prod measurableSet_Iic).nullMeasurableSet · refine Monotone.directed_ge fun r r' hrr' ↦ prod_subset_prod_iff.mpr (Or.inl ⟨subset_rfl, ?_⟩) refine Iic_subset_Iic.mpr ?_ exact mod_cast hrr' @@ -420,11 +421,11 @@ section IsCondKernelCDF variable {f : α × β → StieltjesFunction} /-- A function `f : α × β → StieltjesFunction` is called a conditional kernel CDF of `κ` with -respect to `ν` if it is measurable, tends to to 0 at -∞ and to 1 at +∞ for all `p : α × β`, +respect to `ν` if it is measurable, tends to 0 at -∞ and to 1 at +∞ for all `p : α × β`, `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 ?_ @@ -585,11 +586,11 @@ lemma setLIntegral_toKernel_prod [IsFiniteKernel κ] (hf : IsCondKernelCDF f κ · exact (Kernel.measurable_coe (hf.toKernel f) ht).comp measurable_prod_mk_left · rw [ht_lintegral] exact measure_ne_top _ _ - · exact eventually_of_forall fun a ↦ measure_mono (subset_univ _) + · exact Eventually.of_forall fun a ↦ measure_mono (subset_univ _) _ = κ a (s ×ˢ univ) - κ a (s ×ˢ t) := by rw [setLIntegral_toKernel_univ hf a hs, ht_lintegral] _ = κ a (s ×ˢ tᶜ) := by - rw [← measure_diff _ (hs.prod ht) (measure_ne_top _ _)] + rw [← measure_diff _ (hs.prod ht).nullMeasurableSet (measure_ne_top _ _)] · rw [prod_diff_prod, compl_eq_univ_diff] simp only [diff_self, empty_prod, union_empty] · rw [prod_subset_prod_iff] @@ -621,21 +622,21 @@ 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 - refine setLIntegral_congr_fun ht₁ (eventually_of_forall fun a ha ↦ ?_) + refine setLIntegral_congr_fun ht₁ (Eventually.of_forall fun a ha ↦ ?_) rw [h_prod_eq_snd a ha] have h_eq2 : ∫⁻ x in t₁ᶜ, hf.toKernel f (a, x) {y : ℝ | (x, y) ∈ t₁ ×ˢ t₂} ∂(ν a) = 0 := by suffices h_eq_zero : ∀ x ∈ t₁ᶜ, hf.toKernel f (a, x) {y : ℝ | (x, y) ∈ t₁ ×ˢ t₂} = 0 by - rw [setLIntegral_congr_fun ht₁.compl (eventually_of_forall h_eq_zero)] + rw [setLIntegral_congr_fun ht₁.compl (Eventually.of_forall h_eq_zero)] 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 @@ -650,7 +651,7 @@ lemma lintegral_toKernel_mem [IsFiniteKernel κ] (hf : IsCondKernelCDF f κ ν) ∫⁻ x, hf.toKernel f (a, x) {y : ℝ | (x, y) ∈ t} ∂(ν a) := by have h_le : (fun x ↦ hf.toKernel f (a, x) {y : ℝ | (x, y) ∈ t}) ≤ᵐ[ν a] fun x ↦ hf.toKernel f (a, x) univ := - eventually_of_forall fun _ ↦ measure_mono (subset_univ _) + Eventually.of_forall fun _ ↦ measure_mono (subset_univ _) rw [lintegral_sub _ _ h_le] · exact Kernel.measurable_kernel_prod_mk_left' ht a refine ((lintegral_mono_ae h_le).trans_lt ?_).ne @@ -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] diff --git a/Mathlib/Probability/Kernel/Disintegration/CondCDF.lean b/Mathlib/Probability/Kernel/Disintegration/CondCDF.lean index 0659092ade23a..22bfd49d0e410 100644 --- a/Mathlib/Probability/Kernel/Disintegration/CondCDF.lean +++ b/Mathlib/Probability/Kernel/Disintegration/CondCDF.lean @@ -50,23 +50,18 @@ noncomputable def IicSnd (r : ℝ) : Measure α := theorem IicSnd_apply (r : ℝ) {s : Set α} (hs : MeasurableSet s) : ρ.IicSnd r s = ρ (s ×ˢ Iic r) := by - rw [IicSnd, fst_apply hs, - restrict_apply' (MeasurableSet.univ.prod (measurableSet_Iic : MeasurableSet (Iic r))), ← - prod_univ, prod_inter_prod, inter_univ, univ_inter] + rw [IicSnd, fst_apply hs, restrict_apply' (MeasurableSet.univ.prod measurableSet_Iic), + univ_prod, Set.prod_eq] theorem IicSnd_univ (r : ℝ) : ρ.IicSnd r univ = ρ (univ ×ˢ Iic r) := IicSnd_apply ρ r MeasurableSet.univ +@[gcongr] theorem IicSnd_mono {r r' : ℝ} (h_le : r ≤ r') : ρ.IicSnd r ≤ ρ.IicSnd r' := by - refine Measure.le_iff.2 fun s hs ↦ ?_ - simp_rw [IicSnd_apply ρ _ hs] - refine measure_mono (prod_subset_prod_iff.mpr (Or.inl ⟨subset_rfl, Iic_subset_Iic.mpr ?_⟩)) - exact mod_cast h_le + unfold IicSnd; gcongr -theorem IicSnd_le_fst (r : ℝ) : ρ.IicSnd r ≤ ρ.fst := by - refine Measure.le_iff.2 fun s hs ↦ ?_ - simp_rw [fst_apply hs, IicSnd_apply ρ r hs] - exact measure_mono (prod_subset_preimage_fst _ _) +theorem IicSnd_le_fst (r : ℝ) : ρ.IicSnd r ≤ ρ.fst := + fst_mono restrict_le_self theorem IicSnd_ac_fst (r : ℝ) : ρ.IicSnd r ≪ ρ.fst := Measure.absolutelyContinuous_of_le (IicSnd_le_fst ρ r) @@ -83,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 @@ -106,8 +99,9 @@ theorem tendsto_IicSnd_atBot [IsFiniteMeasure ρ] {s : Set α} (hs : MeasurableS simp_rw [neg_neg] rw [h_fun_eq] exact h_neg.comp tendsto_neg_atBot_atTop - refine tendsto_measure_iInter (fun q ↦ hs.prod measurableSet_Iic) ?_ ⟨0, measure_ne_top ρ _⟩ - refine fun q r hqr ↦ prod_subset_prod_iff.mpr (Or.inl ⟨subset_rfl, fun x hx ↦ ?_⟩) + refine tendsto_measure_iInter (fun q ↦ (hs.prod measurableSet_Iic).nullMeasurableSet) + ?_ ⟨0, measure_ne_top ρ _⟩ + refine fun q r hqr ↦ Set.prod_mono subset_rfl fun x hx ↦ ?_ simp only [Rat.cast_neg, mem_Iic] at hx ⊢ refine hx.trans (neg_le_neg ?_) exact mod_cast hqr @@ -126,7 +120,7 @@ attribute [local instance] MeasureTheory.Measure.IsFiniteMeasure.IicSnd We build towards the definition of `ProbabilityTheory.condCDF`. We first define `ProbabilityTheory.preCDF`, a function defined on `α × ℚ` with the properties of a cdf almost -everywhere. -/ +everywhere. -/ /-- `preCDF` is the Radon-Nikodym derivative of `ρ.IicSnd` with respect to `ρ.fst` at each `r : ℚ`. This function `ℚ → α → ℝ≥0∞` is such that for almost all `a : α`, the function `ℚ → ℝ≥0∞` diff --git a/Mathlib/Probability/Kernel/Disintegration/Density.lean b/Mathlib/Probability/Kernel/Disintegration/Density.lean index ddd69fe353d44..1e1d4fe17ac12 100644 --- a/Mathlib/Probability/Kernel/Disintegration/Density.lean +++ b/Mathlib/Probability/Kernel/Disintegration/Density.lean @@ -385,7 +385,7 @@ lemma tendsto_densityProcess_atTop_empty_of_antitone (κ : Kernel α (γ × β)) ?_ ?_ ?_ · convert h rw [← prod_iInter, hseq_iInter] - · exact fun m ↦ MeasurableSet.prod (measurableSet_countablePartitionSet _ _) (hseq_meas m) + · exact fun m ↦ ((measurableSet_countablePartitionSet _ _).prod (hseq_meas m)).nullMeasurableSet · intro m m' hmm' simp only [le_eq_subset, prod_subset_prod_iff, subset_rfl, true_and] exact Or.inl <| hseq hmm' @@ -501,21 +501,21 @@ lemma measurable_density_right (κ : Kernel α (γ × β)) (ν : Kernel α γ) lemma density_mono_set (hκν : fst κ ≤ ν) (a : α) (x : γ) {s s' : Set β} (h : s ⊆ s') : density κ ν a x s ≤ density κ ν a x s' := by refine limsup_le_limsup ?_ ?_ ?_ - · exact eventually_of_forall (fun n ↦ densityProcess_mono_set hκν n a x h) + · exact Eventually.of_forall (fun n ↦ densityProcess_mono_set hκν n a x h) · exact isCoboundedUnder_le_of_le atTop (fun i ↦ densityProcess_nonneg _ _ _ _ _ _) · exact isBoundedUnder_of ⟨1, fun n ↦ densityProcess_le_one hκν _ _ _ _⟩ lemma density_nonneg (hκν : fst κ ≤ ν) (a : α) (x : γ) (s : Set β) : 0 ≤ density κ ν a x s := by refine le_limsup_of_frequently_le ?_ ?_ - · exact frequently_of_forall (fun n ↦ densityProcess_nonneg _ _ _ _ _ _) + · exact Frequently.of_forall (fun n ↦ densityProcess_nonneg _ _ _ _ _ _) · exact isBoundedUnder_of ⟨1, fun n ↦ densityProcess_le_one hκν _ _ _ _⟩ lemma density_le_one (hκν : fst κ ≤ ν) (a : α) (x : γ) (s : Set β) : density κ ν a x s ≤ 1 := by refine limsup_le_of_le ?_ ?_ · exact isCoboundedUnder_le_of_le atTop (fun i ↦ densityProcess_nonneg _ _ _ _ _ _) - · exact eventually_of_forall (fun n ↦ densityProcess_le_one hκν _ _ _ _) + · exact Eventually.of_forall (fun n ↦ densityProcess_le_one hκν _ _ _ _) section Integral @@ -543,7 +543,7 @@ lemma tendsto_setIntegral_densityProcess (hκν : fst κ ≤ ν) (𝓝 (∫ x in A, density κ ν a x s ∂(ν a))) := by refine tendsto_setIntegral_of_L1' (μ := ν a) (fun x ↦ density κ ν a x s) (integrable_density hκν a hs) (F := fun i x ↦ densityProcess κ ν i a x s) (l := atTop) - (eventually_of_forall (fun n ↦ integrable_densityProcess hκν _ _ hs)) ?_ A + (Eventually.of_forall (fun n ↦ integrable_densityProcess hκν _ _ hs)) ?_ A refine (tendsto_congr fun n ↦ ?_).mp (tendsto_eLpNorm_one_densityProcess_limitProcess hκν a hs) refine eLpNorm_congr_ae ?_ exact EventuallyEq.rfl.sub (density_ae_eq_limitProcess hκν a hs).symm @@ -599,7 +599,7 @@ lemma setIntegral_density (hκν : fst κ ≤ ν) [IsFiniteKernel ν] have : Aᶜ ×ˢ s = univ ×ˢ s \ A ×ˢ s := by rw [prod_diff_prod, compl_eq_univ_diff] simp - rw [this, measure_diff (by intro x; simp) (hA.prod hs) (measure_ne_top (κ a) _), + rw [this, measure_diff (by intro; simp) (hA.prod hs).nullMeasurableSet (measure_ne_top (κ a) _), ENNReal.toReal_sub_of_le (measure_mono (by intro x; simp)) (measure_ne_top _ _)] rw [eq_tsub_iff_add_eq_of_le, add_comm] · exact h @@ -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 = ∅) @@ -677,7 +674,7 @@ lemma tendsto_integral_density_of_antitone (hκν : fst κ ≤ ν) [IsFiniteKern · simp refine h_cont.tendsto.comp ?_ have h := tendsto_measure_iInter (s := fun m ↦ univ ×ˢ seq m) (μ := κ a) - (fun m ↦ MeasurableSet.univ.prod (hseq_meas m)) ?_ ?_ + (fun m ↦ (MeasurableSet.univ.prod (hseq_meas m)).nullMeasurableSet) ?_ ?_ rotate_left · intro n m hnm x; simp only [mem_prod, mem_univ, true_and]; exact fun h ↦ hseq hnm h · refine ⟨0, measure_ne_top _ _⟩ @@ -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 5f5de66ae8cd4..026257adcaf92 100644 --- a/Mathlib/Probability/Kernel/Disintegration/Integral.lean +++ b/Mathlib/Probability/Kernel/Disintegration/Integral.lean @@ -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) : @@ -187,7 +187,7 @@ lemma setLIntegral_condKernel (hf : Measurable f) {s : Set β} ∫⁻ b in s, ∫⁻ ω in t, f (b, ω) ∂(ρ.condKernel b) ∂ρ.fst = ∫⁻ x in s ×ˢ t, f x ∂ρ := by conv_rhs => rw [← ρ.disintegrate ρ.condKernel] - rw [setLIntegral_compProd hf hs ht] + rw [setLIntegral_compProd hf hs ht] @[deprecated (since := "2024-06-29")] alias set_lintegral_condKernel := setLIntegral_condKernel @@ -294,10 +294,10 @@ theorem Integrable.integral_norm_condKernel {f : α × Ω → F} (hf_int : Integ theorem Integrable.norm_integral_condKernel {f : α × Ω → E} (hf_int : Integrable f ρ) : Integrable (fun x ↦ ‖∫ y, f (x, y) ∂ρ.condKernel x‖) ρ.fst := by refine hf_int.integral_norm_condKernel.mono hf_int.1.integral_condKernel.norm ?_ - refine Filter.eventually_of_forall fun x ↦ ?_ + refine Filter.Eventually.of_forall fun x ↦ ?_ rw [norm_norm] refine (norm_integral_le_integral_norm _).trans_eq (Real.norm_of_nonneg ?_).symm - exact integral_nonneg_of_ae (Filter.eventually_of_forall fun y ↦ norm_nonneg _) + exact integral_nonneg_of_ae (Filter.Eventually.of_forall fun y ↦ norm_nonneg _) theorem Integrable.integral_condKernel {f : α × Ω → E} (hf_int : Integrable f ρ) : Integrable (fun x ↦ ∫ y, f (x, y) ∂ρ.condKernel x) ρ.fst := diff --git a/Mathlib/Probability/Kernel/Disintegration/StandardBorel.lean b/Mathlib/Probability/Kernel/Disintegration/StandardBorel.lean index 1659fdaec44bc..c9a1f8966a14e 100644 --- a/Mathlib/Probability/Kernel/Disintegration/StandardBorel.lean +++ b/Mathlib/Probability/Kernel/Disintegration/StandardBorel.lean @@ -234,22 +234,18 @@ instance instIsMarkovKernelBorelMarkovFromReal (η : Kernel α ℝ) [IsMarkovKer · rw [deterministic_apply] simp [(range_nonempty (embeddingReal Ω)).choose_spec] -/-- For `κ' := map κ (Prod.map (id : β → β) e) (measurable_id.prod_map he.measurable)`, the -hypothesis `hη` is `fst κ' ⊗ₖ η = κ'`. The conclusion of the lemma is -`fst κ ⊗ₖ borelMarkovFromReal Ω η = comapRight (fst κ' ⊗ₖ η) _`. -/ +/-- For `κ' := map κ (Prod.map (id : β → β) e)`, the hypothesis `hη` is `fst κ' ⊗ₖ η = κ'`. +The conclusion of the lemma is `fst κ ⊗ₖ borelMarkovFromReal Ω η = comapRight (fst κ' ⊗ₖ η) _`. -/ lemma compProd_fst_borelMarkovFromReal_eq_comapRight_compProd (κ : Kernel α (β × Ω)) [IsSFiniteKernel κ] (η : Kernel (α × β) ℝ) [IsSFiniteKernel η] - (hη : (fst (map κ (Prod.map (id : β → β) (embeddingReal Ω)) - (measurable_id.prod_map (measurableEmbedding_embeddingReal Ω).measurable))) ⊗ₖ η - = map κ (Prod.map (id : β → β) (embeddingReal Ω)) - (measurable_id.prod_map (measurableEmbedding_embeddingReal Ω).measurable)) : + (hη : (fst (map κ (Prod.map (id : β → β) (embeddingReal Ω)))) ⊗ₖ η + = map κ (Prod.map (id : β → β) (embeddingReal Ω))) : fst κ ⊗ₖ borelMarkovFromReal Ω η - = comapRight (fst (map κ (Prod.map (id : β → β) (embeddingReal Ω)) - (measurable_id.prod_map (measurableEmbedding_embeddingReal Ω).measurable)) ⊗ₖ η) + = comapRight (fst (map κ (Prod.map (id : β → β) (embeddingReal Ω))) ⊗ₖ η) (MeasurableEmbedding.id.prod_mk (measurableEmbedding_embeddingReal Ω)) := by let e := embeddingReal Ω let he := measurableEmbedding_embeddingReal Ω - let κ' := map κ (Prod.map (id : β → β) e) (measurable_id.prod_map he.measurable) + let κ' := map κ (Prod.map (id : β → β) e) have hη' : fst κ' ⊗ₖ η = κ' := hη have h_prod_embed : MeasurableEmbedding (Prod.map (id : β → β) e) := MeasurableEmbedding.id.prod_mk he @@ -258,7 +254,8 @@ lemma compProd_fst_borelMarkovFromReal_eq_comapRight_compProd have h_fst : fst κ' = fst κ := by ext a u unfold_let κ' - rw [fst_apply, map_apply, Measure.map_map measurable_fst h_prod_embed.measurable, fst_apply] + rw [fst_apply, map_apply _ (by fun_prop), + Measure.map_map measurable_fst h_prod_embed.measurable, fst_apply] congr rw [h_fst] ext a t ht : 2 @@ -268,7 +265,7 @@ lemma compProd_fst_borelMarkovFromReal_eq_comapRight_compProd rw [← h_fst] have h_compProd : κ' a (univ ×ˢ range e)ᶜ = 0 := by unfold_let κ' - rw [map_apply'] + rw [map_apply' _ (by fun_prop)] swap; · exact (MeasurableSet.univ.prod he.measurableSet_range).compl suffices Prod.map id e ⁻¹' (univ ×ˢ range e)ᶜ = ∅ by rw [this]; simp ext x @@ -286,26 +283,23 @@ lemma compProd_fst_borelMarkovFromReal_eq_comapRight_compProd rw [piecewise_apply, if_pos] exact ha -/-- For `κ' := map κ (Prod.map (id : β → β) e) (measurable_id.prod_map he.measurable)`, the -hypothesis `hη` is `fst κ' ⊗ₖ η = κ'`. With that hypothesis, -`fst κ ⊗ₖ borelMarkovFromReal κ η = κ`.-/ +/-- For `κ' := map κ (Prod.map (id : β → β) e)`, the hypothesis `hη` is `fst κ' ⊗ₖ η = κ'`. +With that hypothesis, `fst κ ⊗ₖ borelMarkovFromReal κ η = κ`.-/ lemma compProd_fst_borelMarkovFromReal (κ : Kernel α (β × Ω)) [IsSFiniteKernel κ] (η : Kernel (α × β) ℝ) [IsSFiniteKernel η] - (hη : (fst (map κ (Prod.map (id : β → β) (embeddingReal Ω)) - (measurable_id.prod_map (measurableEmbedding_embeddingReal Ω).measurable))) ⊗ₖ η - = map κ (Prod.map (id : β → β) (embeddingReal Ω)) - (measurable_id.prod_map (measurableEmbedding_embeddingReal Ω).measurable)) : + (hη : (fst (map κ (Prod.map (id : β → β) (embeddingReal Ω)))) ⊗ₖ η + = map κ (Prod.map (id : β → β) (embeddingReal Ω))) : fst κ ⊗ₖ borelMarkovFromReal Ω η = κ := by let e := embeddingReal Ω let he := measurableEmbedding_embeddingReal Ω - let κ' := map κ (Prod.map (id : β → β) e) (measurable_id.prod_map he.measurable) + let κ' := map κ (Prod.map (id : β → β) e) have hη' : fst κ' ⊗ₖ η = κ' := hη have h_prod_embed : MeasurableEmbedding (Prod.map (id : β → β) e) := MeasurableEmbedding.id.prod_mk he have : κ = comapRight κ' h_prod_embed := by ext c t : 2 unfold_let κ' - rw [comapRight_apply, map_apply, h_prod_embed.comap_map] + rw [comapRight_apply, map_apply _ (by fun_prop), h_prod_embed.comap_map] conv_rhs => rw [this, ← hη'] exact compProd_fst_borelMarkovFromReal_eq_comapRight_compProd κ η hη @@ -320,9 +314,7 @@ A conditional kernel for `κ : Kernel α (γ × Ω)` where `γ` is countably gen standard Borel. -/ noncomputable def condKernelBorel (κ : Kernel α (γ × Ω)) [IsFiniteKernel κ] : Kernel (α × γ) Ω := - let e := embeddingReal Ω - let he := measurableEmbedding_embeddingReal Ω - let κ' := map κ (Prod.map (id : γ → γ) e) (measurable_id.prod_map he.measurable) + let κ' := map κ (Prod.map (id : γ → γ) (embeddingReal Ω)) borelMarkovFromReal Ω (condKernelReal κ') instance instIsMarkovKernelCondKernelBorel (κ : Kernel α (γ × Ω)) [IsFiniteKernel κ] : @@ -349,9 +341,7 @@ variable (κ : Kernel Unit (α × Ω)) [IsFiniteKernel κ] A conditional kernel for `κ : Kernel Unit (α × Ω)` where `Ω` is standard Borel. -/ noncomputable def condKernelUnitBorel : Kernel (Unit × α) Ω := - let e := embeddingReal Ω - let he := measurableEmbedding_embeddingReal Ω - let κ' := map κ (Prod.map (id : α → α) e) (measurable_id.prod_map he.measurable) + let κ' := map κ (Prod.map (id : α → α) (embeddingReal Ω)) borelMarkovFromReal Ω (condKernelUnitReal κ') instance instIsMarkovKernelCondKernelUnitBorel : IsMarkovKernel κ.condKernelUnitBorel := by diff --git a/Mathlib/Probability/Kernel/Disintegration/Unique.lean b/Mathlib/Probability/Kernel/Disintegration/Unique.lean index a55d8224d6a44..e1b79719abfe1 100644 --- a/Mathlib/Probability/Kernel/Disintegration/Unique.lean +++ b/Mathlib/Probability/Kernel/Disintegration/Unique.lean @@ -91,35 +91,35 @@ theorem eq_condKernel_of_measure_eq_compProd (κ : Kernel α Ω) [IsFiniteKernel rw [hρ'def, Measure.fst_apply, Measure.fst_apply, Measure.map_apply] exacts [rfl, Measurable.prod measurable_fst <| hf.measurable.comp measurable_snd, measurable_fst hs, hs, hs] - have hρ'' : ∀ᵐ x ∂ρ.fst, Kernel.map κ f hf.measurable x = ρ'.condKernel x := by + have hρ'' : ∀ᵐ x ∂ρ.fst, Kernel.map κ f x = ρ'.condKernel x := by rw [← hρ'] - refine eq_condKernel_of_measure_eq_compProd_real (Kernel.map κ f hf.measurable) ?_ + refine eq_condKernel_of_measure_eq_compProd_real (Kernel.map κ f) ?_ ext s hs conv_lhs => rw [hρ'def, hκ] rw [Measure.map_apply (measurable_id.prod_map hf.measurable) hs, hρ', Measure.compProd_apply hs, Measure.compProd_apply (measurable_id.prod_map hf.measurable hs)] congr with a - rw [Kernel.map_apply'] + rw [Kernel.map_apply' _ hf.measurable] exacts [rfl, measurable_prod_mk_left hs] suffices ∀ᵐ x ∂ρ.fst, ∀ s, MeasurableSet s → ρ'.condKernel x s = ρ.condKernel x (f ⁻¹' s) by filter_upwards [hρ'', this] with x hx h - rw [Kernel.map_apply] at hx + rw [Kernel.map_apply _ hf.measurable] at hx ext s hs rw [← Set.preimage_image_eq s hf.injective, ← Measure.map_apply hf.measurable <| hf.measurableSet_image.2 hs, hx, h _ <| hf.measurableSet_image.2 hs] - suffices ρ.map (Prod.map id f) = (ρ.fst ⊗ₘ (Kernel.map ρ.condKernel f hf.measurable)) by + suffices ρ.map (Prod.map id f) = (ρ.fst ⊗ₘ (Kernel.map ρ.condKernel f)) by rw [← hρ'] at this have heq := eq_condKernel_of_measure_eq_compProd_real _ this rw [hρ'] at heq filter_upwards [heq] with x hx s hs - rw [← hx, Kernel.map_apply, Measure.map_apply hf.measurable hs] + rw [← hx, Kernel.map_apply _ hf.measurable, Measure.map_apply hf.measurable hs] ext s hs conv_lhs => rw [← ρ.disintegrate ρ.condKernel] rw [Measure.compProd_apply hs, Measure.map_apply (measurable_id.prod_map hf.measurable) hs, Measure.compProd_apply] · congr with a - rw [Kernel.map_apply'] + rw [Kernel.map_apply' _ hf.measurable] exacts [rfl, measurable_prod_mk_left hs] · exact measurable_id.prod_map hf.measurable hs diff --git a/Mathlib/Probability/Kernel/Integral.lean b/Mathlib/Probability/Kernel/Integral.lean new file mode 100644 index 0000000000000..f259203acbe03 --- /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 t : 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 25fa15ae04f0a..a8ad7e64ece6c 100644 --- a/Mathlib/Probability/Kernel/IntegralCompProd.lean +++ b/Mathlib/Probability/Kernel/IntegralCompProd.lean @@ -84,7 +84,7 @@ theorem hasFiniteIntegral_compProd_iff ⦃f : β × γ → E⦄ (h1f : StronglyM HasFiniteIntegral (fun x => ∫ y, ‖f (x, y)‖ ∂η (a, x)) (κ a) := by simp only [HasFiniteIntegral] rw [Kernel.lintegral_compProd _ _ _ h1f.ennnorm] - have : ∀ x, ∀ᵐ y ∂η (a, x), 0 ≤ ‖f (x, y)‖ := fun x => eventually_of_forall fun y => norm_nonneg _ + have : ∀ x, ∀ᵐ y ∂η (a, x), 0 ≤ ‖f (x, y)‖ := fun x => Eventually.of_forall fun y => norm_nonneg _ simp_rw [integral_eq_lintegral_of_nonneg_ae (this _) (h1f.norm.comp_measurable measurable_prod_mk_left).aestronglyMeasurable, ennnorm_eq_ofReal toReal_nonneg, ofReal_norm_eq_coe_nnnorm] @@ -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)) := @@ -130,11 +130,11 @@ theorem _root_.MeasureTheory.Integrable.integral_compProd [NormedSpace ℝ E] ⦃f : β × γ → E⦄ (hf : Integrable f ((κ ⊗ₖ η) a)) : Integrable (fun x => ∫ y, f (x, y) ∂η (a, x)) (κ a) := Integrable.mono hf.integral_norm_compProd hf.aestronglyMeasurable.integral_kernel_compProd <| - eventually_of_forall fun x => + Eventually.of_forall fun x => (norm_integral_le_integral_norm _).trans_eq <| (norm_of_nonneg <| integral_nonneg_of_ae <| - eventually_of_forall fun y => (norm_nonneg (f (x, y)) : _)).symm + Eventually.of_forall fun y => (norm_nonneg (f (x, y)) : _)).symm /-! ### Bochner integral -/ @@ -199,7 +199,7 @@ theorem Kernel.continuous_integral_integral : rw [continuous_iff_continuousAt]; intro g refine tendsto_integral_of_L1 _ (L1.integrable_coeFn g).integral_compProd - (eventually_of_forall fun h => (L1.integrable_coeFn h).integral_compProd) ?_ + (Eventually.of_forall fun h => (L1.integrable_coeFn h).integral_compProd) ?_ simp_rw [← Kernel.lintegral_fn_integral_sub (fun x => (‖x‖₊ : ℝ≥0∞)) (L1.integrable_coeFn _) (L1.integrable_coeFn g)] @@ -226,7 +226,7 @@ theorem integral_compProd : · simp [integral, hE] apply Integrable.induction · intro c s hs h2s - simp_rw [integral_indicator hs, ← indicator_comp_right, Function.comp, + simp_rw [integral_indicator hs, ← indicator_comp_right, Function.comp_def, integral_indicator (measurable_prod_mk_left hs), MeasureTheory.setIntegral_const, integral_smul_const] congr 1 @@ -249,7 +249,7 @@ theorem integral_compProd : theorem setIntegral_compProd {f : β × γ → E} {s : Set β} {t : Set γ} (hs : MeasurableSet s) (ht : MeasurableSet t) (hf : IntegrableOn f (s ×ˢ t) ((κ ⊗ₖ η) a)) : ∫ z in s ×ˢ t, f z ∂(κ ⊗ₖ η) a = ∫ x in s, ∫ y in t, f (x, y) ∂η (a, x) ∂κ a := by - -- Porting note: `compProd_restrict` needed some explicit argumnts + -- Porting note: `compProd_restrict` needed some explicit arguments rw [← Kernel.restrict_apply (κ ⊗ₖ η) (hs.prod ht), ← compProd_restrict hs ht, integral_compProd] · simp_rw [Kernel.restrict_apply] · rw [compProd_restrict, Kernel.restrict_apply]; exact hf diff --git a/Mathlib/Probability/Kernel/MeasurableIntegral.lean b/Mathlib/Probability/Kernel/MeasurableIntegral.lean index 98543badf7199..dc0acc26cac82 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,14 +63,14 @@ 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 => κ a Set.univ - κ a (Prod.mk a ⁻¹' t') := by ext1 a rw [← Set.diff_inter_self_eq_diff, Set.inter_univ, measure_diff (Set.subset_univ _)] - · exact (@measurable_prod_mk_left α β _ _ a) ht' + · exact (measurable_prod_mk_left ht').nullMeasurableSet · exact measure_ne_top _ _ rw [this] exact Measurable.sub (Kernel.measurable_coe κ MeasurableSet.univ) h_meas @@ -236,7 +235,7 @@ variable {E : Type*} [NormedAddCommGroup E] [IsSFiniteKernel κ] [IsSFiniteKerne 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 @@ -285,11 +284,11 @@ theorem StronglyMeasurable.integral_kernel_prod_right ⦃f : α → β → E⦄ tendsto_integral_of_dominated_convergence (fun y => ‖f x y‖ + ‖f x y‖) (fun n => (s' n x).aestronglyMeasurable) (hfx.norm.add hfx.norm) ?_ ?_ · -- Porting note: was - -- exact fun n => eventually_of_forall fun y => + -- exact fun n => Eventually.of_forall fun y => -- SimpleFunc.norm_approxOn_zero_le _ _ (x, y) n - exact fun n => eventually_of_forall fun y => + exact fun n => Eventually.of_forall fun y => SimpleFunc.norm_approxOn_zero_le hf.measurable (by simp) (x, y) n - · refine eventually_of_forall fun y => SimpleFunc.tendsto_approxOn hf.measurable (by simp) ?_ + · refine Eventually.of_forall fun y => SimpleFunc.tendsto_approxOn hf.measurable (by simp) ?_ apply subset_closure simp [-uncurry_apply_pair] · simp [f', hfx, integral_undef] diff --git a/Mathlib/Probability/Kernel/MeasureCompProd.lean b/Mathlib/Probability/Kernel/MeasureCompProd.lean index 99269703362e9..b2bf06645a1a6 100644 --- a/Mathlib/Probability/Kernel/MeasureCompProd.lean +++ b/Mathlib/Probability/Kernel/MeasureCompProd.lean @@ -30,7 +30,7 @@ open ProbabilityTheory namespace MeasureTheory.Measure variable {α β : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} - {μ : Measure α} {κ η : Kernel α β} + {μ ν : Measure α} {κ η : Kernel α β} /-- The composition-product of a measure and a kernel. -/ noncomputable @@ -67,14 +67,16 @@ lemma compProd_apply_prod [SFinite μ] [IsSFiniteKernel κ] rw [Set.indicator_apply] split_ifs with ha <;> simp [ha] -lemma compProd_congr [SFinite μ] [IsSFiniteKernel κ] [IsSFiniteKernel η] +lemma compProd_congr [IsSFiniteKernel κ] [IsSFiniteKernel η] (h : κ =ᵐ[μ] η) : μ ⊗ₘ κ = μ ⊗ₘ η := by - ext s hs - have : (fun a ↦ κ a (Prod.mk a ⁻¹' s)) =ᵐ[μ] fun a ↦ η a (Prod.mk a ⁻¹' s) := by - filter_upwards [h] with a ha using by rw [ha] - rw [compProd_apply hs, lintegral_congr_ae this, compProd_apply hs] - -lemma ae_compProd_of_ae_ae [SFinite μ] [IsSFiniteKernel κ] {p : α × β → Prop} + by_cases hμ : SFinite μ + · ext s hs + have : (fun a ↦ κ a (Prod.mk a ⁻¹' s)) =ᵐ[μ] fun a ↦ η a (Prod.mk a ⁻¹' s) := by + filter_upwards [h] with a ha using by rw [ha] + rw [compProd_apply hs, lintegral_congr_ae this, compProd_apply hs] + · simp [compProd_of_not_sfinite _ _ hμ] + +lemma ae_compProd_of_ae_ae {p : α × β → Prop} (hp : MeasurableSet {x | p x}) (h : ∀ᵐ a ∂μ, ∀ᵐ b ∂(κ a), p (a, b)) : ∀ᵐ x ∂(μ ⊗ₘ κ), p x := Kernel.ae_compProd_of_ae_ae hp h @@ -89,15 +91,18 @@ lemma ae_compProd_iff [SFinite μ] [IsSFiniteKernel κ] {p : α × β → Prop} (∀ᵐ x ∂(μ ⊗ₘ κ), p x) ↔ ∀ᵐ a ∂μ, ∀ᵐ b ∂(κ a), p (a, b) := Kernel.ae_compProd_iff hp -lemma compProd_add_left (μ ν : Measure α) [SFinite μ] [SFinite ν] (κ : Kernel α β) - [IsSFiniteKernel κ] : +lemma compProd_add_left (μ ν : Measure α) [SFinite μ] [SFinite ν] (κ : Kernel α β) : (μ + ν) ⊗ₘ κ = μ ⊗ₘ κ + ν ⊗ₘ κ := by - rw [Measure.compProd, Kernel.const_add, Kernel.compProd_add_left]; rfl + by_cases hκ : IsSFiniteKernel κ + · simp_rw [Measure.compProd, Kernel.const_add, Kernel.compProd_add_left, Kernel.add_apply] + · simp [compProd_of_not_isSFiniteKernel _ _ hκ] -lemma compProd_add_right (μ : Measure α) [SFinite μ] (κ η : Kernel α β) +lemma compProd_add_right (μ : Measure α) (κ η : Kernel α β) [IsSFiniteKernel κ] [IsSFiniteKernel η] : μ ⊗ₘ (κ + η) = μ ⊗ₘ κ + μ ⊗ₘ η := by - rw [Measure.compProd, Kernel.prodMkLeft_add, Kernel.compProd_add_right]; rfl + by_cases hμ : SFinite μ + · simp_rw [Measure.compProd, Kernel.prodMkLeft_add, Kernel.compProd_add_right, Kernel.add_apply] + · simp [compProd_of_not_sfinite _ _ hμ] section Integral @@ -122,8 +127,8 @@ lemma integrable_compProd_iff [SFinite μ] [IsSFiniteKernel κ] {E : Type*} [Nor Integrable f (μ ⊗ₘ κ) ↔ (∀ᵐ x ∂μ, Integrable (fun y => f (x, y)) (κ x)) ∧ Integrable (fun x => ∫ y, ‖f (x, y)‖ ∂(κ x)) μ := by - rw [Measure.compProd, ProbabilityTheory.integrable_compProd_iff hf] - rfl + simp_rw [Measure.compProd, ProbabilityTheory.integrable_compProd_iff hf, Kernel.prodMkLeft_apply, + Kernel.const_apply] lemma integral_compProd [SFinite μ] [IsSFiniteKernel κ] {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] @@ -172,4 +177,56 @@ instance [IsFiniteMeasure μ] [IsFiniteKernel κ] : IsFiniteMeasure (μ ⊗ₘ instance [IsProbabilityMeasure μ] [IsMarkovKernel κ] : IsProbabilityMeasure (μ ⊗ₘ κ) := by rw [compProd]; infer_instance +section AbsolutelyContinuous + +lemma absolutelyContinuous_compProd_left [SFinite ν] (hμν : μ ≪ ν) (κ : Kernel α β) : + μ ⊗ₘ κ ≪ ν ⊗ₘ κ := by + by_cases hκ : IsSFiniteKernel κ + · have : SFinite μ := sFinite_of_absolutelyContinuous hμν + refine Measure.AbsolutelyContinuous.mk fun s hs hs_zero ↦ ?_ + rw [Measure.compProd_apply hs, lintegral_eq_zero_iff (Kernel.measurable_kernel_prod_mk_left hs)] + at hs_zero ⊢ + exact hμν.ae_eq hs_zero + · simp [compProd_of_not_isSFiniteKernel _ _ hκ] + +lemma absolutelyContinuous_compProd_right [SFinite μ] [IsSFiniteKernel η] + (hκη : ∀ᵐ a ∂μ, κ a ≪ η a) : + μ ⊗ₘ κ ≪ μ ⊗ₘ η := by + by_cases hκ : IsSFiniteKernel κ + · refine Measure.AbsolutelyContinuous.mk fun s hs hs_zero ↦ ?_ + rw [Measure.compProd_apply hs, lintegral_eq_zero_iff (Kernel.measurable_kernel_prod_mk_left hs)] + at hs_zero ⊢ + filter_upwards [hs_zero, hκη] with a ha_zero ha_ac using ha_ac ha_zero + · simp [compProd_of_not_isSFiniteKernel _ _ hκ] + +lemma absolutelyContinuous_compProd [SFinite ν] [IsSFiniteKernel η] + (hμν : μ ≪ ν) (hκη : ∀ᵐ a ∂μ, κ a ≪ η a) : + μ ⊗ₘ κ ≪ ν ⊗ₘ η := + have : SFinite μ := sFinite_of_absolutelyContinuous hμν + (Measure.absolutelyContinuous_compProd_right hκη).trans + (Measure.absolutelyContinuous_compProd_left hμν _) + +lemma absolutelyContinuous_of_compProd [SFinite μ] [IsSFiniteKernel κ] [h_zero : ∀ a, NeZero (κ a)] + (h : μ ⊗ₘ κ ≪ ν ⊗ₘ η) : + μ ≪ ν := by + refine Measure.AbsolutelyContinuous.mk (fun s hs hs0 ↦ ?_) + have h1 : (ν ⊗ₘ η) (s ×ˢ Set.univ) = 0 := by + by_cases hν : SFinite ν + swap; · simp [compProd_of_not_sfinite _ _ hν] + by_cases hη : IsSFiniteKernel η + swap; · simp [compProd_of_not_isSFiniteKernel _ _ hη] + rw [Measure.compProd_apply_prod hs MeasurableSet.univ] + exact setLIntegral_measure_zero _ _ hs0 + have h2 : (μ ⊗ₘ κ) (s ×ˢ Set.univ) = 0 := h h1 + rw [Measure.compProd_apply_prod hs MeasurableSet.univ, lintegral_eq_zero_iff] at h2 + swap; · exact Kernel.measurable_coe _ MeasurableSet.univ + by_contra hμs + have : Filter.NeBot (ae (μ.restrict s)) := by simp [hμs] + obtain ⟨a, ha⟩ : ∃ a, κ a Set.univ = 0 := h2.exists + refine absurd ha ?_ + simp only [Measure.measure_univ_eq_zero] + exact (h_zero a).out + +end AbsolutelyContinuous + end MeasureTheory.Measure diff --git a/Mathlib/Probability/Kernel/RadonNikodym.lean b/Mathlib/Probability/Kernel/RadonNikodym.lean index 7f5426267ce77..d99f2e27d910e 100644 --- a/Mathlib/Probability/Kernel/RadonNikodym.lean +++ b/Mathlib/Probability/Kernel/RadonNikodym.lean @@ -69,9 +69,9 @@ Theorem 1.28 in [O. Kallenberg, Random Measures, Theory and Applications][kallen -/ -open MeasureTheory Set Filter +open MeasureTheory Set Filter ENNReal -open scoped NNReal ENNReal MeasureTheory Topology ProbabilityTheory +open scoped NNReal MeasureTheory Topology ProbabilityTheory namespace ProbabilityTheory.Kernel @@ -88,8 +88,7 @@ noncomputable def rnDerivAux (κ η : Kernel α γ) (a : α) (x : γ) : ℝ := if hα : Countable α then ((κ a).rnDeriv (η a) x).toReal else haveI := hαγ.countableOrCountablyGenerated.resolve_left hα - density (map κ (fun a ↦ (a, ())) - (@measurable_prod_mk_right γ Unit _ inferInstance _)) η a x univ + density (map κ (fun a ↦ (a, ()))) η a x univ lemma rnDerivAux_nonneg (hκη : κ ≤ η) {a : α} {x : γ} : 0 ≤ rnDerivAux κ η a x := by rw [rnDerivAux] @@ -144,7 +143,7 @@ lemma setLIntegral_rnDerivAux (κ η : Kernel α γ) [IsFiniteKernel κ] [IsFini rw [ENNReal.ofReal_toReal hx_lt.ne] · have := hαγ.countableOrCountablyGenerated.resolve_left hα rw [setLIntegral_density ((fst_map_id_prod _ measurable_const).trans_le h_le) _ - MeasurableSet.univ hs, map_apply' _ _ _ (hs.prod MeasurableSet.univ)] + MeasurableSet.univ hs, map_apply' _ (by fun_prop) _ (hs.prod MeasurableSet.univ)] congr with x simp @@ -157,8 +156,7 @@ lemma withDensity_rnDerivAux (κ η : Kernel α γ) [IsFiniteKernel κ] [IsFinit rw [Kernel.withDensity_apply'] swap · exact (measurable_rnDerivAux _ _).ennreal_ofReal - have : ∀ b, (Real.toNNReal b : ℝ≥0∞) = ENNReal.ofReal b := fun _ ↦ rfl - simp_rw [this] + simp_rw [ofNNReal_toNNReal] exact setLIntegral_rnDerivAux κ η a hs lemma withDensity_one_sub_rnDerivAux (κ η : Kernel α γ) [IsFiniteKernel κ] [IsFiniteKernel η] : @@ -217,11 +215,10 @@ lemma measurableSet_mutuallySingularSetSlice (κ η : Kernel α γ) (a : α) : lemma measure_mutuallySingularSetSlice (κ η : Kernel α γ) [IsFiniteKernel κ] [IsFiniteKernel η] (a : α) : η a (mutuallySingularSetSlice κ η a) = 0 := by - have h_coe : ∀ b, (Real.toNNReal b : ℝ≥0∞) = ENNReal.ofReal b := fun _ ↦ rfl suffices withDensity (κ + η) (fun a x ↦ Real.toNNReal (1 - rnDerivAux κ (κ + η) a x)) a {x | 1 ≤ rnDerivAux κ (κ + η) a x} = 0 by rwa [withDensity_one_sub_rnDerivAux κ η] at this - simp_rw [h_coe] + simp_rw [ofNNReal_toNNReal] rw [Kernel.withDensity_apply', lintegral_eq_zero_iff, EventuallyEq, ae_restrict_iff] rotate_left · exact (measurable_const.sub @@ -289,10 +286,9 @@ lemma measurable_singularPart_fun_right (κ η : Kernel α γ) (a : α) : lemma singularPart_compl_mutuallySingularSetSlice (κ η : Kernel α γ) [IsSFiniteKernel κ] [IsSFiniteKernel η] (a : α) : singularPart κ η a (mutuallySingularSetSlice κ η a)ᶜ = 0 := by - have h_coe : ∀ b, (Real.toNNReal b : ℝ≥0∞) = ENNReal.ofReal b := fun _ ↦ rfl rw [singularPart, Kernel.withDensity_apply', lintegral_eq_zero_iff, EventuallyEq, ae_restrict_iff] - all_goals simp_rw [h_coe] + all_goals simp_rw [ofNNReal_toNNReal] rotate_left · exact measurableSet_preimage (measurable_singularPart_fun_right κ η a) (measurableSet_singleton _) @@ -351,7 +347,6 @@ lemma withDensity_rnDeriv_of_subset_compl_mutuallySingularSetSlice [IsFiniteKernel κ] [IsFiniteKernel η] {a : α} {s : Set γ} (hsm : MeasurableSet s) (hs : s ⊆ (mutuallySingularSetSlice κ η a)ᶜ) : withDensity η (rnDeriv κ η) a s = κ a s := by - have h_coe : ∀ b, (Real.toNNReal b : ℝ≥0∞) = ENNReal.ofReal b := fun _ ↦ rfl have : withDensity η (rnDeriv κ η) = withDensity (withDensity (κ + η) (fun a x ↦ Real.toNNReal (1 - rnDerivAux κ (κ + η) a x))) (rnDeriv κ η) := by @@ -374,8 +369,8 @@ lemma withDensity_rnDeriv_of_subset_compl_mutuallySingularSetSlice ENNReal.ofReal (1 - rnDerivAux κ (κ + η) a x)) ∂(κ + η) a _ = ∫⁻ x in s, ENNReal.ofReal (rnDerivAux κ (κ + η) a x) ∂(κ + η) a := by refine setLIntegral_congr_fun hsm (ae_of_all _ fun x hx ↦ ?_) - rw [h_coe, ← ENNReal.ofReal_div_of_pos, div_eq_inv_mul, ← ENNReal.ofReal_mul, ← mul_assoc, - mul_inv_cancel₀, one_mul] + rw [ofNNReal_toNNReal, ← ENNReal.ofReal_div_of_pos, div_eq_inv_mul, ← ENNReal.ofReal_mul, + ← mul_assoc, mul_inv_cancel₀, one_mul] · rw [ne_eq, sub_eq_zero] exact (hs' x hx).ne' · simp [(hs' x hx).le] @@ -391,7 +386,7 @@ lemma mutuallySingular_singularPart (κ η : Kernel α γ) [IsFiniteKernel κ] [ measure_mutuallySingularSetSlice κ η a, singularPart_compl_mutuallySingularSetSlice κ η a⟩ /-- Lebesgue decomposition of a finite kernel `κ` with respect to another one `η`. -`κ` is the sum of an abolutely continuous part `withDensity η (rnDeriv κ η)` and a singular part +`κ` is the sum of an absolutely continuous part `withDensity η (rnDeriv κ η)` and a singular part `singularPart κ η`. -/ lemma rnDeriv_add_singularPart (κ η : Kernel α γ) [IsFiniteKernel κ] [IsFiniteKernel η] : withDensity η (rnDeriv κ η) + singularPart κ η = κ := by diff --git a/Mathlib/Probability/Kernel/WithDensity.lean b/Mathlib/Probability/Kernel/WithDensity.lean index 40aa1c46c8c20..a6d76ca32dd21 100644 --- a/Mathlib/Probability/Kernel/WithDensity.lean +++ b/Mathlib/Probability/Kernel/WithDensity.lean @@ -180,8 +180,8 @@ is finite. -/ theorem isFiniteKernel_withDensity_of_bounded (κ : Kernel α β) [IsFiniteKernel κ] {B : ℝ≥0∞} (hB_top : B ≠ ∞) (hf_B : ∀ a b, f a b ≤ B) : IsFiniteKernel (withDensity κ f) := by by_cases hf : Measurable (Function.uncurry f) - · exact ⟨⟨B * IsFiniteKernel.bound κ, ENNReal.mul_lt_top hB_top (IsFiniteKernel.bound_ne_top κ), - fun a => by + · exact ⟨⟨B * IsFiniteKernel.bound κ, ENNReal.mul_lt_top hB_top.lt_top + (IsFiniteKernel.bound_lt_top κ), fun a => by rw [Kernel.withDensity_apply' κ hf a Set.univ] calc ∫⁻ b in Set.univ, f a b ∂κ a ≤ ∫⁻ _ in Set.univ, B ∂κ a := lintegral_mono (hf_B a) diff --git a/Mathlib/Probability/Martingale/Basic.lean b/Mathlib/Probability/Martingale/Basic.lean index f4d4655f4bb85..08032df92e947 100644 --- a/Mathlib/Probability/Martingale/Basic.lean +++ b/Mathlib/Probability/Martingale/Basic.lean @@ -241,10 +241,10 @@ protected theorem sup {f g : ι → Ω → ℝ} (hf : Submartingale f ℱ μ) (h refine EventuallyLE.sup_le ?_ ?_ · exact EventuallyLE.trans (hf.2.1 i j hij) (condexp_mono (hf.integrable _) (Integrable.sup (hf.integrable j) (hg.integrable j)) - (eventually_of_forall fun x => le_max_left _ _)) + (Eventually.of_forall fun x => le_max_left _ _)) · exact EventuallyLE.trans (hg.2.1 i j hij) (condexp_mono (hg.integrable _) (Integrable.sup (hf.integrable j) (hg.integrable j)) - (eventually_of_forall fun x => le_max_right _ _)) + (Eventually.of_forall fun x => le_max_right _ _)) protected theorem pos {f : ι → Ω → ℝ} (hf : Submartingale f ℱ μ) : Submartingale (f⁺) ℱ μ := hf.sup (martingale_zero _ _ _).submartingale @@ -489,7 +489,7 @@ theorem Submartingale.sum_mul_sub [IsFiniteMeasure μ] {R : ℝ} {ξ f : ℕ → refine submartingale_of_condexp_sub_nonneg_nat hadp hint fun i => ?_ simp only [← Finset.sum_Ico_eq_sub _ (Nat.le_succ _), Finset.sum_apply, Pi.mul_apply, Pi.sub_apply, Nat.Ico_succ_singleton, Finset.sum_singleton] - exact EventuallyLE.trans (EventuallyLE.mul_nonneg (eventually_of_forall (hnonneg _)) + exact EventuallyLE.trans (EventuallyLE.mul_nonneg (Eventually.of_forall (hnonneg _)) (hf.condexp_sub_nonneg (Nat.le_succ _))) (condexp_stronglyMeasurable_mul (hξ _) (((hf.integrable _).sub (hf.integrable _)).bdd_mul hξ.stronglyMeasurable.aestronglyMeasurable (hξbdd _)) diff --git a/Mathlib/Probability/Martingale/BorelCantelli.lean b/Mathlib/Probability/Martingale/BorelCantelli.lean index a210e0652fd50..fe55abdba94f9 100644 --- a/Mathlib/Probability/Martingale/BorelCantelli.lean +++ b/Mathlib/Probability/Martingale/BorelCantelli.lean @@ -39,7 +39,6 @@ open scoped NNReal ENNReal MeasureTheory ProbabilityTheory BigOperators Topology namespace MeasureTheory variable {Ω : Type*} {m0 : MeasurableSpace Ω} {μ : Measure Ω} {ℱ : Filtration ℕ m0} {f : ℕ → Ω → ℝ} - {ω : Ω} /-! ### One sided martingale bound @@ -61,7 +60,7 @@ theorem leastGE_le {i : ℕ} {r : ℝ} (ω : Ω) : leastGE f r i ω ≤ i := -- The following four lemmas shows `leastGE` behaves like a stopped process. Ideally we should -- define `leastGE` as a stopping time and take its stopped process. However, we can't do that --- with our current definition since a stopping time takes only finite indicies. An upcomming +-- with our current definition since a stopping time takes only finite indices. An upcoming -- refactor should hopefully make it possible to have stopping times taking infinity as a value theorem leastGE_mono {n m : ℕ} (hnm : n ≤ m) (r : ℝ) (ω : Ω) : leastGE f r n ω ≤ leastGE f r m ω := hitting_mono hnm @@ -347,8 +346,8 @@ theorem tendsto_sum_indicator_atTop_iff' [IsFiniteMeasure μ] {s : ℕ → Set (s (k + 1)).indicator (1 : Ω → ℝ) ω) atTop atTop ↔ Tendsto (fun n => ∑ k ∈ Finset.range n, (μ[(s (k + 1)).indicator (1 : Ω → ℝ)|ℱ k]) ω) atTop atTop := by - have := tendsto_sum_indicator_atTop_iff (eventually_of_forall fun ω n => ?_) (adapted_process hs) - (integrable_process μ hs) (eventually_of_forall <| process_difference_le s) + have := tendsto_sum_indicator_atTop_iff (Eventually.of_forall fun ω n => ?_) (adapted_process hs) + (integrable_process μ hs) (Eventually.of_forall <| process_difference_le s) swap · rw [process, process, ← sub_nonneg, Finset.sum_apply, Finset.sum_apply, Finset.sum_range_succ_sub_sum] 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 25d10c3496810..9ed222f99b9a3 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 @@ -117,7 +117,7 @@ theorem not_frequently_of_upcrossings_lt_top (hab : a < b) (hω : upcrossings a push_neg intro k induction' k with k ih - · simp only [Nat.zero_eq, zero_le, exists_const] + · simp only [zero_le, exists_const] · obtain ⟨N, hN⟩ := ih obtain ⟨N₁, hN₁, hN₁'⟩ := h₁ N obtain ⟨N₂, hN₂, hN₂'⟩ := h₂ N₁ @@ -163,7 +163,7 @@ theorem Submartingale.upcrossings_ae_lt_top' [IsFiniteMeasure μ] (hf : Submarti · simp_rw [lintegral_add_right _ measurable_const, lintegral_const] exact add_le_add (hbdd _) le_rfl refine ne_of_lt (iSup_lt_iff.2 ⟨R + ‖a‖₊ * μ Set.univ, ENNReal.add_lt_top.2 - ⟨ENNReal.coe_lt_top, ENNReal.mul_lt_top ENNReal.coe_lt_top.ne (measure_ne_top _ _)⟩, + ⟨ENNReal.coe_lt_top, ENNReal.mul_lt_top ENNReal.coe_lt_top (measure_lt_top _ _)⟩, fun n => le_trans ?_ (hR' n)⟩) refine lintegral_mono fun ω => ?_ rw [ENNReal.ofReal_le_iff_le_toReal, ENNReal.coe_toReal, coe_nnnorm] @@ -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 @@ -269,12 +269,12 @@ $(f_n)_n$ is a martingale by the tower property for conditional expectations. Fu $(f_n)_n$ is uniformly integrable in the probability sense. Indeed, as a single function is uniformly integrable in the measure theory sense, for all $\epsilon > 0$, there exists some $\delta > 0$ such that for all measurable set $A$ with $\mu(A) < δ$, we have -$\mathbb{E}|h|\mathbf{1}_A < \epsilon$. So, since for sufficently large $\lambda$, by the Markov +$\mathbb{E}|h|\mathbf{1}_A < \epsilon$. So, since for sufficiently large $\lambda$, by the Markov inequality, we have for all $n$, $$ \mu(|f_n| \ge \lambda) \le \lambda^{-1}\mathbb{E}|f_n| \le \lambda^{-1}\mathbb|g| < \delta, $$ -we have for sufficently large $\lambda$, for all $n$, +we have for sufficiently large $\lambda$, for all $n$, $$ \mathbb{E}|f_n|\mathbf{1}_{|f_n| \ge \lambda} \le \mathbb|g|\mathbf{1}_{|f_n| \ge \lambda} < \epsilon, diff --git a/Mathlib/Probability/Martingale/OptionalSampling.lean b/Mathlib/Probability/Martingale/OptionalSampling.lean index 9f77e4e6fc6c7..535963b759aba 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) @@ -76,7 +76,7 @@ theorem stoppedValue_ae_eq_restrict_eq (h : Martingale f ℱ μ) (hτ : IsStoppi refine Filter.EventuallyEq.trans ?_ (condexp_stopping_time_ae_eq_restrict_eq_const_of_le_const h hτ hτ_le i).symm rw [Filter.EventuallyEq, ae_restrict_iff' (ℱ.le _ _ (hτ.measurableSet_eq i))] - refine Filter.eventually_of_forall fun x hx => ?_ + refine Filter.Eventually.of_forall fun x hx => ?_ rw [Set.mem_setOf_eq] at hx simp_rw [stoppedValue, hx] @@ -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] diff --git a/Mathlib/Probability/Martingale/OptionalStopping.lean b/Mathlib/Probability/Martingale/OptionalStopping.lean index 9ccbef6e43662..fee8f4ea1c1a3 100644 --- a/Mathlib/Probability/Martingale/OptionalStopping.lean +++ b/Mathlib/Probability/Martingale/OptionalStopping.lean @@ -130,7 +130,7 @@ theorem smul_le_stoppedValue_hitting [IsFiniteMeasure μ] (hsub : Submartingale we have `ε • μ {ε ≤ f* n} ≤ ∫ ω in {ε ≤ f* n}, f n` where `f* n ω = max_{k ≤ n}, f k ω`. In some literature, the Doob's maximal inequality refers to what we call Doob's Lp inequality -(which is a corollary of this lemma and will be proved in an upcomming PR). -/ +(which is a corollary of this lemma and will be proved in an upcoming PR). -/ theorem maximal_ineq [IsFiniteMeasure μ] (hsub : Submartingale f 𝒢 μ) (hnonneg : 0 ≤ f) {ε : ℝ≥0} (n : ℕ) : ε • μ {ω | (ε : ℝ) ≤ (range (n + 1)).sup' nonempty_range_succ fun k => f k ω} ≤ ENNReal.ofReal (∫ ω in {ω | (ε : ℝ) ≤ (range (n + 1)).sup' nonempty_range_succ fun k => f k ω}, diff --git a/Mathlib/Probability/Martingale/Upcrossing.lean b/Mathlib/Probability/Martingale/Upcrossing.lean index 95f374d8b4aff..9c8e55e651df7 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 = ⊥ := @@ -176,7 +176,7 @@ variable {a b : ℝ} {f : ι → Ω → ℝ} {N : ι} {n m : ℕ} {ω : Ω} theorem upperCrossingTime_le : upperCrossingTime a b f N n ω ≤ N := by cases n - · simp only [upperCrossingTime_zero, Pi.bot_apply, bot_le, Nat.zero_eq] + · simp only [upperCrossingTime_zero, Pi.bot_apply, bot_le] · simp only [upperCrossingTime_succ, hitting_le] @[simp] @@ -430,7 +430,7 @@ theorem upperCrossingTime_lt_of_le_upcrossingsBefore (hN : 0 < N) (hab : a < b) theorem upperCrossingTime_eq_of_upcrossingsBefore_lt (hab : a < b) (hn : upcrossingsBefore a b f N ω < n) : upperCrossingTime a b f N n ω = N := by refine le_antisymm upperCrossingTime_le (not_lt.1 ?_) - convert not_mem_of_csSup_lt hn (upperCrossingTime_lt_bddAbove hab) + convert not_mem_of_csSup_lt hn (upperCrossingTime_lt_bddAbove hab) using 1 theorem upcrossingsBefore_le (f : ℕ → Ω → ℝ) (ω : Ω) (hab : a < b) : upcrossingsBefore a b f N ω ≤ N := by @@ -448,8 +448,8 @@ theorem crossing_eq_crossing_of_lowerCrossingTime_lt {M : ℕ} (hNM : N ≤ M) have h' : upperCrossingTime a b f N n ω < N := lt_of_le_of_lt upperCrossingTime_le_lowerCrossingTime h induction' n with k ih - · simp only [Nat.zero_eq, upperCrossingTime_zero, bot_eq_zero', eq_self_iff_true, - lowerCrossingTime_zero, true_and_iff, eq_comm] + · simp only [upperCrossingTime_zero, bot_eq_zero', eq_self_iff_true, + 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 @@ -605,7 +605,7 @@ theorem integral_mul_upcrossingsBefore_le_integral [IsFiniteMeasure μ] (hf : Su μ[∑ k ∈ Finset.range N, upcrossingStrat a b f N k * (f (k + 1) - f k)] := by rw [← integral_mul_left] refine integral_mono_of_nonneg ?_ ((hf.sum_upcrossingStrat_mul a b N).integrable N) ?_ - · exact eventually_of_forall fun ω => mul_nonneg (sub_nonneg.2 hab.le) (Nat.cast_nonneg _) + · exact Eventually.of_forall fun ω => mul_nonneg (sub_nonneg.2 hab.le) (Nat.cast_nonneg _) · filter_upwards with ω simpa using mul_upcrossingsBefore_le (hfN ω) hab _ ≤ μ[f N] - μ[f 0] := hf.sum_mul_upcrossingStrat_le @@ -625,11 +625,8 @@ theorem crossing_pos_eq (hab : a < b) : have hf' (ω i) : (f i ω - a)⁺ ≤ 0 ↔ f i ω ≤ a := by rw [posPart_nonpos, sub_nonpos] induction' n with k ih · refine ⟨rfl, ?_⟩ - #adaptation_note /-- nightly-2024-03-16: simp was simp (config := { unfoldPartialApp := true }) only [lowerCrossingTime_zero, hitting, - Set.mem_Icc, Set.mem_Iic, Nat.zero_eq] -/ - simp (config := { unfoldPartialApp := true }) only [lowerCrossingTime_zero, hitting_def, - Set.mem_Icc, Set.mem_Iic, Nat.zero_eq] + Set.mem_Icc, Set.mem_Iic] ext ω split_ifs with h₁ h₂ h₂ · simp_rw [hf'] @@ -794,7 +791,7 @@ theorem Submartingale.mul_lintegral_upcrossings_le_lintegral_pos_part [IsFiniteM intro N rw [ofReal_integral_eq_lintegral_ofReal] · exact (hf.sub_martingale (martingale_const _ _ _)).pos.integrable _ - · exact eventually_of_forall fun ω => posPart_nonneg _ + · exact Eventually.of_forall fun ω => posPart_nonneg _ rw [lintegral_iSup'] · simp_rw [this, ENNReal.mul_iSup, iSup_le_iff] intro N diff --git a/Mathlib/Probability/Moments.lean b/Mathlib/Probability/Moments.lean index f50aedd37546c..3ad21345e302f 100644 --- a/Mathlib/Probability/Moments.lean +++ b/Mathlib/Probability/Moments.lean @@ -71,7 +71,9 @@ theorem centralMoment_one' [IsFiniteMeasure μ] (h_int : Integrable X μ) : simp only [sub_mul, integral_const, smul_eq_mul, one_mul] @[simp] -theorem centralMoment_one [IsProbabilityMeasure μ] : centralMoment X 1 μ = 0 := by +theorem centralMoment_one [IsZeroOrProbabilityMeasure μ] : centralMoment X 1 μ = 0 := by + rcases eq_zero_or_isProbabilityMeasure μ with rfl | h + · simp [centralMoment] by_cases h_int : Integrable X μ · rw [centralMoment_one' h_int] simp only [measure_univ, ENNReal.one_toReal, sub_self, zero_mul] @@ -141,12 +143,11 @@ theorem mgf_zero' : mgf X μ 0 = (μ Set.univ).toReal := by theorem mgf_zero [IsProbabilityMeasure μ] : mgf X μ 0 = 1 := by simp only [mgf_zero', measure_univ, ENNReal.one_toReal] -@[simp] theorem cgf_zero' : cgf X μ 0 = log (μ Set.univ).toReal := by simp only [cgf, mgf_zero'] --- @[simp] -- Porting note: `simp only` already proves this -theorem cgf_zero [IsProbabilityMeasure μ] : cgf X μ 0 = 0 := by - simp only [cgf_zero', measure_univ, ENNReal.one_toReal, log_one] +@[simp] +theorem cgf_zero [IsZeroOrProbabilityMeasure μ] : cgf X μ 0 = 0 := by + rcases eq_zero_or_isProbabilityMeasure μ with rfl | h <;> simp [cgf_zero'] theorem mgf_undef (hX : ¬Integrable (fun ω => exp (t * X ω)) μ) : mgf X μ t = 0 := by simp only [mgf, integral_undef hX] @@ -165,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 ?_ @@ -242,7 +243,7 @@ theorem IndepFun.integrable_exp_mul_add {X Y : Ω → ℝ} (h_indep : IndepFun X simp_rw [Pi.add_apply, mul_add, exp_add] exact (h_indep.exp_mul t t).integrable_mul h_int_X h_int_Y -theorem iIndepFun.integrable_exp_mul_sum [IsProbabilityMeasure μ] {X : ι → Ω → ℝ} +theorem iIndepFun.integrable_exp_mul_sum [IsFiniteMeasure μ] {X : ι → Ω → ℝ} (h_indep : iIndepFun (fun i => 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 @@ -257,9 +258,10 @@ theorem iIndepFun.integrable_exp_mul_sum [IsProbabilityMeasure μ] {X : ι → refine IndepFun.integrable_exp_mul_add ?_ (h_int i (mem_insert_self _ _)) h_rec exact (h_indep.indepFun_finset_sum_of_not_mem h_meas hi_notin_s).symm -theorem iIndepFun.mgf_sum [IsProbabilityMeasure μ] {X : ι → Ω → ℝ} +theorem iIndepFun.mgf_sum {X : ι → Ω → ℝ} (h_indep : iIndepFun (fun i => 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 induction' s using Finset.induction_on with i s hi_notin_s h_rec h_int · simp only [sum_empty, mgf_zero_fun, measure_univ, ENNReal.one_toReal, prod_empty] @@ -270,10 +272,11 @@ theorem iIndepFun.mgf_sum [IsProbabilityMeasure μ] {X : ι → Ω → ℝ} (aestronglyMeasurable_exp_mul_sum fun i _ => h_int' i), h_rec, prod_insert hi_notin_s] -theorem iIndepFun.cgf_sum [IsProbabilityMeasure μ] {X : ι → Ω → ℝ} +theorem iIndepFun.cgf_sum {X : ι → Ω → ℝ} (h_indep : iIndepFun (fun i => 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 simp_rw [cgf] rw [← log_prod _ _ fun j hj => ?_] · rw [h_indep.mgf_sum h_meas] @@ -298,7 +301,7 @@ theorem measure_ge_le_exp_mul_mgf [IsFiniteMeasure μ] (ε : ℝ) (ht : 0 ≤ t) have : exp (t * ε) * (μ {ω | exp (t * ε) ≤ exp (t * X ω)}).toReal ≤ μ[fun ω => exp (t * X ω)] := mul_meas_ge_le_integral_of_nonneg (ae_of_all _ fun x => (exp_pos _).le) h_int _ - rwa [mul_comm (exp (t * ε))⁻¹, ← div_eq_mul_inv, le_div_iff' (exp_pos _)] + rwa [mul_comm (exp (t * ε))⁻¹, ← div_eq_mul_inv, le_div_iff₀' (exp_pos _)] _ = exp (-t * ε) * mgf X μ t := by rw [neg_mul, exp_neg]; rfl /-- **Chernoff bound** on the lower tail of a real random variable. -/ diff --git a/Mathlib/Probability/ProbabilityMassFunction/Basic.lean b/Mathlib/Probability/ProbabilityMassFunction/Basic.lean index ec56f812e2f47..877ecc41e7f9d 100644 --- a/Mathlib/Probability/ProbabilityMassFunction/Basic.lean +++ b/Mathlib/Probability/ProbabilityMassFunction/Basic.lean @@ -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] diff --git a/Mathlib/Probability/ProbabilityMassFunction/Constructions.lean b/Mathlib/Probability/ProbabilityMassFunction/Constructions.lean index 9b85c12e07cf7..31bbe40f16a4b 100644 --- a/Mathlib/Probability/ProbabilityMassFunction/Constructions.lean +++ b/Mathlib/Probability/ProbabilityMassFunction/Constructions.lean @@ -58,7 +58,7 @@ theorem bind_pure_comp : bind p (pure ∘ f) = map f p := rfl theorem map_id : map id p = p := bind_pure _ -theorem map_comp (g : β → γ) : (p.map f).map g = p.map (g ∘ f) := by simp [map, Function.comp] +theorem map_comp (g : β → γ) : (p.map f).map g = p.map (g ∘ f) := by simp [map, Function.comp_def] theorem pure_map (a : α) : (pure a).map f = pure (f a) := pure_bind _ _ @@ -72,7 +72,7 @@ theorem bind_map (p : PMF α) (f : α → β) (q : β → PMF γ) : (p.map f).bi @[simp] theorem map_const : p.map (Function.const α b) = pure b := by - simp only [map, Function.comp, bind_const, Function.const] + simp only [map, Function.comp_def, bind_const, Function.const] section Measure @@ -247,7 +247,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 ec731b0e0b14f..befbc17ee812f 100644 --- a/Mathlib/Probability/ProbabilityMassFunction/Integrals.lean +++ b/Mathlib/Probability/ProbabilityMassFunction/Integrals.lean @@ -35,14 +35,14 @@ theorem integral_eq_tsum (p : PMF α) (f : α → E) (hf : Integrable f p.toMeas congr with x; congr 2 apply PMF.toMeasure_apply_singleton p x (MeasurableSet.singleton _) _ = ∑' a, (p a).toReal • f a := - tsum_subtype_eq_of_support_subset <| by calc + tsum_subtype_eq_of_support_subset <| calc (fun a ↦ (p a).toReal • f a).support ⊆ (fun a ↦ (p a).toReal).support := Function.support_smul_subset_left _ _ _ ⊆ support p := fun x h1 h2 => h1 (by simp [h2]) 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..31a9cbfa903d1 100644 --- a/Mathlib/Probability/ProbabilityMassFunction/Monad.lean +++ b/Mathlib/Probability/ProbabilityMassFunction/Monad.lean @@ -67,9 +67,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 α] 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 23d8793910896..a68d221da2416 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 := @@ -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? @@ -567,18 +567,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 +616,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] @@ -704,7 +703,7 @@ variable [LinearOrder ι] /-- Given a map `u : ι → Ω → E`, the stopped process with respect to `τ` is `u i ω` if `i ≤ τ ω`, and `u (τ ω) ω` otherwise. -Intuitively, the stopped process stops evolving once the stopping time has occured. -/ +Intuitively, the stopped process stops evolving once the stopping time has occurred. -/ def stoppedProcess (u : ι → Ω → β) (τ : Ω → ι) : ι → Ω → β := fun i ω => u (min i (τ ω)) ω theorem stoppedProcess_eq_stoppedValue {u : ι → Ω → β} {τ : Ω → ι} : @@ -806,7 +805,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 +956,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 2f8ff3eb320c1..34d9233a9272f 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 := @@ -119,7 +120,7 @@ theorem truncation_nonneg {f : α → ℝ} (A : ℝ) {x : α} (h : 0 ≤ f x) : theorem _root_.MeasureTheory.AEStronglyMeasurable.memℒp_truncation [IsFiniteMeasure μ] (hf : AEStronglyMeasurable f μ) {A : ℝ} {p : ℝ≥0∞} : Memℒp (truncation f A) p μ := - Memℒp.of_bound hf.truncation |A| (eventually_of_forall fun _ => abs_truncation_le_bound _ _ _) + Memℒp.of_bound hf.truncation |A| (Eventually.of_forall fun _ => abs_truncation_le_bound _ _ _) theorem _root_.MeasureTheory.AEStronglyMeasurable.integrable_truncation [IsFiniteMeasure μ] (hf : AEStronglyMeasurable f μ) {A : ℝ} : Integrable (truncation f A) μ := by @@ -153,7 +154,7 @@ theorem moment_truncation_eq_intervalIntegral_of_nonneg (hf : AEStronglyMeasurab zero_eq_neg] apply integral_eq_zero_of_ae have : ∀ᵐ x ∂Measure.map f μ, (0 : ℝ) ≤ x := - (ae_map_iff hf.aemeasurable measurableSet_Ici).2 (eventually_of_forall h'f) + (ae_map_iff hf.aemeasurable measurableSet_Ici).2 (Eventually.of_forall h'f) filter_upwards [this] with x hx simp only [indicator, Set.mem_Ioc, Pi.zero_apply, ite_eq_right_iff, and_imp] intro _ h''x @@ -172,7 +173,7 @@ theorem integral_truncation_eq_intervalIntegral_of_nonneg (hf : AEStronglyMeasur theorem integral_truncation_le_integral_of_nonneg (hf : Integrable f μ) (h'f : 0 ≤ f) {A : ℝ} : ∫ x, truncation f A x ∂μ ≤ ∫ x, f x ∂μ := by apply integral_mono_of_nonneg - (eventually_of_forall fun x => ?_) hf (eventually_of_forall fun x => ?_) + (Eventually.of_forall fun x => ?_) hf (Eventually.of_forall fun x => ?_) · exact truncation_nonneg _ (h'f x) · calc truncation f A x ≤ |truncation f A x| := le_abs_self _ @@ -184,7 +185,7 @@ integral of the whole function. -/ theorem tendsto_integral_truncation {f : α → ℝ} (hf : Integrable f μ) : Tendsto (fun A => ∫ x, truncation f A x ∂μ) atTop (𝓝 (∫ x, f x ∂μ)) := by refine tendsto_integral_filter_of_dominated_convergence (fun x => abs (f x)) ?_ ?_ ?_ ?_ - · exact eventually_of_forall fun A ↦ hf.aestronglyMeasurable.truncation + · exact Eventually.of_forall fun A ↦ hf.aestronglyMeasurable.truncation · filter_upwards with A filter_upwards with x rw [Real.norm_eq_abs] @@ -285,7 +286,7 @@ theorem tsum_prob_mem_Ioi_lt_top {X : Ω → ℝ} (hint : Integrable X) (hnonneg (∑' j : ℕ, ℙ {ω | X ω ∈ Set.Ioi (j : ℝ)}) < ∞ := by suffices ∀ K : ℕ, ∑ j ∈ range K, ℙ {ω | X ω ∈ Set.Ioi (j : ℝ)} ≤ ENNReal.ofReal (𝔼[X] + 1) from (le_of_tendsto_of_tendsto (ENNReal.tendsto_nat_tsum _) tendsto_const_nhds - (eventually_of_forall this)).trans_lt ENNReal.ofReal_lt_top + (Eventually.of_forall this)).trans_lt ENNReal.ofReal_lt_top intro K have A : Tendsto (fun N : ℕ => ∑ j ∈ range K, ℙ {ω | X ω ∈ Set.Ioc (j : ℝ) N}) atTop (𝓝 (∑ j ∈ range K, ℙ {ω | X ω ∈ Set.Ioi (j : ℝ)})) := by @@ -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 @@ -380,11 +381,11 @@ theorem strong_law_aux1 {c : ℝ} (c_one : 1 < c) {ε : ℝ} (εpos : 0 < ε) : ε * ⌊c ^ n⌋₊ := by /- Let `S n = ∑ i ∈ range n, Y i` where `Y i = truncation (X i) i`. We should show that `|S k - 𝔼[S k]| / k ≤ ε` along the sequence of powers of `c`. For this, we apply Borel-Cantelli: - it suffices to show that the converse probabilites are summable. From Chebyshev inequality, this - will follow from a variance control `∑' Var[S (c^i)] / (c^i)^2 < ∞`. This is checked in `I2` - using pairwise independence to expand the variance of the sum as the sum of the variances, + it suffices to show that the converse probabilities are summable. From Chebyshev inequality, + this will follow from a variance control `∑' Var[S (c^i)] / (c^i)^2 < ∞`. This is checked in + `I2` using pairwise independence to expand the variance of the sum as the sum of the variances, and then a straightforward but tedious computation (essentially boiling down to the fact that - the sum of `1/(c ^ i)^2` beyong a threshold `j` is comparable to `1/j^2`). + the sum of `1/(c ^ i)^2` beyond a threshold `j` is comparable to `1/j^2`). Note that we have written `c^i` in the above proof sketch, but rigorously one should put integer parts everywhere, making things more painful. We write `u i = ⌊c^i⌋₊` for brevity. -/ have c_pos : 0 < c := zero_lt_one.trans c_one @@ -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 @@ -456,7 +457,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 +547,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 +563,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,9 +603,22 @@ 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 (X : ℕ → Ω → ℝ) (hint : Integrable (X 0)) +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 + -- 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 + 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 Ω) := + 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. let pos : ℝ → ℝ := fun x => max x 0 let neg : ℝ → ℝ := fun x => max (-x) 0 have posm : Measurable pos := measurable_id'.max measurable_const @@ -725,7 +739,7 @@ lemma strong_law_ae_of_measurable -- check that, when both convergences above hold, then the strong law is satisfied filter_upwards [A, B] with ω hω h'ω rw [tendsto_iff_norm_sub_tendsto_zero, tendsto_order] - refine ⟨fun c hc ↦ eventually_of_forall (fun n ↦ hc.trans_le (norm_nonneg _)), ?_⟩ + refine ⟨fun c hc ↦ Eventually.of_forall (fun n ↦ hc.trans_le (norm_nonneg _)), ?_⟩ -- start with some positive `ε` (the desired precision), and fix `δ` with `3 δ < ε`. intro ε (εpos : 0 < ε) obtain ⟨δ, δpos, hδ⟩ : ∃ δ, 0 < δ ∧ δ + δ + δ < ε := ⟨ε/4, by positivity, by linarith⟩ @@ -773,10 +787,20 @@ lemma strong_law_ae_of_measurable 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 +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 + -- 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 + 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 Ω) := + 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 @@ -799,7 +823,7 @@ end StrongLawVectorSpace section StrongLawLp -variable {Ω : Type*} [MeasureSpace Ω] [IsProbabilityMeasure (ℙ : Measure Ω)] +variable {Ω : Type*} [MeasureSpace Ω] {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] [CompleteSpace E] [MeasurableSpace E] [BorelSpace E] @@ -808,8 +832,23 @@ identically distributed random variables in Lᵖ, then `n⁻¹ • ∑ i ∈ ran 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 ℙ) + 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 + 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 + 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 + (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 => (hident i).aestronglyMeasurable_iff.2 hℒp.1 have hint : Integrable (X 0) ℙ := hℒp.integrable hp diff --git a/Mathlib/Probability/UniformOn.lean b/Mathlib/Probability/UniformOn.lean new file mode 100644 index 0000000000000..8b1de52a5055d --- /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 b737727f95f56..9b0a9bcb2fe5c 100644 --- a/Mathlib/Probability/Variance.lean +++ b/Mathlib/Probability/Variance.lean @@ -210,7 +210,7 @@ theorem variance_le_expectation_sq [@IsProbabilityMeasure Ω _ ℙ] {X : Ω → apply hX convert A.add B simp - · exact eventually_of_forall fun x => sq_nonneg _ + · 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 ℙ) : @@ -228,7 +228,7 @@ 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 @@ -255,7 +255,7 @@ theorem meas_ge_le_variance_div_sq [@IsFiniteMeasure Ω _ ℙ] {X : Ω → ℝ} (hc : 0 < c) : ℙ {ω | c ≤ |X ω - 𝔼[X]|} ≤ ENNReal.ofReal (Var[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] + · simp only [Real.coe_toNNReal', max_le_iff, abs_nonneg, and_true] · rw [ENNReal.ofReal_pow hc.le] rfl diff --git a/Mathlib/RepresentationTheory/Action/Basic.lean b/Mathlib/RepresentationTheory/Action/Basic.lean index 6002bcee80785..e09c00af54f4e 100644 --- a/Mathlib/RepresentationTheory/Action/Basic.lean +++ b/Mathlib/RepresentationTheory/Action/Basic.lean @@ -1,11 +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.Category.Grp.Basic import Mathlib.CategoryTheory.SingleObj -import Mathlib.CategoryTheory.Limits.FunctorCategory +import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic import Mathlib.CategoryTheory.Limits.Preserves.Basic import Mathlib.CategoryTheory.Adjunction.Limits import Mathlib.CategoryTheory.Conj @@ -125,6 +125,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 +155,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`. -/ diff --git a/Mathlib/RepresentationTheory/Action/Concrete.lean b/Mathlib/RepresentationTheory/Action/Concrete.lean index 1ae786bb201e9..e2ebc3a42dff7 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.Basic import Mathlib.RepresentationTheory.Action.Basic /-! @@ -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 a b 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 831b1acf591af..a31d4f9f7196f 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) @@ -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 @@ -308,7 +265,7 @@ each factor. -/ @[simps!] noncomputable def diagonalSucc (G : Type u) [Monoid G] (n : ℕ) : diagonal G (n + 1) ≅ leftRegular G ⊗ diagonal G n := - mkIso (Equiv.piFinSuccAbove _ 0).toIso fun _ => rfl + mkIso (Fin.consEquiv _).symm.toIso fun _ => rfl end Action diff --git a/Mathlib/RepresentationTheory/Basic.lean b/Mathlib/RepresentationTheory/Basic.lean index 380582b4bd4ce..979151b7da507 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 @@ -371,8 +366,8 @@ tensor product `V ⊗[k] W`. -/ noncomputable def tprod : Representation k G (V ⊗[k] W) where toFun g := TensorProduct.map (ρV g) (ρW g) - map_one' := by simp only [_root_.map_one, TensorProduct.map_one] - map_mul' g h := by simp only [_root_.map_mul, TensorProduct.map_mul] + map_one' := by simp only [map_one, TensorProduct.map_one] + map_mul' g h := by simp only [map_mul, TensorProduct.map_mul] local notation ρV " ⊗ " ρW => tprod ρV ρW diff --git a/Mathlib/RepresentationTheory/Character.lean b/Mathlib/RepresentationTheory/Character.lean index a0566328c0f4a..b68c19284a62c 100644 --- a/Mathlib/RepresentationTheory/Character.lean +++ b/Mathlib/RepresentationTheory/Character.lean @@ -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 be57941de8e9f..1f3f8535f0114 100644 --- a/Mathlib/RepresentationTheory/FDRep.lean +++ b/Mathlib/RepresentationTheory/FDRep.lean @@ -1,12 +1,13 @@ /- -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.RepresentationTheory.Rep import Mathlib.Algebra.Category.FGModuleCat.Limits +import Mathlib.CategoryTheory.Monoidal.Rigid.Braided import Mathlib.CategoryTheory.Preadditive.Schur import Mathlib.RepresentationTheory.Basic +import Mathlib.RepresentationTheory.Rep /-! # `FDRep k G` is the category of finite dimensional `k`-linear representations of `G`. @@ -27,12 +28,10 @@ We verify that `FDRep k G` is a `k`-linear monoidal category, and rigid when `G` `FDRep k G` has all finite limits. ## TODO -* `FDRep k G ≌ FullSubcategory (FiniteDimensional k)` -* Upgrade the right rigid structure to a rigid structure - (this just needs to be done for `FGModuleCat`). -* `FDRep k G` has all finite colimits. -* `FDRep k G` is abelian. -* `FDRep k G ≌ FGModuleCat (MonoidAlgebra k G)`. +* `FdRep k G ≌ FullSubcategory (FiniteDimensional k)` +* `FdRep k G` has all finite colimits. +* `FdRep k G` is abelian. +* `FdRep k G ≌ FGModuleCat (MonoidAlgebra k G)`. -/ @@ -115,11 +114,11 @@ example : MonoidalPreadditive (FDRep k G) := by infer_instance example : MonoidalLinear k (FDRep k G) := by infer_instance -open FiniteDimensional +open Module open scoped Classical --- We need to provide this instance explicitely as otherwise `finrank_hom_simple_simple` gives a +-- We need to provide this instance explicitly as otherwise `finrank_hom_simple_simple` gives a -- deterministic timeout. instance : HasKernels (FDRep k G) := by infer_instance @@ -150,6 +149,8 @@ variable {k G : Type u} [Field k] [Group G] noncomputable instance : RightRigidCategory (FDRep k G) := by change RightRigidCategory (Action (FGModuleCat k) (Grp.of G)); infer_instance +example : RigidCategory (FDRep k G) := by infer_instance + end FDRep namespace FDRep diff --git a/Mathlib/RepresentationTheory/GroupCohomology/Basic.lean b/Mathlib/RepresentationTheory/GroupCohomology/Basic.lean index d12b7df3e9055..3d60e4b43bfb4 100644 --- a/Mathlib/RepresentationTheory/GroupCohomology/Basic.lean +++ b/Mathlib/RepresentationTheory/GroupCohomology/Basic.lean @@ -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/Hilbert90.lean b/Mathlib/RepresentationTheory/GroupCohomology/Hilbert90.lean index 222ef95b2b79e..b666cf6409176 100644 --- a/Mathlib/RepresentationTheory/GroupCohomology/Hilbert90.lean +++ b/Mathlib/RepresentationTheory/GroupCohomology/Hilbert90.lean @@ -55,7 +55,7 @@ variable {K L : Type*} [Field K] [Field L] [Algebra K L] [FiniteDimensional K L] /-- Given `f : Aut_K(L) → Lˣ`, the sum `∑ f(φ) • φ` for `φ ∈ Aut_K(L)`, as a function `L → L`. -/ noncomputable def aux (f : (L ≃ₐ[K] L) → Lˣ) : L → L := - Finsupp.total (L ≃ₐ[K] L) (L → L) L (fun φ => φ) + Finsupp.linearCombination L (fun φ : L ≃ₐ[K] L ↦ (φ : L → L)) (Finsupp.equivFunOnFinite.symm (fun φ => (f φ : L))) theorem aux_ne_zero (f : (L ≃ₐ[K] L) → Lˣ) : aux f ≠ 0 := @@ -83,7 +83,7 @@ theorem isMulOneCoboundary_of_isMulOneCocycle_of_aut_to_units /- Let `z : L` be such that `∑ f(h) * h(z) ≠ 0`, for `h ∈ Aut_K(L)` -/ obtain ⟨z, hz⟩ : ∃ z, aux f z ≠ 0 := not_forall.1 (fun H => aux_ne_zero f <| funext <| fun x => H x) - have : aux f z = ∑ h, f h * h z := by simp [aux, Finsupp.total, Finsupp.sum_fintype] + have : aux f z = ∑ h, f h * h z := by simp [aux, Finsupp.linearCombination, Finsupp.sum_fintype] /- Let `β = (∑ f(h) * h(z))⁻¹.` -/ use (Units.mk0 (aux f z) hz)⁻¹ intro g diff --git a/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean b/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean index c0689ba27a5a7..f8101f22d3a29 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 @@ -39,7 +38,7 @@ The file also contains an identification between the definitions in 1-coboundaries (i.e. `B¹(G, A) := Im(d⁰: A → Fun(G, A))`). * `groupCohomology.H2 A`: 2-cocycles (i.e. `Z²(G, A) := Ker(d² : Fun(G², A) → Fun(G³, A)`) modulo 2-coboundaries (i.e. `B²(G, A) := Im(d¹: Fun(G, A) → Fun(G², A))`). -* `groupCohomology.H1LequivOfIsTrivial`: the isomorphism `H¹(G, A) ≃ Hom(G, A)` when the +* `groupCohomology.H1LequivOfIsTrivial`: the isomorphism `H¹(G, A) ≃ Hom(G, A)` when the representation on `A` is trivial. * `groupCohomology.isoHn` for `n = 0, 1, 2`: an isomorphism `groupCohomology A n ≅ groupCohomology.Hn A`. @@ -82,7 +81,7 @@ def twoCochainsLequiv : (inhomogeneousCochains A).X 2 ≃ₗ[k] G × G → A := /-- The 3rd object in the complex of inhomogeneous cochains of `A : Rep k G` is isomorphic to `Fun(G³, A)` as a `k`-module. -/ def threeCochainsLequiv : (inhomogeneousCochains A).X 3 ≃ₗ[k] G × G × G → A := - LinearEquiv.funCongrLeft k A <| ((Equiv.piFinSucc 2 G).trans + LinearEquiv.funCongrLeft k A <| ((Fin.consEquiv _).symm.trans ((Equiv.refl G).prodCongr (piFinTwoEquiv fun _ => G))).symm end Cochains @@ -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] @@ -337,7 +336,7 @@ theorem oneCoboundaries_of_mem_range_apply {f : G → A} (h : f ∈ LinearMap.ra `ρ(g)(x) - x = f(g)` for all `g : G`. -/ def oneCoboundariesOfEq {f : G → A} {x : A} (hf : ∀ g, A.ρ g x - x = f g) : oneCoboundaries A := - oneCoboundariesOfMemRange ⟨x, by ext g; exact hf g⟩ + oneCoboundariesOfMemRange ⟨x, funext hf⟩ theorem oneCoboundariesOfEq_apply {f : G → A} {x : A} (hf : ∀ g, A.ρ g x - x = f g) : (oneCoboundariesOfEq hf).1.1 = f := rfl @@ -365,7 +364,7 @@ theorem twoCoboundariesOfMemRange_apply {f : G × G → A} (h : f ∈ LinearMap. def twoCoboundariesOfEq {f : G × G → A} {x : G → A} (hf : ∀ g h, A.ρ g (x h) - x (g * h) + x g = f (g, h)) : twoCoboundaries A := - twoCoboundariesOfMemRange ⟨x, by ext g; exact hf g.1 g.2⟩ + twoCoboundariesOfMemRange ⟨x, funext fun g ↦ hf g.1 g.2⟩ theorem twoCoboundariesOfEq_apply {f : G × G → A} {x : G → A} (hf : ∀ g h, A.ρ g (x h) - x (g * h) + x g = f (g, h)) : @@ -465,7 +464,7 @@ theorem isOneCocycle_of_oneCocycles (f : oneCocycles (Rep.ofDistribMulAction k G on `A` induced by the `DistribMulAction`. -/ def oneCoboundariesOfIsOneCoboundary {f : G → A} (hf : IsOneCoboundary f) : oneCoboundaries (Rep.ofDistribMulAction k G A) := - oneCoboundariesOfMemRange (by rcases hf with ⟨x, hx⟩; exact ⟨x, by ext g; exact hx g⟩) + oneCoboundariesOfMemRange ⟨hf.choose, funext hf.choose_spec⟩ theorem isOneCoboundary_of_oneCoboundaries (f : oneCoboundaries (Rep.ofDistribMulAction k G A)) : IsOneCoboundary (A := A) f.1.1 := by @@ -487,7 +486,7 @@ theorem isTwoCocycle_of_twoCocycles (f : twoCocycles (Rep.ofDistribMulAction k G representation on `A` induced by the `DistribMulAction`. -/ def twoCoboundariesOfIsTwoCoboundary {f : G × G → A} (hf : IsTwoCoboundary f) : twoCoboundaries (Rep.ofDistribMulAction k G A) := - twoCoboundariesOfMemRange (by rcases hf with ⟨x, hx⟩; exact ⟨x, by ext g; exact hx g.1 g.2⟩) + twoCoboundariesOfMemRange (⟨hf.choose,funext fun g ↦ hf.choose_spec g.1 g.2⟩) theorem isTwoCoboundary_of_twoCoboundaries (f : twoCoboundaries (Rep.ofDistribMulAction k G A)) : IsTwoCoboundary (A := A) f.1.1 := by @@ -588,8 +587,7 @@ theorem isMulOneCocycle_of_oneCocycles (f : oneCocycles (Rep.ofMulDistribMulActi 1-coboundary for the representation on `Additive M` induced by the `MulDistribMulAction`. -/ def oneCoboundariesOfIsMulOneCoboundary {f : G → M} (hf : IsMulOneCoboundary f) : oneCoboundaries (Rep.ofMulDistribMulAction G M) := - oneCoboundariesOfMemRange (f := Additive.ofMul ∘ f) - (by rcases hf with ⟨x, hx⟩; exact ⟨x, by ext g; exact hx g⟩) + oneCoboundariesOfMemRange (f := Additive.ofMul ∘ f) ⟨hf.choose, funext hf.choose_spec⟩ theorem isMulOneCoboundary_of_oneCoboundaries (f : oneCoboundaries (Rep.ofMulDistribMulAction G M)) : @@ -612,7 +610,7 @@ theorem isMulTwoCocycle_of_twoCocycles (f : twoCocycles (Rep.ofMulDistribMulActi 2-coboundary for the representation on `M` induced by the `MulDistribMulAction`. -/ def twoCoboundariesOfIsMulTwoCoboundary {f : G × G → M} (hf : IsMulTwoCoboundary f) : twoCoboundaries (Rep.ofMulDistribMulAction G M) := - twoCoboundariesOfMemRange (by rcases hf with ⟨x, hx⟩; exact ⟨x, by ext g; exact hx g.1 g.2⟩) + twoCoboundariesOfMemRange ⟨hf.choose, funext fun g ↦ hf.choose_spec g.1 g.2⟩ theorem isMulTwoCoboundary_of_twoCoboundaries (f : twoCoboundaries (Rep.ofMulDistribMulAction G M)) : @@ -717,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) @@ -765,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] @@ -775,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 @@ -813,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] @@ -823,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 e1fdb9f4e2b18..9d4c8627a8198 100644 --- a/Mathlib/RepresentationTheory/GroupCohomology/Resolution.lean +++ b/Mathlib/RepresentationTheory/GroupCohomology/Resolution.lean @@ -68,7 +68,7 @@ universe u v w variable {k G : Type u} [CommRing k] {n : ℕ} -open CategoryTheory +open CategoryTheory Finsupp local notation "Gⁿ" => Fin n → G @@ -102,7 +102,7 @@ def actionDiagonalSucc (G : Type u) [Group G] : tensorIso (Iso.refl _) (actionDiagonalSucc G n) ≪≫ leftRegularTensorIso _ _ ≪≫ tensorIso (Iso.refl _) - (mkIso (Equiv.piFinSuccAbove (fun _ => G) 0).symm.toIso fun _ => rfl) + (mkIso (Fin.insertNthEquiv (fun _ => G) 0).toIso fun _ => rfl) theorem actionDiagonalSucc_hom_apply {G : Type u} [Group G] {n : ℕ} (f : Fin (n + 1) → G) : (actionDiagonalSucc G n).hom.hom f = (f 0, fun i => (f (Fin.castSucc i))⁻¹ * f i.succ) := by @@ -136,14 +136,14 @@ 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 simpa only [Fin.cons_succ, Pi.smul_apply, smul_eq_mul, Fin.partialProd_succ', mul_assoc] -/ funext x dsimp [actionDiagonalSucc] - erw [hn, Equiv.piFinSuccAbove_symm_apply] + erw [hn, Fin.consEquiv_apply] refine Fin.cases ?_ (fun i => ?_) x · simp only [Fin.insertNth_zero, Fin.cons_zero, Fin.partialProd_zero, mul_one] · simp only [Fin.cons_succ, Pi.smul_apply, smul_eq_mul, Fin.partialProd_succ', ← mul_assoc] @@ -221,14 +221,11 @@ theorem diagonalSucc_inv_single_left (g : G) (f : Gⁿ →₀ k) (r : k) : 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] + rw [map_zero] · intro _ _ _ _ _ hx - rw [TensorProduct.tmul_add, map_add]; erw [map_add, hx] + rw [TensorProduct.tmul_add, map_add, 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 [diagonalSucc_inv_single_single, sum_single_index, mul_comm] rw [zero_mul, single_zero] theorem diagonalSucc_inv_single_right (g : G →₀ k) (f : Gⁿ) (r : k) : @@ -240,15 +237,11 @@ theorem diagonalSucc_inv_single_right (g : G →₀ k) (f : Gⁿ) (r : k) : · intro a b x ha hb 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] + · rw [TensorProduct.zero_tmul, map_zero, map_zero] · intro _ _ _ _ _ hx - rw [TensorProduct.add_tmul, map_add]; erw [map_add, hx] + rw [TensorProduct.add_tmul, map_add, 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 [diagonalSucc_inv_single_single, sum_single_index] rw [zero_mul, single_zero] end Rep @@ -266,8 +259,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 +349,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 @@ -565,12 +559,12 @@ def forget₂ToModuleCatHomotopyEquiv : /-- The hom of `k`-linear `G`-representations `k[G¹] → k` sending `∑ nᵢgᵢ ↦ ∑ nᵢ`. -/ def ε : Rep.ofMulAction k G (Fin 1 → G) ⟶ Rep.trivial k G k where - hom := Finsupp.total _ _ _ fun _ => (1 : k) + hom := Finsupp.linearCombination _ fun _ => (1 : k) comm g := Finsupp.lhom_ext' fun _ => LinearMap.ext_ring (by show - Finsupp.total (Fin 1 → G) k k (fun _ => (1 : k)) (Finsupp.mapDomain _ (Finsupp.single _ _)) = - Finsupp.total (Fin 1 → G) k k (fun _ => (1 : k)) (Finsupp.single _ _) - simp only [Finsupp.mapDomain_single, Finsupp.total_single]) + Finsupp.linearCombination k (fun _ => (1 : k)) (Finsupp.mapDomain _ (Finsupp.single _ _)) = + Finsupp.linearCombination k (fun _ => (1 : k)) (Finsupp.single _ _) + simp only [Finsupp.mapDomain_single, Finsupp.linearCombination_single]) /-- The homotopy equivalence of complexes of `k`-modules between the standard resolution of `k` as a trivial `G`-representation, and the complex which is `k` at 0 and 0 everywhere else, acts as @@ -583,9 +577,9 @@ theorem forget₂ToModuleCatHomotopyEquiv_f_0_eq : convert Category.id_comp (X := (forget₂ToModuleCat k G).X 0) _ · dsimp only [HomotopyEquiv.ofIso, compForgetAugmentedIso] simp only [Iso.symm_hom, eqToIso.inv, HomologicalComplex.eqToHom_f, eqToHom_refl] - trans (Finsupp.total _ _ _ fun _ => (1 : k)).comp ((ModuleCat.free k).map (terminal.from _)) + trans (linearCombination _ fun _ => (1 : k)).comp ((ModuleCat.free k).map (terminal.from _)) · dsimp - erw [Finsupp.lmapDomain_total (α := 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) @@ -596,7 +590,8 @@ theorem forget₂ToModuleCatHomotopyEquiv_f_0_eq : · ext x dsimp (config := { unfoldPartialApp := true }) [HomotopyEquiv.ofIso, Finsupp.LinearEquiv.finsuppUnique] - rw [Finsupp.total_single, one_smul, @Unique.eq_default _ Types.terminalIso.toEquiv.unique x, + rw [linearCombination_single, one_smul, + @Unique.eq_default _ Types.terminalIso.toEquiv.unique x, ChainComplex.single₀_map_f_zero, LinearMap.coe_mk, AddHom.coe_mk, Function.comp_apply, Finsupp.equivFunOnFinite_apply, Finsupp.single_eq_same] · exact @Subsingleton.elim _ (@Unique.instSubsingleton _ (Limits.uniqueToTerminal _)) _ _ diff --git a/Mathlib/RepresentationTheory/Maschke.lean b/Mathlib/RepresentationTheory/Maschke.lean index f35efe285d18d..7eaec76c225f9 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 diff --git a/Mathlib/RepresentationTheory/Rep.lean b/Mathlib/RepresentationTheory/Rep.lean index 8cf8b61925ff3..0c233f3d57f27 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 @@ -332,7 +332,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 +361,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,7 +371,7 @@ 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) right_inv f := by ext; rfl @@ -404,7 +404,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 +445,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 +569,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..f9ab3648fed20 100644 --- a/Mathlib/RingTheory/AdicCompletion/Algebra.lean +++ b/Mathlib/RingTheory/AdicCompletion/Algebra.lean @@ -200,7 +200,7 @@ instance : SMul (R ⧸ (I • ⊤ : Ideal R)) (M ⧸ (I • ⊤ : Submodule R M) Quotient.liftOn r (· • x) fun b₁ b₂ (h : Setoid.Rel _ b₁ b₂) ↦ 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/Basic.lean b/Mathlib/RingTheory/AdicCompletion/Basic.lean index 97af754373c43..a680f5898fdf6 100644 --- a/Mathlib/RingTheory/AdicCompletion/Basic.lean +++ b/Mathlib/RingTheory/AdicCompletion/Basic.lean @@ -554,8 +554,8 @@ theorem le_jacobson_bot [IsAdicComplete I R] : I ≤ (⊥ : Ideal R).jacobson := convert Ideal.sub_mem _ this (Ideal.mul_mem_left _ (1 + -(x * y)) hL) using 1 ring cases n - · simp only [Ideal.one_eq_top, pow_zero, Nat.zero_eq, mem_top] - · rw [← neg_sub _ (1 : R), neg_mul, mul_geom_sum, neg_sub, sub_sub, add_comm, ← sub_sub, + · simp only [Ideal.one_eq_top, pow_zero, mem_top] + · rw [← neg_sub _ (1 : R), neg_mul, mul_geom_sum, neg_sub, sub_sub, add_comm (_ ^ _), ← sub_sub, sub_self, zero_sub, @neg_mem_iff, mul_pow] exact Ideal.mul_mem_right _ (I ^ _) (Ideal.pow_mem_pow hx _) diff --git a/Mathlib/RingTheory/AdicCompletion/Exactness.lean b/Mathlib/RingTheory/AdicCompletion/Exactness.lean index 347ac711c8b05..c184632614480 100644 --- a/Mathlib/RingTheory/AdicCompletion/Exactness.lean +++ b/Mathlib/RingTheory/AdicCompletion/Exactness.lean @@ -39,14 +39,13 @@ section Surjectivity variable {M : Type v} [AddCommGroup M] [Module R M] variable {N : Type w} [AddCommGroup N] [Module R N] -variable {f : M →ₗ[R] N} (hf : Function.Surjective f) -include hf +variable {f : M →ₗ[R] N} /- In each step, a preimage is constructed from the preimage of the previous step by subtracting this delta. -/ -private noncomputable def mapPreimageDelta (x : AdicCauchySequence I N) +private noncomputable def mapPreimageDelta (hf : Function.Surjective f) (x : AdicCauchySequence I N) {n : ℕ} {y yₙ : M} (hy : f y = x (n + 1)) (hyₙ : f yₙ = x n) : - { d : (I ^ n • ⊤ : Submodule R M) | f d = f (yₙ - y) } := + {d : (I ^ n • ⊤ : Submodule R M) | f d = f (yₙ - y) } := have h : f (yₙ - y) ∈ Submodule.map f (I ^ n • ⊤ : Submodule R M) := by rw [Submodule.map_smul'', Submodule.map_top, LinearMap.range_eq_top.mpr hf, map_sub, hyₙ, hy, ← Submodule.neg_mem_iff, neg_sub, ← SModEq.sub_mem] @@ -54,20 +53,19 @@ private noncomputable def mapPreimageDelta (x : AdicCauchySequence I N) ⟨⟨h.choose, h.choose_spec.1⟩, h.choose_spec.2⟩ /- Inductively construct preimage of cauchy sequence. -/ -private noncomputable def mapPreimage (x : AdicCauchySequence I N) : +private noncomputable def mapPreimage (hf : Function.Surjective f) (x : AdicCauchySequence I N) : (n : ℕ) → f ⁻¹' {x n} | .zero => ⟨(hf (x 0)).choose, (hf (x 0)).choose_spec⟩ | .succ n => let y := (hf (x (n + 1))).choose have hy := (hf (x (n + 1))).choose_spec - let ⟨yₙ, (hyₙ : f yₙ = x n)⟩ := mapPreimage x n + let ⟨yₙ, (hyₙ : f yₙ = x n)⟩ := mapPreimage hf x n let ⟨⟨d, _⟩, (p : f d = f (yₙ - y))⟩ := mapPreimageDelta hf x hy hyₙ ⟨yₙ - d, by simpa [p]⟩ -variable (I) - +variable (I) in /-- Adic completion preserves surjectivity -/ -theorem map_surjective : Function.Surjective (map I f) := fun y ↦ by +theorem map_surjective (hf : Function.Surjective f) : Function.Surjective (map I f) := fun y ↦ by apply AdicCompletion.induction_on I N y (fun b ↦ ?_) let a := mapPreimage hf b refine ⟨AdicCompletion.mk I M (AdicCauchySequence.mk I M (fun n ↦ (a n : M)) ?_), ?_⟩ @@ -100,7 +98,7 @@ theorem map_injective {f : M →ₗ[R] N} (hf : Function.Injective f) : rw [← Submodule.comap_map_eq_of_injective hf (I ^ n • ⊤ : Submodule R M), Submodule.map_smul'', Submodule.map_top] apply (smul_mono_right _ inf_le_right : I ^ n • (I ^ k • ⊤ ⊓ (range f)) ≤ _) - nth_rw 2 [show n = n + k - k by omega] + nth_rw 1 [show n = n + k - k by omega] rw [← hk (n + k) (show n + k ≥ k by omega)] exact ⟨by simpa using congrArg (fun x ↦ x.val (n + k)) hx, ⟨a (n + k), rfl⟩⟩ 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 2e497804ccf8a..83e58942dce2b 100644 --- a/Mathlib/RingTheory/Adjoin/Basic.lean +++ b/Mathlib/RingTheory/Adjoin/Basic.lean @@ -251,7 +251,7 @@ theorem adjoin_inl_union_inr_eq_prod (s) (t) : simpa [P] using Subalgebra.add_mem _ Ha Hb /-- If all elements of `s : Set A` commute pairwise, then `adjoin R s` is a commutative -semiring. -/ +semiring. -/ def adjoinCommSemiringOfComm {s : Set A} (hcomm : ∀ a ∈ s, ∀ b ∈ s, a * b = b * a) : CommSemiring (adjoin R s) := { (adjoin R s).toSemiring with @@ -355,7 +355,7 @@ theorem pow_smul_mem_of_smul_subset_of_mem_adjoin [CommSemiring B] [Algebra R B] [IsScalarTower R A B] (r : A) (s : Set B) (B' : Subalgebra R B) (hs : r • s ⊆ B') {x : B} (hx : x ∈ adjoin R s) (hr : algebraMap A B r ∈ B') : ∃ n₀ : ℕ, ∀ n ≥ n₀, r ^ n • x ∈ B' := by change x ∈ Subalgebra.toSubmodule (adjoin R s) at hx - rw [adjoin_eq_span, Finsupp.mem_span_iff_total] at hx + rw [adjoin_eq_span, Finsupp.mem_span_iff_linearCombination] at hx rcases hx with ⟨l, rfl : (l.sum fun (i : Submonoid.closure s) (c : R) => c • (i : B)) = x⟩ choose n₁ n₂ using fun x : Submonoid.closure s => Submonoid.pow_smul_mem_closure_smul r s x.prop use l.support.sup n₁ @@ -403,7 +403,7 @@ theorem adjoin_eq_ring_closure (s : Set A) : variable (R) /-- If all elements of `s : Set A` commute pairwise, then `adjoin R s` is a commutative -ring. -/ +ring. -/ def adjoinCommRingOfComm {s : Set A} (hcomm : ∀ a ∈ s, ∀ b ∈ s, a * b = b * a) : CommRing (adjoin R s) := { (adjoin R s).toRing, adjoinCommSemiringOfComm R hcomm with } diff --git a/Mathlib/RingTheory/Adjoin/FG.lean b/Mathlib/RingTheory/Adjoin/FG.lean index eae1117ae1555..1256cc4e9a973 100644 --- a/Mathlib/RingTheory/Adjoin/FG.lean +++ b/Mathlib/RingTheory/Adjoin/FG.lean @@ -58,17 +58,17 @@ theorem fg_trans (h1 : (adjoin R s).toSubmodule.FG) (h2 : (adjoin (adjoin R s) t change r ∈ adjoin R (s ∪ t) at hr rw [adjoin_union_eq_adjoin_adjoin] at hr change r ∈ Subalgebra.toSubmodule (adjoin (adjoin R s) t) at hr - rw [← hq', ← Set.image_id q, Finsupp.mem_span_image_iff_total (adjoin R s)] at hr + rw [← hq', ← Set.image_id q, Finsupp.mem_span_image_iff_linearCombination (adjoin R s)] at hr rcases hr with ⟨l, hlq, rfl⟩ - have := @Finsupp.total_apply A A (adjoin R s) + have := @Finsupp.linearCombination_apply A A (adjoin R s) rw [this, Finsupp.sum] refine sum_mem ?_ intro z hz change (l z).1 * _ ∈ _ have : (l z).1 ∈ Subalgebra.toSubmodule (adjoin R s) := (l z).2 - rw [← hp', ← Set.image_id p, Finsupp.mem_span_image_iff_total R] at this + rw [← hp', ← Set.image_id p, Finsupp.mem_span_image_iff_linearCombination R] at this rcases this with ⟨l2, hlp, hl⟩ - have := @Finsupp.total_apply A A R + have := @Finsupp.linearCombination_apply A A R rw [this] at hl rw [← hl, Finsupp.sum_mul] refine sum_mem ?_ diff --git a/Mathlib/RingTheory/Adjoin/Field.lean b/Mathlib/RingTheory/Adjoin/Field.lean index eb204b8922d11..4463b01947e1f 100644 --- a/Mathlib/RingTheory/Adjoin/Field.lean +++ b/Mathlib/RingTheory/Adjoin/Field.lean @@ -88,7 +88,7 @@ variable [Algebra R L] theorem IsIntegral.mem_range_algHom_of_minpoly_splits (int : IsIntegral R x) (h : Splits (algebraMap R K) (minpoly R x))(f : K →ₐ[R] L) : x ∈ f.range := - show x ∈ Set.range f from Set.image_subset_range _ _ <| by + show x ∈ Set.range f from Set.image_subset_range _ ((minpoly R x).rootSet K) <| by rw [image_rootSet h f, mem_rootSet'] exact ⟨((minpoly.monic int).map _).ne_zero, minpoly.aeval R x⟩ diff --git a/Mathlib/RingTheory/AdjoinRoot.lean b/Mathlib/RingTheory/AdjoinRoot.lean index 75dc495a1ff01..bba7f1e3e7457 100644 --- a/Mathlib/RingTheory/AdjoinRoot.lean +++ b/Mathlib/RingTheory/AdjoinRoot.lean @@ -353,11 +353,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) := @@ -736,7 +736,7 @@ theorem quotAdjoinRootEquivQuotPolynomialQuot_symm_mk_mk (p : R[X]) : quotMapCMapSpanMkEquivQuotMapCQuotMapSpanMk_symm_quotQuotMk, quotMapOfEquivQuotMapCMapSpanMk_symm_mk] -/-- Promote `AdjoinRoot.quotAdjoinRootEquivQuotPolynomialQuot` to an alg_equiv. -/ +/-- Promote `AdjoinRoot.quotAdjoinRootEquivQuotPolynomialQuot` to an alg_equiv. -/ @[simps!] noncomputable def quotEquivQuotMap (f : R[X]) (I : Ideal R) : (AdjoinRoot f ⧸ Ideal.map (of f) I) ≃ₐ[R] diff --git a/Mathlib/RingTheory/Algebraic.lean b/Mathlib/RingTheory/Algebraic.lean index 0326b17fa9001..20fba6c16cb72 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 @@ -47,11 +48,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} @@ -79,7 +80,7 @@ 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 diff --git a/Mathlib/RingTheory/AlgebraicIndependent.lean b/Mathlib/RingTheory/AlgebraicIndependent.lean index 6a5c5db0549e9..0e358adaa9418 100644 --- a/Mathlib/RingTheory/AlgebraicIndependent.lean +++ b/Mathlib/RingTheory/AlgebraicIndependent.lean @@ -82,11 +82,7 @@ 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] namespace AlgebraicIndependent @@ -100,19 +96,19 @@ variable (hx : AlgebraicIndependent R x) include hx theorem algebraMap_injective : Injective (algebraMap R A) := by - simpa [Function.comp] using + simpa [Function.comp_def] using (Injective.of_comp_iff (algebraicIndependent_iff_injective_aeval.1 hx) MvPolynomial.C).2 (MvPolynomial.C_injective _ _) theorem linearIndependent : LinearIndependent R x := by - rw [linearIndependent_iff_injective_total] - have : Finsupp.total ι A R x = - (MvPolynomial.aeval x).toLinearMap.comp (Finsupp.total ι _ R X) := by + rw [linearIndependent_iff_injective_linearCombination] + have : Finsupp.linearCombination R x = + (MvPolynomial.aeval x).toLinearMap.comp (Finsupp.linearCombination R X) := by ext simp rw [this] refine hx.comp ?_ - rw [← linearIndependent_iff_injective_total] + rw [← linearIndependent_iff_injective_linearCombination] exact linearIndependent_X _ _ protected theorem injective [Nontrivial R] : Injective x := @@ -135,7 +131,7 @@ theorem map {f : A →ₐ[R] A'} (hf_inj : Set.InjOn f (adjoin R (range x))) : intro p rw [AlgHom.mem_range] refine ⟨MvPolynomial.rename (codRestrict x (range x) mem_range_self) p, ?_⟩ - simp [Function.comp, aeval_rename] + simp [Function.comp_def, aeval_rename] intro x y hxy rw [this] at hxy rw [adjoin_eq_range] at hf_inj diff --git a/Mathlib/RingTheory/Artinian.lean b/Mathlib/RingTheory/Artinian.lean index 65ecbf2b5c896..9e43f7cbc62b9 100644 --- a/Mathlib/RingTheory/Artinian.lean +++ b/Mathlib/RingTheory/Artinian.lean @@ -12,7 +12,6 @@ import Mathlib.Tactic.RSuffices /-! # Artinian rings and modules - A module satisfying these equivalent conditions is said to be an *Artinian* R-module if every decreasing chain of submodules is eventually constant, or equivalently, if the relation `<` on submodules is well founded. @@ -58,8 +57,12 @@ open Set Filter Pointwise /-- `IsArtinian R M` is the proposition that `M` is an Artinian `R`-module, implemented as the well-foundedness of submodule inclusion. -/ -class IsArtinian (R M) [Semiring R] [AddCommMonoid M] [Module R M] : Prop where - wellFounded_submodule_lt' : WellFounded ((· < ·) : Submodule R M → Submodule R M → Prop) +abbrev IsArtinian (R M) [Semiring R] [AddCommMonoid M] [Module R M] : Prop := + WellFoundedLT (Submodule R M) + +theorem isArtinian_iff (R M) [Semiring R] [AddCommMonoid M] [Module R M] : IsArtinian R M ↔ + WellFounded (· < · : Submodule R M → Submodule R M → Prop) := + isWellFounded_iff _ _ section @@ -67,19 +70,11 @@ variable {R M P N : Type*} variable [Ring R] [AddCommGroup M] [AddCommGroup P] [AddCommGroup N] variable [Module R M] [Module R P] [Module R N] -open IsArtinian - -/- Porting note: added this version with `R` and `M` explicit because infer kinds are unsupported in -Lean 4-/ -theorem IsArtinian.wellFounded_submodule_lt (R M) [Semiring R] [AddCommMonoid M] [Module R M] - [IsArtinian R M] : WellFounded ((· < ·) : Submodule R M → Submodule R M → Prop) := - IsArtinian.wellFounded_submodule_lt' - theorem isArtinian_of_injective (f : M →ₗ[R] P) (h : Function.Injective f) [IsArtinian R P] : IsArtinian R M := ⟨Subrelation.wf (fun {A B} hAB => show A.map f < B.map f from Submodule.map_strictMono_of_injective h hAB) - (InvImage.wf (Submodule.map f) (IsArtinian.wellFounded_submodule_lt R P))⟩ + (InvImage.wf (Submodule.map f) IsWellFounded.wf)⟩ instance isArtinian_submodule' [IsArtinian R M] (N : Submodule R M) : IsArtinian R N := isArtinian_of_injective N.subtype Subtype.val_injective @@ -94,7 +89,11 @@ theorem isArtinian_of_surjective (f : M →ₗ[R] P) (hf : Function.Surjective f ⟨Subrelation.wf (fun {A B} hAB => show A.comap f < B.comap f from Submodule.comap_strictMono_of_surjective hf hAB) - (InvImage.wf (Submodule.comap f) (IsArtinian.wellFounded_submodule_lt R M))⟩ + (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} @@ -102,17 +101,23 @@ theorem isArtinian_of_linearEquiv (f : M ≃ₗ[R] P) [IsArtinian R M] : IsArtin isArtinian_of_surjective _ f.toLinearMap f.toEquiv.surjective 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 (IsArtinian.wellFounded_submodule_lt R M) - (IsArtinian.wellFounded_submodule_lt R P) (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 _⟩ @@ -121,17 +126,12 @@ instance (priority := 100) isArtinian_of_finite [Finite M] : IsArtinian R M := -- 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 + ∀ {M : ι → Type*} [Ring R] [∀ 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 @@ -147,20 +147,15 @@ instance isArtinian_finsupp {R ι M : Type*} [Ring R] [AddCommGroup M] [Module R end -open IsArtinian Submodule Function +open Submodule Function section Ring variable {R M : Type*} [Ring R] [AddCommGroup M] [Module R M] -theorem isArtinian_iff_wellFounded : - IsArtinian R M ↔ WellFounded ((· < ·) : Submodule R M → Submodule R M → Prop) := - ⟨fun h => h.1, IsArtinian.mk⟩ - -theorem IsArtinian.finite_of_linearIndependent [Nontrivial R] [IsArtinian R M] {s : Set M} +theorem IsArtinian.finite_of_linearIndependent [Nontrivial R] [h : IsArtinian R M] {s : Set M} (hs : LinearIndependent R ((↑) : s → M)) : s.Finite := by - refine by_contradiction fun hf => (RelEmbedding.wellFounded_iff_no_descending_seq.1 - (wellFounded_submodule_lt (R := R) (M := M))).elim' ?_ + refine by_contradiction fun hf => (RelEmbedding.wellFounded_iff_no_descending_seq.1 h.wf).elim' ?_ have f : ℕ ↪ s := Set.Infinite.natEmbedding s hf have : ∀ n, (↑) ∘ f '' { m | n ≤ m } ⊆ s := by rintro n x ⟨y, _, rfl⟩ @@ -182,7 +177,7 @@ theorem IsArtinian.finite_of_linearIndependent [Nontrivial R] [IsArtinian R M] { /-- A module is Artinian iff every nonempty set of submodules has a minimal submodule among them. -/ theorem set_has_minimal_iff_artinian : (∀ a : Set <| Submodule R M, a.Nonempty → ∃ M' ∈ a, ∀ I ∈ a, ¬I < M') ↔ IsArtinian R M := by - rw [isArtinian_iff_wellFounded, WellFounded.wellFounded_iff_has_min] + rw [isArtinian_iff, WellFounded.wellFounded_iff_has_min] theorem IsArtinian.set_has_minimal [IsArtinian R M] (a : Set <| Submodule R M) (ha : a.Nonempty) : ∃ M' ∈ a, ∀ I ∈ a, ¬I < M' := @@ -191,7 +186,7 @@ theorem IsArtinian.set_has_minimal [IsArtinian R M] (a : Set <| Submodule R M) ( /-- A module is Artinian iff every decreasing chain of submodules stabilizes. -/ theorem monotone_stabilizes_iff_artinian : (∀ f : ℕ →o (Submodule R M)ᵒᵈ, ∃ n, ∀ m, n ≤ m → f n = f m) ↔ IsArtinian R M := by - rw [isArtinian_iff_wellFounded] + rw [isArtinian_iff] exact WellFounded.monotone_chain_condition.symm namespace IsArtinian @@ -209,7 +204,7 @@ theorem eventuallyConst_of_isArtinian (f : ℕ →o (Submodule R M)ᵒᵈ) : /-- If `∀ I > J, P I` implies `P J`, then `P` holds for all submodules. -/ theorem induction {P : Submodule R M → Prop} (hgt : ∀ I, (∀ J < I, P J) → P I) (I : Submodule R M) : P I := - (wellFounded_submodule_lt R M).recursion I hgt + WellFoundedLT.induction I hgt end IsArtinian @@ -222,7 +217,7 @@ and range. -/ theorem eventually_codisjoint_ker_pow_range_pow (f : M →ₗ[R] M) : ∀ᶠ n in atTop, Codisjoint (LinearMap.ker (f ^ n)) (LinearMap.range (f ^ n)) := by obtain ⟨n, hn : ∀ m, n ≤ m → LinearMap.range (f ^ n) = LinearMap.range (f ^ m)⟩ := - monotone_stabilizes f.iterateRange + IsArtinian.monotone_stabilizes f.iterateRange refine eventually_atTop.mpr ⟨n, fun m hm ↦ codisjoint_iff.mpr ?_⟩ simp_rw [← hn _ hm, Submodule.eq_top_iff', Submodule.mem_sup] intro x @@ -236,7 +231,7 @@ theorem eventually_codisjoint_ker_pow_range_pow (f : M →ₗ[R] M) : lemma eventually_iInf_range_pow_eq (f : Module.End R M) : ∀ᶠ n in atTop, ⨅ m, LinearMap.range (f ^ m) = LinearMap.range (f ^ n) := by obtain ⟨n, hn : ∀ m, n ≤ m → LinearMap.range (f ^ n) = LinearMap.range (f ^ m)⟩ := - monotone_stabilizes f.iterateRange + IsArtinian.monotone_stabilizes f.iterateRange refine eventually_atTop.mpr ⟨n, fun l hl ↦ le_antisymm (iInf_le _ _) (le_iInf fun m ↦ ?_)⟩ rcases le_or_lt l m with h | h · rw [← hn _ (hl.trans h), hn _ hl] @@ -347,15 +342,10 @@ 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 := by - rw [isArtinian_iff_wellFounded] at h ⊢ - exact (Submodule.restrictScalarsEmbedding R S M).wellFounded h + [Module S M] [Module R M] [IsScalarTower R S M] (h : IsArtinian R M) : IsArtinian S M := + ⟨(Submodule.restrictScalarsEmbedding R S M).wellFounded h.wf⟩ instance (R) [CommRing R] [IsArtinianRing R] (I : Ideal R) : IsArtinianRing (R ⧸ I) := isArtinian_of_tower R inferInstance @@ -367,7 +357,7 @@ theorem isArtinian_of_fg_of_artinian {R M} [Ring R] [AddCommGroup M] [Module R M haveI := Classical.decEq R have : ∀ x ∈ s, x ∈ N := fun x hx => hs ▸ Submodule.subset_span hx refine @isArtinian_of_surjective _ ((↑s : Set M) →₀ R) N _ _ _ _ _ ?_ ?_ isArtinian_finsupp - · exact Finsupp.total (↑s : Set M) N R (fun i => ⟨i, hs ▸ subset_span i.2⟩) + · exact Finsupp.linearCombination R (fun i => ⟨i, hs ▸ subset_span i.2⟩) · rw [← LinearMap.range_eq_top, eq_top_iff, ← map_le_map_iff_of_injective (show Injective (Submodule.subtype N) from Subtype.val_injective), Submodule.map_top, range_subtype, @@ -395,8 +385,8 @@ theorem isArtinian_span_of_finite (R) {M} [Ring R] [AddCommGroup M] [Module R M] theorem Function.Surjective.isArtinianRing {R} [Ring R] {S} [Ring S] {F} [FunLike F R S] [RingHomClass F R S] {f : F} (hf : Function.Surjective f) [H : IsArtinianRing R] : IsArtinianRing S := by - rw [isArtinianRing_iff, isArtinian_iff_wellFounded] at H ⊢ - exact (Ideal.orderEmbeddingOfSurjective f hf).wellFounded H + rw [isArtinianRing_iff] at H ⊢ + exact ⟨(Ideal.orderEmbeddingOfSurjective f hf).wellFounded H.wf⟩ instance isArtinianRing_range {R} [Ring R] {S} [Ring S] (f : R →+* S) [IsArtinianRing R] : IsArtinianRing f.range := @@ -532,7 +522,7 @@ 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] : +proof_wanted IsSemisimpleRing.isArtinianRing (R : Type*) [Ring R] [IsSemisimpleRing R] : IsArtinianRing R end IsArtinianRing diff --git a/Mathlib/RingTheory/Bezout.lean b/Mathlib/RingTheory/Bezout.lean index 488ce7db5c4fb..37aef0df9ae66 100644 --- a/Mathlib/RingTheory/Bezout.lean +++ b/Mathlib/RingTheory/Bezout.lean @@ -51,15 +51,15 @@ 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 _)⟩ + | H => ⟨fun I => isPrincipal_of_FG _ (IsNoetherian.noetherian _)⟩ 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] - apply RelEmbedding.wellFounded _ h + refine ⟨RelEmbedding.wellFounded ?_ h⟩ have : ∀ I : { J : Ideal R // J.FG }, ∃ x : R, (I : Ideal R) = Ideal.span {x} := fun ⟨I, hI⟩ => (IsBezout.isPrincipal_of_FG I hI).1 choose f hf using this diff --git a/Mathlib/RingTheory/Bialgebra/Basic.lean b/Mathlib/RingTheory/Bialgebra/Basic.lean index dfcfce5f3f06e..516dc36878824 100644 --- a/Mathlib/RingTheory/Bialgebra/Basic.lean +++ b/Mathlib/RingTheory/Bialgebra/Basic.lean @@ -68,7 +68,7 @@ class Bialgebra (R : Type u) (A : Type v) [CommSemiring R] [Semiring A] extends /-- The comultiplication on a bialgebra preserves multiplication. This is written in a rather obscure way: it says that two bilinear maps `A →ₗ[R] A →ₗ[R] (A ⊗[R] A)` are equal. The corresponding equal linear maps `A ⊗[R] A →ₗ[R] A ⊗[R] A` - are firstly multiplcation followed by `comul`, and secondly `comul ⊗ comul` followed + are firstly multiplication followed by `comul`, and secondly `comul ⊗ comul` followed by multiplication on `A ⊗[R] A`. See `Bialgebra.mk'` for a constructor for bialgebras which uses the more familiar diff --git a/Mathlib/RingTheory/Bialgebra/Equiv.lean b/Mathlib/RingTheory/Bialgebra/Equiv.lean index a94379991aff9..c0160257534d0 100644 --- a/Mathlib/RingTheory/Bialgebra/Equiv.lean +++ b/Mathlib/RingTheory/Bialgebra/Equiv.lean @@ -39,7 +39,7 @@ attribute [nolint docBlame] BialgEquiv.toCoalgEquiv notation:50 A " ≃ₐc[" R "] " B => BialgEquiv R A B /-- `BialgEquivClass F R A B` asserts `F` is a type of bundled bialgebra equivalences -from `A` to `B`. -/ +from `A` to `B`. -/ class BialgEquivClass (F : Type*) (R A B : outParam Type*) [CommSemiring R] [Semiring A] [Semiring B] [Algebra R A] [Algebra R B] [CoalgebraStruct R A] [CoalgebraStruct R B] [EquivLike F A B] diff --git a/Mathlib/RingTheory/Bialgebra/Hom.lean b/Mathlib/RingTheory/Bialgebra/Hom.lean index 78feadf839f29..f1b2923cd334c 100644 --- a/Mathlib/RingTheory/Bialgebra/Hom.lean +++ b/Mathlib/RingTheory/Bialgebra/Hom.lean @@ -45,7 +45,7 @@ infixr:25 " →ₐc " => BialgHom _ notation:25 A " →ₐc[" R "] " B => BialgHom R A B /-- `BialgHomClass F R A B` asserts `F` is a type of bundled bialgebra homomorphisms -from `A` to `B`. -/ +from `A` to `B`. -/ class BialgHomClass (F : Type*) (R A B : outParam Type*) [CommSemiring R] [Semiring A] [Algebra R A] [Semiring B] [Algebra R B] [CoalgebraStruct R A] [CoalgebraStruct R B] [FunLike F A B] @@ -67,7 +67,7 @@ instance (priority := 100) toAlgHomClass : AlgHomClass F R A B where map_add := map_add map_zero := map_zero commutes := fun c r => by - simp only [Algebra.algebraMap_eq_smul_one, map_smul, _root_.map_one] + simp only [Algebra.algebraMap_eq_smul_one, map_smul, map_one] /-- Turn an element of a type `F` satisfying `BialgHomClass F R A B` into an actual `BialgHom`. This is declared as the default coercion from `F` to `A →ₐc[R] B`. -/ diff --git a/Mathlib/RingTheory/Binomial.lean b/Mathlib/RingTheory/Binomial.lean index 481d3ed558e54..659a95f8fb226 100644 --- a/Mathlib/RingTheory/Binomial.lean +++ b/Mathlib/RingTheory/Binomial.lean @@ -169,13 +169,13 @@ theorem ascPochhammer_smeval_cast (R : Type*) [Semiring R] {S : Type*} [NonAssoc [Pow S ℕ] [Module R S] [IsScalarTower R S S] [NatPowAssoc S] (x : S) (n : ℕ) : (ascPochhammer R n).smeval x = (ascPochhammer ℕ n).smeval x := by induction n with - | zero => simp only [Nat.zero_eq, ascPochhammer_zero, smeval_one, one_smul] + | zero => simp only [ascPochhammer_zero, smeval_one, one_smul] | succ n hn => simp only [ascPochhammer_succ_right, mul_add, smeval_add, smeval_mul_X, ← Nat.cast_comm] 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 @@ -241,7 +241,7 @@ 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 multichoose := Int.multichoose factorial_nsmul_multichoose r k := by - rw [Int.multichoose, nsmul_eq_mul] + rw [Int.multichoose.eq_def, nsmul_eq_mul] cases r with | ofNat n => simp only [multichoose, nsmul_eq_mul, Int.ofNat_eq_coe, Int.ofNat_mul_out] @@ -452,7 +452,7 @@ theorem choose_smul_choose [NatPowAssoc R] (r : R) (n k : ℕ) (hkn : k ≤ n) : refine nsmul_right_injective (Nat.factorial n) (Nat.factorial_ne_zero n) ?_ simp only rw [nsmul_left_comm, ← descPochhammer_eq_factorial_smul_choose, - ← Nat.choose_mul_factorial_mul_factorial hkn, ← smul_mul_smul, + ← Nat.choose_mul_factorial_mul_factorial hkn, ← smul_mul_smul_comm, ← descPochhammer_eq_factorial_smul_choose, mul_nsmul', ← descPochhammer_eq_factorial_smul_choose, smul_mul_assoc] nth_rw 2 [← Nat.sub_add_cancel hkn] diff --git a/Mathlib/RingTheory/ChainOfDivisors.lean b/Mathlib/RingTheory/ChainOfDivisors.lean index ed816bb3683ea..684edca6086c9 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] @@ -332,7 +332,7 @@ theorem multiplicity_prime_eq_multiplicity_image_by_factor_orderIso {m p : Assoc 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 `∣`. -/ diff --git a/Mathlib/RingTheory/ClassGroup.lean b/Mathlib/RingTheory/ClassGroup.lean index 9037779c7cd2a..1fee05b58a3b4 100644 --- a/Mathlib/RingTheory/ClassGroup.lean +++ b/Mathlib/RingTheory/ClassGroup.lean @@ -3,7 +3,6 @@ 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.GroupTheory.QuotientGroup import Mathlib.RingTheory.DedekindDomain.Ideal /-! diff --git a/Mathlib/RingTheory/Coalgebra/Basic.lean b/Mathlib/RingTheory/Coalgebra/Basic.lean index 03811b4c741c4..643086a03c0e1 100644 --- a/Mathlib/RingTheory/Coalgebra/Basic.lean +++ b/Mathlib/RingTheory/Coalgebra/Basic.lean @@ -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 @@ -284,8 +325,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 5b15a25b51a3b..843220c0bfa2f 100644 --- a/Mathlib/RingTheory/Coalgebra/Equiv.lean +++ b/Mathlib/RingTheory/Coalgebra/Equiv.lean @@ -38,7 +38,7 @@ attribute [nolint docBlame] CoalgEquiv.toLinearEquiv notation:50 A " ≃ₗc[" R "] " B => CoalgEquiv R A B /-- `CoalgEquivClass F R A B` asserts `F` is a type of bundled coalgebra equivalences -from `A` to `B`. -/ +from `A` to `B`. -/ class CoalgEquivClass (F : Type*) (R A B : outParam Type*) [CommSemiring R] [AddCommMonoid A] [AddCommMonoid B] [Module R A] [Module R B] [CoalgebraStruct R A] [CoalgebraStruct R B] [EquivLike F A B] @@ -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 75d7d5fd60d0e..c6c26e0bf65b9 100644 --- a/Mathlib/RingTheory/Coalgebra/Hom.lean +++ b/Mathlib/RingTheory/Coalgebra/Hom.lean @@ -43,7 +43,7 @@ infixr:25 " →ₗc " => CoalgHom _ notation:25 A " →ₗc[" R "] " B => CoalgHom R A B /-- `CoalgHomClass F R A B` asserts `F` is a type of bundled coalgebra homomorphisms -from `A` to `B`. -/ +from `A` to `B`. -/ class CoalgHomClass (F : Type*) (R A B : outParam Type*) [CommSemiring R] [AddCommMonoid A] [Module R A] [AddCommMonoid B] [Module R B] [CoalgebraStruct R A] [CoalgebraStruct R B] [FunLike F A B] @@ -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 30337d5e5beaf..131575077c37b 100644 --- a/Mathlib/RingTheory/Congruence/Basic.lean +++ b/Mathlib/RingTheory/Congruence/Basic.lean @@ -67,16 +67,15 @@ 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} +instance : FunLike (RingCon R) R (R → Prop) where + coe c := c.r + coe_injective' x y h := by + rcases x with ⟨⟨x, _⟩, _⟩ + rcases y with ⟨⟨y, _⟩, _⟩ + congr! + rw [Setoid.ext_iff, (show x.Rel = y.Rel from h)] + simp theorem rel_eq_coe : c.r = c := rfl @@ -126,6 +125,16 @@ theorem ext' {c d : RingCon R} (H : ⇑c = ⇑d) : c = d := DFunLike.coe_injecti 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 @@ -409,7 +418,6 @@ end Quotient The API in this section is copied from `Mathlib/GroupTheory/Congruence.lean` -/ - section Lattice variable [Add R] [Mul R] @@ -448,7 +456,7 @@ theorem coe_sInf (S : Set (RingCon R)) : ⇑(sInf S) = sInf ((⇑) '' S) := by @[simp, norm_cast] theorem coe_iInf {ι : Sort*} (f : ι → RingCon R) : ⇑(iInf f) = ⨅ i, ⇑(f i) := by - rw [iInf, coe_sInf, ← Set.range_comp, sInf_range, Function.comp] + rw [iInf, coe_sInf, ← Set.range_comp, sInf_range, Function.comp_def] instance : PartialOrder (RingCon R) where le_refl _c _ _ := id diff --git a/Mathlib/RingTheory/Coprime/Basic.lean b/Mathlib/RingTheory/Coprime/Basic.lean index ea3e3dce7eff2..851c87915e7a1 100644 --- a/Mathlib/RingTheory/Coprime/Basic.lean +++ b/Mathlib/RingTheory/Coprime/Basic.lean @@ -232,7 +232,7 @@ variable {R G : Type*} [CommSemiring R] [Group G] [MulAction G R] [SMulCommClass theorem isCoprime_group_smul_left : IsCoprime (x • y) z ↔ IsCoprime y z := ⟨fun ⟨a, b, h⟩ => ⟨x • a, b, by rwa [smul_mul_assoc, ← mul_smul_comm]⟩, fun ⟨a, b, h⟩ => - ⟨x⁻¹ • a, b, by rwa [smul_mul_smul, inv_mul_cancel, one_smul]⟩⟩ + ⟨x⁻¹ • a, b, by rwa [smul_mul_smul_comm, inv_mul_cancel, one_smul]⟩⟩ theorem isCoprime_group_smul_right : IsCoprime y (x • z) ↔ IsCoprime y z := isCoprime_comm.trans <| (isCoprime_group_smul_left x z y).trans isCoprime_comm 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 9659b2099784c..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 @@ -458,11 +458,11 @@ instance : Algebra R (v.adicCompletionIntegers K) where map_one' := by simp only [map_one]; rfl map_mul' x y := by ext - simp_rw [RingHom.map_mul, Subring.coe_mul, UniformSpace.Completion.coe_mul] + simp only [map_mul, UniformSpace.Completion.coe_mul, MulMemClass.mk_mul_mk] map_zero' := by simp only [map_zero]; rfl map_add' x y := by ext - simp_rw [RingHom.map_add, Subring.coe_add, UniformSpace.Completion.coe_add] + simp only [map_add, UniformSpace.Completion.coe_add, AddMemClass.mk_add_mk] commutes' r x := by rw [mul_comm] smul_def' r x := by 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/Dvr.lean b/Mathlib/RingTheory/DedekindDomain/Dvr.lean index 04b1f0a1bc959..2edc66bfc7bfa 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 @@ -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/Factorization.lean b/Mathlib/RingTheory/DedekindDomain/Factorization.lean index 21265293630ad..9c8f207b3ee90 100644 --- a/Mathlib/RingTheory/DedekindDomain/Factorization.lean +++ b/Mathlib/RingTheory/DedekindDomain/Factorization.lean @@ -406,7 +406,7 @@ theorem count_neg_zpow (n : ℤ) (I : FractionalIdeal R⁰ K) : ← zpow_add₀ hI, neg_add_cancel, zpow_zero] exact count_one K v -theorem count_inv (I : FractionalIdeal R⁰ K) : +theorem count_inv (I : FractionalIdeal R⁰ K) : count K v (I⁻¹) = - count K v I := by rw [← zpow_neg_one, count_neg_zpow K v (1 : ℤ) I, zpow_one] diff --git a/Mathlib/RingTheory/DedekindDomain/FiniteAdeleRing.lean b/Mathlib/RingTheory/DedekindDomain/FiniteAdeleRing.lean index ed2483621633c..088395622dc68 100644 --- a/Mathlib/RingTheory/DedekindDomain/FiniteAdeleRing.lean +++ b/Mathlib/RingTheory/DedekindDomain/FiniteAdeleRing.lean @@ -54,6 +54,9 @@ instance : CommRing (FiniteIntegralAdeles R K) := instance : TopologicalSpace (FiniteIntegralAdeles R K) := inferInstanceAs (TopologicalSpace (∀ v : HeightOneSpectrum R, v.adicCompletionIntegers K)) +instance (v : HeightOneSpectrum R) : TopologicalRing (v.adicCompletionIntegers K) := + Subring.instTopologicalRing .. + instance : TopologicalRing (FiniteIntegralAdeles R K) := inferInstanceAs (TopologicalRing (∀ v : HeightOneSpectrum R, v.adicCompletionIntegers K)) @@ -107,7 +110,7 @@ def Coe.addMonoidHom : AddMonoidHom (R_hat R K) (K_hat R K) where 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] @@ -120,7 +123,7 @@ def Coe.ringHom : RingHom (R_hat R K) (K_hat R K) := 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 @@ -212,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' @@ -256,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] @@ -334,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₂ := @@ -344,7 +347,7 @@ lemma ext {a₁ a₂ : FiniteAdeleRing R K} (h : (a₁ : K_hat R K) = a₂) : a instance : Algebra (R_hat R K) (FiniteAdeleRing R K) where smul rhat fadele := ⟨fun v ↦ rhat v * fadele.1 v, Finite.subset fadele.2 <| fun v hv ↦ by simp only [mem_adicCompletionIntegers, mem_compl_iff, mem_setOf_eq, map_mul] at hv ⊢ - exact mt (mul_le_one₀ (rhat v).2) hv + exact mt (mul_le_one' (rhat v).2) hv ⟩ toFun r := ⟨r, by simp_all⟩ map_one' := by ext; rfl @@ -368,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) : diff --git a/Mathlib/RingTheory/DedekindDomain/Ideal.lean b/Mathlib/RingTheory/DedekindDomain/Ideal.lean index 6c656b177371a..426d939612987 100644 --- a/Mathlib/RingTheory/DedekindDomain/Ideal.lean +++ b/Mathlib/RingTheory/DedekindDomain/Ideal.lean @@ -108,7 +108,7 @@ theorem right_inverse_eq (I J : FractionalIdeal R₁⁰ K) (h : I * J = 1) : J = apply (le_div_iff_of_nonzero hI).mpr _ intro y hy x hx rw [mul_comm] - exact mul_mem_mul hx hy + exact mul_mem_mul hy hx theorem mul_inv_cancel_iff {I : FractionalIdeal R₁⁰ K} : I * I⁻¹ = 1 ↔ ∃ J, I * J = 1 := ⟨fun h => ⟨I⁻¹, h⟩, fun ⟨J, hJ⟩ => by rwa [← right_inverse_eq K I J hJ]⟩ @@ -562,6 +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 /-- Fractional ideals have cancellative multiplication in a Dedekind domain. @@ -608,10 +609,9 @@ theorem Ideal.dvdNotUnit_iff_lt {I J : Ideal A} : DvdNotUnit I J ↔ J < I := (mt Ideal.dvd_iff_le.mp (not_le_of_lt h))⟩ instance : WfDvdMonoid (Ideal A) where - wellFounded_dvdNotUnit := by - have : WellFounded ((· > ·) : Ideal A → Ideal A → Prop) := - isNoetherian_iff_wellFounded.mp (isNoetherianRing_iff.mp IsDedekindRing.toIsNoetherian) - convert this + wf := by + have : WellFoundedGT (Ideal A) := inferInstance + convert this.wf ext rw [Ideal.dvdNotUnit_iff_lt] @@ -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 @@ -892,7 +892,7 @@ 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] @@ -916,6 +916,17 @@ theorem irreducible_pow_sup_of_ge [DecidableRel fun (x : Ideal T) x_1 ↦ x ∣ 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 +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 /-! @@ -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 @@ -1267,7 +1252,7 @@ noncomputable def IsDedekindDomain.quotientEquivPiFactors {I : Ideal R} (hI : I (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] diff --git a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean index 8f37a34bfe33b..86796148fbcf3 100644 --- a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean +++ b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean @@ -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 881352fd3f2ce..258435cca7f9a 100644 --- a/Mathlib/RingTheory/DedekindDomain/PID.lean +++ b/Mathlib/RingTheory/DedekindDomain/PID.lean @@ -9,7 +9,7 @@ import Mathlib.RingTheory.DedekindDomain.Ideal /-! # Criteria under which a Dedekind domain is a PID -This file contains some results that we can use to test wether all ideals in a Dedekind domain are +This file contains some results that we can use to test whether all ideals in a Dedekind domain are principal. ## Main results @@ -96,7 +96,7 @@ theorem FractionalIdeal.isPrincipal_of_unit_of_comap_mul_span_singleton_eq_top { · conv_rhs => rw [← hinv, mul_comm] apply FractionalIdeal.mul_le_mul_left (FractionalIdeal.spanSingleton_le_iff_mem.mpr hw) · rw [FractionalIdeal.one_le, ← hvw, mul_comm] - exact FractionalIdeal.mul_mem_mul hv (FractionalIdeal.mem_spanSingleton_self _ _) + exact FractionalIdeal.mul_mem_mul (FractionalIdeal.mem_spanSingleton_self _ _) hv /-- An invertible fractional ideal of a commutative ring with finitely many maximal ideals is principal. diff --git a/Mathlib/RingTheory/DedekindDomain/SelmerGroup.lean b/Mathlib/RingTheory/DedekindDomain/SelmerGroup.lean index 3c636cfac5471..3ac49f7143a12 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 @@ -123,7 +123,7 @@ theorem valuation_of_unit_eq (x : Rˣ) : apply_fun v.intValuation at hx rw [map_one, map_mul] at hx rw [not_lt, ← hx, ← mul_one <| v.valuation _, valuation_of_algebraMap, - mul_le_mul_left₀ <| left_ne_zero_of_mul_eq_one hx] + mul_le_mul_left <| zero_lt_iff.2 <| left_ne_zero_of_mul_eq_one hx] exact v.intValuation_le_one _ -- Porting note: invalid attribute 'semireducible', declaration is in an imported module @@ -173,7 +173,7 @@ theorem monotone (hS : S ≤ S') : K⟮S,n⟯ ≤ K⟮S',n⟯ := fun _ hx v => h 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_mul' x y := by simp only [Submonoid.coe_mul, Subgroup.coe_toSubmonoid, map_mul]; rfl + map_mul' x y := by simp only [Subgroup.coe_mul, map_mul]; rfl theorem valuation_ker_eq : valuation.ker = K⟮(∅ : Set <| HeightOneSpectrum R),n⟯.subgroupOf (K⟮S,n⟯) := by @@ -191,8 +191,8 @@ def fromUnit {n : ℕ} : Rˣ →* K⟮(∅ : Set <| HeightOneSpectrum R),n⟯ wh ⟨QuotientGroup.mk <| Units.map (algebraMap R K).toMonoidHom x, fun v _ => v.valuation_of_unit_mod_eq n x⟩ map_one' := by simp only [map_one, QuotientGroup.mk_one, Subgroup.mk_eq_one] - map_mul' _ _ := by simp only [RingHom.toMonoidHom_eq_coe, map_mul, MonoidHom.mem_range, - powMonoidHom_apply, QuotientGroup.mk_mul, Submonoid.mk_mul_mk] + map_mul' _ _ := by simp only [RingHom.toMonoidHom_eq_coe, map_mul, QuotientGroup.mk_mul, + MulMemClass.mk_mul_mk] theorem fromUnit_ker [hn : Fact <| 0 < n] : (@fromUnit R _ _ K _ _ _ n).ker = (powMonoidHom n : Rˣ →* Rˣ).range := by diff --git a/Mathlib/RingTheory/Derivation/Basic.lean b/Mathlib/RingTheory/Derivation/Basic.lean index 31605cb3d9c2b..6a97903473082 100644 --- a/Mathlib/RingTheory/Derivation/Basic.lean +++ b/Mathlib/RingTheory/Derivation/Basic.lean @@ -344,7 +344,8 @@ variable {R : Type*} [CommSemiring R] {A : Type*} [CommSemiring A] [Algebra R A] rule. -/ def mk' (D : A →ₗ[R] M) (h : ∀ a b, D (a * b) = a • D b + b • D a) : Derivation R A M where toLinearMap := D - map_one_eq_zero' := add_right_eq_self.1 <| by simpa only [one_smul, one_mul] using (h 1 1).symm + map_one_eq_zero' := (add_right_eq_self (a := D 1)).1 <| by + simpa only [one_smul, one_mul] using (h 1 1).symm leibniz' := h @[simp] @@ -473,5 +474,4 @@ end end - end Derivation diff --git a/Mathlib/RingTheory/Derivation/DifferentialRing.lean b/Mathlib/RingTheory/Derivation/DifferentialRing.lean new file mode 100644 index 0000000000000..f26d5aab07492 --- /dev/null +++ b/Mathlib/RingTheory/Derivation/DifferentialRing.lean @@ -0,0 +1,95 @@ +/- +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 + +/-! +# Differential and Algebras + +This file defines derivations from a commutative ring to itself as a typeclass, which lets us +use the x′ notation for the derivative of x. +-/ + +/-- A derivation from a ring to itself, as a typeclass. -/ +class Differential (R : Type*) [CommRing R] where + /-- The `Derivation` associated with the ring. -/ + deriv : Derivation ℤ R R + +@[inherit_doc] +scoped[Differential] postfix:max "′" => Differential.deriv + +open scoped Differential + +open Lean PrettyPrinter Delaborator SubExpr in +/-- +A delaborator for the x′ notation. This is required because it's not direct function application, +so the default delaborator doesn't work. +-/ +@[delab app.DFunLike.coe] +def delabDeriv : Delab := do + let e ← getExpr + guard <| e.isAppOfArity' ``DFunLike.coe 6 + guard <| (e.getArg!' 4).isAppOf' ``Differential.deriv + let arg ← withAppArg delab + `($arg′) + +/-- +A differential algebra is an `Algebra` where the derivation commutes with `algebraMap`. +-/ +class DifferentialAlgebra (A B : Type*) [CommRing A] [CommRing B] [Algebra A B] + [Differential A] [Differential B] : Prop where + deriv_algebraMap : ∀ a : A, (algebraMap A B a)′ = algebraMap A B a′ + +export DifferentialAlgebra (deriv_algebraMap) + +@[norm_cast] +lemma algebraMap.coe_deriv {A : Type*} {B : Type*} [CommRing A] [CommRing B] [Algebra A B] + [Differential A] [Differential B] [DifferentialAlgebra A B] (a : A) : + (a′ : A) = (a : B)′ := + (DifferentialAlgebra.deriv_algebraMap _).symm + +/-- +A differential ring `A` and an algebra over it `B` share constants if all +constants in B are in the range of `algberaMap A B`. +-/ +class Differential.ContainConstants (A B : Type*) [CommRing A] [CommRing B] + [Algebra A B] [Differential B] : Prop where + /-- If the derivative of x is 0, then it's in the range of `algberaMap A B`. -/ + protected mem_range_of_deriv_eq_zero {x : B} (h : x′ = 0) : x ∈ (algebraMap A B).range + +lemma mem_range_of_deriv_eq_zero (A : Type*) {B : Type*} [CommRing A] [CommRing B] [Algebra A B] + [Differential B] [Differential.ContainConstants A B] {x : B} (h : x′ = 0) : + x ∈ (algebraMap A B).range := + Differential.ContainConstants.mem_range_of_deriv_eq_zero h + +instance (A : Type*) [CommRing A] [Differential A] : DifferentialAlgebra A A where + deriv_algebraMap _ := rfl + +instance (A : Type*) [CommRing A] [Differential A] : Differential.ContainConstants A A where + mem_range_of_deriv_eq_zero {x} _ := ⟨x, rfl⟩ + +/-- Transfer a `Differential` instance across a `RingEquiv`. -/ +@[reducible] +def Differential.equiv {R R₂ : Type*} [CommRing R] [CommRing R₂] [Differential R₂] + (h : R ≃+* R₂) : Differential R := + ⟨Derivation.mk' (h.symm.toAddMonoidHom.toIntLinearMap ∘ₗ + Differential.deriv.toLinearMap ∘ₗ h.toAddMonoidHom.toIntLinearMap) (by simp)⟩ + +/-- +Transfer a `DifferentialAlgebra` instance across a `AlgEquiv`. +-/ +lemma DifferentialAlgebra.equiv {A : Type*} [CommRing A] [Differential A] + {R R₂ : Type*} [CommRing R] [CommRing R₂] [Differential R₂] [Algebra A R] + [Algebra A R₂] [DifferentialAlgebra A R₂] (h : R ≃ₐ[A] R₂) : + letI := Differential.equiv h.toRingEquiv + DifferentialAlgebra A R := + letI := Differential.equiv h.toRingEquiv + ⟨fun a ↦ by + change (LinearMap.comp ..) _ = _ + simp only [AlgEquiv.toRingEquiv_eq_coe, RingHom.toAddMonoidHom_eq_coe, + RingEquiv.toRingHom_eq_coe, AlgEquiv.toRingEquiv_toRingHom, LinearMap.coe_comp, + AddMonoidHom.coe_toIntLinearMap, AddMonoidHom.coe_coe, RingHom.coe_coe, Derivation.coeFn_coe, + Function.comp_apply, AlgEquiv.commutes, deriv_algebraMap] + apply h.symm.commutes⟩ 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 eba48921f14f4..398d75d13c3f9 100644 --- a/Mathlib/RingTheory/Derivation/ToSquareZero.lean +++ b/Mathlib/RingTheory/Derivation/ToSquareZero.lean @@ -20,7 +20,7 @@ section ToSquareZero universe u v w variable {R : Type u} {A : Type v} {B : Type w} [CommSemiring R] [CommSemiring A] [CommRing B] -variable [Algebra R A] [Algebra R B] (I : Ideal B) (hI : I ^ 2 = ⊥) +variable [Algebra R A] [Algebra R B] (I : Ideal B) /-- If `f₁ f₂ : A →ₐ[R] B` are two lifts of the same `A →ₐ[R] B ⧸ I`, we may define a map `f₁ - f₂ : A →ₗ[R] I`. -/ @@ -42,7 +42,7 @@ variable [Algebra A B] /-- Given a tower of algebras `R → A → B`, and a square-zero `I : Ideal B`, each lift `A →ₐ[R] B` of the canonical map `A →ₐ[R] B ⧸ I` corresponds to an `R`-derivation from `A` to `I`. -/ -def derivationToSquareZeroOfLift [IsScalarTower R A B] (f : A →ₐ[R] B) +def derivationToSquareZeroOfLift [IsScalarTower R A B] (hI : I ^ 2 = ⊥) (f : A →ₐ[R] B) (e : (Ideal.Quotient.mkₐ R I).comp f = IsScalarTower.toAlgHom R A (B ⧸ I)) : Derivation R A I := by refine @@ -66,6 +66,8 @@ def derivationToSquareZeroOfLift [IsScalarTower R A B] (f : A →ₐ[R] B) IsScalarTower.coe_toAlgHom'] ring +variable (hI : I ^ 2 = ⊥) + theorem derivationToSquareZeroOfLift_apply [IsScalarTower R A B] (f : A →ₐ[R] B) (e : (Ideal.Quotient.mkₐ R I).comp f = IsScalarTower.toAlgHom R A (B ⧸ I)) (x : A) : (derivationToSquareZeroOfLift I hI f e x : B) = f x - algebraMap A B x := @@ -74,7 +76,8 @@ theorem derivationToSquareZeroOfLift_apply [IsScalarTower R A B] (f : A →ₐ[R /-- Given a tower of algebras `R → A → B`, and a square-zero `I : Ideal B`, each `R`-derivation from `A` to `I` corresponds to a lift `A →ₐ[R] B` of the canonical map `A →ₐ[R] B ⧸ I`. -/ @[simps (config := .lemmasOnly)] -def liftOfDerivationToSquareZero [IsScalarTower R A B] (f : Derivation R A I) : A →ₐ[R] B := +def liftOfDerivationToSquareZero [IsScalarTower R A B] (hI : I ^ 2 = ⊥) (f : Derivation R A I) : + A →ₐ[R] B := { ((I.restrictScalars R).subtype.comp f.toLinearMap + (IsScalarTower.toAlgHom R A B).toLinearMap : A →ₗ[R] B) with toFun := fun x => f x + algebraMap A B x diff --git a/Mathlib/RingTheory/DiscreteValuationRing/Basic.lean b/Mathlib/RingTheory/DiscreteValuationRing/Basic.lean index 518c5943e0624..214213dcd11a6 100644 --- a/Mathlib/RingTheory/DiscreteValuationRing/Basic.lean +++ b/Mathlib/RingTheory/DiscreteValuationRing/Basic.lean @@ -3,10 +3,10 @@ Copyright (c) 2020 Kevin Buzzard. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kevin Buzzard -/ -import Mathlib.RingTheory.PrincipalIdealDomain -import Mathlib.RingTheory.Valuation.PrimeMultiplicity import Mathlib.RingTheory.AdicCompletion.Basic import Mathlib.RingTheory.LocalRing.MaximalIdeal.Basic +import Mathlib.RingTheory.Valuation.PrimeMultiplicity +import Mathlib.RingTheory.Valuation.ValuationRing /-! # Discrete valuation rings @@ -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 @@ -452,3 +450,31 @@ instance (R : Type*) [CommRing R] [IsDomain R] [DiscreteValuationRing R] : rwa [← addVal_eq_top_iff, PartENat.eq_top_iff_forall_le] end DiscreteValuationRing + + +section + +variable (A : Type u) [CommRing A] [IsDomain A] [DiscreteValuationRing A] + +/-- A DVR is a valuation ring. -/ +instance (priority := 100) of_discreteValuationRing : ValuationRing A := by + constructor + intro a b + by_cases ha : a = 0; · use 0; right; simp [ha] + by_cases hb : b = 0; · use 0; left; simp [hb] + obtain ⟨ϖ, hϖ⟩ := DiscreteValuationRing.exists_irreducible A + obtain ⟨m, u, rfl⟩ := DiscreteValuationRing.eq_unit_mul_pow_irreducible ha hϖ + obtain ⟨n, v, rfl⟩ := DiscreteValuationRing.eq_unit_mul_pow_irreducible hb hϖ + rcases le_total m n with h | h + · use (u⁻¹ * v : Aˣ) * ϖ ^ (n - m); left + simp_rw [mul_comm (u : A), Units.val_mul, ← mul_assoc, mul_assoc _ (u : A)] + simp only [Units.mul_inv, mul_one, mul_comm _ (v : A), mul_assoc, ← pow_add] + congr 2 + exact Nat.add_sub_of_le h + · use (v⁻¹ * u : Aˣ) * ϖ ^ (m - n); right + simp_rw [mul_comm (v : A), Units.val_mul, ← mul_assoc, mul_assoc _ (v : A)] + simp only [Units.mul_inv, mul_one, mul_comm _ (u : A), mul_assoc, ← pow_add] + congr 2 + exact Nat.add_sub_of_le h + +end diff --git a/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean b/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean index 96d349b2cab5b..5957f090f0b89 100644 --- a/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean +++ b/Mathlib/RingTheory/DiscreteValuationRing/TFAE.lean @@ -3,10 +3,9 @@ Copyright (c) 2022 Andrew Yang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ -import Mathlib.RingTheory.Ideal.Cotangent import Mathlib.RingTheory.DedekindDomain.Basic -import Mathlib.RingTheory.Valuation.ValuationRing -import Mathlib.RingTheory.Nakayama +import Mathlib.RingTheory.DiscreteValuationRing.Basic +import Mathlib.RingTheory.Ideal.Cotangent /-! @@ -28,9 +27,9 @@ 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] -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 ≠ ⊥) : @@ -167,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..4db4a640eef89 100644 --- a/Mathlib/RingTheory/EisensteinCriterion.lean +++ b/Mathlib/RingTheory/EisensteinCriterion.lean @@ -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 65b40d237017c..c23b4328ea0fb 100644 --- a/Mathlib/RingTheory/EssentialFiniteness.lean +++ b/Mathlib/RingTheory/EssentialFiniteness.lean @@ -34,7 +34,7 @@ class EssFiniteType : Prop where IsLocalization ((IsUnit.submonoid S).comap (algebraMap (adjoin R (s : Set S)) S)) S /-- Let `S` be an `R`-algebra essentially of finite type, this is a choice of a finset `s ⊆ S` -such that `S` is the localization of `R[s]`. -/ +such that `S` is the localization of `R[s]`. -/ noncomputable def EssFiniteType.finset [h : EssFiniteType R S] : Finset S := h.cond.choose diff --git a/Mathlib/RingTheory/Etale/Basic.lean b/Mathlib/RingTheory/Etale/Basic.lean index 0a5d43bc3a05a..70ab05f56b544 100644 --- a/Mathlib/RingTheory/Etale/Basic.lean +++ b/Mathlib/RingTheory/Etale/Basic.lean @@ -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. @@ -56,7 +56,6 @@ 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 iff_unramified_and_smooth : FormallyEtale R A ↔ FormallyUnramified R A ∧ FormallySmooth R A := by diff --git a/Mathlib/RingTheory/Filtration.lean b/Mathlib/RingTheory/Filtration.lean index a73354fbc33c0..8ce8b760670a3 100644 --- a/Mathlib/RingTheory/Filtration.lean +++ b/Mathlib/RingTheory/Filtration.lean @@ -294,11 +294,11 @@ theorem submodule_eq_span_le_iff_stable_ge (n₀ : ℕ) : · intro H n hn refine (F.smul_le n).antisymm ?_ intro x hx - obtain ⟨l, hl⟩ := (Finsupp.mem_span_iff_total _ _ _).mp (H _ ⟨x, hx, rfl⟩) + obtain ⟨l, hl⟩ := (Finsupp.mem_span_iff_linearCombination _ _ _).mp (H _ ⟨x, hx, rfl⟩) replace hl := congr_arg (fun f : ℕ →₀ M => f (n + 1)) hl dsimp only at hl erw [Finsupp.single_eq_same] at hl - rw [← hl, Finsupp.total_apply, Finsupp.sum_apply] + rw [← hl, Finsupp.linearCombination_apply, Finsupp.sum_apply] apply Submodule.sum_mem _ _ rintro ⟨_, _, ⟨n', rfl⟩, _, ⟨hn', rfl⟩, m, hm, rfl⟩ - dsimp only [Subtype.coe_mk] diff --git a/Mathlib/RingTheory/FiniteLength.lean b/Mathlib/RingTheory/FiniteLength.lean new file mode 100644 index 0000000000000..d0305806bd193 --- /dev/null +++ b/Mathlib/RingTheory/FiniteLength.lean @@ -0,0 +1,78 @@ +/- +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.Order.Atoms.Finite +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⟩ diff --git a/Mathlib/RingTheory/FinitePresentation.lean b/Mathlib/RingTheory/FinitePresentation.lean index a2955e2776f05..b5f8a9e4728c8 100644 --- a/Mathlib/RingTheory/FinitePresentation.lean +++ b/Mathlib/RingTheory/FinitePresentation.lean @@ -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 @@ -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 6272fa5f1de4d..ed78e1a416de7 100644 --- a/Mathlib/RingTheory/FiniteType.lean +++ b/Mathlib/RingTheory/FiniteType.lean @@ -45,7 +45,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 @@ -122,7 +122,8 @@ theorem iff_quotient_freeAlgebra : intro x have hrw : (↑s : Set A) = fun x : A => x ∈ s.val := rfl rw [← Set.mem_range, ← AlgHom.coe_range] - erw [← adjoin_eq_range_freeAlgebra_lift, ← hrw, hs] + erw [← adjoin_eq_range_freeAlgebra_lift] + simp_rw [← hrw, hs] exact Set.mem_univ x · rintro ⟨s, ⟨f, hsur⟩⟩ exact FiniteType.of_surjective (FiniteType.freeAlgebra R s) f hsur @@ -137,7 +138,8 @@ theorem iff_quotient_mvPolynomial : use s, MvPolynomial.aeval (↑) intro x have hrw : (↑s : Set S) = fun x : S => x ∈ s.val := rfl - rw [← Set.mem_range, ← AlgHom.coe_range, ← adjoin_eq_range, ← hrw, hs] + rw [← Set.mem_range, ← AlgHom.coe_range, ← adjoin_eq_range] + simp_rw [← hrw, hs] exact Set.mem_univ x · rintro ⟨s, ⟨f, hsur⟩⟩ exact FiniteType.of_surjective (FiniteType.mvPolynomial R { x // x ∈ s }) f hsur @@ -205,6 +207,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 @@ -226,8 +229,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 @@ -240,15 +242,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 @@ -257,11 +252,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 @@ -744,7 +735,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 208f3f7f870cb..0039e1437e417 100644 --- a/Mathlib/RingTheory/Finiteness.lean +++ b/Mathlib/RingTheory/Finiteness.lean @@ -11,6 +11,7 @@ import Mathlib.GroupTheory.Finiteness import Mathlib.RingTheory.Ideal.Maps import Mathlib.RingTheory.Nilpotent.Defs import Mathlib.LinearAlgebra.Basis.Cardinality +import Mathlib.Tactic.Algebraize /-! # Finiteness conditions in commutative algebra @@ -35,6 +36,7 @@ In this file we define a notion of finiteness that is common in commutative alge open Function (Surjective) +open Finsupp namespace Submodule @@ -274,14 +276,14 @@ theorem fg_of_fg_map_of_fg_inf_ker {R M P : Type*} [Ring R] [AddCommGroup M] [Mo have : f x ∈ s.map f := by rw [mem_map] exact ⟨x, hx, rfl⟩ - rw [← ht1, ← Set.image_id (t1 : Set P), Finsupp.mem_span_image_iff_total] at this + rw [← ht1, ← Set.image_id (t1 : Set P), Finsupp.mem_span_image_iff_linearCombination] at this rcases this with ⟨l, hl1, hl2⟩ refine mem_sup.2 - ⟨(Finsupp.total M M R id).toFun ((Finsupp.lmapDomain R R g : (P →₀ R) → M →₀ R) l), ?_, - x - Finsupp.total M M R id ((Finsupp.lmapDomain R R g : (P →₀ R) → M →₀ R) l), ?_, + ⟨(linearCombination R id).toFun ((lmapDomain R R g : (P →₀ R) → M →₀ R) l), ?_, + x - linearCombination R id ((lmapDomain R R g : (P →₀ R) → M →₀ R) l), ?_, add_sub_cancel _ _⟩ - · rw [← Set.image_id (g '' ↑t1), Finsupp.mem_span_image_iff_total] + · rw [← Set.image_id (g '' ↑t1), Finsupp.mem_span_image_iff_linearCombination] refine ⟨_, ?_, rfl⟩ haveI : Inhabited P := ⟨0⟩ rw [← Finsupp.lmapDomain_supported _ _ g, mem_map] @@ -290,14 +292,14 @@ theorem fg_of_fg_map_of_fg_inf_ker {R M P : Type*} [Ring R] [AddCommGroup M] [Mo rw [ht2, mem_inf] constructor · apply s.sub_mem hx - rw [Finsupp.total_apply, Finsupp.lmapDomain_apply, Finsupp.sum_mapDomain_index] + rw [Finsupp.linearCombination_apply, Finsupp.lmapDomain_apply, Finsupp.sum_mapDomain_index] · refine s.sum_mem ?_ intro y hy exact s.smul_mem _ (hg y (hl1 hy)).1 · exact zero_smul _ · exact fun _ _ _ => add_smul _ _ _ · rw [LinearMap.mem_ker, f.map_sub, ← hl2] - rw [Finsupp.total_apply, Finsupp.total_apply, Finsupp.lmapDomain_apply] + rw [Finsupp.linearCombination_apply, Finsupp.linearCombination_apply, Finsupp.lmapDomain_apply] rw [Finsupp.sum_mapDomain_index, Finsupp.sum, Finsupp.sum, map_sum] · rw [sub_eq_zero] refine Finset.sum_congr rfl fun y hy => ?_ @@ -311,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. -/ @@ -377,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⟩ @@ -498,7 +500,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 @@ -508,7 +510,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 @@ -526,46 +528,47 @@ 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 := +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 ?_⟩ @@ -575,24 +578,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 _) @@ -600,7 +603,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} @@ -639,7 +642,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), @@ -699,7 +702,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] [AddCommGroup M] [Module R M] {ι} [Module.Finite R M] (b : Basis ι R M) : _root_.Finite ι := let ⟨s, hs⟩ := ‹Module.Finite R M› @@ -757,6 +760,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 @@ -775,20 +779,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 80c9c48425e01..813b32f84d0ac 100644 --- a/Mathlib/RingTheory/Flat/Basic.lean +++ b/Mathlib/RingTheory/Flat/Basic.lean @@ -3,17 +3,16 @@ 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 -/ -import Mathlib.RingTheory.Noetherian -import Mathlib.Algebra.DirectSum.Module import Mathlib.Algebra.DirectSum.Finsupp -import Mathlib.Algebra.Module.Projective -import Mathlib.Algebra.Module.Injective +import Mathlib.Algebra.DirectSum.Module +import Mathlib.Algebra.Exact import Mathlib.Algebra.Module.CharacterModule +import Mathlib.Algebra.Module.Injective +import Mathlib.Algebra.Module.Projective import Mathlib.LinearAlgebra.DirectSum.TensorProduct import Mathlib.LinearAlgebra.FreeModule.Basic -import Mathlib.Algebra.Module.Projective import Mathlib.LinearAlgebra.TensorProduct.RightExactness -import Mathlib.Algebra.Exact +import Mathlib.RingTheory.Noetherian /-! # Flat modules @@ -74,6 +73,10 @@ the canonical map `I ⊗ M →ₗ M` is injective. -/ namespace Flat +variable {R} in +instance instSubalgebraToSubmodule {S : Type v} [Ring S] [Algebra R S] + (A : Subalgebra R S) [Flat R A] : Flat R (Subalgebra.toSubmodule A) := ‹Flat R A› + instance self (R : Type u) [CommRing R] : Flat R R := ⟨by intro I _ @@ -169,7 +172,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 @@ -281,7 +284,7 @@ lemma lTensor_exact [Small.{v} R] [flat : Flat R M] ⦃N N' N'' : Type v⦄ 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 + (inj := iff_lTensor_preserves_injective_linearMap R M |>.mp flat _ <| by simpa [ι] using Subtype.val_injective) (h0 := map_zero _) @@ -301,7 +304,7 @@ lemma rTensor_exact [Small.{v} R] [flat : Flat R M] ⦃N N' N'' : Type v⦄ 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 + (inj := iff_rTensor_preserves_injective_linearMap R M |>.mp flat _ <| by simpa [ι] using Subtype.val_injective) (h0 := map_zero _) diff --git a/Mathlib/RingTheory/Flat/CategoryTheory.lean b/Mathlib/RingTheory/Flat/CategoryTheory.lean index 3d88a691a2bac..ea6d1442dad38 100644 --- a/Mathlib/RingTheory/Flat/CategoryTheory.lean +++ b/Mathlib/RingTheory/Flat/CategoryTheory.lean @@ -36,33 +36,33 @@ namespace Module.Flat variable {R : Type u} [CommRing R] (M : ModuleCat.{u} R) -lemma lTensor_shortComplex_exact [Flat R M] (C : ShortComplex $ ModuleCat R) (hC : C.Exact) : +lemma lTensor_shortComplex_exact [Flat R M] (C : ShortComplex <| ModuleCat R) (hC : C.Exact) : C.map (tensorLeft M) |>.Exact := by rw [moduleCat_exact_iff_function_exact] at hC ⊢ exact lTensor_exact M hC -lemma rTensor_shortComplex_exact [Flat R M] (C : ShortComplex $ ModuleCat R) (hC : C.Exact) : +lemma rTensor_shortComplex_exact [Flat R M] (C : ShortComplex <| ModuleCat R) (hC : C.Exact) : C.map (tensorRight M) |>.Exact := by rw [moduleCat_exact_iff_function_exact] at hC ⊢ exact rTensor_exact M hC lemma iff_lTensor_preserves_shortComplex_exact : Flat R M ↔ - ∀ (C : ShortComplex $ ModuleCat R) (_ : C.Exact), (C.map (tensorLeft M) |>.Exact) := - ⟨fun _ _ ↦ lTensor_shortComplex_exact _ _, fun H ↦ iff_lTensor_exact.2 $ + ∀ (C : ShortComplex <| ModuleCat R) (_ : C.Exact), (C.map (tensorLeft M) |>.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) + moduleCat_exact_iff_function_exact _ |>.1 <| + H (.mk (ModuleCat.asHom f) (ModuleCat.asHom g) (DFunLike.ext _ _ h.apply_apply_eq_zero)) (moduleCat_exact_iff_function_exact _ |>.2 h)⟩ lemma iff_rTensor_preserves_shortComplex_exact : Flat R M ↔ - ∀ (C : ShortComplex $ ModuleCat R) (_ : C.Exact), (C.map (tensorRight M) |>.Exact) := - ⟨fun _ _ ↦ rTensor_shortComplex_exact _ _, fun H ↦ iff_rTensor_exact.2 $ + ∀ (C : ShortComplex <| ModuleCat R) (_ : C.Exact), (C.map (tensorRight M) |>.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) + moduleCat_exact_iff_function_exact _ |>.1 <| + 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 42f4b8bf28bd1..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 @@ -144,20 +142,20 @@ theorem tfae_equational_criterion : List.TFAE [ _ = 0 := hfx obtain ⟨κ, hκ, a', y', ⟨ha'y', ha'⟩⟩ := h₄ this use κ, hκ - use Finsupp.total ι (κ →₀ R) R (fun i ↦ equivFunOnFinite.symm (a' i)) - use Finsupp.total κ M R y' + use Finsupp.linearCombination R (fun i ↦ equivFunOnFinite.symm (a' i)) + use Finsupp.linearCombination R y' constructor · apply Finsupp.basisSingleOne.ext intro i - simpa [total_apply, sum_fintype, Finsupp.single_apply] using ha'y' i + simpa [linearCombination_apply, sum_fintype, Finsupp.single_apply] using ha'y' i · ext j - simp only [total_apply, zero_smul, implies_true, sum_fintype, finset_sum_apply] + 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.total ι M R x - have : x' f' = 0 := by simpa [x', f', total_apply, sum_fintype] using hfx + let x' : (ι →₀ R) →ₗ[R] M := Finsupp.linearCombination R x + have : x' f' = 0 := by simpa [x', f', linearCombination_apply, sum_fintype] using hfx obtain ⟨κ, hκ, a', y', ha'y', ha'⟩ := h₅ this refine ⟨κ, hκ, fun i ↦ a' (single i 1), fun j ↦ y' (single j 1), fun i ↦ ?_, fun j ↦ ?_⟩ · simpa [x', ← map_smul, ← map_sum, smul_single] using @@ -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/Stability.lean b/Mathlib/RingTheory/Flat/Stability.lean index 27ba15c69ed04..57de113408f23 100644 --- a/Mathlib/RingTheory/Flat/Stability.lean +++ b/Mathlib/RingTheory/Flat/Stability.lean @@ -22,7 +22,7 @@ We show that flatness is stable under composition and base change. then `S ⊗[R] M` is `S`-flat. * `Module.Flat.of_isLocalizedModule`: if `M` is a flat `R`-module and `S` is a submonoid of `R` then the localization of `M` at `S` is flat as a module - for the localzation of `R` at `S`. + for the localization of `R` at `S`. -/ universe u v w t diff --git a/Mathlib/RingTheory/FractionalIdeal/Basic.lean b/Mathlib/RingTheory/FractionalIdeal/Basic.lean index 155b25b1b2ad7..4ebe1fa201f1f 100644 --- a/Mathlib/RingTheory/FractionalIdeal/Basic.lean +++ b/Mathlib/RingTheory/FractionalIdeal/Basic.lean @@ -462,6 +462,10 @@ theorem sup_eq_add (I J : FractionalIdeal S P) : I ⊔ J = I + J := theorem coe_add (I J : FractionalIdeal S P) : (↑(I + J) : Submodule R P) = I + J := rfl +theorem mem_add (I J : FractionalIdeal S P) (x : P) : + x ∈ I + J ↔ ∃ i ∈ I, ∃ j ∈ J, i + j = x := by + rw [← mem_coe, coe_add, Submodule.add_eq_sup]; exact Submodule.mem_sup + @[simp, norm_cast] theorem coeIdeal_sup (I J : Ideal R) : ↑(I ⊔ J) = (I + J : FractionalIdeal S P) := coeToSubmodule_injective <| coeSubmodule_sup _ _ _ diff --git a/Mathlib/RingTheory/FractionalIdeal/Extended.lean b/Mathlib/RingTheory/FractionalIdeal/Extended.lean new file mode 100644 index 0000000000000..c2dcadde7c9b5 --- /dev/null +++ b/Mathlib/RingTheory/FractionalIdeal/Extended.lean @@ -0,0 +1,111 @@ +/- +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.RingTheory.FractionalIdeal.Basic + +/-! +# Extension of fractional ideals + +This file defines the extension of a fractional ideal along a ring homomorphism. + +## Main definition + +* `FractionalIdeal.extended`: Let `A` and `B` be commutative rings with respective localizations + `IsLocalization M K` and `IsLocalization N L`. Let `f : A →+* B` be a ring homomorphism with + `hf : M ≤ Submonoid.comap f N`. If `I : FractionalIdeal M K`, then the extension of `I` along + `f` is `extended L hf I : FractionalIdeal N L`. + +## Main results + +* `extended_add` says that extension commutes with addition. +* `extended_mul` says that extension commutes with multiplication. + +## Tags + +fractional ideal, fractional ideals, extended, extension +-/ + +open IsLocalization FractionalIdeal Submodule + +namespace FractionalIdeal + +variable {A : Type*} [CommRing A] {B : Type*} [CommRing B] {f : A →+* B} +variable {K : Type*} {M : Submonoid A} [CommRing K] [Algebra A K] [IsLocalization M K] +variable (L : Type*) {N : Submonoid B} [CommRing L] [Algebra B L] [IsLocalization N L] +variable (hf : M ≤ Submonoid.comap f N) +variable (I : FractionalIdeal M K) (J : FractionalIdeal M K) + +/-- Given commutative rings `A` and `B` with respective localizations `IsLocalization M K` and +`IsLocalization N L`, and a ring homomorphism `f : A →+* B` satisfying `M ≤ Submonoid.comap f N`, a +fractional ideal `I` of `A` can be extended along `f` to a fractional ideal of `B`. -/ +def extended (I : FractionalIdeal M K) : FractionalIdeal N L where + val := span B <| (IsLocalization.map (S := K) L f hf) '' I + 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 ↦ ?_) + · rcases hx with ⟨k, kI, rfl⟩ + obtain ⟨c, hc⟩ := frac k kI + exact ⟨f c, by simp [← IsLocalization.map_smul, ← hc]⟩ + · rw [← smul_assoc, smul_eq_mul, mul_comm (f a), ← smul_eq_mul, smul_assoc] + exact isInteger_smul hc + +local notation "map_f" => (IsLocalization.map (S := K) L f hf) + +lemma mem_extended_iff (x : L) : (x ∈ I.extended L hf) ↔ x ∈ span B (map_f '' I) := by + constructor <;> { intro hx; simpa } + +@[simp] +lemma coe_extended_eq_span : I.extended L hf = span B (map_f '' I) := by + ext; simp [mem_coe, mem_extended_iff] + +@[simp] +theorem extended_zero : extended L hf (0 : FractionalIdeal M K) = 0 := + have : ((0 : FractionalIdeal M K) : Set K) = {0} := by ext; simp + coeToSubmodule_injective (by simp [this]) + +@[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), ?_⟩ + · rintro ⟨b, _, rfl⟩ + rw [Algebra.linearMap_apply, Algebra.algebraMap_eq_smul_one] + exact smul_mem _ _ <| subset_span ⟨1, by simp [one_mem_one]⟩ + · rintro _ ⟨_, ⟨a, ha, rfl⟩, rfl⟩ + exact ⟨f a, ha, by rw [Algebra.linearMap_apply, Algebra.linearMap_apply, map_eq]⟩ + +theorem extended_add : (I + J).extended L hf = (I.extended L hf) + (J.extended L hf) := by + apply coeToSubmodule_injective + simp only [coe_extended_eq_span, coe_add, Submodule.add_eq_sup, ← span_union, ← Set.image_union] + apply Submodule.span_eq_span + · rintro _ ⟨y, hy, rfl⟩ + obtain ⟨i, hi, j, hj, rfl⟩ := (mem_add I J y).mp <| SetLike.mem_coe.mp hy + rw [RingHom.map_add] + exact add_mem (Submodule.subset_span ⟨i, Set.mem_union_left _ hi, by simp⟩) + (Submodule.subset_span ⟨j, Set.mem_union_right _ hj, by simp⟩) + · rintro _ ⟨y, hy, rfl⟩ + suffices y ∈ I + J from SetLike.mem_coe.mpr <| Submodule.subset_span ⟨y, by simp [this]⟩ + exact hy.elim (fun h ↦ (mem_add I J y).mpr ⟨y, h, 0, zero_mem J, add_zero y⟩) + (fun h ↦ (mem_add I J y).mpr ⟨0, zero_mem I, y, h, zero_add y⟩) + +theorem extended_mul : (I * J).extended L hf = (I.extended L hf) * (J.extended L hf) := by + apply coeToSubmodule_injective + simp only [coe_extended_eq_span, coe_mul, span_mul_span] + refine Submodule.span_eq_span (fun _ h ↦ ?_) (fun _ h ↦ ?_) + · 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 ↦ ?_) + · 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⟩ + · exact map_add map_f y z ▸ Submodule.add_mem _ hy hz + · rw [Algebra.smul_def, map_mul, map_eq, ← Algebra.smul_def] + exact smul_mem _ (f a) hy + · rcases Set.mem_mul.mp h with ⟨y, ⟨i, hi, rfl⟩, z, ⟨j, hj, rfl⟩, rfl⟩ + exact Submodule.subset_span ⟨i * j, mul_mem_mul hi hj, by simp⟩ + +end FractionalIdeal diff --git a/Mathlib/RingTheory/FractionalIdeal/Operations.lean b/Mathlib/RingTheory/FractionalIdeal/Operations.lean index 56982ee5c698d..d6ab280bcde60 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 @@ -226,7 +227,7 @@ theorem canonicalEquiv_symm : (canonicalEquiv S P P').symm = canonicalEquiv S P' exact ⟨fun ⟨y, mem, Eq⟩ => ⟨y, mem, Eq⟩, fun ⟨y, mem, Eq⟩ => ⟨y, mem, Eq⟩⟩ theorem canonicalEquiv_flip (I) : canonicalEquiv S P P' (canonicalEquiv S P' P I) = I := by - rw [← canonicalEquiv_symm]; erw [RingEquiv.apply_symm_apply] + rw [← canonicalEquiv_symm, RingEquiv.symm_apply_apply] @[simp] theorem canonicalEquiv_canonicalEquiv (P'' : Type*) [CommRing P''] [Algebra R P''] @@ -454,7 +455,7 @@ theorem eq_one_div_of_mul_eq_one_right (I J : FractionalIdeal R₁⁰ K) (h : I apply (le_div_iff_of_nonzero hI).mpr _ intro y hy x hx rw [mul_comm] - exact mul_mem_mul hx hy + exact mul_mem_mul hy hx theorem mul_div_self_cancel_iff {I : FractionalIdeal R₁⁰ K} : I * (1 / I) = 1 ↔ ∃ J, I * J = 1 := ⟨fun h => ⟨1 / I, h⟩, fun ⟨J, hJ⟩ => by rwa [← eq_one_div_of_mul_eq_one_right I J hJ]⟩ diff --git a/Mathlib/RingTheory/Generators.lean b/Mathlib/RingTheory/Generators.lean index d55ec361f5c74..3ded91b21c690 100644 --- a/Mathlib/RingTheory/Generators.lean +++ b/Mathlib/RingTheory/Generators.lean @@ -45,7 +45,7 @@ variable (R : Type u) (S : Type v) [CommRing R] [CommRing S] [Algebra R S] 2. `val : vars → S`: The assignment of each variable to a value in `S`. 3. `σ`: A section of `R[X] → S`. -/ structure Algebra.Generators where - /-- The type of variables. -/ + /-- The type of variables. -/ vars : Type w /-- The assignment of each variable to a value in `S`. -/ val : vars → S @@ -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) : @@ -145,7 +157,7 @@ def localizationAway : Generators R S where letI n : ℕ := (IsLocalization.Away.sec r s).2 C a * X () ^ n aeval_val_σ' s := by - rw [_root_.map_mul, algHom_C, map_pow, aeval_X] + rw [map_mul, algHom_C, map_pow, aeval_X] simp only [← IsLocalization.Away.sec_spec, map_pow, IsLocalization.Away.invSelf] rw [← IsLocalization.mk'_pow, one_pow, ← IsLocalization.mk'_one (M := Submonoid.powers r) S r] rw [← IsLocalization.mk'_pow, one_pow, mul_assoc, ← IsLocalization.mk'_mul] @@ -157,7 +169,7 @@ end Localization variable {T} [CommRing T] [Algebra R T] [Algebra S T] [IsScalarTower R S T] /-- Given two families of generators `S[X] → T` and `R[Y] → S`, -we may constuct the family of generators `R[X, Y] → T`. -/ +we may construct the family of generators `R[X, Y] → T`. -/ @[simps val, simps (config := .lemmasOnly) vars σ] noncomputable def comp (Q : Generators S T) (P : Generators R S) : Generators R T where @@ -166,11 +178,11 @@ def comp (Q : Generators S T) (P : Generators R S) : Generators R T where σ' x := (Q.σ x).sum (fun n r ↦ rename Sum.inr (P.σ r) * monomial (n.mapDomain Sum.inl) 1) aeval_val_σ' s := by have (x : P.Ring) : aeval (algebraMap S T ∘ P.val) x = algebraMap S T (aeval P.val x) := by - rw [map_aeval, aeval_def, coe_eval₂Hom, ← IsScalarTower.algebraMap_eq, Function.comp] + rw [map_aeval, aeval_def, coe_eval₂Hom, ← IsScalarTower.algebraMap_eq, Function.comp_def] conv_rhs => rw [← Q.aeval_val_σ s, ← (Q.σ s).sum_single] - simp only [map_finsupp_sum, _root_.map_mul, aeval_rename, Sum.elim_comp_inr, this, aeval_val_σ, - aeval_monomial, _root_.map_one, Finsupp.prod_mapDomain_index_inj Sum.inl_injective, - Sum.elim_inl, one_mul, single_eq_monomial] + simp only [map_finsupp_sum, map_mul, aeval_rename, Sum.elim_comp_inr, this, aeval_val_σ, + aeval_monomial, map_one, Finsupp.prod_mapDomain_index_inj Sum.inl_injective, Sum.elim_inl, + one_mul, single_eq_monomial] variable (S) in /-- If `R → S → T` is a tower of algebras, a family of generators `R[X] → T` @@ -310,7 +322,7 @@ noncomputable def Hom.comp [IsScalarTower R' R'' S''] [IsScalarTower R' S' S''] induction g.val x using MvPolynomial.induction_on with | h_C r => simp [← IsScalarTower.algebraMap_apply] | h_add x y hx hy => simp only [map_add, hx, hy] - | h_X p i hp => simp only [_root_.map_mul, hp, aeval_X, aeval_val] + | h_X p i hp => simp only [map_mul, hp, aeval_X, aeval_val] @[simp] lemma Hom.comp_id [Algebra R S'] [IsScalarTower R R' S'] [IsScalarTower R S S'] (f : Hom P P') : @@ -334,7 +346,7 @@ lemma Hom.toAlgHom_comp_apply induction x using MvPolynomial.induction_on with | h_C r => simp only [← MvPolynomial.algebraMap_eq, AlgHom.map_algebraMap] | h_add x y hx hy => simp only [map_add, hx, hy] - | h_X p i hp => simp only [_root_.map_mul, hp, toAlgHom_X, comp_val]; rfl + | h_X p i hp => simp only [map_mul, hp, toAlgHom_X, comp_val]; rfl variable {T} [CommRing T] [Algebra R T] [Algebra S T] [IsScalarTower R S T] @@ -381,10 +393,10 @@ instance : AddCommGroup P.Cotangent := inferInstanceAs (AddCommGroup P.ker.Cotan variable {P} -/-- The identity map `P.ker.Cotangent → P.Cotangent` into the type synonym. -/ +/-- The identity map `P.ker.Cotangent → P.Cotangent` into the type synonym. -/ def Cotangent.of (x : P.ker.Cotangent) : P.Cotangent := x -/-- The identity map `P.Cotangent → P.ker.Cotangent` from the type synonym. -/ +/-- The identity map `P.Cotangent → P.ker.Cotangent` from the type synonym. -/ def Cotangent.val (x : P.Cotangent) : P.ker.Cotangent := x @[ext] @@ -438,7 +450,7 @@ instance {R₁ R₂} [CommRing R₁] [CommRing R₂] [Algebra R₁ S] [Algebra R constructor intros r s m show algebraMap R₂ S (r • s) • m = (algebraMap _ S r) • (algebraMap _ S s) • m - rw [Algebra.smul_def, _root_.map_mul, mul_smul, ← IsScalarTower.algebraMap_apply] + rw [Algebra.smul_def, map_mul, mul_smul, ← IsScalarTower.algebraMap_apply] lemma Cotangent.val_smul''' {R₀} [CommRing R₀] [Algebra R₀ S] (r : R₀) (x : P.Cotangent) : (r • x).val = P.σ (algebraMap R₀ S r) • x.val := rfl @@ -488,7 +500,7 @@ def Cotangent.map (f : Hom P P') : P.Cotangent →ₗ[S] P'.Cotangent where ← algebraMap_apply, algebraMap_smul, val_smul', val_of, ← (Ideal.toCotangent _).map_smul] congr 1 ext1 - simp only [SetLike.val_smul, smul_eq_mul, _root_.map_mul] + simp only [SetLike.val_smul, smul_eq_mul, map_mul] @[simp] lemma Cotangent.map_mk (f : Hom P P') (x) : diff --git a/Mathlib/RingTheory/GradedAlgebra/Basic.lean b/Mathlib/RingTheory/GradedAlgebra/Basic.lean index de86d0cc60388..0d6693692b34f 100644 --- a/Mathlib/RingTheory/GradedAlgebra/Basic.lean +++ b/Mathlib/RingTheory/GradedAlgebra/Basic.lean @@ -207,7 +207,7 @@ end DirectSum open DirectSum -/-- The projection maps of graded algebra-/ +/-- The projection maps of graded algebra -/ def GradedAlgebra.proj (𝒜 : ι → Submodule R A) [GradedAlgebra 𝒜] (i : ι) : A →ₗ[R] A := (𝒜 i).subtype.comp <| (DFinsupp.lapply i).comp <| (decomposeAlgEquiv 𝒜).toAlgHom.toLinearMap @@ -350,7 +350,7 @@ noncomputable def coeAlgEquiv (hM : DirectSum.IsInternal M) : /-- Given an `R`-algebra `A` and a family `ι → Submodule R A` of submodules parameterized by an additive monoid `ι` -and statisfying `SetLike.GradedMonoid M` (essentially, is multiplicative) +and satisfying `SetLike.GradedMonoid M` (essentially, is multiplicative) such that `DirectSum.IsInternal M` (`A` is the direct sum of the `M i`), we endow `A` with the structure of a graded algebra. The submodules are the *homogeneous* parts. -/ diff --git a/Mathlib/RingTheory/GradedAlgebra/HomogeneousIdeal.lean b/Mathlib/RingTheory/GradedAlgebra/HomogeneousIdeal.lean index f19c6b57a7077..f434e98f774a3 100644 --- a/Mathlib/RingTheory/GradedAlgebra/HomogeneousIdeal.lean +++ b/Mathlib/RingTheory/GradedAlgebra/HomogeneousIdeal.lean @@ -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 @@ -154,10 +154,10 @@ theorem Ideal.mul_homogeneous_element_mem_of_mem {I : Ideal A} (r x : A) (hx₁ theorem Ideal.homogeneous_span (s : Set A) (h : ∀ x ∈ s, Homogeneous 𝒜 x) : (Ideal.span s).IsHomogeneous 𝒜 := by rintro i r hr - rw [Ideal.span, Finsupp.span_eq_range_total] at hr + rw [Ideal.span, Finsupp.span_eq_range_linearCombination] at hr rw [LinearMap.mem_range] at hr obtain ⟨s, rfl⟩ := hr - rw [Finsupp.total_apply, Finsupp.sum, decompose_sum, DFinsupp.finset_sum_apply, + rw [Finsupp.linearCombination_apply, Finsupp.sum, decompose_sum, DFinsupp.finset_sum_apply, AddSubmonoidClass.coe_finset_sum] refine Ideal.sum_mem _ ?_ rintro z hz1 diff --git a/Mathlib/RingTheory/GradedAlgebra/HomogeneousLocalization.lean b/Mathlib/RingTheory/GradedAlgebra/HomogeneousLocalization.lean index 3822701b81a5c..ace75dcb78fce 100644 --- a/Mathlib/RingTheory/GradedAlgebra/HomogeneousLocalization.lean +++ b/Mathlib/RingTheory/GradedAlgebra/HomogeneousLocalization.lean @@ -238,7 +238,7 @@ instance : Pow (NumDenSameDeg 𝒜 x) ℕ where ⟨n • c.deg, @GradedMonoid.GMonoid.gnpow _ (fun i => ↥(𝒜 i)) _ _ n _ c.num, @GradedMonoid.GMonoid.gnpow _ (fun i => ↥(𝒜 i)) _ _ n _ c.den, by induction' n with n ih - · simpa only [Nat.zero_eq, coe_gnpow, pow_zero] using Submonoid.one_mem _ + · simpa only [coe_gnpow, pow_zero] using Submonoid.one_mem _ · simpa only [pow_succ, coe_gnpow] using x.mul_mem ih c.den_mem⟩ @[simp] @@ -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 @@ -603,7 +603,7 @@ def map (g : A →+* B) /-- Let `A` be a graded algebra and `P ≤ Q` be two submonoids, then the homogeneous localization of `A` -at `P` embedds into the homogeneous localization of `A` at `Q`. +at `P` embeds into the homogeneous localization of `A` at `Q`. -/ abbrev mapId {P Q : Submonoid A} (h : P ≤ Q) : HomogeneousLocalization 𝒜 P →+* HomogeneousLocalization 𝒜 Q := diff --git a/Mathlib/RingTheory/GradedAlgebra/Radical.lean b/Mathlib/RingTheory/GradedAlgebra/Radical.lean index 8d91baaa58401..976b7748f818d 100644 --- a/Mathlib/RingTheory/GradedAlgebra/Radical.lean +++ b/Mathlib/RingTheory/GradedAlgebra/Radical.lean @@ -168,7 +168,7 @@ theorem Ideal.IsHomogeneous.radical {I : Ideal A} (h : I.IsHomogeneous 𝒜) : rw [h.radical_eq] exact Ideal.IsHomogeneous.sInf fun _ => And.left -/-- The radical of a homogenous ideal, as another homogenous ideal. -/ +/-- The radical of a homogeneous ideal, as another homogeneous ideal. -/ def HomogeneousIdeal.radical (I : HomogeneousIdeal 𝒜) : HomogeneousIdeal 𝒜 := ⟨I.toIdeal.radical, I.isHomogeneous.radical⟩ diff --git a/Mathlib/RingTheory/HahnSeries/Basic.lean b/Mathlib/RingTheory/HahnSeries/Basic.lean index b189d32690b7d..b063204680d7f 100644 --- a/Mathlib/RingTheory/HahnSeries/Basic.lean +++ b/Mathlib/RingTheory/HahnSeries/Basic.lean @@ -321,7 +321,7 @@ theorem coeff_order_ne_zero {x : HahnSeries Γ R} (hx : x ≠ 0) : x.coeff x.ord rw [order_of_ne hx] exact x.isWF_support.min_mem (support_nonempty_iff.2 hx) -theorem order_le_of_coeff_ne_zero {Γ} [LinearOrderedCancelAddCommMonoid Γ] {x : HahnSeries Γ R} +theorem order_le_of_coeff_ne_zero {Γ} [AddMonoid Γ] [LinearOrder Γ] {x : HahnSeries Γ R} {g : Γ} (h : x.coeff g ≠ 0) : x.order ≤ g := le_trans (le_of_eq (order_of_ne (ne_zero_of_coeff_ne_zero h))) (Set.IsWF.min_le _ _ ((mem_support _ _).2 h)) diff --git a/Mathlib/RingTheory/HahnSeries/Multiplication.lean b/Mathlib/RingTheory/HahnSeries/Multiplication.lean index 148770477311f..153ac24993c5d 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 /-! @@ -228,10 +229,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 +253,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 @@ -386,7 +387,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 @@ -753,7 +754,7 @@ 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] refine ⟨a, ?_⟩ diff --git a/Mathlib/RingTheory/HahnSeries/PowerSeries.lean b/Mathlib/RingTheory/HahnSeries/PowerSeries.lean index e37029a7b20db..094a71acddd64 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` @@ -87,7 +93,7 @@ theorem ofPowerSeries_injective : Function.Injective (ofPowerSeries Γ R) := embDomain_injective.comp toPowerSeries.symm.injective /-@[simp] Porting note: removing simp. RHS is more complicated and it makes linter -failures elsewhere-/ +failures elsewhere -/ theorem ofPowerSeries_apply (x : PowerSeries R) : ofPowerSeries Γ R x = HahnSeries.embDomain @@ -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 732438273dbdb..871e001eae93b 100644 --- a/Mathlib/RingTheory/HahnSeries/Summable.lean +++ b/Mathlib/RingTheory/HahnSeries/Summable.lean @@ -53,7 +53,7 @@ theorem isPWO_iUnion_support_powers [LinearOrderedCancelAddCommMonoid Γ] [Ring (le_trans (le_of_lt hx) (orderTop_le_of_coeff_ne_zero hg)) refine Set.iUnion_subset fun n => ?_ induction' n with n ih <;> intro g hn - · simp only [Nat.zero_eq, pow_zero, support_one, Set.mem_singleton_iff] at hn + · simp only [pow_zero, support_one, Set.mem_singleton_iff] at hn rw [hn, SetLike.mem_coe] exact AddSubmonoid.zero_mem _ · obtain ⟨i, hi, j, hj, rfl⟩ := support_mul_subset_add_support hn @@ -418,8 +418,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) @@ -505,7 +505,7 @@ instance instField [Field R] : Field (HahnSeries Γ R) where (single (-x.order)) (x.leadingCoeff)⁻¹ * (SummableFamily.powers _ (unit_aux x (inv_mul_cancel₀ (leadingCoeff_ne_iff.mpr x0)))).hsum inv_zero := dif_pos rfl - mul_inv_cancel x x0 := (congr rfl (dif_neg x0)).trans $ by + mul_inv_cancel x x0 := (congr rfl (dif_neg x0)).trans <| by have h := SummableFamily.one_sub_self_mul_hsum_powers (unit_aux x (inv_mul_cancel₀ (leadingCoeff_ne_iff.mpr x0))) diff --git a/Mathlib/RingTheory/HahnSeries/Valuation.lean b/Mathlib/RingTheory/HahnSeries/Valuation.lean index 86b6d16e4a9a0..95c72f7dfe144 100644 --- a/Mathlib/RingTheory/HahnSeries/Valuation.lean +++ b/Mathlib/RingTheory/HahnSeries/Valuation.lean @@ -35,7 +35,7 @@ section Valuation 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. -/ + 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) fun x y => by diff --git a/Mathlib/RingTheory/Henselian.lean b/Mathlib/RingTheory/Henselian.lean index 85b5017c6df8f..b1762c379f824 100644 --- a/Mathlib/RingTheory/Henselian.lean +++ b/Mathlib/RingTheory/Henselian.lean @@ -121,10 +121,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 +135,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φ, @@ -195,13 +194,13 @@ instance (priority := 100) IsAdicComplete.henselianRing (R : Type*) [CommRing R] 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) + 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 intro n induction' n with n ih - · simpa only [Nat.zero_eq, Nat.rec_zero, zero_add, pow_one] using h₁ + · simpa only [Nat.rec_zero, zero_add, pow_one] using h₁ rw [← taylor_eval_sub (c n), hc, sub_eq_add_neg, sub_eq_add_neg, add_neg_cancel_comm] rw [eval_eq_sum, sum_over_range' _ _ _ (lt_add_of_pos_right _ zero_lt_two), ← @@ -230,13 +229,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/HopfAlgebra.lean b/Mathlib/RingTheory/HopfAlgebra.lean index 20f1a7ca2575f..7356afd1a4d6f 100644 --- a/Mathlib/RingTheory/HopfAlgebra.lean +++ b/Mathlib/RingTheory/HopfAlgebra.lean @@ -28,6 +28,9 @@ agree then the antipodes must also agree). * If `A` is commutative then `antipode` is necessarily a bijection and its square is the identity. +(Note that all three facts have been proved for Hopf bimonoids in an arbitrary braided category, +so we could deduce the facts here from an equivalence `HopfAlgebraCat R ≌ Hopf_ (ModuleCat R)`.) + ## References * diff --git a/Mathlib/RingTheory/Ideal/AssociatedPrime.lean b/Mathlib/RingTheory/Ideal/AssociatedPrime.lean index e37e8ce6c85bf..b4ddec4e36127 100644 --- a/Mathlib/RingTheory/Ideal/AssociatedPrime.lean +++ b/Mathlib/RingTheory/Ideal/AssociatedPrime.lean @@ -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) diff --git a/Mathlib/RingTheory/Ideal/Basic.lean b/Mathlib/RingTheory/Ideal/Basic.lean index bb631626fa74b..69a42212b475e 100644 --- a/Mathlib/RingTheory/Ideal/Basic.lean +++ b/Mathlib/RingTheory/Ideal/Basic.lean @@ -28,14 +28,14 @@ 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. -/ +`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 @@ -76,9 +76,9 @@ theorem sum_mem (I : Ideal α) {ι : Type*} {t : Finset ι} {f : ι → α} : theorem eq_top_of_unit_mem (x y : α) (hx : x ∈ I) (h : y * x = 1) : I = ⊤ := eq_top_iff.2 fun z _ => calc - z = z * (y * x) := by simp [h] - _ = z * y * x := Eq.symm <| mul_assoc z y x - _ ∈ I := I.mul_mem_left _ hx + 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 @@ -149,6 +149,9 @@ theorem mem_span_insert {s : Set α} {x y} : 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 _ _ @@ -184,8 +187,8 @@ theorem span_eq_top_iff_finite (s : Set α) : 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 +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⟩ @@ -431,9 +434,6 @@ theorem mul_unit_mem_iff_mem {x y : α} (hy : IsUnit y) : x * y ∈ I ↔ x ∈ 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 @@ -490,6 +490,9 @@ theorem mul_mem_right (h : a ∈ I) : a * b ∈ I := 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 @@ -570,7 +573,7 @@ theorem span_pow_eq_top (s : Set α) (hs : span s = ⊤) (n : ℕ) : · rw [Set.image_empty, hs] trivial · exact subset_span ⟨_, hx, pow_zero _⟩ - rw [eq_top_iff_one, span, Finsupp.mem_span_iff_total] at hs + rw [eq_top_iff_one, span, Finsupp.mem_span_iff_linearCombination] at hs rcases hs with ⟨f, hf⟩ have hf : (f.support.sum fun a => f a * a) = 1 := hf -- Porting note: was `change ... at hf` have := sum_pow_mem_span_pow f.support (fun a => f a * a) n @@ -802,6 +805,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) + [IsLocalRingHom 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/Cotangent.lean b/Mathlib/RingTheory/Ideal/Cotangent.lean index 3156cab853769..9ce01fea0e26b 100644 --- a/Mathlib/RingTheory/Ideal/Cotangent.lean +++ b/Mathlib/RingTheory/Ideal/Cotangent.lean @@ -149,8 +149,9 @@ theorem cotangentEquivIdeal_apply (x : I.Cotangent) : theorem cotangentEquivIdeal_symm_apply (x : R) (hx : x ∈ I) : -- Note: #8386 had to specify `(R₂ := R)` because `I.toCotangent` suggested `R ⧸ I^2` instead - I.cotangentEquivIdeal.symm ⟨(I ^ 2).mkQ x, Submodule.mem_map_of_mem (R₂ := R) hx⟩ = - I.toCotangent ⟨x, hx⟩ := by + I.cotangentEquivIdeal.symm ⟨(I ^ 2).mkQ x, + Submodule.mem_map_of_mem (F := R →ₗ[R] R ⧸ I ^ 2) (f := (I ^ 2).mkQ) hx⟩ = + I.toCotangent (R := R) ⟨x, hx⟩ := by apply I.cotangentEquivIdeal.injective rw [I.cotangentEquivIdeal.apply_symm_apply] ext @@ -250,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/Maps.lean b/Mathlib/RingTheory/Ideal/Maps.lean index 04c32e6e803d6..5a46dd702e132 100644 --- a/Mathlib/RingTheory/Ideal/Maps.lean +++ b/Mathlib/RingTheory/Ideal/Maps.lean @@ -125,11 +125,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 +173,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] @@ -220,7 +233,7 @@ theorem smul_restrictScalars {R S M} [CommSemiring R] [CommSemiring S] (I.map (algebraMap R S) • N).restrictScalars R = I • N.restrictScalars R := by simp_rw [map, Submodule.span_smul_eq, ← Submodule.coe_set_smul, Submodule.set_smul_eq_iSup, ← element_smul_restrictScalars, iSup_image] - exact (_root_.map_iSup₂ (Submodule.restrictScalarsLatticeHom R S M) _) + exact map_iSup₂ (Submodule.restrictScalarsLatticeHom R S M) _ @[simp] theorem smul_top_eq_map {R S : Type*} [CommSemiring R] [CommSemiring S] [Algebra R S] @@ -433,6 +446,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 @@ -529,8 +546,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 @@ -609,13 +627,13 @@ 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 @@ -631,7 +649,7 @@ 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] (f : F') {I : Ideal R} [IsPrime I] : IsPrime (map f I) := by @@ -645,6 +663,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 +748,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 +786,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 +829,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 diff --git a/Mathlib/RingTheory/Ideal/Norm.lean b/Mathlib/RingTheory/Ideal/Norm.lean index b30d0820ffb94..6e1a0aa1de64f 100644 --- a/Mathlib/RingTheory/Ideal/Norm.lean +++ b/Mathlib/RingTheory/Ideal/Norm.lean @@ -12,7 +12,7 @@ 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.LocalProperties.Basic import Mathlib.RingTheory.Localization.NormTrace /-! diff --git a/Mathlib/RingTheory/Ideal/Operations.lean b/Mathlib/RingTheory/Ideal/Operations.lean index 3a108417c37a7..50211d46f660e 100644 --- a/Mathlib/RingTheory/Ideal/Operations.lean +++ b/Mathlib/RingTheory/Ideal/Operations.lean @@ -6,6 +6,8 @@ Authors: Kenny Lau import Mathlib.Algebra.Algebra.Operations import Mathlib.Data.Fintype.Lattice import Mathlib.RingTheory.Coprime.Lemmas +import Mathlib.RingTheory.NonUnitalSubring.Basic +import Mathlib.RingTheory.NonUnitalSubsemiring.Basic /-! # More operations on modules and ideals @@ -606,6 +608,11 @@ theorem sup_prod_eq_top {s : Finset ι} {J : ι → Ideal R} (h : ∀ i, i ∈ s (fun J K 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 <| @@ -973,10 +980,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'] @@ -1015,7 +1049,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 @@ -1036,8 +1070,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 => ?_)) @@ -1045,8 +1079,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 @@ -1057,8 +1091,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⟩) @@ -1093,7 +1127,7 @@ theorem subset_union_prime' {R : Type u} [CommRing R] {s : Finset ι} {f : ι · rw [Set.mem_iUnion₂] at ht rcases ht with ⟨j, hjt, hj⟩ simp only [Finset.inf_eq_iInf, SetLike.mem_coe, Submodule.mem_iInf] at hr - exact hs $ Or.inr $ Set.mem_biUnion hjt <| + exact hs <| Or.inr <| Set.mem_biUnion hjt <| add_sub_cancel_left r s ▸ (f j).sub_mem hj <| hr j hjt /-- Prime avoidance. Atiyah-Macdonald 1.11, Eisenbud 3.3, Stacks 00DS, Matsumura Ex.1.6. -/ @@ -1185,16 +1219,16 @@ variable (ι : Type*) variable (M : Type*) [AddCommGroup M] {R : Type*} [CommRing R] [Module R M] (I : Ideal R) variable (v : ι → M) (hv : Submodule.span R (Set.range v) = ⊤) -/-- A variant of `Finsupp.total` that takes in vectors valued in `I`. -/ +/-- A variant of `Finsupp.linearCombination` that takes in vectors valued in `I`. -/ noncomputable def finsuppTotal : (ι →₀ I) →ₗ[R] M := - (Finsupp.total ι M R v).comp (Finsupp.mapRange.linearMap I.subtype) + (Finsupp.linearCombination R v).comp (Finsupp.mapRange.linearMap I.subtype) variable {ι M v} theorem finsuppTotal_apply (f : ι →₀ I) : finsuppTotal ι M I v f = f.sum fun i x => (x : R) • v i := by dsimp [finsuppTotal] - rw [Finsupp.total_apply, Finsupp.sum_mapRange_index] + rw [Finsupp.linearCombination_apply, Finsupp.sum_mapRange_index] exact fun _ => zero_smul _ _ theorem finsuppTotal_apply_eq_of_fintype [Fintype ι] (f : ι →₀ I) : @@ -1209,7 +1243,8 @@ theorem range_finsuppTotal : refine ⟨fun ⟨f, h⟩ => ⟨Finsupp.mapRange.linearMap I.subtype f, fun i => (f i).2, h⟩, ?_⟩ rintro ⟨a, ha, rfl⟩ classical - refine ⟨a.mapRange (fun r => if h : r ∈ I then ⟨r, h⟩ else 0) (by simp), ?_⟩ + refine ⟨a.mapRange (fun r => if h : r ∈ I then ⟨r, h⟩ else 0) + (by simp only [Submodule.zero_mem, ↓reduceDIte]; rfl), ?_⟩ rw [finsuppTotal_apply, Finsupp.sum_mapRange_index] · apply Finsupp.sum_congr intro i _ @@ -1273,3 +1308,7 @@ theorem set_smul_top_eq_span (s : Set R) : Eq.trans (smul_eq_mul (Ideal R)) (Ideal.mul_top (.span s)) end Submodule + +instance {R} [Semiring R] : NonUnitalSubsemiringClass (Ideal R) R where + mul_mem _ hb := Ideal.mul_mem_left _ _ hb +instance {R} [Ring R] : NonUnitalSubringClass (Ideal R) R where diff --git a/Mathlib/RingTheory/Ideal/Quotient.lean b/Mathlib/RingTheory/Ideal/Quotient.lean index a8a6b587bf0f9..5a9cc0195360c 100644 --- a/Mathlib/RingTheory/Ideal/Quotient.lean +++ b/Mathlib/RingTheory/Ideal/Quotient.lean @@ -55,7 +55,7 @@ instance one (I : Ideal R) : One (R ⧸ I) := 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₂ ⊢ + 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₁] @@ -177,7 +177,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 @@ -291,7 +291,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 diff --git a/Mathlib/RingTheory/Ideal/QuotientOperations.lean b/Mathlib/RingTheory/Ideal/QuotientOperations.lean index 7abf1424f8ab5..5fb624f6f2143 100644 --- a/Mathlib/RingTheory/Ideal/QuotientOperations.lean +++ b/Mathlib/RingTheory/Ideal/QuotientOperations.lean @@ -36,7 +36,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 +49,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) := diff --git a/Mathlib/RingTheory/Idempotents.lean b/Mathlib/RingTheory/Idempotents.lean index 84922b3c3220e..c2dd1724dad6f 100644 --- a/Mathlib/RingTheory/Idempotents.lean +++ b/Mathlib/RingTheory/Idempotents.lean @@ -109,7 +109,7 @@ variable {I : Type*} (e : I → R) @[mk_iff] structure OrthogonalIdempotents : Prop where idem : ∀ i, IsIdempotentElem (e i) - ortho : ∀ i j, i ≠ j → e i * e j = 0 + ortho : Pairwise (e · * e · = 0) variable {e} @@ -117,17 +117,27 @@ lemma OrthogonalIdempotents.mul_eq [DecidableEq I] (he : OrthogonalIdempotents e e i * e j = if i = j then e i else 0 := by split · simp [*, (he.idem j).eq] - · exact he.ortho _ _ ‹_› + · exact he.ortho ‹_› lemma OrthogonalIdempotents.iff_mul_eq [DecidableEq I] : OrthogonalIdempotents e ↔ ∀ i j, e i * e j = if i = j then e i else 0 := ⟨mul_eq, fun H ↦ ⟨fun i ↦ by simpa using H i i, fun i j e ↦ by simpa [e] using H i j⟩⟩ -lemma OrthogonalIdempotents.isIdempotentElem_sum [Fintype I] (he : OrthogonalIdempotents e) : - IsIdempotentElem (∑ i, e i) := by +lemma OrthogonalIdempotents.isIdempotentElem_sum (he : OrthogonalIdempotents e) {s : Finset I} : + IsIdempotentElem (∑ i ∈ s, e i) := by classical simp [IsIdempotentElem, Finset.sum_mul, Finset.mul_sum, he.mul_eq] +lemma OrthogonalIdempotents.mul_sum_of_mem (he : OrthogonalIdempotents e) + {i : I} {s : Finset I} (h : i ∈ s) : e i * ∑ j ∈ s, e j = e i := by + classical + simp [Finset.mul_sum, he.mul_eq, h] + +lemma OrthogonalIdempotents.mul_sum_of_not_mem (he : OrthogonalIdempotents e) + {i : I} {s : Finset I} (h : i ∉ s) : e i * ∑ j ∈ s, e j = 0 := by + classical + simp [Finset.mul_sum, he.mul_eq, h] + lemma OrthogonalIdempotents.map (he : OrthogonalIdempotents e) : OrthogonalIdempotents (f ∘ e) := by classical @@ -150,7 +160,7 @@ lemma OrthogonalIdempotents.equiv {J} (i : J ≃ I) : lemma OrthogonalIdempotents.unique [Unique I] : OrthogonalIdempotents e ↔ IsIdempotentElem (e default) := by - simp [orthogonalIdempotents_iff, Unique.forall_iff] + simp only [orthogonalIdempotents_iff, Unique.forall_iff, Subsingleton.pairwise, and_true] lemma OrthogonalIdempotents.option (he : OrthogonalIdempotents e) [Fintype I] (x) (hx : IsIdempotentElem x) (hx₁ : x * ∑ i, e i = 0) (hx₂ : (∑ i, e i) * x = 0) : @@ -164,7 +174,7 @@ lemma OrthogonalIdempotents.option (he : OrthogonalIdempotents e) [Fintype I] (x ↓reduceIte, zero_mul] using congr_arg (· * e j) hx₁ · simpa only [Option.elim_some, Option.elim_none, ← mul_assoc, Finset.mul_sum, he.mul_eq, Finset.sum_ite_eq, Finset.mem_univ, ↓reduceIte, mul_zero] using congr_arg (e i * ·) hx₂ - · exact he.ortho i j (Option.some_inj.ne.mp ne) + · exact he.ortho (Option.some_inj.ne.mp ne) lemma OrthogonalIdempotents.lift_of_isNilpotent_ker_aux (h : ∀ x ∈ RingHom.ker f, IsNilpotent x) @@ -204,18 +214,15 @@ 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_iff] - simp only [Unique.forall_iff, ne_eq, not_true_eq_false, false_implies, and_true, - Finset.univ_unique, Finset.sum_singleton, and_iff_right_iff_imp] + rw [completeOrthogonalIdempotents_iff, OrthogonalIdempotents.unique, Fintype.sum_unique, + and_iff_right_iff_imp] exact (· ▸ IsIdempotentElem.one) lemma CompleteOrthogonalIdempotents.pair_iff {x y : R} : CompleteOrthogonalIdempotents ![x, y] ↔ IsIdempotentElem x ∧ y = 1 - x := by - rw [completeOrthogonalIdempotents_iff, orthogonalIdempotents_iff, and_assoc] + rw [completeOrthogonalIdempotents_iff, orthogonalIdempotents_iff, and_assoc, Pairwise] simp only [Nat.succ_eq_add_one, Nat.reduceAdd, Fin.forall_fin_two, Fin.isValue, Matrix.cons_val_zero, Matrix.cons_val_one, Matrix.head_cons, ne_eq, not_true_eq_false, false_implies, zero_ne_one, not_false_eq_true, true_implies, true_and, one_ne_zero, @@ -358,7 +365,15 @@ lemma OrthogonalIdempotents.surjective_pi {I : Type*} [Finite I] {e : I → R} exact ⟨x, by ext i; simp [Ideal.quotientInfToPiQuotient]⟩ intros i j hij rw [Ideal.isCoprime_span_singleton_iff] - exact ⟨1, e i, by simp [mul_sub, sub_mul, he.ortho i j hij]⟩ + exact ⟨1, e i, by simp [mul_sub, sub_mul, he.ortho hij]⟩ + +lemma OrthogonalIdempotents.prod_one_sub {I : Type*} {e : I → R} + (he : OrthogonalIdempotents e) (s : Finset I) : + ∏ i ∈ s, (1 - e i) = 1 - ∑ i ∈ s, e i := by + induction s using Finset.cons_induction with + | empty => simp + | cons a s has ih => + simp [ih, sub_mul, mul_sub, he.mul_sum_of_not_mem has, sub_sub] variable {I : Type*} [Fintype I] {e : I → R} @@ -369,18 +384,8 @@ theorem CompleteOrthogonalIdempotents.of_ker_isNilpotent (h : ∀ x ∈ RingHom. of_ker_isNilpotent_of_isMulCentral f h he (fun _ ↦ Semigroup.mem_center_iff.mpr (mul_comm · _)) he' -lemma OrthogonalIdempotents.prod_one_sub (he : OrthogonalIdempotents e) : - ∏ i, (1 - e i) = 1 - ∑ i, e i := by - classical - induction' (@Finset.univ I _) using Finset.induction_on with a s has ih - · simp - · suffices (1 - e a) * (1 - ∑ i in s, e i) = 1 - (e a + ∑ i in s, e i) by simp [*] - have : e a * ∑ i in s, e i = 0 := by - rw [Finset.mul_sum, ← Finset.sum_const_zero (s := s)] - exact Finset.sum_congr rfl fun j hj ↦ he.ortho a j (fun e ↦ has (e ▸ hj)) - rw [sub_mul, mul_sub, mul_sub, one_mul, mul_one, one_mul, this, sub_zero, sub_sub, add_comm] - -lemma CompleteOrthogonalIdempotents.prod_one_sub (he : CompleteOrthogonalIdempotents e) : +lemma CompleteOrthogonalIdempotents.prod_one_sub + (he : CompleteOrthogonalIdempotents e) : ∏ i, (1 - e i) = 0 := by rw [he.1.prod_one_sub, he.complete, sub_self] diff --git a/Mathlib/RingTheory/Int/Basic.lean b/Mathlib/RingTheory/Int/Basic.lean index 99efaa6a6e662..2f194c3abb9aa 100644 --- a/Mathlib/RingTheory/Int/Basic.lean +++ b/Mathlib/RingTheory/Int/Basic.lean @@ -138,7 +138,7 @@ alias eq_pow_of_mul_eq_pow_bit1_left := eq_pow_of_mul_eq_pow_odd_left theorem eq_pow_of_mul_eq_pow_odd_right {a b c : ℤ} (hab : IsCoprime a b) {k : ℕ} (hk : Odd k) (h : a * b = c ^ k) : ∃ d, b = d ^ k := - eq_pow_of_mul_eq_pow_odd_left hab.symm hk (by rwa [mul_comm] at h) + eq_pow_of_mul_eq_pow_odd_left (c := c) hab.symm hk (by rwa [mul_comm] at h) @[deprecated (since := "2024-07-12")] alias eq_pow_of_mul_eq_pow_bit1_right := eq_pow_of_mul_eq_pow_odd_right diff --git a/Mathlib/RingTheory/IntegralClosure/Algebra/Basic.lean b/Mathlib/RingTheory/IntegralClosure/Algebra/Basic.lean index c84cfb1553f9f..37343ddf2c611 100644 --- a/Mathlib/RingTheory/IntegralClosure/Algebra/Basic.lean +++ b/Mathlib/RingTheory/IntegralClosure/Algebra/Basic.lean @@ -33,23 +33,28 @@ 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 := + ⟨fun _ ↦ (isIntegral_algHom_iff f hf).mp (isIntegral _)⟩ + end instance Module.End.isIntegral {M : Type*} [AddCommGroup M] [Module R M] [Module.Finite R M] : Algebra.IsIntegral R (Module.End R M) := ⟨LinearMap.exists_monic_and_aeval_eq_zero R⟩ -variable (R) +variable (R) in theorem IsIntegral.of_finite [Module.Finite R B] (x : B) : IsIntegral R x := (isIntegral_algHom_iff (Algebra.lmul R B) Algebra.lmul_injective).mp (Algebra.IsIntegral.isIntegral _) -variable (B) +theorem isIntegral_of_noetherian (_ : IsNoetherian R B) (x : B) : IsIntegral R x := + .of_finite R x + +variable (R B) in instance Algebra.IsIntegral.of_finite [Module.Finite R B] : Algebra.IsIntegral R B := ⟨.of_finite R⟩ -variable {R B} - /-- 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) @@ -57,6 +62,61 @@ theorem IsIntegral.of_mem_of_fg {A} [Ring A] [Algebra R A] (S : Subalgebra R A) have : Module.Finite R S := ⟨(fg_top _).mpr HS⟩ (isIntegral_algHom_iff S.val Subtype.val_injective).mpr (.of_finite R (⟨x, hx⟩ : S)) +theorem isIntegral_of_submodule_noetherian (S : Subalgebra R B) + (H : IsNoetherian R (Subalgebra.toSubmodule S)) (x : B) (hx : x ∈ S) : IsIntegral R x := + .of_mem_of_fg _ ((fg_top _).mp <| H.noetherian _) _ hx + +/-- Suppose `A` is an `R`-algebra, `M` is an `A`-module such that `a • m ≠ 0` for all non-zero `a` +and `m`. If `x : A` fixes a nontrivial f.g. `R`-submodule `N` of `M`, then `x` is `R`-integral. -/ +theorem isIntegral_of_smul_mem_submodule {M : Type*} [AddCommGroup M] [Module R M] [Module A M] + [IsScalarTower R A M] [NoZeroSMulDivisors A M] (N : Submodule R M) (hN : N ≠ ⊥) (hN' : N.FG) + (x : A) (hx : ∀ n ∈ N, x • n ∈ N) : IsIntegral R x := by + let A' : Subalgebra R A := + { carrier := { x | ∀ n ∈ N, x • n ∈ N } + mul_mem' := fun {a b} ha hb n hn => smul_smul a b n ▸ ha _ (hb _ hn) + one_mem' := fun n hn => (one_smul A n).symm ▸ hn + add_mem' := fun {a b} ha hb n hn => (add_smul a b n).symm ▸ N.add_mem (ha _ hn) (hb _ hn) + zero_mem' := fun n _hn => (zero_smul A n).symm ▸ N.zero_mem + algebraMap_mem' := fun r n hn => (algebraMap_smul A r n).symm ▸ N.smul_mem r hn } + let f : A' →ₐ[R] Module.End R N := + AlgHom.ofLinearMap + { toFun := fun x => (DistribMulAction.toLinearMap R M x).restrict x.prop + -- Porting note: was + -- `fun x y => LinearMap.ext fun n => Subtype.ext <| add_smul x y n` + map_add' := by intros x y; ext; exact add_smul _ _ _ + -- Porting note: was + -- `fun r s => LinearMap.ext fun n => Subtype.ext <| smul_assoc r s n` + map_smul' := by intros r s; ext; apply smul_assoc } + -- Porting note: the next two lines were + --`(LinearMap.ext fun n => Subtype.ext <| one_smul _ _) fun x y =>` + --`LinearMap.ext fun n => Subtype.ext <| mul_smul x y n` + (by ext; apply one_smul) + (by intros x y; ext; apply mul_smul) + obtain ⟨a, ha₁, ha₂⟩ : ∃ a ∈ N, a ≠ (0 : M) := by + by_contra! h' + apply hN + rwa [eq_bot_iff] + have : Function.Injective f := by + show Function.Injective f.toLinearMap + rw [← LinearMap.ker_eq_bot, eq_bot_iff] + intro s hs + have : s.1 • a = 0 := congr_arg Subtype.val (LinearMap.congr_fun hs ⟨a, ha₁⟩) + exact Subtype.ext ((eq_zero_or_eq_zero_of_smul_eq_zero this).resolve_right ha₂) + show IsIntegral R (A'.val ⟨x, hx⟩) + rw [isIntegral_algHom_iff A'.val Subtype.val_injective, ← isIntegral_algHom_iff f this] + haveI : Module.Finite R N := by rwa [Module.finite_def, Submodule.fg_top] + apply Algebra.IsIntegral.isIntegral + +variable {f} + +theorem RingHom.Finite.to_isIntegral (h : f.Finite) : f.IsIntegral := + letI := f.toAlgebra + fun _ ↦ IsIntegral.of_mem_of_fg ⊤ h.1 _ trivial + +alias RingHom.IsIntegral.of_finite := RingHom.Finite.to_isIntegral + +variable (f) + theorem RingHom.IsIntegralElem.of_mem_closure {x y z : S} (hx : f.IsIntegralElem x) (hy : f.IsIntegralElem y) (hz : z ∈ Subring.closure ({x, y} : Set S)) : f.IsIntegralElem z := by letI : Algebra R S := f.toAlgebra @@ -88,9 +148,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) @@ -125,3 +199,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..c987ccc2c77c5 100644 --- a/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.lean +++ b/Mathlib/RingTheory/IntegralClosure/IntegrallyClosed.lean @@ -3,7 +3,6 @@ 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 /-! @@ -275,3 +274,10 @@ theorem isIntegrallyClosedOfFiniteExtension [IsDomain R] [FiniteDimensional K L] (integralClosure_eq_bot_iff L).mp integralClosure_idem end integralClosure + +/-- 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 4950bcffb0f99..ab277015154a5 100644 --- a/Mathlib/RingTheory/IntegralClosure/IsIntegral/Basic.lean +++ b/Mathlib/RingTheory/IntegralClosure/IsIntegral/Basic.lean @@ -104,3 +104,97 @@ theorem IsIntegral.of_pow [Algebra R B] {x : B} {n : ℕ} (hn : 0 < n) (hx : IsI exact ⟨expand R n p, hmonic.expand hn, by rwa [← aeval_def, expand_aeval]⟩ end + +section + +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 IsIntegral.map_of_comp_eq {R S T U : Type*} [CommRing R] [Ring S] + [CommRing T] [Ring U] [Algebra R S] [Algebra T U] (φ : R →+* T) (ψ : S →+* U) + (h : (algebraMap T U).comp φ = ψ.comp (algebraMap R S)) {a : S} (ha : IsIntegral R a) : + IsIntegral T (ψ a) := + let ⟨p, hp⟩ := ha + ⟨p.map φ, hp.1.map _, by + rw [← eval_map, map_map, h, ← map_map, eval_map, eval₂_at_apply, eval_map, hp.2, ψ.map_zero]⟩ + +@[simp] +theorem isIntegral_algEquiv {A B : Type*} [Ring A] [Ring B] [Algebra R A] [Algebra R B] + (f : A ≃ₐ[R] B) {x : A} : IsIntegral R (f x) ↔ IsIntegral R x := + ⟨fun h ↦ by simpa using h.map f.symm, IsIntegral.map f⟩ + +/-- If `R → A → B` is an algebra tower, +then if the entire tower is an integral extension so is `A → B`. -/ +theorem IsIntegral.tower_top [Algebra A B] [IsScalarTower R A B] {x : B} + (hx : IsIntegral R x) : IsIntegral A x := + 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) := + hb.map (f : B →+* C).toIntAlgHom + +theorem IsIntegral.of_subring {x : B} (T : Subring R) (hx : IsIntegral T x) : IsIntegral R x := + hx.tower_top + +protected theorem IsIntegral.algebraMap [Algebra A B] [IsScalarTower R A B] {x : A} + (h : IsIntegral R x) : IsIntegral R (algebraMap A B x) := by + rcases h with ⟨f, hf, hx⟩ + use f, hf + rw [IsScalarTower.algebraMap_eq R A B, ← hom_eval₂, hx, RingHom.map_zero] + +theorem isIntegral_algebraMap_iff [Algebra A B] [IsScalarTower R A B] {x : A} + (hAB : Function.Injective (algebraMap A B)) : + IsIntegral R (algebraMap A B x) ↔ IsIntegral R x := + isIntegral_algHom_iff (IsScalarTower.toAlgHom R A B) hAB + +theorem isIntegral_iff_isIntegral_closure_finite {r : B} : + IsIntegral R r ↔ ∃ s : Set R, s.Finite ∧ IsIntegral (Subring.closure s) r := by + constructor <;> intro hr + · rcases hr with ⟨p, hmp, hpr⟩ + refine ⟨_, Finset.finite_toSet _, p.restriction, monic_restriction.2 hmp, ?_⟩ + rw [← aeval_def, ← aeval_map_algebraMap R r p.restriction, map_restriction, aeval_def, hpr] + rcases hr with ⟨s, _, hsr⟩ + exact hsr.of_subring _ + +theorem fg_adjoin_of_finite {s : Set A} (hfs : s.Finite) (his : ∀ x ∈ s, IsIntegral R x) : + (Algebra.adjoin R s).toSubmodule.FG := + Set.Finite.induction_on hfs + (fun _ => + ⟨{1}, + Submodule.ext fun x => by + rw [Algebra.adjoin_empty, Finset.coe_singleton, ← one_eq_span, Algebra.toSubmodule_bot]⟩) + (fun {a s} _ _ ih his => by + rw [← Set.union_singleton, Algebra.adjoin_union_coe_submodule] + exact + FG.mul (ih fun i hi => his i <| Set.mem_insert_of_mem a hi) + (his a <| Set.mem_insert a s).fg_adjoin_singleton) + his + +theorem isNoetherian_adjoin_finset [IsNoetherianRing R] (s : Finset A) + (hs : ∀ x ∈ s, IsIntegral R x) : IsNoetherian R (Algebra.adjoin R (s : Set A)) := + isNoetherian_of_fg_of_noetherian _ (fg_adjoin_of_finite s.finite_toSet hs) + +end 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 b1fb223b3f0ba..146fc3d8f12a9 100644 --- a/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean +++ b/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean @@ -7,6 +7,7 @@ import Mathlib.RingTheory.IntegralClosure.IsIntegralClosure.Defs import Mathlib.RingTheory.IntegralClosure.Algebra.Basic import Mathlib.RingTheory.FiniteType import Mathlib.RingTheory.Polynomial.ScaleRoots +import Mathlib.LinearAlgebra.FiniteDimensional.Defs /-! # # Integral closure as a characteristic predicate @@ -22,140 +23,7 @@ section 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 IsIntegral.map_of_comp_eq {R S T U : Type*} [CommRing R] [Ring S] - [CommRing T] [Ring U] [Algebra R S] [Algebra T U] (φ : R →+* T) (ψ : S →+* U) - (h : (algebraMap T U).comp φ = ψ.comp (algebraMap R S)) {a : S} (ha : IsIntegral R a) : - IsIntegral T (ψ a) := - let ⟨p, hp⟩ := ha - ⟨p.map φ, hp.1.map _, by - rw [← eval_map, map_map, h, ← map_map, eval_map, eval₂_at_apply, eval_map, hp.2, ψ.map_zero]⟩ - -section - -variable {A B : Type*} [Ring A] [Ring B] [Algebra R A] [Algebra R B] -variable (f : A →ₐ[R] B) - -theorem Algebra.IsIntegral.of_injective (hf : Function.Injective f) [Algebra.IsIntegral R B] : - Algebra.IsIntegral R A := - ⟨fun _ ↦ (isIntegral_algHom_iff f hf).mp (isIntegral _)⟩ - -end - -@[simp] -theorem isIntegral_algEquiv {A B : Type*} [Ring A] [Ring B] [Algebra R A] [Algebra R B] - (f : A ≃ₐ[R] B) {x : A} : IsIntegral R (f x) ↔ IsIntegral R x := - ⟨fun h ↦ by simpa using h.map f.symm, IsIntegral.map f⟩ - -/-- If `R → A → B` is an algebra tower, -then if the entire tower is an integral extension so is `A → B`. -/ -theorem IsIntegral.tower_top [Algebra A B] [IsScalarTower R A B] {x : B} - (hx : IsIntegral R x) : IsIntegral A x := - let ⟨p, hp, hpx⟩ := hx - ⟨p.map <| algebraMap R A, hp.map _, by rw [← aeval_def, aeval_map_algebraMap, aeval_def, hpx]⟩ - -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) := - hb.map (f : B →+* C).toIntAlgHom - -theorem IsIntegral.of_subring {x : B} (T : Subring R) (hx : IsIntegral T x) : IsIntegral R x := - hx.tower_top - -protected theorem IsIntegral.algebraMap [Algebra A B] [IsScalarTower R A B] {x : A} - (h : IsIntegral R x) : IsIntegral R (algebraMap A B x) := by - rcases h with ⟨f, hf, hx⟩ - use f, hf - rw [IsScalarTower.algebraMap_eq R A B, ← hom_eval₂, hx, RingHom.map_zero] - -theorem isIntegral_algebraMap_iff [Algebra A B] [IsScalarTower R A B] {x : A} - (hAB : Function.Injective (algebraMap A B)) : - IsIntegral R (algebraMap A B x) ↔ IsIntegral R x := - isIntegral_algHom_iff (IsScalarTower.toAlgHom R A B) hAB - -theorem isIntegral_iff_isIntegral_closure_finite {r : B} : - IsIntegral R r ↔ ∃ s : Set R, s.Finite ∧ IsIntegral (Subring.closure s) r := by - constructor <;> intro hr - · rcases hr with ⟨p, hmp, hpr⟩ - refine ⟨_, Finset.finite_toSet _, p.restriction, monic_restriction.2 hmp, ?_⟩ - rw [← aeval_def, ← aeval_map_algebraMap R r p.restriction, map_restriction, aeval_def, hpr] - rcases hr with ⟨s, _, hsr⟩ - exact hsr.of_subring _ - -theorem fg_adjoin_of_finite {s : Set A} (hfs : s.Finite) (his : ∀ x ∈ s, IsIntegral R x) : - (Algebra.adjoin R s).toSubmodule.FG := - Set.Finite.induction_on hfs - (fun _ => - ⟨{1}, - Submodule.ext fun x => by - rw [Algebra.adjoin_empty, Finset.coe_singleton, ← one_eq_span, Algebra.toSubmodule_bot]⟩) - (fun {a s} _ _ ih his => by - rw [← Set.union_singleton, Algebra.adjoin_union_coe_submodule] - exact - FG.mul (ih fun i hi => his i <| Set.mem_insert_of_mem a hi) - (his a <| Set.mem_insert a s).fg_adjoin_singleton) - his - -theorem isNoetherian_adjoin_finset [IsNoetherianRing R] (s : Finset A) - (hs : ∀ x ∈ s, IsIntegral R x) : IsNoetherian R (Algebra.adjoin R (s : Set A)) := - isNoetherian_of_fg_of_noetherian _ (fg_adjoin_of_finite s.finite_toSet hs) - -theorem isIntegral_of_noetherian (_ : IsNoetherian R B) (x : B) : IsIntegral R x := - .of_finite R x - -theorem isIntegral_of_submodule_noetherian (S : Subalgebra R B) - (H : IsNoetherian R (Subalgebra.toSubmodule S)) (x : B) (hx : x ∈ S) : IsIntegral R x := - .of_mem_of_fg _ ((fg_top _).mp <| H.noetherian _) _ hx - -/-- Suppose `A` is an `R`-algebra, `M` is an `A`-module such that `a • m ≠ 0` for all non-zero `a` -and `m`. If `x : A` fixes a nontrivial f.g. `R`-submodule `N` of `M`, then `x` is `R`-integral. -/ -theorem isIntegral_of_smul_mem_submodule {M : Type*} [AddCommGroup M] [Module R M] [Module A M] - [IsScalarTower R A M] [NoZeroSMulDivisors A M] (N : Submodule R M) (hN : N ≠ ⊥) (hN' : N.FG) - (x : A) (hx : ∀ n ∈ N, x • n ∈ N) : IsIntegral R x := by - let A' : Subalgebra R A := - { carrier := { x | ∀ n ∈ N, x • n ∈ N } - mul_mem' := fun {a b} ha hb n hn => smul_smul a b n ▸ ha _ (hb _ hn) - one_mem' := fun n hn => (one_smul A n).symm ▸ hn - add_mem' := fun {a b} ha hb n hn => (add_smul a b n).symm ▸ N.add_mem (ha _ hn) (hb _ hn) - zero_mem' := fun n _hn => (zero_smul A n).symm ▸ N.zero_mem - algebraMap_mem' := fun r n hn => (algebraMap_smul A r n).symm ▸ N.smul_mem r hn } - let f : A' →ₐ[R] Module.End R N := - AlgHom.ofLinearMap - { toFun := fun x => (DistribMulAction.toLinearMap R M x).restrict x.prop - -- Porting note: was - -- `fun x y => LinearMap.ext fun n => Subtype.ext <| add_smul x y n` - map_add' := by intros x y; ext; exact add_smul _ _ _ - -- Porting note: was - -- `fun r s => LinearMap.ext fun n => Subtype.ext <| smul_assoc r s n` - map_smul' := by intros r s; ext; apply smul_assoc } - -- Porting note: the next two lines were - --`(LinearMap.ext fun n => Subtype.ext <| one_smul _ _) fun x y =>` - --`LinearMap.ext fun n => Subtype.ext <| mul_smul x y n` - (by ext; apply one_smul) - (by intros x y; ext; apply mul_smul) - obtain ⟨a, ha₁, ha₂⟩ : ∃ a ∈ N, a ≠ (0 : M) := by - by_contra! h' - apply hN - rwa [eq_bot_iff] - have : Function.Injective f := by - show Function.Injective f.toLinearMap - rw [← LinearMap.ker_eq_bot, eq_bot_iff] - intro s hs - have : s.1 • a = 0 := congr_arg Subtype.val (LinearMap.congr_fun hs ⟨a, ha₁⟩) - exact Subtype.ext ((eq_zero_or_eq_zero_of_smul_eq_zero this).resolve_right ha₂) - show IsIntegral R (A'.val ⟨x, hx⟩) - rw [isIntegral_algHom_iff A'.val Subtype.val_injective, ← isIntegral_algHom_iff f this] - haveI : Module.Finite R N := by rwa [Module.finite_def, Submodule.fg_top] - apply Algebra.IsIntegral.isIntegral - -variable {f} - -theorem RingHom.Finite.to_isIntegral (h : f.Finite) : f.IsIntegral := - letI := f.toAlgebra - fun _ ↦ IsIntegral.of_mem_of_fg ⊤ h.1 _ trivial - -alias RingHom.IsIntegral.of_finite := RingHom.Finite.to_isIntegral +variable [Algebra R A] [Algebra R B] {f : R →+* S} /-- The [Kurosh problem](https://en.wikipedia.org/wiki/Kurosh_problem) asks to show that this is still true when `A` is not necessarily commutative and `R` is a field, but it has @@ -527,14 +395,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 @@ -693,7 +561,7 @@ theorem Algebra.IsIntegral.isField_iff_isField {R S : Type*} [CommRing R] end Algebra theorem integralClosure_idem {R A : Type*} [CommRing R] [CommRing A] [Algebra R A] : - integralClosure (integralClosure R A : Set A) A = ⊥ := + integralClosure (integralClosure R A) A = ⊥ := letI := (integralClosure R A).algebra eq_bot_iff.2 fun x hx ↦ Algebra.mem_bot.2 ⟨⟨x, isIntegral_trans (A := integralClosure R A) x hx⟩, rfl⟩ diff --git a/Mathlib/RingTheory/IntegralDomain.lean b/Mathlib/RingTheory/IntegralDomain.lean index aff1446d6ba80..2d5e9ee2a2c51 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,7 +92,9 @@ def Fintype.divisionRingOfIsDomain (R : Type*) [Ring R] [IsDomain R] [DecidableE __ := Fintype.groupWithZeroOfCancel R __ := ‹Ring R› nnqsmul := _ + nnqsmul_def := fun q a => rfl qsmul := _ + qsmul_def := fun q a => rfl /-- Every finite commutative domain is a field. More generally, commutativity is not required: this can be found in `Mathlib.RingTheory.LittleWedderburn`. -/ diff --git a/Mathlib/RingTheory/IsAdjoinRoot.lean b/Mathlib/RingTheory/IsAdjoinRoot.lean index f48ab8430a1bd..1b153b9e33498 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] @@ -195,7 +195,7 @@ variable (i x) -- To match `AdjoinRoot.lift` /-- Lift a ring homomorphism `R →+* T` to `S →+* T` by specifying a root `x` of `f` in `T`, where `S` is given by adjoining a root of `f` to `R`. -/ -def lift (h : IsAdjoinRoot S f) : S →+* T where +def lift (h : IsAdjoinRoot S f) (hx : f.eval₂ i x = 0) : S →+* T where toFun z := (h.repr z).eval₂ i x map_zero' := by dsimp only -- Porting note (#10752): added `dsimp only` @@ -370,7 +370,7 @@ Auxiliary definition for `IsAdjoinRootMonic.powerBasis`. -/ def basis (h : IsAdjoinRootMonic S f) : Basis (Fin (natDegree f)) R S := Basis.ofRepr { toFun := fun x => (h.modByMonicHom x).toFinsupp.comapDomain _ Fin.val_injective.injOn - invFun := fun g => h.map (ofFinsupp (g.mapDomain _)) + invFun := fun g => h.map (ofFinsupp (g.mapDomain Fin.val)) left_inv := fun x => by cases subsingleton_or_nontrivial R · subsingleton [h.subsingleton] @@ -393,12 +393,10 @@ def basis (h : IsAdjoinRootMonic S f) : Basis (Fin (natDegree f)) R S := ext i simp only [h.modByMonicHom_map, Finsupp.comapDomain_apply, Polynomial.toFinsupp_apply] rw [(Polynomial.modByMonic_eq_self_iff h.Monic).mpr, Polynomial.coeff] - · dsimp only -- Porting note (#10752): added `dsimp only` - rw [Finsupp.mapDomain_apply Fin.val_injective] + · rw [Finsupp.mapDomain_apply Fin.val_injective] rw [degree_eq_natDegree h.Monic.ne_zero, degree_lt_iff_coeff_zero] intro m hm rw [Polynomial.coeff] - dsimp only -- Porting note (#10752): added `dsimp only` rw [Finsupp.mapDomain_notin_range] rw [Set.mem_range, not_exists] rintro i rfl diff --git a/Mathlib/RingTheory/IsTensorProduct.lean b/Mathlib/RingTheory/IsTensorProduct.lean index 07110fac07464..b02662937d43f 100644 --- a/Mathlib/RingTheory/IsTensorProduct.lean +++ b/Mathlib/RingTheory/IsTensorProduct.lean @@ -213,10 +213,9 @@ noncomputable nonrec def IsBaseChange.equiv : S ⊗[R] M ≃ₗ[S] N := · rw [smul_zero, map_zero, smul_zero] · intro x y -- porting note (#10745): was simp [smul_tmul', Algebra.ofId_apply] - simp only [Algebra.linearMap_apply, lift.tmul, smul_eq_mul, - LinearMap.mul_apply, LinearMap.smul_apply, IsTensorProduct.equiv_apply, - Module.algebraMap_end_apply, _root_.map_mul, smul_tmul', eq_self_iff_true, - LinearMap.coe_restrictScalars, LinearMap.flip_apply] + simp only [Algebra.linearMap_apply, lift.tmul, smul_eq_mul, LinearMap.mul_apply, + LinearMap.smul_apply, IsTensorProduct.equiv_apply, Module.algebraMap_end_apply, map_mul, + smul_tmul', eq_self_iff_true, LinearMap.coe_restrictScalars, LinearMap.flip_apply] · intro x y hx hy rw [map_add, smul_add, map_add, smul_add, hx, hy] } @@ -319,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') @@ -353,8 +381,7 @@ theorem Algebra.IsPushout.symm (h : Algebra.IsPushout R S R' S') : Algebra.IsPus · intro x y simp only [smul_tmul', smul_eq_mul, TensorProduct.comm_tmul, smul_def, TensorProduct.algebraMap_apply, id.map_eq_id, RingHom.id_apply, TensorProduct.tmul_mul_tmul, - one_mul, h.1.equiv_tmul, AlgHom.toLinearMap_apply, _root_.map_mul, - IsScalarTower.coe_toAlgHom'] + one_mul, h.1.equiv_tmul, AlgHom.toLinearMap_apply, map_mul, IsScalarTower.coe_toAlgHom'] ring · intro x y hx hy rw [map_add, map_add, smul_add, map_add, map_add, hx, hy, smul_add] @@ -399,7 +426,7 @@ noncomputable def Algebra.pushoutDesc [H : Algebra.IsPushout R S R' S'] {A : Typ have : ∀ x, H.out.lift g.toLinearMap (algebraMap R' S' x) = g x := H.out.lift_eq _ refine AlgHom.ofLinearMap ((H.out.lift g.toLinearMap).restrictScalars R) ?_ ?_ · dsimp only [LinearMap.restrictScalars_apply] - rw [← (algebraMap R' S').map_one, this, _root_.map_one] + rw [← (algebraMap R' S').map_one, this, map_one] · intro x y refine H.out.inductionOn x _ ?_ ?_ ?_ ?_ · rw [zero_mul, map_zero, zero_mul] @@ -417,7 +444,7 @@ noncomputable def Algebra.pushoutDesc [H : Algebra.IsPushout R S R' S'] {A : Typ · rw [mul_zero, map_zero, mul_zero] · intro y dsimp - rw [← _root_.map_mul, this, this, _root_.map_mul] + rw [← map_mul, this, this, map_mul] · intro s s' e rw [mul_comm, smul_mul_assoc, LinearMap.map_smul, LinearMap.map_smul, mul_comm, e] change f s * (g x * _) = g x * (f s * _) @@ -426,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 @@ -435,7 +462,7 @@ theorem Algebra.pushoutDesc_left [H : Algebra.IsPushout R S R' S'] {A : Type*} [ show f (r • s) * a = r • (f s * a) by rw [map_smul, smul_mul_assoc] } haveI : IsScalarTower S A A := { smul_assoc := fun r a b => mul_assoc _ _ _ } rw [Algebra.algebraMap_eq_smul_one, pushoutDesc_apply, map_smul, ← - Algebra.pushoutDesc_apply S' f g H, _root_.map_one] + Algebra.pushoutDesc_apply S' f g H, map_one] exact mul_one (f x) theorem Algebra.lift_algHom_comp_left [Algebra.IsPushout R S R' S'] {A : Type*} [Semiring A] @@ -444,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 @@ -467,10 +494,39 @@ theorem Algebra.IsPushout.algHom_ext [H : Algebra.IsPushout R S R' S'] {A : Type · simp only [map_zero] · exact AlgHom.congr_fun h₁ · intro s s' e - rw [Algebra.smul_def, _root_.map_mul, _root_.map_mul, e] + rw [Algebra.smul_def, map_mul, map_mul, e] congr 1 exact (AlgHom.congr_fun h₂ s : _) · 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..93ed9e32a751f 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) diff --git a/Mathlib/RingTheory/JacobsonIdeal.lean b/Mathlib/RingTheory/JacobsonIdeal.lean index c51eef801b35e..5f513287fa395 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.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 @@ -375,3 +424,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 661532a73b713..09bc7c6dc0c45 100644 --- a/Mathlib/RingTheory/Kaehler/Basic.lean +++ b/Mathlib/RingTheory/Kaehler/Basic.lean @@ -49,7 +49,7 @@ suppress_compilation section KaehlerDifferential open scoped TensorProduct -open Algebra +open Algebra Finsupp universe u v @@ -320,7 +320,7 @@ theorem KaehlerDifferential.tensorProductTo_surjective : exact ⟨x, KaehlerDifferential.D_tensorProductTo x⟩ /-- The `S`-linear maps from `Ω[S⁄R]` to `M` are (`S`-linearly) equivalent to `R`-derivations -from `S` to `M`. -/ +from `S` to `M`. -/ @[simps! symm_apply apply_apply] def KaehlerDifferential.linearMapEquivDerivation : (Ω[S⁄R] →ₗ[S] M) ≃ₗ[S] Derivation R S M := { Derivation.llcomp.flip <| KaehlerDifferential.D R S with @@ -369,7 +369,7 @@ theorem KaehlerDifferential.End_equiv_aux (f : S →ₐ[R] S ⊗ S ⧸ KaehlerDi · intro e; apply (KaehlerDifferential.quotientCotangentIdealRingEquiv R S).injective exact e₁.symm.trans (e.trans e₂) -/- Note: Lean is slow to synthesize theses instances (times out). +/- Note: Lean is slow to synthesize these instances (times out). Without them the endEquivDerivation' and endEquivAuxEquiv both have significant timeouts. In Mathlib 3, it was slow but not this slow. -/ /-- A shortcut instance to prevent timing out. Hopefully to be removed in the future. -/ @@ -499,8 +499,9 @@ the relations: 3. `dr = 0` for `r ∈ R` where `db` is the unit in the copy of `S` with index `b`. -This is the kernel of the surjection `Finsupp.total S Ω[S⁄R] S (KaehlerDifferential.D R S)`. -See `KaehlerDifferential.kerTotal_eq` and `KaehlerDifferential.total_surjective`. +This is the kernel of the surjection +`Finsupp.linearCombination S Ω[S⁄R] S (KaehlerDifferential.D R S)`. +See `KaehlerDifferential.kerTotal_eq` and `KaehlerDifferential.linearCombination_surjective`. -/ noncomputable def KaehlerDifferential.kerTotal : Submodule S (S →₀ S) := Submodule.span S @@ -555,46 +556,55 @@ theorem KaehlerDifferential.derivationQuotKerTotal_apply (x) : KaehlerDifferential.derivationQuotKerTotal R S x = 1𝖣x := rfl -theorem KaehlerDifferential.derivationQuotKerTotal_lift_comp_total : +theorem KaehlerDifferential.derivationQuotKerTotal_lift_comp_linearCombination : (KaehlerDifferential.derivationQuotKerTotal R S).liftKaehlerDifferential.comp - (Finsupp.total S (Ω[S⁄R]) S (KaehlerDifferential.D R S)) = + (Finsupp.linearCombination S (KaehlerDifferential.D R S)) = Submodule.mkQ _ := by apply Finsupp.lhom_ext intro a b conv_rhs => rw [← Finsupp.smul_single_one a b, LinearMap.map_smul] simp [KaehlerDifferential.derivationQuotKerTotal_apply] +@[deprecated (since := "2024-08-29")] alias + KaehlerDifferential.derivationQuotKerTotal_lift_comp_total := + KaehlerDifferential.derivationQuotKerTotal_lift_comp_linearCombination + theorem KaehlerDifferential.kerTotal_eq : - LinearMap.ker (Finsupp.total S (Ω[S⁄R]) S (KaehlerDifferential.D R S)) = + LinearMap.ker (Finsupp.linearCombination S (KaehlerDifferential.D R S)) = KaehlerDifferential.kerTotal R S := by apply le_antisymm · conv_rhs => rw [← (KaehlerDifferential.kerTotal R S).ker_mkQ] - rw [← KaehlerDifferential.derivationQuotKerTotal_lift_comp_total] + rw [← KaehlerDifferential.derivationQuotKerTotal_lift_comp_linearCombination] exact LinearMap.ker_le_ker_comp _ _ · rw [KaehlerDifferential.kerTotal, Submodule.span_le] rintro _ ((⟨⟨x, y⟩, rfl⟩ | ⟨⟨x, y⟩, rfl⟩) | ⟨x, rfl⟩) <;> dsimp <;> simp [LinearMap.mem_ker] -theorem KaehlerDifferential.total_surjective : - Function.Surjective (Finsupp.total S (Ω[S⁄R]) S (KaehlerDifferential.D R S)) := by - rw [← LinearMap.range_eq_top, Finsupp.range_total, KaehlerDifferential.span_range_derivation] +theorem KaehlerDifferential.linearCombination_surjective : + Function.Surjective (Finsupp.linearCombination S (KaehlerDifferential.D R S)) := by + rw [← LinearMap.range_eq_top, range_linearCombination, KaehlerDifferential.span_range_derivation] + +@[deprecated (since := "2024-08-29")] alias KaehlerDifferential.total_surjective := + KaehlerDifferential.linearCombination_surjective /-- `Ω[S⁄R]` is isomorphic to `S` copies of `S` with kernel `KaehlerDifferential.kerTotal`. -/ @[simps!] noncomputable def KaehlerDifferential.quotKerTotalEquiv : ((S →₀ S) ⧸ KaehlerDifferential.kerTotal R S) ≃ₗ[S] Ω[S⁄R] := { (KaehlerDifferential.kerTotal R S).liftQ - (Finsupp.total S (Ω[S⁄R]) S (KaehlerDifferential.D R S)) + (Finsupp.linearCombination S (KaehlerDifferential.D R S)) (KaehlerDifferential.kerTotal_eq R S).ge with invFun := (KaehlerDifferential.derivationQuotKerTotal R S).liftKaehlerDifferential left_inv := by intro x obtain ⟨x, rfl⟩ := Submodule.mkQ_surjective _ x exact - LinearMap.congr_fun (KaehlerDifferential.derivationQuotKerTotal_lift_comp_total R S : _) x + LinearMap.congr_fun + (KaehlerDifferential.derivationQuotKerTotal_lift_comp_linearCombination R S : _) x right_inv := by intro x - obtain ⟨x, rfl⟩ := KaehlerDifferential.total_surjective R S x - have := LinearMap.congr_fun (KaehlerDifferential.derivationQuotKerTotal_lift_comp_total R S) x + obtain ⟨x, rfl⟩ := KaehlerDifferential.linearCombination_surjective R S x + have := LinearMap.congr_fun + (KaehlerDifferential.derivationQuotKerTotal_lift_comp_linearCombination R S) x rw [LinearMap.comp_apply] at this rw [this] rfl } @@ -704,13 +714,13 @@ theorem KaehlerDifferential.map_D (x : A) : theorem KaehlerDifferential.ker_map : LinearMap.ker (KaehlerDifferential.map R S A B) = (((kerTotal S B).restrictScalars A).comap finsupp_map).map - (Finsupp.total A (Ω[A⁄R]) A (D R A)) := by - rw [← Submodule.map_comap_eq_of_surjective (total_surjective R A) (LinearMap.ker _)] + (Finsupp.linearCombination (M := Ω[A⁄R]) A (D R A)) := by + rw [← Submodule.map_comap_eq_of_surjective (linearCombination_surjective R A) (LinearMap.ker _)] congr 1 ext x - simp only [Submodule.mem_comap, LinearMap.mem_ker, Finsupp.apply_total, ← kerTotal_eq, + simp only [Submodule.mem_comap, LinearMap.mem_ker, Finsupp.apply_linearCombination, ← kerTotal_eq, Submodule.restrictScalars_mem] - simp only [Finsupp.total_apply, Function.comp_apply, LinearMap.coe_comp, Finsupp.lmapDomain_apply, + simp only [linearCombination_apply, Function.comp_apply, LinearMap.coe_comp, lmapDomain_apply, Finsupp.mapRange.linearMap_apply] rw [Finsupp.sum_mapRange_index, Finsupp.sum_mapDomain_index] · simp [ofId] @@ -720,10 +730,10 @@ theorem KaehlerDifferential.ker_map : lemma KaehlerDifferential.ker_map_of_surjective (h : Function.Surjective (algebraMap A B)) : LinearMap.ker (map R R A B) = - (LinearMap.ker finsupp_map).map (Finsupp.total A _ A (D R A)) := by + (LinearMap.ker finsupp_map).map (Finsupp.linearCombination A (D R A)) := by rw [ker_map, ← kerTotal_map' R A B h, Submodule.comap_map_eq, Submodule.map_sup, Submodule.map_sup, ← kerTotal_eq, ← Submodule.comap_bot, - Submodule.map_comap_eq_of_surjective (total_surjective _ _), + Submodule.map_comap_eq_of_surjective (linearCombination_surjective _ _), bot_sup_eq, Submodule.map_span, ← Set.range_comp] convert bot_sup_eq _ rw [Submodule.span_eq_bot]; simp @@ -763,14 +773,14 @@ lemma KaehlerDifferential.range_mapBaseChange : · rintro _ ⟨x, rfl⟩ induction' x with r s · simp - · obtain ⟨x, rfl⟩ := total_surjective _ _ s + · obtain ⟨x, rfl⟩ := linearCombination_surjective _ _ s simp only [mapBaseChange_tmul, LinearMap.mem_ker, map_smul] induction x using Finsupp.induction_linear · simp · simp [smul_add, *] · simp · rw [map_add]; exact add_mem ‹_› ‹_› - · convert_to (kerTotal A B).map (Finsupp.total B (Ω[B⁄R]) B (D R B)) ≤ _ + · convert_to (kerTotal A B).map (Finsupp.linearCombination B (D R B)) ≤ _ · rw [KaehlerDifferential.ker_map] congr 1 convert Submodule.comap_id _ @@ -795,11 +805,11 @@ noncomputable def KaehlerDifferential.kerToTensor : RingHom.ker (algebraMap A B) →ₗ[A] B ⊗[A] Ω[A⁄R] where toFun x := 1 ⊗ₜ D R A x - map_add' x y := by simp only [AddSubmonoid.coe_add, Submodule.coe_toAddSubmonoid, map_add, - TensorProduct.tmul_add] - map_smul' r x := by simp only [SetLike.val_smul, Derivation.leibniz, RingHom.id_apply, - TensorProduct.tmul_smul, TensorProduct.smul_tmul', add_zero, ← Algebra.algebraMap_eq_smul_one, - TensorProduct.zero_tmul, smul_eq_mul, TensorProduct.tmul_add, (RingHom.mem_ker _).mp x.prop] + 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, + RingHom.id_apply] /-- The map `I/I² → B ⊗[A] B ⊗[A] Ω[A⁄R]` where `I = ker(A → B)`. -/ noncomputable @@ -810,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) : @@ -827,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 @@ -844,21 +854,23 @@ theorem KaehlerDifferential.range_kerCotangentToTensor intro c _ simp only [Finset.filter_congr_decidable, TensorProduct.lid_symm_apply, LinearMap.rTensor_tmul, AlgHom.toLinearMap_apply, map_one, LinearMap.mem_range] - simp only [map_sum, Finsupp.total_single] + simp only [map_sum, Finsupp.linearCombination_single] have : (x.support.filter (algebraMap A B · = c)).sum x ∈ RingHom.ker (algebraMap A B) := by simpa [Finsupp.mapDomain, Finsupp.sum, Finsupp.finset_sum_apply, RingHom.mem_ker, Finsupp.single_apply, ← Finset.sum_filter] using DFunLike.congr_fun hx c obtain ⟨a, ha⟩ := h c use (x.support.filter (algebraMap A B · = c)).attach.sum fun i ↦ x i • Ideal.toCotangent _ ⟨i - a, ?_⟩; swap - · have : x i ≠ 0 ∧ algebraMap A B i = c := by simpa using i.prop + · have : x i ≠ 0 ∧ algebraMap A B i = c := by + convert i.prop + simp_rw [Finset.mem_filter, Finsupp.mem_support_iff] simp [RingHom.mem_ker, ha, this.2] · simp only [map_sum, LinearMapClass.map_smul, kerCotangentToTensor_toCotangent, map_sub] simp_rw [← TensorProduct.tmul_smul] 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 3f687662317e1..75e250102f8fe 100644 --- a/Mathlib/RingTheory/Kaehler/CotangentComplex.lean +++ b/Mathlib/RingTheory/Kaehler/CotangentComplex.lean @@ -111,7 +111,7 @@ lemma map_tmul (f : Hom P P') (x y) : lemma repr_map (f : Hom P P') (i j) : P'.cotangentSpaceBasis.repr (CotangentSpace.map f (P.cotangentSpaceBasis i)) j = aeval P'.val (pderiv j (f.val i)) := by - simp only [cotangentSpaceBasis_apply, map_tmul, _root_.map_one, Hom.toAlgHom_X, + simp only [cotangentSpaceBasis_apply, map_tmul, map_one, Hom.toAlgHom_X, cotangentSpaceBasis_repr_one_tmul] universe w'' u'' v'' @@ -129,7 +129,7 @@ lemma map_id : CotangentSpace.map (.id P) = LinearMap.id := by apply P.cotangentSpaceBasis.ext intro i - simp only [cotangentSpaceBasis_apply, map_tmul, _root_.map_one, Hom.toAlgHom_X, Hom.id_val, + simp only [cotangentSpaceBasis_apply, map_tmul, map_one, Hom.toAlgHom_X, Hom.id_val, LinearMap.id_coe, id_eq] lemma map_comp (f : Hom P P') (g : Hom P' P'') : @@ -137,7 +137,7 @@ lemma map_comp (f : Hom P P') (g : Hom P' P'') : (CotangentSpace.map g).restrictScalars S ∘ₗ CotangentSpace.map f := by apply P.cotangentSpaceBasis.ext intro i - simp only [cotangentSpaceBasis_apply, map_tmul, _root_.map_one, Hom.toAlgHom_X, Hom.comp_val, + simp only [cotangentSpaceBasis_apply, map_tmul, map_one, Hom.toAlgHom_X, Hom.comp_val, LinearMap.coe_comp, LinearMap.coe_restrictScalars, Function.comp_apply] rfl @@ -148,8 +148,7 @@ lemma map_comp_apply (f : Hom P P') (g : Hom P' P'') (x) : lemma map_cotangentComplex (f : Hom P P') (x) : CotangentSpace.map f (P.cotangentComplex x) = P'.cotangentComplex (.map f x) := by obtain ⟨x, rfl⟩ := Cotangent.mk_surjective x - rw [cotangentComplex_mk, map_tmul, _root_.map_one, Cotangent.map_mk, - cotangentComplex_mk] + rw [cotangentComplex_mk, map_tmul, map_one, Cotangent.map_mk, cotangentComplex_mk] lemma map_comp_cotangentComplex (f : Hom P P') : CotangentSpace.map f ∘ₗ P.cotangentComplex = @@ -158,10 +157,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) - @@ -180,7 +175,7 @@ lemma Hom.sub_aux (f g : Hom P P') (x y) : coe_eval₂Hom, ← aeval_def, ker, RingHom.mem_ker, map_sub, algebraMap_toAlgHom, aeval_val_σ, sub_self] convert this using 1 - simp only [_root_.map_mul] + simp only [map_mul] ring /-- @@ -222,8 +217,7 @@ def Hom.sub (f g : Hom P P') : P.CotangentSpace →ₗ[S] P'.Cotangent := by simp only [LinearMap.coe_comp, LinearMap.coe_restrictScalars, Function.comp_apply, Cotangent.val_mk, Cotangent.val_zero, Ideal.toCotangent_eq_zero] erw [LinearMap.codRestrict_apply] - simp only [LinearMap.sub_apply, AlgHom.toLinearMap_apply, _root_.map_one, sub_self, - Submodule.zero_mem] + simp only [LinearMap.sub_apply, AlgHom.toLinearMap_apply, map_one, sub_self, Submodule.zero_mem] · intro x y ext simp only [LinearMap.coe_comp, LinearMap.coe_restrictScalars, Function.comp_apply, @@ -249,7 +243,7 @@ lemma CotangentSpace.map_sub_map (f g : Hom P P') : P'.cotangentComplex.restrictScalars S ∘ₗ (f.sub g) := by apply P.cotangentSpaceBasis.ext intro i - simp only [cotangentSpaceBasis_apply, LinearMap.sub_apply, map_tmul, _root_.map_one, + simp only [cotangentSpaceBasis_apply, LinearMap.sub_apply, map_tmul, map_one, Hom.toAlgHom_X, LinearMap.coe_comp, LinearMap.coe_restrictScalars, Function.comp_apply, Hom.sub_one_tmul, cotangentComplex_mk, Hom.subToKer_apply_coe, map_sub, tmul_sub] diff --git a/Mathlib/RingTheory/Kaehler/Polynomial.lean b/Mathlib/RingTheory/Kaehler/Polynomial.lean index 103fa5aaec60a..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 @@ -27,20 +27,23 @@ section MvPolynomial def KaehlerDifferential.mvPolynomialEquiv (σ : Type*) : Ω[MvPolynomial σ R⁄R] ≃ₗ[MvPolynomial σ R] σ →₀ MvPolynomial σ R where __ := (MvPolynomial.mkDerivation _ (Finsupp.single · 1)).liftKaehlerDifferential - invFun := Finsupp.total σ _ _ (fun x ↦ D _ _ (MvPolynomial.X x)) + invFun := Finsupp.linearCombination (α := σ) _ (fun x ↦ D _ _ (MvPolynomial.X x)) right_inv := by intro x - induction' x using Finsupp.induction_linear with _ _ _ _ a b - · simp only [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom]; rw [map_zero, map_zero] - · simp only [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, map_add] at *; simp only [*] - · simp [LinearMap.map_smul, -map_smul] + induction x using Finsupp.induction_linear with + | h0 => simp only [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom]; rw [map_zero, map_zero] + | hadd => simp only [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, map_add] at *; simp only [*] + | hsingle a b => simp [LinearMap.map_smul, -map_smul] left_inv := by intro x - obtain ⟨x, rfl⟩ := total_surjective _ _ x - induction' x using Finsupp.induction_linear with _ _ _ _ a b - · simp only [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom]; rw [map_zero, map_zero, map_zero] - · simp only [map_add, AddHom.toFun_eq_coe, LinearMap.coe_toAddHom] at *; simp only [*] - · simp only [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, Finsupp.total_single, + obtain ⟨x, rfl⟩ := linearCombination_surjective _ _ x + induction x using Finsupp.induction_linear with + | h0 => + simp only [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom] + rw [map_zero, map_zero, map_zero] + | hadd => simp only [map_add, AddHom.toFun_eq_coe, LinearMap.coe_toAddHom] at *; simp only [*] + | hsingle a b => + simp only [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, Finsupp.linearCombination_single, LinearMap.map_smul, Derivation.liftKaehlerDifferential_comp_D] congr 1 induction a using MvPolynomial.induction_on @@ -109,7 +112,7 @@ def KaehlerDifferential.polynomialEquiv : Ω[R[X]⁄R] ≃ₗ[R[X]] R[X] where invFun := (Algebra.lsmul R R _).toLinearMap.flip (D R R[X] X) left_inv := by intro x - obtain ⟨x, rfl⟩ := total_surjective _ _ x + obtain ⟨x, rfl⟩ := linearCombination_surjective _ _ x induction' x using Finsupp.induction_linear with x y hx hy x y · simp · simp only [map_add, AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, LinearMap.flip_apply, 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/LaurentSeries.lean b/Mathlib/RingTheory/LaurentSeries.lean index 0715d3ae16630..e9cc56ec5ec51 100644 --- a/Mathlib/RingTheory/LaurentSeries.lean +++ b/Mathlib/RingTheory/LaurentSeries.lean @@ -11,46 +11,62 @@ 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 +74,21 @@ 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,7 +101,7 @@ def hasseDeriv (R : Type*) {V : Type*} [AddCommGroup V] [Semiring R] [Module R V variable [Semiring R] {V : Type*} [AddCommGroup V] [Module R V] -theorem hasseDeriv_coeff (k : ℕ) (f : LaurentSeries V) (n : ℤ) : +theorem hasseDeriv_coeff (k : ℕ) (f : V⸨X⸩) (n : ℤ) : (hasseDeriv R k f).coeff n = Ring.choose (n + k) k • f.coeff (n + k) := rfl @@ -86,37 +111,37 @@ 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 := + constant term. -/ +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 +153,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 +170,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 +211,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 +222,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 := +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 := +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 := +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 := +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, @@ -233,61 +257,63 @@ theorem coeff_coe (i : ℤ) : · rw [ofPowerSeries_apply, embDomain_notin_image_support, if_pos (Int.negSucc_lt_zero _)] simp only [not_exists, RelEmbedding.coe_mk, Set.mem_image, not_and, Function.Embedding.coeFn_mk, Ne, toPowerSeries_symm_apply_coeff, mem_support, imp_true_iff, - not_false_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 +323,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 +370,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 +402,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 +421,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 +472,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 +489,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 +516,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 +536,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 @@ -525,7 +551,7 @@ theorem coeff_zero_of_lt_valuation {n D : ℤ} {f : LaurentSeries K} apply (intValuation_le_iff_coeff_lt_eq_zero K F).mp _ m (by linarith) rwa [hF, ofPowerSeries_powerSeriesPart f, hs, neg_neg, ← hd, neg_add_rev, ofAdd_add, map_mul, ← ofPowerSeries_X_pow s, PowerSeries.coe_pow, WithZero.coe_mul, valuation_X_pow K s, - mul_le_mul_left₀ (by simp only [ne_eq, WithZero.coe_ne_zero, not_false_iff])] + mul_le_mul_left (by simp only [ne_eq, WithZero.coe_ne_zero, not_false_iff, zero_lt_iff])] · rw [not_le] at ord_nonpos obtain ⟨s, hs⟩ := Int.exists_eq_neg_ofNat (Int.neg_nonpos_of_nonneg (le_of_lt ord_nonpos)) obtain ⟨m, hm⟩ := Int.eq_ofNat_of_zero_le (a := n - s) (by linarith) @@ -535,10 +561,10 @@ theorem coeff_zero_of_lt_valuation {n D : ℤ} {f : LaurentSeries K} apply (intValuation_le_iff_coeff_lt_eq_zero K F).mp _ m (by linarith) rwa [hF, ofPowerSeries_powerSeriesPart f, map_mul, ← hd, hs, neg_sub, sub_eq_add_neg, ofAdd_add, valuation_single_zpow, neg_neg, WithZero.coe_mul, - mul_le_mul_left₀ (by simp only [ne_eq, WithZero.coe_ne_zero, not_false_iff])] + 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 @@ -558,7 +584,7 @@ theorem valuation_le_iff_coeff_lt_eq_zero {D : ℤ} {f : LaurentSeries K} : rw [powerSeriesPart_coeff f n, hs] apply h_val_f linarith - · simp only [ne_eq, WithZero.coe_ne_zero, not_false_iff] + · simp only [ne_eq, WithZero.coe_ne_zero, not_false_iff, zero_lt_iff] · obtain ⟨s, hs⟩ := Int.exists_eq_neg_ofNat <| neg_nonpos_of_nonneg <| le_of_lt <| not_le.mp ord_nonpos rw [neg_inj] at hs @@ -576,22 +602,22 @@ theorem valuation_le_iff_coeff_lt_eq_zero {D : ℤ} {f : LaurentSeries K} : rw [powerSeriesPart_coeff f n, hs] apply h_val_f (s + n) linarith - · simp only [ne_eq, WithZero.coe_ne_zero, not_false_iff] + · simp only [ne_eq, WithZero.coe_ne_zero, not_false_iff, zero_lt_iff] /- 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) @@ -601,7 +627,7 @@ theorem val_le_one_iff_eq_coe (f : LaurentSeries K) : Valued.v f ≤ (1 : ℤₘ all_goals apply HahnSeries.embDomain_notin_range simp only [Nat.coe_castAddMonoidHom, RelEmbedding.coe_mk, Function.Embedding.coeFn_mk, - Set.mem_range, not_exists, Int.negSucc_lt_zero,] + Set.mem_range, not_exists, Int.negSucc_lt_zero, reduceCtorEq] intro · simp only [not_false_eq_true] · linarith @@ -609,3 +635,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/LittleWedderburn.lean b/Mathlib/RingTheory/LittleWedderburn.lean index 0c6818c3c622f..42f44f6d9f529 100644 --- a/Mathlib/RingTheory/LittleWedderburn.lean +++ b/Mathlib/RingTheory/LittleWedderburn.lean @@ -6,6 +6,7 @@ Authors: Johan Commelin, Eric Rodriguez import Mathlib.GroupTheory.ClassEquation import Mathlib.GroupTheory.GroupAction.ConjAct import Mathlib.RingTheory.Polynomial.Cyclotomic.Eval +import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition /-! # Wedderburn's Little Theorem @@ -47,7 +48,7 @@ private def InductionHyp : Prop := namespace InductionHyp -open FiniteDimensional Polynomial +open Module Polynomial variable {D} @@ -95,7 +96,7 @@ private theorem center_eq_top [Finite D] (hD : InductionHyp D) : Subring.center refine not_le_of_lt hZ.lt_top (fun y _ ↦ Subring.mem_center_iff.mpr fun z ↦ ?_) obtain ⟨r, rfl⟩ := hx y obtain ⟨s, rfl⟩ := hx z - rw [smul_mul_smul, smul_mul_smul, mul_comm] + rw [smul_mul_smul_comm, smul_mul_smul_comm, mul_comm] rw [Nat.cast_sum] apply Finset.dvd_sum rintro ⟨x⟩ hx @@ -148,7 +149,7 @@ private theorem center_eq_top [Finite D] : Subring.center D = ⊤ := by rw [IH (Fintype.card R) _ R inferInstance rfl] · trivial rw [← hn, ← Subring.card_top D] - exact Set.card_lt_card hR + convert Set.card_lt_card hR end LittleWedderburn diff --git a/Mathlib/RingTheory/LocalProperties.lean b/Mathlib/RingTheory/LocalProperties.lean deleted file mode 100644 index 95ef9fd34099e..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, Subtype.coe_mk, ← 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, Subtype.coe_mk, ← 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..a3ece3c9a9726 --- /dev/null +++ b/Mathlib/RingTheory/LocalProperties/Basic.lean @@ -0,0 +1,332 @@ +/- +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.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] (M : Submonoid R) (f : R →+* S) +variable (N : Submonoid S) (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 + +theorem RingHom.PropertyIsLocal.respectsIso (hP : RingHom.PropertyIsLocal @P) : + RingHom.RespectsIso @P := by + constructor + · intro R S T _ _ _ f e hf + letI := e.toRingHom.toAlgebra + have : IsLocalization.Away (1 : S) T := + IsLocalization.away_of_isUnit_of_bijective _ isUnit_one e.bijective + exact hP.StableUnderCompositionWithLocalizationAway.left T (1 : S) f hf + · intro R S T _ _ _ f e hf + letI := e.toRingHom.toAlgebra + have : IsLocalization.Away (1 : R) S := + IsLocalization.away_of_isUnit_of_bijective _ isUnit_one e.bijective + exact hP.StableUnderCompositionWithLocalizationAway.right S (1 : R) f hf + +-- 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] + +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 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..65df178848887 --- /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 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 {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 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 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/Module.lean b/Mathlib/RingTheory/LocalRing/Module.lean index f850665a24192..332bccee7c8f5 100644 --- a/Mathlib/RingTheory/LocalRing/Module.lean +++ b/Mathlib/RingTheory/LocalRing/Module.lean @@ -93,7 +93,7 @@ theorem span_eq_top_of_tmul_eq_basis [Module.Finite R M] {ι} rw [← map_tensorProduct_mk_eq_top, Submodule.map_span, ← Submodule.restrictScalars_span R k Ideal.Quotient.mk_surjective, Submodule.restrictScalars_eq_top_iff, ← b.span_eq, ← Set.range_comp] - simp only [Function.comp, mk_apply, hb, Basis.span_eq] + simp only [Function.comp_def, mk_apply, hb, Basis.span_eq] end LocalRing @@ -151,10 +151,10 @@ theorem free_of_maximalIdeal_rTensor_injective [Module.FinitePresentation R M] letI : IsNoetherian k (k ⊗[R] (I →₀ R)) := isNoetherian_of_isNoetherianRing_of_finite k (k ⊗[R] (I →₀ R)) choose f hf using TensorProduct.mk_surjective R M k Ideal.Quotient.mk_surjective - -- By choosing an abitrary lift of `b` to `I → M`, we get a surjection `i : Rᴵ → M`. - let i := Finsupp.total I M R (f ∘ b) + -- By choosing an arbitrary lift of `b` to `I → M`, we get a surjection `i : Rᴵ → M`. + let i := Finsupp.linearCombination R (f ∘ b) have hi : Surjective i := by - rw [← LinearMap.range_eq_top, Finsupp.range_total] + rw [← LinearMap.range_eq_top, Finsupp.range_linearCombination] exact LocalRing.span_eq_top_of_tmul_eq_basis (R := R) (f := f ∘ b) b (fun _ ↦ hf _) have : Module.Finite R (LinearMap.ker i) := by constructor @@ -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/ResidueField/Basic.lean b/Mathlib/RingTheory/LocalRing/ResidueField/Basic.lean index 25391bf0ccb40..885d727ff53f4 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 /-! @@ -145,6 +145,34 @@ theorem residue_smul (g : G) (r : R) : residue R (g • r) = g • residue R r : end MulSemiringAction +section FiniteDimensional + +variable [Algebra R S] [IsLocalRingHom (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) + +lemma finite_of_finite [IsNoetherian R S] (hfin : Finite (ResidueField R)) : + Finite (ResidueField S) := by + have := @finiteDimensional_of_noetherian R S + exact FiniteDimensional.finite_of_finite (ResidueField R) (ResidueField S) + +end FiniteDimensional + end ResidueField theorem isLocalRingHom_residue : IsLocalRingHom (LocalRing.residue R) := by diff --git a/Mathlib/RingTheory/LocalRing/RingHom/Basic.lean b/Mathlib/RingTheory/LocalRing/RingHom/Basic.lean index fc9ea8c3bc6a3..4b44e62f3ee66 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 @@ -24,34 +24,14 @@ variable [Semiring R] [Semiring S] [Semiring T] instance isLocalRingHom_id (R : Type*) [Semiring R] : IsLocalRingHom (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⟩ +-- see note [lower instance priority] +instance (priority := 100) isLocalRingHom_toRingHom {F : Type*} [FunLike F R S] + [RingHomClass F R S] (f : F) [IsLocalRingHom f] : IsLocalRingHom (f : R →+* S) := + ⟨IsLocalRingHom.map_nonunit (f := f)⟩ --- 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⟩ +instance RingHom.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 := g) (f a) theorem isLocalRingHom_of_comp (f : R →+* S) (g : S →+* T) [IsLocalRingHom (g.comp f)] : IsLocalRingHom f := @@ -97,22 +77,13 @@ theorem local_hom_TFAE (f : R →+* 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 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 bf2fa84c5d38c..794c17c9aea4a 100644 --- a/Mathlib/RingTheory/Localization/Algebra.lean +++ b/Mathlib/RingTheory/Localization/Algebra.lean @@ -56,12 +56,12 @@ 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 [AddSubmonoid.coe_add, Submodule.coe_toAddSubmonoid, map_add, AddSubmonoid.mk_add_mk] + simp only [Submodule.coe_add, map_add, AddMemClass.mk_add_mk] map_smul' a x := by - simp only [SetLike.val_smul, smul_eq_mul, map_mul, RingHom.id_apply, - SetLike.mk_smul_of_tower_mk, Algebra.smul_def] + simp only [SetLike.val_smul, smul_eq_mul, map_mul, id_apply, SetLike.mk_smul_of_tower_mk, + Algebra.smul_def] @[simp] lemma RingHom.toKerIsLocalization_apply (hy : M ≤ Submonoid.comap g T) (r : RingHom.ker g) : diff --git a/Mathlib/RingTheory/Localization/AtPrime.lean b/Mathlib/RingTheory/Localization/AtPrime.lean index 6ff9e226beb8a..5b122fb2d696c 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 @@ -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 diff --git a/Mathlib/RingTheory/Localization/Away/Basic.lean b/Mathlib/RingTheory/Localization/Away/Basic.lean index c41d650a75ef4..13a452b4b4e86 100644 --- a/Mathlib/RingTheory/Localization/Away/Basic.lean +++ b/Mathlib/RingTheory/Localization/Away/Basic.lean @@ -38,7 +38,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 +69,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 +199,53 @@ 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 + +/-- 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 +275,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/Basic.lean b/Mathlib/RingTheory/Localization/Basic.lean index ec5333ad7be07..71f588f147216 100644 --- a/Mathlib/RingTheory/Localization/Basic.lean +++ b/Mathlib/RingTheory/Localization/Basic.lean @@ -262,6 +262,9 @@ 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 @@ -825,6 +828,48 @@ 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 namespace Localization @@ -1056,7 +1101,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..1c11c039219dd 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 diff --git a/Mathlib/RingTheory/Localization/Finiteness.lean b/Mathlib/RingTheory/Localization/Finiteness.lean index 10abd059206ce..ab340bfec9330 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 /-! @@ -53,10 +53,9 @@ lemma of_isLocalizedModule [Module.Finite R M] : Module.Finite Rₚ Mₚ := by (Submodule.span Rₚ (f '' T)).restrictScalars R := by rw [Submodule.span_le]; exact Submodule.subset_span convert (Submodule.span Rₚ (f '' T)).smul_mem - (IsLocalization.mk' Rₚ (1 : R) m) (H this) using 1 + (IsLocalization.mk' Rₚ (1 : R) m) (H this) using 0 · rw [← hyx, ← IsLocalizedModule.mk'_one S, IsLocalizedModule.mk'_smul_mk'] simp - · simp end diff --git a/Mathlib/RingTheory/Localization/FractionRing.lean b/Mathlib/RingTheory/Localization/FractionRing.lean index 1960bbcd7e01d..f4b231a725789 100644 --- a/Mathlib/RingTheory/Localization/FractionRing.lean +++ b/Mathlib/RingTheory/Localization/FractionRing.lean @@ -132,7 +132,7 @@ noncomputable abbrev toField : Field K where 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/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/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/NumDen.lean b/Mathlib/RingTheory/Localization/NumDen.lean index 10a844a4ca9d4..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 := @@ -81,7 +81,7 @@ theorem num_mul_den_eq_num_mul_den_iff_eq {x y : K} : ⟨fun h ↦ by simpa only [mk'_num_den] using mk'_eq_of_eq' (S := K) h, fun h ↦ by rw [h]⟩ theorem eq_zero_of_num_eq_zero {x : K} (h : num A x = 0) : x = 0 := - num_mul_den_eq_num_iff_eq'.mp (by rw [zero_mul, h, RingHom.map_zero]) + (num_mul_den_eq_num_iff_eq' (A := A)).mp (by rw [zero_mul, h, RingHom.map_zero]) @[simp] lemma num_zero : IsFractionRing.num A (0 : K) = 0 := by diff --git a/Mathlib/RingTheory/Localization/Submodule.lean b/Mathlib/RingTheory/Localization/Submodule.lean index b00dfdb755232..b1cda5e8116b6 100644 --- a/Mathlib/RingTheory/Localization/Submodule.lean +++ b/Mathlib/RingTheory/Localization/Submodule.lean @@ -79,7 +79,7 @@ variable [IsLocalization M S] include M in theorem isNoetherianRing (h : IsNoetherianRing R) : IsNoetherianRing S := by - rw [isNoetherianRing_iff, isNoetherian_iff_wellFounded] at h ⊢ + rw [isNoetherianRing_iff, isNoetherian_iff] at h ⊢ exact OrderEmbedding.wellFounded (IsLocalization.orderEmbedding M S).dual h variable {S M} diff --git a/Mathlib/RingTheory/MatrixAlgebra.lean b/Mathlib/RingTheory/MatrixAlgebra.lean index 8525a367e4fcf..4a71967b89d79 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,13 +96,13 @@ 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) + 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] diff --git a/Mathlib/RingTheory/Multiplicity.lean b/Mathlib/RingTheory/Multiplicity.lean index effafa7779249..457a6e35fcef7 100644 --- a/Mathlib/RingTheory/Multiplicity.lean +++ b/Mathlib/RingTheory/Multiplicity.lean @@ -506,7 +506,7 @@ protected theorem mul' {p a b : α} (hp : Prime p) (h : (multiplicity p (a * b)) 1) ∣ a * b := fun h => - not_or_of_not (is_greatest' _ (lt_succ_self _)) (is_greatest' _ (lt_succ_self _)) + not_or_intro (is_greatest' _ (lt_succ_self _)) (is_greatest' _ (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⟩ diff --git a/Mathlib/RingTheory/MvPolynomial/Homogeneous.lean b/Mathlib/RingTheory/MvPolynomial/Homogeneous.lean index f9a0ed2868cf3..4772bb3e6107b 100644 --- a/Mathlib/RingTheory/MvPolynomial/Homogeneous.lean +++ b/Mathlib/RingTheory/MvPolynomial/Homogeneous.lean @@ -49,7 +49,7 @@ variable [CommSemiring R] theorem weightedTotalDegree_one (φ : MvPolynomial σ R) : weightedTotalDegree (1 : σ → ℕ) φ = φ.totalDegree := by simp only [totalDegree, weightedTotalDegree, weight, LinearMap.toAddMonoidHom_coe, - Finsupp.total, Pi.one_apply, Finsupp.coe_lsum, LinearMap.coe_smulRight, LinearMap.id_coe, + linearCombination, Pi.one_apply, Finsupp.coe_lsum, LinearMap.coe_smulRight, LinearMap.id_coe, id, Algebra.id.smul_eq_mul, mul_one] variable (σ R) 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 552085840486d..9f1b0b51970ce 100644 --- a/Mathlib/RingTheory/MvPolynomial/Localization.lean +++ b/Mathlib/RingTheory/MvPolynomial/Localization.lean @@ -129,8 +129,8 @@ private lemma auxInv_auxHom : (auxInv S r).comp (auxHom (S := S) r).toRingHom = Function.comp_apply, auxHom_mk, aeval_X, RingHomCompTriple.comp_eq] erw [IsLocalization.lift_mk'_spec] simp only [map_one, RingHom.coe_comp, Function.comp_apply] - rw [← map_one (Ideal.Quotient.mk _)] - rw [← map_mul, Ideal.Quotient.mk_eq_mk_iff_sub_mem, ← Ideal.neg_mem_iff, neg_sub] + rw [← map_one (Ideal.Quotient.mk _), ← map_mul, Ideal.Quotient.mk_eq_mk_iff_sub_mem, + ← Ideal.neg_mem_iff, neg_sub] exact Ideal.mem_span_singleton_self (C r * X x - 1) /-- The canonical algebra isomorphism from `MvPolynomial Unit R` quotiented by diff --git a/Mathlib/RingTheory/MvPolynomial/Symmetric.lean b/Mathlib/RingTheory/MvPolynomial/Symmetric/Defs.lean similarity index 99% rename from Mathlib/RingTheory/MvPolynomial/Symmetric.lean rename to Mathlib/RingTheory/MvPolynomial/Symmetric/Defs.lean index 49097e138f0bb..691265878f204 100644 --- a/Mathlib/RingTheory/MvPolynomial/Symmetric.lean +++ b/Mathlib/RingTheory/MvPolynomial/Symmetric/Defs.lean @@ -367,12 +367,12 @@ variable [DecidableEq σ] [DecidableEq τ] {n : ℕ} /-- The monomial symmetric `MvPolynomial σ R` with exponent set μ. It is the sum over all the monomials in `MvPolynomial σ R` such that the multiset of exponents is equal to the multiset of parts of μ. -/ -def msymm (μ : n.Partition) : MvPolynomial σ R := - ∑ s : {a : Sym σ n // .ofSym a = μ}, (s.1.1.map X).prod +def msymm (μ : n.Partition) : MvPolynomial σ R := + ∑ s : {a : Sym σ n // .ofSym a = μ}, (s.1.1.map X).prod @[simp] theorem msymm_zero : msymm σ R (.indiscrete 0) = 1 := by - rw [msymm, Fintype.sum_subsingleton _ ⟨(Sym.nil : Sym σ 0), by rfl⟩] + rw [msymm, Fintype.sum_subsingleton _ ⟨(Sym.nil : Sym σ 0), rfl⟩] simp @[simp] diff --git a/Mathlib/RingTheory/MvPolynomial/Symmetric/FundamentalTheorem.lean b/Mathlib/RingTheory/MvPolynomial/Symmetric/FundamentalTheorem.lean new file mode 100644 index 0000000000000..717b6f8ac0bf2 --- /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 in univ.filter (fun i : Fin n ↦ (j : ℕ) ≤ i), t i + map_zero' := funext <| fun j ↦ sum_eq_zero <| fun h _ ↦ 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.card = (Iic (⟨i, him⟩ : Fin m)).card := 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 99% rename from Mathlib/RingTheory/MvPolynomial/NewtonIdentities.lean rename to Mathlib/RingTheory/MvPolynomial/Symmetric/NewtonIdentities.lean index 5d1767881cad0..3aa09ead7b4ab 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 diff --git a/Mathlib/RingTheory/MvPolynomial/Tower.lean b/Mathlib/RingTheory/MvPolynomial/Tower.lean index 691f027ab1158..77228738a64aa 100644 --- a/Mathlib/RingTheory/MvPolynomial/Tower.lean +++ b/Mathlib/RingTheory/MvPolynomial/Tower.lean @@ -47,12 +47,12 @@ theorem aeval_algebraMap_apply (x : σ → A) (p : MvPolynomial σ R) : rw [aeval_def, aeval_def, ← coe_eval₂Hom, ← coe_eval₂Hom, map_eval₂Hom, ← IsScalarTower.algebraMap_eq] -- Porting note: added - simp only [Function.comp] + simp only [Function.comp_def] 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 2f0b07d5dd242..a5d6459f7d56f 100644 --- a/Mathlib/RingTheory/MvPolynomial/WeightedHomogeneous.lean +++ b/Mathlib/RingTheory/MvPolynomial/WeightedHomogeneous.lean @@ -214,7 +214,7 @@ theorem isWeightedHomogeneous_one (w : σ → M) : IsWeightedHomogeneous w (1 : theorem isWeightedHomogeneous_X (w : σ → M) (i : σ) : IsWeightedHomogeneous w (X i : MvPolynomial σ R) (w i) := by apply isWeightedHomogeneous_monomial - simp only [weight, LinearMap.toAddMonoidHom_coe, total_single, one_nsmul] + simp only [weight, LinearMap.toAddMonoidHom_coe, linearCombination_single, one_nsmul] namespace IsWeightedHomogeneous @@ -506,7 +506,7 @@ theorem weightedHomogeneousComponent_zero [NoZeroSMulDivisors ℕ M] (hw : ∀ i rcases Classical.em (d = 0) with (rfl | hd) · simp only [coeff_weightedHomogeneousComponent, if_pos, map_zero, coeff_zero_C] · rw [coeff_weightedHomogeneousComponent, if_neg, coeff_C, if_neg (Ne.symm hd)] - simp only [weight, LinearMap.toAddMonoidHom_coe, Finsupp.total_apply, Finsupp.sum, + simp only [weight, LinearMap.toAddMonoidHom_coe, Finsupp.linearCombination_apply, Finsupp.sum, sum_eq_zero_iff, Finsupp.mem_support_iff, Ne, smul_eq_zero, not_forall, not_or, and_self_left, exists_prop] simp only [DFunLike.ext_iff, Finsupp.coe_zero, Pi.zero_apply, not_forall] at hd @@ -531,7 +531,7 @@ variable [CanonicallyLinearOrderedAddCommMonoid M] {w : σ → M} (φ : MvPolyno has weighted degree zero if and only if `∀ x : σ, m x = 0`. -/ theorem weightedDegree_eq_zero_iff (hw : NonTorsionWeight w) {m : σ →₀ ℕ} : weight w m = 0 ↔ ∀ x : σ, m x = 0 := by - simp only [weight, Finsupp.total, LinearMap.toAddMonoidHom_coe, coe_lsum, + simp only [weight, Finsupp.linearCombination, LinearMap.toAddMonoidHom_coe, coe_lsum, LinearMap.coe_smulRight, LinearMap.id_coe, id_eq] rw [Finsupp.sum, Finset.sum_eq_zero_iff] apply forall_congr' @@ -582,7 +582,7 @@ theorem weightedHomogeneousComponent_eq_zero_of_not_mem [DecidableEq M] variable (R) -/-- The `decompose'` argument of `weightedDecomposition`. -/ +/-- The `decompose'` argument of `weightedDecomposition`. -/ def decompose' [DecidableEq M] := fun φ : MvPolynomial σ R => DirectSum.mk (fun i : M => ↥(weightedHomogeneousSubmodule R w i)) (Finset.image (weight w) φ.support) fun m => diff --git a/Mathlib/RingTheory/MvPowerSeries/Basic.lean b/Mathlib/RingTheory/MvPowerSeries/Basic.lean index 8e2b9f0fb7e79..3e649d881d0c8 100644 --- a/Mathlib/RingTheory/MvPowerSeries/Basic.lean +++ b/Mathlib/RingTheory/MvPowerSeries/Basic.lean @@ -730,7 +730,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..d53136ff960c2 100644 --- a/Mathlib/RingTheory/MvPowerSeries/Inverse.lean +++ b/Mathlib/RingTheory/MvPowerSeries/Inverse.lean @@ -7,7 +7,7 @@ Authors: Johan Commelin, Kenny Lau import Mathlib.Algebra.Group.Units 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 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/Nakayama.lean b/Mathlib/RingTheory/Nakayama.lean index 3c19bfdae99d5..2cf0c3850d107 100644 --- a/Mathlib/RingTheory/Nakayama.lean +++ b/Mathlib/RingTheory/Nakayama.lean @@ -46,7 +46,7 @@ namespace Submodule /-- **Nakayama's Lemma** - A slightly more general version of (2) in [Stacks 00DV](https://stacks.math.columbia.edu/tag/00DV). -See also `eq_bot_of_le_smul_of_le_jacobson_bot` for the special case when `J = ⊥`. -/ +See also `eq_bot_of_le_smul_of_le_jacobson_bot` for the special case when `J = ⊥`. -/ theorem eq_smul_of_le_smul_of_le_jacobson {I J : Ideal R} {N : Submodule R M} (hN : N.FG) (hIN : N ≤ I • N) (hIjac : I ≤ jacobson J) : N = J • N := by refine le_antisymm ?_ (Submodule.smul_le.2 fun _ _ _ => Submodule.smul_mem _ _) @@ -123,7 +123,7 @@ theorem sup_eq_sup_smul_of_le_smul_of_le_jacobson {I J : Ideal R} {N N' : Submod /-- **Nakayama's Lemma** - A slightly more general version of (4) in [Stacks 00DV](https://stacks.math.columbia.edu/tag/00DV). -See also `smul_le_of_le_smul_of_le_jacobson_bot` for the special case when `J = ⊥`. -/ +See also `smul_le_of_le_smul_of_le_jacobson_bot` for the special case when `J = ⊥`. -/ theorem sup_smul_eq_sup_smul_of_le_smul_of_le_jacobson {I J : Ideal R} {N N' : Submodule R M} (hN' : N'.FG) (hIJ : I ≤ jacobson J) (hNN : N' ≤ N ⊔ I • N') : N ⊔ I • N' = N ⊔ J • N' := ((sup_le_sup_left smul_le_right _).antisymm (sup_le le_sup_left hNN)).trans diff --git a/Mathlib/RingTheory/Nilpotent/Basic.lean b/Mathlib/RingTheory/Nilpotent/Basic.lean index 0080e768a4300..71e196c394db9 100644 --- a/Mathlib/RingTheory/Nilpotent/Basic.lean +++ b/Mathlib/RingTheory/Nilpotent/Basic.lean @@ -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 36d5f8aa60445..fdbae3b577172 100644 --- a/Mathlib/RingTheory/Nilpotent/Lemmas.lean +++ b/Mathlib/RingTheory/Nilpotent/Lemmas.lean @@ -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,11 +89,30 @@ 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 [LinearMap.pow_restrict n, LinearMap.restrict_apply, hn]⟩ + 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 5115056fb0474..903c8862e2b78 100644 --- a/Mathlib/RingTheory/Noetherian.lean +++ b/Mathlib/RingTheory/Noetherian.lean @@ -34,8 +34,8 @@ Let `R` be a ring and let `M` and `P` be `R`-modules. Let `N` be an `R`-submodul ## Main statements -* `isNoetherian_iff_wellFounded` is the theorem that an R-module M is Noetherian iff - `>` is well-founded on `Submodule R M`. +* `isNoetherian_iff` is the theorem that an R-module M is Noetherian iff `>` is well-founded on + `Submodule R M`. Note that the Hilbert basis theorem, that if a commutative ring R is Noetherian then so is R[X], is proved in `RingTheory.Polynomial`. @@ -145,17 +145,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,77 +188,13 @@ 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_pi {R ι : Type*} [Finite ι] : + ∀ {M : ι → Type*} [Ring R] [∀ 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 @@ -289,29 +229,37 @@ 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_wellFounded : - 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)⟩⟩ +theorem isNoetherian_iff : + IsNoetherian R M ↔ WellFounded ((· > ·) : Submodule R M → Submodule R M → Prop) := by + rw [isNoetherian_iff', ← isWellFounded_iff] + +alias ⟨IsNoetherian.wf, _⟩ := isNoetherian_iff + +alias ⟨IsNoetherian.wellFoundedGT, isNoetherian_mk⟩ := isNoetherian_iff' + +instance wellFoundedGT [h : IsNoetherian R M] : WellFoundedGT (Submodule R M) := + h.wellFoundedGT + theorem isNoetherian_iff_fg_wellFounded : - IsNoetherian R M ↔ - WellFounded - ((· > ·) : { N : Submodule R M // N.FG } → { N : Submodule R M // N.FG } → Prop) := by + IsNoetherian R M ↔ WellFoundedGT { N : Submodule R M // N.FG } := by let α := { N : Submodule R M // N.FG } constructor · intro H let f : α ↪o Submodule R M := OrderEmbedding.subtype _ - exact OrderEmbedding.wellFounded f.dual (isNoetherian_iff_wellFounded.mp H) + exact OrderEmbedding.wellFoundedLT f.dual · intro H constructor intro N obtain ⟨⟨N₀, h₁⟩, e : N₀ ≤ N, h₂⟩ := - WellFounded.has_min H { N' : α | N'.1 ≤ N } ⟨⟨⊥, Submodule.fg_bot⟩, @bot_le _ _ _ N⟩ + WellFounded.has_min H.wf { N' : α | N'.1 ≤ N } ⟨⟨⊥, Submodule.fg_bot⟩, @bot_le _ _ _ N⟩ convert h₁ refine (e.antisymm ?_).symm by_contra h₃ @@ -322,24 +270,16 @@ theorem isNoetherian_iff_fg_wellFounded : sup_le ((Submodule.span_singleton_le_iff_mem _ _).mpr hx₁) e)] exact (le_sup_left : (R ∙ x) ≤ _) (Submodule.mem_span_singleton_self _) -variable (R M) - -theorem wellFounded_submodule_gt (R M) [Semiring R] [AddCommMonoid M] [Module R M] : - ∀ [IsNoetherian R M], WellFounded ((· > ·) : Submodule R M → Submodule R M → Prop) := - isNoetherian_iff_wellFounded.mp ‹_› - -variable {R M} - /-- A module is Noetherian iff every nonempty set of submodules has a maximal submodule among them. -/ theorem set_has_maximal_iff_noetherian : (∀ a : Set <| Submodule R M, a.Nonempty → ∃ M' ∈ a, ∀ I ∈ a, ¬M' < I) ↔ IsNoetherian R M := by - rw [isNoetherian_iff_wellFounded, WellFounded.wellFounded_iff_has_min] + rw [isNoetherian_iff, WellFounded.wellFounded_iff_has_min] /-- A module is Noetherian iff every increasing chain of submodules stabilizes. -/ theorem monotone_stabilizes_iff_noetherian : (∀ f : ℕ →o Submodule R M, ∃ n, ∀ m, n ≤ m → f n = f m) ↔ IsNoetherian R M := by - rw [isNoetherian_iff_wellFounded, WellFounded.monotone_chain_condition] + rw [isNoetherian_iff, WellFounded.monotone_chain_condition] theorem eventuallyConst_of_isNoetherian [IsNoetherian R M] (f : ℕ →o Submodule R M) : atTop.EventuallyConst f := by @@ -349,7 +289,7 @@ theorem eventuallyConst_of_isNoetherian [IsNoetherian R M] (f : ℕ →o Submodu /-- If `∀ I > J, P I` implies `P J`, then `P` holds for all submodules. -/ theorem IsNoetherian.induction [IsNoetherian R M] {P : Submodule R M → Prop} (hgt : ∀ I, (∀ J > I, P J) → P I) (I : Submodule R M) : P I := - WellFounded.recursion (wellFounded_submodule_gt R M) I hgt + IsWellFounded.induction _ I hgt end @@ -363,15 +303,14 @@ 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 - (isNoetherian_iff_wellFounded.mp inferInstance) 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 - have hwf := isNoetherian_iff_wellFounded.mp (by infer_instance : IsNoetherian R M) - refine CompleteLattice.WellFounded.finite_of_independent hwf hv.independent_span_singleton + refine CompleteLattice.WellFoundedGT.finite_of_independent + hv.independent_span_singleton fun i contra => ?_ apply hv.ne_zero i have : v i ∈ R ∙ v i := Submodule.mem_span_singleton_self (v i) @@ -381,27 +320,28 @@ 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] (f : M →ₗ[R] N) (g : N →ₗ[R] P) (h : LinearMap.range f = LinearMap.ker g) : IsNoetherian R N := - isNoetherian_iff_wellFounded.2 <| + isNoetherian_mk <| wellFounded_gt_exact_sequence - (wellFounded_submodule_gt R _) (wellFounded_submodule_gt R _) (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) : @@ -426,7 +366,7 @@ lemma LinearMap.eventually_iSup_ker_pow_eq (f : M →ₗ[R] M) : · rw [← hn _ (hm.trans h), hn _ hm] · exact f.iterateKer.monotone h.le -/-- **Orzech's theorem** for Noetherian module: if `R` is a ring (not necessarily commutative), +/-- **Orzech's theorem** for Noetherian modules: if `R` is a ring (not necessarily commutative), `M` and `N` are `R`-modules, `M` is Noetherian, `i : N →ₗ[R] M` is injective, `f : N →ₗ[R] M` is surjective, then `f` is also injective. The proof here is adapted from Djoković's paper *Epimorphisms of modules which must be isomorphisms* [djokovic1973], @@ -440,7 +380,7 @@ theorem IsNoetherian.injective_of_surjective_of_injective (i f : N →ₗ[R] M) exact LinearMap.ker_eq_bot.1 <| bot_unique <| f.ker_le_of_iterateMapComap_eq_succ i ⊥ n (H _ (Nat.le_succ _)) hf hi -/-- **Orzech's theorem** for Noetherian module: if `R` is a ring (not necessarily commutative), +/-- **Orzech's theorem** for Noetherian modules: if `R` is a ring (not necessarily commutative), `M` is a Noetherian `R`-module, `N` is a submodule, `f : N →ₗ[R] M` is surjective, then `f` is also injective. -/ theorem IsNoetherian.injective_of_surjective_of_submodule @@ -459,8 +399,7 @@ theorem IsNoetherian.bijective_of_surjective_endomorphism (f : M →ₗ[R] M) /-- A sequence `f` of submodules of a noetherian module, with `f (n+1)` disjoint from the supremum of `f 0`, ..., `f n`, -is eventually zero. --/ +is eventually zero. -/ theorem IsNoetherian.disjoint_partialSups_eventually_bot (f : ℕ → Submodule R M) (h : ∀ n, Disjoint (partialSups f n) (f (n + 1))) : ∃ n : ℕ, ∀ m, n ≤ m → f m = ⊥ := by @@ -493,8 +432,7 @@ def IsNoetherian.equivPUnitOfProdInjective (f : M × N →ₗ[R] M) end /-- A (semi)ring is Noetherian if it is Noetherian as a module over itself, -i.e. all its ideals are finitely generated. --/ +i.e. all its ideals are finitely generated. -/ abbrev IsNoetherianRing (R) [Semiring R] := IsNoetherian R R @@ -506,11 +444,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] @@ -519,16 +452,14 @@ instance (priority := 100) isNoetherian_of_subsingleton (R M) [Subsingleton R] [ isNoetherian_of_finite R M theorem isNoetherian_of_submodule_of_noetherian (R M) [Semiring R] [AddCommMonoid M] [Module R M] - (N : Submodule R M) (h : IsNoetherian R M) : IsNoetherian R N := by - rw [isNoetherian_iff_wellFounded] at h ⊢ - exact OrderEmbedding.wellFounded (Submodule.MapSubtype.orderEmbedding N).dual h + (N : Submodule R M) (h : IsNoetherian R M) : IsNoetherian R N := + isNoetherian_mk ⟨OrderEmbedding.wellFounded (Submodule.MapSubtype.orderEmbedding N).dual h.wf⟩ /-- If `M / S / R` is a scalar tower, and `M / R` is Noetherian, then `M / S` is also noetherian. -/ theorem isNoetherian_of_tower (R) {S M} [Semiring R] [Semiring S] [AddCommMonoid M] [SMul R S] - [Module S M] [Module R M] [IsScalarTower R S M] (h : IsNoetherian R M) : IsNoetherian S M := by - rw [isNoetherian_iff_wellFounded] at h ⊢ - exact (Submodule.restrictScalarsEmbedding R S M).dual.wellFounded h + [Module S M] [Module R M] [IsScalarTower R S M] (h : IsNoetherian R M) : IsNoetherian S M := + isNoetherian_mk ⟨(Submodule.restrictScalarsEmbedding R S M).dual.wellFounded h.wf⟩ theorem isNoetherian_of_fg_of_noetherian {R M} [Ring R] [AddCommGroup M] [Module R M] (N : Submodule R M) [I : IsNoetherianRing R] (hN : N.FG) : IsNoetherian R N := by @@ -555,12 +486,12 @@ theorem isNoetherian_of_fg_of_noetherian {R M} [Ring R] [AddCommGroup M] [Module · rw [LinearMap.range_eq_top] rintro ⟨n, hn⟩ change n ∈ N at hn - rw [← hs, ← Set.image_id (s : Set M), Finsupp.mem_span_image_iff_total] at hn + rw [← hs, ← Set.image_id (s : Set M), Finsupp.mem_span_image_iff_linearCombination] at hn rcases hn with ⟨l, hl1, hl2⟩ refine ⟨fun x => l x, Subtype.ext ?_⟩ change (∑ i ∈ s.attach, l i • (i : M)) = n rw [s.sum_attach fun i ↦ l i • i, ← hl2, - Finsupp.total_apply, Finsupp.sum, eq_comm] + Finsupp.linearCombination_apply, Finsupp.sum, eq_comm] refine Finset.sum_subset hl1 fun x _ hx => ?_ rw [Finsupp.not_mem_support_iff.1 hx, zero_smul] @@ -578,9 +509,8 @@ theorem isNoetherian_span_of_finite (R) {M} [Ring R] [AddCommGroup M] [Module R isNoetherian_of_fg_of_noetherian _ (Submodule.fg_def.mpr ⟨A, hA, rfl⟩) theorem isNoetherianRing_of_surjective (R) [Ring R] (S) [Ring S] (f : R →+* S) - (hf : Function.Surjective f) [H : IsNoetherianRing R] : IsNoetherianRing S := by - rw [isNoetherianRing_iff, isNoetherian_iff_wellFounded] at H ⊢ - exact OrderEmbedding.wellFounded (Ideal.orderEmbeddingOfSurjective f hf).dual H + (hf : Function.Surjective f) [H : IsNoetherianRing R] : IsNoetherianRing S := + isNoetherian_mk ⟨OrderEmbedding.wellFounded (Ideal.orderEmbeddingOfSurjective f hf).dual H.wf⟩ instance isNoetherianRing_range {R} [Ring R] {S} [Ring S] (f : R →+* S) [IsNoetherianRing R] : IsNoetherianRing f.range := diff --git a/Mathlib/RingTheory/NonUnitalSubring/Basic.lean b/Mathlib/RingTheory/NonUnitalSubring/Basic.lean index 0a1478bc862f1..f71dbda3f4e85 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 := @@ -743,7 +737,7 @@ theorem mem_closure_iff {s : Set R} {x} : mul_mem hx hy) (zero_mem _) (fun x y hx hy => add_mem hx hy) fun x hx => neg_mem hx⟩ -/-- If all elements of `s : Set A` commute pairwise, then `closure s` is a commutative ring. -/ +/-- 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 @@ -800,6 +794,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 +904,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 +971,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 +994,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..891e01b70140c 100644 --- a/Mathlib/RingTheory/NonUnitalSubsemiring/Basic.lean +++ b/Mathlib/RingTheory/NonUnitalSubsemiring/Basic.lean @@ -29,7 +29,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 +379,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 := @@ -670,6 +679,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..b7f2ce47f5c97 100644 --- a/Mathlib/RingTheory/Norm/Defs.lean +++ b/Mathlib/RingTheory/Norm/Defs.lean @@ -41,7 +41,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 diff --git a/Mathlib/RingTheory/OreLocalization/Ring.lean b/Mathlib/RingTheory/OreLocalization/Ring.lean index 952d2bd534a8f..2a911ebd37017 100644 --- a/Mathlib/RingTheory/OreLocalization/Ring.lean +++ b/Mathlib/RingTheory/OreLocalization/Ring.lean @@ -229,7 +229,7 @@ instance nontrivial : Nontrivial R[R⁰⁻¹] := variable [NoZeroDivisors R] open Classical in -/-- The inversion of Ore fractions for a ring without zero divisors, satisying `0⁻¹ = 0` and +/-- The inversion of Ore fractions for a ring without zero divisors, satisfying `0⁻¹ = 0` and `(r /ₒ r')⁻¹ = r' /ₒ r` for `r ≠ 0`. -/ @[irreducible] protected def inv : R[R⁰⁻¹] → R[R⁰⁻¹] := 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 f431e6d14be74..ab6d03ba20af2 100644 --- a/Mathlib/RingTheory/Polynomial/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Basic.lean @@ -173,6 +173,34 @@ theorem degreeLT_succ_eq_degreeLE {n : ℕ} : degreeLT R (n + 1) = degreeLE R n · rw [mem_degreeLT, mem_degreeLE, ← natDegree_lt_iff_degree_lt (by rwa [ne_eq]), ← natDegree_le_iff_degree_le, Nat.lt_succ] +/-- The equivalence between monic polynomials of degree `n` and polynomials of degree less than +`n`, formed by adding a term `X ^ n`. -/ +def monicEquivDegreeLT [Nontrivial R] (n : ℕ) : + { p : R[X] // p.Monic ∧ p.natDegree = n } ≃ degreeLT R n where + toFun p := ⟨p.1.eraseLead, by + rcases p with ⟨p, hp, rfl⟩ + simp only [mem_degreeLT] + refine lt_of_lt_of_le ?_ degree_le_natDegree + exact degree_eraseLead_lt (ne_zero_of_ne_zero_of_monic one_ne_zero hp)⟩ + invFun := fun p => + ⟨X^n + p.1, monic_X_pow_add (mem_degreeLT.1 p.2), by + rw [natDegree_add_eq_left_of_degree_lt] + · simp + · simp [mem_degreeLT.1 p.2]⟩ + left_inv := by + rintro ⟨p, hp, rfl⟩ + ext1 + simp only + conv_rhs => rw [← eraseLead_add_C_mul_X_pow p] + simp [Monic.def.1 hp, add_comm] + right_inv := by + rintro ⟨p, hp⟩ + ext1 + simp only + rw [eraseLead_add_of_degree_lt_left] + · simp + · simp [mem_degreeLT.1 hp] + /-- For every polynomial `p` in the span of a set `s : Set R[X]`, there exists a polynomial of `p' ∈ s` with higher degree. See also `Polynomial.exists_degree_le_of_mem_span_of_finite`. -/ theorem exists_degree_le_of_mem_span {s : Set R[X]} {p : R[X]} @@ -219,7 +247,7 @@ theorem span_of_finite_le_degreeLT {s : Set R[X]} (s_fin : s.Finite) : exact ⟨n + 1, by rwa [degreeLT_succ_eq_degreeLE]⟩ /-- If `R` is a nontrivial ring, the polynomials `R[X]` are not finite as an `R`-module. When `R` is -a field, this is equivalent to `R[X]` being an infinite-dimensional vector space over `R`. -/ +a field, this is equivalent to `R[X]` being an infinite-dimensional vector space over `R`. -/ theorem not_finite [Nontrivial R] : ¬ Module.Finite R R[X] := by rw [Module.finite_def, Submodule.fg_def] push_neg @@ -238,6 +266,7 @@ def coeffs (p : R[X]) : Finset R := @[deprecated (since := "2024-05-17")] noncomputable alias frange := coeffs +@[simp] theorem coeffs_zero : coeffs (0 : R[X]) = ∅ := rfl @@ -262,6 +291,10 @@ theorem coeff_mem_coeffs (p : R[X]) (n : ℕ) (h : p.coeff n ≠ 0) : p.coeff n @[deprecated (since := "2024-05-17")] alias coeff_mem_frange := coeff_mem_coeffs +theorem coeffs_monomial (n : ℕ) {c : R} (hc : c ≠ 0) : (monomial n c).coeffs = {c} := by + rw [coeffs, support_monomial n hc] + simp + theorem geom_sum_X_comp_X_add_one_eq_sum (n : ℕ) : (∑ i ∈ range n, (X : R[X]) ^ i).comp (X + 1) = (Finset.range n).sum fun i : ℕ => (n.choose (i + 1) : R[X]) * X ^ i := by @@ -572,8 +605,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]) @@ -724,8 +756,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) @@ -840,14 +871,14 @@ namespace Polynomial instance (priority := 100) wfDvdMonoid {R : Type*} [CommRing R] [IsDomain R] [WfDvdMonoid R] : WfDvdMonoid R[X] where - wellFounded_dvdNotUnit := by + wf := by classical refine RelHomClass.wellFounded (⟨fun p : R[X] => ((if p = 0 then ⊤ else ↑p.degree : WithTop (WithBot ℕ)), p.leadingCoeff), ?_⟩ : DvdNotUnit →r Prod.Lex (· < ·) DvdNotUnit) - (wellFounded_lt.prod_lex ‹WfDvdMonoid R›.wellFounded_dvdNotUnit) + (wellFounded_lt.prod_lex ‹WfDvdMonoid R›.wf) rintro a b ⟨ane0, ⟨c, ⟨not_unit_c, rfl⟩⟩⟩ dsimp rw [Polynomial.degree_mul, if_neg ane0] @@ -876,9 +907,7 @@ end Polynomial protected theorem Polynomial.isNoetherianRing [inst : IsNoetherianRing R] : IsNoetherianRing R[X] := isNoetherianRing_iff.2 ⟨fun I : Ideal R[X] => - let M := - WellFounded.min (isNoetherian_iff_wellFounded.1 (by infer_instance)) - (Set.range I.leadingCoeffNth) ⟨_, ⟨0, rfl⟩⟩ + let M := inst.wf.min (Set.range I.leadingCoeffNth) ⟨_, ⟨0, rfl⟩⟩ have hm : M ∈ Set.range I.leadingCoeffNth := WellFounded.min_mem _ _ _ let ⟨N, HN⟩ := hm let ⟨s, hs⟩ := I.is_fg_degreeLE N @@ -887,7 +916,7 @@ protected theorem Polynomial.isNoetherianRing [inst : IsNoetherianRing R] : IsNo Classical.by_contradiction fun hxm => haveI : IsNoetherian R R := inst have : ¬M < I.leadingCoeffNth k := by - refine WellFounded.not_lt_min (wellFounded_submodule_gt R R) _ _ ?_; exact ⟨k, rfl⟩ + refine WellFounded.not_lt_min inst.wf _ _ ?_; exact ⟨k, rfl⟩ 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 => @@ -970,8 +999,8 @@ theorem exists_irreducible_of_natDegree_ne_zero {R : Type u} [CommRing R] [IsDom theorem linearIndependent_powers_iff_aeval (f : M →ₗ[R] M) (v : M) : (LinearIndependent R fun n : ℕ => (f ^ n) v) ↔ ∀ p : R[X], aeval f p v = 0 → p = 0 := by rw [linearIndependent_iff] - simp only [Finsupp.total_apply, aeval_endomorphism, forall_iff_forall_finsupp, Sum, support, - coeff, ofFinsupp_eq_zero] + simp only [Finsupp.linearCombination_apply, aeval_endomorphism, forall_iff_forall_finsupp, Sum, + support, coeff, ofFinsupp_eq_zero] exact Iff.rfl attribute [-instance] Ring.toNonAssocRing @@ -1185,6 +1214,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 af0d3936dd937..8cae9a4f38a0d 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 @@ -87,7 +87,7 @@ theorem eval_at_1 (n ν : ℕ) : (bernsteinPolynomial R n ν).eval 1 = if ν = n split_ifs with h · subst h; simp · obtain hνn | hnν := Ne.lt_or_lt h - · simp [zero_pow $ Nat.sub_ne_zero_of_lt hνn] + · simp [zero_pow <| Nat.sub_ne_zero_of_lt hνn] · simp [Nat.choose_eq_zero_of_lt hnν] theorem derivative_succ_aux (n ν : ℕ) : diff --git a/Mathlib/RingTheory/Polynomial/Content.lean b/Mathlib/RingTheory/Polynomial/Content.lean index 273f4f4ba8827..c92ff552d810e 100644 --- a/Mathlib/RingTheory/Polynomial/Content.lean +++ b/Mathlib/RingTheory/Polynomial/Content.lean @@ -207,7 +207,7 @@ theorem IsPrimitive.content_eq_one {p : R[X]} (hp : p.IsPrimitive) : p.content = section PrimPart /-- The primitive part of a polynomial `p` is the primitive polynomial gained by dividing `p` by - `p.content`. If `p = 0`, then `p.primPart = 1`. -/ + `p.content`. If `p = 0`, then `p.primPart = 1`. -/ noncomputable def primPart (p : R[X]) : R[X] := letI := Classical.decEq R if p = 0 then 1 else Classical.choose (C_content_dvd p) diff --git a/Mathlib/RingTheory/Polynomial/Cyclotomic/Eval.lean b/Mathlib/RingTheory/Polynomial/Cyclotomic/Eval.lean index cdd1003e5f3ad..4a1ad15664ee8 100644 --- a/Mathlib/RingTheory/Polynomial/Cyclotomic/Eval.lean +++ b/Mathlib/RingTheory/Polynomial/Cyclotomic/Eval.lean @@ -6,7 +6,7 @@ Authors: Eric Rodriguez import Mathlib.RingTheory.Polynomial.Cyclotomic.Roots import Mathlib.Tactic.ByContra import Mathlib.Topology.Algebra.Polynomial -import Mathlib.NumberTheory.Padics.PadicVal +import Mathlib.NumberTheory.Padics.PadicVal.Basic import Mathlib.Analysis.Complex.Arg /-! @@ -80,7 +80,7 @@ theorem cyclotomic_pos {n : ℕ} (hn : 2 < n) {R} [LinearOrderedCommRing R] (x : cases' h with hk hx · refine (ih _ hi.2.2 (Nat.two_lt_of_ne ?_ hi.1 ?_)).le <;> rintro rfl · exact hn'.ne' (zero_dvd_iff.mp hi.2.1) - · exact even_iff_not_odd.mp (even_iff_two_dvd.mpr hi.2.1) hk + · exact not_odd_iff_even.2 (even_iff_two_dvd.mpr hi.2.1) hk · rcases eq_or_ne i 2 with (rfl | hk) · simpa only [eval_X, eval_one, cyclotomic_two, eval_add] using hx.le refine (ih _ hi.2.2 (Nat.two_lt_of_ne ?_ hi.1 hk)).le @@ -147,7 +147,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 +203,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 diff --git a/Mathlib/RingTheory/Polynomial/Cyclotomic/Expand.lean b/Mathlib/RingTheory/Polynomial/Cyclotomic/Expand.lean index 7995fdbf7fc85..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`. @@ -167,7 +167,7 @@ theorem isRoot_cyclotomic_prime_pow_mul_iff_of_charP {m k p : ℕ} {R : Type*} [ · rw [← isRoot_cyclotomic_iff, IsRoot.def] at h rw [cyclotomic_mul_prime_pow_eq R (NeZero.not_char_dvd R p m) hk, IsRoot.def, eval_pow, h, zero_pow] - exact Nat.sub_ne_zero_of_lt $ pow_right_strictMono hp.out.one_lt $ Nat.pred_lt hk.ne' + exact Nat.sub_ne_zero_of_lt <| pow_right_strictMono hp.out.one_lt <| Nat.pred_lt hk.ne' end CharP diff --git a/Mathlib/RingTheory/Polynomial/Cyclotomic/Roots.lean b/Mathlib/RingTheory/Polynomial/Cyclotomic/Roots.lean index ac741208832d2..74c4705dddc41 100644 --- a/Mathlib/RingTheory/Polynomial/Cyclotomic/Roots.lean +++ b/Mathlib/RingTheory/Polynomial/Cyclotomic/Roots.lean @@ -113,7 +113,7 @@ theorem cyclotomic.roots_to_finset_eq_primitiveRoots [NeZero (n : R)] : -- `simp [cyclotomic_ne_zero n R, isRoot_cyclotomic_iff, mem_primitiveRoots,` -- ` NeZero.pos_of_neZero_natCast R]` simp only [mem_primitiveRoots, NeZero.pos_of_neZero_natCast R] - convert isRoot_cyclotomic_iff (n := n) (μ := a) + convert isRoot_cyclotomic_iff (n := n) (μ := a) using 0 simp [cyclotomic_ne_zero n R] theorem cyclotomic.roots_eq_primitiveRoots_val [NeZero (n : R)] : diff --git a/Mathlib/RingTheory/Polynomial/Dickson.lean b/Mathlib/RingTheory/Polynomial/Dickson.lean index 6f3bfc0a478bf..fdb6b3b533b34 100644 --- a/Mathlib/RingTheory/Polynomial/Dickson.lean +++ b/Mathlib/RingTheory/Polynomial/Dickson.lean @@ -231,7 +231,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 +241,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 50e6698cdb932..6365d391b724f 100644 --- a/Mathlib/RingTheory/Polynomial/Eisenstein/IsIntegral.lean +++ b/Mathlib/RingTheory/Polynomial/Eisenstein/IsIntegral.lean @@ -53,6 +53,8 @@ theorem cyclotomic_comp_X_add_one_isEisensteinAt [hp : Fact p.Prime] : congr congr next => skip + congr + next => skip ext rw [lcoeff_apply, ← C_eq_natCast, C_mul_X_pow_eq_monomial, coeff_monomial] rw [natDegree_comp, show (X + 1 : ℤ[X]) = X + C 1 by simp, natDegree_X_add_C, mul_one, @@ -135,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/GaussLemma.lean b/Mathlib/RingTheory/Polynomial/GaussLemma.lean index ca29983d56934..1d03f572b1ea9 100644 --- a/Mathlib/RingTheory/Polynomial/GaussLemma.lean +++ b/Mathlib/RingTheory/Polynomial/GaussLemma.lean @@ -143,7 +143,7 @@ open IsIntegrallyClosed theorem Monic.irreducible_iff_irreducible_map_fraction_map [IsIntegrallyClosed R] {p : R[X]} (h : p.Monic) : Irreducible p ↔ Irreducible (p.map <| algebraMap R K) := by /- The ← direction follows from `IsPrimitive.irreducible_of_irreducible_map_of_injective`. - For the → direction, it is enought to show that if `(p.map <| algebraMap R K) = a * b` and + For the → direction, it is enough to show that if `(p.map <| algebraMap R K) = a * b` and `a` is not a unit then `b` is a unit -/ refine ⟨fun hp => diff --git a/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean b/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean index a4a78d9406f1c..6f7d2d23edce3 100644 --- a/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Hermite/Basic.lean @@ -116,7 +116,7 @@ theorem hermite_monic (n : ℕ) : (hermite n).Monic := leadingCoeff_hermite n theorem coeff_hermite_of_odd_add {n k : ℕ} (hnk : Odd (n + k)) : coeff (hermite n) k = 0 := by - induction n generalizing k with + induction n generalizing k with | zero => rw [zero_add k] at hnk exact coeff_hermite_of_lt hnk.pos @@ -197,7 +197,7 @@ theorem coeff_hermite (n k : ℕ) : if Even (n + k) then (-1 : ℤ) ^ ((n - k) / 2) * (n - k - 1)‼ * Nat.choose n k else 0 := by split_ifs with h · exact coeff_hermite_of_even_add h - · exact coeff_hermite_of_odd_add (Nat.odd_iff_not_even.mpr h) + · exact coeff_hermite_of_odd_add (Nat.not_even_iff_odd.1 h) end CoeffExplicit 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/Pochhammer.lean b/Mathlib/RingTheory/Polynomial/Pochhammer.lean index 63e7f8d15a3bd..a96e49ebd3495 100644 --- a/Mathlib/RingTheory/Polynomial/Pochhammer.lean +++ b/Mathlib/RingTheory/Polynomial/Pochhammer.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.Degree.Definitions import Mathlib.Algebra.Polynomial.Eval @@ -178,7 +178,7 @@ variable {S : Type*} [StrictOrderedSemiring S] theorem ascPochhammer_pos (n : ℕ) (s : S) (h : 0 < s) : 0 < (ascPochhammer S n).eval s := by induction n with | zero => - simp only [Nat.zero_eq, ascPochhammer_zero, eval_one] + simp only [ascPochhammer_zero, eval_one] exact zero_lt_one | succ n ih => rw [ascPochhammer_succ_right, mul_add, eval_add, ← Nat.cast_comm, eval_natCast_mul, eval_mul_X, diff --git a/Mathlib/RingTheory/Polynomial/Quotient.lean b/Mathlib/RingTheory/Polynomial/Quotient.lean index 1f6608a4850b7..6d9f4b7aa653f 100644 --- a/Mathlib/RingTheory/Polynomial/Quotient.lean +++ b/Mathlib/RingTheory/Polynomial/Quotient.lean @@ -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/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..6ad52b3eb26ac 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 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 ce69b35f56744..a9cf86b0049c1 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 @@ -40,9 +40,7 @@ power basis, powerbasis -/ -open Polynomial - -open Polynomial +open Polynomial Finsupp variable {R S T : Type*} [CommRing R] [Ring S] [Algebra R S] variable {A B : Type*} [CommRing A] [CommRing B] [Algebra A B] @@ -79,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 : ℕ)) ↔ @@ -89,9 +87,9 @@ theorem mem_span_pow' {x y : S} {d : ℕ} : ext n simp_rw [Set.mem_range, Set.mem_image, Finset.mem_coe, Finset.mem_range] exact ⟨fun ⟨⟨i, hi⟩, hy⟩ => ⟨i, hi, hy⟩, fun ⟨i, hi, hy⟩ => ⟨⟨i, hi⟩, hy⟩⟩ - simp only [this, Finsupp.mem_span_image_iff_total, degree_lt_iff_coeff_zero, support, + simp only [this, mem_span_image_iff_linearCombination, degree_lt_iff_coeff_zero, Finsupp.support, exists_iff_exists_finsupp, coeff, aeval_def, eval₂RingHom', eval₂_eq_sum, Polynomial.sum, - Finsupp.mem_supported', Finsupp.total, Finsupp.sum, Algebra.smul_def, eval₂_zero, exists_prop, + mem_supported', linearCombination, Finsupp.sum, Algebra.smul_def, eval₂_zero, exists_prop, LinearMap.id_coe, eval₂_one, id, not_lt, Finsupp.coe_lsum, LinearMap.coe_smulRight, Finset.mem_range, AlgHom.coe_mks, Finset.mem_coe] simp_rw [@eq_comm _ y] @@ -164,8 +162,8 @@ noncomputable def minpolyGen (pb : PowerBasis A S) : A[X] := theorem aeval_minpolyGen (pb : PowerBasis A S) : aeval pb.gen (minpolyGen pb) = 0 := by simp_rw [minpolyGen, map_sub, map_sum, map_mul, map_pow, aeval_C, ← Algebra.smul_def, aeval_X] - refine sub_eq_zero.mpr ((pb.basis.total_repr (pb.gen ^ pb.dim)).symm.trans ?_) - rw [Finsupp.total_apply, Finsupp.sum_fintype] <;> + refine sub_eq_zero.mpr ((pb.basis.linearCombination_repr (pb.gen ^ pb.dim)).symm.trans ?_) + rw [Finsupp.linearCombination_apply, Finsupp.sum_fintype] <;> simp only [pb.coe_basis, zero_smul, eq_self_iff_true, imp_true_iff] theorem minpolyGen_monic (pb : PowerBasis A S) : Monic (minpolyGen pb) := by diff --git a/Mathlib/RingTheory/PowerSeries/Basic.lean b/Mathlib/RingTheory/PowerSeries/Basic.lean index b16ab068c4441..bae1dcd02e069 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] @@ -415,7 +415,7 @@ theorem isUnit_constantCoeff (φ : R⟦X⟧) (h : IsUnit φ) : IsUnit (constantC theorem eq_shift_mul_X_add_const (φ : R⟦X⟧) : φ = (mk fun p => coeff R (p + 1) φ) * X + C R (constantCoeff R φ) := by ext (_ | n) - · simp only [Nat.zero_eq, coeff_zero_eq_constantCoeff, map_add, map_mul, constantCoeff_X, + · simp only [coeff_zero_eq_constantCoeff, map_add, map_mul, constantCoeff_X, mul_zero, coeff_zero_C, zero_add] · simp only [coeff_succ_mul_X, coeff_mk, LinearMap.map_add, coeff_C, n.succ_ne_zero, sub_zero, if_false, add_zero] @@ -424,7 +424,7 @@ theorem eq_shift_mul_X_add_const (φ : R⟦X⟧) : theorem eq_X_mul_shift_add_const (φ : R⟦X⟧) : φ = (X * mk fun p => coeff R (p + 1) φ) + C R (constantCoeff R φ) := by ext (_ | n) - · simp only [Nat.zero_eq, coeff_zero_eq_constantCoeff, map_add, map_mul, constantCoeff_X, + · simp only [coeff_zero_eq_constantCoeff, map_add, map_mul, constantCoeff_X, zero_mul, coeff_zero_C, zero_add] · simp only [coeff_succ_X_mul, coeff_mk, LinearMap.map_add, coeff_C, n.succ_ne_zero, sub_zero, if_false, add_zero] @@ -603,14 +603,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 diff --git a/Mathlib/RingTheory/PowerSeries/Inverse.lean b/Mathlib/RingTheory/PowerSeries/Inverse.lean index a8d96e7a4b2ac..b08f4125a38a0 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 diff --git a/Mathlib/RingTheory/PowerSeries/Order.lean b/Mathlib/RingTheory/PowerSeries/Order.lean index f73b2bb21d977..cec9d16a7d726 100644 --- a/Mathlib/RingTheory/PowerSeries/Order.lean +++ b/Mathlib/RingTheory/PowerSeries/Order.lean @@ -272,7 +272,7 @@ theorem order_eq_multiplicity_X {R : Type*} [Semiring R] [@DecidableRel R⟦X⟧ 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-/ + dividing out the largest power of X that divides `f`, that is its order -/ def divided_by_X_pow_order {f : PowerSeries R} (hf : f ≠ 0) : R⟦X⟧ := (exists_eq_mul_right_of_dvd (X_pow_order_dvd (order_finite_iff_ne_zero.2 hf))).choose diff --git a/Mathlib/RingTheory/Presentation.lean b/Mathlib/RingTheory/Presentation.lean index 3212414414659..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 @@ -56,7 +55,7 @@ each relation to a polynomial in the generators. -/ @[nolint checkUnivs] structure Algebra.Presentation extends Algebra.Generators.{w} R S where - /-- The type of relations. -/ + /-- The type of relations. -/ rels : Type t /-- The assignment of each relation to a polynomial in the generators. -/ relation : rels → toGenerators.Ring @@ -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,26 +236,25 @@ 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, _root_.map_one, algebraMap_eq] + TensorProduct.map_tmul, AlgHom.coe_id, id_eq, map_one, algebraMap_eq] erw [aeval_C] simp | h_add p q hp hq => simp only [map_add, hp, hq] | h_X p i hp => - simp only [_root_.map_mul, algebraTensorAlgEquiv_symm_X, hp, TensorProduct.map_tmul, - _root_.map_one, IsScalarTower.coe_toAlgHom', Generators.algebraMap_apply, aeval_X, e] + simp only [map_mul, algebraTensorAlgEquiv_symm_X, hp, TensorProduct.map_tmul, map_one, + IsScalarTower.coe_toAlgHom', Generators.algebraMap_apply, aeval_X, e] 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' convert H' simp only [AlgHom.toRingHom_eq_coe, RingHom.coe_comp, RingHom.coe_coe, Function.comp_apply, - TensorProduct.includeRight_apply, TensorProduct.lift_tmul, _root_.map_one, mapAlgHom_apply, - one_mul] + TensorProduct.includeRight_apply, TensorProduct.lift_tmul, map_one, mapAlgHom_apply, one_mul] rfl /-- If `P` is a presentation of `S` over `R` and `T` is an `R`-algebra, we @@ -228,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/PrimeSpectrum.lean b/Mathlib/RingTheory/PrimeSpectrum.lean index e42c803e3eef2..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 @@ -40,7 +41,7 @@ and Chris Hughes (on an earlier repository). -/ -- A dividing line between this file and `AlgebraicGeometry.PrimeSpectrum.Basic` is --- that we should not depened on the Zariski topology here +-- that we should not depend on the Zariski topology here assert_not_exists TopologicalSpace noncomputable section @@ -186,7 +187,7 @@ theorem gc_set : @GaloisConnection (Set R) (Set (PrimeSpectrum R))ᵒᵈ _ _ (fun s => zeroLocus s) fun t => vanishingIdeal t := by have ideal_gc : GaloisConnection Ideal.span _ := (Submodule.gi R R).gc - simpa [zeroLocus_span, Function.comp] using ideal_gc.compose (gc R) + simpa [zeroLocus_span, Function.comp_def] using ideal_gc.compose (gc R) theorem subset_zeroLocus_iff_subset_vanishingIdeal (t : Set (PrimeSpectrum R)) (s : Set R) : t ⊆ zeroLocus s ↔ s ⊆ vanishingIdeal t := @@ -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 29bea641d71f3..40c180a84813b 100644 --- a/Mathlib/RingTheory/PrincipalIdealDomain.lean +++ b/Mathlib/RingTheory/PrincipalIdealDomain.lean @@ -92,8 +92,9 @@ theorem _root_.Ideal.span_singleton_generator (I : Ideal R) [I.IsPrincipal] : @[simp] theorem generator_mem (S : Submodule R M) [S.IsPrincipal] : generator S ∈ S := by - conv_rhs => rw [← span_singleton_generator S] - exact subset_span (mem_singleton _) + have : generator S ∈ span R {generator S} := subset_span (mem_singleton _) + convert this + exact span_singleton_generator S |>.symm theorem mem_iff_eq_smul_generator (S : Submodule R M) [S.IsPrincipal] {x : M} : x ∈ S ↔ ∃ s : R, x = s • generator S := by diff --git a/Mathlib/RingTheory/Radical.lean b/Mathlib/RingTheory/Radical.lean new file mode 100644 index 0000000000000..c86cee4872a46 --- /dev/null +++ b/Mathlib/RingTheory/Radical.lean @@ -0,0 +1,107 @@ +/- +Copyright (c) 2024 Jineon Baek, Seewoo Lee. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jineon Baek, Seewoo Lee +-/ +import Mathlib.RingTheory.UniqueFactorizationDomain + +/-! +# Radical of an element of a unique factorization normalization monoid + +This file defines a radical of an element `a` of a unique factorization normalization +monoid, which is defined as a product of normalized prime factors of `a` without duplication. +This is different from the radical of an ideal. + +## Main declarations + +- `radical`: The radical of an element `a` in a unique factorization monoid is the product of + its prime factors. +- `radical_eq_of_associated`: If `a` and `b` are associates, i.e. `a * u = b` for some unit `u`, + then `radical a = radical b`. +- `radical_unit_mul`: Multiplying unit does not change the radical. +- `radical_dvd_self`: `radical a` divides `a`. +- `radical_pow`: `radical (a ^ n) = radical a` for any `n ≥ 1` +- `radical_of_prime`: Radical of a prime element is equal to its normalization +- `radical_pow_of_prime`: Radical of a power of prime element is equal to its normalization + +## TODO + +- Make a comparison with `Ideal.radical`. Especially, for principal ideal, + `Ideal.radical (Ideal.span {a}) = Ideal.span {radical a}`. +- Prove `radical (radical a) = radical a`. +- Prove a comparison between `primeFactors` and `Nat.primeFactors`. +-/ + +noncomputable section + +open scoped Classical + +namespace UniqueFactorizationMonoid + +-- `CancelCommMonoidWithZero` is required by `UniqueFactorizationMonoid` +variable {M : Type*} [CancelCommMonoidWithZero M] [NormalizationMonoid M] + [UniqueFactorizationMonoid M] + +/-- The finite set of prime factors of an element in a unique factorization monoid. -/ +def primeFactors (a : M) : Finset M := + (normalizedFactors a).toFinset + +/-- +Radical of an element `a` in a unique factorization monoid is the product of +the prime factors of `a`. +-/ +def radical (a : M) : M := + (primeFactors a).prod id + +@[simp] +theorem radical_zero_eq : radical (0 : M) = 1 := by + rw [radical, primeFactors, normalizedFactors_zero, Multiset.toFinset_zero, Finset.prod_empty] + +@[simp] +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] + +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 + +theorem radical_unit_mul {u : Mˣ} {a : M} : radical ((↑u : M) * a) = radical a := + radical_eq_of_associated (associated_unit_mul_left _ _ u.isUnit) + +theorem radical_mul_unit {u : Mˣ} {a : M} : radical (a * (↑u : M)) = radical a := + radical_eq_of_associated (associated_mul_unit_left _ _ u.isUnit) + +theorem primeFactors_pow (a : M) {n : ℕ} (hn : 0 < n) : primeFactors (a ^ n) = primeFactors a := by + simp_rw [primeFactors] + simp only [normalizedFactors_pow] + rw [Multiset.toFinset_nsmul] + exact ne_of_gt hn + +theorem radical_pow (a : M) {n : Nat} (hn : 0 < n) : radical (a ^ n) = radical a := by + simp_rw [radical, primeFactors_pow a hn] + +theorem radical_dvd_self (a : M) : radical a ∣ a := by + by_cases ha : a = 0 + · rw [ha] + apply dvd_zero + · rw [radical, ← Finset.prod_val, ← (normalizedFactors_prod ha).dvd_iff_dvd_right] + apply Multiset.prod_dvd_prod_of_le + rw [primeFactors, Multiset.toFinset_val] + apply Multiset.dedup_le + +theorem radical_of_prime {a : M} (ha : Prime a) : radical a = normalize a := by + rw [radical, primeFactors] + rw [normalizedFactors_irreducible ha.irreducible] + simp only [Multiset.toFinset_singleton, id, Finset.prod_singleton] + +theorem radical_pow_of_prime {a : M} (ha : Prime a) {n : ℕ} (hn : 0 < n) : + radical (a ^ n) = normalize a := by + rw [radical_pow a hn] + exact radical_of_prime ha + +end UniqueFactorizationMonoid diff --git a/Mathlib/RingTheory/Regular/IsSMulRegular.lean b/Mathlib/RingTheory/Regular/IsSMulRegular.lean index 34012a4084c2b..efe4d52d7cef9 100644 --- a/Mathlib/RingTheory/Regular/IsSMulRegular.lean +++ b/Mathlib/RingTheory/Regular/IsSMulRegular.lean @@ -96,7 +96,7 @@ lemma isSMulRegular_on_submodule_iff_mem_imp_smul_eq_zero_imp_eq_zero : IsSMulRegular N r ↔ ∀ x ∈ N, r • x = 0 → x = 0 := Iff.trans (isSMulRegular_iff_smul_eq_zero_imp_eq_zero N r) <| Iff.trans Subtype.forall <| by - simp only [SetLike.mk_smul_mk, AddSubmonoid.mk_eq_zero] + simp only [SetLike.mk_smul_mk, Submodule.mk_eq_zero] lemma isSMulRegular_on_quot_iff_smul_mem_implies_mem : IsSMulRegular (M ⧸ N) r ↔ ∀ x : M, r • x ∈ N → x ∈ N := diff --git a/Mathlib/RingTheory/Regular/RegularSequence.lean b/Mathlib/RingTheory/Regular/RegularSequence.lean index 6da2991f4d4ca..a1e81fdf08b75 100644 --- a/Mathlib/RingTheory/Regular/RegularSequence.lean +++ b/Mathlib/RingTheory/Regular/RegularSequence.lean @@ -45,7 +45,7 @@ abbrev ofList (rs : List R) := span { r | r ∈ rs } have : { r | r ∈ rs₁ ++ rs₂ } = _ := Set.ext (fun _ => List.mem_append) Eq.trans (congrArg span this) (span_union _ _) -@[simp] lemma ofList_singleton (r : R) : ofList [r] = span {r} := +lemma ofList_singleton (r : R) : ofList [r] = span {r} := congrArg span (Set.ext fun _ => List.mem_singleton) @[simp] lemma ofList_cons (r : R) (rs : List R) : @@ -232,7 +232,7 @@ lemma isWeaklyRegular_cons_iff (r : R) (rs : List R) : IsSMulRegular M r ∧ IsWeaklyRegular (QuotSMulTop r M) rs := have := Eq.trans (congrArg (· • ⊤) Ideal.ofList_nil) (bot_smul ⊤) let e i := quotOfListConsSMulTopEquivQuotSMulTopInner M r (rs.take i) - Iff.trans (isWeaklyRegular_iff_Fin _ _) <| Iff.trans Fin.forall_fin_succ <| + Iff.trans (isWeaklyRegular_iff_Fin _ _) <| Iff.trans Fin.forall_iff_succ <| and_congr ((quotEquivOfEqBot _ this).isSMulRegular_congr r) <| Iff.trans (forall_congr' fun i => (e i).isSMulRegular_congr (rs.get i)) (isWeaklyRegular_iff_Fin _ _).symm @@ -316,7 +316,7 @@ def ndrecIterModByRegular /-- An alternate induction principle from `IsWeaklyRegular.recIterModByRegular` where we mod out by successive elements in both the module and the base ring. -This is useful for propogating certain properties of the initial `M`, e.g. +This is useful for propagating certain properties of the initial `M`, e.g. faithfulness or freeness, throughout the induction. -/ def recIterModByRegularWithRing {motive : (R : Type u) → [CommRing R] → (M : Type v) → [AddCommGroup M] → @@ -447,7 +447,7 @@ def ndrecIterModByRegular /-- An alternate induction principle from `IsRegular.recIterModByRegular` where we mod out by successive elements in both the module and the base ring. This is -useful for propogating certain properties of the initial `M`, e.g. faithfulness +useful for propagating certain properties of the initial `M`, e.g. faithfulness or freeness, throughout the induction. -/ def recIterModByRegularWithRing {motive : (R : Type u) → [CommRing R] → (M : Type v) → [AddCommGroup M] → @@ -555,12 +555,14 @@ lemma map_first_exact_on_four_term_right_exact_of_isSMulRegular_last (h₄ : IsWeaklyRegular M₄ rs) : Exact (mapQ _ _ _ (smul_top_le_comap_smul_top (Ideal.ofList rs) f₁)) (mapQ _ _ _ (smul_top_le_comap_smul_top (Ideal.ofList rs) f₂)) := by - induction' h₄ with _ _ _ N _ _ r rs h₄ _ ih generalizing M M₂ M₃ - · apply (Exact.iff_of_ladder_linearEquiv ?_ ?_).mp h₁₂ + induction h₄ generalizing M M₂ M₃ with + | nil => + apply (Exact.iff_of_ladder_linearEquiv ?_ ?_).mp h₁₂ any_goals exact quotEquivOfEqBot _ <| Eq.trans (congrArg (· • ⊤) Ideal.ofList_nil) (bot_smul ⊤) all_goals exact quot_hom_ext _ _ _ fun _ => rfl - · specialize ih + | cons r rs h₄ _ ih => + specialize ih (map_first_exact_on_four_term_exact_of_isSMulRegular_last h₁₂ h₂₃ h₄) (map_exact r h₂₃ h₃) (map_surjective r h₃) have H₁ := quotOfListConsSMulTopEquivQuotSMulTopInner_naturality r rs f₁ 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 21b4cbcffb892..ad4ae18aa6419 100644 --- a/Mathlib/RingTheory/RingHom/FinitePresentation.lean +++ b/Mathlib/RingTheory/RingHom/FinitePresentation.lean @@ -113,7 +113,7 @@ theorem finitePresentation_ofLocalizationSpanTarget : · infer_instance rw [RingHom.FinitePresentation] obtain ⟨n, f, hf⟩ := Algebra.FiniteType.iff_quotient_mvPolynomial''.mp hfintype - obtain ⟨l, hl⟩ := (Finsupp.mem_span_iff_total S (s : Set S) 1).mp + obtain ⟨l, hl⟩ := (Finsupp.mem_span_iff_linearCombination S (s : Set S) 1).mp (show (1 : S) ∈ Ideal.span (s : Set S) by rw [hs]; trivial) choose g' hg' using (fun g : s ↦ hf g) choose h' hh' using (fun g : s ↦ hf (l g)) @@ -124,7 +124,7 @@ theorem finitePresentation_ofLocalizationSpanTarget : simp only [Finset.univ_eq_attach, I, Ideal.mem_span_singleton] at hp obtain ⟨q, rfl⟩ := hp simp only [map_mul, map_sub, map_sum, map_one, hg', hh'] - erw [Finsupp.total_apply_of_mem_supported S (s := s.attach)] at hl + erw [Finsupp.linearCombination_apply_of_mem_supported S (s := s.attach)] at hl · rw [← hl] simp only [Finset.coe_sort_coe, smul_eq_mul, mul_comm, sub_self, mul_zero, zero_mul] · rintro a - @@ -149,7 +149,9 @@ theorem finitePresentation_ofLocalizationSpanTarget : exact ⟨{∑ g ∈ s.attach, g' g * h' g - 1}, by simp⟩ have Ht (g : t) : Algebra.FinitePresentation R (Localization.Away (f' g)) := by have : ∃ (a : S) (hb : a ∈ s), (Ideal.Quotient.mk I) (g' ⟨a, hb⟩) = g.val := by - simpa [t] using g.property + obtain ⟨g, hg⟩ := g + convert hg + simp [t] obtain ⟨r, hr, hrr⟩ := this simp only [f'] rw [← hrr, Ideal.Quotient.liftₐ_apply, Ideal.Quotient.lift_mk] @@ -161,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 7d6e84d24484f..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 @@ -33,7 +161,7 @@ theorem finiteType_holdsForLocalizationAway : HoldsForLocalizationAway @FiniteTy exact IsLocalization.finiteType_of_monoid_fg (Submonoid.powers r) S theorem finiteType_ofLocalizationSpanTarget : OfLocalizationSpanTarget @FiniteType := by - -- Setup algebra intances. + -- Setup algebra instances. rw [ofLocalizationSpanTarget_iff_finite] introv R hs H classical @@ -47,7 +175,7 @@ theorem finiteType_ofLocalizationSpanTarget : OfLocalizationSpanTarget @FiniteTy -- `∑ lᵢ * sᵢ = 1`. I claim that all `s` and `l` and the numerators of `t` and generates `S`. choose t ht using H obtain ⟨l, hl⟩ := - (Finsupp.mem_span_iff_total S (s : Set S) 1).mp + (Finsupp.mem_span_iff_linearCombination S (s : Set S) 1).mp (show (1 : S) ∈ Ideal.span (s : Set S) by rw [hs]; trivial) let sf := fun x : s => IsLocalization.finsetIntegerMultiple (Submonoid.powers (x : S)) (t x) use s.attach.biUnion sf ∪ s ∪ l.support.image l @@ -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..fc54b147cef5b --- /dev/null +++ b/Mathlib/RingTheory/RingHom/Locally.lean @@ -0,0 +1,146 @@ +/- +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.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. + +-/ + +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 + +end RingHom diff --git a/Mathlib/RingTheory/RingHom/Surjective.lean b/Mathlib/RingTheory/RingHom/Surjective.lean index 732f8377e880b..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_total 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/RootsOfUnity/Basic.lean b/Mathlib/RingTheory/RootsOfUnity/Basic.lean index 04f0e45847dbc..fbfd625bc62c1 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' @@ -868,14 +868,14 @@ theorem card_primitiveRoots {ζ : R} {k : ℕ} (h : IsPrimitiveRoot ζ k) : · 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 7f034a01f4772..a11bd30bfad0a 100644 --- a/Mathlib/RingTheory/RootsOfUnity/Complex.lean +++ b/Mathlib/RingTheory/RootsOfUnity/Complex.lean @@ -152,7 +152,7 @@ theorem IsPrimitiveRoot.arg {n : ℕ} {ζ : ℂ} (h : IsPrimitiveRoot ζ n) (hn rw [← mul_rotate', mul_div_assoc] rw [← mul_one n] at h₂ exact mul_le_of_le_one_right Real.pi_pos.le - ((div_le_iff' <| mod_cast pos_of_gt h).mpr <| mod_cast h₂) + ((div_le_iff₀' <| mod_cast pos_of_gt h).mpr <| mod_cast h₂) rw [← Complex.cos_sub_two_pi, ← Complex.sin_sub_two_pi] convert Complex.arg_cos_add_sin_mul_I _ · push_cast @@ -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/Minpoly.lean b/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean index 18723ca9b73e4..fddcf3946281c 100644 --- a/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean +++ b/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean @@ -199,7 +199,7 @@ theorem is_roots_of_minpoly [DecidableEq K] : intro x hx obtain ⟨m, _, hcop, rfl⟩ := (isPrimitiveRoot_iff h hpos).1 ((mem_primitiveRoots hpos).1 hx) simp only [Multiset.mem_toFinset, mem_roots] - convert pow_isRoot_minpoly h hcop + convert pow_isRoot_minpoly h hcop using 0 rw [← mem_roots] exact map_monic_ne_zero <| minpoly.monic <| isIntegral h hpos diff --git a/Mathlib/RingTheory/SimpleModule.lean b/Mathlib/RingTheory/SimpleModule.lean index 263f1455ae1d0..9a27c4b72d304 100644 --- a/Mathlib/RingTheory/SimpleModule.lean +++ b/Mathlib/RingTheory/SimpleModule.lean @@ -163,7 +163,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⟩ @@ -285,7 +285,7 @@ theorem IsSemisimpleModule.sup {p q : Submodule R M} instance IsSemisimpleRing.isSemisimpleModule [IsSemisimpleRing R] : IsSemisimpleModule R M := have : IsSemisimpleModule R (M →₀ R) := isSemisimpleModule_of_isSemisimpleModule_submodule' (fun _ ↦ .congr (LinearMap.quotKerEquivRange _).symm) Finsupp.iSup_lsingle_range - .congr (LinearMap.quotKerEquivOfSurjective _ <| Finsupp.total_id_surjective R M).symm + .congr (LinearMap.quotKerEquivOfSurjective _ <| Finsupp.linearCombination_id_surjective R M).symm instance IsSemisimpleRing.isCoatomic_submodule [IsSemisimpleRing R] : IsCoatomic (Submodule R M) := isCoatomic_of_isAtomic_of_complementedLattice_of_isModular @@ -338,7 +338,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,7 +398,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 qsmul := _ + qsmul_def := fun q a => 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..179e34269a3af 100644 --- a/Mathlib/RingTheory/Smooth/Basic.lean +++ b/Mathlib/RingTheory/Smooth/Basic.lean @@ -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) : @@ -187,9 +187,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 a5825c5318f5f..e11be1b55e317 100644 --- a/Mathlib/RingTheory/Smooth/Kaehler.lean +++ b/Mathlib/RingTheory/Smooth/Kaehler.lean @@ -48,14 +48,14 @@ def derivationOfSectionOfKerSqZero (f : P →ₐ[R] S) (hf' : (RingHom.ker f) ^ (hg : f.comp g = AlgHom.id R S) : Derivation R P (RingHom.ker f) where toFun x := ⟨x - g (f x), by simpa [RingHom.mem_ker, sub_eq_zero] using AlgHom.congr_fun hg.symm (f x)⟩ - map_add' x y := by simp only [map_add, AddSubmonoid.mk_add_mk, Subtype.mk.injEq]; ring + map_add' x y := by simp only [map_add, AddMemClass.mk_add_mk, Subtype.mk.injEq]; ring map_smul' x y := by ext - simp only [Algebra.smul_def, _root_.map_mul, ← IsScalarTower.algebraMap_apply, - AlgHom.commutes, RingHom.id_apply, Submodule.coe_smul_of_tower] + simp only [Algebra.smul_def, map_mul, ← IsScalarTower.algebraMap_apply, AlgHom.commutes, + RingHom.id_apply, Submodule.coe_smul_of_tower] ring - map_one_eq_zero' := by simp only [LinearMap.coe_mk, AddHom.coe_mk, _root_.map_one, sub_self, - AddSubmonoid.mk_eq_zero] + map_one_eq_zero' := by simp only [LinearMap.coe_mk, AddHom.coe_mk, map_one, sub_self, + Submodule.mk_eq_zero] leibniz' a b := by have : (a - g (f a)) * (b - g (f b)) = 0 := by rw [← Ideal.mem_bot, ← hf', pow_two] @@ -65,8 +65,8 @@ def derivationOfSectionOfKerSqZero (f : P →ₐ[R] S) (hf' : (RingHom.ker f) ^ ext rw [← sub_eq_zero] conv_rhs => rw [← neg_zero, ← this] - simp only [LinearMap.coe_mk, AddHom.coe_mk, _root_.map_mul, SetLike.mk_smul_mk, smul_eq_mul, - mul_sub, AddSubmonoid.mk_add_mk, sub_mul, neg_sub] + simp only [LinearMap.coe_mk, AddHom.coe_mk, map_mul, SetLike.mk_smul_mk, smul_eq_mul, mul_sub, + AddMemClass.mk_add_mk, sub_mul, neg_sub] ring variable (hf' : (RingHom.ker (algebraMap P S)) ^ 2 = ⊥) @@ -80,7 +80,7 @@ lemma isScalarTower_of_section_of_ker_sqZero : intro p s m ext show g (p • s) * m = p * (g s * m) - simp only [Algebra.smul_def, _root_.map_mul, mul_assoc, mul_left_comm _ (g s)] + simp only [Algebra.smul_def, map_mul, mul_assoc, mul_left_comm _ (g s)] congr 1 rw [← sub_eq_zero, ← Ideal.mem_bot, ← hf', pow_two, ← sub_mul] refine Ideal.mul_mem_mul ?_ m.2 @@ -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 @@ -149,12 +149,12 @@ def sectionOfRetractionKerToTensorAux : S →ₐ[R] P where have (x y) : (l x).1 * (l y).1 = 0 := by rw [← Ideal.mem_bot, ← hf', pow_two]; exact Ideal.mul_mem_mul (l x).2 (l y).2 simp only [sectionOfRetractionKerToTensorAux_prop l hl (σ (a * b)) (σ a * σ b) (by simp [hσ]), - Derivation.leibniz, tmul_add, tmul_smul, map_add, map_smul, AddSubmonoid.coe_add, this, - Submodule.coe_toAddSubmonoid, SetLike.val_smul, smul_eq_mul, mul_sub, sub_mul, sub_zero] + Derivation.leibniz, tmul_add, tmul_smul, map_add, map_smul, Submodule.coe_add, + SetLike.val_smul, smul_eq_mul, mul_sub, sub_mul, this, sub_zero] ring map_add' a b := by simp only [sectionOfRetractionKerToTensorAux_prop l hl (σ (a + b)) (σ a + σ b) (by simp [hσ]), - map_add, tmul_add, AddSubmonoid.coe_add, Submodule.coe_toAddSubmonoid, add_sub_add_comm] + map_add, tmul_add, Submodule.coe_add, add_sub_add_comm] map_zero' := by simp [sectionOfRetractionKerToTensorAux_prop l hl (σ 0) 0 (by simp [hσ])] commutes' r := by simp [sectionOfRetractionKerToTensorAux_prop l hl @@ -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/StandardSmooth.lean b/Mathlib/RingTheory/Smooth/StandardSmooth.lean index 33b0d6650afea..988a61b9c879e 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,9 +83,9 @@ in June 2024. universe t t' w w' u v -open TensorProduct +open TensorProduct MvPolynomial Classical -variable (n : ℕ) +variable (n m : ℕ) namespace Algebra @@ -163,10 +157,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 +395,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,6 +495,66 @@ lemma IsStandardSmoothOfRelativeDimension.isStandardSmooth IsStandardSmooth.{t, w} R S := ⟨‹IsStandardSmoothOfRelativeDimension n R S›.out.nonempty⟩ +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 + +section Composition + +variable (R S T) [CommRing T] [Algebra R T] [Algebra S T] [IsScalarTower R S T] + +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⟩ + +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 + +end Composition + +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 namespace RingHom diff --git a/Mathlib/RingTheory/SurjectiveOnStalks.lean b/Mathlib/RingTheory/SurjectiveOnStalks.lean index 67f0451472874..94c5443047b71 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 /-! diff --git a/Mathlib/RingTheory/TensorProduct/Basic.lean b/Mathlib/RingTheory/TensorProduct/Basic.lean index 78c5b9dc2e6f9..3bddb995b0910 100644 --- a/Mathlib/RingTheory/TensorProduct/Basic.lean +++ b/Mathlib/RingTheory/TensorProduct/Basic.lean @@ -1,12 +1,13 @@ /- -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.LinearAlgebra.FiniteDimensional.Defs -import Mathlib.LinearAlgebra.TensorProduct.Tower +import Mathlib.GroupTheory.MonoidLocalization.Basic +import Mathlib.LinearAlgebra.FreeModule.Basic +import Mathlib.LinearAlgebra.Matrix.ToLin import Mathlib.RingTheory.Adjoin.Basic -import Mathlib.LinearAlgebra.DirectSum.Finsupp +import Mathlib.RingTheory.Finiteness /-! # The tensor product of R-algebras @@ -34,6 +35,8 @@ multiplication is characterized by `(a₁ ⊗ₜ b₁) * (a₂ ⊗ₜ b₂) = (a -/ +assert_not_exists Equiv.Perm.cycleType + suppress_compilation open scoped TensorProduct @@ -462,7 +465,7 @@ theorem ext ⦃f g : (A ⊗[R] B) →ₐ[S] C⦄ ext a b have := congr_arg₂ HMul.hMul (AlgHom.congr_fun ha a) (AlgHom.congr_fun hb b) dsimp at * - rwa [← _root_.map_mul, ← _root_.map_mul, tmul_mul_tmul, one_mul, mul_one] at this + rwa [← map_mul, ← map_mul, tmul_mul_tmul, one_mul, mul_one] at this theorem ext' {g h : A ⊗[R] B →ₐ[S] C} (H : ∀ a b, g (a ⊗ₜ b) = h (a ⊗ₜ b)) : g = h := ext (AlgHom.ext fun _ => H _ _) (AlgHom.ext fun _ => H _ _) @@ -693,8 +696,8 @@ def lift (f : A →ₐ[S] C) (g : B →ₐ[R] C) (hfg : ∀ x y, Commute (f x) ( map_smul' := fun c g => LinearMap.ext fun x => 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 [_root_.map_mul, _root_.map_mul, (hfg a₂ b₁).mul_mul_mul_comm]) - (show f 1 * g 1 = 1 by rw [_root_.map_one, _root_.map_one, one_mul]) + rw [map_mul, map_mul, (hfg a₂ b₁).mul_mul_mul_comm]) + (show f 1 * g 1 = 1 by rw [map_one, map_one, one_mul]) @[simp] theorem lift_tmul (f : A →ₐ[S] C) (g : B →ₐ[R] C) (hfg : ∀ x y, Commute (f x) (g y)) @@ -779,7 +782,7 @@ Note that if `A` is commutative this can be instantiated with `S = A`. -/ protected nonrec def rid : A ⊗[R] R ≃ₐ[S] A := algEquivOfLinearEquivTensorProduct (AlgebraTensorModule.rid R S A) - (fun a₁ a₂ r₁ r₂ => smul_mul_smul r₁ r₂ a₁ a₂ |>.symm) + (fun a₁ a₂ r₁ r₂ => smul_mul_smul_comm r₁ a₁ r₂ a₂ |>.symm) (one_smul R _) @[simp] theorem rid_toLinearEquiv : @@ -1213,11 +1216,6 @@ theorem Subalgebra.finite_sup {K L : Type*} [CommSemiring K] [CommSemiring L] [A rw [← E1.range_val, ← E2.range_val, ← Algebra.TensorProduct.productMap_range] exact Module.Finite.range (Algebra.TensorProduct.productMap E1.val E2.val).toLinearMap -@[deprecated Subalgebra.finite_sup (since := "2024-04-11")] -theorem Subalgebra.finiteDimensional_sup {K L : Type*} [Field K] [CommRing L] [Algebra K L] - (E1 E2 : Subalgebra K L) [FiniteDimensional K E1] [FiniteDimensional K E2] : - FiniteDimensional K (E1 ⊔ E2 : Subalgebra K L) := Subalgebra.finite_sup E1 E2 - namespace TensorProduct.Algebra variable {R A B M : Type*} diff --git a/Mathlib/RingTheory/TensorProduct/MvPolynomial.lean b/Mathlib/RingTheory/TensorProduct/MvPolynomial.lean index 10e82ca9edd87..5b8ae61882f73 100644 --- a/Mathlib/RingTheory/TensorProduct/MvPolynomial.lean +++ b/Mathlib/RingTheory/TensorProduct/MvPolynomial.lean @@ -229,6 +229,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 42e25f8be8ce6..e06b0141ff923 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 @@ -119,13 +119,9 @@ variable (K) theorem trace_eq_trace_adjoin [FiniteDimensional K L] (x : L) : Algebra.trace K L x = finrank K⟮x⟯ L • trace K K⟮x⟯ (AdjoinSimple.gen K x) := by - -- Porting note: `conv` was - -- `conv in x => rw [← IntermediateField.AdjoinSimple.algebraMap_gen K x]` - -- and it was after the first `rw`. - conv => - lhs - rw [← IntermediateField.AdjoinSimple.algebraMap_gen K x] - rw [← trace_trace (S := K⟮x⟯), trace_algebraMap, LinearMap.map_smul_of_tower] + rw [← trace_trace (S := K⟮x⟯)] + conv in x => rw [← IntermediateField.AdjoinSimple.algebraMap_gen K x] + rw [trace_algebraMap, LinearMap.map_smul_of_tower] variable {K} @@ -247,12 +243,9 @@ theorem trace_eq_sum_embeddings [FiniteDimensional K L] [Algebra.IsSeparable K L have hx := Algebra.IsSeparable.isIntegral K x let pb := adjoin.powerBasis hx rw [trace_eq_trace_adjoin K x, Algebra.smul_def, RingHom.map_mul, ← adjoin.powerBasis_gen hx, - trace_eq_sum_embeddings_gen E pb (IsAlgClosed.splits_codomain _)] - -- Porting note: the following `convert` was `exact`, with `← Algebra.smul_def, algebraMap_smul` - -- in the previous `rw`. - · convert (sum_embeddings_eq_finrank_mul L E pb).symm - ext - simp + trace_eq_sum_embeddings_gen E pb (IsAlgClosed.splits_codomain _), ← Algebra.smul_def, + algebraMap_smul] + · exact (sum_embeddings_eq_finrank_mul L E pb).symm · haveI := Algebra.isSeparable_tower_bot_of_isSeparable K K⟮x⟯ L exact Algebra.IsSeparable.isSeparable K _ @@ -261,10 +254,8 @@ theorem trace_eq_sum_automorphisms (x : L) [FiniteDimensional K L] [IsGalois K L apply NoZeroSMulDivisors.algebraMap_injective L (AlgebraicClosure L) rw [_root_.map_sum (algebraMap L (AlgebraicClosure L))] rw [← Fintype.sum_equiv (Normal.algHomEquivAut K (AlgebraicClosure L) L)] - · rw [← trace_eq_sum_embeddings (AlgebraicClosure L)] - · simp only [algebraMap_eq_smul_one] - -- Porting note: `smul_one_smul` was in the `simp only`. - apply smul_one_smul + · rw [← trace_eq_sum_embeddings (AlgebraicClosure L) (x := x)] + simp only [algebraMap_eq_smul_one, smul_one_smul] · intro σ simp only [Normal.algHomEquivAut, AlgHom.restrictNormal', Equiv.coe_fn_mk, AlgEquiv.coe_ofBijective, AlgHom.restrictNormal_commutes, id.map_eq_id, RingHom.id_apply] @@ -444,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 diff --git a/Mathlib/RingTheory/Trace/Defs.lean b/Mathlib/RingTheory/Trace/Defs.lean index 86218f0b3ecff..8d961bf7c82e6 100644 --- a/Mathlib/RingTheory/Trace/Defs.lean +++ b/Mathlib/RingTheory/Trace/Defs.lean @@ -48,7 +48,7 @@ variable {R S T : Type*} [CommRing R] [CommRing S] [CommRing T] variable [Algebra R S] [Algebra R T] variable {ι κ : Type w} [Fintype ι] -open FiniteDimensional +open Module open LinearMap (BilinForm) open LinearMap diff --git a/Mathlib/RingTheory/TwoSidedIdeal/Basic.lean b/Mathlib/RingTheory/TwoSidedIdeal/Basic.lean index 01229b99f3fe5..dd7cee192929b 100644 --- a/Mathlib/RingTheory/TwoSidedIdeal/Basic.lean +++ b/Mathlib/RingTheory/TwoSidedIdeal/Basic.lean @@ -45,6 +45,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 @@ -83,7 +87,7 @@ def orderIsoRingCon : TwoSidedIdeal R ≃o RingCon R where invFun := .mk left_inv _ := rfl right_inv _ := rfl - map_rel_iff' {I J} := Iff.symm $ le_iff.trans ⟨fun h x y r => by rw [rel_iff] at r ⊢; exact h r, + map_rel_iff' {I J} := Iff.symm <| le_iff.trans ⟨fun h x y r => by rw [rel_iff] at r ⊢; exact h r, fun h x hx => by rw [SetLike.mem_coe, mem_iff] at hx ⊢; exact h hx⟩ lemma ringCon_injective : Function.Injective (TwoSidedIdeal.ringCon (R := R)) := by @@ -152,17 +156,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/Instances.lean b/Mathlib/RingTheory/TwoSidedIdeal/Instances.lean new file mode 100644 index 0000000000000..dc62e64d97bc8 --- /dev/null +++ b/Mathlib/RingTheory/TwoSidedIdeal/Instances.lean @@ -0,0 +1,14 @@ +/- +Copyright (c) 2024. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: euprunin +-/ +import Mathlib.Algebra.Ring.Defs +import Mathlib.RingTheory.NonUnitalSubring.Basic +import Mathlib.RingTheory.TwoSidedIdeal.Basic + +/-! +# Additional instances for two sided ideals. +-/ +instance {R} [NonUnitalNonAssocRing R] : NonUnitalSubringClass (TwoSidedIdeal R) R where + mul_mem _ hb := TwoSidedIdeal.mul_mem_left _ _ _ hb diff --git a/Mathlib/RingTheory/TwoSidedIdeal/Lattice.lean b/Mathlib/RingTheory/TwoSidedIdeal/Lattice.lean index 9414b3c25d465..55d3b2a16a8c7 100644 --- a/Mathlib/RingTheory/TwoSidedIdeal/Lattice.lean +++ b/Mathlib/RingTheory/TwoSidedIdeal/Lattice.lean @@ -73,7 +73,7 @@ lemma mem_inf {I J : TwoSidedIdeal R} {x : R} : Iff.rfl instance : SupSet (TwoSidedIdeal R) where - sSup s := { ringCon := sSup $ TwoSidedIdeal.ringCon '' s } + sSup s := { ringCon := sSup <| TwoSidedIdeal.ringCon '' s } lemma sSup_ringCon (S : Set (TwoSidedIdeal R)) : (sSup S).ringCon = sSup (TwoSidedIdeal.ringCon '' S) := rfl @@ -83,11 +83,11 @@ lemma iSup_ringCon {ι : Type*} (I : ι → TwoSidedIdeal R) : simp only [iSup, sSup_ringCon]; congr; ext; simp instance : CompleteSemilatticeSup (TwoSidedIdeal R) where - sSup_le s I h := by simp_rw [ringCon_le_iff] at h ⊢; exact sSup_le $ by aesop - le_sSup s I hI := by rw [ringCon_le_iff]; exact le_sSup $ by aesop + sSup_le s I h := by simp_rw [ringCon_le_iff] at h ⊢; exact sSup_le <| by aesop + le_sSup s I hI := by rw [ringCon_le_iff]; exact le_sSup <| by aesop instance : InfSet (TwoSidedIdeal R) where - sInf s := { ringCon := sInf $ TwoSidedIdeal.ringCon '' s } + sInf s := { ringCon := sInf <| TwoSidedIdeal.ringCon '' s } lemma sInf_ringCon (S : Set (TwoSidedIdeal R)) : (sInf S).ringCon = sInf (TwoSidedIdeal.ringCon '' S) := rfl @@ -97,8 +97,8 @@ lemma iInf_ringCon {ι : Type*} (I : ι → TwoSidedIdeal R) : simp only [iInf, sInf_ringCon]; congr!; ext; simp instance : CompleteSemilatticeInf (TwoSidedIdeal R) where - le_sInf s I h := by simp_rw [ringCon_le_iff] at h ⊢; exact le_sInf $ by aesop - sInf_le s I hI := by rw [ringCon_le_iff]; exact sInf_le $ by aesop + le_sInf s I h := by simp_rw [ringCon_le_iff] at h ⊢; exact le_sInf <| by aesop + sInf_le s I hI := by rw [ringCon_le_iff]; exact sInf_le <| by aesop lemma mem_iInf {ι : Type*} {I : ι → TwoSidedIdeal R} {x : R} : x ∈ iInf I ↔ ∀ i, x ∈ I i := @@ -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..78ccd01d0a217 --- /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.RingTheory.TwoSidedIdeal.Lattice +import Mathlib.RingTheory.Congruence.Opposite +import Mathlib.Algebra.BigOperators.Ring +import Mathlib.Data.Fintype.BigOperators +import Mathlib.RingTheory.Ideal.Basic +import Mathlib.Order.GaloisConnection + +/-! +# 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 395b39b238df8..ab4db15117b06 100644 --- a/Mathlib/RingTheory/UniqueFactorizationDomain.lean +++ b/Mathlib/RingTheory/UniqueFactorizationDomain.lean @@ -34,16 +34,18 @@ local infixl:50 " ~ᵤ " => Associated condition on divisibility and to the ascending chain condition on principal ideals in an integral domain. -/ -class WfDvdMonoid (α : Type*) [CommMonoidWithZero α] : Prop where - wellFounded_dvdNotUnit : WellFounded (@DvdNotUnit α _) +abbrev WfDvdMonoid (α : Type*) [CommMonoidWithZero α] : Prop := + IsWellFounded α DvdNotUnit -export WfDvdMonoid (wellFounded_dvdNotUnit) +theorem wellFounded_dvdNotUnit {α : Type*} [CommMonoidWithZero α] [h : WfDvdMonoid α] : + WellFounded (DvdNotUnit (α := α)) := + h.wf -- see Note [lower instance priority] instance (priority := 100) IsNoetherianRing.wfDvdMonoid [CommRing α] [IsDomain α] - [IsNoetherianRing α] : WfDvdMonoid α := + [h : IsNoetherianRing α] : WfDvdMonoid α := ⟨by - convert InvImage.wf (fun a => Ideal.span ({a} : Set α)) (wellFounded_submodule_gt _ _) + convert InvImage.wf (fun a => Ideal.span ({a} : Set α)) h.wf ext exact Ideal.span_singleton_lt_span_singleton.symm⟩ @@ -61,6 +63,10 @@ variable [WfDvdMonoid α] instance wfDvdMonoid_associates : WfDvdMonoid (Associates α) := ⟨(mk_surjective.wellFounded_iff mk_dvdNotUnit_mk_iff.symm).1 wellFounded_dvdNotUnit⟩ +theorem wellFoundedLT_associates : WellFoundedLT (Associates α) := + ⟨Subrelation.wf dvdNotUnit_of_lt wellFounded_dvdNotUnit⟩ + +@[deprecated wellFoundedLT_associates (since := "2024-09-02")] theorem wellFounded_associates : WellFounded ((· < ·) : Associates α → Associates α → Prop) := Subrelation.wf dvdNotUnit_of_lt wellFounded_dvdNotUnit @@ -124,6 +130,15 @@ theorem isRelPrime_of_no_irreducible_factors {x y : α} (nonzero : ¬(x = 0 ∧ end WfDvdMonoid +theorem WfDvdMonoid.of_wellFoundedLT_associates [CancelCommMonoidWithZero α] + (h : WellFoundedLT (Associates α)) : WfDvdMonoid α := + WfDvdMonoid.of_wfDvdMonoid_associates + ⟨by + convert h.wf + ext + exact Associates.dvdNotUnit_iff_lt⟩ + +@[deprecated WfDvdMonoid.of_wellFoundedLT_associates (since := "2024-09-02")] theorem WfDvdMonoid.of_wellFounded_associates [CancelCommMonoidWithZero α] (h : WellFounded ((· < ·) : Associates α → Associates α → Prop)) : WfDvdMonoid α := WfDvdMonoid.of_wfDvdMonoid_associates @@ -133,8 +148,8 @@ theorem WfDvdMonoid.of_wellFounded_associates [CancelCommMonoidWithZero α] exact Associates.dvdNotUnit_iff_lt⟩ theorem WfDvdMonoid.iff_wellFounded_associates [CancelCommMonoidWithZero α] : - WfDvdMonoid α ↔ WellFounded ((· < ·) : Associates α → Associates α → Prop) := - ⟨by apply WfDvdMonoid.wellFounded_associates, WfDvdMonoid.of_wellFounded_associates⟩ + WfDvdMonoid α ↔ WellFoundedLT (Associates α) := + ⟨by apply WfDvdMonoid.wellFoundedLT_associates, WfDvdMonoid.of_wellFoundedLT_associates⟩ theorem WfDvdMonoid.max_power_factor' [CommMonoidWithZero α] [WfDvdMonoid α] {a₀ x : α} (h : a₀ ≠ 0) (hx : ¬IsUnit x) : ∃ (n : ℕ) (a : α), ¬x ∣ a ∧ a₀ = x ^ n * a := by @@ -176,8 +191,8 @@ To define a UFD using the definition in terms of multisets of prime factors, use the definition `of_exists_prime_factors` -/ -class UniqueFactorizationMonoid (α : Type*) [CancelCommMonoidWithZero α] extends WfDvdMonoid α : - Prop where +class UniqueFactorizationMonoid (α : Type*) [CancelCommMonoidWithZero α] extends + 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 → ...`. -/ @@ -308,8 +323,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] @@ -375,8 +389,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 β := @@ -555,7 +569,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 @@ -728,7 +742,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 @@ -744,11 +758,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 @@ -897,20 +916,8 @@ 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 @@ -1013,14 +1020,14 @@ theorem prime_pow_coprime_prod_of_coprime_insert [DecidableEq α] {s : Finset α obtain ⟨q, q_mem, rfl⟩ := Multiset.mem_map.mp q_mem' replace hdq := hd.dvd_of_dvd_pow hdq have : p ∣ q := dvd_trans (hd.irreducible.dvd_symm hp.irreducible hdp) hdq - convert q_mem + convert q_mem using 0 rw [Finset.mem_val, is_coprime _ (Finset.mem_insert_self p s) _ (Finset.mem_insert_of_mem q_mem) this] /-- 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)) @@ -1059,7 +1066,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) @@ -1201,9 +1207,9 @@ theorem prod_mono : ∀ {a b : FactorSet α}, a ≤ b → a.prod ≤ b.prod 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 @@ -1248,7 +1254,7 @@ def BfactorSetMem : { a : Associates α // Irreducible a } → FactorSet α → `s : FactorSet α`. If `p` is not irreducible, `p` is not a member of any `FactorSet`. -/ -def FactorSetMem (p : Associates α) (s : FactorSet α) : Prop := +def FactorSetMem (s : FactorSet α) (p : Associates α) : Prop := letI : Decidable (Irreducible p) := Classical.dec _ if hp : Irreducible p then BfactorSetMem ⟨p, hp⟩ s else False @@ -1256,7 +1262,7 @@ instance : Membership (Associates α) (FactorSet α) := ⟨FactorSetMem⟩ @[simp] -theorem factorSetMem_eq_mem (p : Associates α) (s : FactorSet α) : FactorSetMem p s = (p ∈ s) := +theorem factorSetMem_eq_mem (p : Associates α) (s : FactorSet α) : FactorSetMem s p = (p ∈ s) := rfl theorem mem_factorSet_top {p : Associates α} {hp : Irreducible p} : p ∈ (⊤ : FactorSet α) := by @@ -1572,21 +1578,21 @@ theorem coprime_iff_inf_one {a b : α} (ha0 : a ≠ 0) (hb0 : b ≠ 0) : theorem factors_self [Nontrivial α] {p : Associates α} (hp : Irreducible p) : p.factors = WithTop.some {⟨p, hp⟩} := eq_of_prod_eq_prod - (by rw [factors_prod, FactorSet.prod]; dsimp; rw [prod_singleton]) + (by rw [factors_prod, FactorSet.prod.eq_def]; dsimp; rw [prod_singleton]) theorem factors_prime_pow [Nontrivial α] {p : Associates α} (hp : Irreducible p) (k : ℕ) : factors (p ^ k) = WithTop.some (Multiset.replicate k ⟨p, hp⟩) := eq_of_prod_eq_prod (by - rw [Associates.factors_prod, FactorSet.prod] + rw [Associates.factors_prod, FactorSet.prod.eq_def] dsimp; rw [Multiset.map_replicate, Multiset.prod_replicate, Subtype.coe_mk]) theorem prime_pow_le_iff_le_bcount [DecidableEq (Associates α)] {m p : Associates α} (h₁ : m ≠ 0) (h₂ : Irreducible p) {k : ℕ} : p ^ k ≤ m ↔ k ≤ bcount ⟨p, h₂⟩ m.factors := by rcases Associates.exists_non_zero_rep h₁ with ⟨m, hm, rfl⟩ have := nontrivial_of_ne _ _ hm - rw [bcount, factors_mk, Multiset.le_count_iff_replicate_le, ← factors_le, factors_prime_pow, - factors_mk, WithTop.coe_le_coe] <;> assumption + rw [bcount.eq_def, factors_mk, Multiset.le_count_iff_replicate_le, ← factors_le, + factors_prime_pow, factors_mk, WithTop.coe_le_coe] <;> assumption @[simp] theorem factors_one [Nontrivial α] : factors (1 : Associates α) = 0 := by @@ -1849,14 +1855,14 @@ noncomputable def fintypeSubtypeDvd {M : Type*} [CancelCommMonoidWithZero M] haveI : NormalizationMonoid M := UniqueFactorizationMonoid.normalizationMonoid haveI := Classical.decEq M haveI := Classical.decEq (Associates M) - -- We'll show `λ (u : Mˣ) (f ⊆ factors y) → u * Π f` is injective + -- We'll show `fun (u : Mˣ) (f ⊆ factors y) ↦ u * Π f` is injective -- and has image exactly the divisors of `y`. refine Fintype.ofFinset (((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⟩ @@ -1935,7 +1941,7 @@ theorem Ideal.IsPrime.exists_mem_prime_of_ne_bot {R : Type*} [CommSemiring R] [I namespace Nat instance instWfDvdMonoid : WfDvdMonoid ℕ where - wellFounded_dvdNotUnit := by + wf := by refine RelHomClass.wellFounded (⟨fun x : ℕ => if x = 0 then (⊤ : ℕ∞) else x, ?_⟩ : DvdNotUnit →r (· < ·)) wellFounded_lt intro a b h @@ -1975,3 +1981,5 @@ lemma factors_multiset_prod_of_irreducible {s : Multiset ℕ} (h : ∀ x : ℕ, exact fun con ↦ not_irreducible_zero (h 0 con) end Nat + +set_option linter.style.longFile 2100 diff --git a/Mathlib/RingTheory/Unramified/Basic.lean b/Mathlib/RingTheory/Unramified/Basic.lean index af45772e8e3eb..baf22e56e7160 100644 --- a/Mathlib/RingTheory/Unramified/Basic.lean +++ b/Mathlib/RingTheory/Unramified/Basic.lean @@ -104,23 +104,12 @@ theorem lift_unique' [FormallyUnramified R A] {C : Type u} [CommRing 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 - -section OfEquiv - -variable {R : Type u} [CommSemiring R] -variable {A B : Type u} [Semiring A] [Algebra R A] [Semiring B] [Algebra R B] - -theorem of_equiv [FormallyUnramified R A] (e : A ≃ₐ[R] B) : - FormallyUnramified R B := by +instance : FormallyUnramified R R := by constructor - intro C _ _ I hI f₁ f₂ e' - rw [← f₁.comp_id, ← f₂.comp_id, ← e.comp_symm, ← AlgHom.comp_assoc, ← AlgHom.comp_assoc] - congr 1 - refine FormallyUnramified.comp_injective I hI ?_ - rw [← AlgHom.comp_assoc, e', AlgHom.comp_assoc] + intros B _ _ _ _ f₁ f₂ _ + exact Subsingleton.elim _ _ -end OfEquiv +end section Comp @@ -155,6 +144,33 @@ theorem of_comp [FormallyUnramified R B] : FormallyUnramified A B := by end Comp +section of_surjective + +variable {R : Type u} [CommSemiring R] +variable {A B : Type u} [Semiring A] [Algebra R A] [Semiring B] [Algebra R B] + +/-- This holds in general for epimorphisms. -/ +theorem of_surjective [FormallyUnramified R A] (f : A →ₐ[R] B) (H : Function.Surjective f) : + FormallyUnramified R B := by + constructor + 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 _ _ _) Ideal.Quotient.mk_surjective + +theorem of_equiv [FormallyUnramified R A] (e : A ≃ₐ[R] B) : + FormallyUnramified R B := + of_surjective e.toAlgHom e.surjective + +end of_surjective + section BaseChange open scoped TensorProduct diff --git a/Mathlib/RingTheory/Unramified/Field.lean b/Mathlib/RingTheory/Unramified/Field.lean new file mode 100644 index 0000000000000..3a0152d738c1c --- /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 + constructor + 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) [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 0afad0fed8c13..8652ea0e4337f 100644 --- a/Mathlib/RingTheory/Unramified/Finite.lean +++ b/Mathlib/RingTheory/Unramified/Finite.lean @@ -90,8 +90,9 @@ lemma finite_of_free_aux (I) [DecidableEq I] (b : Basis I R S) let a i := b.repr (b i * x) conv_lhs => simp only [TensorProduct.tmul_mul_tmul, one_mul, mul_comm x (b _), - ← show ∀ i, Finsupp.total _ _ _ b (a i) = b i * x from fun _ ↦ b.total_repr _] - conv_lhs => simp only [Finsupp.total, Finsupp.coe_lsum, + ← show ∀ i, Finsupp.linearCombination _ b (a i) = b i * x from + fun _ ↦ b.linearCombination_repr _] + conv_lhs => simp only [Finsupp.linearCombination, Finsupp.coe_lsum, LinearMap.coe_smulRight, LinearMap.id_coe, id_eq, Finsupp.sum, TensorProduct.tmul_sum, ← TensorProduct.smul_tmul] have h₁ : ∀ k, @@ -107,7 +108,7 @@ lemma finite_of_free_aux (I) [DecidableEq I] (b : Basis I R S) · intro; simp only [zero_smul] · intros; simp only [add_smul] have h₂ : ∀ (x : S), ((b.repr x).support.sum fun a ↦ b.repr x a • b a) = x := by - simpa only [Finsupp.total_apply, Finsupp.sum] using b.total_repr + simpa only [Finsupp.linearCombination_apply, Finsupp.sum] using b.linearCombination_repr simp_rw [map_finsupp_sum, map_smul, h₁, Finsupp.sum, Finset.sum_comm (t := f.support), TensorProduct.smul_tmul', ← TensorProduct.sum_tmul, ← Finset.smul_sum, h₂] apply Finset.sum_congr rfl @@ -159,7 +160,7 @@ lemma finite_of_free [Module.Free R S] : Module.Finite R S := by have ⟨f, hf⟩ : ∃ (a : I →₀ S), elem R S = a.sum (fun i x ↦ x ⊗ₜ b i) := by let b' := ((Basis.singleton PUnit.{1} S).tensorProduct b).reindex (Equiv.punitProd I) use b'.repr (elem R S) - conv_lhs => rw [← b'.total_repr (elem R S), Finsupp.total_apply] + conv_lhs => rw [← b'.linearCombination_repr (elem R S), Finsupp.linearCombination_apply] congr! with _ i x simp [b', Basis.tensorProduct, TensorProduct.smul_tmul'] constructor @@ -197,15 +198,15 @@ lemma finite_of_free [Module.Free R S] : Module.Finite R S := by simp only [Basis.repr_symm_apply, Finsupp.coe_lsum, LinearMap.coe_smulRight, LinearMap.id_coe, id_eq, Basis.tensorProduct_apply, Finsupp.finsuppProdEquiv, Equiv.coe_fn_symm_mk, Finsupp.uncurry, map_finsupp_sum, - Finsupp.total_single, Basis.tensorProduct_apply, Finsupp.equivCongrLeft_apply, - Finsupp.total_equivMapDomain, Equiv.coe_prodComm] + Finsupp.linearCombination_single, Basis.tensorProduct_apply, Finsupp.equivCongrLeft_apply, + Finsupp.linearCombination_equivMapDomain, Equiv.coe_prodComm] rw [Finsupp.onFinset_sum, Finsupp.onFinset_sum] simp only [Function.comp_apply, Prod.swap_prod_mk, Basis.tensorProduct_apply] have : ∀ i, ((b.repr (x * f i)).sum fun j k ↦ k • b j ⊗ₜ[R] b i) = (x * f i) ⊗ₜ[R] b i := by intro i simp_rw [Finsupp.sum, TensorProduct.smul_tmul', ← TensorProduct.sum_tmul] congr 1 - exact b.total_repr _ + exact b.linearCombination_repr _ trans (x ⊗ₜ 1) * elem R S · simp_rw [this, hf, Finsupp.sum, Finset.mul_sum, TensorProduct.tmul_mul_tmul, one_mul] · rw [← one_tmul_mul_elem, hf, finite_of_free_aux] diff --git a/Mathlib/RingTheory/Unramified/Pi.lean b/Mathlib/RingTheory/Unramified/Pi.lean new file mode 100644 index 0000000000000..dc1d2ec8c816b --- /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 + constructor + 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 new file mode 100644 index 0000000000000..91ff35d526b16 --- /dev/null +++ b/Mathlib/RingTheory/Valuation/AlgebraInstances.lean @@ -0,0 +1,89 @@ +/- +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.Order.Group.TypeTags +import Mathlib.RingTheory.IntegralClosure.IsIntegralClosure.Basic +import Mathlib.RingTheory.Valuation.ValuationSubring + +/-! +# Algebra instances + +This file contains several `Algebra` and `IsScalarTower` instances related to extensions +of a field with a valuation, as well as their unit balls. + +# Main Definitions +* `ValuationSubring.algebra` : Given an algebra between two field extensions `L` and `E` of a + field `K` with a valuation, create an algebra between their two rings of integers. + +# Main Results + +* `integralClosure_algebraMap_injective` : the unit ball of a field `K` with respect to a + valuation injects into its integral closure in a field extension `L` of `K`. +-/ + +open Function Valuation + +open scoped Multiplicative + +variable {K : Type*} [Field K] (v : Valuation K ℤₘ₀) (L : Type*) [Field L] [Algebra K L] + +namespace ValuationSubring + +-- Implementation note : this instance was automatic in Lean3 +instance : Algebra v.valuationSubring L := Algebra.ofSubring v.valuationSubring.toSubring + +theorem algebraMap_injective : Injective (algebraMap v.valuationSubring L) := + (NoZeroSMulDivisors.algebraMap_injective K L).comp (IsFractionRing.injective _ _) + +theorem isIntegral_of_mem_ringOfIntegers {x : L} (hx : x ∈ integralClosure v.valuationSubring L) : + IsIntegral v.valuationSubring (⟨x, hx⟩ : integralClosure v.valuationSubring L) := by + obtain ⟨P, hPm, hP⟩ := hx + refine ⟨P, hPm, ?_⟩ + rw [← Polynomial.aeval_def, ← Subalgebra.coe_eq_zero, Polynomial.aeval_subalgebra_coe, + Polynomial.aeval_def, Subtype.coe_mk, hP] + +theorem isIntegral_of_mem_ringOfIntegers' {x : (integralClosure v.valuationSubring L)} : + IsIntegral v.valuationSubring (x : integralClosure v.valuationSubring L) := by + apply isIntegral_of_mem_ringOfIntegers + +variable (E : Type _) [Field E] [Algebra K E] [Algebra L E] [IsScalarTower K L E] + +instance : IsScalarTower v.valuationSubring L E := Subring.instIsScalarTowerSubtypeMem _ + +/-- Given an algebra between two field extensions `L` and `E` of a field `K` with a valuation `v`, + create an algebra between their two rings of integers. -/ +instance algebra : + Algebra (integralClosure v.valuationSubring L) (integralClosure v.valuationSubring E) := + RingHom.toAlgebra + { toFun := fun k => ⟨algebraMap L E k, IsIntegral.algebraMap k.2⟩ + map_zero' := + Subtype.ext <| by simp only [Subtype.coe_mk, Subalgebra.coe_zero, _root_.map_zero] + map_one' := Subtype.ext <| by simp only [Subtype.coe_mk, Subalgebra.coe_one, _root_.map_one] + map_add' := fun x y => + Subtype.ext <| by simp only [_root_.map_add, Subalgebra.coe_add, Subtype.coe_mk] + map_mul' := fun x y => + Subtype.ext <| by simp only [Subalgebra.coe_mul, _root_.map_mul, Subtype.coe_mk] } + +/-- A ring equivalence between the integral closure of the valuation subring of `K` in `L` + and a ring `R` satisfying `isIntegralClosure R v.valuationSubring L`. -/ +protected noncomputable def equiv (R : Type*) [CommRing R] [Algebra v.valuationSubring R] + [Algebra R L] [IsScalarTower v.valuationSubring R L] + [IsIntegralClosure R v.valuationSubring L] : integralClosure v.valuationSubring L ≃+* R := by + have := IsScalarTower.subalgebra' (valuationSubring v) L L + (integralClosure (valuationSubring v) L) + exact (IsIntegralClosure.equiv v.valuationSubring R L + (integralClosure v.valuationSubring L)).symm.toRingEquiv + +theorem integralClosure_algebraMap_injective : + Injective (algebraMap v.valuationSubring (integralClosure v.valuationSubring L)) := by + have hinj : Injective ⇑(algebraMap v.valuationSubring L) := + ValuationSubring.algebraMap_injective v L + rw [injective_iff_map_eq_zero (algebraMap v.valuationSubring _)] + intro x hx + rw [← Subtype.coe_inj, Subalgebra.coe_zero] at hx + rw [injective_iff_map_eq_zero (algebraMap v.valuationSubring L)] at hinj + exact hinj x hx + +end ValuationSubring diff --git a/Mathlib/RingTheory/Valuation/Basic.lean b/Mathlib/RingTheory/Valuation/Basic.lean index 9dfcfbe3ccddc..eec13a2b17f5f 100644 --- a/Mathlib/RingTheory/Valuation/Basic.lean +++ b/Mathlib/RingTheory/Valuation/Basic.lean @@ -57,7 +57,6 @@ If ever someone extends `Valuation`, we should fully comply to the `DFunLike` by boilerplate lemmas to `ValuationClass`. -/ - open scoped Classical open Function Ideal @@ -208,9 +207,19 @@ theorem zero_iff [Nontrivial Γ₀] (v : Valuation K Γ₀) {x : K} : v x = 0 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 +theorem ne_zero_of_unit [Nontrivial Γ₀] (v : Valuation K Γ₀) (x : Kˣ) : v x ≠ (0 : Γ₀) := by + simp only [ne_eq, Valuation.zero_iff, Units.ne_zero x, not_false_iff] + +theorem ne_zero_of_isUnit [Nontrivial Γ₀] (v : Valuation K Γ₀) (x : K) (hx : IsUnit x) : + v x ≠ (0 : Γ₀) := by + simpa [hx.choose_spec] using ne_zero_of_unit v hx.choose + /-- A ring homomorphism `S → R` induces a map `Valuation R Γ₀ → Valuation S Γ₀`. -/ def comap {S : Type*} [Ring S] (f : S →+* R) (v : Valuation R Γ₀) : Valuation S Γ₀ := { v.toMonoidWithZeroHom.comp f.toMonoidWithZeroHom with @@ -316,17 +325,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 @@ -406,32 +414,32 @@ 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 - by_cases hy : y = 0; · simp [hy, zero_iff] - rw [show y = 1 * y by rw [one_mul]] - rw [← inv_mul_cancel_right₀ hy x] - iterate 2 rw [v.map_mul _ y, v'.map_mul _ y] - rw [v.map_one, v'.map_one] - constructor <;> intro H - · apply mul_le_mul_right' - replace hy := v.ne_zero_iff.mpr hy - replace H := le_of_le_mul_right hy H - rwa [h] at H - · apply mul_le_mul_right' - replace hy := v'.ne_zero_iff.mpr hy - replace H := le_of_le_mul_right hy H - rwa [h] + obtain rfl | hy := eq_or_ne y 0 + · simp + · rw [← div_le_one₀, ← v.map_div, h, v'.map_div, div_le_one₀] <;> + 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 @@ -465,13 +473,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 @@ -492,20 +502,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 @@ -835,13 +854,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 new file mode 100644 index 0000000000000..00094cc933c86 --- /dev/null +++ b/Mathlib/RingTheory/Valuation/Minpoly.lean @@ -0,0 +1,50 @@ +/- +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.FieldTheory.Adjoin +import Mathlib.RingTheory.Valuation.Basic + +/-! +# Minimal polynomials. + +We prove some results about valuations of zero coefficients of minimal polynomials. + +Let `K` be a field with a valuation `v` and let `L` be a field extension of `K`. + +# Main Results +* `coeff_zero_minpoly` : for `x ∈ K` the valuation of the zeroth coefficient of the minimal + polynomial of `algebra_map K L x` over `K` is equal to the valuation of `x`. +* `pow_coeff_zero_ne_zero_of_unit` : for any unit `x : Lˣ`, we prove that a certain power of the + valuation of zeroth coefficient of the minimal polynomial of `x` over `K` is nonzero. This lemma + is helpful for defining the valuation on `L` inducing `v`. +-/ + +open Module minpoly Polynomial + +variable {K : Type*} [Field K] {Γ₀ : Type*} [LinearOrderedCommGroupWithZero Γ₀] + (v : Valuation K Γ₀) (L : Type*) [Field L] [Algebra K L] + +namespace Valuation + +/-- For `x ∈ K` the valuation of the zeroth coefficient of the minimal polynomial +of `algebra_map K L x` over `K` is equal to the valuation of `x`.-/ +@[simp] +theorem coeff_zero_minpoly (x : K) : v ((minpoly K (algebraMap K L x)).coeff 0) = v x := by + rw [minpoly.eq_X_sub_C, coeff_sub, coeff_X_zero, coeff_C_zero, zero_sub, Valuation.map_neg] + +variable {L} + +/- For any unit `x : Lˣ`, we prove that a certain power of the valuation of zeroth coefficient of +the minimal polynomial of `x` over `K` is nonzero. This lemma is helpful for defining the valuation +on `L` inducing `v`.-/ +theorem pow_coeff_zero_ne_zero_of_unit [FiniteDimensional K L] (x : L) (hx : IsUnit x): + v ((minpoly K x).coeff 0) ^ (finrank K L / (minpoly K x).natDegree) ≠ (0 : Γ₀) := by + have h_alg : Algebra.IsAlgebraic K L := Algebra.IsAlgebraic.of_finite K L + have hx₀ : IsIntegral K x := (Algebra.IsAlgebraic.isAlgebraic x).isIntegral + have hdeg := Nat.div_pos (natDegree_le x) (natDegree_pos hx₀) + rw [ne_eq, pow_eq_zero_iff hdeg.ne.symm, Valuation.zero_iff] + exact coeff_zero_ne_zero hx₀ hx.ne_zero + +end Valuation diff --git a/Mathlib/RingTheory/Valuation/ValExtension.lean b/Mathlib/RingTheory/Valuation/ValExtension.lean new file mode 100644 index 0000000000000..566aa0f741a77 --- /dev/null +++ b/Mathlib/RingTheory/Valuation/ValExtension.lean @@ -0,0 +1,158 @@ +/- +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 instIsLocalRingHomValuationInteger {S ΓS: Type*} [CommRing S] + [LinearOrderedCommGroupWithZero ΓS] + [Algebra R S] [IsLocalRingHom (algebraMap R S)] {vS : Valuation S ΓS} + [IsValExtension vR vS] : IsLocalRingHom (algebraMap vR.integer vS.integer) where + 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 + +end integer + +end IsValExtension diff --git a/Mathlib/RingTheory/Valuation/ValuationRing.lean b/Mathlib/RingTheory/Valuation/ValuationRing.lean index ed5c3bf093421..e95d7d322ff0d 100644 --- a/Mathlib/RingTheory/Valuation/ValuationRing.lean +++ b/Mathlib/RingTheory/Valuation/ValuationRing.lean @@ -3,12 +3,12 @@ Copyright (c) 2022 Adam Topaz. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Adam Topaz -/ -import Mathlib.RingTheory.Valuation.Integers +import Mathlib.Algebra.EuclideanDomain.Basic +import Mathlib.RingTheory.Bezout +import Mathlib.RingTheory.LocalRing.Basic import Mathlib.RingTheory.Localization.FractionRing import Mathlib.RingTheory.Localization.Integer -import Mathlib.RingTheory.DiscreteValuationRing.Basic -import Mathlib.RingTheory.Bezout -import Mathlib.Tactic.FieldSimp +import Mathlib.RingTheory.Valuation.Integers /-! # Valuation Rings @@ -33,6 +33,7 @@ We also show that, given a valuation `v` on a field `K`, the ring of valuation i valuation ring and `K` is the fraction field of this ring. -/ +assert_not_exists DiscreteValuationRing universe u v w @@ -334,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 @@ -362,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 @@ -440,31 +441,4 @@ instance (priority := 100) of_field : ValuationRing K := by end -section - -variable (A : Type u) [CommRing A] [IsDomain A] [DiscreteValuationRing A] - -/-- A DVR is a valuation ring. -/ -instance (priority := 100) of_discreteValuationRing : ValuationRing A := by - constructor - intro a b - by_cases ha : a = 0; · use 0; right; simp [ha] - by_cases hb : b = 0; · use 0; left; simp [hb] - obtain ⟨ϖ, hϖ⟩ := DiscreteValuationRing.exists_irreducible A - obtain ⟨m, u, rfl⟩ := DiscreteValuationRing.eq_unit_mul_pow_irreducible ha hϖ - obtain ⟨n, v, rfl⟩ := DiscreteValuationRing.eq_unit_mul_pow_irreducible hb hϖ - rcases le_total m n with h | h - · use (u⁻¹ * v : Aˣ) * ϖ ^ (n - m); left - simp_rw [mul_comm (u : A), Units.val_mul, ← mul_assoc, mul_assoc _ (u : A)] - simp only [Units.mul_inv, mul_one, mul_comm _ (v : A), mul_assoc, ← pow_add] - congr 2 - exact Nat.add_sub_of_le h - · use (v⁻¹ * u : Aˣ) * ϖ ^ (m - n); right - simp_rw [mul_comm (v : A), Units.val_mul, ← mul_assoc, mul_assoc _ (v : A)] - simp only [Units.mul_inv, mul_one, mul_comm _ (u : A), mul_assoc, ← pow_add] - congr 2 - exact Nat.add_sub_of_le h - -end - end ValuationRing diff --git a/Mathlib/RingTheory/Valuation/ValuationSubring.lean b/Mathlib/RingTheory/Valuation/ValuationSubring.lean index fb8a0c376dfbb..a62a8375a1d0a 100644 --- a/Mathlib/RingTheory/Valuation/ValuationSubring.lean +++ b/Mathlib/RingTheory/Valuation/ValuationSubring.lean @@ -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 @@ -530,10 +529,8 @@ 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] - -- Porting note: added - simp end nonunits @@ -613,7 +610,7 @@ def principalUnitGroupEquiv : A.coe_mem_principalUnitGroup_iff.1 x.2⟩ invFun x := ⟨A.unitGroupMulEquiv.symm x, by - rw [A.coe_mem_principalUnitGroup_iff]; simpa using SetLike.coe_mem x⟩ + rw [A.coe_mem_principalUnitGroup_iff]; simp⟩ left_inv x := by simp right_inv x := by simp map_mul' x y := rfl @@ -790,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/Compare.lean b/Mathlib/RingTheory/WittVector/Compare.lean index 4f42b10dee496..c99776913713c 100644 --- a/Mathlib/RingTheory/WittVector/Compare.lean +++ b/Mathlib/RingTheory/WittVector/Compare.lean @@ -71,7 +71,8 @@ def zmodEquivTrunc : ZMod (p ^ n) ≃+* TruncatedWittVector p n (ZMod p) := ZMod.ringEquiv (TruncatedWittVector p n (ZMod p)) (card_zmod _ _) theorem zmodEquivTrunc_apply {x : ZMod (p ^ n)} : - zmodEquivTrunc p n x = ZMod.castHom (by rfl) (TruncatedWittVector p n (ZMod p)) x := + zmodEquivTrunc p n x = + ZMod.castHom (m := p ^ n) (by rfl) (TruncatedWittVector p n (ZMod p)) x := rfl /-- The following diagram commutes: diff --git a/Mathlib/RingTheory/WittVector/Defs.lean b/Mathlib/RingTheory/WittVector/Defs.lean index c50793f3e1de2..53b4f06f4f2d8 100644 --- a/Mathlib/RingTheory/WittVector/Defs.lean +++ b/Mathlib/RingTheory/WittVector/Defs.lean @@ -336,10 +336,10 @@ theorem pow_coeff (m : ℕ) (x : 𝕎 R) (n : ℕ) : simp [(· ^ ·), Pow.pow, eval, Matrix.cons_fin_one, coeff_mk] theorem add_coeff_zero (x y : 𝕎 R) : (x + y).coeff 0 = x.coeff 0 + y.coeff 0 := by - simp [add_coeff, peval] + simp [add_coeff, peval, Function.uncurry] theorem mul_coeff_zero (x y : 𝕎 R) : (x * y).coeff 0 = x.coeff 0 * y.coeff 0 := by - simp [mul_coeff, peval] + simp [mul_coeff, peval, Function.uncurry] end Coeff diff --git a/Mathlib/RingTheory/WittVector/DiscreteValuationRing.lean b/Mathlib/RingTheory/WittVector/DiscreteValuationRing.lean index 2dd43d8a231f6..7261a54d9e359 100644 --- a/Mathlib/RingTheory/WittVector/DiscreteValuationRing.lean +++ b/Mathlib/RingTheory/WittVector/DiscreteValuationRing.lean @@ -120,7 +120,7 @@ theorem exists_eq_pow_p_mul (a : 𝕎 k) (ha : a ≠ 0) : rw [← this] at hcm refine ⟨m, b, ?_, ?_⟩ · contrapose! hc - simp [hc, zero_pow $ pow_ne_zero _ hp.out.ne_zero] + simp [hc, zero_pow <| pow_ne_zero _ hp.out.ne_zero] · simp_rw [← mul_left_iterate (p : 𝕎 k) m] convert hcm using 2 ext1 x diff --git a/Mathlib/RingTheory/WittVector/Frobenius.lean b/Mathlib/RingTheory/WittVector/Frobenius.lean index 0492664ca9471..3a15c88d7c9d5 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` diff --git a/Mathlib/RingTheory/WittVector/FrobeniusFractionField.lean b/Mathlib/RingTheory/WittVector/FrobeniusFractionField.lean index d45bf7b04ac15..46ee5f96de2b0 100644 --- a/Mathlib/RingTheory/WittVector/FrobeniusFractionField.lean +++ b/Mathlib/RingTheory/WittVector/FrobeniusFractionField.lean @@ -205,7 +205,7 @@ theorem frobenius_frobeniusRotation {a₁ a₂ : 𝕎 k} (ha₁ : a₁.coeff 0 ext n cases' n with n · simp only [WittVector.mul_coeff_zero, WittVector.coeff_frobenius_charP, frobeniusRotation, - frobeniusRotationCoeff, Nat.zero_eq] + frobeniusRotationCoeff] apply solution_spec' _ ha₁ · simp only [nthRemainder_spec, WittVector.coeff_frobenius_charP, frobeniusRotationCoeff, frobeniusRotation] diff --git a/Mathlib/RingTheory/WittVector/Identities.lean b/Mathlib/RingTheory/WittVector/Identities.lean index fd2d54f2430f1..4ca16f88555f7 100644 --- a/Mathlib/RingTheory/WittVector/Identities.lean +++ b/Mathlib/RingTheory/WittVector/Identities.lean @@ -52,7 +52,7 @@ variable (p R) theorem coeff_p_pow [CharP R p] (i : ℕ) : ((p : 𝕎 R) ^ i).coeff i = 1 := by induction' i with i h - · simp only [Nat.zero_eq, one_coeff_zero, Ne, pow_zero] + · simp only [one_coeff_zero, Ne, pow_zero] · rw [pow_succ, ← frobenius_verschiebung, coeff_frobenius_charP, verschiebung_coeff_succ, h, one_pow] diff --git a/Mathlib/RingTheory/WittVector/InitTail.lean b/Mathlib/RingTheory/WittVector/InitTail.lean index c2c6e3cc9a3a5..ab53e4c4a1507 100644 --- a/Mathlib/RingTheory/WittVector/InitTail.lean +++ b/Mathlib/RingTheory/WittVector/InitTail.lean @@ -101,7 +101,7 @@ theorem select_add_select_not : ∀ x : 𝕎 R, select P x + select (fun i => ¬ refine fun m _ => mul_eq_mul_left_iff.mpr (Or.inl ?_) rw [ite_pow, zero_pow (pow_ne_zero _ hp.out.ne_zero)] by_cases Pm : P m - · rw [if_pos Pm, if_neg $ not_not_intro Pm, zero_pow Fin.size_pos'.ne', add_zero] + · rw [if_pos Pm, if_neg <| not_not_intro Pm, zero_pow Fin.size_pos'.ne', add_zero] · rwa [if_neg Pm, if_pos, zero_add] theorem coeff_add_of_disjoint (x y : 𝕎 R) (h : ∀ n, x.coeff n = 0 ∨ y.coeff n = 0) : diff --git a/Mathlib/RingTheory/WittVector/IsPoly.lean b/Mathlib/RingTheory/WittVector/IsPoly.lean index 4c912841041f4..2e6c8619172e2 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` @@ -116,7 +116,7 @@ theorem poly_eq_of_wittPolynomial_bind_eq' [Fact p.Prime] (f g : ℕ → MvPolyn rw [← Function.funext_iff] at h replace h := congr_arg (fun fam => bind₁ (MvPolynomial.map (Int.castRingHom ℚ) ∘ fam) (xInTermsOfW p ℚ n)) h - simpa only [Function.comp, map_bind₁, map_wittPolynomial, ← bind₁_bind₁, + simpa only [Function.comp_def, map_bind₁, map_wittPolynomial, ← bind₁_bind₁, bind₁_wittPolynomial_xInTermsOfW, bind₁_X_right] using h theorem poly_eq_of_wittPolynomial_bind_eq [Fact p.Prime] (f g : ℕ → MvPolynomial ℕ ℤ) @@ -126,7 +126,7 @@ theorem poly_eq_of_wittPolynomial_bind_eq [Fact p.Prime] (f g : ℕ → MvPolyno rw [← Function.funext_iff] at h replace h := congr_arg (fun fam => bind₁ (MvPolynomial.map (Int.castRingHom ℚ) ∘ fam) (xInTermsOfW p ℚ n)) h - simpa only [Function.comp, map_bind₁, map_wittPolynomial, ← bind₁_bind₁, + simpa only [Function.comp_def, map_bind₁, map_wittPolynomial, ← bind₁_bind₁, bind₁_wittPolynomial_xInTermsOfW, bind₁_X_right] using h -- Ideally, we would generalise this to n-ary functions @@ -233,7 +233,7 @@ instance IsPoly₂.comp {h f g} [hh : IsPoly₂ p h] [hf : IsPoly p f] [hg : IsP uncurry] apply eval₂Hom_congr rfl _ rfl ext ⟨i, n⟩ - fin_cases i <;> simp [aeval_eq_eval₂Hom, eval₂Hom_rename, Function.comp] + fin_cases i <;> simp [aeval_eq_eval₂Hom, eval₂Hom_rename, Function.comp_def] /-- The composition of a polynomial function with a binary polynomial function is polynomial. -/ -- Porting note (#10754): made this an instance @@ -301,10 +301,8 @@ theorem bind₁_onePoly_wittPolynomial [hp : Fact p.Prime] (n : ℕ) : instance oneIsPoly [Fact p.Prime] : IsPoly p fun _ _ _ => 1 := ⟨⟨onePoly, by intros; funext n; cases n - · -- Porting note: was `simp only [...]` but with slightly different `[...]`. - simp only [Nat.zero_eq, lt_self_iff_false, one_coeff_zero, onePoly, ite_true, map_one] - · -- Porting note: was `simp only [...]` but with slightly different `[...]`. - simp only [Nat.succ_pos', one_coeff_eq_of_pos, onePoly, Nat.succ_ne_zero, ite_false, + · simp only [lt_self_iff_false, one_coeff_zero, onePoly, ite_true, map_one] + · simp only [Nat.succ_pos', one_coeff_eq_of_pos, onePoly, Nat.succ_ne_zero, ite_false, map_zero] ⟩⟩ 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 edb4720376f65..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 : ℕ) : @@ -222,7 +221,7 @@ theorem peval_polyOfInterest' (n : ℕ) (x y : 𝕎 k) : rw [peval_polyOfInterest] have : (p : k) = 0 := CharP.cast_eq_zero k p simp only [this, Nat.cast_pow, ne_eq, add_eq_zero, and_false, zero_pow, zero_mul, add_zero, - not_false_eq_true] + not_false_eq_true, reduceCtorEq] have sum_zero_pow_mul_pow_p (y : 𝕎 k) : ∑ x ∈ range (n + 1 + 1), (0 : k) ^ x * y.coeff x ^ p ^ (n + 1 - x) = y.coeff 0 ^ p ^ (n + 1) := by rw [Finset.sum_eq_single_of_mem 0] <;> simp (config := { contextual := true }) @@ -243,10 +242,15 @@ theorem nth_mul_coeff' (n : ℕ) : apply f₀ rintro ⟨a, ha⟩ apply Function.uncurry ![x, y] - simp_rw [product_val, this, Multiset.mem_product, mem_univ_val, true_and_iff, range_val, - Multiset.range_succ, Multiset.mem_cons, Multiset.mem_range] at ha + simp_rw [product_val, this, range_val, Multiset.range_succ] at ha + let S : Set (Fin 2 × ℕ) := (fun a => a.2 = n ∨ a.2 < n) + have ha' : a ∈ S := by + convert ha + dsimp [S] + congr! + simp refine ⟨a.fst, ⟨a.snd, ?_⟩⟩ - cases' ha with ha ha <;> omega + cases' ha' with ha ha <;> omega use f intro x y dsimp [f, peval] diff --git a/Mathlib/RingTheory/WittVector/MulP.lean b/Mathlib/RingTheory/WittVector/MulP.lean index c5519b92ba158..6cdf37a89f03d 100644 --- a/Mathlib/RingTheory/WittVector/MulP.lean +++ b/Mathlib/RingTheory/WittVector/MulP.lean @@ -70,7 +70,7 @@ theorem bind₁_wittMulN_wittPolynomial (n k : ℕ) : · rw [wittMulN, ← bind₁_bind₁, wittAdd, wittStructureInt_prop] simp only [map_add, Nat.cast_succ, bind₁_X_right] rw [add_mul, one_mul, bind₁_rename, bind₁_rename] - simp only [ih, Function.uncurry, Function.comp, bind₁_X_left, AlgHom.id_apply, + simp only [ih, Function.uncurry, Function.comp_def, bind₁_X_left, AlgHom.id_apply, Matrix.cons_val_zero, Matrix.head_cons, Matrix.cons_val_one] end diff --git a/Mathlib/RingTheory/WittVector/StructurePolynomial.lean b/Mathlib/RingTheory/WittVector/StructurePolynomial.lean index 0558c0e06035e..5a89447cb88ff 100644 --- a/Mathlib/RingTheory/WittVector/StructurePolynomial.lean +++ b/Mathlib/RingTheory/WittVector/StructurePolynomial.lean @@ -229,7 +229,7 @@ theorem C_p_pow_dvd_bind₁_rename_wittPolynomial_sub_sum (Φ : MvPolynomial idx ∑ i ∈ range n, C ((p : ℤ) ^ i) * wittStructureInt p Φ i ^ p ^ (n - i) := by cases' n with n · simp only [isUnit_one, Int.ofNat_zero, Int.ofNat_succ, zero_add, pow_zero, C_1, IsUnit.dvd, - Nat.cast_one, Nat.zero_eq] + Nat.cast_one] -- prepare a useful equation for rewriting have key := bind₁_rename_expand_wittPolynomial Φ n IH apply_fun map (Int.castRingHom (ZMod (p ^ (n + 1)))) at key @@ -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/Verschiebung.lean b/Mathlib/RingTheory/WittVector/Verschiebung.lean index 17a60efd46d57..8d6566ba6c58a 100644 --- a/Mathlib/RingTheory/WittVector/Verschiebung.lean +++ b/Mathlib/RingTheory/WittVector/Verschiebung.lean @@ -112,8 +112,7 @@ noncomputable def verschiebung : 𝕎 R →+ 𝕎 R where map_add' := by dsimp ghost_calc _ _ - rintro ⟨⟩ <;> -- Uses the dumb induction principle, hence adding `Nat.zero_eq` to ghost_simps. - ghost_simp + rintro ⟨⟩ <;> ghost_simp /-- `WittVector.verschiebung` is a polynomial function. -/ @[is_poly] diff --git a/Mathlib/RingTheory/WittVector/WittPolynomial.lean b/Mathlib/RingTheory/WittVector/WittPolynomial.lean index ff8d6143ceae0..ea728fea38133 100644 --- a/Mathlib/RingTheory/WittVector/WittPolynomial.lean +++ b/Mathlib/RingTheory/WittVector/WittPolynomial.lean @@ -201,8 +201,7 @@ theorem xInTermsOfW_eq [Invertible (p : R)] {n : ℕ} : xInTermsOfW p R n = @[simp] theorem constantCoeff_xInTermsOfW [hp : Fact p.Prime] [Invertible (p : R)] (n : ℕ) : constantCoeff (xInTermsOfW p R n) = 0 := by - apply Nat.strongInductionOn n; clear n - intro n IH + induction n using Nat.strongRecOn with | ind n IH => ?_ rw [xInTermsOfW_eq, mul_comm, RingHom.map_mul, RingHom.map_sub, map_sum, constantCoeff_C, constantCoeff_X, zero_sub, mul_neg, neg_eq_zero] -- Porting note: here, we should be able to do `rw [sum_eq_zero]`, but the goal that @@ -227,12 +226,11 @@ variable [hp : Fact p.Prime] theorem xInTermsOfW_vars_aux (n : ℕ) : n ∈ (xInTermsOfW p ℚ n).vars ∧ (xInTermsOfW p ℚ n).vars ⊆ range (n + 1) := by - apply Nat.strongInductionOn n; clear n - intro n ih - rw [xInTermsOfW_eq, mul_comm, vars_C_mul _ (nonzero_of_invertible _), + induction n using Nat.strongRecOn with | ind n ih => ?_ + 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 @@ -276,9 +274,7 @@ theorem bind₁_xInTermsOfW_wittPolynomial [Invertible (p : R)] (k : ℕ) : @[simp] theorem bind₁_wittPolynomial_xInTermsOfW [Invertible (p : R)] (n : ℕ) : bind₁ (W_ R) (xInTermsOfW p R n) = X n := by - apply Nat.strongInductionOn n - clear n - intro n H + induction n using Nat.strongRecOn with | ind n H => ?_ rw [xInTermsOfW_eq, map_mul, map_sub, bind₁_X_right, algHom_C, map_sum, show X n = (X n * C ((p : R) ^ n)) * C ((⅟p : R) ^ n) by rw [mul_assoc, ← C_mul, ← mul_pow, mul_invOf_self, one_pow, map_one, mul_one]] diff --git a/Mathlib/SetTheory/Cardinal/Aleph.lean b/Mathlib/SetTheory/Cardinal/Aleph.lean new file mode 100644 index 0000000000000..a2d762c20d204 --- /dev/null +++ b/Mathlib/SetTheory/Cardinal/Aleph.lean @@ -0,0 +1,424 @@ +/- +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.Ordinal.Arithmetic + +/-! +# Aleph and beth functions + +* The function `Cardinal.aleph'` gives the cardinals listed by their ordinal index. + `aleph' n = n`, `aleph' ω = ℵ₀`, `aleph' (ω + 1) = succ ℵ₀`, etc. + It is an order isomorphism between ordinals and cardinals. +* The function `Cardinal.aleph` gives the infinite cardinals listed by their + ordinal index. `aleph 0 = ℵ₀`, `aleph 1 = succ ℵ₀` is the first + uncountable cardinal, and so on. The notation `ω_` combines the latter with `Cardinal.ord`, + giving an enumeration of (infinite) initial ordinals. + Thus `ω_ 0 = ω` and `ω₁ = ω_ 1` is the first uncountable ordinal. +* The function `Cardinal.beth` enumerates the Beth cardinals. `beth 0 = ℵ₀`, + `beth (succ o) = 2 ^ beth o`, and for a limit ordinal `o`, `beth o` is the supremum of `beth a` + for `a < o`. +-/ + +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 + +namespace Cardinal + +/-! ### Aleph cardinals -/ + +/-- The `aleph'` function gives the cardinals listed by their ordinal index. `aleph' n = n`, +`aleph' ω = ℵ₀`, `aleph' (ω + 1) = succ ℵ₀`, etc. + +For the more common aleph function skipping over finite cardinals, see `Cardinal.aleph`. -/ +def aleph' : Ordinal.{u} ≃o Cardinal.{u} := by + let f := RelEmbedding.collapse Cardinal.ord.orderEmbedding.ltEmbedding.{u} + refine (OrderIso.ofRelIsoLT <| RelIso.ofSurjective f ?_).symm + apply f.eq_or_principal.resolve_right + rintro ⟨o, e⟩ + have : ∀ c, f c < o := fun c => (e _).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)⟩) + +/-- The `aleph'` index function, which gives the ordinal index of a cardinal. + (The `aleph'` part is because unlike `aleph` this counts also the + finite stages. So `alephIdx n = n`, `alephIdx ω = ω`, + `alephIdx ℵ₁ = ω + 1` and so on.) + In this definition, we register additionally that this function is an initial segment, + i.e., it is order preserving and its range is an initial segment of the ordinals. + For the basic function version, see `alephIdx`. + For an upgraded version stating that the range is everything, see `AlephIdx.rel_iso`. -/ +@[deprecated aleph' (since := "2024-08-28")] +def alephIdx.initialSeg : @InitialSeg Cardinal Ordinal (· < ·) (· < ·) := + @RelEmbedding.collapse Cardinal Ordinal (· < ·) (· < ·) _ Cardinal.ord.orderEmbedding.ltEmbedding + +/-- The `aleph'` index function, which gives the ordinal index of a cardinal. + (The `aleph'` part is because unlike `aleph` this counts also the + finite stages. So `alephIdx n = n`, `alephIdx ℵ₀ = ω`, + `alephIdx ℵ₁ = ω + 1` and so on.) + In this version, we register additionally that this function is an order isomorphism + between cardinals and ordinals. + For the basic function version, see `alephIdx`. -/ +@[deprecated aleph' (since := "2024-08-28")] +def alephIdx.relIso : @RelIso Cardinal.{u} Ordinal.{u} (· < ·) (· < ·) := + aleph'.symm.toRelIsoLT + +/-- The `aleph'` index function, which gives the ordinal index of a cardinal. + (The `aleph'` part is because unlike `aleph` this counts also the + finite stages. So `alephIdx n = n`, `alephIdx ω = ω`, + `alephIdx ℵ₁ = ω + 1` and so on.) + For an upgraded version stating that the range is everything, see `AlephIdx.rel_iso`. -/ +@[deprecated aleph' (since := "2024-08-28")] +def alephIdx : Cardinal → Ordinal := + aleph'.symm + +set_option linter.deprecated false in +@[deprecated (since := "2024-08-28")] +theorem alephIdx.initialSeg_coe : (alephIdx.initialSeg : Cardinal → Ordinal) = alephIdx := + rfl + +set_option linter.deprecated false in +@[deprecated (since := "2024-08-28")] +theorem alephIdx_lt {a b} : alephIdx a < alephIdx b ↔ a < b := + alephIdx.initialSeg.toRelEmbedding.map_rel_iff + +set_option linter.deprecated false in +@[deprecated (since := "2024-08-28")] +theorem alephIdx_le {a b} : alephIdx a ≤ alephIdx b ↔ a ≤ b := by + rw [← not_lt, ← not_lt, alephIdx_lt] + +set_option linter.deprecated false in +@[deprecated (since := "2024-08-28")] +theorem alephIdx.init {a b} : b < alephIdx a → ∃ c, alephIdx c = b := + alephIdx.initialSeg.init + +set_option linter.deprecated false in +@[deprecated (since := "2024-08-28")] +theorem alephIdx.relIso_coe : (alephIdx.relIso : Cardinal → Ordinal) = alephIdx := + rfl + +@[simp] +theorem type_cardinal : @type Cardinal (· < ·) _ = Ordinal.univ.{u, u + 1} := by + rw [Ordinal.univ_id] + exact Quotient.sound ⟨aleph'.symm.toRelIsoLT⟩ + +@[simp] +theorem mk_cardinal : #Cardinal = univ.{u, u + 1} := by + simpa only [card_type, card_univ] using congr_arg card type_cardinal + +/-- The `aleph'` function gives the cardinals listed by their ordinal + index, and is the inverse of `aleph_idx`. + `aleph' n = n`, `aleph' ω = ω`, `aleph' (ω + 1) = succ ℵ₀`, etc. + In this version, we register additionally that this function is an order isomorphism + between ordinals and cardinals. + For the basic function version, see `aleph'`. -/ +@[deprecated aleph' (since := "2024-08-28")] +def Aleph'.relIso := + aleph' + +set_option linter.deprecated false in +@[deprecated (since := "2024-08-28")] +theorem aleph'.relIso_coe : (Aleph'.relIso : Ordinal → Cardinal) = aleph' := + rfl + +theorem aleph'_lt {o₁ o₂ : Ordinal} : aleph' o₁ < aleph' o₂ ↔ o₁ < o₂ := + aleph'.lt_iff_lt + +theorem aleph'_le {o₁ o₂ : Ordinal} : aleph' o₁ ≤ aleph' o₂ ↔ o₁ ≤ o₂ := + aleph'.le_iff_le + +theorem aleph'_max (o₁ o₂ : Ordinal) : aleph' (max o₁ o₂) = max (aleph' o₁) (aleph' o₂) := + aleph'.monotone.map_max + +set_option linter.deprecated false in +@[deprecated (since := "2024-08-28")] +theorem aleph'_alephIdx (c : Cardinal) : aleph' c.alephIdx = c := + Cardinal.alephIdx.relIso.toEquiv.symm_apply_apply c + +set_option linter.deprecated false in +@[deprecated (since := "2024-08-28")] +theorem alephIdx_aleph' (o : Ordinal) : (aleph' o).alephIdx = o := + Cardinal.alephIdx.relIso.toEquiv.apply_symm_apply o + +@[simp] +theorem aleph'_zero : aleph' 0 = 0 := + aleph'.map_bot + +@[simp] +theorem aleph'_succ (o : Ordinal) : aleph' (succ o) = succ (aleph' o) := + aleph'.map_succ o + +@[simp] +theorem aleph'_nat : ∀ n : ℕ, aleph' n = n + | 0 => aleph'_zero + | n + 1 => show aleph' (succ n) = n.succ by rw [aleph'_succ, aleph'_nat n, nat_succ] + +theorem aleph'_le_of_limit {o : Ordinal} (l : o.IsLimit) {c} : + aleph' o ≤ c ↔ ∀ o' < o, aleph' o' ≤ c := + ⟨fun h o' h' => (aleph'_le.2 <| h'.le).trans h, fun h => by + rw [← aleph'.apply_symm_apply c, aleph'_le, limit_le l] + intro x h' + rw [← aleph'_le, aleph'.apply_symm_apply] + exact h _ h'⟩ + +theorem aleph'_limit {o : Ordinal} (ho : o.IsLimit) : aleph' o = ⨆ a : Iio o, aleph' a := by + refine le_antisymm ?_ (ciSup_le' fun i => aleph'_le.2 (le_of_lt i.2)) + rw [aleph'_le_of_limit ho] + exact fun a ha => le_ciSup (bddAbove_of_small _) (⟨a, ha⟩ : Iio o) + +@[simp] +theorem aleph'_omega0 : aleph' ω = ℵ₀ := + eq_of_forall_ge_iff fun c => by + simp only [aleph'_le_of_limit omega0_isLimit, lt_omega0, exists_imp, aleph0_le] + exact forall_swap.trans (forall_congr' fun n => by simp only [forall_eq, aleph'_nat]) + +@[deprecated (since := "2024-09-30")] +alias aleph'_omega := aleph'_omega0 + +set_option linter.deprecated false in +/-- `aleph'` and `aleph_idx` form an equivalence between `Ordinal` and `Cardinal` -/ +@[deprecated aleph' (since := "2024-08-28")] +def aleph'Equiv : Ordinal ≃ Cardinal := + ⟨aleph', alephIdx, alephIdx_aleph', aleph'_alephIdx⟩ + +/-- The `aleph` function gives the infinite cardinals listed by their ordinal index. `aleph 0 = ℵ₀`, +`aleph 1 = succ ℵ₀` is the first uncountable cardinal, and so on. + +For a version including finite cardinals, see `Cardinal.aleph'`. -/ +def aleph : Ordinal ↪o Cardinal := + (OrderEmbedding.addLeft ω).trans aleph'.toOrderEmbedding + +theorem aleph_eq_aleph' (o : Ordinal) : aleph o = aleph' (ω + o) := + rfl + +theorem aleph_lt {o₁ o₂ : Ordinal} : aleph o₁ < aleph o₂ ↔ o₁ < o₂ := + aleph.lt_iff_lt + +theorem aleph_le {o₁ o₂ : Ordinal} : aleph o₁ ≤ aleph o₂ ↔ o₁ ≤ o₂ := + aleph.le_iff_le + +theorem aleph_max (o₁ o₂ : Ordinal) : aleph (max o₁ o₂) = max (aleph o₁) (aleph o₂) := + aleph.monotone.map_max + +@[deprecated aleph_max (since := "2024-08-28")] +theorem max_aleph_eq (o₁ o₂ : Ordinal) : max (aleph o₁) (aleph o₂) = aleph (max o₁ o₂) := + (aleph_max o₁ o₂).symm + +@[simp] +theorem aleph_succ (o : Ordinal) : aleph (succ o) = succ (aleph o) := by + rw [aleph_eq_aleph', add_succ, aleph'_succ, aleph_eq_aleph'] + +@[simp] +theorem aleph_zero : aleph 0 = ℵ₀ := by rw [aleph_eq_aleph', add_zero, aleph'_omega0] + +theorem aleph_limit {o : Ordinal} (ho : o.IsLimit) : aleph o = ⨆ a : Iio o, aleph a := by + apply le_antisymm _ (ciSup_le' _) + · rw [aleph_eq_aleph', aleph'_limit (ho.add _)] + refine ciSup_mono' (bddAbove_of_small _) ?_ + rintro ⟨i, hi⟩ + cases' lt_or_le i ω with h h + · rcases lt_omega0.1 h with ⟨n, rfl⟩ + use ⟨0, ho.pos⟩ + simpa using (nat_lt_aleph0 n).le + · exact ⟨⟨_, (sub_lt_of_le h).2 hi⟩, aleph'_le.2 (le_add_sub _ _)⟩ + · exact fun i => aleph_le.2 (le_of_lt i.2) + +theorem aleph0_le_aleph' {o : Ordinal} : ℵ₀ ≤ aleph' o ↔ ω ≤ o := by rw [← aleph'_omega0, aleph'_le] + +theorem aleph0_le_aleph (o : Ordinal) : ℵ₀ ≤ aleph o := by + rw [aleph_eq_aleph', aleph0_le_aleph'] + apply Ordinal.le_add_right + +theorem aleph'_pos {o : Ordinal} (ho : 0 < o) : 0 < aleph' o := by rwa [← aleph'_zero, aleph'_lt] + +theorem aleph_pos (o : Ordinal) : 0 < aleph o := + aleph0_pos.trans_le (aleph0_le_aleph o) + +@[simp] +theorem aleph_toNat (o : Ordinal) : toNat (aleph o) = 0 := + toNat_apply_of_aleph0_le <| aleph0_le_aleph o + +@[simp] +theorem aleph_toPartENat (o : Ordinal) : toPartENat (aleph o) = ⊤ := + toPartENat_apply_of_aleph0_le <| aleph0_le_aleph o + +instance nonempty_toType_aleph (o : Ordinal) : Nonempty (aleph o).ord.toType := by + rw [toType_nonempty_iff_ne_zero, ← ord_zero] + exact fun h => (ord_injective h).not_gt (aleph_pos o) + +theorem ord_aleph_isLimit (o : Ordinal) : (aleph o).ord.IsLimit := + ord_isLimit <| aleph0_le_aleph _ + +instance (o : Ordinal) : NoMaxOrder (aleph o).ord.toType := + toType_noMax_of_succ_lt (ord_aleph_isLimit o).2 + +theorem exists_aleph {c : Cardinal} : ℵ₀ ≤ c ↔ ∃ o, c = aleph o := + ⟨fun h => + ⟨aleph'.symm c - ω, by + rw [aleph_eq_aleph', Ordinal.add_sub_cancel_of_le, aleph'.apply_symm_apply] + rwa [← aleph0_le_aleph', aleph'.apply_symm_apply]⟩, + fun ⟨o, e⟩ => e.symm ▸ aleph0_le_aleph _⟩ + +theorem aleph'_isNormal : IsNormal (ord ∘ aleph') := + ⟨fun o => ord_lt_ord.2 <| aleph'_lt.2 <| lt_succ o, fun o l a => by + simp [ord_le, aleph'_le_of_limit l]⟩ + +theorem aleph_isNormal : IsNormal (ord ∘ aleph) := + aleph'_isNormal.trans <| add_isNormal ω + +theorem succ_aleph0 : succ ℵ₀ = aleph 1 := by rw [← aleph_zero, ← aleph_succ, Ordinal.succ_zero] + +theorem aleph0_lt_aleph_one : ℵ₀ < aleph 1 := by + rw [← succ_aleph0] + apply lt_succ + +theorem countable_iff_lt_aleph_one {α : Type*} (s : Set α) : s.Countable ↔ #s < aleph 1 := by + rw [← succ_aleph0, lt_succ_iff, le_aleph0_iff_set_countable] + +section deprecated + +set_option linter.deprecated false + +-- TODO: these lemmas should be stated in terms of the `ω` function and of an `IsInitial` predicate, +-- neither of which currently exist. +-- +-- They should also use `¬ BddAbove` instead of `Unbounded (· < ·)`. + +/-- Ordinals that are cardinals are unbounded. -/ +@[deprecated (since := "2024-09-24")] +theorem ord_card_unbounded : Unbounded (· < ·) { b : Ordinal | b.card.ord = b } := + unbounded_lt_iff.2 fun a => + ⟨_, + ⟨by + dsimp + rw [card_ord], (lt_ord_succ_card a).le⟩⟩ + +@[deprecated (since := "2024-09-24")] +theorem eq_aleph'_of_eq_card_ord {o : Ordinal} (ho : o.card.ord = o) : ∃ a, (aleph' a).ord = o := + ⟨aleph'.symm o.card, by simpa using ho⟩ + +/-- Infinite ordinals that are cardinals are unbounded. -/ +@[deprecated (since := "2024-09-24")] +theorem ord_card_unbounded' : Unbounded (· < ·) { b : Ordinal | b.card.ord = b ∧ ω ≤ b } := + (unbounded_lt_inter_le ω).2 ord_card_unbounded + +@[deprecated (since := "2024-09-24")] +theorem eq_aleph_of_eq_card_ord {o : Ordinal} (ho : o.card.ord = o) (ho' : ω ≤ o) : + ∃ a, (aleph a).ord = o := by + cases' eq_aleph'_of_eq_card_ord ho with a ha + use a - ω + rwa [aleph_eq_aleph', Ordinal.add_sub_cancel_of_le] + rwa [← aleph0_le_aleph', ← ord_le_ord, ha, ord_aleph0] + +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 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 Cardinal + +/-! ### Omega ordinals -/ + +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)) + +end Ordinal diff --git a/Mathlib/SetTheory/Cardinal/Ordinal.lean b/Mathlib/SetTheory/Cardinal/Arithmetic.lean similarity index 57% rename from Mathlib/SetTheory/Cardinal/Ordinal.lean rename to Mathlib/SetTheory/Cardinal/Arithmetic.lean index 98fb9b0b0ef76..4bb8721a053d7 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,380 +36,8 @@ 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.out.α := - Ordinal.out_no_max_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_out_aleph (o : Ordinal) : Nonempty (aleph o).ord.out.α := by - rw [out_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.out.α := - out_no_max_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 @@ -475,13 +86,6 @@ theorem mul_eq_self {c : Cardinal} (h : ℵ₀ ≤ c) : c * c = c := by rw [mk'_def, 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,7 +101,7 @@ theorem mul_mk_eq_max {α β : Type u} [Infinite α] [Infinite β] : #α * #β = @[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] + 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 := @@ -752,6 +356,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}) @@ -766,8 +371,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, @@ -795,8 +400,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) @@ -812,9 +417,12 @@ 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] + 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 @@ -835,7 +443,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 @@ -856,8 +464,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 @@ -932,7 +542,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 @@ -1176,6 +786,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 @@ -1205,234 +816,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 @@ -1444,15 +838,10 @@ lemma mk_iUnion_Ordinal_le_of_le {β : Type*} {o : Ordinal} {c : Cardinal} (ho : o.card ≤ c) (hc : ℵ₀ ≤ c) (A : Ordinal → Set β) (hA : ∀ j < o, #(A j) ≤ c) : #(⋃ j < o, A j) ≤ c := by - simp_rw [← mem_Iio, biUnion_eq_iUnion, iUnion, iSup, ← o.enumIsoOut.symm.surjective.range_comp] + simp_rw [← mem_Iio, biUnion_eq_iUnion, iUnion, iSup, ← o.enumIsoToType.symm.surjective.range_comp] apply ((mk_iUnion_le _).trans _).trans_eq (mul_eq_self hc) - rw [mk_ordinal_out] + rw [mk_toType] 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 302fa05874ae6..0000f54003d7c 100644 --- a/Mathlib/SetTheory/Cardinal/Basic.lean +++ b/Mathlib/SetTheory/Cardinal/Basic.lean @@ -6,6 +6,7 @@ Authors: Johannes Hölzl, Mario Carneiro, Floris van Doorn import Mathlib.Data.Fintype.BigOperators import Mathlib.Data.Set.Countable import Mathlib.Logic.Small.Set +import Mathlib.Order.InitialSeg import Mathlib.Order.SuccPred.CompleteLinearOrder import Mathlib.SetTheory.Cardinal.SchroederBernstein import Mathlib.Algebra.Order.Ring.Nat @@ -79,14 +80,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,6 +133,10 @@ 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' @@ -164,52 +171,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 +219,54 @@ 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. -/ +-- 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 + @[simp] lemma mk_preimage_down {s : Set α} : #(ULift.down.{v} ⁻¹' s) = lift.{v} (#s) := by rw [← mk_uLift, Cardinal.eq] @@ -297,34 +306,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_mk_shrink' (α : Type u) [Small.{v} α] : + Cardinal.lift.{u} #(Shrink.{v} α) = Cardinal.lift.{v} #α := + lift_mk_shrink.{u, v, 0} α + @[simp] -theorem lift_le {a b : Cardinal.{v}} : lift.{u, v} a ≤ lift.{u, v} b ↔ a ≤ b := - inductionOn₂ a b fun α β => by - rw [← lift_umax] - exact lift_mk_le.{u} +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_of_le_lift {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_of_le_lift (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_of_le_lift --- 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)⟩ @@ -401,11 +470,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 +480,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,41 +496,45 @@ 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)) + 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 := @@ -538,9 +603,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 ⟨α⟩ @@ -610,7 +673,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 +702,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 @@ -663,7 +724,7 @@ instance : WellFoundedLT Cardinal.{u} := instance wo : @IsWellOrder Cardinal.{u} (· < ·) where instance : ConditionallyCompleteLinearOrderBot Cardinal := - IsWellOrder.conditionallyCompleteLinearOrderBot _ + WellFoundedLT.conditionallyCompleteLinearOrderBot _ @[simp] theorem sInf_empty : sInf (∅ : Set Cardinal.{u}) = 0 := @@ -682,16 +743,27 @@ 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 := - SuccOrder.ofSuccLeIff (fun c => sInf { c' | c < c' }) - -- Porting note: Needed to insert `by apply` in the next line - ⟨by apply lt_of_lt_of_le <| csInf_mem <| exists_gt _, - -- Porting note used to be just `csInf_le'` - fun h ↦ csInf_le' h⟩ +instance : SuccOrder Cardinal := ConditionallyCompleteLinearOrder.toSuccOrder theorem succ_def (c : Cardinal) : succ c = sInf { c' | c < c' } := - rfl + dif_neg <| not_isMax c theorem succ_pos : ∀ c : Cardinal, 0 < succ c := bot_lt_succ @@ -713,38 +785,76 @@ 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 `IsSuccLimit` 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 ∧ IsSuccLimit c + c ≠ 0 ∧ IsSuccPrelimit c + +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 -protected theorem IsLimit.isSuccLimit {c} (h : IsLimit c) : IsSuccLimit c := - h.2 +@[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.isSuccLimit.succ_lt + h.isSuccPrelimit.succ_lt + +@[deprecated isSuccPrelimit_zero (since := "2024-09-05")] +alias isSuccLimit_zero := isSuccPrelimit_zero + +end deprecated -theorem isSuccLimit_zero : IsSuccLimit (0 : Cardinal) := - isSuccLimit_bot +/-! ### 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_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 := @@ -803,6 +913,42 @@ 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⟩⟩ + +/-! ### 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) := @@ -810,14 +956,17 @@ 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 := @@ -845,8 +994,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 @@ -857,60 +1005,97 @@ 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_of_le_lift (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] -lemma exists_eq_of_iSup_eq_of_not_isSuccLimit +/-- 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.IsSuccLimit ω) + (hω : ¬ IsSuccPrelimit ω) (h : ⨆ i : ι, f i = ω) : ∃ i, f i = ω := by subst h - refine (isLUB_csSup' ?_).exists_of_not_isSuccLimit hω + refine (isLUB_csSup' ?_).exists_of_not_isSuccPrelimit hω contrapose! hω with hf rw [iSup, csSup_of_not_bddAbove hf, csSup_empty] - exact Order.isSuccLimit_bot + exact isSuccPrelimit_bot + +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) (h : ⨆ i : ι, f i = ω) : ∃ i, f i = ω := by refine (not_and_or.mp hω).elim (fun e ↦ ⟨hι.some, ?_⟩) - (Cardinal.exists_eq_of_iSup_eq_of_not_isSuccLimit.{u, v} f ω · h) + (Cardinal.exists_eq_of_iSup_eq_of_not_isSuccPrelimit.{u, v} f ω · h) cases not_not.mp e 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 @[simp] @@ -933,6 +1118,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 @@ -955,115 +1151,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] - -/-- 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} := @@ -1102,7 +1209,6 @@ theorem lift_lt_aleph0 {c : Cardinal.{u}} : lift.{v} c < ℵ₀ ↔ c < ℵ₀ : rw [← lift_aleph0.{v, u}, lift_lt] /-! ### Properties about the cast from `ℕ` -/ -section castFromN -- porting note (#10618): simp can prove this -- @[simp] @@ -1269,6 +1375,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 α @@ -1297,6 +1406,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 @@ -1311,7 +1422,7 @@ theorem one_le_aleph0 : 1 ≤ ℵ₀ := 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 @@ -1330,27 +1441,52 @@ theorem aleph0_le {c : Cardinal} : ℵ₀ ≤ c ↔ ∀ n : ℕ, ↑n ≤ c := rcases lt_aleph0.1 hn with ⟨n, rfl⟩ exact (Nat.lt_succ_self _).not_le (natCast_le.1 (h (n + 1)))⟩ -theorem isSuccLimit_aleph0 : IsSuccLimit ℵ₀ := - isSuccLimit_of_succ_lt fun a ha => by +theorem isSuccPrelimit_aleph0 : IsSuccPrelimit ℵ₀ := + isSuccPrelimit_of_succ_lt fun a ha => by rcases lt_aleph0.1 ha with ⟨n, rfl⟩ rw [← nat_succ] apply nat_lt_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, isSuccLimit_aleph0⟩ + ⟨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_isSuccLimit_succ _ (nat_succ n ▸ e.2) + | 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 ℵ₀ := @@ -1418,7 +1554,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] @@ -1557,31 +1693,7 @@ theorem mk_int : #ℤ = ℵ₀ := theorem mk_pNat : #ℕ+ = ℵ₀ := mk_denumerable ℕ+ -end castFromN - -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 +/-! ### Cardinalities of basic sets and types -/ -- porting note (#10618): simp can prove this -- @[simp] @@ -1929,9 +2041,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} := @@ -1976,7 +2086,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 @@ -1998,3 +2107,5 @@ end Cardinal -- failed -- end Tactic + +set_option linter.style.longFile 2200 diff --git a/Mathlib/SetTheory/Cardinal/Cofinality.lean b/Mathlib/SetTheory/Cardinal/Cofinality.lean index aa8f521ccd377..55b3d56e3120c 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 /-! @@ -195,7 +195,7 @@ theorem ord_cof_eq (r : α → α → Prop) [IsWellOrder α r] : private theorem card_mem_cof {o} : ∃ (ι : _) (f : ι → Ordinal), lsub.{u, u} f = o ∧ #ι = o.card := - ⟨_, _, lsub_typein o, mk_ordinal_out o⟩ + ⟨_, _, lsub_typein o, mk_toType o⟩ /-- The set in the `lsub` characterization of `cof` is nonempty. -/ theorem cof_lsub_def_nonempty (o) : @@ -210,7 +210,7 @@ theorem cof_eq_sInf_lsub (o : Ordinal.{u}) : cof o = refine (cof_type_le fun a => ?_).trans (@mk_le_of_injective _ _ - (fun s : typein ((· < ·) : o.out.α → o.out.α → Prop) ⁻¹' Set.range f => + (fun s : typein ((· < ·) : o.toType → o.toType → Prop) ⁻¹' Set.range f => Classical.choose s.prop) fun s t hst => by let H := congr_arg f hst @@ -219,18 +219,18 @@ theorem cof_eq_sInf_lsub (o : Ordinal.{u}) : cof o = have := typein_lt_self a simp_rw [← hf, lt_lsub_iff] at this cases' this with i hi - refine ⟨enum (· < ·) (f i) ?_, ?_, ?_⟩ + refine ⟨enum (α := o.toType) (· < ·) ⟨f i, ?_⟩, ?_, ?_⟩ · rw [type_lt, ← hf] apply lt_lsub · rw [mem_preimage, typein_enum] exact mem_range_self i · rwa [← typein_le_typein, typein_enum] - · rcases cof_eq (· < · : (Quotient.out o).α → (Quotient.out o).α → Prop) with ⟨S, hS, hS'⟩ + · 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 - rcases hS (enum (· < ·) a ha) with ⟨b, hb, hb'⟩ + 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 +303,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 +366,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 +381,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_ordinal_out]) fun i => hf _ _ + nfpFamily_lt_ord_lift hc (by rwa [mk_toType]) fun i => 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} : @@ -381,7 +410,7 @@ theorem le_cof_iff_blsub {b : Ordinal} {a : Cardinal} : theorem cof_blsub_le_lift {o} (f : ∀ a < o, Ordinal) : cof (blsub.{u, v} o f) ≤ Cardinal.lift.{v, u} o.card := by - rw [← mk_ordinal_out o] + rw [← mk_toType o] exact cof_lsub_le_lift _ theorem cof_blsub_le {o} (f : ∀ a < o, Ordinal) : cof (blsub.{u, u} o f) ≤ o.card := by @@ -553,7 +582,7 @@ theorem exists_fundamental_sequence (a : Ordinal.{u}) : let hrr' : r' ↪r r := Subrel.relEmbedding _ _ haveI := hrr'.isWellOrder refine - ⟨_, _, hrr'.ordinal_type_le.trans ?_, @fun i j _ h _ => (enum r' j h).prop _ ?_, + ⟨_, _, hrr'.ordinal_type_le.trans ?_, @fun i j _ h _ => (enum r' ⟨j, h⟩).prop _ ?_, le_antisymm (blsub_le fun i hi => lsub_le_iff.1 hf.le _) ?_⟩ · rw [← hι, hr] · change r (hrr'.1 _) (hrr'.1 _) @@ -651,16 +680,19 @@ theorem aleph_cof {o : Ordinal} (ho : o.IsLimit) : (aleph 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 omega0_isLimit).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 ⟨S, fun a => - let a' := enum r _ (h.2 _ (typein_lt_type r a)) + let a' := enum r ⟨_, h.2 _ (typein_lt_type r a)⟩ let ⟨b, h, ab⟩ := H a' ⟨b, h, (IsOrderConnected.conn a b a' <| @@ -680,16 +712,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_of_le_lift 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,18 +809,28 @@ 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 := - isSuccLimit_of_succ_lt fun x h => (succ_le_of_lt <| cantor x).trans_lt (H.two_power_lt h) +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 := + H.isSuccLimit.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.isSuccLimit⟩ + ⟨H.ne_zero, H.isSuccPrelimit⟩ -theorem isStrongLimit_beth {o : Ordinal} (H : IsSuccLimit o) : IsStrongLimit (beth o) := by +theorem isStrongLimit_beth {o : Ordinal} (H : IsSuccPrelimit o) : IsStrongLimit (beth o) := by rcases eq_or_ne o 0 with (rfl | h) · rw [beth_zero] exact isStrongLimit_aleph0 · refine ⟨beth_ne_zero o, fun a ha => ?_⟩ - rw [beth_limit ⟨h, isSuccLimit_iff_succ_lt.1 H⟩] at ha + rw [beth_limit ⟨h, isSuccPrelimit_iff_succ_lt.1 H⟩] at ha rcases exists_lt_of_lt_ciSup' ha with ⟨⟨i, hi⟩, ha⟩ have := power_le_power_left two_ne_zero ha.le rw [← beth_succ] at this @@ -804,7 +846,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] @@ -839,7 +881,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 (ord_isLimit h'.aleph0_le)) · intro a b hab simpa [singleton_eq_singleton_iff] using hab @@ -952,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) : @@ -1037,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_ordinal_out]) hc' fun i => hf _ _ + nfpFamily_lt_ord_lift_of_isRegular hc (by rwa [mk_toType]) hc' fun i => hf _ _ theorem nfpBFamily_lt_ord_of_isRegular {o : Ordinal} {f : ∀ a < o, Ordinal → Ordinal} {c} (hc : IsRegular c) (ho : o.card < c) (hc' : c ≠ ℵ₀) @@ -1086,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_ordinal_out]) hc' fun i => hf _ _ + derivFamily_lt_ord_lift hc (by rwa [mk_toType]) hc' fun i => 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} : @@ -1145,6 +1199,16 @@ namespace Ordinal open Cardinal open scoped Ordinal +-- TODO: generalize universes +lemma iSup_sequence_lt_omega1 {α : Type u} [Countable α] + (o : α → Ordinal.{max u v}) (ho : ∀ n, o n < ω₁) : + iSup o < ω₁ := by + apply iSup_lt_ord_lift _ ho + rw [Cardinal.isRegular_aleph_one.cof_eq] + exact lt_of_le_of_lt mk_le_aleph0 aleph0_lt_aleph_one + +set_option linter.deprecated false in +@[deprecated iSup_sequence_lt_omega1 (since := "2024-08-27")] lemma sup_sequence_lt_omega1 {α} [Countable α] (o : α → Ordinal) (ho : ∀ n, o n < ω₁) : sup o < ω₁ := by apply sup_lt_ord_lift _ ho diff --git a/Mathlib/SetTheory/Cardinal/Continuum.lean b/Mathlib/SetTheory/Cardinal/Continuum.lean index 8614f68343c3b..fa8694e0661e5 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 @@ -166,15 +166,22 @@ theorem continuum_mul_ofNat {n : ℕ} [Nat.AtLeastTwo n] : 𝔠 * no_index (OfNa @[simp] -theorem aleph0_power_aleph0 : aleph0.{u} ^ aleph0.{u} = 𝔠 := +theorem aleph0_power_aleph0 : ℵ₀ ^ ℵ₀ = 𝔠 := power_self_eq le_rfl @[simp] -theorem nat_power_aleph0 {n : ℕ} (hn : 2 ≤ n) : (n ^ aleph0.{u} : Cardinal.{u}) = 𝔠 := +theorem nat_power_aleph0 {n : ℕ} (hn : 2 ≤ n) : n ^ ℵ₀ = 𝔠 := nat_power_eq le_rfl hn @[simp] -theorem continuum_power_aleph0 : continuum.{u} ^ aleph0.{u} = 𝔠 := by +theorem continuum_power_aleph0 : 𝔠 ^ ℵ₀ = 𝔠 := by rw [← two_power_aleph0, ← power_mul, mul_eq_left le_rfl le_rfl aleph0_ne_zero] +theorem power_aleph0_of_le_continuum {x : Cardinal} (h₁ : 2 ≤ x) (h₂ : x ≤ 𝔠) : x ^ ℵ₀ = 𝔠 := by + apply le_antisymm + · rw [← continuum_power_aleph0] + exact power_le_power_right h₂ + · rw [← two_power_aleph0] + exact power_le_power_right h₁ + end Cardinal diff --git a/Mathlib/SetTheory/Cardinal/CountableCover.lean b/Mathlib/SetTheory/Cardinal/CountableCover.lean index 35f9e9f8483e6..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 /-! @@ -25,7 +25,7 @@ universe u v /-- If a set `t` is eventually covered by a countable family of sets, all with cardinality at most `a`, then the cardinality of `t` is also bounded by `a`. -Supersed by `mk_le_of_countable_eventually_mem` which does not assume +Superseded by `mk_le_of_countable_eventually_mem` which does not assume that the indexing set lives in the same universe. -/ lemma mk_subtype_le_of_countable_eventually_mem_aux {α ι : Type u} {a : Cardinal} [Countable ι] {f : ι → Set α} {l : Filter ι} [NeBot l] 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..08b850cedaa5a 100644 --- a/Mathlib/SetTheory/Cardinal/Finite.lean +++ b/Mathlib/SetTheory/Cardinal/Finite.lean @@ -95,15 +95,19 @@ protected theorem bijective_iff_injective_and_card [Finite β] (f : α → β) : rw [← and_congr_right_iff, ← Bijective, card_eq_fintype_card, card_eq_fintype_card, Fintype.bijective_iff_injective_and_card] +#adaptation_note +/-- +After nightly-2024-09-06 we can remove the `_root_` prefixes below. +-/ protected theorem bijective_iff_surjective_and_card [Finite α] (f : α → β) : Bijective f ↔ Surjective f ∧ Nat.card α = Nat.card β := by classical - 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 revert h - rw [← and_congr_left_iff, ← Bijective, ← and_comm, + rw [← and_congr_left_iff, ← Bijective, ← _root_.and_comm, card_eq_fintype_card, card_eq_fintype_card, Fintype.bijective_iff_surjective_and_card] theorem _root_.Function.Injective.bijective_of_nat_card_le [Finite β] {f : α → β} @@ -152,6 +156,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 diff --git a/Mathlib/SetTheory/Cardinal/Finsupp.lean b/Mathlib/SetTheory/Cardinal/Finsupp.lean index fc2818b357c56..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 @@ -58,15 +58,15 @@ theorem mk_finsupp_nat (α : Type u) [Nonempty α] : #(α →₀ ℕ) = max #α theorem mk_multiset_of_isEmpty (α : Type u) [IsEmpty α] : #(Multiset α) = 1 := Multiset.toFinsupp.toEquiv.cardinal_eq.trans (by simp) -open scoped Classical - @[simp] -theorem mk_multiset_of_nonempty (α : Type u) [Nonempty α] : #(Multiset α) = max #α ℵ₀ := - Multiset.toFinsupp.toEquiv.cardinal_eq.trans (mk_finsupp_nat α) +theorem mk_multiset_of_nonempty (α : Type u) [Nonempty α] : #(Multiset α) = max #α ℵ₀ := by + classical + exact Multiset.toFinsupp.toEquiv.cardinal_eq.trans (mk_finsupp_nat α) theorem mk_multiset_of_infinite (α : Type u) [Infinite α] : #(Multiset α) = #α := by simp -theorem mk_multiset_of_countable (α : Type u) [Countable α] [Nonempty α] : #(Multiset α) = ℵ₀ := - Multiset.toFinsupp.toEquiv.cardinal_eq.trans (by simp) +theorem mk_multiset_of_countable (α : Type u) [Countable α] [Nonempty α] : #(Multiset α) = ℵ₀ := by + classical + exact Multiset.toFinsupp.toEquiv.cardinal_eq.trans (by simp) end Cardinal diff --git a/Mathlib/SetTheory/Cardinal/SchroederBernstein.lean b/Mathlib/SetTheory/Cardinal/SchroederBernstein.lean index 4e8640d0749be..a15d05c552591 100644 --- a/Mathlib/SetTheory/Cardinal/SchroederBernstein.lean +++ b/Mathlib/SetTheory/Cardinal/SchroederBernstein.lean @@ -3,7 +3,6 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro -/ -import Mathlib.Init.Classical import Mathlib.Order.FixedPoints import Mathlib.Order.Zorn diff --git a/Mathlib/SetTheory/Game/Basic.lean b/Mathlib/SetTheory/Game/Basic.lean index 2752abc297073..8c72765907e52 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,6 +78,9 @@ 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_refl := by @@ -134,7 +137,7 @@ end Game namespace PGame --- Porting note: In a lot of places, I had to add explicitely that the quotient element was a Game. +-- Porting note: In a lot of places, I had to add explicitly that the quotient element was a Game. -- In Lean4, quotients don't have the setoid as an instance argument, -- but as an explicit argument, see https://leanprover.zulipchat.com/#narrow/stream/113489-new-members/topic/confusion.20between.20equivalence.20and.20instance.20setoid/near/360822354 theorem le_iff_game_le {x y : PGame} : x ≤ y ↔ (⟦x⟧ : Game) ≤ ⟦y⟧ := @@ -198,7 +201,7 @@ lemma bddAbove_range_of_small {ι : Type*} [Small.{u} ι] (f : ι → Game.{u}) BddAbove (Set.range f) := by obtain ⟨x, hx⟩ := PGame.bddAbove_range_of_small (Quotient.out ∘ f) refine ⟨⟦x⟧, Set.forall_mem_range.2 fun i ↦ ?_⟩ - simpa [PGame.le_iff_game_le] using hx $ Set.mem_range_self i + simpa [PGame.le_iff_game_le] using hx <| Set.mem_range_self i /-- A small set of games is bounded above. -/ lemma bddAbove_of_small (s : Set Game.{u}) [Small.{u} s] : BddAbove s := by @@ -209,7 +212,7 @@ lemma bddBelow_range_of_small {ι : Type*} [Small.{u} ι] (f : ι → Game.{u}) BddBelow (Set.range f) := by obtain ⟨x, hx⟩ := PGame.bddBelow_range_of_small (Quotient.out ∘ f) refine ⟨⟦x⟧, Set.forall_mem_range.2 fun i ↦ ?_⟩ - simpa [PGame.le_iff_game_le] using hx $ Set.mem_range_self i + simpa [PGame.le_iff_game_le] using hx <| Set.mem_range_self i /-- A small set of games is bounded below. -/ lemma bddBelow_of_small (s : Set Game.{u}) [Small.{u} s] : BddBelow s := by @@ -219,23 +222,24 @@ end Game namespace PGame -@[simp] -theorem quot_neg (a : PGame) : (⟦-a⟧ : Game) = -⟦a⟧ := - rfl +@[simp] theorem quot_zero : (⟦0⟧ : Game) = 0 := rfl +@[simp] theorem quot_one : (⟦1⟧ : Game) = 1 := rfl +@[simp] theorem quot_neg (a : PGame) : (⟦-a⟧ : Game) = -⟦a⟧ := rfl +@[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_add (a b : PGame) : ⟦a + b⟧ = (⟦a⟧ : Game) + ⟦b⟧ := - rfl - -@[simp] -theorem quot_sub (a b : PGame) : ⟦a - b⟧ = (⟦a⟧ : Game) - ⟦b⟧ := - rfl +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⟧ := by - exact Quot.sound (equiv_of_mk_equiv L R (fun _ => equiv_iff_game_eq.2 (hl _)) - (fun _ => equiv_iff_game_eq.2 (hr _))) + (hr : ∀ j, (⟦x.moveRight j⟧ : Game) = ⟦y.moveRight (R j)⟧) : (⟦x⟧ : Game) = ⟦y⟧ := + 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, but to prove their properties we need to use the abelian group structure of games. @@ -246,8 +250,8 @@ Hence we define them here. -/ `{xL*y + x*yL - xL*yL, xR*y + x*yR - xR*yR | xL*y + x*yR - xL*yR, x*yL + xR*y - xR*yL }`. -/ instance : Mul PGame.{u} := ⟨fun x y => by - induction' x with xl xr _ _ IHxl IHxr generalizing y - induction' y with yl yr yL yR IHyl IHyr + induction x generalizing y with | mk xl xr _ _ IHxl IHxr => _ + induction y with | mk yl yr yL yR IHyl IHyr => _ have y := mk yl yr yL yR refine ⟨(xl × yl) ⊕ (xr × yr), (xl × yr) ⊕ (xr × yl), ?_, ?_⟩ <;> rintro (⟨i, j⟩ | ⟨i, j⟩) · exact IHxl i y + IHyl j - IHxl i (yL j) @@ -392,7 +396,7 @@ def mulCommRelabelling (x y : PGame.{u}) : x * y ≡r y * x := termination_by (x, y) theorem quot_mul_comm (x y : PGame.{u}) : (⟦x * y⟧ : Game) = ⟦y * x⟧ := - Quot.sound (mulCommRelabelling x y).equiv + game_eq (mulCommRelabelling x y).equiv /-- `x * y` is equivalent to `y * x`. -/ theorem mul_comm_equiv (x y : PGame) : x * y ≈ y * x := @@ -421,8 +425,8 @@ theorem mul_zero_equiv (x : PGame) : x * 0 ≈ 0 := (mulZeroRelabelling x).equiv @[simp] -theorem quot_mul_zero (x : PGame) : (⟦x * 0⟧ : Game) = ⟦0⟧ := - @Quotient.sound _ _ (x * 0) _ x.mul_zero_equiv +theorem quot_mul_zero (x : PGame) : (⟦x * 0⟧ : Game) = 0 := + game_eq x.mul_zero_equiv /-- `0 * x` has exactly the same moves as `0`. -/ def zeroMulRelabelling (x : PGame) : 0 * x ≡r 0 := @@ -433,8 +437,8 @@ theorem zero_mul_equiv (x : PGame) : 0 * x ≈ 0 := (zeroMulRelabelling x).equiv @[simp] -theorem quot_zero_mul (x : PGame) : (⟦0 * x⟧ : Game) = ⟦0⟧ := - @Quotient.sound _ _ (0 * x) _ x.zero_mul_equiv +theorem quot_zero_mul (x : PGame) : (⟦0 * x⟧ : Game) = 0 := + game_eq x.zero_mul_equiv /-- `-x * y` and `-(x * y)` have the same moves. -/ def negMulRelabelling (x y : PGame.{u}) : -x * y ≡r -(x * y) := @@ -457,7 +461,7 @@ def negMulRelabelling (x y : PGame.{u}) : -x * y ≡r -(x * y) := @[simp] theorem quot_neg_mul (x y : PGame) : (⟦-x * y⟧ : Game) = -⟦x * y⟧ := - Quot.sound (negMulRelabelling x y).equiv + game_eq (negMulRelabelling x y).equiv /-- `x * -y` and `-(x * y)` have the same moves. -/ def mulNegRelabelling (x y : PGame) : x * -y ≡r -(x * y) := @@ -465,7 +469,7 @@ def mulNegRelabelling (x y : PGame) : x * -y ≡r -(x * y) := @[simp] theorem quot_mul_neg (x y : PGame) : ⟦x * -y⟧ = (-⟦x * y⟧ : Game) := - Quot.sound (mulNegRelabelling x y).equiv + game_eq (mulNegRelabelling x y).equiv theorem quot_neg_mul_neg (x y : PGame) : ⟦-x * -y⟧ = (⟦x * y⟧ : Game) := by simp @@ -601,13 +605,13 @@ 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 _) } @[simp] theorem quot_mul_one (x : PGame) : (⟦x * 1⟧ : Game) = ⟦x⟧ := - Quot.sound <| PGame.Relabelling.equiv <| mulOneRelabelling x + game_eq <| PGame.Relabelling.equiv <| mulOneRelabelling x /-- `x * 1` is equivalent to `x`. -/ theorem mul_one_equiv (x : PGame) : x * 1 ≈ x := @@ -619,7 +623,7 @@ def oneMulRelabelling (x : PGame) : 1 * x ≡r x := @[simp] theorem quot_one_mul (x : PGame) : (⟦1 * x⟧ : Game) = ⟦x⟧ := - Quot.sound <| PGame.Relabelling.equiv <| oneMulRelabelling x + game_eq <| PGame.Relabelling.equiv <| oneMulRelabelling x /-- `1 * x` is equivalent to `x`. -/ theorem one_mul_equiv (x : PGame) : 1 * x ≈ x := diff --git a/Mathlib/SetTheory/Game/Birthday.lean b/Mathlib/SetTheory/Game/Birthday.lean index ec738e14e6401..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 @@ -83,7 +88,6 @@ theorem Relabelling.birthday_congr : ∀ {x y : PGame.{u}}, x ≡r y → birthda · exact ⟨_, (r.moveLeftSymm j).birthday_congr⟩ · exact ⟨_, (r.moveRight j).birthday_congr.symm⟩ · exact ⟨_, (r.moveRightSymm j).birthday_congr⟩ -termination_by x y => (x, y) @[simp] theorem birthday_eq_zero {x : PGame} : @@ -100,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] @@ -122,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⟩] @@ -157,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/Impartial.lean b/Mathlib/SetTheory/Game/Impartial.lean index 24c984856e4bb..fea623654ef44 100644 --- a/Mathlib/SetTheory/Game/Impartial.lean +++ b/Mathlib/SetTheory/Game/Impartial.lean @@ -25,13 +25,12 @@ open scoped PGame namespace PGame /-- The definition for an impartial game, defined using Conway induction. -/ -def ImpartialAux : PGame → Prop - | G => (G ≈ -G) ∧ (∀ i, ImpartialAux (G.moveLeft i)) ∧ ∀ j, ImpartialAux (G.moveRight j) -termination_by G => G -- Porting note: Added `termination_by` +def ImpartialAux (G : PGame) : Prop := + (G ≈ -G) ∧ (∀ i, ImpartialAux (G.moveLeft i)) ∧ ∀ j, ImpartialAux (G.moveRight j) +termination_by G -theorem impartialAux_def {G : PGame} : - G.ImpartialAux ↔ - (G ≈ -G) ∧ (∀ i, ImpartialAux (G.moveLeft i)) ∧ ∀ j, ImpartialAux (G.moveRight j) := by +theorem impartialAux_def {G : PGame} : G.ImpartialAux ↔ + (G ≈ -G) ∧ (∀ i, ImpartialAux (G.moveLeft i)) ∧ ∀ j, ImpartialAux (G.moveRight j) := by rw [ImpartialAux] /-- A typeclass on impartial games. -/ @@ -47,18 +46,20 @@ theorem impartial_def {G : PGame} : namespace Impartial -instance impartial_zero : Impartial 0 := by rw [impartial_def]; dsimp; simp +instance impartial_zero : Impartial 0 := by + rw [impartial_def] + simp instance impartial_star : Impartial star := by - rw [impartial_def]; simpa using Impartial.impartial_zero + rw [impartial_def] + simpa using Impartial.impartial_zero theorem neg_equiv_self (G : PGame) [h : G.Impartial] : G ≈ -G := (impartial_def.1 h).1 --- Porting note: Changed `-⟦G⟧` to `-(⟦G⟧ : Quotient setoid)` @[simp] -theorem mk'_neg_equiv_self (G : PGame) [G.Impartial] : -(⟦G⟧ : Quotient setoid) = ⟦G⟧ := - Quot.sound (Equiv.symm (neg_equiv_self G)) +theorem mk'_neg_equiv_self (G : PGame) [G.Impartial] : -(⟦G⟧ : Game) = ⟦G⟧ := + game_eq (Equiv.symm (neg_equiv_self G)) instance moveLeft_impartial {G : PGame} [h : G.Impartial] (i : G.LeftMoves) : (G.moveLeft i).Impartial := @@ -68,49 +69,47 @@ instance moveRight_impartial {G : PGame} [h : G.Impartial] (j : G.RightMoves) : (G.moveRight j).Impartial := (impartial_def.1 h).2.2 j -theorem impartial_congr : ∀ {G H : PGame} (_ : G ≡r H) [G.Impartial], H.Impartial - | G, H => fun e => by - intro h - exact impartial_def.2 - ⟨Equiv.trans e.symm.equiv (Equiv.trans (neg_equiv_self G) (neg_equiv_neg_iff.2 e.equiv)), - fun i => impartial_congr (e.moveLeftSymm i), fun j => impartial_congr (e.moveRightSymm j)⟩ -termination_by G H => (G, H) - -instance impartial_add : ∀ (G H : PGame) [G.Impartial] [H.Impartial], (G + H).Impartial - | G, H, _, _ => by - rw [impartial_def] - refine ⟨Equiv.trans (add_congr (neg_equiv_self G) (neg_equiv_self _)) - (Equiv.symm (negAddRelabelling _ _).equiv), fun k => ?_, fun k => ?_⟩ - · apply leftMoves_add_cases k - all_goals - intro i; simp only [add_moveLeft_inl, add_moveLeft_inr] - apply impartial_add - · apply rightMoves_add_cases k - all_goals - intro i; simp only [add_moveRight_inl, add_moveRight_inr] - apply impartial_add -termination_by G H => (G, H) - -instance impartial_neg : ∀ (G : PGame) [G.Impartial], (-G).Impartial - | G, _ => by - rw [impartial_def] - refine ⟨?_, fun i => ?_, fun i => ?_⟩ - · rw [neg_neg] - exact Equiv.symm (neg_equiv_self G) - · rw [moveLeft_neg'] - apply impartial_neg - · rw [moveRight_neg'] - apply impartial_neg -termination_by G => G +theorem impartial_congr {G H : PGame} (e : G ≡r H) [G.Impartial] : H.Impartial := + impartial_def.2 + ⟨Equiv.trans e.symm.equiv (Equiv.trans (neg_equiv_self G) (neg_equiv_neg_iff.2 e.equiv)), + fun i => impartial_congr (e.moveLeftSymm i), fun j => impartial_congr (e.moveRightSymm j)⟩ +termination_by G + +instance impartial_add (G H : PGame) [G.Impartial] [H.Impartial] : (G + H).Impartial := by + rw [impartial_def] + refine ⟨Equiv.trans (add_congr (neg_equiv_self G) (neg_equiv_self _)) + (Equiv.symm (negAddRelabelling _ _).equiv), fun k => ?_, fun k => ?_⟩ + · apply leftMoves_add_cases k + all_goals + intro i; simp only [add_moveLeft_inl, add_moveLeft_inr] + apply impartial_add + · apply rightMoves_add_cases k + all_goals + intro i; simp only [add_moveRight_inl, add_moveRight_inr] + apply impartial_add +termination_by (G, H) + +instance impartial_neg (G : PGame) [G.Impartial] : (-G).Impartial := by + rw [impartial_def] + refine ⟨?_, fun i => ?_, fun i => ?_⟩ + · rw [neg_neg] + exact Equiv.symm (neg_equiv_self G) + · rw [moveLeft_neg'] + exact impartial_neg _ + · rw [moveRight_neg'] + exact impartial_neg _ +termination_by G variable (G : PGame) [Impartial G] -theorem nonpos : ¬0 < G := fun h => by +theorem nonpos : ¬0 < G := by + intro h have h' := neg_lt_neg_iff.2 h rw [neg_zero, lt_congr_left (Equiv.symm (neg_equiv_self G))] at h' exact (h.trans h').false -theorem nonneg : ¬G < 0 := fun h => by +theorem nonneg : ¬G < 0 := by + intro h have h' := neg_lt_neg_iff.2 h rw [neg_zero, lt_congr_right (Equiv.symm (neg_equiv_self G))] at h' exact (h.trans h').false @@ -134,22 +133,19 @@ theorem not_fuzzy_zero_iff : ¬G ‖ 0 ↔ (G ≈ 0) := theorem add_self : G + G ≈ 0 := Equiv.trans (add_congr_left (neg_equiv_self G)) (neg_add_cancel_equiv G) --- Porting note: Changed `⟦G⟧` to `(⟦G⟧ : Quotient setoid)` @[simp] -theorem mk'_add_self : (⟦G⟧ : Quotient setoid) + ⟦G⟧ = 0 := - Quot.sound (add_self G) +theorem mk'_add_self : (⟦G⟧ : Game) + ⟦G⟧ = 0 := + game_eq (add_self G) /-- This lemma doesn't require `H` to be impartial. -/ theorem equiv_iff_add_equiv_zero (H : PGame) : (H ≈ G) ↔ (H + G ≈ 0) := by - rw [equiv_iff_game_eq, ← @add_right_cancel_iff _ _ _ ⟦G⟧, mk'_add_self, ← quot_add, - equiv_iff_game_eq] - rfl + rw [equiv_iff_game_eq, ← add_right_cancel_iff (a := ⟦G⟧), mk'_add_self, ← quot_add, + equiv_iff_game_eq, quot_zero] /-- This lemma doesn't require `H` to be impartial. -/ theorem equiv_iff_add_equiv_zero' (H : PGame) : (G ≈ H) ↔ (G + H ≈ 0) := by - rw [equiv_iff_game_eq, ← @add_left_cancel_iff _ _ _ ⟦G⟧, mk'_add_self, ← quot_add, - equiv_iff_game_eq] - exact ⟨Eq.symm, Eq.symm⟩ + rw [equiv_iff_game_eq, ← add_left_cancel_iff, mk'_add_self, ← quot_add, equiv_iff_game_eq, + Eq.comm, quot_zero] theorem le_zero_iff {G : PGame} [G.Impartial] : G ≤ 0 ↔ 0 ≤ G := by rw [← zero_le_neg_iff, le_congr_right (neg_equiv_self G)] diff --git a/Mathlib/SetTheory/Game/Nim.lean b/Mathlib/SetTheory/Game/Nim.lean index f56bc51986556..f563fafa77d4b 100644 --- a/Mathlib/SetTheory/Game/Nim.lean +++ b/Mathlib/SetTheory/Game/Nim.lean @@ -24,7 +24,7 @@ However, this definition does not work for us because it would make the type of `Ordinal.{u} → SetTheory.PGame.{u + 1}`, which would make it impossible for us to state the Sprague-Grundy theorem, since that requires the type of `nim` to be `Ordinal.{u} → SetTheory.PGame.{u}`. For this reason, we -instead use `o.out.α` for the possible moves. You can use `to_left_moves_nim` and +instead use `o.toType` for the possible moves. You can use `to_left_moves_nim` and `to_right_moves_nim` to convert an ordinal less than `o` into a left or right move of `nim o`, and vice versa. -/ @@ -37,62 +37,54 @@ universe u namespace SetTheory open scoped PGame +open Ordinal namespace PGame --- Uses `noncomputable!` to avoid `rec_fn_macro only allowed in meta definitions` VM error /-- The definition of single-heap nim, which can be viewed as a pile of stones where each player can take a positive number of stones from it on their turn. -/ -noncomputable def nim : Ordinal.{u} → PGame.{u} - | o₁ => - let f o₂ := - have _ : Ordinal.typein o₁.out.r o₂ < o₁ := Ordinal.typein_lt_self o₂ - nim (Ordinal.typein o₁.out.r o₂) - ⟨o₁.out.α, o₁.out.α, f, f⟩ -termination_by o => o - -open Ordinal - -theorem nim_def (o : Ordinal) : - have : IsWellOrder (Quotient.out o).α (· < ·) := inferInstance - nim o = - PGame.mk o.out.α o.out.α (fun o₂ => nim (Ordinal.typein (· < ·) o₂)) fun o₂ => - nim (Ordinal.typein (· < ·) o₂) := by - rw [nim]; rfl - -theorem leftMoves_nim (o : Ordinal) : (nim o).LeftMoves = o.out.α := by rw [nim_def]; rfl - -theorem rightMoves_nim (o : Ordinal) : (nim o).RightMoves = o.out.α := by rw [nim_def]; rfl +noncomputable def nim (o : Ordinal.{u}) : PGame.{u} := + ⟨o.toType, o.toType, + fun x => nim ((enumIsoToType o).symm x).val, + fun x => nim ((enumIsoToType o).symm x).val⟩ +termination_by o +decreasing_by all_goals exact ((enumIsoToType o).symm x).prop + +theorem nim_def (o : Ordinal) : nim o = + ⟨o.toType, o.toType, + fun x => nim ((enumIsoToType o).symm x).val, + fun x => nim ((enumIsoToType o).symm x).val⟩ := by + rw [nim] + +theorem leftMoves_nim (o : Ordinal) : (nim o).LeftMoves = o.toType := by rw [nim_def]; rfl +theorem rightMoves_nim (o : Ordinal) : (nim o).RightMoves = o.toType := by rw [nim_def]; rfl theorem moveLeft_nim_hEq (o : Ordinal) : - have : IsWellOrder (Quotient.out o).α (· < ·) := inferInstance - HEq (nim o).moveLeft fun i : o.out.α => nim (typein (· < ·) i) := by rw [nim_def]; rfl + HEq (nim o).moveLeft fun i : o.toType => nim ((enumIsoToType o).symm i) := by rw [nim_def]; rfl theorem moveRight_nim_hEq (o : Ordinal) : - have : IsWellOrder (Quotient.out o).α (· < ·) := inferInstance - HEq (nim o).moveRight fun i : o.out.α => nim (typein (· < ·) i) := by rw [nim_def]; rfl + HEq (nim o).moveRight fun i : o.toType => nim ((enumIsoToType o).symm i) := by rw [nim_def]; rfl -/-- Turns an ordinal less than `o` into a left move for `nim o` and viceversa. -/ +/-- Turns an ordinal less than `o` into a left move for `nim o` and vice versa. -/ noncomputable def toLeftMovesNim {o : Ordinal} : Set.Iio o ≃ (nim o).LeftMoves := - (enumIsoOut o).toEquiv.trans (Equiv.cast (leftMoves_nim o).symm) + (enumIsoToType o).toEquiv.trans (Equiv.cast (leftMoves_nim o).symm) -/-- Turns an ordinal less than `o` into a right move for `nim o` and viceversa. -/ +/-- Turns an ordinal less than `o` into a right move for `nim o` and vice versa. -/ noncomputable def toRightMovesNim {o : Ordinal} : Set.Iio o ≃ (nim o).RightMoves := - (enumIsoOut o).toEquiv.trans (Equiv.cast (rightMoves_nim o).symm) + (enumIsoToType o).toEquiv.trans (Equiv.cast (rightMoves_nim o).symm) @[simp] theorem toLeftMovesNim_symm_lt {o : Ordinal} (i : (nim o).LeftMoves) : - ↑(toLeftMovesNim.symm i) < o := + toLeftMovesNim.symm i < o := (toLeftMovesNim.symm i).prop @[simp] theorem toRightMovesNim_symm_lt {o : Ordinal} (i : (nim o).RightMoves) : - ↑(toRightMovesNim.symm i) < o := + toRightMovesNim.symm i < o := (toRightMovesNim.symm i).prop @[simp] -theorem moveLeft_nim' {o : Ordinal.{u}} (i) : - (nim o).moveLeft i = nim (toLeftMovesNim.symm i).val := +theorem moveLeft_nim' {o : Ordinal} (i) : (nim o).moveLeft i = nim (toLeftMovesNim.symm i).val := (congr_heq (moveLeft_nim_hEq o).symm (cast_heq _ i)).symm theorem moveLeft_nim {o : Ordinal} (i) : (nim o).moveLeft (toLeftMovesNim i) = nim i := by simp @@ -117,11 +109,11 @@ def rightMovesNimRecOn {o : Ordinal} {P : (nim o).RightMoves → Sort*} (i : (ni instance isEmpty_nim_zero_leftMoves : IsEmpty (nim 0).LeftMoves := by rw [nim_def] - exact Ordinal.isEmpty_out_zero + exact isEmpty_toType_zero instance isEmpty_nim_zero_rightMoves : IsEmpty (nim 0).RightMoves := by rw [nim_def] - exact Ordinal.isEmpty_out_zero + exact isEmpty_toType_zero /-- `nim 0` has exactly the same moves as `0`. -/ def nimZeroRelabelling : nim 0 ≡r 0 := @@ -165,7 +157,7 @@ def nimOneRelabelling : nim 1 ≡r star := by rw [nim_def] refine ⟨?_, ?_, fun i => ?_, fun j => ?_⟩ any_goals dsimp; apply Equiv.equivOfUnique - all_goals simpa using nimZeroRelabelling + all_goals simpa [enumIsoToType] using nimZeroRelabelling theorem nim_one_equiv : nim 1 ≈ star := nimOneRelabelling.equiv @@ -190,9 +182,9 @@ instance nim_impartial (o : Ordinal) : Impartial (nim o) := by refine ⟨equiv_rfl, fun i => ?_, fun i => ?_⟩ <;> simpa using IH _ (typein_lt_self _) theorem nim_fuzzy_zero_of_ne_zero {o : Ordinal} (ho : o ≠ 0) : nim o ‖ 0 := by - rw [Impartial.fuzzy_zero_iff_lf, nim_def, lf_zero_le] - rw [← Ordinal.pos_iff_ne_zero] at ho - exact ⟨(Ordinal.principalSegOut ho).top, by simp⟩ + rw [Impartial.fuzzy_zero_iff_lf, lf_zero_le] + use toRightMovesNim ⟨0, Ordinal.pos_iff_ne_zero.2 ho⟩ + simp @[simp] theorem nim_add_equiv_zero_iff (o₁ o₂ : Ordinal) : (nim o₁ + nim o₂ ≈ 0) ↔ o₁ = o₂ := by @@ -200,12 +192,9 @@ theorem nim_add_equiv_zero_iff (o₁ o₂ : Ordinal) : (nim o₁ + nim o₂ ≈ · refine not_imp_not.1 fun hne : _ ≠ _ => (Impartial.not_equiv_zero_iff (nim o₁ + nim o₂)).2 ?_ wlog h : o₁ < o₂ · exact (fuzzy_congr_left add_comm_equiv).1 (this _ _ hne.symm (hne.lt_or_lt.resolve_left h)) - rw [Impartial.fuzzy_zero_iff_gf, zero_lf_le, nim_def o₂] - refine ⟨toLeftMovesAdd (Sum.inr ?_), ?_⟩ - · exact (Ordinal.principalSegOut h).top - · -- Porting note: squeezed simp - simpa only [Ordinal.typein_top, Ordinal.type_lt, PGame.add_moveLeft_inr, PGame.moveLeft_mk] - using (Impartial.add_self (nim o₁)).2 + rw [Impartial.fuzzy_zero_iff_gf, zero_lf_le] + use toLeftMovesAdd (Sum.inr <| toLeftMovesNim ⟨_, h⟩) + · simpa using (Impartial.add_self (nim o₁)).2 · rintro rfl exact Impartial.add_self (nim o₁) @@ -217,57 +206,69 @@ 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. -/ +noncomputable def grundyValue (G : PGame.{u}) : Ordinal.{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 (Quotient.out (grundyValue G)).r i₂ := by - revert i₂ - rw [grundyValue_eq_mex_left] - intro i₂ - have hnotin : _ ∉ _ := fun hin => - (le_not_le_of_lt (Ordinal.typein_lt_self i₂)).2 (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 + 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 : Ordinal} + (h : Set.Iio o ⊆ Set.range (grundyValue ∘ G.moveLeft)) : o ≤ grundyValue G := by + by_contra! ho + obtain ⟨i, hi⟩ := h ho + exact grundyValue_ne_moveLeft i hi + +theorem exists_grundyValue_moveLeft_of_lt {G : PGame} {o : Ordinal} (h : o < grundyValue G) : + ∃ i, grundyValue (G.moveLeft i) = o := by + rw [grundyValue_eq_sInf_moveLeft] at h + by_contra ha + exact h.not_le (csInf_le' ha) + +theorem grundyValue_le_of_forall_moveLeft {G : PGame} {o : Ordinal} + (h : ∀ i, grundyValue (G.moveLeft i) ≠ o) : G.grundyValue ≤ o := by + contrapose! h + exact exists_grundyValue_moveLeft_of_lt h + +/-- The **Sprague-Grundy theorem** states that every impartial game is equivalent to a game of nim, +namely the game of nim corresponding to the game's Grundy value. -/ +theorem equiv_nim_grundyValue (G : PGame.{u}) [G.Impartial] : G ≈ nim (grundyValue G) := by + 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 : Ordinal} : - grundyValue G = o ↔ (G ≈ nim o) := + grundyValue G = o ↔ G ≈ nim 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⟩ @@ -294,58 +295,77 @@ 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. +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 : Ordinal} + (h : Set.Iio o ⊆ Set.range (grundyValue ∘ G.moveRight)) : o ≤ grundyValue G := by + by_contra! ho + obtain ⟨i, hi⟩ := h ho + exact grundyValue_ne_moveRight i hi + +theorem exists_grundyValue_moveRight_of_lt {G : PGame} [G.Impartial] {o : Ordinal} + (h : o < grundyValue G) : ∃ i, grundyValue (G.moveRight i) = o := by + rw [← grundyValue_neg] at h + obtain ⟨i, hi⟩ := exists_grundyValue_moveLeft_of_lt h + use toLeftMovesNeg.symm i + rwa [← grundyValue_neg, ← moveLeft_neg'] + +theorem grundyValue_le_of_forall_moveRight {G : PGame} [G.Impartial] {o : Ordinal} + (h : ∀ i, grundyValue (G.moveRight i) ≠ o) : G.grundyValue ≤ o := by + contrapose! h + exact exists_grundyValue_moveRight_of_lt h + +-- Todo: redefine `grundyValue` as a nimber, and prove `grundyValue (nim a + nim b) = a + b` for all +-- nimbers. + /-- The Grundy value of the sum of two nim games with natural numbers of piles equals their bitwise xor. -/ @[simp] -theorem grundyValue_nim_add_nim (n m : ℕ) : - grundyValue (nim.{u} n + nim.{u} m) = n ^^^ m := by - -- 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 grundyValue_nim_add_nim (n m : ℕ) : grundyValue (nim.{u} n + nim.{u} m) = n ^^^ m := by + apply (grundyValue_le_of_forall_moveLeft _).antisymm (le_grundyValue_of_Iio_subset_moveLeft _) + -- Since XOR is injective, no left moves of `nim n + nim m` will have `n ^^^ m` as a Grundy value. + · intro i + apply leftMoves_add_cases i + all_goals + intro j + have hj := toLeftMovesNim_symm_lt j + obtain ⟨k, hk⟩ := lt_omega0.1 (hj.trans (nat_lt_omega0 _)) + rw [hk, Nat.cast_lt] at hj + have := hj.ne + have := hj -- The termination checker doesn't work without this. + · rwa [add_moveLeft_inl, moveLeft_nim', ne_eq, hk, grundyValue_nim_add_nim, Nat.cast_inj, + Nat.xor_left_inj] + · rwa [add_moveLeft_inr, moveLeft_nim', ne_eq, hk, grundyValue_nim_add_nim, Nat.cast_inj, + Nat.xor_right_inj] + -- For any `k < n ^^^ m`, either `nim (k ^^^ m) + nim m` or `nim n + nim (k ^^^ n)` is a left + -- option with Grundy value `k`. + · intro k hk + obtain ⟨k, rfl⟩ := Ordinal.lt_omega0.1 (hk.trans (Ordinal.nat_lt_omega0 _)) + rw [Set.mem_Iio, Nat.cast_lt] at hk + obtain hk | hk := Nat.lt_xor_cases hk <;> rw [← natCast_lt] at hk + · use toLeftMovesAdd (Sum.inl (toLeftMovesNim ⟨_, hk⟩)) + rw [Function.comp_apply, add_moveLeft_inl, moveLeft_nim', Equiv.symm_apply_apply, + grundyValue_nim_add_nim, Nat.xor_cancel_right] + · use toLeftMovesAdd (Sum.inr (toLeftMovesNim ⟨_, hk⟩)) + rw [Function.comp_apply, add_moveLeft_inr, moveLeft_nim', Equiv.symm_apply_apply, + grundyValue_nim_add_nim, Nat.xor_comm, Nat.xor_cancel_right] +termination_by (n, m) theorem nim_add_nim_equiv {n m : ℕ} : nim n + nim m ≈ nim (n ^^^ m) := by rw [← grundyValue_eq_iff_equiv_nim, grundyValue_nim_add_nim] diff --git a/Mathlib/SetTheory/Game/Ordinal.lean b/Mathlib/SetTheory/Game/Ordinal.lean index f5a9f99f65e82..b04e1d965c6ca 100644 --- a/Mathlib/SetTheory/Game/Ordinal.lean +++ b/Mathlib/SetTheory/Game/Ordinal.lean @@ -30,26 +30,20 @@ open scoped NaturalOps PGame namespace Ordinal /-- Converts an ordinal into the corresponding pre-game. -/ -noncomputable def toPGame : Ordinal.{u} → PGame.{u} - | o => - have : IsWellOrder o.out.α (· < ·) := isWellOrder_out_lt o - ⟨o.out.α, PEmpty, fun x => - have := Ordinal.typein_lt_self x - (typein (· < ·) x).toPGame, - PEmpty.elim⟩ -termination_by x => x +noncomputable def toPGame (o : Ordinal.{u}) : PGame.{u} := + ⟨o.toType, PEmpty, fun x => ((enumIsoToType o).symm x).val.toPGame, PEmpty.elim⟩ +termination_by o +decreasing_by exact ((enumIsoToType o).symm x).prop -@[nolint unusedHavesSuffices] -theorem toPGame_def (o : Ordinal) : - have : IsWellOrder o.out.α (· < ·) := isWellOrder_out_lt o - o.toPGame = ⟨o.out.α, PEmpty, fun x => (typein (· < ·) x).toPGame, PEmpty.elim⟩ := by +theorem toPGame_def (o : Ordinal) : o.toPGame = + ⟨o.toType, PEmpty, fun x => ((enumIsoToType o).symm x).val.toPGame, PEmpty.elim⟩ := by rw [toPGame] -@[simp, nolint unusedHavesSuffices] -theorem toPGame_leftMoves (o : Ordinal) : o.toPGame.LeftMoves = o.out.α := by +@[simp] +theorem toPGame_leftMoves (o : Ordinal) : o.toPGame.LeftMoves = o.toType := by rw [toPGame, LeftMoves] -@[simp, nolint unusedHavesSuffices] +@[simp] theorem toPGame_rightMoves (o : Ordinal) : o.toPGame.RightMoves = PEmpty := by rw [toPGame, RightMoves] @@ -62,7 +56,7 @@ instance isEmpty_toPGame_rightMoves (o : Ordinal) : IsEmpty o.toPGame.RightMoves /-- Converts an ordinal less than `o` into a move for the `PGame` corresponding to `o`, and vice versa. -/ noncomputable def toLeftMovesToPGame {o : Ordinal} : Set.Iio o ≃ o.toPGame.LeftMoves := - (enumIsoOut o).toEquiv.trans (Equiv.cast (toPGame_leftMoves o).symm) + (enumIsoToType o).toEquiv.trans (Equiv.cast (toPGame_leftMoves o).symm) @[simp] theorem toLeftMovesToPGame_symm_lt {o : Ordinal} (i : o.toPGame.LeftMoves) : @@ -71,8 +65,7 @@ theorem toLeftMovesToPGame_symm_lt {o : Ordinal} (i : o.toPGame.LeftMoves) : @[nolint unusedHavesSuffices] theorem toPGame_moveLeft_hEq {o : Ordinal} : - have : IsWellOrder o.out.α (· < ·) := isWellOrder_out_lt o - HEq o.toPGame.moveLeft fun x : o.out.α => (typein (· < ·) x).toPGame := by + HEq o.toPGame.moveLeft fun x : o.toType => ((enumIsoToType o).symm x).val.toPGame := by rw [toPGame] rfl @@ -207,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 4452aab15c7dd..a6b6ae996bb57 100644 --- a/Mathlib/SetTheory/Game/PGame.lean +++ b/Mathlib/SetTheory/Game/PGame.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 +Authors: Reid Barton, Mario Carneiro, Isabel Longbottom, Kim Morrison -/ import Mathlib.Algebra.Order.ZeroLEOne import Mathlib.Data.List.InsertNth @@ -216,9 +216,9 @@ theorem wf_isOption : WellFounded IsOption := ⟨fun x => moveRecOn x fun x IHl IHr => Acc.intro x fun y h => by - induction' h with _ i _ j - · exact IHl i - · exact IHr j⟩ + induction h with + | moveLeft i => exact IHl i + | moveRight j => exact IHr j⟩ /-- `Subsequent x y` says that `x` can be obtained by playing some nonempty sequence of moves from `y`. It is the transitive closure of `IsOption`. -/ @@ -458,7 +458,7 @@ private theorem le_trans_aux {x y z : PGame} instance : Preorder PGame := { PGame.le with le_refl := fun x => by - induction' x with _ _ _ _ IHl IHr + induction x with | mk _ _ _ _ IHl IHr => _ exact le_of_forall_lf (fun i => lf_of_le_moveLeft (IHl i)) fun i => lf_of_moveRight_le (IHr i) le_trans := by @@ -644,7 +644,7 @@ theorem leftResponse_spec {x : PGame} (h : 0 ≤ x) (j : x.RightMoves) : /-- A small family of pre-games is bounded above. -/ lemma bddAbove_range_of_small {ι : Type*} [Small.{u} ι] (f : ι → PGame.{u}) : BddAbove (Set.range f) := by - let x : PGame.{u} := ⟨Σ i, (f $ (equivShrink.{u} ι).symm i).LeftMoves, PEmpty, + let x : PGame.{u} := ⟨Σ i, (f <| (equivShrink.{u} ι).symm i).LeftMoves, PEmpty, fun x ↦ moveLeft _ x.2, PEmpty.elim⟩ refine ⟨x, Set.forall_mem_range.2 fun i ↦ ?_⟩ rw [← (equivShrink ι).symm_apply_apply i, le_iff_forall_lf] @@ -657,7 +657,7 @@ lemma bddAbove_of_small (s : Set PGame.{u}) [Small.{u} s] : BddAbove s := by /-- A small family of pre-games is bounded below. -/ lemma bddBelow_range_of_small {ι : Type*} [Small.{u} ι] (f : ι → PGame.{u}) : BddBelow (Set.range f) := by - let x : PGame.{u} := ⟨PEmpty, Σ i, (f $ (equivShrink.{u} ι).symm i).RightMoves, PEmpty.elim, + let x : PGame.{u} := ⟨PEmpty, Σ i, (f <| (equivShrink.{u} ι).symm i).RightMoves, PEmpty.elim, fun x ↦ moveRight _ x.2⟩ refine ⟨x, Set.forall_mem_range.2 fun i ↦ ?_⟩ rw [← (equivShrink ι).symm_apply_apply i, le_iff_forall_lf] @@ -682,7 +682,7 @@ instance : IsEquiv _ PGame.Equiv where trans := fun _ _ _ ⟨xy, yx⟩ ⟨yz, zy⟩ => ⟨xy.trans yz, zy.trans yx⟩ symm _ _ := And.symm --- Porting note: moved the setoid instance from Basic.lean to here +-- Porting note: moved the setoid instance from Basic.lean to here instance setoid : Setoid PGame := ⟨Equiv, refl, symm, Trans.trans⟩ @@ -828,13 +828,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`. -/ @@ -1268,8 +1270,8 @@ theorem zero_fuzzy_neg_iff {x : PGame} : 0 ‖ -x ↔ 0 ‖ x := by rw [← neg_ /-- The sum of `x = {xL | xR}` and `y = {yL | yR}` is `{xL + y, x + yL | xR + y, x + yR}`. -/ instance : Add PGame.{u} := ⟨fun x y => by - induction' x with xl xr _ _ IHxl IHxr generalizing y - induction' y with yl yr yL yR IHyl IHyr + induction x generalizing y with | mk xl xr _ _ IHxl IHxr => _ + induction y with | mk yl yr yL yR IHyl IHyr => _ have y := mk yl yr yL yR refine ⟨xl ⊕ yl, xr ⊕ yr, Sum.rec ?_ ?_, Sum.rec ?_ ?_⟩ · exact fun i => IHxl i y @@ -1281,7 +1283,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⟩ @@ -1439,9 +1442,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 := @@ -1840,15 +1845,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] @@ -1867,3 +1875,5 @@ theorem zero_lf_one : (0 : PGame) ⧏ 1 := end PGame end SetTheory + +set_option linter.style.longFile 1900 diff --git a/Mathlib/SetTheory/Game/Short.lean b/Mathlib/SetTheory/Game/Short.lean index f067239a8a277..03c8ecbda2c5b 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 => @@ -175,8 +175,8 @@ class inductive ListShort : List PGame.{u} → Type (u + 1) attribute [instance] ListShort.nil -instance ListShort.cons (hd : PGame.{u}) [short_hd : Short hd] - (tl : List PGame.{u}) [short_tl : ListShort tl] : +instance ListShort.cons + (hd : PGame.{u}) [short_hd : Short hd] (tl : List PGame.{u}) [short_tl : ListShort tl] : ListShort (hd::tl) := cons' short_hd short_tl @@ -188,9 +188,7 @@ instance listShortGet : instance shortOfLists : ∀ (L R : List PGame) [ListShort L] [ListShort R], Short (PGame.ofLists L R) | L, R, _, _ => by - apply Short.mk - · intros; infer_instance - · intros; apply PGame.listShortGet + exact Short.mk (fun i ↦ inferInstance) fun j ↦ listShortGet R (↑j.down) (ofLists.proof_2 R j) /-- If `x` is a short game, and `y` is a relabelling of `x`, then `y` is also short. -/ def shortOfRelabelling : ∀ {x y : PGame.{u}}, Relabelling x y → Short x → Short y @@ -236,21 +234,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) := @@ -260,10 +262,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..d7871744adc58 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 diff --git a/Mathlib/SetTheory/Lists.lean b/Mathlib/SetTheory/Lists.lean index efd26b100c4e1..cd2aeac9c7722 100644 --- a/Mathlib/SetTheory/Lists.lean +++ b/Mathlib/SetTheory/Lists.lean @@ -129,7 +129,7 @@ instance : HasSubset (Lists' α true) := /-- ZFA prelist membership. A ZFA list is in a ZFA prelist if some element of this ZFA prelist is equivalent as a ZFA list to this ZFA list. -/ instance {b} : Membership (Lists α) (Lists' α b) := - ⟨fun a l => ∃ a' ∈ l.toList, a ~ a'⟩ + ⟨fun l a => ∃ a' ∈ l.toList, a ~ a'⟩ theorem mem_def {b a} {l : Lists' α b} : a ∈ l ↔ ∃ a' ∈ l.toList, a ~ a' := Iff.rfl @@ -148,9 +148,11 @@ theorem cons_subset {a} {l₁ l₂ : Lists' α true} : Lists'.cons a l₁ ⊆ l theorem ofList_subset {l₁ l₂ : List (Lists α)} (h : l₁ ⊆ l₂) : Lists'.ofList l₁ ⊆ Lists'.ofList l₂ := by - induction' l₁ with _ _ l₁_ih; · exact Subset.nil - refine Subset.cons (Lists.Equiv.refl _) ?_ (l₁_ih (List.subset_of_cons_subset h)) - simp only [List.cons_subset] at h; simp [h] + induction l₁ with + | nil => exact Subset.nil + | cons _ _ l₁_ih => + refine Subset.cons (Lists.Equiv.refl _) ?_ (l₁_ih (List.subset_of_cons_subset h)) + simp only [List.cons_subset] at h; simp [h] @[refl] theorem Subset.refl {l : Lists' α true} : l ⊆ l := by @@ -246,8 +248,8 @@ def mem (a : Lists α) : Lists α → Prop | ⟨false, _⟩ => False | ⟨_, l⟩ => a ∈ l -instance : Membership (Lists α) (Lists α) := - ⟨mem⟩ +instance : Membership (Lists α) (Lists α) where + mem ls l := mem l ls theorem isList_of_mem {a : Lists α} : ∀ {l : Lists α}, a ∈ l → IsList l | ⟨_, Lists'.nil⟩, _ => rfl @@ -299,16 +301,6 @@ instance instSetoidLists : Setoid (Lists α) := section Decidable -/-- Auxiliary function to prove termination of decidability checking -/ -@[simp, deprecated (since := "2023-06-24")] -def Equiv.decidableMeas : - ((Σ' _l₁ : Lists α, Lists α) ⊕' - ((Σ' _l₁ : Lists' α true, Lists' α true) ⊕' (Σ' _a : Lists α, Lists' α true))) → - ℕ - | PSum.inl ⟨l₁, l₂⟩ => SizeOf.sizeOf l₁ + SizeOf.sizeOf l₂ - | PSum.inr <| PSum.inl ⟨l₁, l₂⟩ => SizeOf.sizeOf l₁ + SizeOf.sizeOf l₂ - | PSum.inr <| PSum.inr ⟨l₁, l₂⟩ => SizeOf.sizeOf l₁ + SizeOf.sizeOf l₂ - theorem sizeof_pos {b} (l : Lists' α b) : 0 < SizeOf.sizeOf l := by cases l <;> simp only [Lists'.atom.sizeOf_spec, Lists'.nil.sizeOf_spec, Lists'.cons'.sizeOf_spec, true_or, add_pos_iff, zero_lt_one] diff --git a/Mathlib/SetTheory/Ordinal/Arithmetic.lean b/Mathlib/SetTheory/Ordinal/Arithmetic.lean index 42eadc412c344..c98fcecd35665 100644 --- a/Mathlib/SetTheory/Ordinal/Arithmetic.lean +++ b/Mathlib/SetTheory/Ordinal/Arithmetic.lean @@ -40,7 +40,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 +60,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 +76,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 add_contravariantClass_le : + ContravariantClass Ordinal.{u} Ordinal.{u} (· + ·) (· ≤ ·) where + elim c a b := by + refine inductionOn₃ a b c fun α r _ β s _ γ t _ ⟨f⟩ ↦ ?_ + have H₁ a : f (Sum.inl a) = Sum.inl a := by + simpa using ((InitialSeg.leAdd t r).trans f).eq (InitialSeg.leAdd t s) a + have H₂ a : ∃ b, f (Sum.inr a) = Sum.inr b := by + generalize hx : f (Sum.inr a) = x + obtain x | x := x + · rw [← H₁, f.inj] at hx + contradiction + · exact ⟨x, rfl⟩ + choose g hg using H₂ + refine (RelEmbedding.ofMonotone g fun _ _ h ↦ ?_).ordinal_type_le + rwa [← @Sum.lex_inr_inr _ t _ s, ← hg, ← hg, f.map_rel_iff, Sum.lex_inr_inr] theorem add_left_cancel (a) {b c : Ordinal} : a + b = a + c ↔ b = c := by simp only [le_antisymm_iff, add_le_add_iff_left] @@ -117,14 +99,14 @@ private theorem add_lt_add_iff_left' (a) {b c : Ordinal} : a + b < a + c ↔ b < 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⟩ + ⟨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⟩ + ⟨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 _⟩ + ⟨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] @@ -212,16 +193,25 @@ 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 -theorem IsLimit.isSuccLimit {o} (h : IsLimit o) : IsSuccLimit o := isSuccLimit_iff_succ_lt.mpr h.2 +theorem IsLimit.isSuccPrelimit {o} (h : IsLimit o) : IsSuccPrelimit o := + isSuccPrelimit_iff_succ_lt.mpr h.2 + +@[deprecated IsLimit.isSuccPrelimit (since := "2024-09-05")] +alias IsLimit.isSuccLimit := IsLimit.isSuccPrelimit theorem IsLimit.succ_lt {o a : Ordinal} (h : IsLimit o) : a < o → succ a < o := h.2 a -theorem isSuccLimit_zero : IsSuccLimit (0 : Ordinal) := isSuccLimit_bot +theorem isSuccPrelimit_zero : IsSuccPrelimit (0 : Ordinal) := isSuccPrelimit_bot + +@[deprecated isSuccPrelimit_zero (since := "2024-09-05")] +alias isSuccLimit_zero := isSuccPrelimit_zero theorem not_zero_isLimit : ¬IsLimit 0 | ⟨h, _⟩ => h rfl @@ -277,71 +267,109 @@ theorem zero_or_succ_or_limit (o : Ordinal) : o = 0 ∨ (∃ a, o = succ a) ∨ @[elab_as_elim] def limitRecOn {C : Ordinal → Sort*} (o : Ordinal) (H₁ : C 0) (H₂ : ∀ o, C o → C (succ o)) (H₃ : ∀ o, IsLimit o → (∀ o' < o, C o') → C o) : C o := - SuccOrder.limitRecOn o (fun o _ ↦ H₂ o) fun o hl ↦ + SuccOrder.prelimitRecOn o (fun o _ ↦ H₂ o) fun o hl ↦ if h : o = 0 then fun _ ↦ h ▸ H₁ else H₃ o ⟨h, fun _ ↦ hl.succ_lt⟩ @[simp] theorem limitRecOn_zero {C} (H₁ H₂ H₃) : @limitRecOn C 0 H₁ H₂ H₃ = H₁ := by - rw [limitRecOn, SuccOrder.limitRecOn_limit _ _ isSuccLimit_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 - simp_rw [limitRecOn, SuccOrder.limitRecOn_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.limitRecOn_limit _ _ h.isSuccLimit, 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 -instance orderTopOutSucc (o : Ordinal) : OrderTop (succ o).out.α := +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 (· < ·) o - (by - rw [type_lt] - exact lt_succ o) = - (⊤ : (succ o).out.α) := + enum (α := (succ o).toType) (· < ·) ⟨o, by rw [type_lt]; exact lt_succ o⟩ = ⊤ := rfl theorem has_succ_of_type_succ_lt {α} {r : α → α → Prop} [wo : IsWellOrder α r] (h : ∀ a < type r, succ a < type r) (x : α) : ∃ y, r x y := by - use enum r (succ (typein r x)) (h _ (typein_lt_type r x)) - convert (enum_lt_enum (typein_lt_type r x) - (h _ (typein_lt_type r x))).mpr (lt_succ _); rw [enum_typein] + use enum r ⟨succ (typein r x), h _ (typein_lt_type r x)⟩ + convert enum_lt_enum (o₁ := ⟨_, typein_lt_type r x⟩) (o₂ := ⟨_, h _ (typein_lt_type r x)⟩).mpr _ + · rw [enum_typein] + · rw [Subtype.mk_lt_mk, lt_succ_iff] -theorem out_no_max_of_succ_lt {o : Ordinal} (ho : ∀ a < o, succ a < o) : NoMaxOrder o.out.α := +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])⟩ +@[deprecated toType_noMax_of_succ_lt (since := "2024-08-26")] +alias out_no_max_of_succ_lt := toType_noMax_of_succ_lt + theorem bounded_singleton {r : α → α → Prop} [IsWellOrder α r] (hr : (type r).IsLimit) (x) : Bounded r {x} := by - refine ⟨enum r (succ (typein r x)) (hr.2 _ (typein_lt_type r x)), ?_⟩ + refine ⟨enum r ⟨succ (typein r x), hr.2 _ (typein_lt_type r x)⟩, ?_⟩ intro b hb rw [mem_singleton_iff.1 hb] nth_rw 1 [← enum_typein r x] - rw [@enum_lt_enum _ r] + 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 → Ordinal → Prop) { 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 - -- Porting note: `symm; refine' [term]` → `refine' [term].symm` - constructor; refine ((RelIso.preimage Equiv.ulift r).trans (enumIso r).symm).symm + 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 -/ /-- A normal ordinal function is a strictly increasing function which is order-continuous, i.e., the image `f o` of a limit ordinal `o` is the sup of `f a` for - `a < o`. -/ + `a < o`. -/ def IsNormal (f : Ordinal → Ordinal) : Prop := (∀ o, f o < f (succ o)) ∧ ∀ o, IsLimit o → ∀ a, f o ≤ a ↔ ∀ b < o, f b ≤ a @@ -377,8 +405,18 @@ 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 := @@ -414,9 +452,6 @@ 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 => le_of_not_lt <| by @@ -426,11 +461,11 @@ theorem add_le_of_limit {a b c : Ordinal} (h : IsLimit b) : a + b ≤ c ↔ ∀ induction b using inductionOn with | H β s => intro l - suffices ∀ x : β, Sum.Lex r s (Sum.inr x) (enum _ _ l) by + suffices ∀ x : β, Sum.Lex r s (Sum.inr x) (enum _ ⟨_, l⟩) by -- Porting note: `revert` & `intro` is required because `cases'` doesn't replace -- `enum _ _ l` in `this`. - revert this; cases' enum _ _ l with x x <;> intro this - · cases this (enum s 0 h.pos) + revert this; cases' enum _ ⟨_, l⟩ with x x <;> intro this + · cases this (enum s ⟨0, h.pos⟩) · exact irrefl _ (this _) intro x rw [← typein_lt_typein (Sum.Lex r s), typein_enum] @@ -452,11 +487,11 @@ theorem add_isLimit (a) {b} : IsLimit b → IsLimit (a + b) := alias IsLimit.add := add_isLimit -/-! ### Subtraction on ordinals-/ +/-! ### Subtraction on ordinals -/ /-- 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,9 +559,9 @@ theorem sub_isLimit {a b} (l : IsLimit a) (h : b < a) : IsLimit (a - b) := 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 +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 @@ -535,11 +570,17 @@ 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] -/-! ### Multiplication of ordinals-/ +@[deprecated (since := "2024-09-30")] +alias one_add_of_omega_le := one_add_of_omega0_le + +/-! ### Multiplication of ordinals -/ /-- The multiplication of ordinals `o₁` and `o₂` is the (well founded) lexicographic order on @@ -565,15 +606,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] @@ -615,11 +656,10 @@ instance leftDistribClass : LeftDistribClass Ordinal.{u} := Quotient.sound ⟨⟨sumProdDistrib _ _ _, by rintro ⟨a₁ | a₁, a₂⟩ ⟨b₁ | b₁, b₂⟩ <;> - 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] <;> + 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 @@ -654,8 +694,8 @@ theorem le_mul_right (a : Ordinal) {b : Ordinal} (hb : 0 < b) : a ≤ b * a := b private theorem mul_le_of_limit_aux {α β r s} [IsWellOrder α r] [IsWellOrder β s] {c} (h : IsLimit (type s)) (H : ∀ b' < type s, type r * b' ≤ c) (l : c < type r * type s) : False := by - suffices ∀ a b, Prod.Lex s r (b, a) (enum _ _ l) by - cases' enum _ _ l with b a + suffices ∀ a b, Prod.Lex s r (b, a) (enum _ ⟨_, l⟩) by + cases' enum _ ⟨_, l⟩ with b a exact irrefl _ (this _ _) intro a b rw [← typein_lt_typein (Prod.Lex s r), typein_enum] @@ -679,11 +719,11 @@ 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, @@ -750,20 +790,20 @@ 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)⟩ /-- `a / b` is the unique ordinal `o` satisfying `a = b * o + o'` with `o' < b`. -/ instance div : Div Ordinal := - ⟨fun a b => if _h : b = 0 then 0 else sInf { o | a < b * succ o }⟩ + ⟨fun a b => if b = 0 then 0 else sInf { o | a < b * succ o }⟩ @[simp] 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 @@ -787,8 +827,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 @@ -824,6 +863,26 @@ theorem div_eq_zero_of_lt {a b : Ordinal} (h : a < b) : a / b = 0 := by theorem mul_div_cancel (a) {b : Ordinal} (b0 : b ≠ 0) : b * a / b = a := by simpa only [add_zero, zero_div] using mul_add_div a b0 0 +theorem mul_add_div_mul {a c : Ordinal} (hc : c < a) (b d : Ordinal) : + (a * b + c) / (a * d) = b / d := by + have ha : a ≠ 0 := ((Ordinal.zero_le c).trans_lt hc).ne' + obtain rfl | hd := eq_or_ne d 0 + · rw [mul_zero, div_zero, div_zero] + · have H := mul_ne_zero ha hd + apply le_antisymm + · rw [← lt_succ_iff, div_lt H, mul_assoc] + · apply (add_lt_add_left hc _).trans_le + rw [← mul_succ] + apply mul_le_mul_left' + rw [succ_le_iff] + exact lt_mul_succ_div b hd + · rw [le_div H, mul_assoc] + exact (mul_le_mul_left' (mul_div_le b d) a).trans (le_add_right _ c) + +theorem mul_div_mul_cancel {a : Ordinal} (ha : a ≠ 0) (b c) : a * b / (a * c) = b / c := by + convert mul_add_div_mul (Ordinal.pos_iff_ne_zero.2 ha) b c using 1 + rw [add_zero] + @[simp] theorem div_one (a : Ordinal) : a / 1 = a := by simpa only [one_mul] using mul_div_cancel a Ordinal.one_ne_zero @@ -936,6 +995,18 @@ theorem mul_add_mod_self (x y z : Ordinal) : (x * y + z) % x = z % x := by theorem mul_mod (x y : Ordinal) : x * y % x = 0 := by simpa using mul_add_mod_self x y 0 +theorem mul_add_mod_mul {w x : Ordinal} (hw : w < x) (y z : Ordinal) : + (x * y + w) % (x * z) = x * (y % z) + w := by + rw [mod_def, mul_add_div_mul hw] + apply sub_eq_of_add_eq + rw [← add_assoc, mul_assoc, ← mul_add, div_add_mod] + +theorem mul_mod_mul (x y z : Ordinal) : (x * y) % (x * z) = x * (y % z) := by + obtain rfl | hx := Ordinal.eq_zero_or_pos x + · simp + · convert mul_add_mod_mul hx y z using 1 <;> + rw [add_zero] + theorem mod_mod_of_dvd (a : Ordinal) {b c : Ordinal} (h : c ∣ b) : a % b % c = a % c := by nth_rw 2 [← div_add_mod a b] rcases h with ⟨d, rfl⟩ @@ -958,7 +1029,7 @@ claim on the other. -/ /-- Converts a family indexed by a `Type u` to one indexed by an `Ordinal.{u}` using a specified well-ordering. -/ def bfamilyOfFamily' {ι : Type u} (r : ι → ι → Prop) [IsWellOrder ι r] (f : ι → α) : - ∀ a < type r, α := fun a ha => f (enum r a ha) + ∀ a < type r, α := fun a ha => f (enum r ⟨a, ha⟩) /-- Converts a family indexed by a `Type u` to one indexed by an `Ordinal.{u}` using a well-ordering given by the axiom of choice. -/ @@ -976,7 +1047,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.out.α → α := +def familyOfBFamily (o : Ordinal) (f : ∀ a < o, α) : o.toType → α := familyOfBFamily' (· < ·) (type_lt o) f @[simp] @@ -992,17 +1063,12 @@ theorem bfamilyOfFamily_typein {ι} (f : ι → α) (i) : @[simp, nolint simpNF] -- Porting note (#10959): simp cannot prove this theorem familyOfBFamily'_enum {ι : Type u} (r : ι → ι → Prop) [IsWellOrder ι r] {o} (ho : type r = o) (f : ∀ a < o, α) (i hi) : - familyOfBFamily' r ho f (enum r i (by rwa [ho])) = f i hi := by + familyOfBFamily' r ho f (enum r ⟨i, by rwa [ho]⟩) = f i hi := by simp only [familyOfBFamily', typein_enum] @[simp, nolint simpNF] -- Porting note (#10959): simp cannot prove this theorem familyOfBFamily_enum (o : Ordinal) (f : ∀ a < o, α) (i hi) : - familyOfBFamily o f - (enum (· < ·) i - (by - convert hi - exact type_lt _)) = - f i hi := + familyOfBFamily o f (enum (α := o.toType) (· < ·) ⟨i, hi.trans_eq (type_lt _).symm⟩) = f i hi := familyOfBFamily'_enum _ (type_lt o) f _ _ /-- The range of a family indexed by ordinals. -/ @@ -1044,7 +1110,7 @@ theorem brange_bfamilyOfFamily {ι : Type u} (f : ι → α) : brange _ (bfamily @[simp] theorem brange_const {o : Ordinal} (ho : o ≠ 0) {c : α} : (brange o fun _ _ => c) = {c} := by rw [← range_familyOfBFamily] - exact @Set.range_const _ o.out.α (out_nonempty_iff_ne_zero.2 ho) c + exact @Set.range_const _ o.toType (toType_nonempty_iff_ne_zero.2 ho) c theorem comp_bfamilyOfFamily' {ι : Type u} (r : ι → ι → Prop) [IsWellOrder ι r] (f : ι → α) (g : α → β) : (fun i hi => g (bfamilyOfFamily' r f i hi)) = bfamilyOfFamily' r (g ∘ f) := @@ -1065,13 +1131,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 @@ -1083,29 +1150,83 @@ theorem bddAbove_range {ι : Type u} (f : ι → Ordinal.{max u v}) : BddAbove ( exact le_of_lt (Cardinal.lt_ord.2 ((lt_succ _).trans_le (le_ciSup (Cardinal.bddAbove_range.{_, v} _) _)))⟩ +/-- `le_ciSup` whenever the outputs live in a higher universe than the inputs. -/ +protected theorem le_iSup {ι : Type u} (f : ι → Ordinal.{max u v}) : ∀ i, f i ≤ iSup f := + le_ciSup (bddAbove_range f) + +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 outputs live in a higher universe than the inputs. -/ +protected theorem iSup_le_iff {ι : Type u} {f : ι → Ordinal.{max u v}} {a} : + iSup f ≤ a ↔ ∀ i, f i ≤ a := + ciSup_le_iff' (bddAbove_range f) + +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 + +/-- `ciSup_le'` whenever the outputs live in a higher universe than the inputs. -/ +protected theorem iSup_le {ι : Type u} {f : ι → Ordinal.{max u v}} {a} : + (∀ 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 +-- TODO: generalize to conditionally complete linear orders. +protected theorem lt_iSup {ι : Type u} {f : ι → Ordinal.{max u v}} {a} : + a < iSup f ↔ ∃ i, a < f i := by + rw [← not_iff_not] + simpa using Ordinal.iSup_le_iff + +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 {ι : Type u} {f : ι → Ordinal.{max u v}} + (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 {ι : Type u} {f : ι → Ordinal.{max u v}} : + 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 @@ -1114,35 +1235,71 @@ theorem sup_eq_zero_iff {ι : Type u} {f : ι → Ordinal.{max u v}} : rw [← Ordinal.le_zero, ← h] exact le_sup f i +-- TODO: generalize universes, make sSup version. +theorem IsNormal.map_iSup {f : Ordinal.{max u v} → Ordinal.{max u w}} (H : IsNormal f) {ι : Type u} + (g : ι → Ordinal.{max u v}) [Nonempty ι] : f (⨆ i, g i) = ⨆ i, f (g i) := by + apply eq_of_forall_ge_iff + intro a + rw [H.le_set' Set.univ Set.univ_nonempty g] + · rw [Ordinal.iSup_le_iff] + simp + · intro o + rw [Ordinal.iSup_le_iff] + simp + +set_option linter.deprecated false in +@[deprecated IsNormal.map_iSup (since := "2024-08-27")] theorem IsNormal.sup {f : Ordinal.{max u v} → Ordinal.{max u w}} (H : IsNormal f) {ι : Type u} (g : ι → Ordinal.{max u v}) [Nonempty ι] : f (sup.{_, v} g) = sup.{_, w} (f ∘ g) := - 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] + H.map_iSup g -@[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 {α : Type u} {β : Type v} (f : α ⊕ β → Ordinal.{max u v w}) : + iSup f = max (⨆ a, f (Sum.inl a)) (⨆ b, f (Sum.inr b)) := by + apply (Ordinal.iSup_le _).antisymm (max_le _ _) + · rintro (i | i) + · exact le_max_of_le_left (Ordinal.le_iSup.{u, max u v w} _ i) + · exact le_max_of_le_right (Ordinal.le_iSup.{v, max u v w} _ i) + all_goals + apply csSup_le_csSup' (bddAbove_range _) + 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 @@ -1155,41 +1312,40 @@ 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.out.α → Set.Iio o := - fun x => ⟨typein ((· < ·) : o.out.α → o.out.α → Prop) x, typein_lt_self x⟩ - let hf : Surjective f := fun b => - ⟨enum (· < ·) b.val - (by - rw [type_lt] - exact b.prop), - Subtype.ext (typein_enum _ _)⟩ - small_of_surjective hf +-- TODO: move this together with `bddAbove_range`. -instance small_Iic (o : Ordinal.{u}) : Small.{u} (Set.Iic o) := by - rw [← Iio_succ] - infer_instance +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 _x hx => h hx, fun h => - ⟨sup.{u, u} fun x => ((@equivShrink s h).symm x).val, le_sup_shrink_equiv h⟩⟩ - -theorem bddAbove_of_small (s : Set Ordinal.{u}) [h : Small.{u} s] : BddAbove s := - bddAbove_iff_small.2 h + ⟨fun ⟨a, h⟩ => small_subset <| show s ⊆ Iic a from fun _ hx => h hx, fun _ => + bddAbove_of_small _⟩ +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 @@ -1211,6 +1367,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}) : @@ -1337,7 +1514,7 @@ theorem bsup_const {o : Ordinal.{u}} (ho : o ≠ 0) (a : Ordinal.{max u v}) : @[simp] theorem bsup_one (f : ∀ a < (1 : Ordinal), Ordinal) : bsup 1 f = f 0 zero_lt_one := by - simp_rw [← sup_eq_bsup, sup_unique, familyOfBFamily, familyOfBFamily', typein_one_out] + simp_rw [← sup_eq_bsup, sup_unique, familyOfBFamily, familyOfBFamily', typein_one_toType] theorem bsup_le_of_brange_subset {o o'} {f : ∀ a < o, Ordinal} {g : ∀ a < o', Ordinal} (h : brange o f ⊆ brange o' g) : bsup.{u, max v w} o f ≤ bsup.{v, max u w} o' g := @@ -1350,6 +1527,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) @@ -1468,25 +1652,25 @@ theorem nonempty_compl_range {ι : Type u} (f : ι → Ordinal.{max u v}) : (Set ⟨_, lsub_not_mem_range.{_, v} f⟩ @[simp] -theorem lsub_typein (o : Ordinal) : lsub.{u, u} (typein ((· < ·) : o.out.α → o.out.α → Prop)) = o := +theorem lsub_typein (o : Ordinal) : lsub.{u, u} (typein (α := o.toType) (· < ·)) = o := (lsub_le.{u, u} typein_lt_self).antisymm (by by_contra! h -- Porting note: `nth_rw` → `conv_rhs` & `rw` conv_rhs at h => rw [← type_lt o] - simpa [typein_enum] using lt_lsub.{u, u} (typein (· < ·)) (enum (· < ·) _ h)) + simpa [typein_enum] using lt_lsub.{u, u} (typein (· < ·)) (enum (· < ·) ⟨_, h⟩)) theorem sup_typein_limit {o : Ordinal} (ho : ∀ a, a < o → succ a < o) : - sup.{u, u} (typein ((· < ·) : o.out.α → o.out.α → Prop)) = o := by + sup.{u, u} (typein ((· < ·) : o.toType → o.toType → Prop)) = o := by -- Porting note: `rwa` → `rw` & `assumption` rw [(sup_eq_lsub_iff_succ.{u, u} (typein (· < ·))).2] <;> rw [lsub_typein o]; assumption @[simp] theorem sup_typein_succ {o : Ordinal} : - sup.{u, u} (typein ((· < ·) : (succ o).out.α → (succ o).out.α → Prop)) = o := by + sup.{u, u} (typein ((· < ·) : (succ o).toType → (succ o).toType → Prop)) = o := by cases' sup_eq_lsub_or_sup_succ_eq_lsub.{u, u} - (typein ((· < ·) : (succ o).out.α → (succ o).out.α → Prop)) with + (typein ((· < ·) : (succ o).toType → (succ o).toType → Prop)) with h h · rw [sup_eq_lsub_iff_succ] at h simp only [lsub_typein] at h @@ -1494,6 +1678,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}`. @@ -1610,7 +1802,7 @@ theorem blsub_succ_of_mono {o : Ordinal.{u}} {f : ∀ a < succ o, Ordinal.{max u @[simp] theorem blsub_eq_zero_iff {o} {f : ∀ a < o, Ordinal} : blsub o f = 0 ↔ o = 0 := by rw [← lsub_eq_blsub, lsub_eq_zero_iff] - exact out_empty_iff_eq_zero + exact toType_empty_iff_eq_zero -- Porting note: `rwa` → `rw` @[simp] @@ -1624,7 +1816,7 @@ theorem blsub_type {α : Type u} (r : α → α → Prop) [IsWellOrder α r] blsub.{_, v} (type r) f = lsub.{_, v} fun a => f (typein r a) (typein_lt_type _ _) := eq_of_forall_ge_iff fun o => by rw [blsub_le_iff, lsub_le_iff] - exact ⟨fun H b => H _ _, fun H i h => by simpa only [typein_enum] using H (enum r i h)⟩ + exact ⟨fun H b => H _ _, fun H i h => by simpa only [typein_enum] using H (enum r ⟨i, h⟩)⟩ theorem blsub_const {o : Ordinal} (ho : o ≠ 0) (a : Ordinal) : (blsub.{u, v} o fun _ _ => a) = succ a := @@ -1702,54 +1894,72 @@ theorem IsNormal.eq_iff_zero_and_succ {f g : Ordinal.{u} → Ordinal.{u}} (hf : (hg : IsNormal g) : f = g ↔ f 0 = g 0 ∧ ∀ a, f a = g a → f (succ a) = g (succ a) := ⟨fun h => by simp [h], fun ⟨h₁, h₂⟩ => funext fun a => by - induction' a using limitRecOn with _ _ _ ho H - any_goals solve_by_elim - rw [← IsNormal.bsup_eq.{u, u} hf ho, ← IsNormal.bsup_eq.{u, u} hg ho] - congr - ext b hb - exact H b hb⟩ + induction a using limitRecOn with + | H₁ => solve_by_elim + | H₂ => solve_by_elim + | H₃ _ ho H => + rw [← IsNormal.bsup_eq.{u, u} hf ho, ← IsNormal.bsup_eq.{u, u} hg ho] + congr + ext b hb + 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. -/ def blsub₂ (o₁ o₂ : Ordinal) (op : {a : Ordinal} → (a < o₁) → {b : Ordinal} → (b < o₂) → Ordinal) : Ordinal := - lsub (fun x : o₁.out.α × o₂.out.α => op (typein_lt_self x.1) (typein_lt_self x.2)) + lsub (fun x : o₁.toType × o₂.toType => op (typein_lt_self x.1) (typein_lt_self x.2)) +-- TODO: deprecate this, and replace the arguments using it by arguments about small sets. 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 - convert lt_lsub _ (Prod.mk (enum (· < ·) a (by rwa [type_lt])) - (enum (· < ·) b (by rwa [type_lt]))) + convert lt_lsub _ (Prod.mk (enum (· < ·) ⟨a, by rwa [type_lt]⟩) + (enum (· < ·) ⟨b, by rwa [type_lt]⟩)) simp only [typein_enum] +end blsub + +-- TODO: deprecate in favor of `sInf sᶜ`. + +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 => ?_ @@ -1757,68 +1967,80 @@ 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 apply (lt_succ #ι).not_le have H := fun a => exists_of_lt_mex ((typein_lt_self a).trans_le h) - let g : (succ #ι).ord.out.α → ι := fun a => Classical.choose (H a) + let g : (succ #ι).ord.toType → ι := fun a => Classical.choose (H a) have hg : Injective g := fun a b h' => by have Hf : ∀ x, f (g x) = - typein ((· < ·) : (succ #ι).ord.out.α → (succ #ι).ord.out.α → Prop) x := + typein ((· < ·) : (succ #ι).ord.toType → (succ #ι).ord.toType → Prop) x := fun a => Classical.choose_spec (H a) apply_fun f at h' rwa [Hf, Hf, typein_inj] at h' convert Cardinal.mk_le_of_injective hg - rw [Cardinal.mk_ord_out (succ #ι)] + rw [Cardinal.mk_ord_toType (succ #ι)] /-- The minimum excluded ordinal of a family of ordinals indexed by the set of ordinals less than some `o : Ordinal.{u}`. This is a special case of `mex` over the family provided by `familyOfBFamily`. 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}) - ne_mex.{_, v} (familyOfBFamily o f) (enum (· < ·) i (by rwa [type_lt])) using 2 + ne_mex.{_, v} (familyOfBFamily o f) (enum (α := o.toType) (· < ·) ⟨i, by rwa [type_lt]⟩) using 2 -- 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_ordinal_out] + rw [← mk_toType] exact mex_lt_ord_succ_mk (familyOfBFamily o f) +end mex + end Ordinal /-! ### Results about injectivity and surjectivity -/ @@ -1841,136 +2063,19 @@ 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 enumOrd_le_of_subset {S T : Set Ordinal} (hS : Unbounded (· < ·) S) (hST : S ⊆ T) (a) : - enumOrd T a ≤ enumOrd S a := by - apply Ordinal.induction a - intro b H - rw [enumOrd_def] - exact csInf_le' ⟨hST (enumOrd_mem hS b), fun c h => (H c h).trans_lt (enumOrd_strictMono hS h)⟩ - -theorem enumOrd_surjective (hS : Unbounded (· < ·) S) : ∀ s ∈ S, ∃ a, enumOrd S a = s := fun s hs => - ⟨sSup { a | enumOrd S a ≤ s }, by - apply le_antisymm - · rw [enumOrd_def] - refine csInf_le' ⟨hs, fun a ha => ?_⟩ - have : enumOrd S 0 ≤ s := by - rw [enumOrd_zero] - exact csInf_le' hs - -- Porting note: `flip` is required to infer a metavariable. - rcases flip exists_lt_of_lt_csSup ha ⟨0, this⟩ with ⟨b, hb, hab⟩ - exact (enumOrd_strictMono hS hab).trans_le hb - · by_contra! h - exact - (le_csSup ⟨s, fun a => (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 +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 /-! ### Casting naturals into ordinals, compatibility with operations -/ +namespace Ordinal + @[simp] theorem one_add_natCast (m : ℕ) : 1 + (m : Ordinal) = succ m := by rw [← Nat.cast_one, ← Nat.cast_add, add_comm] @@ -2084,7 +2189,7 @@ theorem lift_ofNat (n : ℕ) [n.AtLeastTwo] : end Ordinal -/-! ### Properties of `omega` -/ +/-! ### Properties of ω -/ namespace Cardinal @@ -2101,7 +2206,7 @@ theorem ord_aleph0 : ord.{u} ℵ₀ = ω := @[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 @@ -2113,34 +2218,61 @@ theorem lt_add_of_limit {a b c : Ordinal.{u}} (h : IsLimit c) : -- Porting note: `bex_def` is required. rw [← IsNormal.bsup_eq.{u, u} (add_isNormal 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 omega_ne_zero : ω ≠ 0 := - omega_pos.ne' +theorem omega0_ne_zero : ω ≠ 0 := + omega0_pos.ne' -theorem one_lt_omega : 1 < ω := by simpa only [Nat.cast_one] using nat_lt_omega 1 +@[deprecated (since := "2024-09-30")] +alias omega_ne_zero := omega0_ne_zero -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)⟩ +theorem one_lt_omega0 : 1 < ω := by simpa only [Nat.cast_one] using nat_lt_omega0 1 -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 one_lt_omega := one_lt_omega0 + +theorem omega0_isLimit : IsLimit ω := + ⟨omega0_ne_zero, fun o h => by + let ⟨n, e⟩ := lt_omega0.1 h + rw [e]; exact nat_lt_omega0 (n + 1)⟩ + +@[deprecated (since := "2024-09-30")] +alias omega_isLimit := omega0_isLimit + +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 @@ -2149,24 +2281,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 + +@[deprecated (since := "2024-09-30")] +alias omega_le_of_isLimit := omega0_le_of_isLimit -theorem isLimit_iff_omega_dvd {a : Ordinal} : IsLimit a ↔ a ≠ 0 ∧ ω ∣ a := by +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 omega0_isLimit] 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 · rcases h with ⟨a0, b, rfl⟩ - refine mul_isLimit_left omega_isLimit (Ordinal.pos_iff_ne_zero.2 <| mt ?_ a0) + refine mul_isLimit_left omega0_isLimit (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 @@ -2205,22 +2343,58 @@ 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 + ω := + (add_isNormal 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 + (add_isNormal o).apply_omega0 @[simp] +theorem iSup_mul_nat (o : Ordinal) : ⨆ n : ℕ, o * n = o * ω := by + rcases eq_zero_or_pos o with (rfl | ho) + · rw [zero_mul] + exact iSup_eq_zero_iff.2 fun n => zero_mul (n : Ordinal) + · exact (mul_isNormal ho).apply_omega0 + +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 +namespace Cardinal + +open Ordinal + +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 Ordinal.omega0_isLimit + +theorem noMaxOrder {c} (h : ℵ₀ ≤ c) : NoMaxOrder c.ord.toType := + toType_noMax_of_succ_lt (ord_isLimit h).2 + +end Cardinal + variable {α : Type u} {r : α → α → Prop} {a b : α} namespace Acc @@ -2229,10 +2403,10 @@ namespace Acc 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 + 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 = Ordinal.sup.{u, u} fun b : { b // r b a } => Order.succ (h.inv b.2).rank := by + h.rank = ⨆ b : { b // r b a }, Order.succ (h.inv b.2).rank := by change (Acc.intro a fun _ => h.inv).rank = _ rfl @@ -2240,7 +2414,7 @@ theorem rank_eq (h : Acc r a) : 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⟩) + refine le_trans ?_ (Ordinal.le_iSup _ ⟨a, h⟩) rfl end Acc @@ -2256,7 +2430,7 @@ noncomputable def rank (a : α) : Ordinal.{u} := (hwf.apply a).rank theorem rank_eq : - hwf.rank a = Ordinal.sup.{u, u} fun b : { b // r b a } => Order.succ <| hwf.rank b := by + hwf.rank a = ⨆ b : { b // r b a }, Order.succ (hwf.rank b) := by rw [rank, Acc.rank_eq] rfl @@ -2270,3 +2444,5 @@ theorem rank_strictAnti [Preorder α] [WellFoundedGT α] : StrictAnti (rank <| @wellFounded_gt α _ _) := fun _ _ => rank_lt_of_rel wellFounded_gt end WellFounded + +set_option linter.style.longFile 2700 diff --git a/Mathlib/SetTheory/Ordinal/Basic.lean b/Mathlib/SetTheory/Ordinal/Basic.lean index 5aa1b13790de0..d2993ff4d2f73 100644 --- a/Mathlib/SetTheory/Ordinal/Basic.lean +++ b/Mathlib/SetTheory/Ordinal/Basic.lean @@ -3,8 +3,8 @@ 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 -/ +import Mathlib.Algebra.Order.SuccPred import Mathlib.Data.Sum.Order -import Mathlib.Order.InitialSeg import Mathlib.SetTheory.Cardinal.Basic import Mathlib.Tactic.PPWithUniv @@ -21,18 +21,19 @@ initial segment (or, equivalently, in any way). This total order is well founded * `Ordinal.type r`: given a well-founded order `r`, this is the corresponding ordinal * `Ordinal.typein r a`: given a well-founded order `r` on a type `α`, and `a : α`, the ordinal corresponding to all elements smaller than `a`. -* `enum r o h`: given a well-order `r` on a type `α`, and an ordinal `o` strictly smaller than +* `enum r ⟨o, h⟩`: given a well-order `r` on a type `α`, and an ordinal `o` strictly smaller than the ordinal corresponding to `r` (this is the assumption `h`), returns the `o`-th element of `α`. In other words, the elements of `α` can be enumerated using ordinals up to `type r`. * `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₂`. @@ -66,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 -/ @@ -141,13 +106,20 @@ instance Ordinal.isEquivalent : Setoid WellOrder where def Ordinal : Type (u + 1) := Quotient Ordinal.isEquivalent -instance hasWellFoundedOut (o : Ordinal) : WellFoundedRelation o.out.α := +/-- A "canonical" type order-isomorphic to the ordinal `o`, living in the same universe. This is +defined through the axiom of choice. + +Use this over `Iio o` only when it is paramount to have a `Type u` rather than a `Type (u + 1)`. -/ +def Ordinal.toType (o : Ordinal.{u}) : Type u := + o.out.α + +instance hasWellFounded_toType (o : Ordinal) : WellFoundedRelation o.toType := ⟨o.out.r, o.out.wo.wf⟩ -instance linearOrderOut (o : Ordinal) : LinearOrder o.out.α := - IsWellOrder.linearOrder o.out.r +instance linearOrder_toType (o : Ordinal) : LinearOrder o.toType := + @IsWellOrder.linearOrder _ o.out.r o.out.wo -instance isWellOrder_out_lt (o : Ordinal) : IsWellOrder o.out.α (· < ·) := +instance isWellOrder_toType_lt (o : Ordinal) : IsWellOrder o.toType (· < ·) := o.out.wo namespace Ordinal @@ -182,8 +154,12 @@ theorem type_def (r) [wo : IsWellOrder α r] : (⟦⟨α, r, wo⟩⟧ : Ordinal) rfl @[simp] -theorem type_out (o : Ordinal) : Ordinal.type o.out.r = o := by - rw [Ordinal.type, WellOrder.eta, Quotient.out_eq] +theorem type_lt (o : Ordinal) : type (α := o.toType) (· < ·) = o := + (type_def' _).symm.trans <| Quotient.out_eq o + +@[deprecated type_lt (since := "2024-08-26")] +theorem type_out (o : Ordinal) : Ordinal.type o.out.r = o := + type_lt o theorem type_eq {α β} {r : α → α → Prop} {s : β → β → Prop} [IsWellOrder α r] [IsWellOrder β s] : type r = type s ↔ Nonempty (r ≃r s) := @@ -193,10 +169,6 @@ theorem _root_.RelIso.ordinal_type_eq {α β} {r : α → α → Prop} {s : β [IsWellOrder β s] (h : r ≃r s) : type r = type s := type_eq.2 ⟨h⟩ -@[simp] -theorem type_lt (o : Ordinal) : type ((· < ·) : o.out.α → o.out.α → Prop) = o := - (type_def' _).symm.trans <| Quotient.out_eq o - theorem type_eq_zero_of_empty (r) [IsWellOrder α r] [IsEmpty α] : type r = 0 := (RelIso.relIsoOfIsEmpty r _).ordinal_type_eq @@ -235,21 +207,29 @@ theorem type_unit : type (@EmptyRelation Unit) = 1 := rfl @[simp] -theorem out_empty_iff_eq_zero {o : Ordinal} : IsEmpty o.out.α ↔ o = 0 := by - rw [← @type_eq_zero_iff_isEmpty o.out.α (· < ·), type_lt] +theorem toType_empty_iff_eq_zero {o : Ordinal} : IsEmpty o.toType ↔ o = 0 := by + rw [← @type_eq_zero_iff_isEmpty o.toType (· < ·), type_lt] + +@[deprecated toType_empty_iff_eq_zero (since := "2024-08-26")] +alias out_empty_iff_eq_zero := toType_empty_iff_eq_zero -theorem eq_zero_of_out_empty (o : Ordinal) [h : IsEmpty o.out.α] : o = 0 := - out_empty_iff_eq_zero.1 h +@[deprecated toType_empty_iff_eq_zero (since := "2024-08-26")] +theorem eq_zero_of_out_empty (o : Ordinal) [h : IsEmpty o.toType] : o = 0 := + toType_empty_iff_eq_zero.1 h -instance isEmpty_out_zero : IsEmpty (0 : Ordinal).out.α := - out_empty_iff_eq_zero.2 rfl +instance isEmpty_toType_zero : IsEmpty (toType 0) := + toType_empty_iff_eq_zero.2 rfl @[simp] -theorem out_nonempty_iff_ne_zero {o : Ordinal} : Nonempty o.out.α ↔ o ≠ 0 := by - rw [← @type_ne_zero_iff_nonempty o.out.α (· < ·), type_lt] +theorem toType_nonempty_iff_ne_zero {o : Ordinal} : Nonempty o.toType ↔ o ≠ 0 := by + rw [← @type_ne_zero_iff_nonempty o.toType (· < ·), type_lt] + +@[deprecated toType_nonempty_iff_ne_zero (since := "2024-08-26")] +alias out_nonempty_iff_ne_zero := toType_nonempty_iff_ne_zero -theorem ne_zero_of_out_nonempty (o : Ordinal) [h : Nonempty o.out.α] : o ≠ 0 := - out_nonempty_iff_ne_zero.1 h +@[deprecated toType_nonempty_iff_ne_zero (since := "2024-08-26")] +theorem ne_zero_of_out_nonempty (o : Ordinal) [h : Nonempty o.toType] : o ≠ 0 := + toType_nonempty_iff_ne_zero.1 h protected theorem one_ne_zero : (1 : Ordinal) ≠ 0 := type_ne_zero_of_nonempty _ @@ -257,21 +237,28 @@ protected theorem one_ne_zero : (1 : Ordinal) ≠ 0 := instance nontrivial : Nontrivial Ordinal.{u} := ⟨⟨1, 0, Ordinal.one_ne_zero⟩⟩ ---@[simp] -- Porting note: not in simp nf, added aux lemma below +@[simp] theorem type_preimage {α β : Type u} (r : α → α → Prop) [IsWellOrder α r] (f : β ≃ α) : type (f ⁻¹'o r) = type r := (RelIso.preimage f r).ordinal_type_eq -@[simp, nolint simpNF] -- `simpNF` incorrectly complains the LHS doesn't simplify. -theorem type_preimage_aux {α β : Type u} (r : α → α → Prop) [IsWellOrder α r] (f : β ≃ α) : - @type _ (fun x y => r (f x) (f y)) (inferInstanceAs (IsWellOrder β (↑f ⁻¹'o r))) = type r := by - convert (RelIso.preimage f r).ordinal_type_eq - @[elab_as_elim] 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 -/ /-- @@ -279,9 +266,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 := @@ -302,11 +291,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 @@ -363,27 +358,28 @@ instance zeroLEOneClass : ZeroLEOneClass Ordinal := instance NeZero.one : NeZero (1 : Ordinal) := ⟨Ordinal.one_ne_zero⟩ -/-- Given two ordinals `α ≤ β`, then `initialSegOut α β` is the initial segment embedding -of `α` to `β`, as map from a model type for `α` to a model type for `β`. -/ -def initialSegOut {α β : Ordinal} (h : α ≤ β) : - InitialSeg ((· < ·) : α.out.α → α.out.α → Prop) ((· < ·) : β.out.α → β.out.α → Prop) := 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 - -/-- Given two ordinals `α < β`, then `principalSegOut α β` is the principal segment embedding -of `α` to `β`, as map from a model type for `α` to a model type for `β`. -/ -def principalSegOut {α β : Ordinal} (h : α < β) : - PrincipalSeg ((· < ·) : α.out.α → α.out.α → Prop) ((· < ·) : β.out.α → β.out.α → Prop) := 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 +/-- Given two ordinals `α ≤ β`, then `initialSegToType α β` is the initial segment embedding of +`α.toType` into `β.toType`. -/ +def initialSegToType {α β : Ordinal} (h : α ≤ β) : α.toType ≤i β.toType := by + apply Classical.choice (type_le_iff.mp _) + rwa [type_lt, type_lt] + +@[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 : α < β) : α.toType by - rcases f.down.1 h with ⟨b, rfl⟩; exact ⟨b, rfl⟩⟩ + rcases f.mem_range_of_rel_top h with ⟨b, rfl⟩; exact ⟨b, rfl⟩⟩ @[simp] theorem typein_apply {α β} {r : α → α → Prop} {s : β → β → Prop} [IsWellOrder α r] [IsWellOrder β s] @@ -404,7 +400,7 @@ theorem typein_apply {α β} {r : α → α → Prop} {s : β → β → Prop} [ (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⟩ + rcases f.mem_range_of_rel h with ⟨a, rfl⟩ exact ⟨⟨a, f.toRelEmbedding.map_rel_iff.1 h⟩, Subtype.eq <| RelEmbedding.trans_apply _ _ _⟩⟩ @@ -432,12 +428,12 @@ theorem typein_injective (r : α → α → Prop) [IsWellOrder α r] : Injective 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. -/ +/-- 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⟩⟩ + fun _ ↦ ⟨fun ⟨a, h⟩ ↦ h ▸ typein_lt_type r a, typein_surj r⟩⟩ @[simp] theorem typein.principalSeg_coe (r : α → α → Prop) [IsWellOrder α r] : @@ -446,67 +442,61 @@ theorem typein.principalSeg_coe (r : α → α → Prop) [IsWellOrder α r] : /-! ### Enumerating elements in a well-order with ordinals. -/ +/-- A well order `r` is order-isomorphic to the set of ordinals smaller than `type r`. +`enum r ⟨o, h⟩` is the `o`-th element of `α` ordered by `r`. -/-- `enum r o h` is the `o`-th element of `α` ordered by `r`. - That is, `enum` maps an initial segment of the ordinals, those - less than the order type of `r`, to the elements of `α`. -/ -def enum (r : α → α → Prop) [IsWellOrder α r] (o) (h : o < type r) : α := - (typein.principalSeg r).subrelIso ⟨o, h⟩ +That is, `enum` maps an initial segment of the ordinals, those less than the order type of `r`, to +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 @[simp] theorem typein_enum (r : α → α → Prop) [IsWellOrder α r] {o} (h : o < type r) : - typein r (enum r o h) = o := + typein r (enum r ⟨o, h⟩) = o := (typein.principalSeg 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 := + (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 @[simp] theorem enum_typein (r : α → α → Prop) [IsWellOrder α r] (a : α) : - enum r (typein r a) (typein_lt_type r a) = a := + enum r ⟨typein r a, typein_lt_type r a⟩ = a := enum_type (PrincipalSeg.ofElement r a) -theorem enum_lt_enum {r : α → α → Prop} [IsWellOrder α r] {o₁ o₂ : Ordinal} (h₁ : o₁ < type r) - (h₂ : o₂ < type r) : r (enum r o₁ h₁) (enum r o₂ h₂) ↔ o₁ < o₂ := by - rw [← typein_lt_typein r, typein_enum, typein_enum] +theorem enum_lt_enum {r : α → α → Prop} [IsWellOrder α r] {o₁ o₂ : {o // o < type r}} : + r (enum r o₁) (enum r o₂) ↔ o₁ < o₂ := by + rw [← typein_lt_typein r, typein_enum, typein_enum, Subtype.coe_lt_coe] theorem relIso_enum' {α β : Type u} {r : α → α → Prop} {s : β → β → Prop} [IsWellOrder α r] [IsWellOrder β s] (f : r ≃r s) (o : Ordinal) : - ∀ (hr : o < type r) (hs : o < type s), f (enum r o hr) = enum s o hs := by + ∀ (hr : o < type r) (hs : o < type s), f (enum r ⟨o, hr⟩) = enum s ⟨o, hs⟩ := by refine inductionOn o ?_; rintro γ t wo ⟨g⟩ ⟨h⟩ rw [enum_type g, enum_type (PrincipalSeg.ltEquiv g f)]; rfl theorem relIso_enum {α β : Type u} {r : α → α → Prop} {s : β → β → Prop} [IsWellOrder α r] [IsWellOrder β s] (f : r ≃r s) (o : Ordinal) (hr : o < type r) : - f (enum r o hr) = - enum s o - (by - convert hr using 1 - apply Quotient.sound - exact ⟨f.symm⟩) := + f (enum r ⟨o, hr⟩) = enum s ⟨o, hr.trans_eq (Quotient.sound ⟨f⟩)⟩ := relIso_enum' _ _ _ _ theorem lt_wf : @WellFounded Ordinal (· < ·) := -/- - wellFounded_iff_wellFounded_subrel.mpr (·.induction_on fun ⟨_, r, wo⟩ ↦ - RelHomClass.wellFounded (typein.principalSeg r).subrelIso wo.wf) --/ - ⟨fun a => - inductionOn a fun α r wo => - suffices ∀ a, Acc (· < ·) (typein r a) from - ⟨_, fun o h => - let ⟨a, e⟩ := typein_surj r h - e ▸ this a⟩ - fun a => - Acc.recOn (wo.wf.apply a) fun x _ IH => - ⟨_, fun o h => by - rcases typein_surj r (lt_trans h (typein_lt_type r _)) with ⟨b, rfl⟩ - exact IH _ ((typein_lt_typein r).1 h)⟩⟩ + wellFounded_iff_wellFounded_subrel.mpr (·.induction_on fun ⟨_, _, wo⟩ ↦ + RelHomClass.wellFounded (enum _) wo.wf) 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) : @@ -525,8 +515,7 @@ def card : Ordinal → Cardinal := theorem card_type (r : α → α → Prop) [IsWellOrder α r] : card (type r) = #α := rfl --- Porting note: nolint, simpNF linter falsely claims the lemma never applies -@[simp, nolint simpNF] +@[simp] theorem card_typein {r : α → α → Prop} [IsWellOrder α r] (x : α) : #{ y // r y x } = (typein r x).card := rfl @@ -545,27 +534,19 @@ 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⟩ => Quot.sound ⟨(RelIso.preimage Equiv.ulift r).trans <| f.trans (RelIso.preimage Equiv.ulift s).symm⟩ --- Porting note: Needed to add universe hints ULift.down.{v,u} below --- @[simp] -- Porting note: Not in simpnf, added aux lemma below +@[simp] theorem type_uLift (r : α → α → Prop) [IsWellOrder α r] : - type (ULift.down.{v,u} ⁻¹'o r) = lift.{v} (type r) := by + type (ULift.down ⁻¹'o r) = lift.{v} (type r) := by simp (config := { unfoldPartialApp := true }) rfl --- Porting note: simpNF linter falsely claims that this never applies -@[simp, nolint simpNF] -theorem type_uLift_aux (r : α → α → Prop) [IsWellOrder α r] : - @type.{max v u} _ (fun x y => r (ULift.down.{v,u} x) (ULift.down.{v,u} y)) - (inferInstanceAs (IsWellOrder (ULift α) (ULift.down ⁻¹'o r))) = lift.{v} (type r) := - rfl - theorem _root_.RelIso.ordinal_lift_type_eq {α : Type u} {β : Type v} {r : α → α → Prop} {s : β → β → Prop} [IsWellOrder α r] [IsWellOrder β s] (f : r ≃r s) : lift.{v} (type r) = lift.{u} (type s) := @@ -583,20 +564,23 @@ theorem type_lift_preimage_aux {α : Type u} {β : Type v} (r : α → α → Pr (inferInstanceAs (IsWellOrder β (f ⁻¹'o r)))) = lift.{v} (type r) := (RelIso.preimage f r).ordinal_lift_type_eq -/-- `lift.{max u v, u}` equals `lift.{v, u}`. -/ --- @[simp] -- Porting note: simp lemma never applies, tested +/-- `lift.{max u v, u}` equals `lift.{v, u}`. + +Unfortunately, the simp lemma doesn't seem to work. -/ theorem lift_umax : lift.{max u v, u} = lift.{v, u} := funext fun a => inductionOn a fun _ r _ => Quotient.sound ⟨(RelIso.preimage Equiv.ulift r).trans (RelIso.preimage Equiv.ulift r).symm⟩ -/-- `lift.{max v u, u}` equals `lift.{v, u}`. -/ --- @[simp] -- Porting note: simp lemma never applies, tested +/-- `lift.{max v u, u}` equals `lift.{v, u}`. + +Unfortunately, the simp lemma doesn't seem to work. -/ theorem lift_umax' : lift.{max v u, u} = lift.{v, u} := lift_umax -/-- An ordinal lifted to a lower or equal universe equals itself. -/ --- @[simp] -- Porting note: simp lemma never applies, tested +/-- An ordinal lifted to a lower or equal universe equals itself. + +Unfortunately, the simp lemma doesn't work. -/ theorem lift_id' (a : Ordinal) : lift a = a := inductionOn a fun _ r _ => Quotient.sound ⟨RelIso.preimage Equiv.ulift r⟩ @@ -676,7 +660,7 @@ theorem lift_card (a) : Cardinal.lift.{u,v} (card a)= card (lift.{u,v} a) := 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 + let ⟨c, e⟩ := Cardinal.mem_range_of_le_lift h Cardinal.inductionOn c (fun α => inductionOn b fun β s _ e' => by @@ -708,38 +692,55 @@ theorem lt_lift_iff {a : Ordinal.{u}} {b : Ordinal.{max u v}} : ⟨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} (· < ·) (· < ·) := +/-- 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.{u} ≤i Ordinal.{max u v} := ⟨⟨⟨lift.{v}, fun _ _ => lift_inj.1⟩, lift_lt⟩, fun _ _ h => lift_down (le_of_lt h)⟩ +@[deprecated liftInitialSeg (since := "2024-09-21")] +alias lift.initialSeg := liftInitialSeg + @[simp] -theorem lift.initialSeg_coe : (lift.initialSeg.{u,v} : Ordinal → Ordinal) = lift.{v,u} := +theorem liftInitialSeg_coe : (liftInitialSeg.{u, v} : Ordinal → Ordinal) = lift.{v, u} := + rfl + +set_option linter.deprecated false in +@[deprecated liftInitialSeg_coe (since := "2024-09-21")] +theorem lift.initialSeg_coe : (lift.initialSeg.{u, v} : Ordinal → Ordinal) = lift.{v, u} := rfl -/-! ### 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 ℕ (· < ·) _ +@[deprecated Ordinal.omega0 (since := "2024-09-26")] +alias omega := omega0 + @[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 @@ -751,11 +752,10 @@ 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 := (· + ·) @@ -796,45 +796,18 @@ 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 + 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 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]⟩ + 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 @@ -842,32 +815,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 := - IsWellOrder.conditionallyCompleteLinearOrderBot _ - theorem max_zero_left : ∀ a : Ordinal, max 0 a = a := max_bot_left @@ -884,39 +831,21 @@ 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⟩⟩ -instance succOrder : SuccOrder Ordinal.{u} := +instance instSuccOrder : SuccOrder Ordinal.{u} := SuccOrder.ofSuccLeIff (fun o => o + 1) succ_le_iff' +instance instSuccAddOrder : SuccAddOrder Ordinal := ⟨fun _ => rfl⟩ + @[simp] theorem add_one_eq_succ (o : Ordinal) : o + 1 = succ o := rfl @@ -932,10 +861,12 @@ theorem succ_one : succ (1 : Ordinal) = 2 := by congr; simp only [Nat.unaryCast, theorem add_succ (o₁ o₂ : Ordinal) : o₁ + succ o₂ = succ (o₁ + o₂) := (add_assoc _ _ _).symm -theorem one_le_iff_pos {o : Ordinal} : 1 ≤ o ↔ 0 < o := by rw [← succ_zero, succ_le_iff] +@[deprecated Order.one_le_iff_pos (since := "2024-09-04")] +protected theorem one_le_iff_pos {o : Ordinal} : 1 ≤ o ↔ 0 < o := + Order.one_le_iff_pos theorem one_le_iff_ne_zero {o : Ordinal} : 1 ≤ o ↔ o ≠ 0 := by - rw [one_le_iff_pos, Ordinal.pos_iff_ne_zero] + rw [Order.one_le_iff_pos, Ordinal.pos_iff_ne_zero] theorem succ_pos (o : Ordinal) : 0 < succ o := bot_lt_succ o @@ -964,102 +895,111 @@ instance uniqueIioOne : Unique (Iio (1 : Ordinal)) where default := ⟨0, by simp⟩ uniq a := Subtype.ext <| lt_one_iff_zero.1 a.2 -instance uniqueOutOne : Unique (1 : Ordinal).out.α where - default := enum (· < ·) 0 (by simp) +instance uniqueToTypeOne : Unique (toType 1) where + default := enum (α := toType 1) (· < ·) ⟨0, by simp⟩ uniq a := by unfold default - rw [← @enum_typein _ (· < ·) (isWellOrder_out_lt _) a] + rw [← enum_typein (α := toType 1) (· < ·) a] congr rw [← lt_one_iff_zero] apply typein_lt_self -theorem one_out_eq (x : (1 : Ordinal).out.α) : x = enum (· < ·) 0 (by simp) := +theorem one_toType_eq (x : toType 1) : x = enum (· < ·) ⟨0, by simp⟩ := Unique.eq_default x +@[deprecated one_toType_eq (since := "2024-08-26")] +alias one_out_eq := one_toType_eq + /-! ### Extra properties of typein and enum -/ +-- TODO: move this section with the other properties of `typein` and `enum`. +-- TODO: use `enumIsoToType` for lemmas on `toType` rather than `enum` and `typein`. @[simp] -theorem typein_one_out (x : (1 : Ordinal).out.α) : - @typein _ (· < ·) (isWellOrder_out_lt _) x = 0 := by - rw [one_out_eq x, typein_enum] +theorem typein_one_toType (x : toType 1) : typein (α := toType 1) (· < ·) x = 0 := by + rw [one_toType_eq x, typein_enum] + +@[deprecated typein_one_toType (since := "2024-08-26")] +alias typein_one_out := typein_one_toType @[simp] -theorem typein_le_typein (r : α → α → Prop) [IsWellOrder α r] {x x' : α} : - typein r x ≤ typein r x' ↔ ¬r x' x := by rw [← not_lt, typein_lt_typein] +theorem typein_le_typein (r : α → α → Prop) [IsWellOrder α r] {x y : α} : + typein r x ≤ typein r y ↔ ¬r y x := by + rw [← not_lt, typein_lt_typein] --- @[simp] -- Porting note (#10618): simp can prove this -theorem typein_le_typein' (o : Ordinal) {x x' : o.out.α} : - @typein _ (· < ·) (isWellOrder_out_lt _) x ≤ @typein _ (· < ·) (isWellOrder_out_lt _) x' - ↔ x ≤ x' := by - rw [typein_le_typein] - exact not_lt +theorem typein_le_typein' (o : Ordinal) {x y : o.toType} : + typein (α := o.toType) (· < ·) x ≤ typein (α := o.toType) (· < ·) y ↔ x ≤ y := by + simp --- Porting note: added nolint, simpnf linter falsely claims it never applies -@[simp, nolint simpNF] -theorem enum_le_enum (r : α → α → Prop) [IsWellOrder α r] {o o' : Ordinal} (ho : o < type r) - (ho' : o' < type r) : ¬r (enum r o' ho') (enum r o ho) ↔ o ≤ o' := by - rw [← @not_lt _ _ o' o, enum_lt_enum ho'] +theorem enum_le_enum (r : α → α → Prop) [IsWellOrder α r] {o₁ o₂ : {o // o < type r}} : + ¬r (enum r o₁) (enum r o₂) ↔ o₂ ≤ o₁ := by + rw [← @not_lt _ _ o₁ o₂, enum_lt_enum (r := r)] @[simp] -theorem enum_le_enum' (a : Ordinal) {o o' : Ordinal} (ho : o < type (· < ·)) - (ho' : o' < type (· < ·)) : enum (· < ·) o ho ≤ @enum a.out.α (· < ·) _ o' ho' ↔ o ≤ o' := by - rw [← @enum_le_enum _ (· < ·) (isWellOrder_out_lt _), ← not_lt] +theorem enum_le_enum' (a : Ordinal) {o₁ o₂ : {o // o < type (· < ·)}} : + enum (· < ·) o₁ ≤ enum (α := a.toType) (· < ·) o₂ ↔ o₁ ≤ o₂ := by + rw [← enum_le_enum (α := a.toType) (· < ·), ← not_lt] theorem enum_zero_le {r : α → α → Prop} [IsWellOrder α r] (h0 : 0 < type r) (a : α) : - ¬r a (enum r 0 h0) := by + ¬r a (enum r ⟨0, h0⟩) := by rw [← enum_typein r a, enum_le_enum r] apply Ordinal.zero_le -theorem enum_zero_le' {o : Ordinal} (h0 : 0 < o) (a : o.out.α) : - @enum o.out.α (· < ·) _ 0 (by rwa [type_lt]) ≤ a := by +theorem enum_zero_le' {o : Ordinal} (h0 : 0 < o) (a : o.toType) : + enum (α := o.toType) (· < ·) ⟨0, by rwa [type_lt]⟩ ≤ a := by rw [← not_lt] apply enum_zero_le -theorem le_enum_succ {o : Ordinal} (a : (succ o).out.α) : - a ≤ - @enum (succ o).out.α (· < ·) _ o - (by - rw [type_lt] - exact lt_succ o) := by - rw [← @enum_typein _ (· < ·) (isWellOrder_out_lt _) a, enum_le_enum', ← lt_succ_iff] +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 + rw [← enum_typein (α := (succ o).toType) (· < ·) a, enum_le_enum', Subtype.mk_le_mk, + ← lt_succ_iff] apply typein_lt_self -@[simp] -theorem enum_inj {r : α → α → Prop} [IsWellOrder α r] {o₁ o₂ : Ordinal} (h₁ : o₁ < type r) - (h₂ : o₂ < type r) : enum r o₁ h₁ = enum r o₂ h₂ ↔ o₁ = o₂ := - (typein.principalSeg r).subrelIso.injective.eq_iff.trans Subtype.mk_eq_mk - --- TODO: Can we remove this definition and just use `(typein.principalSeg r).subrelIso` directly? -/-- A well order `r` is order isomorphic to the set of ordinals smaller than `type r`. -/ -@[simps] -def enumIso (r : α → α → Prop) [IsWellOrder α r] : Subrel (· < ·) (· < type r) ≃r r := - { (typein.principalSeg r).subrelIso with - toFun := fun x ↦ enum r x.1 x.2 - invFun := fun x ↦ ⟨typein r x, typein_lt_type r x⟩ } +theorem enum_inj {r : α → α → Prop} [IsWellOrder α r] {o₁ o₂ : {o // o < type r}} : + enum r o₁ = enum r o₂ ↔ o₁ = o₂ := by + rw [EmbeddingLike.apply_eq_iff_eq, Subtype.mk.injEq] -/-- The order isomorphism between ordinals less than `o` and `o.out.α`. -/ -@[simps!] -noncomputable def enumIsoOut (o : Ordinal) : Set.Iio o ≃o o.out.α where +/-- The order isomorphism between ordinals less than `o` and `o.toType`. -/ +@[simps! (config := .lemmasOnly)] +noncomputable def enumIsoToType (o : Ordinal) : Set.Iio o ≃o o.toType where toFun x := - enum (· < ·) x.1 <| by + enum (α := o.toType) (· < ·) ⟨x.1, by rw [type_lt] - exact x.2 - invFun x := ⟨@typein _ (· < ·) (isWellOrder_out_lt _) x, typein_lt_self x⟩ + exact 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' -/-- `o.out.α` is an `OrderBot` whenever `0 < o`. -/ -def outOrderBotOfPos {o : Ordinal} (ho : 0 < o) : OrderBot o.out.α where +@[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 +@[deprecated toTypeOrderBotOfPos (since := "2024-08-26")] +noncomputable alias outOrderBotOfPos := toTypeOrderBotOfPos + theorem enum_zero_eq_bot {o : Ordinal} (ho : 0 < o) : - enum (· < ·) 0 (by rwa [type_lt]) = - haveI H := outOrderBotOfPos ho - (⊥ : (Quotient.out o).α) := + enum (α := o.toType) (· < ·) ⟨0, by rwa [type_lt]⟩ = + have H := toTypeOrderBotOfPos ho + (⊥ : o.toType) := rfl /-! ### Universal ordinal -/ @@ -1082,12 +1022,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.principalSeg r⟩ · rw [← lift_id (type s)] at h ⊢ cases' lift_type_lt.{_,_,v}.1 h with f cases' f with f a hf @@ -1096,34 +1041,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] @@ -1137,8 +1094,11 @@ namespace Cardinal open Ordinal @[simp] -theorem mk_ordinal_out (o : Ordinal) : #o.out.α = o.card := - (Ordinal.card_type (· < ·)).symm.trans <| by rw [Ordinal.type_lt] +theorem mk_toType (o : Ordinal) : #o.toType = o.card := + (Ordinal.card_type _).symm.trans <| by rw [Ordinal.type_lt] + +@[deprecated mk_toType (since := "2024-08-26")] +alias mk_ordinal_out := mk_toType /-- The ordinal corresponding to a cardinal `c` is the least ordinal whose cardinal is `c`. For the order-embedding version, see `ord.order_embedding`. -/ @@ -1193,6 +1153,9 @@ theorem card_ord (c) : (ord c).card = c := -- Porting note: cardinal.mk_def is now Cardinal.mk'_def, not sure why simp only [mk'_def, e, card_type] +theorem card_surjective : Function.Surjective card := + fun c ↦ ⟨_, card_ord c⟩ + /-- Galois coinsertion between `Cardinal.ord` and `Ordinal.card`. -/ def gciOrdCard : GaloisCoinsertion ord card := gc_ord_card.toGaloisCoinsertion fun c => c.card_ord.le @@ -1259,24 +1222,46 @@ theorem lift_ord (c) : Ordinal.lift.{u,v} (ord c) = ord (lift.{u,v} c) := by rwa [lt_ord, ← lift_card, lift_lt, ← lt_ord, ← Ordinal.lift_lt] · rw [ord_le, ← lift_card, card_ord] -theorem mk_ord_out (c : Cardinal) : #c.ord.out.α = c := by simp +theorem mk_ord_toType (c : Cardinal) : #c.ord.toType = c := by simp + +@[deprecated mk_ord_toType (since := "2024-08-26")] +alias mk_ord_out := mk_ord_toType theorem card_typein_lt (r : α → α → Prop) [IsWellOrder α r] (x : α) (h : ord #α = type r) : card (typein r x) < #α := by rw [← lt_ord, h] apply typein_lt_type -theorem card_typein_out_lt (c : Cardinal) (x : c.ord.out.α) : - card (@typein _ (· < ·) (isWellOrder_out_lt _) x) < c := by +theorem card_typein_toType_lt (c : Cardinal) (x : c.ord.toType) : + card (typein (α := c.ord.toType) (· < ·) x) < c := by rw [← lt_ord] apply typein_lt_self -theorem mk_Iio_ord_out_α {c : Cardinal} (i : c.ord.out.α) : #(Iio i) < c := card_typein_out_lt c i +@[deprecated card_typein_toType_lt (since := "2024-08-26")] +alias card_typein_out_lt := card_typein_toType_lt + +theorem mk_Iio_ord_toType {c : Cardinal} (i : c.ord.toType) : #(Iio i) < c := + card_typein_toType_lt c i + +@[deprecated (since := "2024-08-26")] +alias mk_Iio_ord_out_α := mk_Iio_ord_toType 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`. -/ @@ -1307,8 +1292,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) @@ -1318,23 +1303,23 @@ 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 + rw [← e, liftPrincipalSeg_coe, ← lift_card] at this exact ⟨_, this.symm⟩, fun ⟨c', 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' _⟩ 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..c5a4c3b7442d6 --- /dev/null +++ b/Mathlib/SetTheory/Ordinal/Enum.lean @@ -0,0 +1,125 @@ +/- +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_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 7c5c895e19db7..b00223b311dab 100644 --- a/Mathlib/SetTheory/Ordinal/Exponential.lean +++ b/Mathlib/SetTheory/Ordinal/Exponential.lean @@ -25,9 +25,6 @@ namespace Ordinal instance pow : Pow Ordinal Ordinal := ⟨fun a b => if a = 0 then 1 - b else limitRecOn b 1 (fun _ IH => IH * a) fun b _ => bsup.{u, u} b⟩ --- Porting note: Ambiguous notations. --- local infixr:0 "^" => @Pow.pow Ordinal Ordinal Ordinal.instPowOrdinalOrdinal - theorem opow_def (a b : Ordinal) : a ^ b = if a = 0 then 1 - b else limitRecOn b 1 (fun _ IH => IH * a) fun b _ => bsup.{u, u} b := rfl @@ -89,6 +86,20 @@ 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 ^ ·) := 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, @@ -148,7 +159,7 @@ theorem left_le_opow (a : Ordinal) {b : Ordinal} (b1 : 0 < b) : a ≤ a ^ b := b rwa [opow_le_opow_iff_right a1, one_le_iff_pos] theorem right_le_opow {a : Ordinal} (b : Ordinal) (a1 : 1 < a) : b ≤ a ^ b := - (opow_isNormal a1).self_le _ + (opow_isNormal a1).id_le _ 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] @@ -215,41 +226,56 @@ theorem opow_mul (a b c : Ordinal) : a ^ (b * c) = (a ^ b) ^ c := by 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 := @@ -258,7 +284,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 @@ -283,17 +309,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] @@ -307,69 +383,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) @@ -383,11 +465,10 @@ 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 /-! ### Interaction with `Nat.cast` -/ @@ -397,12 +478,21 @@ 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 (opow_isNormal ho₁).apply_omega0 + · rw [one_opow] + refine le_antisymm (Ordinal.iSup_le fun n => by rw [one_opow]) ?_ + convert Ordinal.le_iSup _ 0 + rw [Nat.cast_zero, opow_zero] -theorem sup_opow_nat {o : Ordinal} (ho : 0 < o) : (sup fun n : ℕ => o ^ (n : Ordinal)) = o ^ ω := by - rcases lt_or_eq_of_le (one_le_iff_pos.2 ho) with (ho₁ | rfl) - · exact (opow_isNormal ho₁).apply_omega +set_option linter.deprecated false in +@[deprecated iSup_pow (since := "2024-08-27")] +theorem sup_opow_nat {o : Ordinal} (ho : 0 < o) : (sup fun n : ℕ => o ^ n) = o ^ ω := by + simp_rw [← opow_natCast] + rcases (one_le_iff_pos.2 ho).lt_or_eq with ho₁ | rfl + · exact (opow_isNormal ho₁).apply_omega0 · 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 d6d8d3151c634..0ec30e305b66c 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 _ [] 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 @@ -173,7 +185,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 (derivFamily_isNormal _).le_apply intro o induction' o using limitRecOn with o IH o l IH · intro h₁ @@ -202,7 +214,7 @@ 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)] + rw [eq_comm, eq_enumOrd _ (not_bddAbove_fp_family H)] use (derivFamily_isNormal f).strictMono rw [Set.range_eq_iff] refine ⟨?_, fun a ha => ?_⟩ @@ -234,23 +246,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 _ [] 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.{u, v} theorem nfpBFamily_monotone (hf : ∀ i hi, Monotone (f i hi)) : Monotone (nfpBFamily.{u, v} o f) := nfpFamily_monotone fun _ => hf _ _ @@ -263,7 +275,7 @@ theorem apply_lt_nfpBFamily (H : ∀ i hi, IsNormal (f i hi)) {a b} (hb : b < nf theorem apply_lt_nfpBFamily_iff (ho : o ≠ 0) (H : ∀ i hi, IsNormal (f i hi)) {a b} : (∀ i hi, f i hi b < nfpBFamily.{u, v} o f a) ↔ b < nfpBFamily.{u, v} o f a := ⟨fun h => by - haveI := out_nonempty_iff_ne_zero.2 ho + haveI := toType_nonempty_iff_ne_zero.2 ho refine (apply_lt_nfpFamily_iff.{u, v} ?_).1 fun _ => h _ _ exact fun _ => H _ _, apply_lt_nfpBFamily H⟩ @@ -288,7 +300,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 +309,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 @@ -343,7 +365,7 @@ 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)] + rw [eq_comm, eq_enumOrd _ (not_bddAbove_fp_bfamily H)] use (derivBFamily_isNormal 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 => ?_⟩ @@ -368,10 +390,23 @@ def nfp (f : Ordinal → Ordinal) : Ordinal → Ordinal := theorem nfp_eq_nfpFamily (f : Ordinal → Ordinal) : nfp f = nfpFamily fun _ : Unit => f := rfl -@[simp] -theorem sup_iterate_eq_nfp (f : Ordinal.{u} → Ordinal.{u}) : - (fun a => sup fun n : ℕ => f^[n] a) = nfp f := by - refine funext fun a => le_antisymm ?_ (sup_le fun l => ?_) +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 => ?_) · rw [sup_le_iff] intro n rw [← List.length_replicate n Unit.unit, ← List.foldr_const f a] @@ -380,28 +415,28 @@ theorem sup_iterate_eq_nfp (f : Ordinal.{u} → 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 _ 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 @@ -421,13 +456,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 @@ -442,7 +485,7 @@ theorem deriv_eq_derivFamily (f : Ordinal → Ordinal) : deriv f = derivFamily f rfl @[simp] -theorem deriv_zero (f) : deriv f 0 = nfp f 0 := +theorem deriv_zero_right (f) : deriv f 0 = nfp f 0 := derivFamily_zero _ @[simp] @@ -477,63 +520,91 @@ theorem deriv_eq_enumOrd (H : IsNormal f) : deriv f = enumOrd (Function.fixedPoi 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] +theorem nfp_zero_left (a) : nfp 0 a = a := by + 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'] + exact Ordinal.zero_le a + +@[simp] +theorem nfp_zero : nfp 0 = id := by + ext + exact nfp_zero_left _ + +@[simp] +theorem deriv_zero : deriv 0 = id := + deriv_eq_id_of_nfp_eq_id nfp_zero + +theorem deriv_zero_left (a) : deriv 0 a = a := by + rw [deriv_zero] + rfl + 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 +theorem nfp_add_eq_mul_omega0 {a b} (hba : b ≤ a * ω) : nfp (a + ·) b = a * ω := by apply le_antisymm (nfp_le_fp (add_isNormal a).monotone hba _) · rw [← nfp_add_zero] exact nfp_monotone (add_isNormal a).monotone (Ordinal.zero_le b) - · dsimp; rw [← mul_one_add, one_add_omega] + · 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] + · rw [← nfp_add_zero a, ← deriv_zero_right] cases' (add_isNormal a).fp_iff_deriv.1 h with c hc rw [← hc] exact (deriv_isNormal _).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] +@[deprecated (since := "2024-09-30")] +alias add_eq_right_iff_mul_omega_le := add_eq_right_iff_mul_omega0_le + +theorem add_le_right_iff_mul_omega0_le {a b : Ordinal} : a + b ≤ b ↔ a * ω ≤ b := by + rw [← add_eq_right_iff_mul_omega0_le] exact (add_isNormal a).le_iff_eq -theorem deriv_add_eq_mul_omega_add (a b : Ordinal.{u}) : deriv (a + ·) b = a * omega + b := by +@[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 _)] refine ⟨?_, fun a h => ?_⟩ - · rw [deriv_zero, add_zero] + · 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 _))) -/-! ### Fixed points of multiplication -/ +@[deprecated (since := "2024-09-30")] +alias deriv_add_eq_mul_omega_add := deriv_add_eq_mul_omega0_add --- Porting note: commented out, doesn't seem necessary --- local infixr:0 "^" => @Pow.pow Ordinal Ordinal Ordinal.hasPow +/-! ### 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] - · dsimp - congr - funext n - induction' n with n hn - · rw [Nat.cast_zero, opow_zero, iterate_zero_apply] - rw [iterate_succ_apply', Nat.add_comm, Nat.cast_add, Nat.cast_one, opow_add, opow_one, hn] - · exact 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 + · rw [pow_zero, iterate_zero_apply] + · rw [iterate_succ_apply', Nat.add_comm, pow_add, pow_one, hn] @[simp] theorem nfp_mul_zero (a : Ordinal) : nfp (a * ·) 0 = 0 := by @@ -542,37 +613,25 @@ 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] -@[simp] -theorem nfp_zero_mul : nfp (HMul.hMul 0) = id := by - rw [← sup_iterate_eq_nfp] - refine funext fun a => (sup_le fun n => ?_).antisymm (le_sup (fun n => (0 * ·)^[n] a) 0) - induction' n with n _ - · rfl - rw [Function.iterate_succ'] - change 0 * _ ≤ a - rw [zero_mul] - exact Ordinal.zero_le a - -@[simp] -theorem deriv_mul_zero : deriv (HMul.hMul 0) = id := - deriv_eq_id_of_nfp_eq_id nfp_zero_mul - -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 [Ordinal.le_zero.1 hba, nfp_zero_mul] - rfl + · 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] + 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) -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 @@ -580,51 +639,66 @@ theorem eq_zero_or_opow_omega_le_of_mul_eq_right {a b : Ordinal} (hab : a * b = rw [← Ne, ← one_le_iff_ne_zero] at hb exact nfp_le_fp (mul_isNormal ha).monotone hb (le_of_eq hab) -theorem mul_eq_right_iff_opow_omega_dvd {a b : Ordinal} : a * b = b ↔ (a^omega) ∣ b := by +@[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_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] +theorem mul_le_right_iff_opow_omega0_dvd {a b : Ordinal} (ha : 0 < a) : + a * b ≤ b ↔ (a ^ ω) ∣ b := by + rw [← mul_eq_right_iff_opow_omega0_dvd] exact (mul_isNormal ha).le_iff_eq -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 · 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 + · dsimp only; rw [← mul_assoc, ← opow_one_add, one_add_omega0] + · cases' mul_eq_right_iff_opow_omega0_dvd.1 ((mul_isNormal ha).nfp_fp ((a ^ ω) * b + c)) with d hd 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 (deriv_isNormal _) (mul_isNormal (opow_pos ω ha))] refine ⟨?_, fun c h => ?_⟩ - · dsimp only; rw [deriv_zero, nfp_mul_zero, mul_zero] + · 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 22ea84fdfe087..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 succeding 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 7742f066f545b..b901e17cfa608 100644 --- a/Mathlib/SetTheory/Ordinal/NaturalOps.lean +++ b/Mathlib/SetTheory/Ordinal/NaturalOps.lean @@ -27,13 +27,13 @@ The natural addition of two ordinals corresponds to adding their Cantor normal f polynomials in `ω`. Likewise, their natural multiplication corresponds to multiplying the Cantor normal forms as polynomials. -# Implementation notes +## Implementation notes Given the rich algebraic structure of these two operations, we choose to create a type synonym `NatOrdinal`, where we provide the appropriate instances. However, to avoid casting back and forth between both types, we attempt to prove and state most results on `Ordinal`. -# Todo +## Todo - Prove the characterizations of natural addition and multiplication in terms of the Cantor normal form. @@ -47,14 +47,16 @@ noncomputable section /-! ### Basic casts between `Ordinal` and `NatOrdinal` -/ + /-- A type synonym for ordinals with natural addition and multiplication. -/ def NatOrdinal : Type _ := -- Porting note: used to derive LinearOrder & SuccOrder but need to manually define Ordinal deriving Zero, Inhabited, One, WellFoundedRelation instance NatOrdinal.linearOrder : LinearOrder NatOrdinal := {Ordinal.linearOrder with} - -instance NatOrdinal.succOrder : SuccOrder NatOrdinal := {Ordinal.succOrder with} +instance NatOrdinal.instSuccOrder : SuccOrder NatOrdinal := {Ordinal.instSuccOrder with} +instance NatOrdinal.orderBot : OrderBot NatOrdinal := {Ordinal.orderBot with} +instance NatOrdinal.noMaxOrder : NoMaxOrder NatOrdinal := {Ordinal.noMaxOrder with} /-- The identity function between `Ordinal` and `NatOrdinal`. -/ @[match_pattern] @@ -86,7 +88,14 @@ instance : WellFoundedLT NatOrdinal := Ordinal.wellFoundedLT instance : IsWellOrder NatOrdinal (· < ·) := - Ordinal.isWellOrder + { } + +instance : ConditionallyCompleteLinearOrderBot NatOrdinal := + WellFoundedLT.conditionallyCompleteLinearOrderBot _ + +@[simp] +theorem bot_eq_zero : ⊥ = 0 := + rfl @[simp] theorem toOrdinal_zero : toOrdinal 0 = 0 := @@ -97,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) := @@ -161,7 +170,7 @@ theorem toNatOrdinal_max (a b : Ordinal) : @[simp] theorem toNatOrdinal_min (a b : Ordinal) : - toNatOrdinal (linearOrder.min a b) = linearOrder.min (toNatOrdinal a) (toNatOrdinal b) := + toNatOrdinal (min a b) = min (toNatOrdinal a) (toNatOrdinal b) := rfl /-! We place the definitions of `nadd` and `nmul` before actually developing their API, as this @@ -173,10 +182,9 @@ to normal ordinal addition, it is commutative. Natural addition can equivalently be characterized as the ordinal resulting from adding up corresponding coefficients in the Cantor normal forms of `a` and `b`. -/ -noncomputable def nadd : Ordinal → Ordinal → Ordinal - | a, b => - max (blsub.{u, u} a fun a' _ => nadd a' b) (blsub.{u, u} b fun b' _ => nadd a b') - termination_by o₁ o₂ => (o₁, o₂) +noncomputable def nadd (a b : Ordinal) : Ordinal := + max (blsub.{u, u} a fun a' _ => nadd a' b) (blsub.{u, u} b fun b' _ => nadd a b') +termination_by (a, b) @[inherit_doc] scoped[NaturalOps] infixl:65 " ♯ " => Ordinal.nadd @@ -184,22 +192,23 @@ 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). Natural multiplication can equivalently be characterized as the ordinal resulting from multiplying the Cantor normal forms of `a` and `b` as if they were polynomials in `ω`. Addition of exponents is done via natural addition. -/ -noncomputable def nmul : Ordinal.{u} → Ordinal.{u} → Ordinal.{u} - | a, b => sInf {c | ∀ a' < a, ∀ b' < b, nmul a' b ♯ nmul a b' < c ♯ nmul a' b'} -termination_by a b => (a, b) +noncomputable def nmul (a b : Ordinal.{u}) : Ordinal.{u} := + sInf {c | ∀ a' < a, ∀ b' < b, nmul a' b ♯ nmul a b' < c ♯ nmul a' b'} +termination_by (a, b) @[inherit_doc] scoped[NaturalOps] infixl:70 " ⨳ " => Ordinal.nmul /-! ### Natural addition -/ + theorem nadd_def (a b : Ordinal) : a ♯ b = max (blsub.{u, u} a fun a' _ => a' ♯ b) (blsub.{u, u} b fun b' _ => a ♯ b') := by rw [nadd] @@ -230,11 +239,10 @@ theorem nadd_le_nadd_right (h : b ≤ c) (a) : b ♯ a ≤ c ♯ a := by variable (a b) -theorem nadd_comm : ∀ a b, a ♯ b = b ♯ a - | a, b => by - rw [nadd_def, nadd_def, max_comm] - congr <;> ext <;> apply nadd_comm - termination_by a b => (a,b) +theorem nadd_comm (a b) : a ♯ b = b ♯ a := by + rw [nadd_def, nadd_def, max_comm] + congr <;> ext <;> apply nadd_comm +termination_by (a, b) theorem blsub_nadd_of_mono {f : ∀ c < a ♯ b, Ordinal.{max u v}} (hf : ∀ {i j} (hi hj), i ≤ j → f i hi ≤ f j hj) : @@ -308,8 +316,8 @@ namespace NatOrdinal open Ordinal NaturalOps -instance : Add NatOrdinal := - ⟨nadd⟩ +instance : Add NatOrdinal := ⟨nadd⟩ +instance : SuccAddOrder NatOrdinal := ⟨fun x => (nadd_one x).symm⟩ instance add_covariantClass_lt : CovariantClass NatOrdinal.{u} NatOrdinal.{u} (· + ·) (· < ·) := ⟨fun a _ _ h => nadd_lt_nadd_left h a⟩ @@ -338,9 +346,9 @@ instance orderedCancelAddCommMonoid : OrderedCancelAddCommMonoid NatOrdinal := instance addMonoidWithOne : AddMonoidWithOne NatOrdinal := AddMonoidWithOne.unary -@[simp] -theorem add_one_eq_succ : ∀ a : NatOrdinal, a + 1 = succ a := - nadd_one +@[deprecated Order.succ_eq_add_one (since := "2024-09-04")] +theorem add_one_eq_succ (a : NatOrdinal) : a + 1 = succ a := + (Order.succ_eq_add_one a).symm @[simp] theorem toOrdinal_cast_nat (n : ℕ) : toOrdinal n = n := by @@ -431,13 +439,14 @@ theorem nadd_right_comm : ∀ a b c, a ♯ b ♯ c = a ♯ c ♯ b := /-! ### Natural multiplication -/ + variable {a b c d : Ordinal.{u}} 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}) : +private theorem nmul_nonempty (a b : Ordinal.{u}) : {c : Ordinal.{u} | ∀ a' < a, ∀ b' < b, a' ⨳ b ♯ a ⨳ b' < c ♯ a' ⨳ b'}.Nonempty := ⟨_, fun _ ha _ hb => (lt_blsub₂.{u, u, u} _ ha hb).trans_le le_self_nadd⟩ @@ -465,17 +474,16 @@ theorem lt_nmul_iff : c < a ⨳ b ↔ ∃ a' < a, ∃ b' < b, c ♯ a' ⨳ b' theorem nmul_le_iff : a ⨳ b ≤ c ↔ ∀ a' < a, ∀ b' < b, a' ⨳ b ♯ a ⨳ b' < c ♯ a' ⨳ b' := by rw [← not_iff_not]; simp [lt_nmul_iff] -theorem nmul_comm : ∀ a b, a ⨳ b = b ⨳ a - | a, b => by - rw [nmul, nmul] - congr; ext x; constructor <;> intro H c hc d hd - -- Porting note: had to add additional arguments to `nmul_comm` here - -- for the termination checker. - · rw [nadd_comm, ← nmul_comm d b, ← nmul_comm a c, ← nmul_comm d] - exact H _ hd _ hc - · rw [nadd_comm, nmul_comm a d, nmul_comm c, nmul_comm c] - exact H _ hd _ hc -termination_by a b => (a, b) +theorem nmul_comm (a b) : a ⨳ b = b ⨳ a := by + rw [nmul, nmul] + congr; ext x; constructor <;> intro H c hc d hd + -- Porting note: had to add additional arguments to `nmul_comm` here + -- for the termination checker. + · rw [nadd_comm, ← nmul_comm d b, ← nmul_comm a c, ← nmul_comm d] + exact H _ hd _ hc + · rw [nadd_comm, nmul_comm a d, nmul_comm c, nmul_comm c] + exact H _ hd _ hc +termination_by (a, b) @[simp] theorem nmul_zero (a) : a ⨳ 0 = 0 := by @@ -510,56 +518,61 @@ theorem nmul_lt_nmul_of_pos_left (h₁ : a < b) (h₂ : 0 < c) : c ⨳ a < c ⨳ theorem nmul_lt_nmul_of_pos_right (h₁ : a < b) (h₂ : 0 < c) : a ⨳ c < b ⨳ c := lt_nmul_iff.2 ⟨a, h₁, 0, h₂, by simp⟩ -theorem nmul_le_nmul_of_nonneg_left (h₁ : a ≤ b) (h₂ : 0 ≤ c) : c ⨳ a ≤ c ⨳ b := by - rcases lt_or_eq_of_le h₁ with (h₁ | rfl) <;> rcases lt_or_eq_of_le h₂ with (h₂ | rfl) +theorem nmul_le_nmul_left (h : a ≤ b) (c) : c ⨳ a ≤ c ⨳ b := by + rcases lt_or_eq_of_le h with (h₁ | rfl) <;> rcases (eq_zero_or_pos c).symm with (h₂ | rfl) · exact (nmul_lt_nmul_of_pos_left h₁ h₂).le all_goals simp -theorem nmul_le_nmul_of_nonneg_right (h₁ : a ≤ b) (h₂ : 0 ≤ c) : a ⨳ c ≤ b ⨳ c := by +@[deprecated nmul_le_nmul_left (since := "2024-08-20")] +alias nmul_le_nmul_of_nonneg_left := nmul_le_nmul_left + +theorem nmul_le_nmul_right (h : a ≤ b) (c) : a ⨳ c ≤ b ⨳ c := by rw [nmul_comm, nmul_comm b] - exact nmul_le_nmul_of_nonneg_left h₁ h₂ - -theorem nmul_nadd : ∀ a b c, a ⨳ (b ♯ c) = a ⨳ b ♯ a ⨳ c - | a, b, c => by - refine le_antisymm (nmul_le_iff.2 fun a' ha d hd => ?_) - (nadd_le_iff.2 ⟨fun d hd => ?_, fun d hd => ?_⟩) - · -- Porting note: adding arguments to `nmul_nadd` for the termination checker. - rw [nmul_nadd a' b c] - rcases lt_nadd_iff.1 hd with (⟨b', hb, hd⟩ | ⟨c', hc, hd⟩) - · have := nadd_lt_nadd_of_lt_of_le (nmul_nadd_lt ha hb) (nmul_nadd_le ha.le hd) - -- Porting note: adding arguments to `nmul_nadd` for the termination checker. - rw [nmul_nadd a' b' c, nmul_nadd a b' c] at this - simp only [nadd_assoc] at this - rwa [nadd_left_comm, nadd_left_comm _ (a ⨳ b'), nadd_left_comm (a ⨳ b), - nadd_lt_nadd_iff_left, nadd_left_comm (a' ⨳ b), nadd_left_comm (a ⨳ b), - nadd_lt_nadd_iff_left, ← nadd_assoc, ← nadd_assoc] at this - · have := nadd_lt_nadd_of_le_of_lt (nmul_nadd_le ha.le hd) (nmul_nadd_lt ha hc) - -- Porting note: adding arguments to `nmul_nadd` for the termination checker. - rw [nmul_nadd a' b c', nmul_nadd a b c'] at this - simp only [nadd_assoc] at this - rwa [nadd_left_comm, nadd_comm (a ⨳ c), nadd_left_comm (a' ⨳ d), nadd_left_comm (a ⨳ c'), - nadd_left_comm (a ⨳ b), nadd_lt_nadd_iff_left, nadd_comm (a' ⨳ c), nadd_left_comm (a ⨳ d), - nadd_left_comm (a' ⨳ b), nadd_left_comm (a ⨳ b), nadd_lt_nadd_iff_left, nadd_comm (a ⨳ d), - nadd_comm (a' ⨳ d), ← nadd_assoc, ← nadd_assoc] at this - · rcases lt_nmul_iff.1 hd with ⟨a', ha, b', hb, hd⟩ - have := nadd_lt_nadd_of_le_of_lt hd (nmul_nadd_lt ha (nadd_lt_nadd_right hb c)) + exact nmul_le_nmul_left h c + +@[deprecated nmul_le_nmul_left (since := "2024-08-20")] +alias nmul_le_nmul_of_nonneg_right := nmul_le_nmul_right + +theorem nmul_nadd (a b c : Ordinal) : a ⨳ (b ♯ c) = a ⨳ b ♯ a ⨳ c := by + refine le_antisymm (nmul_le_iff.2 fun a' ha d hd => ?_) + (nadd_le_iff.2 ⟨fun d hd => ?_, fun d hd => ?_⟩) + · -- Porting note: adding arguments to `nmul_nadd` for the termination checker. + rw [nmul_nadd a' b c] + rcases lt_nadd_iff.1 hd with (⟨b', hb, hd⟩ | ⟨c', hc, hd⟩) + · have := nadd_lt_nadd_of_lt_of_le (nmul_nadd_lt ha hb) (nmul_nadd_le ha.le hd) -- Porting note: adding arguments to `nmul_nadd` for the termination checker. - rw [nmul_nadd a' b c, nmul_nadd a b' c, nmul_nadd a'] at this + rw [nmul_nadd a' b' c, nmul_nadd a b' c] at this simp only [nadd_assoc] at this - rwa [nadd_left_comm (a' ⨳ b'), nadd_left_comm, nadd_lt_nadd_iff_left, nadd_left_comm, - nadd_left_comm _ (a' ⨳ b'), nadd_left_comm (a ⨳ b'), nadd_lt_nadd_iff_left, - nadd_left_comm (a' ⨳ c), nadd_left_comm, nadd_lt_nadd_iff_left, nadd_left_comm, - nadd_comm _ (a' ⨳ c), nadd_lt_nadd_iff_left] at this - · rcases lt_nmul_iff.1 hd with ⟨a', ha, c', hc, hd⟩ - have := nadd_lt_nadd_of_lt_of_le (nmul_nadd_lt ha (nadd_lt_nadd_left hc b)) hd + rwa [nadd_left_comm, nadd_left_comm _ (a ⨳ b'), nadd_left_comm (a ⨳ b), + nadd_lt_nadd_iff_left, nadd_left_comm (a' ⨳ b), nadd_left_comm (a ⨳ b), + nadd_lt_nadd_iff_left, ← nadd_assoc, ← nadd_assoc] at this + · have := nadd_lt_nadd_of_le_of_lt (nmul_nadd_le ha.le hd) (nmul_nadd_lt ha hc) -- Porting note: adding arguments to `nmul_nadd` for the termination checker. - rw [nmul_nadd a' b c, nmul_nadd a b c', nmul_nadd a'] at this + rw [nmul_nadd a' b c', nmul_nadd a b c'] at this simp only [nadd_assoc] at this - rwa [nadd_left_comm _ (a' ⨳ b), nadd_lt_nadd_iff_left, nadd_left_comm (a' ⨳ c'), - nadd_left_comm _ (a' ⨳ c), nadd_lt_nadd_iff_left, nadd_left_comm, nadd_comm (a' ⨳ c'), - nadd_left_comm _ (a ⨳ c'), nadd_lt_nadd_iff_left, nadd_comm _ (a' ⨳ c'), - nadd_comm _ (a' ⨳ c'), nadd_left_comm, nadd_lt_nadd_iff_left] at this -termination_by a b c => (a, b, c) + rwa [nadd_left_comm, nadd_comm (a ⨳ c), nadd_left_comm (a' ⨳ d), nadd_left_comm (a ⨳ c'), + nadd_left_comm (a ⨳ b), nadd_lt_nadd_iff_left, nadd_comm (a' ⨳ c), nadd_left_comm (a ⨳ d), + nadd_left_comm (a' ⨳ b), nadd_left_comm (a ⨳ b), nadd_lt_nadd_iff_left, nadd_comm (a ⨳ d), + nadd_comm (a' ⨳ d), ← nadd_assoc, ← nadd_assoc] at this + · rcases lt_nmul_iff.1 hd with ⟨a', ha, b', hb, hd⟩ + have := nadd_lt_nadd_of_le_of_lt hd (nmul_nadd_lt ha (nadd_lt_nadd_right hb c)) + -- Porting note: adding arguments to `nmul_nadd` for the termination checker. + rw [nmul_nadd a' b c, nmul_nadd a b' c, nmul_nadd a'] at this + simp only [nadd_assoc] at this + rwa [nadd_left_comm (a' ⨳ b'), nadd_left_comm, nadd_lt_nadd_iff_left, nadd_left_comm, + nadd_left_comm _ (a' ⨳ b'), nadd_left_comm (a ⨳ b'), nadd_lt_nadd_iff_left, + nadd_left_comm (a' ⨳ c), nadd_left_comm, nadd_lt_nadd_iff_left, nadd_left_comm, + nadd_comm _ (a' ⨳ c), nadd_lt_nadd_iff_left] at this + · rcases lt_nmul_iff.1 hd with ⟨a', ha, c', hc, hd⟩ + have := nadd_lt_nadd_of_lt_of_le (nmul_nadd_lt ha (nadd_lt_nadd_left hc b)) hd + -- Porting note: adding arguments to `nmul_nadd` for the termination checker. + rw [nmul_nadd a' b c, nmul_nadd a b c', nmul_nadd a'] at this + simp only [nadd_assoc] at this + rwa [nadd_left_comm _ (a' ⨳ b), nadd_lt_nadd_iff_left, nadd_left_comm (a' ⨳ c'), + nadd_left_comm _ (a' ⨳ c), nadd_lt_nadd_iff_left, nadd_left_comm, nadd_comm (a' ⨳ c'), + nadd_left_comm _ (a ⨳ c'), nadd_lt_nadd_iff_left, nadd_comm _ (a' ⨳ c'), + nadd_comm _ (a' ⨳ c'), nadd_left_comm, nadd_lt_nadd_iff_left] at this +termination_by (a, b, c) theorem nadd_nmul (a b c) : (a ♯ b) ⨳ c = a ⨳ c ♯ b ⨳ c := by rw [nmul_comm, nmul_nadd, nmul_comm, nmul_comm c] @@ -632,26 +645,25 @@ theorem nmul_le_iff₃' : d ♯ a' ⨳ (b' ⨳ c) ♯ a' ⨳ (b ⨳ c') ♯ a ⨳ (b' ⨳ c') := by rw [← not_iff_not]; simp [lt_nmul_iff₃'] -theorem nmul_assoc : ∀ a b c, a ⨳ b ⨳ c = a ⨳ (b ⨳ c) - | a, b, c => by - apply le_antisymm - · rw [nmul_le_iff₃] - intro a' ha b' hb c' hc - -- Porting note: the next line was just - -- repeat' rw [nmul_assoc] - -- but we need to spell out the arguments for the termination checker. - rw [nmul_assoc a' b c, nmul_assoc a b' c, nmul_assoc a b c', nmul_assoc a' b' c', - nmul_assoc a' b' c, nmul_assoc a' b c', nmul_assoc a b' c'] - exact nmul_nadd_lt₃' ha hb hc - · rw [nmul_le_iff₃'] - intro a' ha b' hb c' hc - -- Porting note: the next line was just - -- repeat' rw [← nmul_assoc] - -- but we need to spell out the arguments for the termination checker. - rw [← nmul_assoc a' b c, ← nmul_assoc a b' c, ← nmul_assoc a b c', ← nmul_assoc a' b' c', - ← nmul_assoc a' b' c, ← nmul_assoc a' b c', ← nmul_assoc a b' c'] - exact nmul_nadd_lt₃ ha hb hc -termination_by a b c => (a, b, c) +theorem nmul_assoc (a b c : Ordinal) : a ⨳ b ⨳ c = a ⨳ (b ⨳ c) := by + apply le_antisymm + · rw [nmul_le_iff₃] + intro a' ha b' hb c' hc + -- Porting note: the next line was just + -- repeat' rw [nmul_assoc] + -- but we need to spell out the arguments for the termination checker. + rw [nmul_assoc a' b c, nmul_assoc a b' c, nmul_assoc a b c', nmul_assoc a' b' c', + nmul_assoc a' b' c, nmul_assoc a' b c', nmul_assoc a b' c'] + exact nmul_nadd_lt₃' ha hb hc + · rw [nmul_le_iff₃'] + intro a' ha b' hb c' hc + -- Porting note: the next line was just + -- repeat' rw [← nmul_assoc] + -- but we need to spell out the arguments for the termination checker. + rw [← nmul_assoc a' b c, ← nmul_assoc a b' c, ← nmul_assoc a b c', ← nmul_assoc a' b' c', + ← nmul_assoc a' b' c, ← nmul_assoc a' b c', ← nmul_assoc a b' c'] + exact nmul_nadd_lt₃ ha hb hc +termination_by (a, b, c) end Ordinal @@ -676,8 +688,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 => nmul_le_nmul_of_nonneg_left - mul_le_mul_of_nonneg_right := fun a b c => nmul_le_nmul_of_nonneg_right } + 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 } namespace Ordinal @@ -700,12 +712,6 @@ theorem nmul_add_one : ∀ a b, a ⨳ (b + 1) = a ⨳ b ♯ a := theorem add_one_nmul : ∀ a b, (a + 1) ⨳ b = a ⨳ b ♯ b := succ_nmul -end Ordinal - -namespace NatOrdinal - -open Ordinal - theorem mul_le_nmul (a b : Ordinal.{u}) : a * b ≤ a ⨳ b := by refine b.limitRecOn ?_ ?_ ?_ · simp @@ -718,4 +724,7 @@ theorem mul_le_nmul (a b : Ordinal.{u}) : a * b ≤ a ⨳ b := by · rw [← IsNormal.blsub_eq.{u, u} (mul_isNormal ha) hc, blsub_le_iff] exact fun i hi => (H i hi).trans_lt (nmul_lt_nmul_of_pos_left hi ha) -end NatOrdinal +@[deprecated mul_le_nmul (since := "2024-08-20")] +alias _root_.NatOrdinal.mul_le_nmul := mul_le_nmul + +end Ordinal diff --git a/Mathlib/SetTheory/Ordinal/Nimber.lean b/Mathlib/SetTheory/Ordinal/Nimber.lean new file mode 100644 index 0000000000000..8a3f05befdbaa --- /dev/null +++ b/Mathlib/SetTheory/Ordinal/Nimber.lean @@ -0,0 +1,393 @@ +/- +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 + +/-- 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 71c72e2dc3afd..fd54a141e2131 100644 --- a/Mathlib/SetTheory/Ordinal/Notation.lean +++ b/Mathlib/SetTheory/Ordinal/Notation.lean @@ -139,12 +139,15 @@ 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 (natCast_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 -/ def cmp : ONote → ONote → Ordering @@ -152,7 +155,7 @@ def cmp : ONote → ONote → Ordering | _, 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 @@ -164,8 +167,8 @@ theorem eq_of_cmp_eq : ∀ {o₁ o₂}, cmp o₁ o₂ = Ordering.eq → o₁ = o obtain rfl := eq_of_cmp_eq h₁ revert h; cases h₂ : _root_.cmp (n₁ : ℕ) n₂ <;> intro h <;> try cases h obtain rfl := eq_of_cmp_eq h - rw [_root_.cmp, cmpUsing_eq_eq] at h₂ - obtain rfl := Subtype.eq (eq_of_incomp h₂) + rw [_root_.cmp, cmpUsing_eq_eq, not_lt, not_lt, ← le_antisymm_iff] at h₂ + obtain rfl := Subtype.eq h₂ simp protected theorem zero_lt_one : (0 : ONote) < 1 := by @@ -230,18 +233,20 @@ theorem NF.zero_of_zero {e n a} (h : NF (ONote.oadd e n a)) (e0 : e = 0) : a = 0 simpa [e0, NFBelow_zero] using h.snd' theorem NFBelow.repr_lt {o b} (h : NFBelow o b) : repr o < ω ^ b := by - induction' h with _ e n a eb b h₁ h₂ h₃ _ IH - · exact opow_pos _ omega_pos - · rw [repr] + induction h with + | 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 _ e n a eb b h₁ h₂ h₃ _ _ <;> constructor - exacts [h₁, h₂, lt_of_lt_of_le h₃ bb] + induction h with + | zero => exact zero + | oadd' h₁ h₂ h₃ _ _ => constructor; exacts [h₁, h₂, lt_of_lt_of_le h₃ bb] theorem NF.below_of_lt {e n a b} (H : repr e < b) : NF (ONote.oadd e n a) → NFBelow (ONote.oadd e n a) b @@ -251,7 +256,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 @@ -265,13 +270,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, natCast_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 @@ -309,7 +314,7 @@ theorem cmp_compares : ∀ (a b : ONote) [NF a] [NF b], (cmp a b).Compares a b rw [ite_eq_iff] at nhr cases' nhr with nhr nhr · cases nhr; contradiction - obtain rfl := Subtype.eq (eq_of_incomp ⟨(not_lt_of_ge nhl), nhr.left⟩) + obtain rfl := Subtype.eq (nhl.eq_of_not_lt nhr.1) have IHa := @cmp_compares _ _ h₁.snd h₂.snd revert IHa; cases cmp a₁ a₂ <;> intro IHa <;> dsimp at IHa case lt => exact oadd_lt_oadd_3 IHa @@ -323,7 +328,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) @@ -331,9 +336,15 @@ 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 @@ -441,7 +452,7 @@ 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 + · simpa using (Ordinal.mul_le_mul_iff_left <| opow_pos (repr e') omega0_pos).2 (natCast_le.2 n'.pos) · rw [ee, ← add_assoc, ← mul_add] @@ -501,7 +512,7 @@ theorem repr_sub : ∀ (o₁ o₂) [NF o₁] [NF o₂], repr (o₁ - o₂) = rep simpa using mul_le_mul_left' (natCast_le.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 @@ -555,7 +566,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 (natCast_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] @@ -568,8 +579,8 @@ 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 (opow_isLimit_left omega0_isLimit this), mul_assoc, + mul_omega0_dvd (natCast_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 ω. @@ -652,9 +663,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] @@ -680,7 +689,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] @@ -723,9 +732,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 @@ -781,22 +790,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' omega0_isLimit).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 omega0_isLimit.2 _ l + · apply (principal_mul_omega0 (omega0_isLimit.2 _ h) l).le.trans simpa using mul_le_mul_right' (one_le_iff_ne_zero.2 e0) ω section @@ -827,29 +836,30 @@ 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 - · simp [opow_mul, opow_add, mul_assoc] + 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 <| + (opow_le_opow_right omega0_pos <| mul_le_mul_left' (succ_le_succ_iff.2 (natCast_le.2 (le_of_lt k.lt_succ_self))) _) calc (ω0 ^ (k.succ : Ordinal)) * α' + R' @@ -861,10 +871,10 @@ 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 (natCast_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)) @@ -877,7 +887,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 @@ -892,21 +902,22 @@ theorem repr_opow (o₁ o₂) [NF o₁] [NF o₂] : repr (o₁ ^ o₂) = repr o · cases' e₂ : split' o₂ with b' k cases' nf_repr_split' e₂ with _ r₂ by_cases h : m = 0 - · simp [opow_def, opow, e₁, h, r₁, e₂, r₂, ← Nat.one_eq_succ_zero] + · simp [opow_def, opow, e₁, h, r₁, e₂, r₂] 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] @@ -915,7 +926,7 @@ theorem repr_opow (o₁ o₂) [NF o₁] [NF o₂] : repr (o₁ ^ o₂) = repr o simp only [opow_def, opow, e₁, r₁, split_eq_scale_split' e₂, opowAux2, repr] cases' k with k · simp [r₂, opow_mul, repr_opow_aux₁ a00 al aa, add_assoc] - · simp? [r₂, opow_add, opow_mul, mul_assoc, add_assoc, -repr] says + · simp? [r₂, opow_add, opow_mul, mul_assoc, add_assoc, -repr, -opow_natCast] says simp only [mulNat_eq_mul, repr_add, repr_scale, repr_mul, repr_ofNat, opow_add, opow_mul, mul_assoc, add_assoc, r₂, Nat.cast_add, Nat.cast_one, add_one_eq_succ, opow_succ] simp only [repr, opow_zero, Nat.succPNat_coe, Nat.cast_one, mul_one, add_zero, opow_one] @@ -953,13 +964,13 @@ 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 omega0_isLimit).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 @@ -1012,39 +1023,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'⟩ + ⟨mul_isLimit this omega0_isLimit, 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'⟩ + ⟨add_isLimit _ (mul_isLimit this omega0_isLimit), 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 ⟨opow_isLimit 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)⟩ + ⟨add_isLimit _ (opow_isLimit 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 diff --git a/Mathlib/SetTheory/Ordinal/Principal.lean b/Mathlib/SetTheory/Ordinal/Principal.lean index 02c84a0a53cd7..2835fd286b3f3 100644 --- a/Mathlib/SetTheory/Ordinal/Principal.lean +++ b/Mathlib/SetTheory/Ordinal/Principal.lean @@ -14,9 +14,9 @@ We define principal or indecomposable ordinals, and we prove the standard proper * `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 +* `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 @@ -24,16 +24,15 @@ We define principal or indecomposable ordinals, and we prove the standard proper of `fun x ↦ ω ^ x`. -/ -universe u v w - -noncomputable section +universe u open Order namespace Ordinal --- Porting note: commented out, doesn't seem necessary ---local infixr:0 "^" => @pow Ordinal Ordinal Ordinal.hasPow +section Arbitrary + +variable {op : Ordinal → Ordinal → Ordinal} /-! ### Principal ordinals -/ @@ -42,41 +41,50 @@ namespace Ordinal ordinals less than it is closed under that operation. In standard mathematical usage, this term is almost exclusively used for additive and multiplicative principal ordinals. -For simplicity, we break usual convention and regard 0 as principal. -/ +For simplicity, we break usual convention and regard `0` as principal. -/ def Principal (op : Ordinal → Ordinal → Ordinal) (o : Ordinal) : Prop := ∀ ⦃a b⦄, a < o → b < o → op a b < o -theorem principal_iff_principal_swap {op : Ordinal → Ordinal → Ordinal} {o : Ordinal} : - Principal op o ↔ Principal (Function.swap op) o := by +theorem principal_swap_iff {o : Ordinal} : Principal (Function.swap op) o ↔ Principal op o := by constructor <;> exact fun h a b ha hb => h hb ha -theorem principal_zero {op : Ordinal → Ordinal → Ordinal} : Principal op 0 := fun a _ h => +@[deprecated principal_swap_iff (since := "2024-08-18")] +theorem principal_iff_principal_swap {o : Ordinal} : + Principal op o ↔ Principal (Function.swap op) o := + principal_swap_iff + +theorem not_principal_iff {o : Ordinal} : ¬ Principal op o ↔ ∃ a < o, ∃ b < o, o ≤ op a b := by + simp [Principal] + +theorem principal_zero : Principal op 0 := fun a _ h => (Ordinal.not_lt_zero a h).elim @[simp] -theorem principal_one_iff {op : Ordinal → Ordinal → Ordinal} : Principal op 1 ↔ op 0 0 = 0 := by +theorem principal_one_iff : Principal op 1 ↔ op 0 0 = 0 := by refine ⟨fun h => ?_, fun h a b ha hb => ?_⟩ · rw [← lt_one_iff_zero] exact h zero_lt_one zero_lt_one · rwa [lt_one_iff_zero, ha, hb] at * -theorem Principal.iterate_lt {op : Ordinal → Ordinal → Ordinal} {a o : Ordinal} (hao : a < o) - (ho : Principal op o) (n : ℕ) : (op a)^[n] a < o := by +theorem Principal.iterate_lt {a o : Ordinal} (hao : a < o) (ho : Principal op o) (n : ℕ) : + (op a)^[n] a < o := by induction' n with n hn · rwa [Function.iterate_zero] · rw [Function.iterate_succ'] exact ho hao hn -theorem op_eq_self_of_principal {op : Ordinal → Ordinal → Ordinal} {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 _) +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 + apply H.le_apply.antisymm' rw [← IsNormal.bsup_eq.{u, u} H ho', bsup_le_iff] exact fun b hbo => (ho hao hbo).le -theorem nfp_le_of_principal {op : Ordinal → Ordinal → Ordinal} {a o : Ordinal} (hao : a < o) - (ho : Principal op o) : nfp (op a) a ≤ o := +theorem nfp_le_of_principal {a o : Ordinal} (hao : a < o) (ho : Principal op o) : + nfp (op a) a ≤ o := nfp_le fun n => (ho.iterate_lt hao n).le +end Arbitrary + /-! ### Principal ordinals are unbounded -/ #adaptation_note /-- 2024-04-23 @@ -85,8 +93,8 @@ 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. -/ 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) := - fun a b ha hb => by + Principal op (nfp (fun o' => blsub₂.{u, u, u} o' o' (@fun a _ b _ => op a b)) o) := by + intro a b ha hb rw [lt_nfp] at * cases' ha with m hm cases' hb with n hn @@ -95,11 +103,12 @@ theorem principal_nfp_blsub₂ (op : Ordinal → Ordinal → Ordinal) (o : Ordin ((fun o' => blsub₂.{u, u, u} o' o' (@fun a _ b _ => op a b))^[n] o) with h h · use n + 1 rw [Function.iterate_succ'] - exact lt_blsub₂.{u} (@fun a _ b _ => op a b) (hm.trans_le h) hn + exact lt_blsub₂ (@fun a _ b _ => op a b) (hm.trans_le h) hn · use m + 1 rw [Function.iterate_succ'] - exact lt_blsub₂.{u} (@fun a _ b _ => op a b) hm (hn.trans_le h) + exact lt_blsub₂ (@fun a _ b _ => op a b) hm (hn.trans_le h) +/-- Principal ordinals under any operation form a ZFC proper class. -/ 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⟩ @@ -139,87 +148,103 @@ theorem principal_add_iff_add_left_eq_self {o : Ordinal} : exact (add_isNormal a).strictMono hbo theorem exists_lt_add_of_not_principal_add {a} (ha : ¬Principal (· + ·) a) : - ∃ b c, b < a ∧ c < a ∧ b + c = a := by - unfold Principal at ha - push_neg at ha - rcases ha with ⟨b, c, hb, hc, H⟩ + ∃ b < a, ∃ c < a, b + c = a := by + rw [not_principal_iff] at ha + rcases ha with ⟨b, hb, c, hc, H⟩ refine - ⟨b, _, hb, lt_of_le_of_ne (sub_le_self a b) fun hab => ?_, Ordinal.add_sub_cancel_of_le hb.le⟩ + ⟨b, hb, _, lt_of_le_of_ne (sub_le_self a b) fun hab => ?_, Ordinal.add_sub_cancel_of_le hb.le⟩ rw [← sub_le, hab] at H exact H.not_lt hc theorem principal_add_iff_add_lt_ne_self {a} : - Principal (· + ·) a ↔ ∀ ⦃b c⦄, b < a → c < a → b + c ≠ a := - ⟨fun ha b c hb hc => (ha hb hc).ne, fun H => by + Principal (· + ·) a ↔ ∀ b < a, ∀ c < a, b + c ≠ a := + ⟨fun ha b hb c hc => (ha hb hc).ne, fun H => by by_contra! ha - rcases exists_lt_add_of_not_principal_add ha with ⟨b, c, hb, hc, rfl⟩ - exact (H hb hc).irrefl⟩ + 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 < omega) : a + omega = omega := 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 (· + ·) omega := - 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 < (omega^b)) : a + (omega^b) = (omega^b) := by - refine le_antisymm ?_ (le_add_left _ _) +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⟩ - refine le_trans (add_le_add_right (le_of_lt ax) _) ?_ - rw [opow_succ, ← mul_add, add_omega xo] - · rcases (lt_opow_of_limit omega_ne_zero l).1 h with ⟨x, xb, ax⟩ - exact - (((add_isNormal a).trans (opow_isNormal one_lt_omega)).limit_le l).2 fun y yb => - (add_le_add_left (opow_le_opow_right omega_pos (le_max_right _ _)) _).trans - (le_trans - (IH _ (max_lt xb yb) (ax.trans_le <| opow_le_opow_right omega_pos (le_max_left _ _))) - (opow_le_opow_right omega_pos <| le_of_lt <| max_lt xb yb)) - -theorem principal_add_omega_opow (o : Ordinal) : Principal (· + ·) (omega^o) := - principal_add_iff_add_left_eq_self.2 fun _ => add_omega_opow + rcases (lt_mul_of_limit omega0_isLimit).1 h with ⟨x, xo, ax⟩ + apply (add_le_add_right ax.le _).trans + rw [opow_succ, ← mul_add, add_omega0 xo] + · rcases (lt_opow_of_limit omega0_ne_zero l).1 h with ⟨x, xb, ax⟩ + apply (((add_isNormal a).trans <| opow_isNormal one_lt_omega0).limit_le l).2 + intro y yb + calc a + ω ^ y ≤ a + ω ^ max x y := + add_le_add_left (opow_le_opow_right omega0_pos (le_max_right x y)) _ + _ ≤ ω ^ max 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 omega0_pos <| (max_lt xb yb).le + +@[deprecated (since := "2024-09-30")] +alias add_omega_opow := add_omega0_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} : - Principal (· + ·) o ↔ o = 0 ∨ ∃ a : Ordinal, o = (omega^a) := by +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 => ?_).symm⟩, - fun ⟨b, e⟩ => e.symm ▸ fun a => add_omega_opow⟩ + ⟨fun H => ⟨_, ((lt_or_eq_of_le (opow_log_le_self _ ho)).resolve_left fun h => ?_)⟩, + 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 omega0_isLimit] 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 - suffices e : (omega^log omega o) * ↑n + o = o by - simpa only [e] using le_add_right ((omega^log omega o) * ↑n) o + suffices e : ω ^ log ω o * n + o = o by + simpa only [e] using le_add_right (ω ^ log ω o * ↑n) o induction' n with n IH · simp [Nat.cast_zero, mul_zero, zero_add] - simp only [Nat.cast_succ, mul_add_one, add_assoc, this, IH] + · 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⟩) + Principal (· + ·) (a ^ b) := by + 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 < (omega^b)) (h₂ : (omega^b) ≤ c) : a + c = c := by - rw [← Ordinal.add_sub_cancel_of_le h₂, ← add_assoc, add_omega_opow h₁] +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_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 @@ -245,17 +270,15 @@ theorem principal_mul_one : Principal (· * ·) 1 := by rw [principal_one_iff] exact zero_mul _ -theorem principal_mul_two : Principal (· * ·) 2 := fun a b ha hb => by - have h₂ : succ (1 : Ordinal) = 2 := by simp - dsimp only - rw [← h₂, lt_succ_iff] at ha hb ⊢ +theorem principal_mul_two : Principal (· * ·) 2 := by + intro a b ha hb + rw [← succ_one, lt_succ_iff] at * convert mul_le_mul' ha hb exact (mul_one 1).symm theorem principal_mul_of_le_two {o : Ordinal} (ho : o ≤ 2) : Principal (· * ·) o := by rcases lt_or_eq_of_le ho with (ho | rfl) - · have h₂ : succ (1 : Ordinal) = 2 := by simp - rw [← h₂, lt_succ_iff] at ho + · rw [← succ_one, lt_succ_iff] at ho rcases lt_or_eq_of_le ho with (ho | rfl) · rw [lt_one_iff_zero.1 ho] exact principal_zero @@ -294,81 +317,104 @@ theorem principal_mul_iff_mul_left_eq {o : Ordinal} : rw [← h a ha hao] exact (mul_isNormal ha).strictMono hbo -theorem principal_mul_omega : Principal (· * ·) omega := 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 < omega) : a * omega = omega := - 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 < (omega^c)) (hb : b < omega) : - a * b < (omega^c) := by +@[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⟩ + rcases ((mul_isNormal <| opow_pos _ omega0_pos).limit_lt omega0_isLimit).1 ha with ⟨n, hn, an⟩ 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 ((opow_isNormal 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 < (omega^omega^b)) : - a * (omega^omega^b) = (omega^omega^b) := by - by_cases b0 : b = 0 - · rw [b0, opow_zero, opow_one] at h ⊢ - exact mul_omega a0 h - refine - le_antisymm ?_ - (by simpa only [one_mul] using mul_le_mul_right' (one_le_iff_pos.2 a0) (omega^omega^b)) - rcases (lt_opow_of_limit omega_ne_zero (opow_isLimit_left omega_isLimit b0)).1 h with ⟨x, xb, ax⟩ - apply (mul_le_mul_right' (le_of_lt ax) _).trans - rw [← opow_add, add_omega_opow xb] +@[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_omega0 a0 h + · apply le_antisymm + · obtain ⟨x, xb, ax⟩ := + (lt_opow_of_limit omega0_ne_zero (opow_isLimit_left omega0_isLimit b0)).1 h + apply (mul_le_mul_right' (le_of_lt ax) _).trans + rw [← opow_add, add_omega0_opow xb] + · conv_lhs => rw [← one_mul (ω ^ _)] + exact mul_le_mul_right' (one_le_iff_pos.2 a0) _ + +@[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 -theorem principal_mul_omega_opow_opow (o : Ordinal) : Principal (· * ·) (omega^omega^o) := - principal_mul_iff_mul_left_eq.2 fun _ => mul_omega_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 := fun x y hx hy => by + (ho : Principal (· * ·) (b ^ o)) : Principal (· + ·) o := by + intro x y hx hy have := ho ((opow_lt_opow_iff_right hb).2 hx) ((opow_lt_opow_iff_right hb).2 hy) - dsimp only at *; rwa [← opow_add, opow_lt_opow_iff_right hb] at this + dsimp only at * + 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} : - Principal (· * ·) o ↔ o ≤ 2 ∨ ∃ a : Ordinal, o = (omega^omega^a) := by +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⟩) - · 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⟩) - · simp - exact Or.inr ⟨b, 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_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 -theorem mul_omega_dvd {a : Ordinal} (a0 : 0 < a) (ha : a < omega) : ∀ {b}, omega ∣ b → a * b = b - | _, ⟨b, rfl⟩ => by rw [← mul_assoc, mul_omega a0 ha] +@[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] + +@[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 + (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] intro c hcb - have hb₁ : 1 < b := (lt_succ 1).trans (by simpa using hb₂) - have hbo₀ : (b^b.log a) ≠ 0 := Ordinal.pos_iff_ne_zero.1 (opow_pos _ (zero_lt_one.trans hb₁)) - apply le_trans (mul_le_mul_right' (le_of_lt (lt_mul_succ_div a hbo₀)) c) + have hb₁ : 1 < b := (lt_succ 1).trans (by rwa [succ_one]) + have hbo₀ : b ^ log b a ≠ 0 := Ordinal.pos_iff_ne_zero.1 (opow_pos _ (zero_lt_one.trans hb₁)) + apply (mul_le_mul_right' (le_of_lt (lt_mul_succ_div a hbo₀)) c).trans rw [mul_assoc, opow_succ] - refine mul_le_mul_left' (le_of_lt (hb (hbl.2 _ ?_) hcb)) _ + refine mul_le_mul_left' (hb (hbl.2 _ ?_) hcb).le _ rw [div_lt hbo₀, ← opow_succ] exact lt_opow_succ_log_self hb₁ _ · rw [opow_succ] @@ -377,16 +423,21 @@ theorem mul_eq_opow_log_succ {a b : Ordinal.{u}} (ha : a ≠ 0) (hb : Principal /-! #### Exponential principal ordinals -/ -theorem principal_opow_omega : Principal (·^·) omega := 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_omega0 {a : Ordinal} (a1 : 1 < a) (h : a < ω) : a ^ ω = ω := + ((opow_le_of_limit (one_le_iff_ne_zero.1 <| le_of_lt a1) omega0_isLimit).2 fun _ hb => + (principal_opow_omega0 h hb).le).antisymm + (right_le_opow _ a1) -theorem opow_omega {a : Ordinal} (a1 : 1 < a) (h : a < omega) : (a^omega) = omega := - le_antisymm - ((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) - (right_le_opow _ a1) +@[deprecated (since := "2024-09-30")] +alias opow_omega := opow_omega0 end Ordinal diff --git a/Mathlib/SetTheory/Ordinal/Topology.lean b/Mathlib/SetTheory/Ordinal/Topology.lean index 24d2a3e5e65c9..6993d517742e4 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,31 +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⟩ - exact ⟨_, out_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 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 := 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 := - ((mem_closure_tfae a s).out 0 5).trans <| 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 := - ((mem_closure_tfae a s).out 0 4).trans <| 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 ↔ @@ -141,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 @@ -154,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] - refine ⟨fun H o ho f hf => H (out_nonempty_iff_ne_zero.2 ho) _ ?_, fun H ι hι f hf => ?_⟩ + 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 _ @@ -188,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 - ⟨_, out_nonempty_iff_ne_zero.2 ho.1, typein (· < ·), fun i => h _ (typein_lt_self i), + ⟨_, 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 diff --git a/Mathlib/SetTheory/Surreal/Basic.lean b/Mathlib/SetTheory/Surreal/Basic.lean index ff9eb5a98053c..a8c2cc9c505b6 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 16ea03efd65ee..f47d76361786e 100644 --- a/Mathlib/SetTheory/Surreal/Dyadic.lean +++ b/Mathlib/SetTheory/Surreal/Dyadic.lean @@ -75,9 +75,10 @@ theorem birthday_half : birthday (powHalf 1) = 2 := by /-- For all natural numbers `n`, the pre-games `powHalf n` are numeric. -/ theorem numeric_powHalf (n) : (powHalf n).Numeric := by - induction' n with n hn - · exact numeric_one - · constructor + induction n with + | zero => exact numeric_one + | succ n hn => + constructor · simpa using hn.moveLeft_lt default · exact ⟨fun _ => numeric_zero, fun _ => hn⟩ @@ -88,9 +89,9 @@ theorem powHalf_succ_le_powHalf (n : ℕ) : powHalf (n + 1) ≤ powHalf n := (powHalf_succ_lt_powHalf n).le theorem powHalf_le_one (n : ℕ) : powHalf n ≤ 1 := by - induction' n with n hn - · exact le_rfl - · exact (powHalf_succ_le_powHalf n).trans hn + induction n with + | zero => exact le_rfl + | succ n hn => exact (powHalf_succ_le_powHalf n).trans hn theorem powHalf_succ_lt_one (n : ℕ) : powHalf (n + 1) < 1 := (powHalf_succ_lt_powHalf n).trans_le <| powHalf_le_one n @@ -168,7 +169,7 @@ theorem nsmul_pow_two_powHalf (n : ℕ) : 2 ^ n * powHalf n = 1 := by @[simp] theorem nsmul_pow_two_powHalf' (n k : ℕ) : 2 ^ n * powHalf (n + k) = powHalf k := by induction' k with k hk - · simp only [add_zero, Surreal.nsmul_pow_two_powHalf, Nat.zero_eq, eq_self_iff_true, + · simp only [add_zero, Surreal.nsmul_pow_two_powHalf, eq_self_iff_true, Surreal.powHalf_zero] · rw [← double_powHalf_succ_eq_powHalf (n + k), ← double_powHalf_succ_eq_powHalf k, ← mul_assoc, mul_comm (2 ^ n) 2, mul_assoc] at hk diff --git a/Mathlib/SetTheory/Surreal/Multiplication.lean b/Mathlib/SetTheory/Surreal/Multiplication.lean index 3f931a7db4fd7..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 @@ -173,7 +173,7 @@ open Relation /-- The relation specifying when a list of (pregame) arguments is considered simpler than another: `ArgsRel a₁ a₂` is true if `a₁`, considered as a multiset, can be obtained from `a₂` by - repeatedly removing a pregame from `a₂` and adding back one or two options of the pregame. -/ + repeatedly removing a pregame from `a₂` and adding back one or two options of the pregame. -/ def ArgsRel := InvImage (TransGen <| CutExpand IsOption) Args.toMultiset /-- `ArgsRel` is well-founded. -/ @@ -463,7 +463,7 @@ theorem Equiv.mul_congr_left (hx₁ : x₁.Numeric) (hx₂ : x₂.Numeric) (hy : (he : x₁ ≈ x₂) : x₁ * y ≈ x₂ * y := equiv_iff_game_eq.2 <| (P24 hx₁ hx₂ hy).1 he -theorem Equiv.mul_congr_right (hx : x.Numeric) (hy₁ : y₁.Numeric) (hy₂ : y₂.Numeric) +theorem Equiv.mul_congr_right (hx : x.Numeric) (hy₁ : y₁.Numeric) (hy₂ : y₂.Numeric) (he : y₁ ≈ y₂) : x * y₁ ≈ x * y₂ := .trans (mul_comm_equiv _ _) <| .trans (mul_congr_left hy₁ hy₂ hx he) (mul_comm_equiv _ _) diff --git a/Mathlib/SetTheory/ZFC/Basic.lean b/Mathlib/SetTheory/ZFC/Basic.lean index 3b4f62f933cd2..bc21fd9e20d72 100644 --- a/Mathlib/SetTheory/ZFC/Basic.lean +++ b/Mathlib/SetTheory/ZFC/Basic.lean @@ -193,7 +193,7 @@ theorem Subset.congr_right : ∀ {x y z : PSet}, Equiv x y → (z ⊆ x ↔ z ⟨a, cb.trans (Equiv.symm ab)⟩⟩ /-- `x ∈ y` as pre-sets if `x` is extensionally equivalent to a member of the family `y`. -/ -protected def Mem (x y : PSet.{u}) : Prop := +protected def Mem (y x : PSet.{u}) : Prop := ∃ b, Equiv x (y.Func b) instance : Membership PSet PSet := @@ -232,6 +232,12 @@ theorem equiv_iff_mem {x y : PSet.{u}} : Equiv x y ↔ ∀ {w : PSet.{u}}, w ∈ theorem Mem.congr_left : ∀ {x y : PSet.{u}}, Equiv x y → ∀ {w : PSet.{u}}, x ∈ w ↔ y ∈ w | _, _, h, ⟨_, _⟩ => ⟨fun ⟨a, ha⟩ => ⟨a, h.symm.trans ha⟩, fun ⟨a, ha⟩ => ⟨a, h.trans ha⟩⟩ +theorem mem_of_subset {x y z : PSet} : x ⊆ y → z ∈ x → z ∈ y + | h₁, ⟨a, h₂⟩ => (h₁ a).elim fun b h₃ => ⟨b, h₂.trans h₃⟩ + +theorem subset_iff {x y : PSet} : x ⊆ y ↔ ∀ ⦃z⦄, z ∈ x → z ∈ y := + ⟨fun h _ => mem_of_subset h, fun h a => h (Mem.mk _ a)⟩ + private theorem mem_wf_aux : ∀ {x y : PSet.{u}}, Equiv x y → Acc (· ∈ ·) y | ⟨α, A⟩, ⟨β, B⟩, H => ⟨_, by @@ -254,10 +260,10 @@ instance : IsIrrefl PSet (· ∈ ·) := mem_wf.isIrrefl theorem mem_asymm {x y : PSet} : x ∈ y → y ∉ x := - asymm + asymm (r := (· ∈ ·)) theorem mem_irrefl (x : PSet) : x ∉ x := - irrefl x + irrefl (r := (· ∈ ·)) x /-- Convert a pre-set to a `Set` of pre-sets. -/ def toSet (u : PSet.{u}) : Set PSet.{u} := @@ -339,6 +345,33 @@ instance : LawfulSingleton PSet PSet := instance (x y : PSet) : Inhabited (insert x y).Type := inferInstanceAs (Inhabited <| Option y.Type) +@[simp] +theorem mem_insert_iff : ∀ {x y z : PSet.{u}}, x ∈ insert y z ↔ Equiv x y ∨ x ∈ z + | x, y, ⟨α, A⟩ => + show (x ∈ PSet.mk (Option α) fun o => Option.rec y A o) ↔ Equiv x y ∨ x ∈ PSet.mk α A from + ⟨fun m => + match m with + | ⟨some a, ha⟩ => Or.inr ⟨a, ha⟩ + | ⟨none, h⟩ => Or.inl h, + fun m => + match m with + | Or.inr ⟨a, ha⟩ => ⟨some a, ha⟩ + | Or.inl h => ⟨none, h⟩⟩ + +theorem mem_insert (x y : PSet) : x ∈ insert x y := + mem_insert_iff.2 <| Or.inl Equiv.rfl + +theorem mem_insert_of_mem {y z : PSet} (x) (h : z ∈ y) : z ∈ insert x y := + mem_insert_iff.2 <| Or.inr h + +@[simp] +theorem mem_singleton {x y : PSet} : x ∈ ({y} : PSet) ↔ Equiv x y := + mem_insert_iff.trans + ⟨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 + /-- The n-th von Neumann ordinal -/ def ofNat : ℕ → PSet | 0 => ∅ @@ -355,6 +388,12 @@ protected def sep (p : PSet → Prop) (x : PSet) : PSet := instance : Sep PSet PSet := ⟨PSet.sep⟩ +theorem mem_sep {p : PSet → Prop} (H : ∀ x y, Equiv x y → p x → p y) : + ∀ {x y : PSet}, y ∈ PSet.sep p x ↔ y ∈ x ∧ p y + | ⟨_, _⟩, _ => + ⟨fun ⟨⟨a, pa⟩, h⟩ => ⟨⟨a, h⟩, H _ _ h.symm pa⟩, fun ⟨⟨a, h⟩, pa⟩ => + ⟨⟨a, H _ _ h pa⟩, h⟩⟩ + /-- The pre-set powerset operator -/ def powerset (x : PSet) : PSet := ⟨Set x.Type, fun p => ⟨{ a // p a }, fun y => x.Func y.1⟩⟩ @@ -578,11 +617,11 @@ theorem eval_mk {n f x} : /-- The membership relation for ZFC sets is inherited from the membership relation for pre-sets. -/ protected def Mem : ZFSet → ZFSet → Prop := - Quotient.lift₂ PSet.Mem fun _ _ _ _ hx hy => + Quotient.lift₂ (· ∈ ·) fun _ _ _ _ hx hy => propext ((Mem.congr_left hx).trans (Mem.congr_right hy)) -instance : Membership ZFSet ZFSet := - ⟨ZFSet.Mem⟩ +instance : Membership ZFSet ZFSet where + mem t s := ZFSet.Mem s t @[simp] theorem mk_mem_iff {x y : PSet} : mk x ∈ mk y ↔ x ∈ y := @@ -726,16 +765,7 @@ instance : LawfulSingleton ZFSet ZFSet := @[simp] theorem mem_insert_iff {x y z : ZFSet.{u}} : x ∈ insert y z ↔ x = y ∨ x ∈ z := - Quotient.inductionOn₃ x y z fun x y ⟨α, A⟩ => - show (x ∈ PSet.mk (Option α) fun o => Option.rec y A o) ↔ mk x = mk y ∨ x ∈ PSet.mk α A from - ⟨fun m => - match m with - | ⟨some a, ha⟩ => Or.inr ⟨a, ha⟩ - | ⟨none, h⟩ => Or.inl (Quotient.sound h), - fun m => - match m with - | Or.inr ⟨a, ha⟩ => ⟨some a, ha⟩ - | Or.inl h => ⟨none, Quotient.exact h⟩⟩ + Quotient.inductionOn₃ x y z fun _ _ _ => PSet.mem_insert_iff.trans (or_congr_left eq.symm) theorem mem_insert (x y : ZFSet) : x ∈ insert x y := mem_insert_iff.2 <| Or.inl rfl @@ -750,8 +780,7 @@ theorem toSet_insert (x y : ZFSet) : (insert x y).toSet = insert x y.toSet := by @[simp] theorem mem_singleton {x y : ZFSet.{u}} : x ∈ @singleton ZFSet.{u} ZFSet.{u} _ y ↔ x = y := - Iff.trans mem_insert_iff - ⟨fun o => Or.rec (fun h => h) (fun n => absurd n (not_mem_empty _)) o, Or.inl⟩ + Quotient.inductionOn₂ x y fun _ _ => PSet.mem_singleton.trans eq.symm @[simp] theorem toSet_singleton (x : ZFSet) : ({x} : ZFSet).toSet = {x} := by @@ -802,12 +831,12 @@ instance : Sep ZFSet ZFSet := @[simp] theorem mem_sep {p : ZFSet.{u} → Prop} {x y : ZFSet.{u}} : y ∈ ZFSet.sep p x ↔ y ∈ x ∧ p y := - Quotient.inductionOn₂ x y fun ⟨α, A⟩ y => - ⟨fun ⟨⟨a, pa⟩, h⟩ => ⟨⟨a, h⟩, by rwa [@Quotient.sound PSet _ _ _ h]⟩, fun ⟨⟨a, h⟩, pa⟩ => - ⟨⟨a, by - rw [mk_func] at h - rwa [mk_func, ← ZFSet.sound h]⟩, - h⟩⟩ + 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) : @@ -831,8 +860,7 @@ def powerset : ZFSet → ZFSet := @[simp] theorem mem_powerset {x y : ZFSet.{u}} : y ∈ powerset x ↔ y ⊆ x := - Quotient.inductionOn₂ x y fun ⟨α, A⟩ ⟨β, B⟩ => - show (⟨β, B⟩ : PSet.{u}) ∈ PSet.powerset.{u} ⟨α, A⟩ ↔ _ by simp [mem_powerset, subset_iff] + Quotient.inductionOn₂ x y fun _ _ => PSet.mem_powerset.trans subset_iff.symm theorem sUnion_lem {α β : Type u} (A : α → PSet) (B : β → PSet) (αβ : ∀ a, ∃ b, Equiv (A a) (B b)) : ∀ a, ∃ b, Equiv ((sUnion ⟨α, A⟩).Func a) ((sUnion ⟨β, B⟩).Func b) @@ -862,23 +890,24 @@ 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 @[simp] theorem mem_sUnion {x y : ZFSet.{u}} : y ∈ ⋃₀ x ↔ ∃ z ∈ x, y ∈ z := - Quotient.inductionOn₂ x y fun _ _ => - Iff.trans PSet.mem_sUnion - ⟨fun ⟨z, h⟩ => ⟨⟦z⟧, h⟩, fun ⟨z, h⟩ => Quotient.inductionOn z (fun z h => ⟨z, h⟩) h⟩ + Quotient.inductionOn₂ x y fun _ _ => PSet.mem_sUnion.trans + ⟨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 @@ -886,7 +915,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) @@ -999,10 +1028,10 @@ instance : IsIrrefl ZFSet (· ∈ ·) := mem_wf.isIrrefl theorem mem_asymm {x y : ZFSet} : x ∈ y → y ∉ x := - asymm + asymm (r := (· ∈ ·)) theorem mem_irrefl (x : ZFSet) : x ∉ x := - irrefl x + irrefl (r := (· ∈ ·)) x theorem regularity (x : ZFSet.{u}) (h : x ≠ ∅) : ∃ y ∈ x, x ∩ y = ∅ := by_contradiction fun ne => @@ -1097,7 +1126,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) @@ -1241,7 +1270,7 @@ def ToSet (B : Class.{u}) (A : Class.{u}) : Prop := ∃ x : ZFSet, ↑x = A ∧ B x /-- `A ∈ B` if `A` is a ZFC set which satisfies `B` -/ -protected def Mem (A B : Class.{u}) : Prop := +protected def Mem (B A : Class.{u}) : Prop := ToSet.{u} B A instance : Membership Class Class := @@ -1259,7 +1288,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 := @@ -1292,10 +1321,10 @@ instance : IsIrrefl Class (· ∈ ·) := mem_wf.isIrrefl theorem mem_asymm {x y : Class} : x ∈ y → y ∉ x := - asymm + asymm (r := (· ∈ ·)) theorem mem_irrefl (x : Class) : x ∉ x := - irrefl x + irrefl (r := (· ∈ ·)) x /-- **There is no universal set.** This is stated as `univ ∉ univ`, meaning that `univ` (the class of all sets) is proper (does not @@ -1310,7 +1339,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) -/ @@ -1368,7 +1397,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 := @@ -1541,3 +1570,5 @@ noncomputable def toSet_equiv : ZFSet.{u} ≃ {s : Set ZFSet.{u} // Small.{u, u+ right_inv s := Subtype.coe_injective <| toSet_equiv_aux s.2 end ZFSet + +set_option linter.style.longFile 1700 diff --git a/Mathlib/SetTheory/ZFC/Rank.lean b/Mathlib/SetTheory/ZFC/Rank.lean new file mode 100644 index 0000000000000..2cecc412eaa35 --- /dev/null +++ b/Mathlib/SetTheory/ZFC/Rank.lean @@ -0,0 +1,209 @@ +/- +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.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 +same as the indexing types. + +## Definitions + +* `PSet.rank`: Ordinal rank of a pre-set. +* `ZFSet.rank`: Ordinal rank of a ZFC set. +-/ + +universe u v + +open Ordinal Order + +namespace PSet + +/-- The ordinal rank of a pre-set -/ +noncomputable def rank : PSet.{u} → Ordinal.{u} + | ⟨_, A⟩ => lsub fun a => rank (A a) + +theorem rank_congr : ∀ {x y : PSet}, Equiv x y → rank x = rank y + | ⟨_, _⟩, ⟨_, _⟩, ⟨αβ, βα⟩ => + lsub_eq_of_range_eq (by + ext + constructor <;> simp <;> intro a h + · obtain ⟨b, h'⟩ := αβ a + exists b + rw [← h, rank_congr h'] + · obtain ⟨b, h'⟩ := βα a + exists b + rw [← h, rank_congr h']) + +theorem rank_lt_of_mem : ∀ {x y : PSet}, y ∈ x → rank y < rank x + | ⟨_, _⟩, _, ⟨_, h⟩ => by + rw [rank_congr h] + apply lt_lsub + +theorem rank_le_iff {o : Ordinal} : ∀ {x : PSet}, rank x ≤ o ↔ ∀ ⦃y⦄, y ∈ x → rank y < o + | ⟨_, A⟩ => + ⟨fun h _ h' => (rank_lt_of_mem h').trans_le h, fun h => + lsub_le fun a => h (Mem.mk A a)⟩ + +theorem lt_rank_iff {o : Ordinal} {x : PSet} : o < rank x ↔ ∃ y ∈ x, o ≤ rank y := by + rw [← not_iff_not, not_lt, rank_le_iff] + simp + +variable {x y : PSet.{u}} + +@[gcongr] theorem rank_mono (h : x ⊆ y) : rank x ≤ rank y := + rank_le_iff.2 fun _ h₁ => rank_lt_of_mem (mem_of_subset h h₁) + +@[simp] +theorem rank_empty : rank ∅ = 0 := by simp [rank] + +@[simp] +theorem rank_insert : rank (insert x y) = max (succ (rank x)) (rank y) := by + apply le_antisymm + · simp_rw [rank_le_iff, mem_insert_iff] + rintro _ (h | h) + · simp [rank_congr h] + · simp [rank_lt_of_mem h] + · apply max_le + · exact (rank_lt_of_mem (mem_insert x y)).succ_le + · exact rank_mono (subset_iff.2 fun z => mem_insert_of_mem x) + +@[simp] +theorem rank_singleton : rank {x} = succ (rank x) := + rank_insert.trans (by simp) + +theorem rank_pair : rank {x, y} = max (succ (rank x)) (succ (rank y)) := by + simp + +@[simp] +theorem rank_powerset : rank (powerset x) = succ (rank x) := by + apply le_antisymm + · simp_rw [rank_le_iff, mem_powerset, lt_succ_iff] + intro + exact rank_mono + · rw [succ_le_iff] + apply rank_lt_of_mem + simp + +/-- For the rank of `⋃₀ x`, we only have `rank (⋃₀ x) ≤ rank x ≤ rank (⋃₀ x) + 1`. + +This inequality is split into `rank_sUnion_le` and `le_succ_rank_sUnion`. -/ +theorem rank_sUnion_le : rank (⋃₀ x) ≤ rank x := by + simp_rw [rank_le_iff, mem_sUnion] + intro _ ⟨_, _, _⟩ + trans <;> apply rank_lt_of_mem <;> assumption + +theorem le_succ_rank_sUnion : rank x ≤ succ (rank (⋃₀ x)) := by + rw [← rank_powerset] + apply rank_mono + rw [subset_iff] + intro z _ + rw [mem_powerset, subset_iff] + intro _ _ + 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 + induction' x using mem_wf.induction with x ih + rw [mem_wf.rank_eq] + simp_rw [← fun y : { y // y ∈ x } => ih y y.2] + apply (le_of_forall_lt _).antisymm (Ordinal.iSup_le.{u + 1, u} _) <;> intro h + · rw [lt_lift_iff] + rintro ⟨o, rfl, h⟩ + simpa [Ordinal.lt_iSup.{u + 1, u}] using lt_rank_iff.1 h + · simpa using rank_lt_of_mem h.2 + +end PSet + +namespace ZFSet + +variable {x y : ZFSet.{u}} + +/-- The ordinal rank of a ZFC set -/ +noncomputable def rank : ZFSet.{u} → Ordinal.{u} := + Quotient.lift _ fun _ _ => PSet.rank_congr + +theorem rank_lt_of_mem : y ∈ x → rank y < rank x := + Quotient.inductionOn₂ x y fun _ _ => PSet.rank_lt_of_mem + +theorem rank_le_iff {o : Ordinal} : rank x ≤ o ↔ ∀ ⦃y⦄, y ∈ x → rank y < o := + ⟨fun h _ h' => (rank_lt_of_mem h').trans_le h, + Quotient.inductionOn x fun _ h => + PSet.rank_le_iff.2 fun y h' => @h ⟦y⟧ h'⟩ + +theorem lt_rank_iff {o : Ordinal} : o < rank x ↔ ∃ y ∈ x, o ≤ rank y := by + rw [← not_iff_not, not_lt, rank_le_iff] + simp + +@[gcongr] theorem rank_mono (h : x ⊆ y) : rank x ≤ rank y := + rank_le_iff.2 fun _ h₁ => rank_lt_of_mem (h h₁) + +@[simp] +theorem rank_empty : rank ∅ = 0 := PSet.rank_empty + +@[simp] +theorem rank_insert : rank (insert x y) = max (succ (rank x)) (rank y) := + Quotient.inductionOn₂ x y fun _ _ => PSet.rank_insert + +@[simp] +theorem rank_singleton : rank {x} = succ (rank x) := + rank_insert.trans (by simp) + +theorem rank_pair : rank {x, y} = max (succ (rank x)) (succ (rank y)) := by + simp + +@[simp] +theorem rank_union : rank (x ∪ y) = max (rank x) (rank y) := by + apply le_antisymm + · simp_rw [rank_le_iff, mem_union, lt_max_iff] + intro + apply Or.imp <;> apply rank_lt_of_mem + · apply max_le <;> apply rank_mono <;> intro _ h <;> simp [h] + +@[simp] +theorem rank_powerset : rank (powerset x) = succ (rank x) := + Quotient.inductionOn x fun _ => PSet.rank_powerset + +/-- For the rank of `⋃₀ x`, we only have `rank (⋃₀ x) ≤ rank x ≤ rank (⋃₀ x) + 1`. + +This inequality is split into `rank_sUnion_le` and `le_succ_rank_sUnion`. -/ +theorem rank_sUnion_le : rank (⋃₀ x) ≤ rank x := by + simp_rw [rank_le_iff, mem_sUnion] + intro _ ⟨_, _, _⟩ + trans <;> apply rank_lt_of_mem <;> assumption + +theorem le_succ_rank_sUnion : rank x ≤ succ (rank (⋃₀ x)) := by + rw [← rank_powerset] + apply rank_mono + intro z _ + rw [mem_powerset] + intro _ _ + rw [mem_sUnion] + exists z + +@[simp] +theorem rank_range {α : Type u} {f : α → ZFSet.{max u v}} : + rank (range f) = lsub fun i => rank (f i) := by + apply (lsub_le _).antisymm' + · 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 + induction' x using inductionOn with x ih + rw [mem_wf.rank_eq] + simp_rw [← fun y : { y // y ∈ x } => ih y y.2] + apply (le_of_forall_lt _).antisymm (Ordinal.iSup_le.{u + 1, u} _) <;> intro h + · rw [lt_lift_iff] + rintro ⟨o, rfl, h⟩ + simpa [Ordinal.lt_iSup.{u + 1, u}] 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..19199a7f7e67b --- /dev/null +++ b/Mathlib/Std/Data/HashMap.lean @@ -0,0 +1,22 @@ +/- +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 + +/-! +# 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 dd7ed5f122df3..46952152d3576 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 @@ -84,6 +97,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 @@ -117,13 +131,19 @@ import Mathlib.Tactic.Linarith.Parsing 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.Lint import Mathlib.Tactic.Linter.MinImports 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 @@ -133,6 +153,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 @@ -188,6 +209,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 @@ -202,6 +224,7 @@ import Mathlib.Tactic.Simps.NotationClass import Mathlib.Tactic.SlimCheck import Mathlib.Tactic.SplitIfs import Mathlib.Tactic.Spread +import Mathlib.Tactic.StacksAttribute import Mathlib.Tactic.Subsingleton import Mathlib.Tactic.Substs import Mathlib.Tactic.SuccessIfFailWithMsg diff --git a/Mathlib/Tactic/Abel.lean b/Mathlib/Tactic/Abel.lean index 105a5e5f2c9bb..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 @@ -563,8 +563,4 @@ macro (name := abelConv) "abel" : conv => @[inherit_doc abelConv] macro "abel!" : conv => `(conv| first | discharge => abel1! | try_this abel_nf!) -end Abel - -end Tactic - -end Mathlib +end Mathlib.Tactic.Abel diff --git a/Mathlib/Tactic/AdaptationNote.lean b/Mathlib/Tactic/AdaptationNote.lean index 1f6e49a9cb244..d8700ceceb3c2 100644 --- a/Mathlib/Tactic/AdaptationNote.lean +++ b/Mathlib/Tactic/AdaptationNote.lean @@ -3,6 +3,7 @@ Copyright (c) 2024 Kyle Miller. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kyle Miller -/ +import Mathlib.Init import Lean /-! @@ -10,7 +11,7 @@ import Lean This file defines a `#adaptation_note` command. Adaptation notes are comments that are used to indicate that a piece of code -has been changed to accomodate a change in Lean core. +has been changed to accommodate a change in Lean core. They typically require further action/maintenance to be taken in the future. -/ @@ -37,7 +38,7 @@ def reportAdaptationNote (f : Syntax → Meta.Tactic.TryThis.Suggestion) : MetaM Meta.Tactic.TryThis.addSuggestion (← getRef) (f stx') (origSpan? := ← getRef) /-- Adaptation notes are comments that are used to indicate that a piece of code -has been changed to accomodate a change in Lean core. +has been changed to accommodate a change in Lean core. They typically require further action/maintenance to be taken in the future. -/ elab (name := adaptationNoteCmd) "#adaptation_note " (docComment)? : command => do Elab.Command.liftTermElabM <| reportAdaptationNote (fun s => (⟨s⟩ : TSyntax `tactic)) diff --git a/Mathlib/Tactic/Algebraize.lean b/Mathlib/Tactic/Algebraize.lean new file mode 100644 index 0000000000000..74c3a9eaf8230 --- /dev/null +++ b/Mathlib/Tactic/Algebraize.lean @@ -0,0 +1,298 @@ +/- +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. +2. A constructor for the `Algebra` property. In this case it is assumed that the `RingHom` property +is the last argument of the constructor, and that no other explicit argument is needed. The tactic +then constructs the `Algebra` property by applying the constructor to the `RingHom` property. + +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 constructor for the `Algebra` property. In this case it is assumed that the `RingHom` property +is the last argument of the constructor, and that no other explicit argument is needed. The tactic +then constructs the `Algebra` property by applying the constructor to the `RingHom` property. + +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 be the name of the corresponding `Algebra` property (or a 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. -/ + match cinfo with + | .inductInfo _ => + let pargs := pargs.set! 0 args[0]! + let pargs := pargs.set! 1 args[1]! + let tp ← mkAppOptM p pargs -- This should be the type `Algebra.Property A B` + unless (← synthInstance? tp).isSome do + liftMetaTactic fun mvarid => do + let nm ← mkFreshBinderNameForTactic `algebraizeInst + let mvar ← mvarid.define nm tp decl.toExpr + let (_, mvar) ← mvar.intro1P + return [mvar] + /- Otherwise, the attribute points to a constructor of the `Algebra` property. In this case, + we assume that the `RingHom` property is the last argument of the constructor (and that + this is all we need to supply explicitly). -/ + | .ctorInfo ctor => + -- construct the desired value + let pargs := pargs.set! (n - 1) decl.toExpr + let val ← mkAppOptM p pargs + + -- construct the expected type + let alg ← mkAppOptM ``Algebra #[args[0]!, args[1]!, none, none] + let algInst := (← synthInstance? alg) + let mut argsType := Array.mkArray (ctor.numParams) (none : Option Expr) + argsType := argsType.set! 0 args[0]! + argsType := argsType.set! 1 args[1]! + argsType := argsType.set! (ctor.numParams - 1) algInst + let tp := ← mkAppOptM ctor.induct argsType + + unless (← synthInstance? tp).isSome do + liftMetaTactic fun mvarid => do + let nm ← mkFreshBinderNameForTactic `algebraizeInst + let mvar ← mvarid.define nm tp val + let (_, mvar) ← mvar.intro1P + return [mvar] + | _ => logError s!"bad argument to `algebraize` attribute: {p}. \ + Only supporting inductive types or constructors." + | 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) => 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/ApplyAt.lean b/Mathlib/Tactic/ApplyAt.lean index 4f3e2750087e7..1bf1be33a22a4 100644 --- a/Mathlib/Tactic/ApplyAt.lean +++ b/Mathlib/Tactic/ApplyAt.lean @@ -38,3 +38,5 @@ elab "apply" t:term "at" i:ident : tactic => withSynthesize <| withMainContext d (← mkAppOptM' f (mvs.pop.push ldecl.toExpr |>.map fun e => some e)) let (_, mainGoal) ← mainGoal.intro1P replaceMainGoal <| [mainGoal] ++ mvs.pop.toList.map fun e => e.mvarId! + +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 09d1d12840f90..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 @@ -214,3 +214,5 @@ elab_rules : tactic | `(tactic| apply_fun $f $[$loc]? $[using $P]?) => do (atTarget := withMainContext do replaceMainGoal <| ← applyFunTarget f P (← getMainGoal)) (failed := fun _ ↦ throwError "apply_fun failed") + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/ApplyWith.lean b/Mathlib/Tactic/ApplyWith.lean index 80bee54facbee..c4ddb7097accc 100644 --- a/Mathlib/Tactic/ApplyWith.lean +++ b/Mathlib/Tactic/ApplyWith.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.Init import Lean.Elab.Eval import Lean.Elab.Tactic.ElabTerm @@ -22,3 +23,5 @@ open Lean Meta Elab Tactic Term elab (name := applyWith) "apply" " (" &"config" " := " cfg:term ") " e:term : tactic => do let cfg ← unsafe evalTerm ApplyConfig (mkConst ``ApplyConfig) cfg evalApplyLikeTactic (·.apply · cfg) e + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/ArithMult.lean b/Mathlib/Tactic/ArithMult.lean index f8bc0c339d012..c2e5f0530ec2d 100644 --- a/Mathlib/Tactic/ArithMult.lean +++ b/Mathlib/Tactic/ArithMult.lean @@ -41,3 +41,5 @@ proof term. -/ macro (name := arith_mult?) "arith_mult?" c:Aesop.tactic_clause* : tactic => `(tactic| { show_term { arith_mult $c* } }) + +end ArithmeticFunction diff --git a/Mathlib/Tactic/ArithMult/Init.lean b/Mathlib/Tactic/ArithMult/Init.lean index e2a7114273970..40a20040c7bdc 100644 --- a/Mathlib/Tactic/ArithMult/Init.lean +++ b/Mathlib/Tactic/ArithMult/Init.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Arend Mellendijk -/ +import Mathlib.Init import Aesop /-! diff --git a/Mathlib/Tactic/Attr/Core.lean b/Mathlib/Tactic/Attr/Core.lean index e08139380e134..3da5505f2c84f 100644 --- a/Mathlib/Tactic/Attr/Core.lean +++ b/Mathlib/Tactic/Attr/Core.lean @@ -21,7 +21,4 @@ attribute [monad_norm] seq_eq_bind_map attribute [mfld_simps] id and_true true_and Function.comp_apply and_self eq_self not_false true_or or_true heq_eq_eq forall_const and_imp --- Porting note: until we change the default induction principle on `Nat`: -attribute [ghost_simps] Nat.zero_eq - attribute [nontriviality] eq_iff_true_of_subsingleton diff --git a/Mathlib/Tactic/Attr/Register.lean b/Mathlib/Tactic/Attr/Register.lean index 9369b682db7c2..cc80f10b4abbf 100644 --- a/Mathlib/Tactic/Attr/Register.lean +++ b/Mathlib/Tactic/Attr/Register.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 -/ +import Mathlib.Init import Lean.Meta.Tactic.Simp.SimpTheorems import Lean.Meta.Tactic.Simp.RegisterCommand import Lean.LabelAttribute @@ -83,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/Basic.lean b/Mathlib/Tactic/Basic.lean index 7ebc0c52d04c7..3d427acacd7df 100644 --- a/Mathlib/Tactic/Basic.lean +++ b/Mathlib/Tactic/Basic.lean @@ -14,6 +14,7 @@ import Mathlib.Tactic.Linter.OldObtain # Basic tactics and utilities for tactic writing This file defines some basic utilities for tactic writing, and also +- a dummy `variables` macro (which warns that the Lean 4 name is `variable`) - the `introv` tactic, which allows the user to automatically introduce the variables of a theorem and explicitly name the non-dependent hypotheses, - an `assumption` macro, calling the `assumption` tactic on all goals @@ -25,8 +26,12 @@ changing them into regular hypotheses). namespace Mathlib.Tactic open Lean Parser.Tactic Elab Command Elab.Tactic Meta +/-- Syntax for the `variables` command: this command is just a stub, +and merely warns that it has been renamed to `variable` in Lean 4. -/ syntax (name := «variables») "variables" (ppSpace bracketedBinder)* : command +/-- The `variables` command: this is just a stub, +and merely warns that it has been renamed to `variable` in Lean 4. -/ @[command_elab «variables»] def elabVariables : CommandElab | `(variables%$pos $binders*) => do logWarningAt pos "'variables' has been replaced by 'variable' in lean 4" @@ -152,3 +157,5 @@ elab (name := clearValue) "clear_value" hs:(ppSpace colGt term:max)+ : tactic => replaceMainGoal [mvarId] attribute [pp_with_univ] ULift PUnit PEmpty + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Bound/Attribute.lean b/Mathlib/Tactic/Bound/Attribute.lean index f2633e11e5b0c..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 @@ -137,3 +138,5 @@ context. A typical example is exposing an inequality field of a structure, such `HasPowerSeriesOnBall.r_pos`. -/ macro "bound_forward" : attr => `(attr|aesop safe forward (rule_sets := [$(Lean.mkIdent `Bound):ident])) + +end Mathlib.Tactic.Bound diff --git a/Mathlib/Tactic/Bound/Init.lean b/Mathlib/Tactic/Bound/Init.lean index 68e5fdae37e04..5ca4a86975928 100644 --- a/Mathlib/Tactic/Bound/Init.lean +++ b/Mathlib/Tactic/Bound/Init.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Geoffrey Irving -/ +import Mathlib.Init import Aesop.Frontend.Command /-! 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 df7636b3fd528..51dcb46a44da0 100644 --- a/Mathlib/Tactic/CC/Addition.lean +++ b/Mathlib/Tactic/CC/Addition.lean @@ -192,8 +192,8 @@ def mkCCHCongrTheorem (fn : Expr) (nargs : Nat) : CCM (Option CCCongrTheorem) := -- Check if `{ fn, nargs }` is in the cache let key₁ : CCCongrTheoremKey := { fn, nargs } - if let some it₁ := cache.findEntry? key₁ then - return it₁.2 + if let some it := cache[key₁]? then + return it -- Try automatically generated congruence lemma with support for heterogeneous equality. let lemm ← mkCCHCongrWithArity fn nargs @@ -495,7 +495,7 @@ partial def mkProof (lhs rhs : Expr) (H : EntryExpr) (heqProofs : Bool) : CCM Ex getHEqProof a b >>= liftOption else -- TODO(Leo): the following code assumes R is homogeneous. - -- We should add support arbitrary heterogenous reflexive relations. + -- We should add support arbitrary heterogeneous reflexive relations. getEqProof a b >>= liftOption >>= fun aEqb => liftM (liftFromEq R aEqb) let aRbEqTrue ← mkEqTrue aRb if flip then @@ -662,7 +662,7 @@ equality to the todo list. If not, add `e` to the congruence table. -/ def addCongruenceTable (e : Expr) : CCM Unit := do guard e.isApp let k ← mkCongruencesKey e - if let some es := (← get).congruences.find? k then + if let some es := (← get).congruences[k]? then for oldE in es do if ← isCongruent e oldE then -- Found new equivalence: `e ~ oldE` @@ -687,7 +687,7 @@ def addSymmCongruenceTable (e : Expr) : CCM Unit := do let some (rel, lhs, rhs) ← e.relSidesIfSymm? | failure let k ← mkSymmCongruencesKey lhs rhs let newP := (e, rel) - if let some ps := (← get).symmCongruences.find? k then + if let some ps := (← get).symmCongruences[k]? then for p in ps do if ← compareSymm newP p then -- Found new equivalence: `e ~ p.1` @@ -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 @@ -1623,7 +1624,7 @@ def removeParents (e : Expr) (parentsToPropagate : Array Expr := #[]) : CCM (Arr if pocc.symmTable then let some (rel, lhs, rhs) ← p.relSidesIfSymm? | failure let k' ← mkSymmCongruencesKey lhs rhs - if let some lst := (← get).symmCongruences.find? k' then + if let some lst := (← get).symmCongruences[k']? then let k := (p, rel) let newLst ← lst.filterM fun k₂ => (!·) <$> compareSymm k k₂ if !newLst.isEmpty then @@ -1634,7 +1635,7 @@ def removeParents (e : Expr) (parentsToPropagate : Array Expr := #[]) : CCM (Arr { ccs with symmCongruences := ccs.symmCongruences.erase k' } else let k' ← mkCongruencesKey p - if let some es := (← get).congruences.find? k' then + if let some es := (← get).congruences[k']? then let newEs := es.erase p if !newEs.isEmpty then modify fun ccs => @@ -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) @@ -2099,3 +2101,5 @@ def add (type : Expr) (proof : Expr) : CCM Unit := do end CCM end Mathlib.Tactic.CC + +set_option linter.style.longFile 2300 diff --git a/Mathlib/Tactic/CC/Datatypes.lean b/Mathlib/Tactic/CC/Datatypes.lean index 2ea400963f095..6c11094d2ff5a 100644 --- a/Mathlib/Tactic/CC/Datatypes.lean +++ b/Mathlib/Tactic/CC/Datatypes.lean @@ -5,9 +5,9 @@ Authors: Leonardo de Moura, Miyahara Kō -/ import Lean.Meta.CongrTheorems import Lean.Meta.Tactic.Rfl -import Batteries.Data.HashMap.Basic import Batteries.Data.RBMap.Basic import Mathlib.Lean.Meta.Basic +import Std.Data.HashMap.Basic /-! # Datatypes for `cc` @@ -84,7 +84,7 @@ Once the `cc` tactic is used a lot in Mathlib, we should profile and see if `HashSet` could be more optimal. -/ abbrev RBExprSet := Batteries.RBSet Expr compare -/-- `CongrTheorem`s equiped with additional infos used by congruence closure modules. -/ +/-- `CongrTheorem`s equipped with additional infos used by congruence closure modules. -/ structure CCCongrTheorem extends CongrTheorem where /-- If `heqResult` is true, then lemma is based on heterogeneous equality and the conclusion is a heterogeneous equality. -/ @@ -110,7 +110,7 @@ structure CCCongrTheoremKey where deriving BEq, Hashable /-- Caches used to find corresponding `CCCongrTheorem`s. -/ -abbrev CCCongrTheoremCache := Batteries.HashMap CCCongrTheoremKey (Option CCCongrTheorem) +abbrev CCCongrTheoremCache := Std.HashMap CCCongrTheoremKey (Option CCCongrTheorem) /-- Configs used in congruence closure modules. -/ structure CCConfig where @@ -366,7 +366,7 @@ structure Entry where theorem prover. The basic idea is to introduce a counter gmt that records the number of heuristic instantiation that have occurred in the current branch. It is incremented after each round of heuristic instantiation. The field `mt` records the last time any proper descendant - of of thie entry was involved in a merge. -/ + of this entry was involved in a merge. -/ mt : Nat deriving Inhabited @@ -415,7 +415,7 @@ inductive CongruencesKey deriving BEq, Hashable /-- Maps each expression (via `mkCongruenceKey`) to expressions it might be congruent to. -/ -abbrev Congruences := Batteries.HashMap CongruencesKey (List Expr) +abbrev Congruences := Std.HashMap CongruencesKey (List Expr) structure SymmCongruencesKey where (h₁ h₂ : Expr) @@ -426,7 +426,7 @@ structure SymmCongruencesKey where The `Name` identifies which relation the congruence is considered for. Note that this only works for two-argument relations: `ModEq n` and `ModEq m` are considered the same. -/ -abbrev SymmCongruences := Batteries.HashMap SymmCongruencesKey (List (Expr × Name)) +abbrev SymmCongruences := Std.HashMap SymmCongruencesKey (List (Expr × Name)) /-- Stores the root representatives of subsingletons. -/ abbrev SubsingletonReprs := RBExprMap Expr @@ -462,7 +462,7 @@ structure CCState extends CCConfig where /-- Mapping from operators occurring in terms and their canonical representation in this module -/ canOps : RBExprMap Expr := ∅ - /-- Whether the canonical operator is suppoted by AC. -/ + /-- Whether the canonical operator is supported by AC. -/ opInfo : RBExprMap Bool := ∅ /-- Extra `Entry` information used by the AC part of the tactic. -/ acEntries : RBExprMap ACEntry := ∅ @@ -521,7 +521,7 @@ def isCgRoot (ccs : CCState) (e : Expr) : Bool := "Modification Time". The field `mt` is used to implement the mod-time optimization introduced by the Simplify theorem prover. The basic idea is to introduce a counter `gmt` that records the number of heuristic instantiation that have occurred in the current branch. It is incremented after each round -of heuristic instantiation. The field `mt` records the last time any proper descendant of of thie +of heuristic instantiation. The field `mt` records the last time any proper descendant of this entry was involved in a merge. -/ def mt (ccs : CCState) (e : Expr) : Nat := match ccs.entries.find? e with @@ -667,7 +667,7 @@ end CCState /-- The congruence closure module (optionally) uses a normalizer. The idea is to use it (if available) to normalize auxiliary expressions - produced by internal propagation rules (e.g., subsingleton propagator). -/ + produced by internal propagation rules (e.g., subsingleton propagator). -/ structure CCNormalizer where normalize : Expr → MetaM Expr diff --git a/Mathlib/Tactic/CC/Lemmas.lean b/Mathlib/Tactic/CC/Lemmas.lean index cd6fc4d14d2c8..12348c1e7b4cb 100644 --- a/Mathlib/Tactic/CC/Lemmas.lean +++ b/Mathlib/Tactic/CC/Lemmas.lean @@ -4,47 +4,45 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura -/ -import Mathlib.Init.Logic - /-! 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 +86,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/CancelDenoms/Core.lean b/Mathlib/Tactic/CancelDenoms/Core.lean index 4ba1bdec9c1cb..89310275c745f 100644 --- a/Mathlib/Tactic/CancelDenoms/Core.lean +++ b/Mathlib/Tactic/CancelDenoms/Core.lean @@ -10,7 +10,6 @@ import Mathlib.Logic.Basic import Mathlib.Tactic.NormNum.Core import Mathlib.Util.SynthesizeUsing import Mathlib.Util.Qq -import Mathlib.Algebra.Order.Field.Unbundled.Basic /-! # A tactic for canceling numeric denominators @@ -70,14 +69,14 @@ theorem cancel_factors_lt {α} [LinearOrderedField α] {a b ad bd a' b' gcd : α (a < b) = (1 / gcd * (bd * a') < 1 / gcd * (ad * b')) := by rw [mul_lt_mul_left, ← ha, ← hb, ← mul_assoc, ← mul_assoc, mul_comm bd, mul_lt_mul_left] · exact mul_pos had hbd - · exact one_div_pos (α := α) |>.2 hgcd + · exact one_div_pos.2 hgcd theorem cancel_factors_le {α} [LinearOrderedField α] {a b ad bd a' b' gcd : α} (ha : ad * a = a') (hb : bd * b = b') (had : 0 < ad) (hbd : 0 < bd) (hgcd : 0 < gcd) : (a ≤ b) = (1 / gcd * (bd * a') ≤ 1 / gcd * (ad * b')) := by rw [mul_le_mul_left, ← ha, ← hb, ← mul_assoc, ← mul_assoc, mul_comm bd, mul_le_mul_left] · exact mul_pos had hbd - · exact one_div_pos (α := α) |>.2 hgcd + · exact one_div_pos.2 hgcd theorem cancel_factors_eq {α} [Field α] {a b ad bd a' b' gcd : α} (ha : ad * a = a') (hb : bd * b = b') (had : ad ≠ 0) (hbd : bd ≠ 0) (hgcd : gcd ≠ 0) : @@ -147,7 +146,7 @@ def synthesizeUsingNormNum (type : Q(Prop)) : MetaM Q($type) := do catch e => throwError "Could not prove {type} using norm_num. {e.toMessageData}" -/-- `CancelResult mα e v'` provies a value for `v * e` where the denominators have been cancelled. +/-- `CancelResult mα e v'` provides a value for `v * e` where the denominators have been cancelled. -/ structure CancelResult {u : Level} {α : Q(Type u)} (mα : Q(Mul $α)) (e : Q($α)) (v : Q($α)) where /-- An expression with denominators cancelled. -/ diff --git a/Mathlib/Tactic/Cases.lean b/Mathlib/Tactic/Cases.lean index 91ee82d214cb9..34ad80c027727 100644 --- a/Mathlib/Tactic/Cases.lean +++ b/Mathlib/Tactic/Cases.lean @@ -6,12 +6,12 @@ Authors: Mario Carneiro import Lean.Elab.Tactic.Induction import Batteries.Tactic.OpenPrivate import Mathlib.Lean.Expr.Basic +import Batteries.Data.List.Basic /-! - # Backward compatible implementation of lean 3 `cases` tactic -This tactic is similar to the `cases` tactic in lean 4 core, but the syntax for giving +This tactic is similar to the `cases` tactic in Lean 4 core, but the syntax for giving names is different: ``` @@ -58,7 +58,7 @@ def ElimApp.evalNames (elimInfo : ElimInfo) (alts : Array ElimApp.Alt) (withArg let (introduced, g) ← g.introNP generalized.size let subst := (generalized.zip introduced).foldl (init := subst) fun subst (a, b) => subst.insert a (.fvar b) - let g ← liftM $ toClear.foldlM (·.tryClear) g + let g ← liftM <| toClear.foldlM (·.tryClear) g g.withContext do for (stx, fvar) in toTag do Term.addLocalVarInfo stx (subst.get fvar) @@ -68,6 +68,29 @@ def ElimApp.evalNames (elimInfo : ElimInfo) (alts : Array ElimApp.Alt) (withArg pure subgoals open private getElimNameInfo generalizeTargets generalizeVars from Lean.Elab.Tactic.Induction +/-- The `induction'` tactic is similar to the `induction` tactic in Lean 4 core, +but with slightly different syntax (such as, no requirement to name the constructors). + +``` +open Nat + +example (n : ℕ) : 0 < factorial n := by + induction' n with n ih + · rw [factorial_zero] + simp + · rw [factorial_succ] + apply mul_pos (succ_pos n) ih + +example (n : ℕ) : 0 < factorial n := by + induction n + case zero => + rw [factorial_zero] + simp + case succ n ih => + rw [factorial_succ] + apply mul_pos (succ_pos n) ih +``` + -/ elab (name := induction') "induction' " tgts:(Parser.Tactic.casesTarget,+) usingArg:((" using " ident)?) withArg:((" with" (ppSpace colGt binderIdent)+)?) @@ -101,6 +124,28 @@ elab (name := induction') "induction' " tgts:(Parser.Tactic.casesTarget,+) (generalized := fvarIds) (toClear := targetFVarIds) (toTag := toTag) setGoals <| (subgoals ++ result.others).toList ++ gs +/-- The `cases'` tactic is similar to the `cases` tactic in Lean 4 core, but the syntax for giving +names is different: + +``` +example (h : p ∨ q) : q ∨ p := by + cases h with + | inl hp => exact Or.inr hp + | inr hq => exact Or.inl hq + +example (h : p ∨ q) : q ∨ p := by + cases' h with hp hq + · exact Or.inr hp + · exact Or.inl hq + +example (h : p ∨ q) : q ∨ p := by + rcases h with hp | hq + · exact Or.inr hp + · exact Or.inl hq +``` + +Prefer `cases` or `rcases` when possible, because these tactics promote structured proofs. +-/ elab (name := cases') "cases' " tgts:(Parser.Tactic.casesTarget,+) usingArg:((" using " ident)?) withArg:((" with" (ppSpace colGt binderIdent)+)?) : tactic => do let (targets, toTag) ← elabCasesTargets tgts.1.getSepArgs @@ -120,3 +165,5 @@ elab (name := cases') "cases' " tgts:(Parser.Tactic.casesTarget,+) usingArg:((" let subgoals ← ElimApp.evalNames elimInfo result.alts withArg (numEqs := targets.size) (toClear := targetsNew) (toTag := toTag) setGoals <| subgoals.toList ++ gs + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/CasesM.lean b/Mathlib/Tactic/CasesM.lean index f3113a9fab7e4..a1b012c5b4baf 100644 --- a/Mathlib/Tactic/CasesM.lean +++ b/Mathlib/Tactic/CasesM.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.Init import Lean.Elab.Tactic.Conv.Pattern /-! @@ -163,3 +164,5 @@ constructorm* _ ∨ _, _ ∧ _, True elab (name := constructorM) "constructorm" recursive:"*"? ppSpace pats:term,+ : tactic => do let pats ← elabPatterns pats.getElems liftMetaTactic (constructorMatching · (matchPatterns pats) recursive.isSome) + +end Mathlib.Tactic 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 cdae67c853745..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 - -- TODO: is this `dsimp only` step necessary? It doesn't appear to be in the tests below. - let (ty, _) ← dsimp (← g.getType) (← Simp.Context.ofNames [] true) + 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 @@ -159,8 +161,4 @@ theorem assoc_liftHom₂ {f g h i : a ⟶ b} [LiftHom f] [LiftHom g] [LiftHom h] (η : f ⟶ g) (θ : g ⟶ h) (ι : h ⟶ i) [LiftHom₂ η] [LiftHom₂ θ] : η ≫ θ ≫ ι = (η ≫ θ) ≫ ι := (Category.assoc _ _ _).symm -end BicategoryCoherence - -end Tactic - -end Mathlib +end Mathlib.Tactic.BicategoryCoherence diff --git a/Mathlib/Tactic/CategoryTheory/Coherence.lean b/Mathlib/Tactic/CategoryTheory/Coherence.lean index 53555e21afdd6..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 - -- TODO: is this `dsimp only` step necessary? It doesn't appear to be in the tests below. - let (ty, _) ← dsimp (← g.getType) (← Simp.Context.ofNames [] true) + 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]) <;> + [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₂]))) @@ -284,15 +289,11 @@ syntax (name := coherence) "coherence" : tactic elab_rules : tactic | `(tactic| coherence) => do evalTactic (← `(tactic| - (simp (config := {failIfUnchanged := false}) only [bicategoricalComp, - BicategoricalCoherence.hom, - monoidalComp]); + (simp (config := {failIfUnchanged := false}) only [bicategoricalComp, monoidalComp]); whisker_simps (config := {failIfUnchanged := false}); monoidal_simps (config := {failIfUnchanged := false}))) coherence_loop end Coherence -end Tactic - -end Mathlib +end Mathlib.Tactic 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..52e90c1260e65 --- /dev/null +++ b/Mathlib/Tactic/CategoryTheory/Coherence/Datatypes.lean @@ -0,0 +1,467 @@ +/- +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 + +/-! +# 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..63738eff6d0a9 --- /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 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} [Monad m] + +/-- 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} [Context ρ] +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} [Context ρ] + [MonadMor₁ (CoherenceM ρ)] + [MonadMor₂Iso (CoherenceM ρ)] + [MonadNormalExpr (CoherenceM ρ)] [MkEval (CoherenceM ρ)] + [MonadMor₂ (CoherenceM ρ)] + [MkMor₂ (CoherenceM ρ)] + +/-- Trace the proof of the normalization. -/ +def traceProof (nm : Name) (result : Expr) : CoherenceM ρ Unit := do + 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..fb4cf07da5033 --- /dev/null +++ b/Mathlib/Tactic/CategoryTheory/Coherence/PureCoherence.lean @@ -0,0 +1,197 @@ +/- +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 + +/-! +# 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 61bd308d9a8de..0000000000000 --- a/Mathlib/Tactic/CategoryTheory/Monoidal.lean +++ /dev/null @@ -1,705 +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.Coherence - -/-! -# 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'`. - --/ - -namespace Mathlib.Tactic.Monoidal - -open Lean Meta Elab -open CategoryTheory -open Mathlib.Tactic.Coherence - -/-- 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 - 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 - | _ => 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 - /-- Expressions for `α` in the monoidal composition `η ⊗≫ θ := η ≫ α ≫ θ`. -/ - | monoidalCoherence (f g : Mor₁) (e : Expr) : 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 - -/-- 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 - -/-- 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 - | .monoidalCoherence f _ _ => 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 - | .monoidalCoherence _ g _ => g - -/-- 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 - -/-- Return `η` for `η ▷ g₁ ▷ ... ▷ gₙ`. -/ -def WhiskerRightExpr.atom : WhiskerRightExpr → Atom - | WhiskerRightExpr.of η => η - | WhiskerRightExpr.whisker η _ => η.atom - -/-- Return `η` for `f₁ ◁ ... ◁ fₙ ◁ η ▷ g₁ ▷ ... ▷ gₙ`. -/ -def WhiskerLeftExpr.atom : WhiskerLeftExpr → Atom - | WhiskerLeftExpr.of η => η.atom - | WhiskerLeftExpr.whisker _ η => η.atom - -/-- Construct a `Structural` expression from a Lean expression for a structural 2-morphism. -/ -partial def structural? (e : Expr) : MetaM Structural := do - match (← whnfR e).getAppFnArgs with - | (``CategoryStruct.comp, #[_, _, _, α, β]) => - return .comp (← structural? α) (← structural? β) - | (``CategoryStruct.id, #[_, f]) => return .id (← toMor₁ f) - | (``MonoidalCategoryStruct.whiskerLeft, #[f, η]) => - return .whiskerLeft (← toMor₁ f) (← structural? η) - | (``MonoidalCategoryStruct.whiskerRight, #[η, f]) => - return .whiskerRight (← structural? η) (← toMor₁ f) - | (``MonoidalCoherence.hom, #[_, _, f, g, inst]) => - return .monoidalCoherence (← toMor₁ f) (← toMor₁ g) inst - | _ => match ← structuralAtom? e with - | some η => return .atom η - | none => throwError "not a structural 2-morphism" - -/-- 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 - structural? α₀ - -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]] - -/-- 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] - | .monoidalCoherence _ _ e => do - mkAppOptM ``MonoidalCoherence.hom #[none, none, none, none, 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 "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 d83662642b472..f76eba34bf8a9 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 @@ -29,7 +29,7 @@ namespace CategoryTheory variable {C : Type*} [Category C] -/-- A variant of `eq_whisker` with a more convenient argument order for use in tactics. -/ +/-- A variant of `eq_whisker` with a more convenient argument order for use in tactics. -/ theorem eq_whisker' {X Y : C} {f g : X ⟶ Y} (w : f = g) {Z : C} (h : Y ⟶ Z) : f ≫ h = g ≫ h := by rw [w] 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/Change.lean b/Mathlib/Tactic/Change.lean index c961f512b9f9e..235826d756da2 100644 --- a/Mathlib/Tactic/Change.lean +++ b/Mathlib/Tactic/Change.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa -/ +import Mathlib.Init import Lean.Elab.Tactic.ElabTerm import Lean.Meta.Tactic.TryThis /-! diff --git a/Mathlib/Tactic/Check.lean b/Mathlib/Tactic/Check.lean index f4120a1084a1a..f2014e8970861 100644 --- a/Mathlib/Tactic/Check.lean +++ b/Mathlib/Tactic/Check.lean @@ -3,6 +3,7 @@ Copyright (c) 2024 Kyle Miller. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kyle Miller -/ +import Mathlib.Init import Lean.Elab.Tactic.Basic import Lean.PrettyPrinter import Lean.Elab.SyntheticMVars @@ -54,3 +55,5 @@ Like the `#check` command, the `#check` tactic allows stuck typeclass instance p These become metavariables in the output. -/ elab tk:"#check " colGt term:term : tactic => elabCheckTactic tk true term + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Choose.lean b/Mathlib/Tactic/Choose.lean index 8e5fd8cbf8861..910c9d6fe5919 100644 --- a/Mathlib/Tactic/Choose.lean +++ b/Mathlib/Tactic/Choose.lean @@ -220,3 +220,5 @@ elab_rules : tactic syntax "choose!" (ppSpace colGt binderIdent)+ (" using " term)? : tactic macro_rules | `(tactic| choose! $[$ids]* $[using $h]?) => `(tactic| choose ! $[$ids]* $[using $h]?) + +end Mathlib.Tactic.Choose diff --git a/Mathlib/Tactic/Clean.lean b/Mathlib/Tactic/Clean.lean index 3c27d21b3c97e..ae5800de840f4 100644 --- a/Mathlib/Tactic/Clean.lean +++ b/Mathlib/Tactic/Clean.lean @@ -3,6 +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, Michail Karatarakis, Kyle Miller -/ +import Mathlib.Init import Lean.Elab.SyntheticMVars /-! diff --git a/Mathlib/Tactic/ClearExcept.lean b/Mathlib/Tactic/ClearExcept.lean index 8f3e829ba3472..1e4296b36ed44 100644 --- a/Mathlib/Tactic/ClearExcept.lean +++ b/Mathlib/Tactic/ClearExcept.lean @@ -3,6 +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 Mathlib.Init import Lean.Elab.Tactic.ElabTerm /-! @@ -16,7 +17,11 @@ open Lean.Meta namespace Lean.Elab.Tactic -/-- Clears all hypotheses it can besides those provided -/ +/-- Clears all hypotheses it can, except those provided after a minus sign. Example: +``` + clear * - h₁ h₂ +``` +-/ syntax (name := clearExcept) "clear " "*" " -" (ppSpace colGt ident)* : tactic elab_rules : tactic @@ -29,3 +34,5 @@ elab_rules : tactic if let none ← isClass? decl.type then toClear := toClear.push decl.fvarId goal.tryClearMany toClear + +end Lean.Elab.Tactic diff --git a/Mathlib/Tactic/ClearExclamation.lean b/Mathlib/Tactic/ClearExclamation.lean index f15744e865792..5935d32048c32 100644 --- a/Mathlib/Tactic/ClearExclamation.lean +++ b/Mathlib/Tactic/ClearExclamation.lean @@ -3,6 +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 Mathlib.Init import Lean.Elab.Tactic.ElabTerm /-! # `clear!` tactic -/ @@ -16,3 +17,5 @@ elab (name := clear!) "clear!" hs:(ppSpace colGt ident)* : tactic => do let fvarIds ← getFVarIds hs liftMetaTactic1 fun goal ↦ do goal.tryClearMany <| (← collectForwardDeps (fvarIds.map .fvar) true).map (·.fvarId!) + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Clear_.lean b/Mathlib/Tactic/Clear_.lean index d1be75bb99ce9..0e2d325b31be1 100644 --- a/Mathlib/Tactic/Clear_.lean +++ b/Mathlib/Tactic/Clear_.lean @@ -3,6 +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 Mathlib.Init import Lean.Meta.Tactic.Clear import Lean.Elab.Tactic.Basic @@ -21,3 +22,5 @@ elab (name := clear_) "clear_" : tactic => if let none ← isClass? decl.type then toClear := toClear.push decl.fvarId goal.tryClearMany toClear + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Coe.lean b/Mathlib/Tactic/Coe.lean index e4bc51dc6cff2..ce4de64cb81eb 100644 --- a/Mathlib/Tactic/Coe.lean +++ b/Mathlib/Tactic/Coe.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Gabriel Ebner. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner -/ +import Mathlib.Init import Lean.Elab.ElabRules /-! @@ -60,3 +61,5 @@ elab "(" "↥" ")" : term <= expectedType => ensureHasType b ty else throwError "cannot coerce to sort{indentExpr x}" + +end Lean.Elab.Term.CoeImpl diff --git a/Mathlib/Tactic/Common.lean b/Mathlib/Tactic/Common.lean index 53c1b1a4c238f..f9c7a25eb782c 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 @@ -13,6 +13,10 @@ import ImportGraph.Imports -- Import common Batteries tactics and commands import Batteries.Tactic.Where +import Batteries.Tactic.Basic + +-- Import syntax for leansearch +import LeanSearchClient -- Import Mathlib-specific linters. import Mathlib.Tactic.Linter.Lint diff --git a/Mathlib/Tactic/CongrExclamation.lean b/Mathlib/Tactic/CongrExclamation.lean index 8bf7ba9cc9af7..93901abe7dd66 100644 --- a/Mathlib/Tactic/CongrExclamation.lean +++ b/Mathlib/Tactic/CongrExclamation.lean @@ -583,7 +583,7 @@ def Lean.MVarId.preCongr! (mvarId : MVarId) (tryClose : Bool) : MetaM (Option MV -- We allow synthetic opaque metavariables to be assigned to fill in `x = _` goals that might -- appear (for example, due to using `convert` with placeholders). try withAssignableSyntheticOpaque mvarId.refl; return none catch _ => pure () - -- Now we go for (heterogenous) equality via subsingleton considerations + -- Now we go for (heterogeneous) equality via subsingleton considerations if ← Lean.Meta.fastSubsingletonElim mvarId then return none if ← mvarId.proofIrrelHeq then return none return some mvarId diff --git a/Mathlib/Tactic/CongrM.lean b/Mathlib/Tactic/CongrM.lean index de9a449def47e..c41789aec94d7 100644 --- a/Mathlib/Tactic/CongrM.lean +++ b/Mathlib/Tactic/CongrM.lean @@ -76,3 +76,5 @@ elab_rules : tactic let gStx ← Term.exprToSyntax (← getMainTarget) -- Gives the expected type to `refine` as a workaround for its elaboration order. evalTactic <| ← `(tactic| refine (congr($(⟨pattern⟩)) : $gStx)) + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Constructor.lean b/Mathlib/Tactic/Constructor.lean index 8d7ab63b5ab4e..64adccae545b7 100644 --- a/Mathlib/Tactic/Constructor.lean +++ b/Mathlib/Tactic/Constructor.lean @@ -1,8 +1,9 @@ /- -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 import Lean.Meta.Tactic.Constructor diff --git a/Mathlib/Tactic/Continuity/Init.lean b/Mathlib/Tactic/Continuity/Init.lean index bf0e7dfe0f52f..e8ff04a4ed852 100644 --- a/Mathlib/Tactic/Continuity/Init.lean +++ b/Mathlib/Tactic/Continuity/Init.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jannis Limperg -/ +import Mathlib.Init import Aesop /-! diff --git a/Mathlib/Tactic/ContinuousFunctionalCalculus.lean b/Mathlib/Tactic/ContinuousFunctionalCalculus.lean index d65a4da1a676c..9eca49727383c 100644 --- a/Mathlib/Tactic/ContinuousFunctionalCalculus.lean +++ b/Mathlib/Tactic/ContinuousFunctionalCalculus.lean @@ -15,21 +15,33 @@ import Aesop At the moment, these tactics are just wrappers, but potentially they could be more sophisticated. -/ +declare_aesop_rule_sets [CStarAlgebra] + /-- A tactic used to automatically discharge goals relating to the continuous functional calculus, specifically whether the element satisfies the predicate. -/ syntax (name := cfcTac) "cfc_tac" : tactic macro_rules - | `(tactic| cfc_tac) => `(tactic| (try (first | assumption | infer_instance | aesop))) + | `(tactic| cfc_tac) => `(tactic| + try (first | + assumption | + infer_instance | + aesop (rule_sets := [$(Lean.mkIdent `CStarAlgebra):ident]))) -- we may want to try using `fun_prop` directly in the future. /-- A tactic used to automatically discharge goals relating to the continuous functional calculus, specifically concerning continuity of the functions involved. -/ syntax (name := cfcContTac) "cfc_cont_tac" : tactic macro_rules - | `(tactic| cfc_cont_tac) => `(tactic| try (first | fun_prop (disch := aesop) | assumption)) + | `(tactic| cfc_cont_tac) => + `(tactic| try (first + | fun_prop (disch := aesop (config := {warnOnNonterminal := false}) + (rule_sets := [$(Lean.mkIdent `CStarAlgebra):ident])) + | assumption)) /-- A tactic used to automatically discharge goals relating to the non-unital continuous functional calculus, specifically concerning whether `f 0 = 0`. -/ syntax (name := cfcZeroTac) "cfc_zero_tac" : tactic macro_rules - | `(tactic| cfc_zero_tac) => `(tactic| try (first | aesop | assumption)) + | `(tactic| cfc_zero_tac) => + `(tactic| try + (first | aesop (rule_sets := [$(Lean.mkIdent `CStarAlgebra):ident]) | assumption)) diff --git a/Mathlib/Tactic/Conv.lean b/Mathlib/Tactic/Conv.lean index 840ffec93b3ce..c3936735e3032 100644 --- a/Mathlib/Tactic/Conv.lean +++ b/Mathlib/Tactic/Conv.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Gabriel Ebner. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner -/ +import Mathlib.Init import Lean.Elab.Tactic.Conv.Basic import Lean.Elab.Command @@ -133,3 +134,5 @@ syntax "#simp" (&" only")? (simpArgs)? " =>"? ppSpace term : command macro_rules | `(#simp%$tk $[only%$o]? $[[$args,*]]? $[=>]? $e) => `(#conv%$tk simp $[only%$o]? $[[$args,*]]? => $e) + +end Mathlib.Tactic.Conv diff --git a/Mathlib/Tactic/Convert.lean b/Mathlib/Tactic/Convert.lean index bd9219b70db22..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 @@ -46,7 +46,8 @@ def Lean.MVarId.convertLocalDecl (g : MVarId) (fvarId : FVarId) (typeNew : Expr) (patterns : List (TSyntax `rcasesPat) := []) : MetaM (MVarId × List MVarId) := g.withContext do let typeOld ← fvarId.getType - let v ← mkFreshExprMVar (← mkAppM ``Eq (if symm then #[typeNew, typeOld] else #[typeOld, typeNew])) + let v ← mkFreshExprMVar (← mkAppM ``Eq + (if symm then #[typeNew, typeOld] else #[typeOld, typeNew])) let pf ← if symm then mkEqSymm v else pure v let res ← g.replaceLocalDecl fvarId typeNew pf let gs ← v.mvarId!.congrN! depth config patterns diff --git a/Mathlib/Tactic/Core.lean b/Mathlib/Tactic/Core.lean index bc9892963dcee..1aeb2717c5047 100644 --- a/Mathlib/Tactic/Core.lean +++ b/Mathlib/Tactic/Core.lean @@ -258,3 +258,5 @@ def getPackageDir (pkg : String) : IO System.FilePath := do /-- Returns the mathlib root directory. -/ def getMathlibDir := getPackageDir "Mathlib" + +end Mathlib diff --git a/Mathlib/Tactic/DefEqTransformations.lean b/Mathlib/Tactic/DefEqTransformations.lean index f84e06c214a9f..1bd541cc82ae7 100644 --- a/Mathlib/Tactic/DefEqTransformations.lean +++ b/Mathlib/Tactic/DefEqTransformations.lean @@ -247,7 +247,7 @@ elab "eta_reduce" : conv => runDefEqConvTactic etaReduceAll /-- Eta expand every sub-expression in the given expression. -As a side-effect, beta reduces any pre-existing instances of eta expanded terms. -/ +As a side-effect, beta reduces any pre-existing instances of eta expanded terms. -/ partial def etaExpandAll (e : Expr) : MetaM Expr := do let betaOrApp (f : Expr) (args : Array Expr) : Expr := if f.etaExpanded?.isSome then f.beta args else mkAppN f args 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/DeriveTraversable.lean b/Mathlib/Tactic/DeriveTraversable.lean index 147e79d3bde4c..9b4bba79c6c92 100644 --- a/Mathlib/Tactic/DeriveTraversable.lean +++ b/Mathlib/Tactic/DeriveTraversable.lean @@ -55,7 +55,7 @@ def mapField (n : Name) (cl f α β e : Expr) : TermElabM Expr := do return e /-- Get the auxiliary local declaration corresponding to the current declaration. If there are -multiple declaraions it will throw. -/ +multiple declarations it will throw. -/ def getAuxDefOfDeclName : TermElabM FVarId := do let some declName ← getDeclName? | throwError "no 'declName?'" let auxDeclMap := (← read).auxDeclToFullName diff --git a/Mathlib/Tactic/Eqns.lean b/Mathlib/Tactic/Eqns.lean index f682526f53380..35ce6fc0c98ce 100644 --- a/Mathlib/Tactic/Eqns.lean +++ b/Mathlib/Tactic/Eqns.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 Mathlib.Init import Lean.Meta.Eqns import Batteries.Lean.NameMapAttribute import Lean.Elab.Exception diff --git a/Mathlib/Tactic/Eval.lean b/Mathlib/Tactic/Eval.lean index 8edda73b3590a..e8611d5425ea1 100644 --- a/Mathlib/Tactic/Eval.lean +++ b/Mathlib/Tactic/Eval.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ +import Mathlib.Init import Qq.Macro /-! diff --git a/Mathlib/Tactic/ExistsI.lean b/Mathlib/Tactic/ExistsI.lean index 09df3468c3bb8..636ee485e54b7 100644 --- a/Mathlib/Tactic/ExistsI.lean +++ b/Mathlib/Tactic/ExistsI.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Arthur Paulino, Gabriel Ebner, Moritz Doll -/ +import Mathlib.Init /-! # The `existsi` tactic This file defines the `existsi` tactic: its purpose is to instantiate existential quantifiers. @@ -30,3 +31,5 @@ example : ∃ x : Nat, ∃ y : Nat, x = y := by -/ macro "existsi " es:term,+ : tactic => `(tactic| refine ⟨$es,*, ?_⟩) + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Explode.lean b/Mathlib/Tactic/Explode.lean index da1139fbe0012..d8c2f0dc5f172 100644 --- a/Mathlib/Tactic/Explode.lean +++ b/Mathlib/Tactic/Explode.lean @@ -115,7 +115,7 @@ partial def explodeCore (e : Expr) (depth : Nat) (entries : Entries) (start : Bo let entries := valEntry?.map (entries.addSynonym var) |>.getD entries explodeCore (body.instantiate1 var) depth entries | _ => do - -- Right now all of these are caught by this case case: + -- Right now all of these are caught by this case: -- Expr.lit, Expr.forallE, Expr.const, Expr.sort, Expr.mvar, Expr.fvar, Expr.bvar -- (Note: Expr.mdata is stripped by cleanupAnnotations) -- Might be good to handle them individually. @@ -271,3 +271,7 @@ elab "#explode " stx:term : command => withoutModifyingEnv <| Command.runTermEla let entries ← explode e let fitchTable : MessageData ← entriesToMessageData entries logInfo <|← addMessageContext m!"{heading}\n\n{fitchTable}\n" + +end Explode + +end Mathlib diff --git a/Mathlib/Tactic/Explode/Datatypes.lean b/Mathlib/Tactic/Explode/Datatypes.lean index 0ce6999aa004c..1379a9f398989 100644 --- a/Mathlib/Tactic/Explode/Datatypes.lean +++ b/Mathlib/Tactic/Explode/Datatypes.lean @@ -3,6 +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, Evgenia Karunus, Kyle Miller -/ +import Mathlib.Init import Lean.Util.Trace /-! @@ -65,7 +66,7 @@ structure Entries : Type where /-- Find a row where `Entry.expr` == `e`. -/ def Entries.find? (es : Entries) (e : Expr) : Option Entry := - es.s.find? e + es.s[e]? /-- Length of our entries. -/ def Entries.size (es : Entries) : Nat := @@ -84,3 +85,7 @@ def Entries.add (entries : Entries) (expr : Expr) (entry : Entry) : Entry × Ent This is used by `let` bindings where `expr` is an fvar. -/ def Entries.addSynonym (entries : Entries) (expr : Expr) (entry : Entry) : Entries := ⟨entries.s.insert expr entry, entries.l⟩ + +end Explode + +end Mathlib diff --git a/Mathlib/Tactic/Explode/Pretty.lean b/Mathlib/Tactic/Explode/Pretty.lean index cb2b463d13943..79d34b772d0ec 100644 --- a/Mathlib/Tactic/Explode/Pretty.lean +++ b/Mathlib/Tactic/Explode/Pretty.lean @@ -63,3 +63,7 @@ def entriesToMessageData (entries : Entries) : MetaM MessageData := do let paddedThms ← padRight <| entries.l.map (·.thm) rowToMessageData paddedLines paddedDeps paddedThms entries.l + +end Explode + +end Mathlib diff --git a/Mathlib/Tactic/ExtendDoc.lean b/Mathlib/Tactic/ExtendDoc.lean index ece9c14e0436f..87e11b9cbef8d 100644 --- a/Mathlib/Tactic/ExtendDoc.lean +++ b/Mathlib/Tactic/ExtendDoc.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa -/ +import Mathlib.Init import Lean.Elab.ElabRules import Lean.DocString diff --git a/Mathlib/Tactic/ExtractGoal.lean b/Mathlib/Tactic/ExtractGoal.lean index fd7e32324ebc2..46ebf8c95a989 100644 --- a/Mathlib/Tactic/ExtractGoal.lean +++ b/Mathlib/Tactic/ExtractGoal.lean @@ -3,6 +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, Kyle Miller, Damiano Testa -/ +import Mathlib.Init import Lean.Elab.Tactic.ElabTerm import Lean.Meta.Tactic.Cleanup import Lean.PrettyPrinter @@ -167,3 +168,5 @@ elab_rules : tactic let cmd := if ← Meta.isProp ty then "theorem" else "def" pure m!"{cmd} {sig} := sorry" logInfo msg + +end Mathlib.Tactic.ExtractGoal diff --git a/Mathlib/Tactic/FBinop.lean b/Mathlib/Tactic/FBinop.lean index 590322600e3c9..01903971c62dd 100644 --- a/Mathlib/Tactic/FBinop.lean +++ b/Mathlib/Tactic/FBinop.lean @@ -206,7 +206,7 @@ where let type ← instantiateMVars (← inferType e) trace[Elab.fbinop] "visiting {e} : {type}" let some (_, x) ← extractS type - | -- We want our operators to be "homogenous" so do a defeq check as an elaboration hint + | -- We want our operators to be "homogeneous" so do a defeq check as an elaboration hint let x' ← mkFreshExprMVar none let some maxType ← applyS maxS x' | trace[Elab.fbinop] "mvar apply failed"; return t trace[Elab.fbinop] "defeq hint {maxType} =?= {type}" diff --git a/Mathlib/Tactic/FailIfNoProgress.lean b/Mathlib/Tactic/FailIfNoProgress.lean index 7544d90f2ec45..00a6545c4d97c 100644 --- a/Mathlib/Tactic/FailIfNoProgress.lean +++ b/Mathlib/Tactic/FailIfNoProgress.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Thomas Murrills. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Thomas Murrills -/ +import Mathlib.Init import Lean.Elab.Tactic.Basic import Lean.Meta.Tactic.Util @@ -80,3 +81,5 @@ elab_rules : tactic let goal ← getMainGoal let l ← runAndFailIfNoProgress goal (evalTactic tacs) replaceMainGoal l + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/FieldSimp.lean b/Mathlib/Tactic/FieldSimp.lean index 8db488b31477d..b02abb4f47983 100644 --- a/Mathlib/Tactic/FieldSimp.lean +++ b/Mathlib/Tactic/FieldSimp.lean @@ -194,8 +194,4 @@ elab_rules : tactic _ ← simpLocation r.ctx {} dis loc -end FieldSimp - -end Tactic - -end Mathlib +end Mathlib.Tactic.FieldSimp diff --git a/Mathlib/Tactic/FinCases.lean b/Mathlib/Tactic/FinCases.lean index 90da0519ec7cb..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 @@ -60,7 +60,7 @@ partial def finCasesAt (g : MVarId) (hyp : FVarId) : MetaM (List MVarId) := g.wi -- Deal with `x : A`, where `[Fintype A]` is available: let inst ← synthInstance (← mkAppM ``Fintype #[type]) let elems ← mkAppOptM ``Fintype.elems #[type, inst] - let t ← mkAppM ``Membership.mem #[.fvar hyp, elems] + let t ← mkAppM ``Membership.mem #[elems, .fvar hyp] let v ← mkAppOptM ``Fintype.complete #[type, inst, Expr.fvar hyp] let (fvar, g) ← (← g.assert `this t v).intro1P finCasesAt g fvar diff --git a/Mathlib/Tactic/Find.lean b/Mathlib/Tactic/Find.lean index e52d15513b559..6e411fa824810 100644 --- a/Mathlib/Tactic/Find.lean +++ b/Mathlib/Tactic/Find.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Sebastian Ullrich. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sebastian Ullrich -/ +import Mathlib.Init import Batteries.Util.Cache import Lean.HeadIndex import Lean.Elab.Command @@ -22,7 +23,7 @@ or the `find` tactic which looks for lemmas which are `apply`able against the cu -/ -open Lean +open Lean Std open Lean.Meta open Lean.Elab open Lean.Elab @@ -50,7 +51,7 @@ private def isBlackListed (declName : Name) : MetaM Bool := do <||> isRec declName <||> isMatcher declName -initialize findDeclsPerHead : DeclCache (Lean.HashMap HeadIndex (Array Name)) ← +initialize findDeclsPerHead : DeclCache (Std.HashMap HeadIndex (Array Name)) ← DeclCache.mk "#find: init cache" failure {} fun _ c headMap ↦ do if (← isBlackListed c.name) then return headMap @@ -58,7 +59,7 @@ initialize findDeclsPerHead : DeclCache (Lean.HashMap HeadIndex (Array Name)) -- to avoid leaking metavariables. let (_, _, ty) ← forallMetaTelescopeReducing c.type let head := ty.toHeadIndex - pure <| headMap.insert head (headMap.findD head #[] |>.push c.name) + pure <| headMap.insert head (headMap.getD head #[] |>.push c.name) def findType (t : Expr) : TermElabM Unit := withReducible do let t ← instantiateMVars t @@ -67,7 +68,7 @@ def findType (t : Expr) : TermElabM Unit := withReducible do let env ← getEnv let mut numFound := 0 - for n in (← findDeclsPerHead.get).findD head #[] do + for n in (← findDeclsPerHead.get).getD head #[] do let c := env.find? n |>.get! let cTy := c.instantiateTypeLevelParams (← mkFreshLevelMVars c.numLevelParams) let found ← forallTelescopeReducing cTy fun cParams cTy' ↦ do @@ -134,3 +135,5 @@ elab "#find " t:term : tactic => do let t ← Term.elabTerm t none Term.synthesizeSyntheticMVars (postpone := .no) (ignoreStuckTC := true) findType t + +end Mathlib.Tactic.Find diff --git a/Mathlib/Tactic/FunProp/Attr.lean b/Mathlib/Tactic/FunProp/Attr.lean index 314b0c2f80965..b77b4b9cf2b0d 100644 --- a/Mathlib/Tactic/FunProp/Attr.lean +++ b/Mathlib/Tactic/FunProp/Attr.lean @@ -38,3 +38,7 @@ initialize funPropAttr : Unit ← erase := fun _declName => throwError "can't remove `funProp` attribute (not implemented yet)" } + +end Meta.FunProp + +end Mathlib diff --git a/Mathlib/Tactic/FunProp/ContDiff.lean b/Mathlib/Tactic/FunProp/ContDiff.lean index 636f5fa0db5bf..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,14 +72,13 @@ 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:ℕ∞)` and `funProp` can't work with such theorem. The theorem should be state where `n` is explicitly the smallest possible value i.e. `n=m+1`. -In conjunction with `ContDiff.of_le` we can recover the full power of the original theorem. -/ +In conjunction with `ContDiff.of_le` we can recover the full power of the original theorem. -/ theorem ContDiff.differentiable_iteratedDeriv' {m : ℕ} {f : K → F} (hf : ContDiff K (m+1) f) : Differentiable K (iteratedDeriv m f) := ContDiff.differentiable_iteratedDeriv m hf (Nat.cast_lt.mpr m.lt_succ_self) diff --git a/Mathlib/Tactic/FunProp/Core.lean b/Mathlib/Tactic/FunProp/Core.lean index 1459b86032271..e337933dc09dc 100644 --- a/Mathlib/Tactic/FunProp/Core.lean +++ b/Mathlib/Tactic/FunProp/Core.lean @@ -31,7 +31,7 @@ def synthesizeInstance (thmId : Origin) (x type : Expr) : MetaM Bool := do else trace[Meta.Tactic.fun_prop] "{← ppOrigin thmId}, failed to assign instance{indentExpr type} -sythesized value{indentExpr val}\nis not definitionally equal to{indentExpr x}" +synthesized value{indentExpr val}\nis not definitionally equal to{indentExpr x}" return false | _ => trace[Meta.Tactic.fun_prop] @@ -39,27 +39,23 @@ sythesized value{indentExpr val}\nis not definitionally equal to{indentExpr x}" return false -/-- Synthesize arguments `xs` either with typeclass synthesis, with `fun_prop` or with discharger. -/ -def synthesizeArgs (thmId : Origin) (xs : Array Expr) (bis : Array BinderInfo) + +/-- Synthesize arguments `xs` either with typeclass synthesis, with `fun_prop` or with +discharger. -/ +def synthesizeArgs (thmId : Origin) (xs : Array Expr) (funProp : Expr → FunPropM (Option Result)) : FunPropM Bool := do let mut postponed : Array Expr := #[] - for x in xs, bi in bis do + for x in xs do let type ← inferType x - if bi.isInstImplicit then - unless (← synthesizeInstance thmId x type) do - logError s!"Failed to synthesize instance `{← ppExpr type}` \ - when applying theorem `{← ppOrigin' thmId}`." - return false - else if (← instantiateMVars x).isMVar then + if (← instantiateMVars x).isMVar then -- try type class if (← isClass? type).isSome then if (← synthesizeInstance thmId x type) then continue - - -- try function property - if (← isFunProp type.getForallBody) then + else if (← isFunProp type.getForallBody) then + -- try function property if let .some ⟨proof⟩ ← funProp type then if (← isDefEq x proof) then continue @@ -103,14 +99,14 @@ def synthesizeArgs (thmId : Origin) (xs : Array Expr) (bis : Array BinderInfo) /-- Try to apply theorem - core function -/ -def tryTheoremCore (xs : Array Expr) (bis : Array BinderInfo) (val : Expr) (type : Expr) (e : Expr) +def tryTheoremCore (xs : Array Expr) (val : Expr) (type : Expr) (e : Expr) (thmId : Origin) (funProp : Expr → FunPropM (Option Result)) : FunPropM (Option Result) := do withTraceNode `Meta.Tactic.fun_prop (fun r => return s!"[{ExceptToEmoji.toEmoji r}] applying: {← ppOrigin' thmId}") do if (← isDefEq type e) then - if ¬(← synthesizeArgs thmId xs bis funProp) then + if ¬(← synthesizeArgs thmId xs funProp) then return none let proof ← instantiateMVars (mkAppN val xs) @@ -128,17 +124,17 @@ def tryTheoremWithHint? (e : Expr) (thmOrigin : Origin) let go : FunPropM (Option Result) := do let thmProof ← thmOrigin.getValue let type ← inferType thmProof - let (xs, bis, type) ← forallMetaTelescope type + let (xs, _, type) ← forallMetaTelescope type for (i,x) in hint do try for (id,v) in hint do xs[id]!.mvarId!.assignIfDefeq v catch _ => - trace[Meta.Tactic.fun_trans] + trace[Debug.Meta.Tactic.fun_prop] "failed to use hint {i} `{← ppExpr x} when applying theorem {← ppOrigin thmOrigin}" - tryTheoremCore xs bis thmProof type e thmOrigin funProp + tryTheoremCore xs thmProof type e thmOrigin funProp -- `simp` introduces new meta variable context depth for some reason -- This is probably to avoid mvar assignment when trying a theorem fails @@ -148,7 +144,7 @@ def tryTheoremWithHint? (e : Expr) (thmOrigin : Origin) -- hypothesis `(h : ContDiff ℝ ∞ f)` and assign `∞` to the mvar `?n`. -- -- This could be problematic if there are two local hypothesis `(hinf : ContDiff ℝ ∞ f)` and - -- `(h1 : ContDiff ℝ 1 f)` and appart from solving `ContDiff ℝ ?n f` there is also a subgoal + -- `(h1 : ContDiff ℝ 1 f)` and apart from solving `ContDiff ℝ ?n f` there is also a subgoal -- `2 ≤ ?n`. If `fun_prop` decides to try `h1` first it would assign `1` to `?n` and then there -- is no hope solving `2 ≤ 1` and it won't be able to apply `hinf` after trying `h1` as `n?` is -- assigned already. Ideally `fun_prop` would roll back the `MetaM.State`. This issue did not @@ -198,7 +194,6 @@ def applyConstRule (funPropDecl : FunPropDecl) (e : Expr) logError msg trace[Meta.Tactic.fun_prop] msg return none - for thm in thms do let .const := thm.thmArgs | return none if let .some r ← tryTheorem? e (.decl thm.thmName) funProp then @@ -214,7 +209,6 @@ For example, `e = q(Continuous fun f => f x)` and `funPropDecl` is `FunPropDecl` def applyApplyRule (funPropDecl : FunPropDecl) (e : Expr) (funProp : Expr → FunPropM (Option Result)) : FunPropM (Option Result) := do let thms := (← getLambdaTheorems funPropDecl.funPropName .apply) - for thm in thms do if let .some r ← tryTheoremWithHint? e (.decl thm.thmName) #[] funProp then return r @@ -227,7 +221,7 @@ Try to prove `e` using *composition lambda theorem*. For example, `e = q(Continuous fun x => f (g x))` and `funPropDecl` is `FunPropDecl` for `Continuous` -You also have to provide the functions `f` and `g`. -/ +You also have to provide the functions `f` and `g`. -/ def applyCompRule (funPropDecl : FunPropDecl) (e f g : Expr) (funProp : Expr → FunPropM (Option Result)) : FunPropM (Option Result) := do @@ -323,7 +317,7 @@ def applyMorRules (funPropDecl : FunPropDecl) (e : Expr) (fData : FunctionData) trace[Debug.Meta.Tactic.fun_prop] "applying morphism theorems to {← ppExpr e}" match ← fData.isMorApplication with - | .none => throwError "fun_prop bug: ivalid use of mor rules on {← ppExpr e}" + | .none => throwError "fun_prop bug: invalid use of mor rules on {← ppExpr e}" | .underApplied => applyPiRule funPropDecl e funProp | .overApplied => @@ -345,7 +339,7 @@ def applyMorRules (funPropDecl : FunPropDecl) (e : Expr) (fData : FunctionData) trace[Debug.Meta.Tactic.fun_prop] "no theorem matched" return none -/-- Prove function property of using *transition theorems*. -/ +/-- Prove function property of using *transition theorems*. -/ def applyTransitionRules (e : Expr) (funProp : Expr → FunPropM (Option Result)) : FunPropM (Option Result) := do withIncreasedTransitionDepth do @@ -440,7 +434,8 @@ def getLocalTheorems (funPropDecl : FunPropDecl) (funOrigin : Origin) let .some (decl,f) ← getFunProp? b | return none unless decl.funPropName = funPropDecl.funPropName do return none - let .data fData ← getFunctionData? f (← unfoldNamePred) {zeta := false} | return none + let .data fData ← getFunctionData? f (← unfoldNamePred) {zeta := false, zetaDelta := false} + | return none unless (fData.getFnOrigin == funOrigin) do return none unless isOrderedSubsetOf mainArgs fData.mainArgs do return none @@ -660,7 +655,7 @@ mutual let e' := e.setArg funPropDecl.funArgId b funProp (← mkLambdaFVars xs e') - match ← getFunctionData? f (← unfoldNamePred) {zeta := false} with + match ← getFunctionData? f (← unfoldNamePred) {zeta := false, zetaDelta := false} with | .letE f => trace[Debug.Meta.Tactic.fun_prop] "let case on {← ppExpr f}" let e := e.setArg funPropDecl.funArgId f -- update e with reduced f @@ -690,3 +685,7 @@ mutual return none end + +end Meta.FunProp + +end Mathlib diff --git a/Mathlib/Tactic/FunProp/Decl.lean b/Mathlib/Tactic/FunProp/Decl.lean index 8ef6ae4bb0367..c744ad6ea026b 100644 --- a/Mathlib/Tactic/FunProp/Decl.lean +++ b/Mathlib/Tactic/FunProp/Decl.lean @@ -3,6 +3,7 @@ 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 Mathlib.Init import Lean /-! @@ -151,3 +152,7 @@ def tacticToDischarge (tacticCode : TSyntax `tactic) : Expr → MetaM (Option Ex let (result?, _) ← runTac?.run {} {} return result? + +end Meta.FunProp + +end Mathlib diff --git a/Mathlib/Tactic/FunProp/Differentiable.lean b/Mathlib/Tactic/FunProp/Differentiable.lean index 5e20116dd53ac..1d81eec7d76f2 100644 --- a/Mathlib/Tactic/FunProp/Differentiable.lean +++ b/Mathlib/Tactic/FunProp/Differentiable.lean @@ -104,7 +104,6 @@ attribute [fun_prop] Differentiable.mul Differentiable.smul Differentiable.div - Differentiable.inv' Differentiable.inv DifferentiableAt.add @@ -113,7 +112,6 @@ attribute [fun_prop] DifferentiableAt.mul DifferentiableAt.smul DifferentiableAt.div - DifferentiableAt.inv' DifferentiableAt.inv DifferentiableOn.add @@ -122,7 +120,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 37a1f37478417..afa3b31d7cf78 100644 --- a/Mathlib/Tactic/FunProp/Elab.lean +++ b/Mathlib/Tactic/FunProp/Elab.lean @@ -84,3 +84,7 @@ def funPropTac : Tactic throwError msg | _ => throwUnsupportedSyntax + +end Meta.FunProp + +end Mathlib diff --git a/Mathlib/Tactic/FunProp/FunctionData.lean b/Mathlib/Tactic/FunProp/FunctionData.lean index 843b3963b807e..04be35eced734 100644 --- a/Mathlib/Tactic/FunProp/FunctionData.lean +++ b/Mathlib/Tactic/FunProp/FunctionData.lean @@ -41,7 +41,7 @@ def FunctionData.toExpr (f : FunctionData) : MetaM Expr := do let body := Mor.mkAppN f.fn f.args mkLambdaFVars #[f.mainVar] body -/-- Is `f` an indentity function? -/ +/-- Is `f` an identity function? -/ def FunctionData.isIdentityFun (f : FunctionData) : Bool := (f.args.size = 0 && f.fn == f.mainVar) @@ -121,9 +121,9 @@ def getFunctionData? (f : Expr) (unfoldPred : Name → Bool := fun _ => false) (cfg : WhnfCoreConfig := {}) : MetaM MaybeFunctionData := do - let unfold := fun e : Expr => + let unfold := fun e : Expr => do if let .some n := e.getAppFn'.constName? then - pure (unfoldPred n) + pure ((unfoldPred n) || (← isReducible n)) else pure false @@ -131,7 +131,7 @@ def getFunctionData? (f : Expr) | throwError m!"fun_prop bug: function expected, got `{f} : {← inferType f}, \ type ctor {(← inferType f).ctorName}" withLocalDeclD xName xType fun x => do - let fx' ← Mor.whnfPred (f.beta #[x]).eta unfold cfg + let fx' := (← Mor.whnfPred (f.beta #[x]).eta unfold cfg) |> headBetaThroughLet let f' ← mkLambdaFVars #[x] fx' match fx' with | .letE .. => return .letE f' @@ -144,7 +144,7 @@ def FunctionData.unfoldHeadFVar? (fData : FunctionData) : MetaM (Option Expr) := let .fvar id := fData.fn | return none let .some val ← id.getValue? | return none let f ← withLCtx fData.lctx fData.insts do - mkLambdaFVars #[fData.mainVar] (Mor.mkAppN val fData.args) + mkLambdaFVars #[fData.mainVar] (headBetaThroughLet (Mor.mkAppN val fData.args)) return f /-- Type of morphism application. -/ @@ -292,3 +292,7 @@ def FunctionData.decompositionOverArgs (fData : FunctionData) (args : Array Nat) return (f,g) catch _ => return none + +end Meta.FunProp + +end Mathlib diff --git a/Mathlib/Tactic/FunProp/Mor.lean b/Mathlib/Tactic/FunProp/Mor.lean index afe269094f0de..73bf51afe47f0 100644 --- a/Mathlib/Tactic/FunProp/Mor.lean +++ b/Mathlib/Tactic/FunProp/Mor.lean @@ -29,12 +29,12 @@ namespace Meta.FunProp namespace Mor -/-- Is `name` a coerction from some function space to functiosn? -/ +/-- Is `name` a coerction from some function space to functions? -/ def isCoeFunName (name : Name) : CoreM Bool := do let .some info ← getCoeFnInfo? name | return false return info.type == .coeFun -/-- Is `e` a coerction from some function space to functiosn? -/ +/-- Is `e` a coerction from some function space to functions? -/ def isCoeFun (e : Expr) : MetaM Bool := do let .some (name,_) := e.getAppFn.const? | return false let .some info ← getCoeFnInfo? name | return false @@ -89,7 +89,7 @@ Weak normal head form of an expression involving morphism applications. For example calling this on `coe (f a) b` will put `f` in weak normal head form instead of `coe`. -/ -def whnf (e : Expr) (cfg : WhnfCoreConfig := {}) : MetaM Expr := +def whnf (e : Expr) (cfg : WhnfCoreConfig := {}) : MetaM Expr := whnfPred e (fun _ => return false) cfg @@ -120,6 +120,14 @@ where go f (as.push { coe := c, expr := x}) else go (.app c f) (as.push { expr := x}) + | .app (.proj n i f) x, as => do + -- convert proj back to function application + let env ← getEnv + let info := getStructureInfo? env n |>.get! + let projFn := getProjFnForField? env n (info.fieldNames[i]!) |>.get! + let .app c f ← mkAppM projFn #[f] | panic! "bug in Mor.withApp" + + go (.app (.app c f) x) as | .app f a, as => go f (as.push { expr := a }) | f , as => k f as.reverse @@ -150,3 +158,9 @@ def mkAppN (f : Expr) (xs : Array Arg) : Expr := match x with | ⟨x, .none⟩ => (f.app x) | ⟨x, .some coe⟩ => (coe.app f).app x) + +end Mor + +end Meta.FunProp + +end Mathlib diff --git a/Mathlib/Tactic/FunProp/RefinedDiscrTree.lean b/Mathlib/Tactic/FunProp/RefinedDiscrTree.lean index 64e4a3bbc7639..141a5bb819107 100644 --- a/Mathlib/Tactic/FunProp/RefinedDiscrTree.lean +++ b/Mathlib/Tactic/FunProp/RefinedDiscrTree.lean @@ -47,7 +47,7 @@ I document here what features are not in the original: For example, matching `(1 + 2) + 3` with `add_comm` gives a score of 2, since the pattern of commutativity is [⟨HAdd.hAdd, 6⟩, *0, *0, *0, *1, *2, *3], so matching `⟨HAdd.hAdd, 6⟩` gives 1 point, - and matching `*0` after its first appearence gives another point, but the third argument is an + and matching `*0` after its first appearance gives another point, but the third argument is an outParam, so this gets ignored. Similarly, matching it with `add_assoc` gives a score of 5. - Patterns that have the potential to be η-reduced are put into the `RefinedDiscrTree` under all @@ -135,16 +135,16 @@ inductive Key where deriving Inhabited, BEq, Repr private nonrec def Key.hash : Key → UInt64 - | .star i => mixHash 7883 $ hash i + | .star i => mixHash 7883 <| hash i | .opaque => 342 - | .const n a => mixHash 5237 $ mixHash (hash n) (hash a) - | .fvar n a => mixHash 8765 $ mixHash (hash n) (hash a) - | .bvar i a => mixHash 4323 $ mixHash (hash i) (hash a) - | .lit v => mixHash 1879 $ hash v + | .const n a => mixHash 5237 <| mixHash (hash n) (hash a) + | .fvar n a => mixHash 8765 <| mixHash (hash n) (hash a) + | .bvar i a => mixHash 4323 <| mixHash (hash i) (hash a) + | .lit v => mixHash 1879 <| hash v | .sort => 2411 | .lam => 4742 | .«forall» => 9752 - | .proj s i a => mixHash (hash a) $ mixHash (hash s) (hash i) + | .proj s i a => mixHash (hash a) <| mixHash (hash s) (hash i) instance : Hashable Key := ⟨Key.hash⟩ @@ -242,7 +242,7 @@ def Trie.children! : Trie α → Array (Key × Trie α) | .values _ => panic! "did not expect .values constructor" private partial def Trie.format [ToFormat α] : Trie α → Format - | .node cs => Format.group $ Format.paren $ + | .node cs => Format.group <| Format.paren <| "node " ++ Format.join (cs.toList.map fun (k, c) => Format.line ++ Format.paren (format (prepend k c))) | .values vs => if vs.isEmpty then Format.nil else Std.format vs @@ -282,7 +282,7 @@ inductive DTExpr where | opaque : DTExpr /-- A constant. It stores the name and the arguments. -/ | const : Name → Array DTExpr → DTExpr - /-- A free variable. It stores the `FVarId` and the argumenst -/ + /-- A free variable. It stores the `FVarId` and the arguments -/ | fvar : FVarId → Array DTExpr → DTExpr /-- A bound variable. It stores the De Bruijn index and the arguments -/ | bvar : Nat → Array DTExpr → DTExpr @@ -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 => @@ -530,10 +530,9 @@ def etaExpand (args : Array Expr) (type : Expr) (lambdas : List FVarId) (goalAri etaExpand (args.push fvar) type (fvar.fvarId! :: lambdas) goalArity k else k args lambdas -termination_by goalArity - args.size -/-- Normalize an application of a heterogenous binary operator like `HAdd.hAdd`, using: +/-- Normalize an application of a heterogeneous binary operator like `HAdd.hAdd`, using: - `f = fun x => f x` to increase the arity to 6 - `(f + g) a = f a + g a` to decrease the arity to 6 - `(fun x => f x + g x) = f + g` to get rid of any lambdas in front -/ @@ -708,7 +707,7 @@ partial def mkDTExprAux (e : Expr) (root : Bool) : ReaderT Context MetaM DTExpr | _ => unreachable! -private abbrev M := StateListT (AssocList Expr DTExpr) $ ReaderT Context MetaM +private abbrev M := StateListT (AssocList Expr DTExpr) <| ReaderT Context MetaM /- Caching values is a bit dangerous, because when two expressions are be equal and they live under @@ -883,13 +882,12 @@ where loop (i+1) else vs.push v -termination_by vs.size - i /-- Insert the value `v` at index `keys : Array Key` in a `Trie`. -/ partial def insertInTrie [BEq α] (keys : Array Key) (v : α) (i : Nat) : Trie α → Trie α | .node cs => let k := keys[i]! - let c := Id.run $ cs.binInsertM + let c := Id.run <| cs.binInsertM (fun a b => a.1 < b.1) (fun (k', s) => (k', insertInTrie keys v (i+1) s)) (fun _ => (k, Trie.singleton keys v (i+1))) @@ -909,7 +907,7 @@ partial def insertInTrie [BEq α] (keys : Array Key) (v : α) (i : Nat) : Trie /-- Insert the value `v` at index `keys : Array Key` in a `RefinedDiscrTree`. -Warning: to accound for η-reduction, an entry may need to be added at multiple indexes, +Warning: to account for η-reduction, an entry may need to be added at multiple indexes, so it is recommended to use `RefinedDiscrTree.insert` for insertion. -/ def insertInRefinedDiscrTree [BEq α] (d : RefinedDiscrTree α) (keys : Array Key) (v : α) : RefinedDiscrTree α := @@ -924,7 +922,7 @@ def insertInRefinedDiscrTree [BEq α] (d : RefinedDiscrTree α) (keys : Array Ke /-- Insert the value `v` at index `e : DTExpr` in a `RefinedDiscrTree`. -Warning: to accound for η-reduction, an entry may need to be added at multiple indexes, +Warning: to account for η-reduction, an entry may need to be added at multiple indexes, so it is recommended to use `RefinedDiscrTree.insert` for insertion. -/ def insertDTExpr [BEq α] (d : RefinedDiscrTree α) (e : DTExpr) (v : α) : RefinedDiscrTree α := insertInRefinedDiscrTree d e.flatten v @@ -982,7 +980,7 @@ private structure State where mvarAssignments : Std.HashMap MVarId (Array Key) := {} -private abbrev M := ReaderT Context $ StateListM State +private abbrev M := ReaderT Context <| StateListM State /-- Return all values from `x` in an array, together with their scores. -/ private def M.run (unify : Bool) (config : WhnfCoreConfig) (x : M (Trie α)) : @@ -1152,3 +1150,5 @@ def mapArraysM (d : RefinedDiscrTree α) (f : Array α → m (Array β)) : m (Re /-- Apply a function to the array of values at each node in a `RefinedDiscrTree`. -/ def mapArrays (d : RefinedDiscrTree α) (f : Array α → Array β) : RefinedDiscrTree β := d.mapArraysM (m := Id) f + +end Mathlib.Meta.FunProp.RefinedDiscrTree diff --git a/Mathlib/Tactic/FunProp/StateList.lean b/Mathlib/Tactic/FunProp/StateList.lean index b1f6431c1794f..24bce5cf29fd1 100644 --- a/Mathlib/Tactic/FunProp/StateList.lean +++ b/Mathlib/Tactic/FunProp/StateList.lean @@ -2,7 +2,11 @@ Copyright (c) 2023 J. W. Gerbscheid. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: J. W. Gerbscheid +-/ + +import Mathlib.Init +/-! The combined state and list monad transformer. `StateListT σ α` is equivalent to `StateT σ (ListT α)` but more efficient. @@ -168,3 +172,5 @@ instance StateListT.monadControl : MonadControl m (StateListT σ m) where stM := StateList σ liftWith := fun f => do let s ← get; liftM (f (fun x => x s)) restoreM := fun x _ => x + +end Mathlib.Meta.FunProp diff --git a/Mathlib/Tactic/FunProp/Theorems.lean b/Mathlib/Tactic/FunProp/Theorems.lean index 26571a80035b4..1ab9b3850fec5 100644 --- a/Mathlib/Tactic/FunProp/Theorems.lean +++ b/Mathlib/Tactic/FunProp/Theorems.lean @@ -389,3 +389,7 @@ function property: {thm.funPropName}" transition theorem: {thm.thmName} function property: {thm.funPropName}" transitionTheoremsExt.add thm attrKind + +end Meta.FunProp + +end Mathlib diff --git a/Mathlib/Tactic/FunProp/ToBatteries.lean b/Mathlib/Tactic/FunProp/ToBatteries.lean index 5cf39afb38db6..11ce07dbc78c3 100644 --- a/Mathlib/Tactic/FunProp/ToBatteries.lean +++ b/Mathlib/Tactic/FunProp/ToBatteries.lean @@ -3,6 +3,7 @@ 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 Mathlib.Init import Lean /-! @@ -34,7 +35,7 @@ def isOrderedSubsetOf {α} [Inhabited α] [DecidableEq α] (a b : Array α) : Bo private def letTelescopeImpl {α} (e : Expr) (k : Array Expr → Expr → MetaM α) : MetaM α := - lambdaLetTelescope e λ xs b => do + lambdaLetTelescope e fun xs b ↦ do if let .some i ← xs.findIdxM? (fun x ↦ do pure ¬(← x.fvarId!.isLetVar)) then k xs[0:i] (← mkLambdaFVars xs[i:] b) else @@ -97,18 +98,18 @@ def mkProdProj (x : Expr) (i : Nat) (n : Nat) : MetaM Expr := do i.e. `#[xs.1, xs.2.1, xs.2.2.1, ..., xs.2..2]` -/ def mkProdSplitElem (xs : Expr) (n : Nat) : MetaM (Array Expr) := (Array.range n) - |>.mapM (λ i => mkProdProj xs i n) + |>.mapM (fun i ↦ mkProdProj xs i n) /-- Uncurry function `f` in `n` arguments. -/ def mkUncurryFun (n : Nat) (f : Expr) : MetaM Expr := do if n ≤ 1 then return f - forallBoundedTelescope (← inferType f) n λ xs _ => do - let xProdName : String ← xs.foldlM (init:="") λ n x => + forallBoundedTelescope (← inferType f) n fun xs _ ↦ do + let xProdName : String ← xs.foldlM (init:="") fun n x ↦ do return (n ++ toString (← x.fvarId!.getUserName).eraseMacroScopes) let xProdType ← inferType (← mkProdElem xs) - withLocalDecl (.mkSimple xProdName) default xProdType λ xProd => do + withLocalDecl (.mkSimple xProdName) default xProdType fun xProd ↦ do let xs' ← mkProdSplitElem xProd n mkLambdaFVars #[xProd] (← mkAppM' f xs').headBeta @@ -129,3 +130,44 @@ def etaExpand1 (f : Expr) : MetaM Expr := do else withDefault do forallBoundedTelescope (← inferType f) (.some 1) fun xs _ => do mkLambdaFVars xs (mkAppN f xs) + +/-- Implementation of `betaThroughLet` -/ +private def betaThroughLetAux (f : Expr) (args : List Expr) : Expr := + match f, args with + | f, [] => f + | .lam _ _ b _, a :: as => (betaThroughLetAux (b.instantiate1 a) as) + | .letE n t v b _, args => .letE n t v (betaThroughLetAux b args) false + | .mdata _ b, args => betaThroughLetAux b args + | f, args => mkAppN f args.toArray + +/-- Apply the given arguments to `f`, beta-reducing if `f` is a lambda expression. This variant +does beta-reduction through let bindings without inlining them. + +Example +``` +beta' (fun x => let y := x * x; fun z => x + y + z) #[a,b] +==> +let y := a * a; a + y + b +``` +-/ +def betaThroughLet (f : Expr) (args : Array Expr) : Expr := + betaThroughLetAux f args.toList + +/-- Beta reduces head of an expression, `(fun x => e) a` ==> `e[x/a]`. This version applies +arguments through let bindings without inlining them. + +Example +``` +headBeta' ((fun x => let y := x * x; fun z => x + y + z) a b) +==> +let y := a * a; a + y + b +``` +-/ +def headBetaThroughLet (e : Expr) : Expr := + let f := e.getAppFn + if f.isHeadBetaTargetFn true then betaThroughLet f e.getAppArgs else e + + +end Meta.FunProp + +end Mathlib diff --git a/Mathlib/Tactic/FunProp/Types.lean b/Mathlib/Tactic/FunProp/Types.lean index 398048a9db06a..6f12b788e1928 100644 --- a/Mathlib/Tactic/FunProp/Types.lean +++ b/Mathlib/Tactic/FunProp/Types.lean @@ -67,7 +67,7 @@ def defaultNamesToUnfold : Array Name := /-- `fun_prop` configuration -/ structure Config where - /-- Maximum number of transitions between function properties. For example infering continuity + /-- Maximum number of transitions between function properties. For example inferring continuity from differentiability and then differentiability from smoothness (`ContDiff ℝ ∞`) requires `maxTransitionDepth = 2`. The default value of one expects that transition theorems are transitively closed e.g. there is a transition theorem that infers continuity directly from @@ -152,8 +152,8 @@ Messages are logged only when `transitionDepth = 0` i.e. when `fun_prop` is **no function property like continuity from another property like differentiability. The main reason is that if the user forgets to add a continuity theorem for function `foo` then `fun_prop` should report that there is a continuity theorem for `foo` missing. If we would log -messages `transitionDepth > 0` then user will see messages saying that there is a missing theorem for -differentiability, smoothness, ... for `foo`. -/ +messages `transitionDepth > 0` then user will see messages saying that there is a missing theorem +for differentiability, smoothness, ... for `foo`. -/ def logError (msg : String) : FunPropM Unit := do if (← read).transitionDepth = 0 then modify fun s => @@ -162,3 +162,7 @@ def logError (msg : String) : FunPropM Unit := do s.msgLog else msg::s.msgLog} + +end Meta.FunProp + +end Mathlib 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 bcb5eeb0a05d9..bf7982ef2748e 100644 --- a/Mathlib/Tactic/GCongr/Core.lean +++ b/Mathlib/Tactic/GCongr/Core.lean @@ -134,9 +134,9 @@ structure GCongrLemma where /-- Environment extension for "generalized congruence" (`gcongr`) lemmas. -/ initialize gcongrExt : SimpleScopedEnvExtension ((Name × Name × Array Bool) × GCongrLemma) - (HashMap (Name × Name × Array Bool) (Array GCongrLemma)) ← + (Std.HashMap (Name × Name × Array Bool) (Array GCongrLemma)) ← registerSimpleScopedEnvExtension { - addEntry := fun m (n, lem) => m.insert n ((m.findD n #[]).push lem) + addEntry := fun m (n, lem) => m.insert n ((m.getD n #[]).push lem) initial := {} } @@ -363,7 +363,7 @@ partial def _root_.Lean.MVarId.gcongr -- Look up the `@[gcongr]` lemmas whose conclusion has the same relation and head function as -- the goal and whether the boolean-array of varying/nonvarying arguments of such -- a lemma matches `varyingArgs`. - for lem in (gcongrExt.getState (← getEnv)).findD (relName, lhsHead, varyingArgs) #[] do + for lem in (gcongrExt.getState (← getEnv)).getD (relName, lhsHead, varyingArgs) #[] do let gs ← try -- Try `apply`-ing such a lemma to the goal. Except.ok <$> g.apply (← mkConstWithFreshMVarLevels lem.declName) @@ -406,8 +406,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, @@ -527,3 +532,7 @@ elab_rules : tactic let g := Lean.MessageData.joinSep (unsolvedGoals.map Lean.MessageData.ofExpr) Format.line throwError "rel failed, cannot prove goal by 'substituting' the listed relationships. \ The steps which could not be automatically justified were:\n{g}" + +end GCongr + +end Mathlib.Tactic 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/GCongr/ForwardAttr.lean b/Mathlib/Tactic/GCongr/ForwardAttr.lean index 88078fb3adb8c..b2223676bf279 100644 --- a/Mathlib/Tactic/GCongr/ForwardAttr.lean +++ b/Mathlib/Tactic/GCongr/ForwardAttr.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 Mathlib.Init import Batteries.Tactic.Basic /-! @@ -51,3 +52,7 @@ initialize registerBuiltinAttribute { setEnv <| forwardExt.addEntry env (declName, ext) | _ => throwUnsupportedSyntax } + +end GCongr + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Generalize.lean b/Mathlib/Tactic/Generalize.lean index decfd95b40a4f..20250ad5f6e41 100644 --- a/Mathlib/Tactic/Generalize.lean +++ b/Mathlib/Tactic/Generalize.lean @@ -1,8 +1,9 @@ /- 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 import Lean.Elab.Tactic.ElabTerm import Lean.Meta.Tactic.Generalize diff --git a/Mathlib/Tactic/GeneralizeProofs.lean b/Mathlib/Tactic/GeneralizeProofs.lean index ecd3ab4028c91..645637ae46a0f 100644 --- a/Mathlib/Tactic/GeneralizeProofs.lean +++ b/Mathlib/Tactic/GeneralizeProofs.lean @@ -109,10 +109,10 @@ def MGen.runMAbs {α : Type} (mx : MAbs α) : MGen (α × Array (Expr × Expr)) Finds a proof of `prop` by looking at `propToFVar` and `propToProof`. -/ def MAbs.findProof? (prop : Expr) : MAbs (Option Expr) := do - if let some pf := (← read).propToFVar.find? prop then + if let some pf := (← read).propToFVar[prop]? then return pf else - return (← get).propToProof.find? prop + return (← get).propToProof[prop]? /-- Generalize `prop`, where `proof` is its proof. @@ -152,7 +152,7 @@ def appArgExpectedTypes (f : Expr) (args : Array Expr) (ty? : Option Expr) : -- Try using the expected type, but (*) below might find a bad solution (guard ty?.isSome *> go f args ty?) <|> go f args none where - /-- Core implementation for `appArgExpectedTypes`. -/ + /-- Core implementation for `appArgExpectedTypes`. -/ go (f : Expr) (args : Array Expr) (ty? : Option Expr) : MetaM (Array (Option Expr)) := do -- Metavariables for each argument to `f`: let mut margs := #[] @@ -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,18 +351,18 @@ 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] - let ty := (← instantiateMVars (ty.replace proofToFVar.find?)).cleanupAnnotations + let ty := (← instantiateMVars (ty.replace proofToFVar.get?)).cleanupAnnotations withLocalDeclD (← mkFreshUserName `pf) ty fun fvar => do go (i + 1) (fvars := fvars.push fvar) (pfs := pfs.push pf) (proofToFVar := proofToFVar.insert pf fvar) (propToFVar := propToFVar.insert ty fvar) else withNewLocalInstances fvars 0 do - let e' := e.replace proofToFVar.find? + let e' := e.replace proofToFVar.get? trace[Tactic.generalize_proofs] "after: e' = {e}" modify fun s => { s with propToFVar } k fvars pfs e' @@ -395,7 +395,7 @@ where let g' ← mkFreshExprSyntheticOpaqueMVar tgt' tag g.assign <| .app g' tgt.letValue! return ← go g'.mvarId! i hs - if let some pf := (← get).propToFVar.find? ty then + if let some pf := (← get).propToFVar[ty]? then -- Eliminate this local hypothesis using the pre-existing proof, using proof irrelevance let tgt' := tgt.bindingBody!.instantiate1 pf let g' ← mkFreshExprSyntheticOpaqueMVar tgt' tag @@ -520,3 +520,5 @@ elab (name := generalizeProofsElab) "generalize_proofs" config?:(Parser.Tactic.c let g' ← mkFreshExprSyntheticOpaqueMVar (← g.getType) (← g.getTag) g.assign g' return g'.mvarId! + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Group.lean b/Mathlib/Tactic/Group.lean index 1f0943d59fc51..b20838a434f79 100644 --- a/Mathlib/Tactic/Group.lean +++ b/Mathlib/Tactic/Group.lean @@ -52,7 +52,7 @@ macro_rules [commutatorElement_def, mul_one, one_mul, ← zpow_neg_one, ← zpow_natCast, ← zpow_mul, Int.ofNat_add, Int.ofNat_mul, - Int.mul_neg_eq_neg_mul_symm, Int.neg_mul_eq_neg_mul_symm, neg_neg, + Int.mul_neg, Int.neg_mul, neg_neg, one_zpow, zpow_zero, zpow_one, mul_zpow_neg_one, ← mul_assoc, ← zpow_add, ← zpow_add_one, ← zpow_one_add, zpow_trick, zpow_trick_one, zpow_trick_one', @@ -86,8 +86,4 @@ macro_rules | `(tactic| group $[$loc]?) => `(tactic| repeat (fail_if_no_progress (aux_group₁ $[$loc]? <;> aux_group₂ $[$loc]?))) -end Group - -end Tactic - -end Mathlib +end Mathlib.Tactic.Group diff --git a/Mathlib/Tactic/GuardGoalNums.lean b/Mathlib/Tactic/GuardGoalNums.lean index 882cb6b7bf060..27531fd64874f 100644 --- a/Mathlib/Tactic/GuardGoalNums.lean +++ b/Mathlib/Tactic/GuardGoalNums.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Robert Y. Lewis. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Robert Y. Lewis -/ +import Mathlib.Init import Lean.Elab.Tactic.Basic /-! diff --git a/Mathlib/Tactic/GuardHypNums.lean b/Mathlib/Tactic/GuardHypNums.lean index 60a0cf119966a..ad3202937bbca 100644 --- a/Mathlib/Tactic/GuardHypNums.lean +++ b/Mathlib/Tactic/GuardHypNums.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Robert Y. Lewis. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Robert Y. Lewis -/ +import Mathlib.Init import Lean.Elab.Tactic.Basic /-! diff --git a/Mathlib/Tactic/Have.lean b/Mathlib/Tactic/Have.lean index 582bb2c0559e5..c8240ce05b77f 100644 --- a/Mathlib/Tactic/Have.lean +++ b/Mathlib/Tactic/Have.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Arthur Paulino. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Arthur Paulino, Edward Ayers, Mario Carneiro -/ +import Mathlib.Init import Lean.Elab.Binders import Lean.Elab.SyntheticMVars import Lean.Meta.Tactic.Assert @@ -100,3 +101,5 @@ elab_rules : tactic | `(tactic| let $n:optBinderIdent $bs* $[: $t:term]?) => withMainContext do let (goal1, goal2) ← haveLetCore (← getMainGoal) n bs t true replaceMainGoal [goal1, goal2] + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/HaveI.lean b/Mathlib/Tactic/HaveI.lean index 533c20e8d38ee..f0dce3425b640 100644 --- a/Mathlib/Tactic/HaveI.lean +++ b/Mathlib/Tactic/HaveI.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner -/ +import Mathlib.Init /-! # Variants of `haveI`/`letI` for use in do-notation. @@ -40,3 +41,5 @@ macro_rules -/ macro "letI' " hd:haveDecl : doElem => `(doElem| assert! letIDummy $hd:haveDecl) + +end Mathlib.Tactic.HaveI diff --git a/Mathlib/Tactic/HelpCmd.lean b/Mathlib/Tactic/HelpCmd.lean index c5f5709996c83..1dafab19653f5 100644 --- a/Mathlib/Tactic/HelpCmd.lean +++ b/Mathlib/Tactic/HelpCmd.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.Init import Lean.Elab.Syntax import Lean.DocString @@ -68,7 +69,7 @@ private def elabHelpOption (id : Option Ident) : CommandElabM Unit := do | .ofInt val => s!"Int := {repr val}" | .ofSyntax val => s!"Syntax := {repr val}" if let some val := opts.find (.mkSimple name) then - msg1 := s!"{msg1} (currently: {val})" + msg1 := s!"{msg1} (currently: {val})" msg := msg ++ .nest 2 (f!"option {name} : {msg1}" ++ .line ++ decl.descr) ++ .line ++ .line logInfo msg @@ -315,3 +316,5 @@ syntax withPosition("#help " colGt &"command" "+"? macro_rules | `(#help command%$tk $[+%$more]? $(id)?) => `(#help cat$[+%$more]? $(mkIdentFrom tk `command) $(id)?) + +end Mathlib.Tactic 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 fdb027224a4f9..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 /-! @@ -732,3 +730,5 @@ macro_rules -- category := DocCategory.tactic -- declNames := [`tactic.interactive.itauto] -- tags := ["logic", "propositional logic", "intuitionistic logic", "decision procedure"] } + +end Mathlib.Tactic.ITauto diff --git a/Mathlib/Tactic/InferParam.lean b/Mathlib/Tactic/InferParam.lean index e649d5b1f7f72..61823d34ed51a 100644 --- a/Mathlib/Tactic/InferParam.lean +++ b/Mathlib/Tactic/InferParam.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Yury Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov, Mario Carneiro -/ +import Mathlib.Init import Lean.Elab.Tactic.Basic import Lean.Meta.Tactic.Replace @@ -31,3 +32,5 @@ elab (name := inferOptParam) "infer_param" : tactic => do evalTactic tacticSyntax else throwError "`infer_param` only solves goals of the form `optParam _ _` or `autoParam _ _`, not {tgt}" + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Inhabit.lean b/Mathlib/Tactic/Inhabit.lean index daa5b484d6c1e..cda2beb10fd0b 100644 --- a/Mathlib/Tactic/Inhabit.lean +++ b/Mathlib/Tactic/Inhabit.lean @@ -54,3 +54,5 @@ elab_rules : tactic | `(tactic| inhabit $[$h_name:ident :]? $term) => do let goal ← evalInhabit (← getMainGoal) h_name term replaceMainGoal [goal] + +end Lean.Elab.Tactic diff --git a/Mathlib/Tactic/IntervalCases.lean b/Mathlib/Tactic/IntervalCases.lean index d683390c9cec7..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 @@ -397,6 +398,4 @@ elab_rules : tactic cont x xs[1]? subst g e lbs ubs (mustUseBounds := false) | _, _, _ => throwUnsupportedSyntax -end Tactic - -end Mathlib +end Mathlib.Tactic diff --git a/Mathlib/Tactic/IrreducibleDef.lean b/Mathlib/Tactic/IrreducibleDef.lean index e233d30979e21..bfdf7272c85bd 100644 --- a/Mathlib/Tactic/IrreducibleDef.lean +++ b/Mathlib/Tactic/IrreducibleDef.lean @@ -50,7 +50,7 @@ local elab "eta_helper " t:term : term => do let lhs := (mkAppN lhs xs).headBeta mkForallFVars xs <|← mkEq lhs rhs -/-- `val_proj x` elabs to the *primitive projection* `@x.val`. -/ +/-- `val_proj x` elabs to the *primitive projection* `@x.val`. -/ local elab "val_proj " e:term : term => do let e ← elabTerm (← `(($e : Subtype _))) none return mkProj ``Subtype 0 e @@ -113,3 +113,5 @@ elab mods:declModifiers "irreducible_def" n_id:declId n_def:(irredDefLemma)? attribute [$attrs:attrInstance,*] $n) if prot.isSome then modifyEnv (addProtected · ((← getCurrNamespace) ++ n.getId)) + +end Lean.Elab.Command diff --git a/Mathlib/Tactic/Lemma.lean b/Mathlib/Tactic/Lemma.lean index 4412258b0c428..10d49cd8d8a8f 100644 --- a/Mathlib/Tactic/Lemma.lean +++ b/Mathlib/Tactic/Lemma.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Kyle Miller -/ +import Mathlib.Init import Lean.Parser.Command /-! @@ -11,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 5e0832bb5836a..4b939583e90ec 100644 --- a/Mathlib/Tactic/Linarith/Datatypes.lean +++ b/Mathlib/Tactic/Linarith/Datatypes.lean @@ -311,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/Lemmas.lean b/Mathlib/Tactic/Linarith/Lemmas.lean index 44ee9f4ba3c58..9105528b9c4ec 100644 --- a/Mathlib/Tactic/Linarith/Lemmas.lean +++ b/Mathlib/Tactic/Linarith/Lemmas.lean @@ -8,7 +8,7 @@ import Mathlib.Algebra.Order.Monoid.Unbundled.Basic import Mathlib.Algebra.Order.Ring.Defs import Mathlib.Algebra.Order.ZeroLEOne import Mathlib.Data.Nat.Cast.Order.Ring -import Mathlib.Init.Data.Int.Order +import Mathlib.Data.Int.Order.Basic /-! # Lemmas for `linarith`. 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/Datatypes.lean b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/Datatypes.lean index fc26e112464dd..8a5a9488ae1a9 100644 --- a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/Datatypes.lean +++ b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/Datatypes.lean @@ -3,8 +3,9 @@ Copyright (c) 2024 Vasily Nesterov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Vasily Nesterov -/ -import Lean.Data.HashMap +import Mathlib.Init import Batteries.Data.Rat.Basic +import Std.Data.HashMap.Basic /-! # Datatypes for the Simplex Algorithm implementation @@ -81,10 +82,10 @@ values. -/ structure SparseMatrix (n m : Nat) where /-- The content of the matrix. -/ - data : Array <| Lean.HashMap Nat Rat + data : Array <| Std.HashMap Nat Rat instance : UsableInSimplexAlgorithm SparseMatrix where - getElem mat i j := mat.data[i]!.findD j 0 + getElem mat i j := mat.data[i]!.getD j 0 setElem mat i j v := if v == 0 then ⟨mat.data.modify i fun row => row.erase j⟩ @@ -95,7 +96,7 @@ instance : UsableInSimplexAlgorithm SparseMatrix where let rowVals := row.toList.map fun (j, v) => (i, j, v) rowVals ++ acc ofValues {n _ : Nat} vals := Id.run do - let mut data : Array (Lean.HashMap Nat Rat) := Array.mkArray n .empty + let mut data : Array (Std.HashMap Nat Rat) := Array.mkArray n .empty for ⟨i, j, v⟩ in vals do if v != 0 then data := data.modify i fun row => row.insert j v @@ -104,12 +105,12 @@ instance : UsableInSimplexAlgorithm SparseMatrix where subtractRow mat i j coef := let newData := mat.data.modify j fun row => mat.data[i]!.fold (fun cur k val => - let newVal := (cur.findD k 0) - coef * val + let newVal := (cur.getD k 0) - coef * val if newVal != 0 then cur.insert k newVal else cur.erase k ) row ⟨newData⟩ divideRow mat i coef := - let newData : Array (Lean.HashMap Nat Rat) := mat.data.modify i fun row => + let newData : Array (Std.HashMap Nat Rat) := mat.data.modify i fun row => row.fold (fun cur k v => cur.insert k (v / coef)) row ⟨newData⟩ 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 8198ec0a53234..97f8d6d475622 100644 --- a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/PositiveVector.lean +++ b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/PositiveVector.lean @@ -70,7 +70,7 @@ def stateLP {n m : Nat} (A : matType n m) (strictIndexes : List Nat) : matType ( ofValues (objectiveRow ++ constraintRow ++ valuesA) -/-- Extracts target vector from the tableau, putting auxilary variables aside (see `stateLP`). -/ +/-- Extracts target vector from the tableau, putting auxiliary variables aside (see `stateLP`). -/ def extractSolution (tableau : Tableau matType) : Array Rat := Id.run do let mut ans : Array Rat := Array.mkArray (tableau.basic.size + tableau.free.size - 3) 0 for i in [1:tableau.basic.size] do @@ -90,11 +90,15 @@ 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 throwError "Simplex Algorithm failed" + +end SimplexAlgorithm + +end Linarith 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/Preprocessing.lean b/Mathlib/Tactic/Linarith/Preprocessing.lean index 8d0a1bbd44edd..2a496d4cd5670 100644 --- a/Mathlib/Tactic/Linarith/Preprocessing.lean +++ b/Mathlib/Tactic/Linarith/Preprocessing.lean @@ -306,7 +306,7 @@ section nlinarith `findSquares s e` collects all terms of the form `a ^ 2` and `a * a` that appear in `e` and adds them to the set `s`. A pair `(i, true)` is added to `s` when `atoms[i]^2` appears in `e`, -and `(i, false)` is added to `s` when `atoms[i]*atoms[i]` appears in `e`. -/ +and `(i, false)` is added to `s` when `atoms[i]*atoms[i]` appears in `e`. -/ partial def findSquares (s : RBSet (Nat × Bool) lexOrd.compare) (e : Expr) : AtomM (RBSet (Nat × Bool) lexOrd.compare) := -- Completely traversing the expression is non-ideal, 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 new file mode 100644 index 0000000000000..c7965a7998ee9 --- /dev/null +++ b/Mathlib/Tactic/LinearCombination'.lean @@ -0,0 +1,263 @@ +/- +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.Ring + +/-! +# linear_combination' Tactic + +In this file, the `linear_combination'` tactic is created. This tactic, which +works over `CommRing`s, attempts to simplify the target by creating a linear combination +of a list of equalities and subtracting it from the target. A `Syntax.Tactic` +object can also be passed into the tactic, allowing the user to specify a +normalization tactic. + +## Implementation Notes + +This tactic works by creating a weighted sum of the given equations with the +given coefficients. Then, it subtracts the right side of the weighted sum +from the left side so that the right side equals 0, and it does the same with +the target. Afterwards, it sets the goal to be the equality between the +lefthand side of the new goal and the lefthand side of the new weighted sum. +Lastly, calls a normalization tactic on this target. + +This file contains the `linear_combination'` tactic (note the '): the original +Lean 4 implementation of the "linear combination" idea, written at the time of +the port from Lean 3. Notably, its scope includes certain *nonlinear* +operations. The `linear_combination` tactic (in a separate file) is a variant +implementation, but this version is provided for backward-compatibility. + +## References + +* + +-/ + +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 sub_pf [Sub α] (p₁ : (a₁:α) = b₁) (p₂ : a₂ = b₂) : a₁ - a₂ = b₁ - b₂ := p₁ ▸ p₂ ▸ rfl +theorem neg_pf [Neg α] (p : (a:α) = b) : -a = -b := 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`. -/ + | proof (pf : Syntax.Term) + /-- A value, equivalently a proof of `c = c`. -/ + | const (c : Syntax.Term) + +/-- +Performs macro expansion of a linear combination expression, +using `+`/`-`/`*`/`/` on equations and values. +* `.proof p` means that `p` is a syntax corresponding to a proof of an equation. + For example, if `h : a = b` then `expandLinearCombo (2 * h)` returns `.proof (c_add_pf 2 h)` + which is a proof of `2 * a = 2 * b`. +* `.const c` means that the input expression is not an equation but a value. +-/ +partial def expandLinearCombo (ty : Expr) (stx : Syntax.Term) : TermElabM Expanded := withRef stx do + match stx with + | `(($e)) => expandLinearCombo ty e + | `($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₂) + | `($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₁, .proof p₂ => .proof <$> ``(sub_pf $p₁ $p₂) + | `(-$e) => do + match ← expandLinearCombo ty e with + | .const c => .const <$> `(-$c) + | .proof p => .proof <$> ``(neg_pf $p) + | `(← $e) => do + match ← expandLinearCombo ty e with + | .const c => return .const c + | .proof p => .proof <$> ``(Eq.symm $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_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 + 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₂) + | e => + -- We have the expected type from the goal, so we can fully synthesize this leaf node. + withSynthesize do + -- It is OK to use `ty` as the expected type even if `e` is a proof. + -- The expected type is just a hint. + let c ← withSynthesizeLight <| Term.elabTerm e ty + if (← whnfR (← inferType c)).isEq then + .proof <$> c.toSyntax + else + .const <$> c.toSyntax + +theorem eq_trans₃ (p : (a:α) = b) (p₁ : a = a') (p₂ : b = b') : a' = b' := p₁ ▸ p₂ ▸ p + +theorem eq_of_add [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_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'` and `linear_combination2`. -/ +def elabLinearCombination' (tk : Syntax) + (norm? : Option Syntax.Tactic) (exp? : Option Syntax.NumLit) (input : Option Syntax.Term) + (twoGoals := false) : Tactic.TacticM Unit := Tactic.withMainContext do + let some (ty, _) := (← (← Tactic.getMainGoal).getType').eq? | + throwError "'linear_combination'' only proves equalities" + let p ← match input with + | none => `(Eq.refl 0) + | some e => + match ← expandLinearCombo ty e with + | .const c => `(Eq.refl $c) + | .proof p => pure p + let norm := norm?.getD (Unhygienic.run <| withRef tk `(tactic| ring1)) + Term.withoutErrToSorry <| Tactic.evalTactic <| ← withFreshMacroScope <| + if twoGoals then + `(tactic| ( + refine eq_trans₃ $p ?a ?b + case' a => $norm:tactic + case' b => $norm:tactic)) + else + match exp? with + | some n => + if n.getNat = 1 then `(tactic| (refine eq_of_add $p ?a; case' a => $norm:tactic)) + else `(tactic| (refine eq_of_add_pow $n $p ?a; case' a => $norm:tactic)) + | _ => `(tactic| (refine eq_of_add $p ?a; case' a => $norm:tactic)) + +/-- +The `(norm := $tac)` syntax says to use `tac` as a normalization postprocessor for +`linear_combination'`. The default normalizer is `ring1`, but you can override it with `ring_nf` +to get subgoals from `linear_combination'` or with `skip` to disable normalization. +-/ +syntax normStx := atomic(" (" &"norm" " := ") withoutPosition(tactic) ")" + +/-- +The `(exp := n)` syntax for `linear_combination'` says to take the goal to the `n`th power before +subtracting the given combination of hypotheses. +-/ +syntax expStx := atomic(" (" &"exp" " := ") withoutPosition(num) ")" + +/-- +`linear_combination'` attempts to simplify the target by creating a linear combination + 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 `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. 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 + instances of `Mul` and `AddGroup` for this type. + +* The input `e` in `linear_combination' e` is a linear combination of proofs of equalities, + given as a sum/difference of coefficients multiplied by expressions. + The coefficients may be arbitrary expressions. + The expressions can be arbitrary proof terms proving equalities. + Most commonly they are hypothesis names `h1, h2, ...`. +* `linear_combination' (norm := tac) e` runs the "normalization tactic" `tac` + on the subgoal(s) after constructing the linear combination. + * The default normalization tactic is `ring1`, which closes the goal or fails. + * To get a subgoal in the case that it is not immediately provable, use + `ring_nf` as the normalization tactic. + * To avoid normalization entirely, use `skip` as the normalization tactic. +* `linear_combination' (exp := n) e` will take the goal to the `n`th power before subtracting the + combination `e`. In other words, if the goal is `t1 = t2`, `linear_combination' (exp := n) e` + will change the goal to `(t1 - t2)^n = 0` before proceeding as above. + This feature is not supported for `linear_combination2`. +* `linear_combination2 e` is the same as `linear_combination' e` but it produces two + subgoals instead of one: rather than proving that `(a - b) - (a' - b') = 0` where + `a' = b'` is the linear combination from `e` and `a = b` is the goal, + it instead attempts to prove `a = a'` and `b = b'`. + Because it does not use subtraction, this form is applicable also to semirings. + * Note that a goal which is provable by `linear_combination' e` may not be provable + by `linear_combination2 e`; in general you may need to add a coefficient to `e` + to make both sides match, as in `linear_combination2 e + c`. + * You can also reverse equalities using `← h`, so for example if `h₁ : a = b` + then `2 * (← h)` is a proof of `2 * b = 2 * a`. + +Example Usage: +``` +example (x y : ℤ) (h1 : x*y + 2*x = 1) (h2 : x = y) : x*y = -2*y + 1 := by + linear_combination' 1*h1 - 2*h2 + +example (x y : ℤ) (h1 : x*y + 2*x = 1) (h2 : x = y) : x*y = -2*y + 1 := by + linear_combination' h1 - 2*h2 + +example (x y : ℤ) (h1 : x*y + 2*x = 1) (h2 : x = y) : x*y = -2*y + 1 := by + linear_combination' (norm := ring_nf) -2*h2 + /- Goal: x * y + x * 2 - 1 = 0 -/ + +example (x y z : ℝ) (ha : x + 2*y - z = 4) (hb : 2*x + y + z = -2) + (hc : x + 2*y + z = 2) : + -3*x - 3*y - 4*z = 2 := by + linear_combination' ha - hb - 2*hc + +example (x y : ℚ) (h1 : x + y = 3) (h2 : 3*x = 7) : + x*x*y + y*x*y + 6*x = 3*x*y + 14 := by + linear_combination' x*y*h1 + 2*h2 + +example (x y : ℤ) (h1 : x = -3) (h2 : y = 10) : 2*x = -6 := by + linear_combination' (norm := skip) 2*h1 + simp + +axiom qc : ℚ +axiom hqc : qc = 2*qc + +example (a b : ℚ) (h : ∀ p q : ℚ, p = q) : 3*a + qc = 3*b + 2*qc := by + linear_combination' 3 * h a b + hqc +``` +-/ +syntax (name := linearCombination') "linear_combination'" + (normStx)? (expStx)? (ppSpace colGt term)? : tactic +elab_rules : tactic + | `(tactic| linear_combination'%$tk $[(norm := $tac)]? $[(exp := $n)]? $(e)?) => + elabLinearCombination' tk tac n e + +@[inherit_doc linearCombination'] +syntax "linear_combination2" (normStx)? (ppSpace colGt term)? : tactic +elab_rules : tactic + | `(tactic| linear_combination2%$tk $[(norm := $tac)]? $(e)?) => + elabLinearCombination' tk tac none e true + +end Mathlib.Tactic.LinearCombination' diff --git a/Mathlib/Tactic/LinearCombination.lean b/Mathlib/Tactic/LinearCombination.lean index 78472a591957f..ae81750d27b27 100644 --- a/Mathlib/Tactic/LinearCombination.lean +++ b/Mathlib/Tactic/LinearCombination.lean @@ -3,16 +3,16 @@ 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 /-! # linear_combination Tactic In this file, the `linear_combination` tactic is created. This tactic, which -works over `Ring`s, attempts to simplify the target by creating a linear combination -of a list of equalities and subtracting it from the target. This file also includes a -definition for `linear_combination_config`. A `linear_combination_config` -object can be passed into the tactic, allowing the user to specify a +works over `CommRing`s, attempts to simplify the target by creating a linear combination +of a list of equalities and subtracting it from the target. A `Syntax.Tactic` +object can also be passed into the tactic, allowing the user to specify a normalization tactic. ## Implementation Notes @@ -34,23 +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 sub_pf [Sub α] (p₁ : (a₁:α) = b₁) (p₂ : a₂ = b₂) : a₁ - a₂ = b₁ - b₂ := p₁ ▸ p₂ ▸ rfl -theorem neg_pf [Neg α] (p : (a:α) = b) : -a = -b := 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`. -/ @@ -72,39 +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₁, .proof p₂ => .proof <$> ``(sub_pf $p₁ $p₂) + | .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 <$> ``(neg_pf $p) - | `(← $e) => do - match ← expandLinearCombo ty e with - | .const c => return .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 @@ -116,40 +100,39 @@ partial def expandLinearCombo (ty : Expr) (stx : Syntax.Term) : TermElabM Expand else .const <$> c.toSyntax -theorem eq_trans₃ (p : (a:α) = b) (p₁ : a = a') (p₂ : b = b') : a' = b' := p₁ ▸ p₂ ▸ p - -theorem eq_of_add [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_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` and `linear_combination2`. -/ -def elabLinearCombination - (norm? : Option Syntax.Tactic) (exp? : Option Syntax.NumLit) (input : Option Syntax.Term) - (twoGoals := false) : Tactic.TacticM Unit := Tactic.withMainContext do +/-- Implementation of `linear_combination`. -/ +def elabLinearCombination (tk : Syntax) + (norm? : Option Syntax.Tactic) (exp? : Option Syntax.NumLit) (input : Option Syntax.Term) : + Tactic.TacticM Unit := Tactic.withMainContext do let some (ty, _) := (← (← Tactic.getMainGoal).getType').eq? | throwError "'linear_combination' only proves equalities" let p ← match input with | none => `(Eq.refl 0) | some e => match ← expandLinearCombo ty e with - | .const c => `(Eq.refl $c) + | .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 `(tactic| ring1)) - Tactic.evalTactic <| ← withFreshMacroScope <| - if twoGoals then - `(tactic| ( - refine eq_trans₃ $p ?a ?b - case' a => $norm:tactic - case' b => $norm:tactic)) - else - match exp? with - | some n => - if n.getNat = 1 then `(tactic| (refine eq_of_add $p ?a; case' a => $norm:tactic)) - else `(tactic| (refine eq_of_add_pow $n $p ?a; case' a => $norm:tactic)) - | _ => `(tactic| (refine eq_of_add $p ?a; case' a => $norm:tactic)) + let norm := norm?.getD (Unhygienic.run <| withRef tk `(tactic| ring1)) + let lem : Ident ← mkIdent <$> do + try + -- if we are in a "true" ring, with well-behaved negation, it is better to present the + -- normalization tactic with a goal of the form `[stuff] = 0`, because this gives more useful + -- error messages on failure + let _ ← synthInstance (← mkAppM ``Neg #[ty]) + pure ``eq_of_sub + catch _ => + -- but otherwise (for example over `ℕ` or `ℝ≥0`) we can solve the problem by presenting the + -- normalization tactic with a goal of the form `[stuff] = [stuff]` + pure ``eq_of_add + Term.withoutErrToSorry <| Tactic.evalTactic <| ← withFreshMacroScope <| + match exp? with + | some n => + if n.getNat = 1 then `(tactic| (refine $lem $p ?a; case' a => $norm:tactic)) + else `(tactic| (refine eq_of_add_pow $n $p ?a; case' a => $norm:tactic)) + | _ => `(tactic| (refine $lem $p ?a; case' a => $norm:tactic)) /-- The `(norm := $tac)` syntax says to use `tac` as a normalization postprocessor for @@ -169,13 +152,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: 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 - instances of `Mul` and `AddGroup` for this type. +Note: The left and right sides of all the equalities should have the same type `α`, and the +coefficients should also have type `α`. For full functionality `α` should be a commutative ring -- +strictly speaking, a commutative semiring with "cancellative" addition (in the semiring case, +negation and subtraction will be handled "formally" as if operating in the enveloping ring). If a +nonstandard normalization is used (for example `abel` or `skip`), the tactic will work over types +`α` with less algebraic structure: the minimum is instances of `[Add α] [IsRightCancelAdd α]` +together with instances of whatever operations are used in the tactic call. * The input `e` in `linear_combination e` is a linear combination of proofs of equalities, given as a sum/difference of coefficients multiplied by expressions. @@ -191,17 +178,6 @@ Note: The left and right sides of all the equalities should have the same * `linear_combination (exp := n) e` will take the goal to the `n`th power before subtracting the combination `e`. In other words, if the goal is `t1 = t2`, `linear_combination (exp := n) e` will change the goal to `(t1 - t2)^n = 0` before proceeding as above. - This feature is not supported for `linear_combination2`. -* `linear_combination2 e` is the same as `linear_combination e` but it produces two - subgoals instead of one: rather than proving that `(a - b) - (a' - b') = 0` where - `a' = b'` is the linear combination from `e` and `a = b` is the goal, - it instead attempts to prove `a = a'` and `b = b'`. - Because it does not use subtraction, this form is applicable also to semirings. - * Note that a goal which is provable by `linear_combination e` may not be provable - by `linear_combination2 e`; in general you may need to add a coefficient to `e` - to make both sides match, as in `linear_combination2 e + c`. - * You can also reverse equalities using `← h`, so for example if `h₁ : a = b` - then `2 * (← h)` is a proof of `2 * b = 2 * a`. Example Usage: ``` @@ -238,16 +214,7 @@ example (a b : ℚ) (h : ∀ p q : ℚ, p = q) : 3*a + qc = 3*b + 2*qc := by syntax (name := linearCombination) "linear_combination" (normStx)? (expStx)? (ppSpace colGt term)? : tactic elab_rules : tactic - | `(tactic| linear_combination $[(norm := $tac)]? $[(exp := $n)]? $(e)?) => - elabLinearCombination tac n e - -@[inherit_doc linearCombination] -syntax "linear_combination2" (normStx)? (ppSpace colGt term)? : tactic -elab_rules : tactic - | `(tactic| linear_combination2 $[(norm := $tac)]? $(e)?) => elabLinearCombination tac none e true - -end LinearCombination - -end Tactic + | `(tactic| linear_combination%$tk $[(norm := $tac)]? $[(exp := $n)]? $(e)?) => + elabLinearCombination tk tac n e -end Mathlib +end Mathlib.Tactic.LinearCombination 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 5ed156753cbd9..2f67da1bea192 100644 --- a/Mathlib/Tactic/Linter.lean +++ b/Mathlib/Tactic/Linter.lean @@ -1,16 +1,14 @@ /- -This is the `Linter`s file: it only imports files defining linters and is -intended to be imported fairly early in `Mathlib`. +This is the `Linter`s file: it imports files defining linters. +All syntax linters enabled by default are imported in `Mathlib.Init`; +this file contains all other linters. This file is ignored by `shake`: * it is in `ignoreAll`, meaning that all its imports are considered necessary; * it is in `ignoreImport`, meaning that where it is imported, it is considered necessary. -/ -import Mathlib.Tactic.Linter.GlobalAttributeIn -import Mathlib.Tactic.Linter.HashCommandLinter +import Mathlib.Tactic.Linter.FlexibleLinter import Mathlib.Tactic.Linter.HaveLetLinter -import Mathlib.Tactic.Linter.Lint -import Mathlib.Tactic.Linter.RefineLinter -import Mathlib.Tactic.Linter.Style -import Mathlib.Tactic.Linter.UnusedTactic +import Mathlib.Tactic.Linter.MinImports +import Mathlib.Tactic.Linter.PPRoundtrip diff --git a/Mathlib/Tactic/Linter/AdmitLinter.lean b/Mathlib/Tactic/Linter/AdmitLinter.lean new file mode 100644 index 0000000000000..602952c5a6692 --- /dev/null +++ b/Mathlib/Tactic/Linter/AdmitLinter.lean @@ -0,0 +1,55 @@ +/- +Copyright (c) 2024 Adomas Baliuka. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Damiano Testa, Adomas Baliuka +-/ +import Lean.Elab.Command + +/-! +# The "admit" linter + +The "admit" linter flags usages of the `admit` tactic. + +The tactics `admit` and `sorry` are synonyms. +The use of `sorry` is much more common and should be preferred. + +This linter is an incentive to discourage uses of `admit`, without being a ban. +-/ + +namespace Mathlib.Linter + +/-- The admit linter emits a warning on usages of `admit`. -/ +register_option linter.admit : Bool := { + defValue := false + descr := "enable the admit linter" +} + +namespace AdmitLinter + +open Lean Elab + +/-- `getAdmit t` returns all usages of the `admit` tactic in the input syntax `t`. -/ +partial +def getAdmit (stx : Syntax) : Array Syntax := + if let `(tactic| admit) := stx then + #[stx] + else + stx.foldArgs (fun arg r => r ++ getAdmit arg) #[] + +/-- The "admit" linter flags usages of the `admit` tactic. + +The tactics `admit` and `sorry` are synonyms. +The use of `sorry` is much more common and should be preferred. +-/ +def admitLinter : Linter where run := withSetOptionIn fun stx => do + unless Linter.getLinterValue linter.admit (← getOptions) do + return + if (← MonadState.get).messages.hasErrors then + return + for stxAdmit in (getAdmit stx) do + Linter.logLint linter.admit stxAdmit + "The `admit` tactic is discouraged: please consider using the synonymous `sorry` instead." + +initialize addLinter admitLinter + +end AdmitLinter 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 new file mode 100644 index 0000000000000..525285a97bfef --- /dev/null +++ b/Mathlib/Tactic/Linter/FlexibleLinter.lean @@ -0,0 +1,429 @@ +/- +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 Batteries.Data.Array.Basic +import Batteries.Lean.HashSet + +/-! +# The "flexible" linter + +The "flexible" linter makes sure that a "rigid" tactic (such as `rw`) does not act on the +output of a "flexible" tactic (such as `simp`). + +For example, this ensures that, if you want to use `simp [...]` in the middle of a proof, +then you should replace `simp [...]` by one of +* a `suffices \"expr after simp\" by simpa` line; +* the output of `simp? [...]`, so that the final code contains `simp only [...]`; +* something else that does not involve `simp`! + +Otherwise, the linter will complain. + +Simplifying and appealing to a geometric intuition, you can imagine a (tactic) proof like a +directed graph, where +* each node is a local hypothesis or a goal in some metavariable and +* two hypotheses/goals are connected by an arrow if there is a tactic that modifies the source + of the arrow into the target (this does not apply well to all tactics, but it does apply to + a large number of them). +With this in mind, a tactic like `rw [lemma]` takes a *very specific* input and return a +*very predictable* output. +Such a tactic is "rigid". Any tactic is rigid, unless it is in `flexible` or `stoppers`. +Conversely, a tactic like `simp` acts on a wide variety of inputs and returns an output that +is possibly unpredictable: if later modifications adds a `simp`-lemma or some internals of +`simp` changes, the output of `simp` may change as well. +Such a tactic is `flexible`. Other examples are `split`, `abel`, `norm_cast`,... +Let's go back to the graph picture above. +* ✅️ [`rigid` --> `flexible`] + A sequence `rw [lemma]; simp` is unlikely to break, since `rw [lemma]` produces the same output + unless some *really major* change happens! +* ❌️ [`flexible` --> `rigid`] + A sequence `simp; rw [lemma]` is instead more likely to break, since the goal after `simp` is + subject to change by even a small, likely, modification of the `simp` set. +* ✅️ [`flexible` --> `flexible`] + A sequence `simp; linarith` is also quite stable, since if `linarith` was able to close the + goal with a "weaker" `simp`, it will likely still be able to close the goal with a `simp` + that takes one further step. +* ✅️ [`flexible` --> `stopper`] + Finally, a sequence `simp; ring_nf` is stable and, moreover, the output of `ring_nf` is a + "normal form", which means that it is likely to produce an unchanged result, even if the initial + input is different from the proof in its initial form. + A stopper can be followed by a rigid tactic, "stopping" the spread of the flexible reach. + +What the linter does is keeping track of nodes that are connected by `flexible` tactics and +makes sure that only `flexible` or `stoppers` follow them. +Such nodes are `Stained`. +Whenever it reaches a `stopper` edge, the target node is no longer `Stained` and it is +available again to `rigid` tactics. + +Currently, the only tactics that "start" the bookkeeping are most forms of non-`only` `simp`s. +These are encoded by the `flexible?` predicate. +Future modifications of the linter may increase the scope of the `flexible?` predicate and +forbid a wider range of combinations. + +## TODO +The example +```lean +example (h : 0 = 0) : True := by + simp at h + assumption +``` +should trigger the linter, since `assumption` uses `h` that has been "stained" by `simp at h`. +However, `assumption` contains no syntax information for the location `h`, so the linter in its +current form does not catch this. + +## Implementation notes + +A large part of the code is devoted to tracking `FVar`s and `MVar`s between tactics. + +For the `FVar`s, this follows the following heuristic: +* if the unique name of the `FVar` is preserved, then we use that; +* otherwise, if the `userName` of the `FVar` is preserved, then we use that; +* if neither is preserved, we drop the ball and stop tracking the `FVarId`. + +For the `MVar`s, we use the information of `Lean.Elab.TacticInfo.goalsBefore` and +`Lean.Elab.TacticInfo.goalsAfter`. +By looking at the `mvar`s that are either only "before" or only "after", we focus on the +"active" goals. +We then propagate all the `FVarId`s that were present in the "before" goals to the "after" goals, +while leaving untouched the ones in the "inert" goals. +-/ + +open Lean Elab + +namespace Mathlib.Linter + +/-- The flexible linter makes sure that "rigid" tactics do not follow "flexible" tactics. -/ +register_option linter.flexible : Bool := { + defValue := false + descr := "enable the flexible linter" +} + +/-- `flexible? stx` is `true` if `stx` is syntax for a tactic that takes a "wide" variety of +inputs and modifies them in possibly unpredictable ways. + +The prototypical flexible tactic is `simp`. +The prototypical non-flexible tactic `rw`. +`simp only` is also non-flexible. -/ +-- TODO: adding more entries here, allows to consider more tactics to be flexible +def flexible? : Syntax → Bool + | .node _ ``Lean.Parser.Tactic.simp #[_, _, _, only?, _, _] => only?[0].getAtomVal != "only" + | .node _ ``Lean.Parser.Tactic.simpAll #[_, _, _, only?, _] => only?[0].getAtomVal != "only" + | _ => false + +end Mathlib.Linter + +section goals_heuristic +namespace Lean.Elab.TacticInfo + +/-! +### Heuristics for determining goals goals that a tactic modifies what they become + +The two definitions `goalsTargetedBy`, `goalsCreatedBy` extract a list of +`MVarId`s attempting to determine on which goals the tactic `t` is acting and what are the +resulting modified goals. +This is mostly based on the heuristic that the tactic will "change" an `MVarId`. +-/ + +/-- `goalsTargetedBy t` are the `MVarId`s before the `TacticInfo` `t` that "disappear" after it. +They should correspond to the goals in which the tactic `t` performs some action. -/ +def goalsTargetedBy (t : TacticInfo) : List MVarId := + t.goalsBefore.filter (·.name ∉ t.goalsAfter.map (·.name)) + +/-- `goalsCreatedBy t` are the `MVarId`s after the `TacticInfo` `t` that were not present before. +They should correspond to the goals created or changed by the tactic `t`. -/ +def goalsCreatedBy (t : TacticInfo) : List MVarId := + t.goalsAfter.filter (·.name ∉ t.goalsBefore.map (·.name)) + +end Lean.Elab.TacticInfo +end goals_heuristic + +namespace Mathlib.Linter.Flexible + +variable (take? : Syntax → Bool) in +/-- `extractCtxAndGoals take? tree` takes as input a function `take? : Syntax → Bool` and +an `InfoTree` and returns the array of pairs `(stx, mvars)`, +where `stx` is a syntax node such that `take? stx` is `true` and +`mvars` indicates the goal state: + * the context before `stx` + * the context after `stx` + * a list of metavariables closed by `stx` + * a list of metavariables created by `stx` + +A typical usage is to find the goals following a `simp` application. +-/ +partial +def extractCtxAndGoals : InfoTree → + Array (Syntax × MetavarContext × MetavarContext × List MVarId × List MVarId) + | .node k args => + let kargs := (args.map extractCtxAndGoals).foldl (· ++ ·) #[] + if let .ofTacticInfo i := k then + if take? i.stx && (i.stx.getRange? true).isSome then + #[(i.stx, i.mctxBefore, i.mctxAfter, i.goalsTargetedBy, i.goalsCreatedBy)] ++ kargs + else kargs + else kargs + | .context _ t => extractCtxAndGoals t + | _ => default + +/-- `Stained` is the type of the stained locations: it can be +* a `Name` (typically of associated to the `FVarId` of a local declaration); +* the goal (`⊢`); +* the "wildcard" -- all the declaration in context (`*`). +-/ +inductive Stained + | name : Name → Stained + | goal : Stained + | wildcard : Stained + deriving Repr, Inhabited, DecidableEq, Hashable + +/-- Converting a `Stained` to a `String`: +* a `Name` is represented by the corresponding string; +* `goal` is represented by `⊢`; +* `wildcard` is represented by `*`. +-/ +instance : ToString Stained where + toString | .name n => n.toString | .goal => "⊢" | .wildcard => "*" + +/-- +`toStained stx` scans the input `Syntax` `stx` extracting identifiers and atoms, making an effort +to convert them to `Stained`. +The function is used to extract "location" information about `stx`: either explicit locations as in +`rw [] at locations` or implicit ones as `rw [h]`. + +Whether or not what this function extracts really is a location will be determined by the linter +using data embedded in the `InfoTree`s. -/ +partial +def toStained : Syntax → Std.HashSet Stained + | .node _ _ arg => (arg.map toStained).foldl (.union) {} + | .ident _ _ val _ => {.name val} + | .atom _ val => match val with + | "*" => {.wildcard} + | "⊢" => {.goal} + | "|" => {.goal} + | _ => {} + | _ => {} + +/-- `getStained stx` expects `stx` to be an argument of a node of `SyntaxNodeKind` +`Lean.Parser.Tactic.location`. +Typically, we apply `getStained` to the output of `getLocs`. + +See `getStained!` for a similar function. -/ +partial +def getStained (stx : Syntax) (all? : Syntax → Bool := fun _ ↦ false) : Std.HashSet Stained := + match stx with + | stx@(.node _ ``Lean.Parser.Tactic.location loc) => + if all? stx then {} else (loc.map toStained).foldl (·.union) {} + | .node _ _ args => (args.map (getStained · all?)).foldl (·.union) {} + | _ => default + +/-- `getStained! stx` expects `stx` to be an argument of a node of `SyntaxNodeKind` +`Lean.Parser.Tactic.location`. +Typically, we apply `getStained!` to the output of `getLocs`. + +It returns the `HashSet` of `Stained` determined by the locations in `stx`. + +The only difference with `getStained stx`, is that `getStained!` never returns `{}`: +if `getStained stx = {}`, then `getStained' stx = {.goal}`. + +This means that tactics that do not have an explicit "`at`" in their syntax will be treated as +acting on the main goal. -/ +def getStained! (stx : Syntax) (all? : Syntax → Bool := fun _ ↦ false) : Std.HashSet Stained := + let out := getStained stx all? + if out.size == 0 then {.goal} else out + +/-- `Stained.toFMVarId mv lctx st` takes a metavariable `mv`, a local context `lctx` and +a `Stained` `st` and returns the array of pairs `(FVarId, mv)`s that `lctx` assigns to `st` +(the second component is always `mv`): +* if `st` "is" a `Name`, returns the singleton of the `FVarId` with the name carried by `st`; +* if `st` is `.goal`, returns the singleton `#[default]`; +* if `st` is `.wildcard`, returns the array of all the `FVarId`s in `lctx` with also `default` + (to keep track of the `goal`). +-/ +def Stained.toFMVarId (mv : MVarId) (lctx: LocalContext) : Stained → Array (FVarId × MVarId) + | name n => match lctx.findFromUserName? n with + | none => #[] + | some decl => #[(decl.fvarId, mv)] + | goal => #[(default, mv)] + | wildcard => (lctx.getFVarIds.push default).map (·, mv) + +/-- `SyntaxNodeKind`s that are mostly "formatting": mostly they are ignored +because we do not want the linter to spend time on them. +The nodes that they contain will be visited by the linter anyway. +The nodes that *follow* them, though, will *not* be visited by the linter. +-/ +def stoppers : Std.HashSet Name := + { -- "properly stopper tactics": the effect of these tactics is to return a normal form + -- (or possibly be finishing tactics -- the ultimate normal form! + -- finishing tactics could equally well be considered as `flexible`, but as there is + -- no possibility of a follower anyway, it does not make a big difference.) + ``Lean.Parser.Tactic.tacticSorry, + ``Lean.Parser.Tactic.tacticRepeat_, + ``Lean.Parser.Tactic.tacticStop_, + `Mathlib.Tactic.Abel.abelNF, + `Mathlib.Tactic.RingNF.ringNF, + -- "continuators": the *effect* of these tactics is similar the "properly stoppers" above, + -- though they typically wrap other tactics inside them. + -- The linter ignores the wrapper, but does recurse into the enclosed tactics + ``Lean.Parser.Tactic.tacticSeq1Indented, + ``Lean.Parser.Tactic.tacticSeq, + ``Lean.Parser.Term.byTactic, + `by, + ``Lean.Parser.Tactic.tacticTry_, + `choice, -- involved in `first` + ``Lean.Parser.Tactic.allGoals, + `Std.Tactic.«tacticOn_goal-_=>_», + ``Lean.Parser.Tactic.«tactic_<;>_», + ``cdotTk, + ``cdot } + +/-- `SyntaxNodeKind`s that are allowed to follow a flexible tactic: + `simp`, `simp_all`, `simpa`, `dsimp`, `constructor`, `congr`, `done`, `rfl`, `omega`, `abel`, + `ring`, `linarith`, `nlinarith`, `norm_cast`, `aesop`, `tauto`, `fun_prop`, `split`, `split_ifs`. +-/ +def flexible : Std.HashSet Name := + { ``Lean.Parser.Tactic.simp, + ``Lean.Parser.Tactic.simpAll, + ``Lean.Parser.Tactic.simpa, + ``Lean.Parser.Tactic.dsimp, + ``Lean.Parser.Tactic.constructor, + ``Lean.Parser.Tactic.congr, + ``Lean.Parser.Tactic.done, + ``Lean.Parser.Tactic.tacticRfl, + ``Lean.Parser.Tactic.omega, + `Mathlib.Tactic.Abel.abel, + `Mathlib.Tactic.RingNF.ring, + `Mathlib.Tactic.normNum, + `linarith, + `nlinarith, + ``Lean.Parser.Tactic.tacticNorm_cast_, + `Aesop.Frontend.Parser.aesopTactic, + `Mathlib.Tactic.Tauto.tauto, + `Mathlib.Meta.FunProp.funPropTacStx, + `Lean.Parser.Tactic.split, + `Mathlib.Tactic.splitIfs } + +/-- By default, if a `SyntaxNodeKind` is not special-cased here, then the linter assumes that +the tactic will use the goal as well: this heuristic works well with `exact`, `refine`, `apply`. +For tactics such as `cases` this is not true: for these tactics, `usesGoal?` yields `false. -/ +def usesGoal? : SyntaxNodeKind → Bool + | ``Lean.Parser.Tactic.cases => false + | `Mathlib.Tactic.cases' => false + | ``Lean.Parser.Tactic.obtain => false + | ``Lean.Parser.Tactic.tacticHave_ => false + | ``Lean.Parser.Tactic.rcases => false + | ``Lean.Parser.Tactic.specialize => false + | ``Lean.Parser.Tactic.subst => false + | ``«tacticBy_cases_:_» => false + | ``Lean.Parser.Tactic.induction => false + | _ => true + +/-- `getFVarIdCandidates fv name lctx` takes an input an `FVarId`, a `Name` and a `LocalContext`. +It returns an array of guesses for a "best fit" `FVarId` in the given `LocalContext`. +The first entry of the array is the input `FVarId` `fv`, if it is present. +The next entry of the array is the `FVarId` with the given `Name`, if present. + +Usually, the first entry of the returned array is "the best approximation" to `(fv, name)`. -/ +def getFVarIdCandidates (fv : FVarId) (name : Name) (lctx : LocalContext) : Array FVarId := + #[lctx.find? fv, lctx.findFromUserName? name].reduceOption.map (·.fvarId) + +/-! +Tactics often change the name of the current `MVarId`, as well as the names of the `FVarId`s +appearing in their local contexts. +The function `reallyPersist` makes an attempt at "tracking" pairs `(fvar, mvar)` across a +simultaneous change represented by an "old" list of `MVarId`s and the corresponding +`MetavarContext` and a new one. + +This arises in the context of the information encoded in the `InfoTree`s when processing a +tactic proof. +-/ + +/-- `persistFVars` is one step in persisting: track a single `FVarId` between two `LocalContext`s. +If an `FVarId` with the same unique name exists in the new context, use it. +Otherwise, if an `FVarId` with the same `userName` exists in the new context, use it. +If both of these fail, return `default` (i.e. "fail"). -/ +def persistFVars (fv : FVarId) (before after : LocalContext) : FVarId := + let ldecl := (before.find? fv).getD default + let name := ldecl.userName + (getFVarIdCandidates fv name after).getD 0 default + +/-- `reallyPersist` converts an array of pairs `(fvar, mvar)` to another array of the same type. -/ +def reallyPersist + (fmvars : Array (FVarId × MVarId)) (mvs0 mvs1 : List MVarId) (ctx0 ctx1 : MetavarContext) : + Array (FVarId × MVarId) := Id.run do + -- split the input `fmvars` into + -- * the `active` ones, whose `mvar` appears in `mvs0` and + -- * the `inert` ones, the rest. + -- `inert` gets copied unchanged, while we transform `active` + let (active, inert) := fmvars.partition fun (_, mv) => mvs0.contains mv + let mut new := #[] + for (fvar, mvar) in active do -- for each `active` pair `(fvar, mvar)` + match ctx0.decls.find? mvar with -- check if `mvar` is managed by `ctx0` (it should be) + | none => -- the `mvar` is not managed by `ctx0`: no change + new := new.push (fvar, mvar) + | some mvDecl0 => -- the `mvar` *is* managed by `ctx0`: push the pair `(fvar, mvar)` through + for mv1 in mvs1 do -- for each new `MVarId` in `mvs1` + match ctx1.decls.find? mv1 with -- check if `mv1` is managed by `ctx1` (it should be) + | none => dbg_trace "'really_persist' could this happen?" default -- ??? maybe `.push`? + | some mvDecl1 => -- we found a "new" declaration + let persisted_fv := persistFVars fvar mvDecl0.lctx mvDecl1.lctx -- persist `fv` + new := new.push (persisted_fv, mv1) + return inert ++ new + +/-- The main implementation of the flexible linter. -/ +def flexibleLinter : Linter where run := withSetOptionIn fun _stx => do + unless Linter.getLinterValue linter.flexible (← getOptions) && (← getInfoState).enabled do + return + if (← MonadState.get).messages.hasErrors then + return + let trees ← getInfoTrees + let x := trees.toList.map (extractCtxAndGoals (fun _ => true)) + -- `stains` records pairs `(location, mvar)`, where + -- * `location` is either a hypothesis or the main goal modified by a flexible tactic and + -- * `mvar` is the metavariable containing the modified location + let mut stains : Array ((FVarId × MVarId) × (Stained × Syntax)) := .empty + let mut msgs : Array (Syntax × Syntax × Stained) := #[] + for d in x do for (s, ctx0, ctx1, mvs0, mvs1) in d do + let skind := s.getKind + if stoppers.contains skind then continue + let shouldStain? := flexible? s && mvs1.length == mvs0.length + for d in getStained! s do + if shouldStain? then + for currMVar1 in mvs1 do + let lctx1 := ((ctx1.decls.find? currMVar1).getD default).lctx + let locsAfter := d.toFMVarId currMVar1 lctx1 + + for l in locsAfter do + stains := stains.push (l, (d, s)) + + else + let stained_in_syntax := if usesGoal? skind then (toStained s).insert d else toStained s + if !flexible.contains skind then + for currMv0 in mvs0 do + let lctx0 := ((ctx0.decls.find? currMv0).getD default).lctx + let mut foundFvs : Std.HashSet (FVarId × MVarId):= {} + for st in stained_in_syntax do + for d in st.toFMVarId currMv0 lctx0 do + if !foundFvs.contains d then foundFvs := foundFvs.insert d + for l in foundFvs do + if let some (_stdLoc, (st, kind)) := stains.find? (Prod.fst · == l) then + msgs := msgs.push (s, kind, st) + + -- tactics often change the name of the current `MVarId`, so we migrate the `FvarId`s + -- in the "old" `mvars` to the "same" `FVarId` in the "new" `mvars` + let mut new : Array ((FVarId × MVarId) × (Stained × Syntax)) := .empty + for (fv, (stLoc, kd)) in stains do + let psisted := reallyPersist #[fv] mvs0 mvs1 ctx0 ctx1 + if psisted == #[] && mvs1 != [] then + new := new.push (fv, (stLoc, kd)) + dbg_trace "lost {((fv.1.name, fv.2.name), stLoc, kd)}" + for p in psisted do new := new.push (p, (stLoc, kd)) + stains := new + + for (s, stainStx, d) in msgs do + Linter.logLint linter.flexible stainStx m!"'{stainStx}' is a flexible tactic modifying '{d}'…" + logInfoAt s m!"… and '{s}' uses '{d}'!" + +initialize addLinter flexibleLinter + +end Mathlib.Linter.Flexible diff --git a/Mathlib/Tactic/Linter/GlobalAttributeIn.lean b/Mathlib/Tactic/Linter/GlobalAttributeIn.lean index 578c12d114d36..6a6c49e09f4ad 100644 --- a/Mathlib/Tactic/Linter/GlobalAttributeIn.lean +++ b/Mathlib/Tactic/Linter/GlobalAttributeIn.lean @@ -5,7 +5,6 @@ Authors: Michael Rothgang, Damiano Testa -/ import Lean.Elab.Command -import Lean.Linter.Util /-! # Linter for `attribute [...] in` declarations diff --git a/Mathlib/Tactic/Linter/HashCommandLinter.lean b/Mathlib/Tactic/Linter/HashCommandLinter.lean index 09ceae9db6b3a..66cac438ada34 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 Lean.Linter.Util import Batteries.Lean.HashSet /-! @@ -29,7 +28,7 @@ For example, `#guard true` and `#check_tactic True ~> True by skip` trigger a me There is a list of silent `#`-command that are allowed. -/ register_option linter.hashCommand : Bool := { - defValue := true + defValue := false descr := "enable the `#`-command linter" } @@ -37,9 +36,6 @@ namespace HashCommandLinter open Lean Elab -/-- Gets the value of the `linter.hashCommand` option. -/ -def getLinterHash (o : Options) : Bool := Linter.getLinterValue linter.hashCommand o - open Command in /-- Exactly like `withSetOptionIn`, but recursively discards nested uses of `in`. Intended to be used in the `hashCommand` linter, where we want to enter `set_option` `in` commands. @@ -56,7 +52,7 @@ private partial def withSetOptionIn' (cmd : CommandElab) : CommandElab := fun st cmd stx /-- `allowed_commands` is the `HashSet` of `#`-commands that are allowed in 'Mathlib'. -/ -private abbrev allowed_commands : HashSet String := { "#adaptation_note" } +private abbrev allowed_commands : Std.HashSet String := { "#adaptation_note" } /-- Checks that no command beginning with `#` is present in 'Mathlib', except for the ones in `allowed_commands`. @@ -68,7 +64,7 @@ However, in order to avoid local clutter, when `warningAsError` is `false`, the logs a warning only for the `#`-commands that do not already emit a message. -/ def hashCommandLinter : Linter where run := withSetOptionIn' fun stx => do let mod := (← getMainModule).components - if getLinterHash (← getOptions) && + if Linter.getLinterValue linter.hashCommand (← getOptions) && ((← get).messages.toList.isEmpty || warningAsError.get (← getOptions)) && -- we check that the module is either not in `test` or, is `test.HashCommandLinter` (mod.getD 0 default != `test || (mod == [`test, `HashCommandLinter])) diff --git a/Mathlib/Tactic/Linter/HaveLetLinter.lean b/Mathlib/Tactic/Linter/HaveLetLinter.lean index e59b5417ef447..08b0435b8de7c 100644 --- a/Mathlib/Tactic/Linter/HaveLetLinter.lean +++ b/Mathlib/Tactic/Linter/HaveLetLinter.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa -/ +import Mathlib.Init import Lean.Elab.Command import Lean.Server.InfoUtils @@ -38,7 +39,7 @@ There are three settings: The default value is `1`. -/ register_option linter.haveLet : Nat := { - defValue := 1 + defValue := 0 descr := "enable the `have` vs `let` linter:\n\ * 0 -- inactive;\n\ * 1 -- active only on noisy declarations;\n\ @@ -128,3 +129,7 @@ def haveLetLinter : Linter where run := withSetOptionIn fun _stx => do You can disable this linter using `set_option linter.haveLet 0`" initialize addLinter haveLetLinter + +end haveLet + +end Mathlib.Linter diff --git a/Mathlib/Tactic/Linter/Lint.lean b/Mathlib/Tactic/Linter/Lint.lean index bdd5e856f065d..6d00f05354dde 100644 --- a/Mathlib/Tactic/Linter/Lint.lean +++ b/Mathlib/Tactic/Linter/Lint.lean @@ -3,8 +3,6 @@ Copyright (c) 2023 Floris van Doorn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn -/ -import Lean.Linter.Util -import Batteries.Data.String.Matcher import Batteries.Tactic.Lint /-! @@ -15,7 +13,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 /-- @@ -29,7 +27,7 @@ Linter that checks whether a structure should be in Prop. -- remark: using `Lean.Meta.isProp` doesn't suffice here, because it doesn't (always?) -- recognize predicates as propositional. let isProp ← forallTelescopeReducing (← inferType (← mkConstWithLevelParams declName)) - fun _ ty => return ty == .sort .zero + fun _ ty ↦ return ty == .sort .zero if isProp then return none let projs := (getStructureInfo? (← getEnv) declName).get!.fieldNames if projs.isEmpty then return none -- don't flag empty structures @@ -47,7 +45,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 @@ -79,9 +77,6 @@ namespace DupNamespaceLinter open Lean Parser Elab Command Meta -/-- Gets the value of the `linter.dupNamespace` option. -/ -def getLinterDupNamespace (o : Options) : Bool := Linter.getLinterValue linter.dupNamespace o - /-- `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 @@ -89,18 +84,18 @@ 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) + ((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 getLinterDupNamespace (← getOptions) then +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 + 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}'" @@ -122,24 +117,19 @@ open Lean Elab Command /-- The "missing end" linter emits a warning on non-closed `section`s and `namespace`s. It allows the "outermost" `noncomputable section` to be left open (whether or not it is named). -/ -register_option linter.missingEnd : Bool := { - defValue := true +register_option linter.style.missingEnd : Bool := { + defValue := false descr := "enable the missing end linter" } -namespace MissingEnd +namespace Style.missingEnd -/-- Gets the value of the `linter.missingEnd` option. -/ -def getLinterHash (o : Options) : Bool := Linter.getLinterValue linter.missingEnd o - -@[inherit_doc Mathlib.Linter.linter.missingEnd] +@[inherit_doc Mathlib.Linter.linter.style.missingEnd] def missingEndLinter : Linter where run := withSetOptionIn fun stx ↦ do -- Only run this linter at the end of a module. unless stx.isOfKind ``Lean.Parser.Command.eoi do return - -- TODO: once mathlib's Lean version includes leanprover/lean4#4741, make this configurable - unless #[`Mathlib, `test, `Archive, `Counterexamples].contains (← getMainModule).getRoot do - return - if getLinterHash (← getOptions) && !(← MonadState.get).messages.hasErrors then + if Linter.getLinterValue linter.style.missingEnd (← getOptions) && + !(← MonadState.get).messages.hasErrors then let sc ← getScopes -- The last scope is always the "base scope", corresponding to no active `section`s or -- `namespace`s. We are interested in any *other* unclosed scopes. @@ -151,12 +141,12 @@ def missingEndLinter : Linter where run := withSetOptionIn fun stx ↦ do if !ends.isEmpty then let ending := (ends.map Prod.fst).foldl (init := "") fun a b ↦ a ++ s!"\n\nend{if b == "" then "" else " "}{b}" - Linter.logLint linter.missingEnd stx + Linter.logLint linter.style.missingEnd stx m!"unclosed sections or namespaces; expected: '{ending}'" initialize addLinter missingEndLinter -end MissingEnd +end Style.missingEnd /-! # The `cdot` linter @@ -164,14 +154,16 @@ end MissingEnd The `cdot` linter is a syntax-linter that flags uses of the "cdot" `·` that are achieved by typing a character different from `·`. For instance, a "plain" dot `.` is allowed syntax, but is flagged by the linter. +It also flags "isolated cdots", i.e. when the `·` is on its own line. -/ /-- The `cdot` linter flags uses of the "cdot" `·` that are achieved by typing a character different from `·`. -For instance, a "plain" dot `.` is allowed syntax, but is flagged by the linter. -/ -register_option linter.cdot : Bool := { - defValue := true +For instance, a "plain" dot `.` is allowed syntax, but is flagged by the linter. +It also flags "isolated cdots", i.e. when the `·` is on its own line. -/ +register_option linter.style.cdot : Bool := { + defValue := false descr := "enable the `cdot` linter" } @@ -189,7 +181,7 @@ def findCDot : Syntax → Array Syntax | stx@(.node _ kind args) => let dargs := (args.map findCDot).flatten match kind with - | ``Lean.Parser.Term.cdot | ``cdotTk=> dargs.push stx + | ``Lean.Parser.Term.cdot | ``cdotTk => dargs.push stx | _ => dargs |_ => #[] @@ -200,47 +192,207 @@ This is precisely what the `cdot` linter flags. def unwanted_cdot (stx : Syntax) : Array Syntax := (findCDot stx).filter (!isCDot? ·) -namespace CDotLinter +namespace Style -/-- Gets the value of the `linter.generic` option. -/ -def getLinterHash (o : Options) : Bool := Linter.getLinterValue linter.cdot o - -@[inherit_doc linter.cdot] -def cdotLinter : Linter where run := withSetOptionIn fun stx => do - unless getLinterHash (← getOptions) do +@[inherit_doc linter.style.cdot] +def cdotLinter : Linter where run := withSetOptionIn fun stx ↦ do + unless Linter.getLinterValue linter.style.cdot (← getOptions) do return if (← MonadState.get).messages.hasErrors then return for s in unwanted_cdot stx do - Linter.logLint linter.cdot s m!"Please, use '·' (typed as `\\.`) instead of '{s}' as 'cdot'." + Linter.logLint linter.style.cdot s + m!"Please, use '·' (typed as `\\.`) instead of '{s}' as 'cdot'." + -- We also check for isolated cdot's, i.e. when the cdot is on its own line. + for cdot in Mathlib.Linter.findCDot stx do + match cdot.find? (·.isOfKind `token.«· ») with + | some (.node _ _ #[.atom (.original _ _ afterCDot _) _]) => + if (afterCDot.takeWhile (·.isWhitespace)).contains '\n' then + logWarningAt cdot <| .tagged linter.style.cdot.name + m!"This central dot `·` is isolated; please merge it with the next line." + | _ => return initialize addLinter cdotLinter -end CDotLinter +end Style + +/-! +# The `dollarSyntax` linter + +The `dollarSyntax` linter flags uses of `<|` that are achieved by typing `$`. +These are disallowed by the mathlib style guide, as using `<|` pairs better with `|>`. +-/ + +/-- The `dollarSyntax` linter flags uses of `<|` that are achieved by typing `$`. +These are disallowed by the mathlib style guide, as using `<|` pairs better with `|>`. -/ +register_option linter.style.dollarSyntax : Bool := { + defValue := false + descr := "enable the `dollarSyntax` linter" +} + +namespace Style.dollarSyntax + +/-- `findDollarSyntax stx` extracts from `stx` the syntax nodes of `kind` `$`. -/ +partial +def findDollarSyntax : Syntax → Array Syntax + | stx@(.node _ kind args) => + let dargs := (args.map findDollarSyntax).flatten + match kind with + | ``«term_$__» => dargs.push stx + | _ => dargs + |_ => #[] + +@[inherit_doc linter.style.dollarSyntax] +def dollarSyntaxLinter : Linter where run := withSetOptionIn fun stx ↦ do + unless Linter.getLinterValue linter.style.dollarSyntax (← getOptions) do + return + if (← MonadState.get).messages.hasErrors then + return + for s in findDollarSyntax stx do + Linter.logLint linter.style.dollarSyntax s + m!"Please use '<|' instead of '$' for the pipe operator." + +initialize addLinter dollarSyntaxLinter + +end Style.dollarSyntax + +/-! +# The `lambdaSyntax` linter + +The `lambdaSyntax` linter is a syntax linter that flags uses of the symbol `λ` to define anonymous +functions, as opposed to the `fun` keyword. These are syntactically equivalent; mathlib style +prefers the latter as it is considered more readable. +-/ + +/-- +The `lambdaSyntax` linter flags uses of the symbol `λ` to define anonymous functions. +This is syntactically equivalent to the `fun` keyword; mathlib style prefers using the latter. +-/ +register_option linter.style.lambdaSyntax : Bool := { + defValue := false + descr := "enable the `lambdaSyntax` linter" +} + +namespace Style.lambdaSyntax + +/-- +`findLambdaSyntax stx` extracts from `stx` all syntax nodes of `kind` `Term.fun`. -/ +partial +def findLambdaSyntax : Syntax → Array Syntax + | stx@(.node _ kind args) => + let dargs := (args.map findLambdaSyntax).flatten + match kind with + | ``Parser.Term.fun => dargs.push stx + | _ => dargs + |_ => #[] + +@[inherit_doc linter.style.lambdaSyntax] +def lambdaSyntaxLinter : Linter where run := withSetOptionIn fun stx ↦ do + unless Linter.getLinterValue linter.style.lambdaSyntax (← getOptions) do + return + if (← MonadState.get).messages.hasErrors then + return + for s in findLambdaSyntax stx do + if let .atom _ "λ" := s[0] then + Linter.logLint linter.style.lambdaSyntax s[0] m!"\ + Please use 'fun' and not 'λ' to define anonymous functions.\n\ + The 'λ' syntax is deprecated in mathlib4." + +initialize addLinter lambdaSyntaxLinter + +end Style.lambdaSyntax + +/-! +# The "longFile" linter + +The "longFile" linter emits a warning on files which are longer than a certain number of lines +(1500 by default). +-/ + +/-- +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). +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. +-/ +register_option linter.style.longFile : Nat := { + defValue := 0 + 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] +def longFileLinter : Linter where run := withSetOptionIn fun stx ↦ do + let linterBound := linter.style.longFile.get (← getOptions) + if linterBound == 0 then + return + let defValue := linter.style.longFileDefValue.get (← getOptions) + let smallOption := match stx with + | `(set_option linter.style.longFile $x) => TSyntax.getNat ⟨x.raw⟩ ≤ defValue + | _ => false + if smallOption then + logWarningAt stx <| .tagged linter.style.longFile.name + m!"The default value of the `longFile` linter is {defValue}.\n\ + The current value of {linterBound} does not exceed the allowed bound.\n\ + Please, remove the `set_option linter.style.longFile {linterBound}`." + else + -- Thanks to the above check, the linter option is either not set (and hence equal + -- to the default) or set to some value *larger* than the default. + -- `Parser.isTerminalCommand` allows `stx` to be `#exit`: this is useful for tests. + unless Parser.isTerminalCommand stx do return + -- We exclude `Mathlib.lean` from the linter: it exceeds linter's default number of allowed + -- lines, and it is an auto-generated import-only file. + -- TODO: if there are more such files, revise the implementation. + if (← getMainModule) == `Mathlib then return + 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 + if lastLine ≤ defValue && defValue < linterBound then + logWarningAt stx <| .tagged linter.style.longFile.name + m!"The default value of the `longFile` linter is {defValue}.\n\ + This file is {lastLine} lines long which does not exceed the allowed bound.\n\ + Please, remove the `set_option linter.style.longFile {linterBound}`." + else + -- `candidate` is divisible by `100` and satisfies `lastLine + 100 < candidate ≤ lastLine + 200` + -- note that either `lastLine ≤ defValue` and `defValue = linterBound` hold or + -- `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 + 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`." + +initialize addLinter longFileLinter + +end Style.longFile /-! # The "longLine linter" -/ /-- The "longLine" linter emits a warning on lines longer than 100 characters. We allow lines containing URLs to be longer, though. -/ -register_option linter.longLine : Bool := { - defValue := true +register_option linter.style.longLine : Bool := { + defValue := false descr := "enable the longLine linter" } -namespace LongLine +namespace Style.longLine -/-- Gets the value of the `linter.longLine` option. -/ -def getLinterHash (o : Options) : Bool := Linter.getLinterValue linter.longLine o - -@[inherit_doc Mathlib.Linter.linter.longLine] +@[inherit_doc Mathlib.Linter.linter.style.longLine] def longLineLinter : Linter where run := withSetOptionIn fun stx ↦ do - unless getLinterHash (← getOptions) do + unless Linter.getLinterValue linter.style.longLine (← getOptions) do return if (← MonadState.get).messages.hasErrors then return - -- TODO: once mathlib's Lean version includes leanprover/lean4#4741, make this configurable - unless #[`Mathlib, `test, `Archive, `Counterexamples].contains (← getMainModule).getRoot do - return -- The linter ignores the `#guard_msgs` command, in particular its doc-string. -- The linter still lints the message guarded by `#guard_msgs`. if stx.isOfKind ``Lean.guardMsgsCmd then @@ -256,15 +408,19 @@ def longLineLinter : Linter where run := withSetOptionIn fun stx ↦ do else return stx let sstr := stx.getSubstring? let fm ← getFileMap - let longLines := ((sstr.getD default).splitOn "\n").filter fun line => + let longLines := ((sstr.getD default).splitOn "\n").filter fun line ↦ (100 < (fm.toPosition line.stopPos).column) for line in longLines do - if !(line.containsSubstr "http") then - Linter.logLint linter.longLine (.ofRange ⟨line.startPos, line.stopPos⟩) - m!"This line exceeds the 100 character limit, please shorten it!" - + 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!{stringMsg}" initialize addLinter longLineLinter -end LongLine +end Style.longLine end Mathlib.Linter diff --git a/Mathlib/Tactic/Linter/MinImports.lean b/Mathlib/Tactic/Linter/MinImports.lean index 999aca9d8c390..202d32297ca82 100644 --- a/Mathlib/Tactic/Linter/MinImports.lean +++ b/Mathlib/Tactic/Linter/MinImports.lean @@ -53,19 +53,16 @@ namespace MinImports open Mathlib.Command.MinImports -/-- Gets the value of the `linter.minImports` option. -/ -def getLinterHash (o : Options) : Bool := Linter.getLinterValue linter.minImports o - @[inherit_doc Mathlib.Linter.linter.minImports] def minImportsLinter : Linter where run := withSetOptionIn fun stx => do - unless linter.minImports.get (← getOptions) do + unless Linter.getLinterValue linter.minImports (← getOptions) do return if (← MonadState.get).messages.hasErrors then return if stx == (← `(command| set_option $(mkIdent `linter.minImports) true)) then return let importsSoFar ← minImportsRef.get -- 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 + if #[``Parser.Command.eoi, ``Lean.Parser.Command.exit].contains stx.getKind then let explicitImportsInFile : NameSet := .fromArray (((← getEnv).imports.map (·.module)).erase `Init) Name.quickCmp let newImps := importsSoFar.diff explicitImportsInFile diff --git a/Mathlib/Tactic/Linter/OldObtain.lean b/Mathlib/Tactic/Linter/OldObtain.lean index 49f19a5a47846..0fd427c77bbfe 100644 --- a/Mathlib/Tactic/Linter/OldObtain.lean +++ b/Mathlib/Tactic/Linter/OldObtain.lean @@ -5,7 +5,6 @@ Authors: Michael Rothgang -/ import Lean.Elab.Command -import Lean.Linter.Util /-! # The `oldObtain` linter, against stream-of-conciousness `obtain` @@ -62,16 +61,13 @@ def is_obtain_without_proof : Syntax → Bool /-- The `oldObtain` linter emits a warning upon uses of the "stream-of-conciousness" variants of the `obtain` tactic, i.e. with the proof postponed. -/ register_option linter.oldObtain : Bool := { - defValue := true + defValue := false descr := "enable the `oldObtain` linter" } -/-- Gets the value of the `linter.oldObtain` option. -/ -def getLinterHash (o : Options) : Bool := Linter.getLinterValue linter.oldObtain o - /-- The `oldObtain` linter: see docstring above -/ def oldObtainLinter : Linter where run := withSetOptionIn fun stx => do - unless getLinterHash (← getOptions) do + unless Linter.getLinterValue linter.oldObtain (← getOptions) do return if (← MonadState.get).messages.hasErrors then return 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/RefineLinter.lean b/Mathlib/Tactic/Linter/RefineLinter.lean index d6cb739dbf88c..7bbc39eee11dc 100644 --- a/Mathlib/Tactic/Linter/RefineLinter.lean +++ b/Mathlib/Tactic/Linter/RefineLinter.lean @@ -3,8 +3,8 @@ 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 Lean.Linter.Util /-! # The "refine" linter @@ -20,11 +20,16 @@ This linter is an incentive to discourage uses of `refine'`, without being a ban open Lean Elab -namespace Mathlib.Linter.refine +namespace Mathlib.Linter + +/-- The "refine" linter flags usages of the `refine'` tactic. -/-- The refine linter emits a warning on usages of `refine'`. -/ +The tactics `refine` and `refine'` are similar, but they handle meta-variables slightly differently. +This means that they are not completely interchangeable, nor can one completely replace the other. +However, `refine` is more readable and (heuristically) tends to be more efficient on average. +-/ register_option linter.refine : Bool := { - defValue := true + defValue := false descr := "enable the refine linter" } @@ -36,17 +41,9 @@ def getRefine' : Syntax → Array Syntax if kind == ``Lean.Parser.Tactic.refine' then rargs.push stx else rargs | _ => default -/-- The "refine" linter flags usages of the `refine'` tactic. - -The tactics `refine` and `refine'` are similar, but they handle meta-variables slightly differently. -This means that they are not completely interchangeable, nor can one completely replace the other. -However, `refine` is more readable and (heuristically) tends to be more efficient on average. --/ -def getLinterHash (o : Options) : Bool := Linter.getLinterValue linter.refine o - -@[inherit_doc getLinterHash] +@[inherit_doc linter.refine] def refineLinter : Linter where run := withSetOptionIn fun _stx => do - unless getLinterHash (← getOptions) do + unless Linter.getLinterValue linter.refine (← getOptions) do return if (← MonadState.get).messages.hasErrors then return @@ -56,3 +53,5 @@ def refineLinter : Linter where run := withSetOptionIn fun _stx => do please strongly consider using `refine` or `apply` instead." initialize addLinter refineLinter + +end Mathlib.Linter diff --git a/Mathlib/Tactic/Linter/Style.lean b/Mathlib/Tactic/Linter/Style.lean index fbceb4a721f86..1f737feb7c3ef 100644 --- a/Mathlib/Tactic/Linter/Style.lean +++ b/Mathlib/Tactic/Linter/Style.lean @@ -5,7 +5,6 @@ Authors: Michael Rothgang -/ import Lean.Elab.Command -import Lean.Linter.Util /-! ## Style linters @@ -22,12 +21,12 @@ namespace Mathlib.Linter /-- The `setOption` linter emits a warning on a `set_option` command, term or tactic which sets a `pp`, `profiler` or `trace` option. -/ -register_option linter.setOption : Bool := { - defValue := true +register_option linter.style.setOption : Bool := { + defValue := false descr := "enable the `setOption` linter" } -namespace Style.SetOption +namespace Style.setOption /-- Whether a syntax element is a `set_option` command, tactic or term: Return the name of the option being set, if any. -/ @@ -42,9 +41,6 @@ def parse_set_option : Syntax → Option Name def is_set_option : Syntax → Bool := fun stx ↦ parse_set_option stx matches some _name -/-- Gets the value of the `linter.setOption` option. -/ -def getLinterHash (o : Options) : Bool := Linter.getLinterValue linter.setOption o - /-- The `setOption` linter: this lints any `set_option` command, term or tactic which sets a `pp`, `profiler` or `trace` option. @@ -54,18 +50,15 @@ used in production code. (Some tests will intentionally use one of these options; in this case, simply allow the linter.) -/ def setOptionLinter : Linter where run := withSetOptionIn fun stx => do - unless getLinterHash (← getOptions) do + unless Linter.getLinterValue linter.style.setOption (← getOptions) do return if (← MonadState.get).messages.hasErrors then return - -- TODO: once mathlib's Lean version includes leanprover/lean4#4741, make this configurable - unless #[`Mathlib, `test, `Archive, `Counterexamples].contains (← getMainModule).getRoot do - return if let some head := stx.find? is_set_option then if let some name := parse_set_option head then let forbidden := [`debug, `pp, `profiler, `trace] if forbidden.contains name.getRoot then - Linter.logLint linter.setOption head + Linter.logLint linter.style.setOption head m!"Setting options starting with '{"', '".intercalate (forbidden.map (·.toString))}' \ is only intended for development and not for final code. \ If you intend to submit this contribution to the Mathlib project, \ @@ -73,6 +66,6 @@ def setOptionLinter : Linter where run := withSetOptionIn fun stx => do initialize addLinter setOptionLinter -end Style.SetOption +end Style.setOption end Mathlib.Linter diff --git a/Mathlib/Tactic/Linter/TextBased.lean b/Mathlib/Tactic/Linter/TextBased.lean index 38204f9292cc3..b4556c694d081 100644 --- a/Mathlib/Tactic/Linter/TextBased.lean +++ b/Mathlib/Tactic/Linter/TextBased.lean @@ -6,22 +6,40 @@ Authors: Michael Rothgang import Batteries.Data.String.Matcher import Mathlib.Data.Nat.Notation +import Std.Data.HashMap.Basic /-! ## Text-based linters This file defines various mathlib linters which are based on reading the source code only. -In practice, only style linters will have this form. -All of these have been rewritten from the `lint-style.py` script. +In practice, all such linters check for code style issues. -For now, this only contains the linters for the copyright and author headers and large files: -further linters will be ported in subsequent PRs. +For now, this only contains linters checking +- that the copyright header and authors line are correctly formatted +- existence of module docstrings (in the right place) +- for certain disallowed imports +- if the string "adaptation note" is used instead of the command #adaptation_note +- files are at most 1500 lines long (unless specifically allowed). + +For historic reasons, some of these checks are still written in a Python script `lint-style.py`: +these are gradually being rewritten in Lean. + +This linter maintains a list of exceptions, for legacy reasons. +Ideally, the length of the list of exceptions tends to 0. + +The `longFile` and the `longLine` *syntax* linter take care of flagging lines that exceed the +100 character limit and files that exceed the 1500 line limit. +The text-based versions of this file are still used for the files where the linter is not imported. +This means that the exceptions for the text-based linters are shorter, as they do not need to +include those handled with `set_option linter.style.longFile x`/`set_option linter.longLine false`. An executable running all these linters is defined in `scripts/lint-style.lean`. -/ open System +namespace Mathlib.Linter.TextBased + /-- Different kinds of "broad imports" that are linted against. -/ inductive BroadImports /-- Importing the entire "Mathlib.Tactic" folder -/ @@ -45,13 +63,9 @@ inductive StyleError where /-- Lint against "too broad" imports, such as `Mathlib.Tactic` or any module in `Lake` (unless carefully measured) -/ | broadImport (module : BroadImports) - /-- Line longer than 100 characters -/ - | lineLength (actual : Int) : StyleError - /-- The current file was too large: this error contains the current number of lines - as well as a size limit (slightly larger). On future runs, this linter will allow this file - to grow up to this limit. - For diagnostic purposes, this may also contain a previous size limit, which is now exceeded. -/ - | fileTooLong (numberLines : ℕ) (newSizeLimit : ℕ) (previousLimit : Option ℕ) : StyleError + /-- 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 -/ @@ -67,7 +81,7 @@ inductive ErrorFormat deriving BEq /-- Create the underlying error message for a given `StyleError`. -/ -def StyleError.errorMessage (err : StyleError) (style : ErrorFormat) : String := match err with +def StyleError.errorMessage (err : StyleError) : String := match err with | StyleError.copyright (some context) => s!"Malformed or missing copyright header: {context}" | StyleError.copyright none => "Malformed or missing copyright header" | StyleError.authors => @@ -80,17 +94,10 @@ def StyleError.errorMessage (err : StyleError) (style : ErrorFormat) : String := "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." - | StyleError.lineLength n => s!"Line has {n} characters, which is more than 100" - | StyleError.fileTooLong currentSize sizeLimit previousLimit => - match style with - | ErrorFormat.github => - if let some n := previousLimit then - s!"file contains {currentSize} lines (at most {n} allowed), try to split it up" - else - s!"file contains {currentSize} lines, try to split it up" - | ErrorFormat.exceptionsFile => - s!"{sizeLimit} file contains {currentSize} lines, try to split it up" - | ErrorFormat.humanReadable => s!"file contains {currentSize} lines, try to split it up" + | 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; @@ -100,8 +107,8 @@ def StyleError.errorCode (err : StyleError) : String := match err with | StyleError.authors => "ERR_AUT" | StyleError.adaptationNote => "ERR_ADN" | StyleError.broadImport _ => "ERR_IMP" - | StyleError.lineLength _ => "ERR_LIN" - | StyleError.fileTooLong _ _ _ => "ERR_NUM_LIN" + | 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. -/ @@ -131,27 +138,17 @@ inductive ComparisonResult and, if it is, if we prefer replacing the new exception or keeping the previous one. -/ def compare (existing new : ErrorContext) : ComparisonResult := -- Two comparable error contexts must have the same path. - if existing.path != new.path then - ComparisonResult.Different + -- To avoid issues with different path separators across different operating systems, + -- we compare the set of path components instead. + if existing.path.components != new.path.components then ComparisonResult.Different -- We entirely ignore their line numbers: not sure if this is best. -- NB: keep the following in sync with `parse?_errorContext` below. -- Generally, comparable errors must have equal `StyleError`s, but there are some exceptions. else match (existing.error, new.error) with - -- File length errors are the biggest exceptions: generally, we prefer to keep the - -- existing entry, *except* when a newer entry is much shorter. - | (StyleError.fileTooLong n nLimit _, StyleError.fileTooLong m _mLimit _) => - -- The only exception are "file too long" errors. - -- If a file got much longer, the existing exception does not apply; - if m > nLimit then ComparisonResult.Different - -- if it does apply, we prefer to keep the existing entry, - -- *unless* the newer entry is much shorter. - else if m + 200 <= n then ComparisonResult.Comparable false - else ComparisonResult.Comparable true -- We do *not* care about the *kind* of wrong copyright, -- nor about the particular length of a too long line. | (StyleError.copyright _, StyleError.copyright _) => ComparisonResult.Comparable true - | (StyleError.lineLength _, StyleError.lineLength _) => ComparisonResult.Comparable true -- In all other cases, `StyleErrors` must compare equal. | (a, b) => if a == b then ComparisonResult.Comparable true else ComparisonResult.Different @@ -164,7 +161,7 @@ def ErrorContext.find?_comparable (e : ErrorContext) (exceptions : Array ErrorCo `style` specifies if the error should be formatted for humans to read, github problem matchers to consume, or for the style exceptions file. -/ def outputMessage (errctx : ErrorContext) (style : ErrorFormat) : String := - let errorMessage := errctx.error.errorMessage style + let errorMessage := errctx.error.errorMessage match style with | ErrorFormat.github => -- We are outputting for github: duplicate file path, line number and error code, @@ -195,29 +192,16 @@ def parse?_errorContext (line : String) : Option ErrorContext := Id.run do -- Use default values for parameters which are ignored for comparing style exceptions. -- NB: keep this in sync with `compare` above! | "ERR_COP" => some (StyleError.copyright none) - | "ERR_LIN" => - if let some n := errorMessage.get? 2 then - match String.toNat? n with - | some n => return StyleError.lineLength n - | none => none - else none | "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 some (StyleError.broadImport BroadImports.TacticFolder) else some (StyleError.broadImport BroadImports.Lake) - | "ERR_NUM_LIN" => - -- Parse the error message in the script. `none` indicates invalid input. - match (errorMessage.get? 0, errorMessage.get? 3) with - | (some limit, some current) => - match (String.toNat? limit, String.toNat? current) with - | (some sizeLimit, some currentSize) => - some (StyleError.fileTooLong currentSize sizeLimit (some sizeLimit)) - | _ => none - | _ => none | _ => none match String.toNat? lineNumber with | some n => err.map fun e ↦ (ErrorContext.mk e n path) @@ -241,8 +225,11 @@ def formatErrors (errors : Array ErrorContext) (style : ErrorFormat) : IO Unit : IO.println (outputMessage e style) /-- Core logic of a text based linter: given a collection of lines, -return an array of all style errors with line numbers. -/ -abbrev TextbasedLinter := Array String → Array (StyleError × ℕ) +return an array of all style errors with line numbers. If possible, +also return the collection of all lines, changed as needed to fix the linter errors. +(Such automatic fixes are only possible for some kinds of `StyleError`s.) +-/ +abbrev TextbasedLinter := Array String → Array (StyleError × ℕ) × (Option (Array String)) /-! Definitions of the actual text-based linters. -/ section @@ -291,7 +278,7 @@ def copyrightHeaderLinter : TextbasedLinter := fun lines ↦ Id.run do -- If it does, we check the authors line is formatted correctly. if !isCorrectAuthorsLine line then output := output.push (StyleError.authors, 4) - return output + return (output, none) /-- Lint on any occurrences of the string "Adaptation note:" or variants thereof. -/ def adaptationNoteLinter : TextbasedLinter := fun lines ↦ Id.run do @@ -302,7 +289,27 @@ def adaptationNoteLinter : TextbasedLinter := fun lines ↦ Id.run do if line.containsSubstr "daptation note" then errors := errors.push (StyleError.adaptationNote, lineNumber) lineNumber := lineNumber + 1 - return errors + 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 @@ -330,17 +337,8 @@ def broadImportsLinter : TextbasedLinter := fun lines ↦ Id.run do else if name == "Lake" || name.startsWith "Lake." then errors := errors.push (StyleError.broadImport BroadImports.Lake, lineNumber) lineNumber := lineNumber + 1 - return errors + return (errors, none) -/-- Iterates over a collection of strings, finding all lines which are longer than 101 chars. -We allow URLs to be longer, though. --/ -def lineLengthLinter : TextbasedLinter := fun lines ↦ Id.run do - let errors := (lines.toList.enumFrom 1).filterMap (fun (lineNumber, line) ↦ - if line.length > 101 && !line.containsSubstr "http" then - some (StyleError.lineLength line.length, lineNumber) - else none) - errors.toArray /-- Whether a collection of lines consists *only* of imports, blank lines and single-line comments. In practice, this means it's an imports-only file and exempt from almost all linting. -/ @@ -349,115 +347,94 @@ def isImportsOnlyFile (lines : Array String) : Bool := -- this is in fact not necessary. (It is needed for `Tactic/Linter.lean`, though.) lines.all (fun line ↦ line.startsWith "import " || line == "" || line.startsWith "-- ") -/-- Error if a collection of lines is too large. "Too large" means more than 1500 lines -**and** longer than an optional previous limit. -If the file is too large, return a matching `StyleError`, which includes a new size limit -(which is somewhat larger than the current size). -/ -def checkFileLength (lines : Array String) (existingLimit : Option ℕ) : Option StyleError := - Id.run do - if lines.size > 1500 then - let isLarger : Bool := match existingLimit with - | some mark => lines.size > mark - | none => true - if isLarger then - -- We add about 200 lines of slack to the current file size: small PRs will be unaffected, - -- but sufficiently large PRs will get nudged towards splitting up this file. - return some (StyleError.fileTooLong lines.size - ((Nat.div lines.size 100) * 100 + 200) existingLimit) - none - end /-- All text-based linters registered in this file. -/ def allLinters : Array TextbasedLinter := #[ - copyrightHeaderLinter, adaptationNoteLinter, broadImportsLinter, lineLengthLinter + copyrightHeaderLinter, adaptationNoteLinter, broadImportsLinter, duplicateImportsLinter ] -/-- Controls what kind of output this programme produces. -/ -inductive OutputSetting : Type - /-- Print any style error to standard output (the default) -/ - | print (style : ErrorFormat) - /-- Update the style exceptions file (and still print style errors to standard output). - This adds entries for any new exceptions, removes any entries which are no longer necessary, - and tries to not modify exception entries unless necessary. - To fully regenerate the exceptions file, delete `style-exceptions.txt` and run again in this mode. - -/ - | update - deriving BEq -/-- Read a file and apply all text-based linters. Return a list of all unexpected errors. -`sizeLimit` is any pre-existing limit on this file's size. -`exceptions` are any other style exceptions. -/ -def lintFile (path : FilePath) (sizeLimit : Option ℕ) (exceptions : Array ErrorContext) : - IO (Array ErrorContext) := do - let lines ← IO.FS.lines path - -- We don't need to run any checks on imports-only files. - -- NB. The Python script used to still run a few linters; this is in fact not necessary. - if isImportsOnlyFile lines then - return #[] +/-- Read a file and apply all text-based linters. +Return a list of all unexpected errors, and, if some errors could be fixed automatically, +the collection of all lines with every automatic fix applied. +`exceptions` are any pre-existing style exceptions for this file. -/ +def lintFile (path : FilePath) (exceptions : Array ErrorContext) : + IO (Array ErrorContext × Option (Array String)) := do let mut errors := #[] - if let some (StyleError.fileTooLong n limit ex) := checkFileLength lines sizeLimit then - errors := #[ErrorContext.mk (StyleError.fileTooLong n limit ex) 1 path] - let allOutput := (Array.map (fun lint ↦ - (Array.map (fun (e, n) ↦ ErrorContext.mk e n path)) (lint lines))) allLinters - -- This this list is not sorted: for github, this is fine. - errors := errors.append (allOutput.flatten.filter (fun e ↦ (e.find?_comparable exceptions).isNone)) - return errors + -- Whether any changes were made by auto-fixes. + let mut changes_made := false + -- Check for windows line endings first: as `FS.lines` treats Unix and Windows lines the same, + -- we need to analyse the actual file contents. + let contents ← IO.FS.readFile path + let replaced := contents.crlfToLf + if replaced != contents then + changes_made := true + errors := errors.push (ErrorContext.mk StyleError.windowsLineEnding 1 path) + let lines := (replaced.splitOn "\n").toArray + + -- We don't need to run any further checks on imports-only files. + if isImportsOnlyFile lines then + return (errors, if changes_made then some lines else none) + + -- All further style errors raised in this file. + let mut allOutput := #[] + -- A working copy of the lines in this file, modified by applying the auto-fixes. + let mut changed := lines + + for lint in allLinters do + let (err, changes) := lint changed + allOutput := allOutput.append (Array.map (fun (e, n) ↦ #[(ErrorContext.mk e n path)]) err) + if let some c := changes then + changed := c + changes_made := true + -- This list is not sorted: for github, this is fine. + errors := errors.append + (allOutput.flatten.filter (fun e ↦ (e.find?_comparable exceptions).isNone)) + return (errors, if changes_made then some changed else none) + /-- Lint a collection of modules for style violations. Print formatted errors for all unexpected style violations to standard output; -update the list of style exceptions if configured so. +correct automatically fixable style errors if configured so. Return the number of files which had new style errors. `moduleNames` are all the modules to lint, -`mode` specifies what kind of output this script should produce. -/ -def lintModules (moduleNames : Array String) (mode : OutputSetting) : IO UInt32 := do - -- Read the style exceptions file. - -- We also have a `nolints` file with manual exceptions for the linter. - let exceptionsFilePath : FilePath := "scripts" / "style-exceptions.txt" - let exceptions ← IO.FS.lines exceptionsFilePath - let mut styleExceptions := parseStyleExceptions exceptions +`mode` specifies what kind of output this script should produce, +`fix` configures whether fixable errors should be corrected in-place. -/ +def lintModules (moduleNames : Array String) (style : ErrorFormat) (fix : Bool) : IO UInt32 := do + -- Read the `nolints` file, with manual exceptions for the linter. let nolints ← IO.FS.lines ("scripts" / "nolints-style.txt") - styleExceptions := styleExceptions.append (parseStyleExceptions nolints) + let styleExceptions := parseStyleExceptions nolints let mut numberErrorFiles : UInt32 := 0 let mut allUnexpectedErrors := #[] for module in moduleNames do -- Convert the module name to a file name, then lint that file. let path := (mkFilePath (module.split (· == '.'))).addExtension "lean" - -- Find all size limits for this given file. - -- If several size limits are given (unlikely in practice), we use the first one. - let sizeLimits := (styleExceptions.filter (fun ex ↦ ex.path == path)).filterMap (fun errctx ↦ - match errctx.error with - | StyleError.fileTooLong _ limit _ => some limit - | _ => none) - let errors := - if let OutputSetting.print _ := mode then - ← lintFile path (sizeLimits.get? 0) styleExceptions - else - -- In "update" mode, we ignore the exceptions file (and only take `nolints` into account). - ← lintFile path none (parseStyleExceptions nolints) + + let (errors, changed) := ← lintFile path styleExceptions + if let some c := changed then + if fix then + let _ := ← IO.FS.writeFile path ("\n".intercalate c.toList) if errors.size > 0 then allUnexpectedErrors := allUnexpectedErrors.append errors numberErrorFiles := numberErrorFiles + 1 - match mode with - | OutputSetting.print style => - formatErrors allUnexpectedErrors style - if numberErrorFiles > 0 && mode matches OutputSetting.print _ then - IO.println s!"error: found {allUnexpectedErrors.size} new style errors\n\ - run `lake exe lint-style --update` to ignore all of them" - | OutputSetting.update => - formatErrors allUnexpectedErrors ErrorFormat.humanReadable - -- Regenerate the style exceptions file, including the Python output. - IO.FS.writeFile exceptionsFilePath "" - let pythonOutput ← IO.Process.run { cmd := "./scripts/print-style-errors.sh" } - -- Combine style exception entries: for each new error, replace by a corresponding - -- previous exception if that is preferred. - let mut tweaked := allUnexpectedErrors.map fun err ↦ - if let some existing := err.find?_comparable styleExceptions then - if let ComparisonResult.Comparable (true) := _root_.compare err existing then existing - else err - else err - let thisOutput := "\n".intercalate (tweaked.map - (fun err ↦ outputMessage err ErrorFormat.exceptionsFile)).toList - IO.FS.writeFile exceptionsFilePath s!"{pythonOutput}{thisOutput}\n" + + -- Run the remaining python linters. It is easier to just run on all files. + -- 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 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.eprint output.stdout + formatErrors allUnexpectedErrors style + if allUnexpectedErrors.size > 0 then + 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 425cdc0023e0e..67eb1b34f7d9f 100644 --- a/Mathlib/Tactic/Linter/UnusedTactic.lean +++ b/Mathlib/Tactic/Linter/UnusedTactic.lean @@ -3,8 +3,8 @@ 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 Lean.Linter.Util import Batteries.Tactic.Unreachable /-! @@ -50,7 +50,7 @@ before and after and see if there is some change. Yet another linter copied from the `unreachableTactic` linter! -/ -open Lean Elab +open Lean Elab Std namespace Mathlib.Linter @@ -63,13 +63,13 @@ register_option linter.unusedTactic : Bool := { namespace UnusedTactic /-- The monad for collecting the ranges of the syntaxes that do not modify any goal. -/ -abbrev M := StateRefT (HashMap String.Range Syntax) IO +abbrev M := StateRefT (Std.HashMap String.Range Syntax) IO /-- `Parser`s allowed to not change the tactic state. This can be increased dynamically, using `#allow_unused_tactic`. -/ -initialize allowedRef : IO.Ref (HashSet SyntaxNodeKind) ← - IO.mkRef <| HashSet.empty +initialize allowedRef : IO.Ref (Std.HashSet SyntaxNodeKind) ← + IO.mkRef <| Std.HashSet.empty |>.insert `Mathlib.Tactic.Says.says |>.insert `Batteries.Tactic.«tacticOn_goal-_=>_» -- attempt to speed up, by ignoring more tactics @@ -92,6 +92,7 @@ initialize allowedRef : IO.Ref (HashSet SyntaxNodeKind) ← |>.insert `Mathlib.Tactic.tacticMatch_target_ |>.insert `change? |>.insert `«tactic#adaptation_note_» + |>.insert `tacticSleep_heartbeats_ /-- `#allow_unused_tactic` takes an input a space-separated list of identifiers. These identifiers are then allowed by the unused tactic linter: @@ -113,7 +114,7 @@ A list of blacklisted syntax kinds, which are expected to have subterms that con unevaluated tactics. -/ initialize ignoreTacticKindsRef : IO.Ref NameHashSet ← - IO.mkRef <| HashSet.empty + IO.mkRef <| Std.HashSet.empty |>.insert `Mathlib.Tactic.Says.says |>.insert ``Parser.Term.binderTactic |>.insert ``Lean.Parser.Term.dynamicQuot @@ -126,6 +127,7 @@ initialize ignoreTacticKindsRef : IO.Ref NameHashSet ← |>.insert `Batteries.Tactic.seq_focus |>.insert `Mathlib.Tactic.Hint.registerHintStx |>.insert `Mathlib.Tactic.LinearCombination.linearCombination + |>.insert `Mathlib.Tactic.LinearCombination'.linearCombination' -- the following `SyntaxNodeKind`s play a role in silencing `test`s |>.insert ``Lean.Parser.Tactic.failIfSuccess |>.insert `Mathlib.Tactic.successIfFailWithMsg @@ -196,12 +198,9 @@ partial def eraseUsedTactics : InfoTree → M Unit end -/-- Gets the value of the `linter.unusedTactic` option. -/ -def getLinterHash (o : Options) : Bool := Linter.getLinterValue linter.unusedTactic o - /-- The main entry point to the unused tactic linter. -/ def unusedTacticLinter : Linter where run := withSetOptionIn fun stx => do - unless getLinterHash (← getOptions) && (← getInfoState).enabled do + unless Linter.getLinterValue linter.unusedTactic (← getOptions) && (← getInfoState).enabled do return if (← get).messages.hasErrors then return @@ -220,7 +219,7 @@ def unusedTacticLinter : Linter where run := withSetOptionIn fun stx => do let key (r : String.Range) := (r.start.byteIdx, (-r.stop.byteIdx : Int)) let mut last : String.Range := ⟨0, 0⟩ for (r, stx) in let _ := @lexOrd; let _ := @ltOfOrd.{0}; unused.qsort (key ·.1 < key ·.1) do - if stx.getKind ∈ [``Batteries.Tactic.unreachable, ``Batteries.Tactic.unreachableConv] then + if stx.getKind ∈ [`Batteries.Tactic.unreachable, `Batteries.Tactic.unreachableConv] then continue if last.start ≤ r.start && r.stop ≤ last.stop then continue Linter.logLint linter.unusedTactic stx m!"'{stx}' tactic does nothing" diff --git a/Mathlib/Tactic/Measurability/Init.lean b/Mathlib/Tactic/Measurability/Init.lean index 0821e564490e1..8d4de6f8f88c6 100644 --- a/Mathlib/Tactic/Measurability/Init.lean +++ b/Mathlib/Tactic/Measurability/Init.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Miyahara Kō -/ +import Mathlib.Init import Aesop /-! diff --git a/Mathlib/Tactic/MinImports.lean b/Mathlib/Tactic/MinImports.lean index f1419676d8a07..f079b40e3b93d 100644 --- a/Mathlib/Tactic/MinImports.lean +++ b/Mathlib/Tactic/MinImports.lean @@ -3,6 +3,7 @@ Copyright (c) 2024 Damiano Testa. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Damiano Testa -/ +import Mathlib.Init import ImportGraph.Imports /-! # `#min_imports in` a command to find minimal imports @@ -159,7 +160,7 @@ def getAllImports (cmd id : Syntax) (dbg? : Bool := false) : |>.append (getSyntaxNodeKinds cmd) |>.append (getAttrs env cmd) if dbg? then dbg_trace "{ts.toArray.qsort Name.lt}" - let mut hm : HashMap Nat Name := {} + let mut hm : Std.HashMap Nat Name := {} for imp in env.header.moduleNames do hm := hm.insert ((env.getModuleIdx? imp).getD default) imp let mut fins : NameSet := {} @@ -167,7 +168,7 @@ def getAllImports (cmd id : Syntax) (dbg? : Bool := false) : let tns := t1::(← resolveGlobalName t1).map Prod.fst for t in tns do let new := match env.getModuleIdxFor? t with - | some t => (hm.find? t).get! + | some t => (hm.get? t).get! | none => .anonymous -- instead of `getMainModule`, we omit the current module if !fins.contains new then fins := fins.insert new return fins.erase .anonymous diff --git a/Mathlib/Tactic/MkIffOfInductiveProp.lean b/Mathlib/Tactic/MkIffOfInductiveProp.lean index baf6206f73b80..151383da0f1f0 100644 --- a/Mathlib/Tactic/MkIffOfInductiveProp.lean +++ b/Mathlib/Tactic/MkIffOfInductiveProp.lean @@ -411,3 +411,5 @@ initialize Lean.registerBuiltinAttribute { | _ => throwError "unrecognized syntax" mkIffOfInductivePropImpl decl tgt idStx } + +end Mathlib.Tactic.MkIff diff --git a/Mathlib/Tactic/ModCases.lean b/Mathlib/Tactic/ModCases.lean index 760aaf8275f0b..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 @@ -191,8 +192,4 @@ elab_rules : tactic | ~q(ℕ) => NatMod.modCases h e n | _ => throwError "mod_cases only works with Int and Nat" -end ModCases - -end Tactic - -end Mathlib +end Mathlib.Tactic.ModCases 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/Monotonicity/Attr.lean b/Mathlib/Tactic/Monotonicity/Attr.lean index f42c19899eb0b..ce61e3c78dcda 100644 --- a/Mathlib/Tactic/Monotonicity/Attr.lean +++ b/Mathlib/Tactic/Monotonicity/Attr.lean @@ -3,6 +3,7 @@ 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.Init import Lean.LabelAttribute /-! # The @[mono] attribute -/ @@ -29,3 +30,9 @@ initialize ext : LabelExtension ← ( relations on its domain and range, and possibly with side conditions." let mono := `mono registerLabelAttr mono descr mono) + +end Attr + +end Monotonicity + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Monotonicity/Basic.lean b/Mathlib/Tactic/Monotonicity/Basic.lean index 0b0ba3b09f108..c7c981caabe3c 100644 --- a/Mathlib/Tactic/Monotonicity/Basic.lean +++ b/Mathlib/Tactic/Monotonicity/Basic.lean @@ -53,3 +53,7 @@ elab_rules : tactic transparency := .reducible exfalso := false } liftMetaTactic fun g => do processSyntax cfg false false [] [] #[mkIdent `mono] [g] + +end Monotonicity + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Monotonicity/Lemmas.lean b/Mathlib/Tactic/Monotonicity/Lemmas.lean index 3ad48a50d8db3..a0ad5266eac62 100644 --- a/Mathlib/Tactic/Monotonicity/Lemmas.lean +++ b/Mathlib/Tactic/Monotonicity/Lemmas.lean @@ -5,7 +5,7 @@ Authors: Simon Hudon -/ import Mathlib.Algebra.Order.Group.Abs import Mathlib.Algebra.Order.Ring.Defs -import Mathlib.Algebra.Order.Sub.Canonical +import Mathlib.Algebra.Order.Sub.Unbundled.Basic import Mathlib.Data.Set.Lattice import Mathlib.Tactic.Monotonicity.Attr diff --git a/Mathlib/Tactic/MoveAdd.lean b/Mathlib/Tactic/MoveAdd.lean index 0e14071ab836d..094ce46b60265 100644 --- a/Mathlib/Tactic/MoveAdd.lean +++ b/Mathlib/Tactic/MoveAdd.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Arthur Paulino, Damiano Testa -/ import Mathlib.Algebra.Group.Basic -import Mathlib.Init.Order.LinearOrder /-! @@ -459,3 +458,7 @@ elab "move_mul" rws:rwRuleSeq : tactic => do evalTactic (← `(tactic| move_oper $hmul $rws)) end parsing + +end MoveAdd + +end Mathlib 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/Nontriviality/Core.lean b/Mathlib/Tactic/Nontriviality/Core.lean index b3f566a5629c5..2f6edcb097560 100644 --- a/Mathlib/Tactic/Nontriviality/Core.lean +++ b/Mathlib/Tactic/Nontriviality/Core.lean @@ -123,3 +123,7 @@ syntax (name := nontriviality) "nontriviality" (ppSpace colGt term)? g.assert `inst ty m let g ← liftM <| tac <|> nontrivialityByElim α g stx[2][1].getSepArgs replaceMainGoal [(← g.intro1).2] + +end Nontriviality + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/NormNum/Basic.lean b/Mathlib/Tactic/NormNum/Basic.lean index 5ab1887c9a653..f2921c511d2d3 100644 --- a/Mathlib/Tactic/NormNum/Basic.lean +++ b/Mathlib/Tactic/NormNum/Basic.lean @@ -196,11 +196,11 @@ theorem isRat_add {α} [Ring α] {f : α → α → α} {a b : α} {na nb nc : have H := (Nat.cast_commute (α := α) da db).invOf_left.invOf_right.right_comm have h₁ := congr_arg (↑· * (⅟↑da * ⅟↑db : α)) h₁ simp only [Int.cast_add, Int.cast_mul, Int.cast_natCast, ← mul_assoc, - add_mul, mul_mul_invOf_self_cancel] at h₁ + add_mul, mul_invOf_cancel_right] at h₁ have h₂ := congr_arg (↑nc * ↑· * (⅟↑da * ⅟↑db * ⅟↑dc : α)) h₂ - simp only [H, mul_mul_invOf_self_cancel', Nat.cast_mul, ← mul_assoc] at h₁ h₂ + simp only [H, mul_invOf_cancel_right', Nat.cast_mul, ← mul_assoc] at h₁ h₂ rw [h₁, h₂, Nat.cast_commute] - simp only [mul_mul_invOf_self_cancel, + simp only [mul_invOf_cancel_right, (Nat.cast_commute (α := α) da dc).invOf_left.invOf_right.right_comm, (Nat.cast_commute (α := α) db dc).invOf_left.invOf_right.right_comm] @@ -382,8 +382,8 @@ theorem isRat_mul {α} [Ring α] {f : α → α → α} {a b : α} {na nb nc : simp only [← mul_assoc, (Nat.cast_commute (α := α) da nb).invOf_left.right_comm, h₁] have h₂ := congr_arg (↑nc * ↑· * (⅟↑da * ⅟↑db * ⅟↑dc : α)) h₂ simp only [Nat.cast_mul, ← mul_assoc] at h₂; rw [H] at h₂ - simp only [mul_mul_invOf_self_cancel'] at h₂; rw [h₂, Nat.cast_commute] - simp only [mul_mul_invOf_self_cancel, + simp only [mul_invOf_cancel_right'] at h₂; rw [h₂, Nat.cast_commute] + simp only [mul_invOf_cancel_right, (Nat.cast_commute (α := α) da dc).invOf_left.invOf_right.right_comm, (Nat.cast_commute (α := α) db dc).invOf_left.invOf_right.right_comm] diff --git a/Mathlib/Tactic/NormNum/Core.lean b/Mathlib/Tactic/NormNum/Core.lean index 505eaca4e984f..2c3834acb555f 100644 --- a/Mathlib/Tactic/NormNum/Core.lean +++ b/Mathlib/Tactic/NormNum/Core.lean @@ -357,3 +357,5 @@ Unlike `norm_num`, this command does not fail when no simplifications are made. macro (name := normNumCmd) "#norm_num" cfg:(config)? o:(&" only")? args:(Parser.Tactic.simpArgs)? " :"? ppSpace e:term : command => `(command| #conv norm_num $(cfg)? $[only%$o]? $(args)? => $e) + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/NormNum/DivMod.lean b/Mathlib/Tactic/NormNum/DivMod.lean index 3037be0ca7da7..821532050c549 100644 --- a/Mathlib/Tactic/NormNum/DivMod.lean +++ b/Mathlib/Tactic/NormNum/DivMod.lean @@ -147,8 +147,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 +167,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/Ineq.lean b/Mathlib/Tactic/NormNum/Ineq.lean index 3a6b3579bea01..9c5a20797bcc2 100644 --- a/Mathlib/Tactic/NormNum/Ineq.lean +++ b/Mathlib/Tactic/NormNum/Ineq.lean @@ -62,7 +62,7 @@ theorem isRat_lt_true [LinearOrderedRing α] [Nontrivial α] : {a b : α} → {n have hb : 0 < ⅟(db : α) := pos_invOf_of_invertible_cast db have h := (mul_lt_mul_of_pos_left · hb) <| mul_lt_mul_of_pos_right h ha rw [← mul_assoc, Int.commute_cast] at h - simp? at h says simp only [Int.cast_mul, Int.cast_natCast, mul_mul_invOf_self_cancel'] at h + simp? at h says simp only [Int.cast_mul, Int.cast_natCast, mul_invOf_cancel_right'] at h rwa [Int.commute_cast] at h theorem isRat_le_false [LinearOrderedRing α] [Nontrivial α] {a b : α} {na nb : ℤ} {da db : ℕ} @@ -108,12 +108,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 +134,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 +153,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 +172,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 +201,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 +218,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/Prime.lean b/Mathlib/Tactic/NormNum/Prime.lean index 015e44548304d..4f9a95a5d7158 100644 --- a/Mathlib/Tactic/NormNum/Prime.lean +++ b/Mathlib/Tactic/NormNum/Prime.lean @@ -57,7 +57,7 @@ theorem minFacHelper_0 (n : ℕ) (h1 : Nat.ble (nat_lit 2) n = true) (h2 : nat_lit 1 = n % (nat_lit 2)) : MinFacHelper n (nat_lit 3) := by refine ⟨by norm_num, by norm_num, ?_⟩ - refine (le_minFac'.mpr λ p hp hpn ↦ ?_).resolve_left (Nat.ne_of_gt (Nat.le_of_ble_eq_true h1)) + refine (le_minFac'.mpr fun p hp hpn ↦ ?_).resolve_left (Nat.ne_of_gt (Nat.le_of_ble_eq_true h1)) rcases hp.eq_or_lt with rfl|h · simp [(Nat.dvd_iff_mod_eq_zero ..).1 hpn] at h2 · exact h @@ -81,13 +81,13 @@ theorem minFacHelper_1 {n k k' : ℕ} (e : k + 2 = k') (h : MinFacHelper n k) theorem minFacHelper_2 {n k k' : ℕ} (e : k + 2 = k') (nk : ¬ Nat.Prime k) (h : MinFacHelper n k) : MinFacHelper n k' := by - refine minFacHelper_1 e h λ h2 ↦ ?_ + refine minFacHelper_1 e h fun h2 ↦ ?_ rw [← h2] at nk exact nk <| minFac_prime h.one_lt.ne' theorem minFacHelper_3 {n k k' : ℕ} (e : k + 2 = k') (nk : (n % k).beq 0 = false) (h : MinFacHelper n k) : MinFacHelper n k' := by - refine minFacHelper_1 e h λ h2 ↦ ?_ + refine minFacHelper_1 e h fun h2 ↦ ?_ have nk := Nat.ne_of_beq_eq_false nk rw [← Nat.dvd_iff_mod_eq_zero, ← h2] at nk exact nk <| minFac_dvd n @@ -109,7 +109,7 @@ theorem isNat_minFac_4 : {n n' k : ℕ} → | n, _, k, ⟨rfl⟩, h1, h2 => by refine ⟨(Nat.prime_def_minFac.mp ?_).2⟩ rw [Nat.prime_def_le_sqrt] - refine ⟨h1.one_lt, λ m hm hmn h2mn ↦ ?_⟩ + refine ⟨h1.one_lt, fun m hm hmn h2mn ↦ ?_⟩ exact lt_irrefl m <| calc m ≤ sqrt n := hmn _ < k := sqrt_lt.mpr (ble_eq_false.mp h2) diff --git a/Mathlib/Tactic/NormNum/Result.lean b/Mathlib/Tactic/NormNum/Result.lean index 2edf11a135ca5..a8a58dcf2cb7a 100644 --- a/Mathlib/Tactic/NormNum/Result.lean +++ b/Mathlib/Tactic/NormNum/Result.lean @@ -238,7 +238,7 @@ theorem IsRat.of_raw (α) [DivisionRing α] (n : ℤ) (d : ℕ) ⟨this, by simp [div_eq_mul_inv]⟩ theorem IsRat.den_nz {α} [DivisionRing α] {a n d} : IsRat (a : α) n d → (d : α) ≠ 0 - | ⟨_, _⟩ => nonzero_of_invertible (d : α) + | ⟨_, _⟩ => Invertible.ne_zero (d : α) /-- The result of `norm_num` running on an expression `x` of type `α`. Untyped version of `Result`. -/ @@ -468,3 +468,5 @@ def Result.eqTrans {α : Q(Type u)} {a b : Q($α)} (eq : Q($a = $b)) : Result b | .isRat inst q n d proof => Result.isRat inst q n d q($eq ▸ $proof) end Meta.NormNum + +end Mathlib diff --git a/Mathlib/Tactic/NthRewrite.lean b/Mathlib/Tactic/NthRewrite.lean index eff8ce34cc201..2b57f362e7b19 100644 --- a/Mathlib/Tactic/NthRewrite.lean +++ b/Mathlib/Tactic/NthRewrite.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Moritz Doll -/ +import Mathlib.Init import Lean.Elab.Tactic.Rewrite /-! @@ -145,3 +146,5 @@ macro (name := nthRwSeq) "nth_rw" c:(config)? ppSpace n:num+ s:rwRuleSeq l:(loca `(tactic| (nth_rewrite $(c)? $[$n]* [$rs,*] $(l)?; with_annotate_state $rbrak (try (with_reducible rfl)))) | _ => Macro.throwUnsupported + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Observe.lean b/Mathlib/Tactic/Observe.lean index b6f47514b7d3b..9013fc9f12636 100644 --- a/Mathlib/Tactic/Observe.lean +++ b/Mathlib/Tactic/Observe.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Johan Commelin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin -/ +import Mathlib.Init import Lean.Meta.Tactic.TryThis import Lean.Elab.Tactic.ElabTerm import Lean.Meta.Tactic.LibrarySearch diff --git a/Mathlib/Tactic/PPWithUniv.lean b/Mathlib/Tactic/PPWithUniv.lean index 24a90c3e1394e..ad26e61447be9 100644 --- a/Mathlib/Tactic/PPWithUniv.lean +++ b/Mathlib/Tactic/PPWithUniv.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner -/ +import Mathlib.Init import Lean /-! @@ -46,3 +47,7 @@ initialize registerBuiltinAttribute { let attr ← Elab.elabAttr <| ← `(Term.attrInstance| delab $(mkIdent <| `app ++ src)) liftTermElabM <| Term.applyAttributes ``delabWithUniv #[{attr with kind}] | _ => throwUnsupportedSyntax } + +end PPWithUniv + +end Mathlib diff --git a/Mathlib/Tactic/Peel.lean b/Mathlib/Tactic/Peel.lean index 05de63976ca4e..0428aed375d7c 100644 --- a/Mathlib/Tactic/Peel.lean +++ b/Mathlib/Tactic/Peel.lean @@ -10,7 +10,7 @@ import Mathlib.Tactic.Basic # The `peel` tactic `peel h with h' idents*` tries to apply `forall_imp` (or `Exists.imp`, or `Filter.Eventually.mp`, -`Filter.Frequently.mp` and `Filter.eventually_of_forall`) with the argument `h` and uses `idents*` +`Filter.Frequently.mp` and `Filter.Eventually.of_forall`) with the argument `h` and uses `idents*` to introduce variables with the supplied names, giving the "peeled" argument the name `h'`. One can provide a numeric argument as in `peel 4 h` which will peel 4 quantifiers off @@ -78,7 +78,7 @@ immediately. In particular, `peel h using e` is equivalent to `peel h; exact e`. may be paired with any of the other features of `peel`. This tactic works by repeatedly applying lemmas such as `forall_imp`, `Exists.imp`, -`Filter.Eventually.mp`, `Filter.Frequently.mp`, and `Filter.eventually_of_forall`. +`Filter.Eventually.mp`, `Filter.Frequently.mp`, and `Filter.Eventually.of_forall`. -/ syntax (name := peel) "peel" (num)? (ppSpace colGt term)? @@ -88,11 +88,11 @@ private lemma and_imp_left_of_imp_imp {p q r : Prop} (h : r → p → q) : r ∧ private theorem eventually_imp {α : Type*} {p q : α → Prop} {f : Filter α} (hq : ∀ (x : α), p x → q x) (hp : ∀ᶠ (x : α) in f, p x) : ∀ᶠ (x : α) in f, q x := - Filter.Eventually.mp hp (Filter.eventually_of_forall hq) + Filter.Eventually.mp hp (Filter.Eventually.of_forall hq) private theorem frequently_imp {α : Type*} {p q : α → Prop} {f : Filter α} (hq : ∀ (x : α), p x → q x) (hp : ∃ᶠ (x : α) in f, p x) : ∃ᶠ (x : α) in f, q x := - Filter.Frequently.mp hp (Filter.eventually_of_forall hq) + Filter.Frequently.mp hp (Filter.Eventually.of_forall hq) private theorem eventually_congr {α : Type*} {p q : α → Prop} {f : Filter α} (hq : ∀ (x : α), p x ↔ q x) : (∀ᶠ (x : α) in f, p x) ↔ ∀ᶠ (x : α) in f, q x := by @@ -225,7 +225,7 @@ def peelArgsIff (l : List Name) : TacticM Unit := withMainContext do elab_rules : tactic | `(tactic| peel $[$num?:num]? $e:term $[with $l?* $n?]?) => withMainContext do /- we use `elabTermForApply` instead of `elabTerm` so that terms passed to `peel` can contain - quantifiers with implicit bound variables without causing errors or requiring `@`. -/ + quantifiers with implicit bound variables without causing errors or requiring `@`. -/ let e ← elabTermForApply e false let n? := n?.bind fun n => if n.raw.isIdent then pure n.raw.getId else none let l := (l?.getD #[]).map getNameOfIdent' |>.toList @@ -244,8 +244,4 @@ macro_rules | `(tactic| peel $[$n:num]? $[$e:term]? $[with $h*]? using $u:term) => `(tactic| peel $[$n:num]? $[$e:term]? $[with $h*]?; exact $u) -end Peel - -end Tactic - -end Mathlib +end Mathlib.Tactic.Peel diff --git a/Mathlib/Tactic/Polyrith.lean b/Mathlib/Tactic/Polyrith.lean index c2a538579b186..1b3ef56ab08c8 100644 --- a/Mathlib/Tactic/Polyrith.lean +++ b/Mathlib/Tactic/Polyrith.lean @@ -392,7 +392,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: @@ -426,8 +425,4 @@ elab_rules : tactic if !traceMe then Lean.Meta.Tactic.TryThis.addSuggestion tk stx | .error g => replaceMainGoal [g] -end Polyrith - -end Tactic - -end Mathlib +end Mathlib.Tactic.Polyrith diff --git a/Mathlib/Tactic/Positivity.lean b/Mathlib/Tactic/Positivity.lean index 88170863d05df..8d76b597bcf25 100644 --- a/Mathlib/Tactic/Positivity.lean +++ b/Mathlib/Tactic/Positivity.lean @@ -1,3 +1,3 @@ import Mathlib.Tactic.Positivity.Basic import Mathlib.Tactic.NormNum.Basic -import Mathlib.Init.Data.Int.Order +import Mathlib.Data.Int.Order.Basic diff --git a/Mathlib/Tactic/Positivity/Basic.lean b/Mathlib/Tactic/Positivity/Basic.lean index f15f4b15daf14..44f3d57c3fec7 100644 --- a/Mathlib/Tactic/Positivity/Basic.lean +++ b/Mathlib/Tactic/Positivity/Basic.lean @@ -5,7 +5,6 @@ Authors: Mario Carneiro, Heather Macbeth, Yaël Dillies -/ import Mathlib.Algebra.Order.Group.PosPart import Mathlib.Algebra.Order.Ring.Basic -import Mathlib.Algebra.Order.Ring.Rat import Mathlib.Data.Int.CharZero import Mathlib.Data.Nat.Factorial.Basic import Mathlib.Data.NNRat.Defs @@ -484,9 +483,9 @@ def evalRatNum : PositivityExt where eval {u α} _ _ e := do let pα : Q(PartialOrder ℚ) := q(inferInstance) assumeInstancesCommute match ← core zα pα a with - | .positive pa => pure $ .positive q(num_pos_of_pos $pa) - | .nonnegative pa => pure $ .nonnegative q(num_nonneg_of_nonneg $pa) - | .nonzero pa => pure $ .nonzero q(num_ne_zero_of_ne_zero $pa) + | .positive pa => pure <| .positive q(num_pos_of_pos $pa) + | .nonnegative pa => pure <| .nonnegative q(num_nonneg_of_nonneg $pa) + | .nonzero pa => pure <| .nonzero q(num_ne_zero_of_ne_zero $pa) | .none => pure .none | _, _ => throwError "not Rat.num" @@ -496,7 +495,7 @@ def evalRatDen : PositivityExt where eval {u α} _ _ e := do match u, α, e with | 0, ~q(ℕ), ~q(Rat.den $a) => assumeInstancesCommute - pure $ .positive q(den_pos $a) + pure <| .positive q(den_pos $a) | _, _ => throwError "not Rat.num" /-- Extension for `posPart`. `a⁺` is always nonegative, and positive if `a` is. -/ diff --git a/Mathlib/Tactic/Positivity/Core.lean b/Mathlib/Tactic/Positivity/Core.lean index b7778a848a069..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 @@ -341,7 +342,7 @@ private inductive OrderRel : Type end Meta.Positivity namespace Meta.Positivity -/-- An auxillary entry point to the `positivity` tactic. Given a proposition `t` of the form +/-- An auxiliary entry point to the `positivity` tactic. Given a proposition `t` of the form `0 [≤/ do end Positivity -end Tactic - -end Mathlib +end Mathlib.Tactic diff --git a/Mathlib/Tactic/ProdAssoc.lean b/Mathlib/Tactic/ProdAssoc.lean index 3c1f7e87755fc..40a335233a30e 100644 --- a/Mathlib/Tactic/ProdAssoc.lean +++ b/Mathlib/Tactic/ProdAssoc.lean @@ -37,7 +37,7 @@ def ProdTree.size : ProdTree → Nat | type _ _ => 1 | prod fst snd _ _ => fst.size + snd.size -/-- The components of an interated product, presented as a `ProdTree`. -/ +/-- The components of an iterated product, presented as a `ProdTree`. -/ def ProdTree.components : ProdTree → List Expr | type tp _ => [tp] | prod fst snd _ _ => fst.components ++ snd.components diff --git a/Mathlib/Tactic/ProjectionNotation.lean b/Mathlib/Tactic/ProjectionNotation.lean index b35c8b3dac9b7..d56a57bf0f447 100644 --- a/Mathlib/Tactic/ProjectionNotation.lean +++ b/Mathlib/Tactic/ProjectionNotation.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 Mathlib.Init import Lean /-! diff --git a/Mathlib/Tactic/Propose.lean b/Mathlib/Tactic/Propose.lean index 1df6661535b19..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 @@ -143,3 +143,5 @@ macro_rules `(tactic| have?%$tk ! $[: $type]? using $terms,*) | `(tactic| have!?%$tk $[: $type]? using $terms,*) => `(tactic| have?%$tk ! $[: $type]? using $terms,*) + +end Mathlib.Tactic.Propose diff --git a/Mathlib/Tactic/PushNeg.lean b/Mathlib/Tactic/PushNeg.lean index 2fe1ef4ab42da..07699624b4fc5 100644 --- a/Mathlib/Tactic/PushNeg.lean +++ b/Mathlib/Tactic/PushNeg.lean @@ -5,11 +5,10 @@ Authors: Patrick Massot, Simon Hudon, Alice Laroche, Frédéric Dupuis, Jireh Lo -/ import Lean.Elab.Tactic.Location +import Mathlib.Data.Set.Defs import Mathlib.Logic.Basic import Mathlib.Order.Defs import Mathlib.Tactic.Conv -import Mathlib.Init.Set -import Lean.Elab.Tactic.Location /-! # The `push_neg` tactic @@ -235,3 +234,5 @@ elab "push_neg" loc:(location)? : tactic => pushNegLocalDecl pushNegTarget (fun _ ↦ logInfo "push_neg couldn't find a negation to push") + +end Mathlib.Tactic.PushNeg diff --git a/Mathlib/Tactic/Qify.lean b/Mathlib/Tactic/Qify.lean index 6a264ce96ee33..f5b370e93f538 100644 --- a/Mathlib/Tactic/Qify.lean +++ b/Mathlib/Tactic/Qify.lean @@ -75,6 +75,4 @@ alias int_cast_ne := intCast_ne end Qify -end Tactic - -end Mathlib +end Mathlib.Tactic 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/Recall.lean b/Mathlib/Tactic/Recall.lean index 373b55ea8addd..29e44ac4dc6fb 100644 --- a/Mathlib/Tactic/Recall.lean +++ b/Mathlib/Tactic/Recall.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Mac Malone. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mac Malone, Kyle Miller -/ +import Mathlib.Init import Lean.Elab.Command import Lean.Elab.DeclUtil @@ -76,3 +77,5 @@ elab_rules : command else unless binders.getNumArgs == 0 do throwError "expected type after ':'" + +end Mathlib.Tactic.Recall diff --git a/Mathlib/Tactic/Recover.lean b/Mathlib/Tactic/Recover.lean index 93ee578786e42..abae8c5304d60 100644 --- a/Mathlib/Tactic/Recover.lean +++ b/Mathlib/Tactic/Recover.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Siddhartha Gadgil. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner, Siddhartha Gadgil, Jannis Limperg -/ +import Mathlib.Init import Lean /-! @@ -25,21 +26,21 @@ which occur in the target or local context or delayed assignment (if any) of `mvarId`, plus the metavariables which occur in these metavariables, etc. -/ partial def getUnassignedGoalMVarDependencies (mvarId : MVarId) : - MetaM (HashSet MVarId) := + MetaM (Std.HashSet MVarId) := return (← go mvarId |>.run {}).snd where /-- auxiliary function for `getUnassignedGoalMVarDependencies` -/ - addMVars (e : Expr) : StateRefT (HashSet MVarId) MetaM Unit := do + addMVars (e : Expr) : StateRefT (Std.HashSet MVarId) MetaM Unit := do let mvars ← getMVars e let mut s ← get - set ({} : HashSet MVarId) -- Ensure that `s` is not shared. + set ({} : Std.HashSet MVarId) -- Ensure that `s` is not shared. for mvarId in mvars do unless ← mvarId.isDelayedAssigned do s := s.insert mvarId set s mvars.forM go /-- auxiliary function for `getUnassignedGoalMVarDependencies` -/ - go (mvarId : MVarId) : StateRefT (HashSet MVarId) MetaM Unit := + go (mvarId : MVarId) : StateRefT (Std.HashSet MVarId) MetaM Unit := withIncRecDepth do let mdecl ← mvarId.getDecl addMVars mdecl.type @@ -59,10 +60,12 @@ that are not closed, starting from the original goal. -/ elab "recover " tacs:tacticSeq : tactic => do let originalGoals ← getGoals evalTactic tacs - let mut unassigned : HashSet MVarId := {} + let mut unassigned : Std.HashSet MVarId := {} for mvarId in originalGoals do unless ← mvarId.isAssigned <||> mvarId.isDelayedAssigned do unassigned := unassigned.insert mvarId let unassignedMVarDependencies ← getUnassignedGoalMVarDependencies mvarId unassigned := unassigned.insertMany unassignedMVarDependencies.toList setGoals <| ((← getGoals) ++ unassigned.toList).eraseDups + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/ReduceModChar/Ext.lean b/Mathlib/Tactic/ReduceModChar/Ext.lean index 2ee6b19df63b0..4e53350dd2539 100644 --- a/Mathlib/Tactic/ReduceModChar/Ext.lean +++ b/Mathlib/Tactic/ReduceModChar/Ext.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Anne Baanen. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen -/ +import Mathlib.Init import Lean.Meta.Tactic.Simp.Attr /-! diff --git a/Mathlib/Tactic/Relation/Rfl.lean b/Mathlib/Tactic/Relation/Rfl.lean index 038d0e43f1fc4..b35a56bd7c5c9 100644 --- a/Mathlib/Tactic/Relation/Rfl.lean +++ b/Mathlib/Tactic/Relation/Rfl.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Newell Jensen. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Newell Jensen -/ +import Mathlib.Init import Lean.Meta.Tactic.Rfl /-! @@ -40,3 +41,5 @@ def _root_.Lean.Expr.relSidesIfRefl? (e : Expr) : MetaM (Option (Name × Expr × | some n => return some (n, lhs, rhs) | none => return none return none + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Relation/Symm.lean b/Mathlib/Tactic/Relation/Symm.lean index 4f2d9e03bb9cb..8d33854268714 100644 --- a/Mathlib/Tactic/Relation/Symm.lean +++ b/Mathlib/Tactic/Relation/Symm.lean @@ -1,8 +1,9 @@ /- -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 /-! @@ -31,3 +32,5 @@ def _root_.Lean.Expr.relSidesIfSymm? (e : Expr) : MetaM (Option (Name × Expr × | some n => return some (n, lhs, rhs) | none => return none return none + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Relation/Trans.lean b/Mathlib/Tactic/Relation/Trans.lean index 80e8b89318c54..290d23e9aeb70 100644 --- a/Mathlib/Tactic/Relation/Trans.lean +++ b/Mathlib/Tactic/Relation/Trans.lean @@ -218,3 +218,5 @@ 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 f082fe62abf99..207f568849012 100644 --- a/Mathlib/Tactic/Rename.lean +++ b/Mathlib/Tactic/Rename.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Gabriel Ebner. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner -/ +import Mathlib.Init import Lean /-! @@ -14,6 +15,8 @@ namespace Mathlib.Tactic open Lean Elab.Tactic Meta +/-- A parser for a single rename to perform in the `rename` tactic: +these should have the form `h => hnew` (describing a rename of a hypothesis `h` to `hnew`). -/ syntax renameArg := term " => " ident /-- `rename' h => hnew` renames the hypothesis named `h` to `hnew`. @@ -35,3 +38,5 @@ elab_rules : tactic withMainContext do for fvar in ids, tgt in bs do Elab.Term.addTermInfo' tgt (mkFVar fvar) + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/RenameBVar.lean b/Mathlib/Tactic/RenameBVar.lean index 2f4ded3799ee4..fe1706f2eacfc 100644 --- a/Mathlib/Tactic/RenameBVar.lean +++ b/Mathlib/Tactic/RenameBVar.lean @@ -49,3 +49,5 @@ elab "rename_bvar " old:ident " → " new:ident loc?:(location)? : tactic => do (fun fvarId ↦ renameBVarHyp mvarId fvarId old.getId new.getId) (renameBVarTarget mvarId old.getId new.getId) fun _ ↦ throwError "unexpected location syntax" + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Replace.lean b/Mathlib/Tactic/Replace.lean index 7a4da71738e92..150bb27671e9f 100644 --- a/Mathlib/Tactic/Replace.lean +++ b/Mathlib/Tactic/Replace.lean @@ -60,3 +60,5 @@ elab_rules : tactic match hId? with | some hId => replaceMainGoal [goal1, (← observing? <| goal2.clear hId).getD goal2] | none => replaceMainGoal [goal1, goal2] + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/RewriteSearch.lean b/Mathlib/Tactic/RewriteSearch.lean index d232d90ba1581..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 @@ -328,6 +328,4 @@ elab_rules : tactic | end RewriteSearch -end Tactic - -end Mathlib +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Rify.lean b/Mathlib/Tactic/Rify.lean index 8fe355b461dd2..cf51d4c2f58e1 100644 --- a/Mathlib/Tactic/Rify.lean +++ b/Mathlib/Tactic/Rify.lean @@ -86,8 +86,4 @@ alias rat_cast_ne := ratCast_ne @[rify_simps] lemma ofNat_rat_real (a : ℕ) [a.AtLeastTwo] : ((no_index (OfNat.ofNat a : ℚ)) : ℝ) = (OfNat.ofNat a : ℝ) := rfl -end Rify - -end Tactic - -end Mathlib +end Mathlib.Tactic.Rify diff --git a/Mathlib/Tactic/Ring/Basic.lean b/Mathlib/Tactic/Ring/Basic.lean index 49b7a2931f4f8..c5ac7fd426cd8 100644 --- a/Mathlib/Tactic/Ring/Basic.lean +++ b/Mathlib/Tactic/Ring/Basic.lean @@ -134,26 +134,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 +166,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 +202,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 +307,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 +319,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 +337,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 +365,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 +413,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 +457,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 +477,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 +562,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 +580,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 +593,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 +609,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 +626,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 +732,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 +765,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 +779,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 +843,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 +875,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 +985,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 +1000,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 +1014,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 +1032,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 +1107,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 +1128,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 +1149,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 @@ -1219,6 +1251,4 @@ elab (name := ring1) "ring1" tk:"!"? : tactic => liftMetaMAtMain fun g ↦ do end Ring -end Tactic - -end Mathlib +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Ring/Compare.lean b/Mathlib/Tactic/Ring/Compare.lean new file mode 100644 index 0000000000000..5868ee2ee1706 --- /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 `[CovariantClass α α (swap (· + ·)) (· ≤ ·)]` 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/PNat.lean b/Mathlib/Tactic/Ring/PNat.lean index 7a8519746d309..d5e2883e3d672 100644 --- a/Mathlib/Tactic/Ring/PNat.lean +++ b/Mathlib/Tactic/Ring/PNat.lean @@ -42,6 +42,4 @@ instance {n n' k} [h1 : CSLiftVal (n : ℕ+) n'] : end Ring -end Tactic - -end Mathlib +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Ring/RingNF.lean b/Mathlib/Tactic/Ring/RingNF.lean index 04fc8327befe7..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. -/ @@ -196,6 +196,11 @@ which rewrites all ring expressions into a normal form. * `recursive`: if true, `ring_nf` will also recurse into atoms * `ring_nf` works as both a tactic and a conv tactic. In tactic mode, `ring_nf at h` can be used to rewrite in a hypothesis. + +This can be used non-terminally to normalize ring expressions in the goal such as +`⊢ P (x + x + x)` ~> `⊢ P (x * 3)`, as well as being able to prove some equations that +`ring` cannot because they involve ring reasoning inside a subterm, such as +`sin (x + y) + sin (y + x) = 2 * sin (x + y)`. -/ elab (name := ringNF) "ring_nf" tk:"!"? cfg:(config ?) loc:(location)? : tactic => do let mut cfg ← elabConfig cfg @@ -238,7 +243,8 @@ elab (name := ring1NF) "ring1_nf" tk:"!"? cfg:(config ?) : tactic => do /-- Tactic for evaluating expressions in *commutative* (semi)rings, allowing for variables in the -exponent. +exponent. If the goal is not appropriate for `ring` (e.g. not an equality) `ring_nf` will be +suggested. * `ring!` will use a more aggressive reducibility setting to determine equality of atoms. * `ring1` fails if the target is not an equality. @@ -248,6 +254,7 @@ For example: example (n : ℕ) (m : ℤ) : 2^(n+1) * m = 2 * 2^n * m := by ring example (a b : ℤ) (n : ℕ) : (a + b)^(n + 2) = (a^2 + b^2 + a * b + b * a) * (a + b)^n := by ring example (x y : ℕ) : x + id y = y + id x := by ring! +example (x : ℕ) (h : x * 2 > 5): x + x > 5 := by ring; assumption -- suggests ring_nf ``` -/ macro (name := ring) "ring" : tactic => @@ -268,6 +275,4 @@ macro (name := ringConv) "ring" : conv => end RingNF -end Tactic - -end Mathlib +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Sat/FromLRAT.lean b/Mathlib/Tactic/Sat/FromLRAT.lean index a97a50a16c9b3..b8d7f1a56e43c 100644 --- a/Mathlib/Tactic/Sat/FromLRAT.lean +++ b/Mathlib/Tactic/Sat/FromLRAT.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ import Mathlib.Algebra.Group.Nat +import Batteries.Data.HashMap.Basic /-! # `lrat_proof` command @@ -161,8 +162,9 @@ theorem Valuation.mk_implies {p} {as ps} (as₁) : as = List.reverseAux as₁ ps subst e; clear ih H suffices ∀ n n', n' = List.length as₁ + n → ∀ bs, mk (as₁.reverseAux bs) n' ↔ mk bs n from this 0 _ rfl (a::as) - induction as₁ with simp - | cons b as₁ ih => exact fun n bs ↦ ih (n+1) _ (Nat.succ_add ..) _ + induction as₁ with + | nil => simp + | cons b as₁ ih => simpa using fun n bs ↦ ih (n+1) _ (Nat.succ_add ..) _ /-- Asserts that `¬⟦f⟧_v` implies `p`. -/ structure Fmla.reify (v : Valuation) (f : Fmla) (p : Prop) : Prop where @@ -493,30 +495,30 @@ where open Lean namespace Parser -open Lean Parsec +open Lean Std.Internal.Parsec String /-- Parse a natural number -/ -def parseNat : Parsec Nat := Json.Parser.natMaybeZero +def parseNat : String.Parser Nat := Json.Parser.natMaybeZero /-- Parse an integer -/ -def parseInt : Parsec Int := do +def parseInt : String.Parser Int := do if (← peek!) = '-' then skip; pure <| -(← parseNat) else parseNat /-- Parse a list of integers terminated by 0 -/ -partial def parseInts (arr : Array Int := #[]) : Parsec (Array Int) := do +partial def parseInts (arr : Array Int := #[]) : String.Parser (Array Int) := do match ← parseInt <* ws with | 0 => pure arr | n => parseInts (arr.push n) /-- Parse a list of natural numbers terminated by 0 -/ -partial def parseNats (arr : Array Nat := #[]) : Parsec (Array Nat) := do +partial def parseNats (arr : Array Nat := #[]) : String.Parser (Array Nat) := do match ← parseNat <* ws with | 0 => pure arr | n => parseNats (arr.push n) /-- Parse a DIMACS format `.cnf` file. This is not very robust; we assume the file has had comments stripped. -/ -def parseDimacs : Parsec (Nat × Array (Array Int)) := do +def parseDimacs : String.Parser (Nat × Array (Array Int)) := do pstring "p cnf" *> ws let nvars ← parseNat <* ws let nclauses ← parseNat <* ws @@ -526,13 +528,15 @@ def parseDimacs : Parsec (Nat × Array (Array Int)) := do pure (nvars, clauses) /-- Parse an LRAT file into a list of steps. -/ -def parseLRAT : Parsec (Array LRATStep) := many do +def parseLRAT : String.Parser (Array LRATStep) := many do let step ← parseNat <* ws if (← peek!) = 'd' then skip <* ws; pure <| LRATStep.del (← parseNats) else ws; pure <| LRATStep.add step (← parseInts) (← parseInts) end Parser +open Std.Internal + /-- Core of `fromLRAT`. Constructs the context and main proof definitions, but not the reification theorem. Returns: @@ -669,3 +673,7 @@ elab "from_lrat " cnf:term:max ppSpace lrat:term:max : term => do example : ∀ (a b : Prop), (¬a ∧ ¬b ∨ a ∧ ¬b) ∨ ¬a ∧ b ∨ a ∧ b := from_lrat "p cnf 2 4 1 2 0 -1 2 0 1 -2 0 -1 -2 0" "5 -2 0 4 3 0 5 d 3 4 0 6 1 0 5 1 0 6 d 1 0 7 0 5 2 6 0" + +end Sat + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Says.lean b/Mathlib/Tactic/Says.lean index 92726858cd89e..29bd33ed183cf 100644 --- a/Mathlib/Tactic/Says.lean +++ b/Mathlib/Tactic/Says.lean @@ -1,8 +1,9 @@ /- -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 import Lean.Meta.Tactic.TryThis import Batteries.Linter.UnreachableTactic @@ -39,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 @@ -133,3 +134,7 @@ elab_rules : tactic evalTactic result initialize Batteries.Linter.UnreachableTactic.addIgnoreTacticKind `Mathlib.Tactic.Says.says + +end Says + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/ScopedNS.lean b/Mathlib/Tactic/ScopedNS.lean index c12423cbc1cd4..0057e00d2ffe4 100644 --- a/Mathlib/Tactic/ScopedNS.lean +++ b/Mathlib/Tactic/ScopedNS.lean @@ -53,3 +53,5 @@ macro_rules | `(scoped[$ns] attribute [$[$attr:attr],*] $ids*) => `(with_weak_namespace $(mkIdentFrom ns <| rootNamespace ++ ns.getId) attribute [$[scoped $attr:attr],*] $ids*) + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Set.lean b/Mathlib/Tactic/Set.lean index ec186f24acd28..742da43bb1561 100644 --- a/Mathlib/Tactic/Set.lean +++ b/Mathlib/Tactic/Set.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Ian Benway. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Ian Benway -/ +import Mathlib.Init import Lean /-! @@ -74,3 +75,5 @@ elab_rules : tactic evalTactic (← `(tactic| have%$tk $h : ($(← Term.exprToSyntax vale) : $(← Term.exprToSyntax ty)) = $a := rfl)) | _, _ => pure () + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/SetLike.lean b/Mathlib/Tactic/SetLike.lean index fb0cd27dc2b04..3f55f3606d7d7 100644 --- a/Mathlib/Tactic/SetLike.lean +++ b/Mathlib/Tactic/SetLike.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jireh Loreaux -/ +import Mathlib.Init import Aesop /-! diff --git a/Mathlib/Tactic/SimpIntro.lean b/Mathlib/Tactic/SimpIntro.lean index 61e5eeafcdc63..7012c998ee2ba 100644 --- a/Mathlib/Tactic/SimpIntro.lean +++ b/Mathlib/Tactic/SimpIntro.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.Init import Lean /-! # `simp_intro` tactic -/ @@ -73,3 +74,5 @@ elab "simp_intro" cfg:(config)? disch:(discharger)? g.withContext do let g? ← simpIntroCore g ctx (simprocs := simprocs) discharge? more.isSome ids.toList replaceMainGoal <| if let some g := g? then [g] else [] + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/SimpRw.lean b/Mathlib/Tactic/SimpRw.lean index c8ce3d76dcf33..fc9e243d4cc87 100644 --- a/Mathlib/Tactic/SimpRw.lean +++ b/Mathlib/Tactic/SimpRw.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen, Mario Carneiro, Alex J. Best -/ +import Mathlib.Init import Lean /-! @@ -77,3 +78,5 @@ elab s:"simp_rw " cfg:(config)? rws:rwRuleSeq g:(location)? : tactic => focus do `(tactic| simp%$e $[$cfg]? only [← $e:term] $g ?) else `(tactic| simp%$e $[$cfg]? only [$e:term] $g ?)) + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Simps/Basic.lean b/Mathlib/Tactic/Simps/Basic.lean index 6f1c5c4089821..1caba0e4825ab 100644 --- a/Mathlib/Tactic/Simps/Basic.lean +++ b/Mathlib/Tactic/Simps/Basic.lean @@ -269,31 +269,38 @@ syntax simpsRule := simpsRule.prefix <|> simpsRule.rename <|> simpsRule.erase <| syntax simpsProj := ppSpace ident (" (" simpsRule,+ ")")? /-- -This command specifies custom names and custom projections for the simp attribute `simpsAttr`. -* You can specify custom names by writing e.g. - `initialize_simps_projections Equiv (toFun → apply, invFun → symm_apply)`. -* See Note [custom simps projection] and the examples below for information how to declare custom - projections. +This command allows customisation of the lemmas generated by `simps`. + +By default, tagging a definition of an element `myObj` of a structure `MyStruct` with `@[simps]` +generates one `@[simp]` lemma `myObj_myProj` for each projection `myProj` of `MyStruct`. There are a +few exceptions to this general rule: * For algebraic structures, we will automatically use the notation (like `Mul`) for the projections if such an instance is available. * By default, the projections to parent structures are not default projections, but all the data-carrying fields are (including those in parent structures). + +This default behavior is customisable as such: * You can disable a projection by default by running - `initialize_simps_projections Equiv (-invFun)` + `initialize_simps_projections MulEquiv (-invFun)` This will ensure that no simp lemmas are generated for this projection, - unless this projection is explicitly specified by the user. + unless this projection is explicitly specified by the user (as in + `@[simps invFun] def myEquiv : MulEquiv _ _ := _`). * Conversely, you can enable a projection by default by running - `initialize_simps_projections Equiv (+toEquiv)`. + `initialize_simps_projections MulEquiv (+toEquiv)`. +* You can specify custom names by writing e.g. + `initialize_simps_projections MulEquiv (toFun → apply, invFun → symm_apply)`. * If you want the projection name added as a prefix in the generated lemma name, you can use `as_prefix fieldName`: - `initialize_simps_projections Equiv (toFun → coe, as_prefix coe)` + `initialize_simps_projections MulEquiv (toFun → coe, as_prefix coe)` Note that this does not influence the parsing of projection names: if you have a declaration `foo` and you want to apply the projections `snd`, `coe` (which is a prefix) and `fst`, in that order you can run `@[simps snd_coe_fst] def foo ...` and this will generate a lemma with the name `coe_foo_snd_fst`. + +Here are a few extra pieces of information: * Run `initialize_simps_projections?` (or `set_option trace.simps.verbose true`) to see the generated projections. -* Running `initialize_simps_projections MyStruc` without arguments is not necessary, it has the +* Running `initialize_simps_projections MyStruct` without arguments is not necessary, it has the same effect if you just add `@[simps]` to a declaration. * It is recommended to call `@[simps]` or `initialize_simps_projections` in the same file as the structure declaration. Otherwise, the projections could be generated multiple times in different @@ -304,7 +311,7 @@ Some common uses: `initialize_simps_projections` after defining the `DFunLike` instance (or instance that implies a `DFunLike` instance). ``` - instance {mM : Mul M} {mN : Mul N} : DFunLike (MulHom M N) M N := ... + instance {mM : Mul M} {mN : Mul N} : FunLike (MulHom M N) M N := ... initialize_simps_projections MulHom (toFun → apply) ``` This will generate `foo_apply` lemmas for each declaration `foo`. @@ -482,7 +489,7 @@ We use this variant because the latter is often a different field with an auto-g -/ private def dropPrefixIfNotNumber? (s : String) (pre : Substring) : Option Substring := do let ret ← Substring.dropPrefix? s pre - -- flag is true when the remaning part is nonempty and starts with a digit. + -- flag is true when the remaining part is nonempty and starts with a digit. let flag := ret.toString.data.head?.elim false Char.isDigit if flag then none else some ret @@ -535,7 +542,7 @@ partial def getCompositeOfProjectionsAux (proj : String) (e : Expr) (pos : Array initialize_simps_projections (toFun_toFun_toFun → myMul) ``` we will be able to generate the "projection" - `λ {A} (f : gradedFun A) (x : A i) (y : A j) ↦ ↑(↑(f.toFun i j) x) y`, + `fun {A} (f : gradedFun A) (x : A i) (y : A j) ↦ ↑(↑(f.toFun i j) x) y`, which projection notation cannot do. -/ def getCompositeOfProjections (structName : Name) (proj : String) : MetaM (Expr × Array Nat) := do let strExpr ← mkConstWithLevelParams structName @@ -1172,7 +1179,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/Simps/NotationClass.lean b/Mathlib/Tactic/Simps/NotationClass.lean index 42f2271a61ea7..4ce2493b876a1 100644 --- a/Mathlib/Tactic/Simps/NotationClass.lean +++ b/Mathlib/Tactic/Simps/NotationClass.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn -/ +import Mathlib.Init import Lean.Elab.Exception import Batteries.Lean.NameMapAttribute import Batteries.Lean.Expr @@ -45,7 +46,7 @@ We partly define this as a separate definition so that the unused arguments lint def findArgType : Type := Name → Name → Array Expr → MetaM (Array (Option Expr)) /-- Find arguments for a notation class -/ -def defaultfindArgs : findArgType := λ _ className args => do +def defaultfindArgs : findArgType := fun _ className args ↦ do let some classExpr := (← getEnv).find? className | throwError "no such class {className}" let arity := classExpr.type.forallArity if arity == args.size then @@ -57,29 +58,29 @@ def defaultfindArgs : findArgType := λ _ className args => do {className}" /-- Find arguments by duplicating the first argument. Used for `pow`. -/ -def copyFirst : findArgType := λ _ _ args => return (args.push <| args[0]?.getD default).map some +def copyFirst : findArgType := fun _ _ args ↦ return (args.push <| args[0]?.getD default).map some /-- Find arguments by duplicating the first argument. Used for `smul`. -/ -def copySecond : findArgType := λ _ _ args => return (args.push <| args[1]?.getD default).map some +def copySecond : findArgType := fun _ _ args ↦ return (args.push <| args[1]?.getD default).map some /-- Find arguments by prepending `ℕ` and duplicating the first argument. Used for `nsmul`. -/ -def nsmulArgs : findArgType := λ _ _ args => +def nsmulArgs : findArgType := fun _ _ args ↦ return #[Expr.const `Nat [], args[0]?.getD default] ++ args |>.map some /-- Find arguments by prepending `ℤ` and duplicating the first argument. Used for `zsmul`. -/ -def zsmulArgs : findArgType := λ _ _ args => +def zsmulArgs : findArgType := fun _ _ args ↦ return #[Expr.const `Int [], args[0]?.getD default] ++ args |>.map some /-- Find arguments for the `Zero` class. -/ -def findZeroArgs : findArgType := λ _ _ args => +def findZeroArgs : findArgType := fun _ _ args ↦ return #[some <| args[0]?.getD default, some <| mkRawNatLit 0] /-- Find arguments for the `One` class. -/ -def findOneArgs : findArgType := λ _ _ args => +def findOneArgs : findArgType := fun _ _ args ↦ return #[some <| args[0]?.getD default, some <| mkRawNatLit 1] /-- Find arguments of a coercion class (`DFunLike` or `SetLike`) -/ -def findCoercionArgs : findArgType := λ str className args => do +def findCoercionArgs : findArgType := fun str className args ↦ do let some classExpr := (← getEnv).find? className | throwError "no such class {className}" let arity := classExpr.type.forallArity let eStr := mkAppN (← mkConstWithLevelParams str) args diff --git a/Mathlib/Tactic/SlimCheck.lean b/Mathlib/Tactic/SlimCheck.lean index e5088f231ead7..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 @@ -181,7 +181,7 @@ elab_rules : tactic | `(tactic| slim_check $[$cfg]?) => withMainContext do Failed to create a `testable` instance for `{tgt}`.\ \nWhat to do:\ \n1. make sure that the types you are using have `SlimCheck.SampleableExt` instances\ - \n (you can use `#sample my_type` if you are unsure);\ + \n (you can use `#sample my_type` if you are unsure);\ \n2. make sure that the relations and predicates that your proposition use are decidable;\ \n3. make sure that instances of `SlimCheck.Testable` exist that, when combined,\ \n apply to your decorated proposition:\ diff --git a/Mathlib/Tactic/SplitIfs.lean b/Mathlib/Tactic/SplitIfs.lean index 13d9944826b89..97bfe7da56045 100644 --- a/Mathlib/Tactic/SplitIfs.lean +++ b/Mathlib/Tactic/SplitIfs.lean @@ -74,7 +74,7 @@ private def discharge? (e : Expr) : SimpM (Option Expr) := do private def reduceIfsAt (loc : Location) : TacticM Unit := do let ctx ← SplitIf.getSimpContext let ctx := { ctx with config := { ctx.config with failIfUnchanged := false } } - let _ ← simpLocation ctx {} discharge? loc + let _ ← simpLocation ctx (← ({} : Simp.SimprocsArray).add `reduceCtorEq false) discharge? loc pure () /-- Splits a single if-then-else expression and then reduces the resulting goals. @@ -154,3 +154,5 @@ elab_rules : tactic splitIfsCore loc names [] for name in ← names.get do logWarningAt name m!"unused name: {name}" + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Spread.lean b/Mathlib/Tactic/Spread.lean index aeb6043b465e1..0252a2fa396db 100644 --- a/Mathlib/Tactic/Spread.lean +++ b/Mathlib/Tactic/Spread.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Gabriel Ebner. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner -/ +import Mathlib.Init import Lean.Elab.Binders /-! diff --git a/Mathlib/Tactic/StacksAttribute.lean b/Mathlib/Tactic/StacksAttribute.lean new file mode 100644 index 0000000000000..0dc60503a6780 --- /dev/null +++ b/Mathlib/Tactic/StacksAttribute.lean @@ -0,0 +1,223 @@ +/- +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 `stacks` and `kerodon` attributes + +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.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 project tag and a corresponding +Mathlib declaration. -/ +structure Tag where + /-- The name of the declaration with the given tag. -/ + declName : Name + /-- 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 + deriving BEq, Hashable + +/-- Defines the `tagExt` extension for adding a `HashSet` of `Tag`s +to the environment. -/ +initialize tagExt : SimplePersistentEnvExtension Tag (Std.HashSet Tag) ← + registerSimplePersistentEnvExtension { + addImportedFn := fun as => as.foldl Std.HashSet.insertMany {} + addEntryFn := .insert + } + +/-- +`addTagEntry declName tag comment` takes as input the `Name` `declName` of a declaration and +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) (db : Database) (tag comment : String) : m Unit := + modifyEnv (tagExt.addEntry · + { declName := declName, database := db, tag := tag, comment := comment }) + +open Parser + +/-- `stacksTag` is the node kind of Stacks Project Tags: a sequence of digits and +uppercase letters. -/ +abbrev stacksTagKind : SyntaxNodeKind := `stacksTag + +/-- The main parser for Stacks Project Tags: it accepts any sequence of 4 digits or +uppercase letters. -/ +def stacksTagFn : ParserFn := fun c s => + let i := s.pos + let s := takeWhileFn (fun c => c.isAlphanum) c s + if s.hasError then + s + else if s.pos == i then + ParserState.mkError s "stacks tag" + else + let tag := Substring.mk c.input i s.pos |>.toString + if !tag.all fun c => c.isDigit || c.isUpper then + ParserState.mkUnexpectedError s + "Stacks tags must consist only of digits and uppercase letters." + else if tag.length != 4 then + ParserState.mkUnexpectedError s "Stacks tags must be exactly 4 characters" + else + mkNodeToken stacksTagKind i c s + +@[inherit_doc stacksTagFn] +def stacksTagNoAntiquot : Parser := { + fn := stacksTagFn + info := mkAtomicInfo "stacksTag" +} + +@[inherit_doc stacksTagFn] +def stacksTagParser : Parser := + withAntiquot (mkAntiquot "stacksTag" stacksTagKind) stacksTagNoAntiquot + +end Mathlib.StacksTag + +open Mathlib.StacksTag + +/-- Extract the underlying tag as a string from a `stacksTag` node. -/ +def Lean.TSyntax.getStacksTag (stx : TSyntax stacksTagKind) : CoreM String := do + let some val := Syntax.isLit? stacksTagKind stx | throwError "Malformed Stacks tag" + return val + +namespace Lean.PrettyPrinter + +namespace Formatter + +/-- The formatter for Stacks Project Tags syntax. -/ +@[combinator_formatter stacksTagNoAntiquot] def stacksTagNoAntiquot.formatter := + visitAtom stacksTagKind + +end Formatter + +namespace Parenthesizer + +/-- The parenthesizer for Stacks Project Tags syntax. -/ +@[combinator_parenthesizer stacksTagNoAntiquot] def stacksTagAntiquot.parenthesizer := visitToken + +end Lean.PrettyPrinter.Parenthesizer + +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 `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 or +[Tags page](https://kerodon.net/tag/) in the Kerodon project for more details. +-/ +syntax (name := stacksTag) stacksTagDB stacksTagParser (ppSpace str)? : attr + +initialize Lean.registerBuiltinAttribute { + 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 .stacks (← tag.getStacksTag) <| (comment.map (·.getString)).getD "" + | `(attr| kerodon $tag $[$comment]?) => do + addTagEntry decl .kerodon (← tag.getStacksTag) <| (comment.map (·.getString)).getD "" + | _ => throwUnsupportedSyntax +} + +end Mathlib.StacksTag + +/-- +`getSortedStackProjectTags env` returns the array of `Tags`, sorted by alphabetical order of 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`. +-/ +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 + +namespace Mathlib.StacksTag + +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`. +-/ +def traceStacksTags (db : Database) (verbose : Bool := false) : + Command.CommandElabM Unit := do + let env ← getEnv + 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 + let dname ← Command.liftCoreM do realizeGlobalConstNoOverloadWithInfo (mkIdent d.declName) + let (parL, parR) := if d.comment.isEmpty then ("", "") else (" (", ")") + let cmt := parL ++ d.comment ++ parR + msgs := msgs.push + m!"[Stacks Tag {d.tag}]({databaseURL db ++ d.tag}) \ + corresponds to declaration '{dname}'.{cmt}" + 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/Subsingleton.lean b/Mathlib/Tactic/Subsingleton.lean index 1a6dbcd2f6260..b5b8b9b18f06a 100644 --- a/Mathlib/Tactic/Subsingleton.lean +++ b/Mathlib/Tactic/Subsingleton.lean @@ -96,8 +96,9 @@ def Lean.MVarId.subsingleton (g : MVarId) (insts : Array (Term × AbstractMVarsR if ← (Meta.isProp xTy <&&> Meta.isProp yTy) then g.assign <| mkApp4 (.const ``proof_irrel_heq []) xTy yTy x y return - throwError "tactic 'subsingleton' could not prove heterogenous equality" - throwError "tactic 'subsingleton' failed, goal is neither an equality nor heterogenous equality" + throwError "tactic 'subsingleton' could not prove heterogeneous equality" + throwError "tactic 'subsingleton' failed, goal is neither an equality nor a \ + heterogeneous equality" namespace Mathlib.Tactic @@ -116,7 +117,7 @@ As a nicety, `subsingleton` first runs the `intros` tactic. Techniques the `subsingleton` tactic can apply: - proof irrelevance -- heterogenous proof irrelevance (via `proof_irrel_heq`) +- heterogeneous proof irrelevance (via `proof_irrel_heq`) - using `Subsingleton` (via `Subsingleton.elim`) - proving `BEq` instances are equal if they are both lawful (via `lawful_beq_subsingleton`) diff --git a/Mathlib/Tactic/Substs.lean b/Mathlib/Tactic/Substs.lean index 7b0b8bb481d9f..b5f3ea55b20d3 100644 --- a/Mathlib/Tactic/Substs.lean +++ b/Mathlib/Tactic/Substs.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Evan Lohn. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Evan Lohn, Mario Carneiro -/ +import Mathlib.Init import Lean /-! @@ -21,3 +22,7 @@ syntax (name := substs) "substs" (colGt ppSpace ident)* : tactic macro_rules | `(tactic| substs $xs:ident*) => `(tactic| ($[subst $xs]*)) + +end Substs + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/SuccessIfFailWithMsg.lean b/Mathlib/Tactic/SuccessIfFailWithMsg.lean index 33b4f0709426c..70bb4e7e8468d 100644 --- a/Mathlib/Tactic/SuccessIfFailWithMsg.lean +++ b/Mathlib/Tactic/SuccessIfFailWithMsg.lean @@ -1,8 +1,9 @@ /- Copyright (c) 2017 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Mario Carneiro, Simon Hudon, Sébastien Gouëzel, Scott Morrison, Thomas Murrills +Authors: Mario Carneiro, Simon Hudon, Sébastien Gouëzel, Kim Morrison, Thomas Murrills -/ +import Mathlib.Init import Lean /-! @@ -51,3 +52,5 @@ elab_rules : tactic Term.withoutErrToSorry <| withoutRecover do let msg ← unsafe Term.evalTerm String (.const ``String []) msg successIfFailWithMessage msg (evalTacticSeq tacs) tacs + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/SudoSetOption.lean b/Mathlib/Tactic/SudoSetOption.lean index 7d6ba36b7818b..8457c4741033c 100644 --- a/Mathlib/Tactic/SudoSetOption.lean +++ b/Mathlib/Tactic/SudoSetOption.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Gabriel Ebner. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner -/ +import Mathlib.Init import Lean.Elab.ElabRules /-! diff --git a/Mathlib/Tactic/SuppressCompilation.lean b/Mathlib/Tactic/SuppressCompilation.lean index 945340816281a..f647b5f2a31be 100644 --- a/Mathlib/Tactic/SuppressCompilation.lean +++ b/Mathlib/Tactic/SuppressCompilation.lean @@ -3,11 +3,12 @@ Copyright (c) 2023 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Alex J. Best, Mac Malone -/ +import Mathlib.Init import Lean.Elab.Declaration import Lean.Elab.Notation /-! -# Supressing compilation to executable code in a file or in a section +# Suppressing compilation to executable code in a file or in a section Currently, the compiler may spend a lot of time trying to produce executable code for complicated definitions. This is a waste of resources for definitions in area of mathematics that will never diff --git a/Mathlib/Tactic/SwapVar.lean b/Mathlib/Tactic/SwapVar.lean index 7bc39caecd595..96c6c0987b180 100644 --- a/Mathlib/Tactic/SwapVar.lean +++ b/Mathlib/Tactic/SwapVar.lean @@ -46,3 +46,5 @@ elab "swap_var " swapRules:(colGt swapRule),+ : tactic => do return lctx.setUserName fvarId₁ n₂ |>.setUserName fvarId₂ n₁ let mdecl := { mdecl with lctx := lctx } modifyMCtx fun mctx ↦ { mctx with decls := mctx.decls.insert mvarId mdecl } + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/TFAE.lean b/Mathlib/Tactic/TFAE.lean index d5ef4b815aad8..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 @@ -101,7 +161,7 @@ where variable (hyps : Array (ℕ × ℕ × Expr)) (atoms : Array Q(Prop)) /-- Uses depth-first search to find a path from `P` to `P'`. -/ -partial def dfs (i j : ℕ) (P P' : Q(Prop)) (hP : Q($P)) : StateT (HashSet ℕ) MetaM Q($P') := do +partial def dfs (i j : ℕ) (P P' : Q(Prop)) (hP : Q($P)) : StateT (Std.HashSet ℕ) MetaM Q($P') := do if i == j then return hP modify (·.insert i) @@ -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 @@ -236,3 +306,40 @@ elab_rules : tactic let q2 ← AtomM.addAtom ty.bindingBody! 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/Tauto.lean b/Mathlib/Tactic/Tauto.lean index 2ccb7671879e9..14285f3eb5428 100644 --- a/Mathlib/Tactic/Tauto.lean +++ b/Mathlib/Tactic/Tauto.lean @@ -220,3 +220,5 @@ syntax (name := tauto) "tauto" (config)? : tactic elab_rules : tactic | `(tactic| tauto $[$cfg:config]?) => do let _cfg ← elabConfig (mkOptionalNode cfg) tautology + +end Mathlib.Tactic.Tauto diff --git a/Mathlib/Tactic/TermCongr.lean b/Mathlib/Tactic/TermCongr.lean index adc9350e2ff19..5ec0c3b92a6bf 100644 --- a/Mathlib/Tactic/TermCongr.lean +++ b/Mathlib/Tactic/TermCongr.lean @@ -103,7 +103,7 @@ Note that there is no relation between `val` and the proof. We need to decouple these to support letting the proof's elaboration be deferred until we know whether we want an iff, eq, or heq, while also allowing it to choose to elaborate as an iff, eq, or heq. -Later, the congruence generator handles any discrepencies. +Later, the congruence generator handles any discrepancies. See `Mathlib.Tactic.TermCongr.CongrResult`. -/ @[reducible, nolint unusedArguments] def cHole {α : Sort u} (val : α) {p : Prop} (_pf : p) : α := val @@ -139,7 +139,7 @@ def cHole? (e : Expr) (mvarCounterSaved? : Option Nat := none) : Option (Bool × return (forLhs, val, pf) | _ => none -/-- Returns any subexpression that is a recent congruence hole. -/ +/-- Returns any subexpression that is a recent congruence hole. -/ def hasCHole (mvarCounterSaved : Nat) (e : Expr) : Option Expr := e.find? fun e' => (cHole? e' mvarCounterSaved).isSome @@ -638,3 +638,7 @@ def elabTermCongr : Term.TermElab := fun stx expectedType? => do let ty ← mkEq res.lhs res.rhs mkExpectedTypeHint pf ty | _ => throwUnsupportedSyntax + +end TermCongr + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/ToAdditive/Frontend.lean b/Mathlib/Tactic/ToAdditive/Frontend.lean index f3d84bce1ec87..bdc528a294073 100644 --- a/Mathlib/Tactic/ToAdditive/Frontend.lean +++ b/Mathlib/Tactic/ToAdditive/Frontend.lean @@ -13,8 +13,9 @@ import Mathlib.Lean.Name import Lean.Elab.Tactic.Ext import Lean.Meta.Tactic.Symm 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 for DiscrTree.elements +import Batteries.Tactic.Lint -- useful to lint this file and for DiscrTree.elements import Mathlib.Tactic.Relation.Trans -- just to copy the attribute import Mathlib.Tactic.Eqns -- just to copy the attribute import Mathlib.Tactic.Simps.Basic @@ -816,6 +817,12 @@ partial def transformDeclAux selectionRange := ← getDeclarationRange cfg.ref } if isProtected (← getEnv) src then setEnv <| addProtected (← getEnv) tgt + if let some matcherInfo ← getMatcherInfo? src then + /- + Use `Match.addMatcherInfo tgt matcherInfo` + once https://github.com/leanprover/lean4/pull/5068 is in + -/ + modifyEnv fun env => Match.Extension.addMatcherInfo env tgt matcherInfo /-- Copy the instance attribute in a `to_additive` @@ -958,6 +965,7 @@ def nameDict : String → List String | "zpowers" => ["zmultiples"] | "powers" => ["multiples"] | "multipliable"=> ["summable"] + | "gpfree" => ["apfree"] | x => [x] /-- @@ -1042,8 +1050,10 @@ def fixAbbreviation : List String → List String => "function" :: "_" :: "commute" :: fixAbbreviation s | "zero" :: "Le" :: "Part" :: s => "posPart" :: fixAbbreviation s | "le" :: "Zero" :: "Part" :: s => "negPart" :: fixAbbreviation s - | "three" :: "GPFree" :: s => "three" :: "APFree" :: fixAbbreviation s - | "Three" :: "GPFree" :: s => "Three" :: "APFree" :: fixAbbreviation s + | "Division" :: "Add" :: "Monoid" :: s => "SubtractionMonoid" :: fixAbbreviation s + | "division" :: "Add" :: "Monoid" :: s => "subtractionMonoid" :: fixAbbreviation s + | "Sub" :: "Neg" :: "Zero" :: "Add" :: "Monoid" :: s => "SubNegZeroMonoid" :: fixAbbreviation s + | "sub" :: "Neg" :: "Zero" :: "Add" :: "Monoid" :: s => "subNegZeroMonoid" :: fixAbbreviation s | x :: s => x :: fixAbbreviation s | [] => [] @@ -1213,7 +1223,7 @@ partial def copyMetaData (cfg : Config) (src tgt : Name) : CoreM (Array Name) := definitions. If we don't do that, the equation lemma for `src` might be generated later when doing a `rw`, but it won't be generated for `tgt`. -/ additivizeLemmas #[src, tgt] "equation lemmas" fun nm ↦ - (·.getD #[]) <$> MetaM.run' (getEqnsFor? nm true) + (·.getD #[]) <$> MetaM.run' (getEqnsFor? nm) MetaM.run' <| Elab.Term.TermElabM.run' <| applyAttributes cfg.ref cfg.attrs `to_additive src tgt @@ -1496,3 +1506,5 @@ initialize registerBuiltinAttribute { } end ToAdditive + +set_option linter.style.longFile 1700 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/Trace.lean b/Mathlib/Tactic/Trace.lean index 364412c44ada5..2e5673d8cd799 100644 --- a/Mathlib/Tactic/Trace.lean +++ b/Mathlib/Tactic/Trace.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.Init import Lean.Elab.Tactic.ElabTerm import Lean.Meta.Eval diff --git a/Mathlib/Tactic/TryThis.lean b/Mathlib/Tactic/TryThis.lean index 44e8c914dbc5c..9e0c3ea6a3cc0 100644 --- a/Mathlib/Tactic/TryThis.lean +++ b/Mathlib/Tactic/TryThis.lean @@ -3,6 +3,7 @@ Copyright (c) 2024 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ +import Mathlib.Init import Lean /-! @@ -25,3 +26,5 @@ elab tk:"try_this" tac:tactic : tactic => do elab tk:"try_this" tac:conv : conv => do Elab.Tactic.evalTactic tac Meta.Tactic.TryThis.addSuggestion tk tac (origSpan? := ← getRef) + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/TypeCheck.lean b/Mathlib/Tactic/TypeCheck.lean index b72e3f2079b0f..027d17e403e20 100644 --- a/Mathlib/Tactic/TypeCheck.lean +++ b/Mathlib/Tactic/TypeCheck.lean @@ -3,6 +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.Init import Lean.Elab.Tactic.Basic import Lean.Elab.SyntheticMVars diff --git a/Mathlib/Tactic/TypeStar.lean b/Mathlib/Tactic/TypeStar.lean index d020ece4a2492..35c0d6d1b7fae 100644 --- a/Mathlib/Tactic/TypeStar.lean +++ b/Mathlib/Tactic/TypeStar.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Matthew Robert Ballard. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kyle Miller -/ +import Mathlib.Init import Lean.Elab.Term /-! diff --git a/Mathlib/Tactic/UnsetOption.lean b/Mathlib/Tactic/UnsetOption.lean index a57bfe4ffc56c..032d3f10d0be6 100644 --- a/Mathlib/Tactic/UnsetOption.lean +++ b/Mathlib/Tactic/UnsetOption.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Alex J. Best. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Alex J. Best -/ +import Mathlib.Init import Lean.Parser.Term import Lean.Parser.Do import Lean.Elab.Command diff --git a/Mathlib/Tactic/Use.lean b/Mathlib/Tactic/Use.lean index bb735ceacafb9..0f48c40b79e55 100644 --- a/Mathlib/Tactic/Use.lean +++ b/Mathlib/Tactic/Use.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Arthur Paulino. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Arthur Paulino, Gabriel Ebner, Kyle Miller -/ +import Mathlib.Init import Lean.Meta.Tactic.Util import Lean.Elab.Tactic.Basic @@ -201,3 +202,5 @@ elab (name := useSyntax) @[inherit_doc useSyntax] elab "use!" discharger?:(Parser.Tactic.discharger)? ppSpace args:term,+ : tactic => do runUse true (← mkUseDischarger discharger?) args.getElems.toList + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Variable.lean b/Mathlib/Tactic/Variable.lean index d09edae33938b..ce1dd2966519a 100644 --- a/Mathlib/Tactic/Variable.lean +++ b/Mathlib/Tactic/Variable.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 Mathlib.Init import Lean.Meta.Tactic.TryThis /-! @@ -249,7 +250,7 @@ def elabVariables : CommandElab := fun stx => where extendScope (binders : TSyntaxArray ``bracketedBinder) : CommandElabM Unit := do for binder in binders do - let varUIds ← getBracketedBinderIds binder |>.mapM + let varUIds ← (← getBracketedBinderIds binder) |>.mapM (withFreshMacroScope ∘ MonadQuotation.addMacroScope) modifyScope fun scope => { scope with varDecls := scope.varDecls.push binder, varUIds := scope.varUIds ++ varUIds } @@ -269,7 +270,7 @@ where Term.withAutoBoundImplicit <| Term.elabBinders binders fun _ => pure () -- Filter out omitted binders let binders' : TSyntaxArray ``bracketedBinder := - (binders.zip toOmit).filterMap fun (b, omit) => if omit then none else some b + (binders.zip toOmit).filterMap fun (b, toOmit) => if toOmit then none else some b if let some expectedBinders := expectedBinders? then trace[«variable?»] "checking expected binders" /- We re-elaborate the binders to create an expression that represents the entire resulting @@ -307,3 +308,9 @@ where def ignorevariable? : Lean.Linter.IgnoreFunction := fun _ stack _ => stack.matches [`null, none, `null, ``Mathlib.Command.Variable.variable?] || stack.matches [`null, none, `null, `null, ``Mathlib.Command.Variable.variable?] + +end Variable + +end Command + +end Mathlib diff --git a/Mathlib/Tactic/WLOG.lean b/Mathlib/Tactic/WLOG.lean index 54a4007761d67..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 @@ -138,3 +139,5 @@ elab_rules : tactic let goal ← getMainGoal let { reductionGoal, hypothesisGoal .. } ← goal.wlog h P xs H replaceMainGoal [reductionGoal, hypothesisGoal] + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Widget/Calc.lean b/Mathlib/Tactic/Widget/Calc.lean index 34ea5f388d745..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. -/ @@ -142,3 +142,5 @@ elab_rules : tactic Widget.savePanelWidgetInfo CalcPanel.javascriptHash (pure json) proofTerm isFirst := false evalCalc (← `(tactic|calc%$calcstx $stx)) + +end Lean.Elab.Tactic diff --git a/Mathlib/Tactic/Widget/CommDiag.lean b/Mathlib/Tactic/Widget/CommDiag.lean index b4b2a8a73ae77..1e089b2114a61 100644 --- a/Mathlib/Tactic/Widget/CommDiag.lean +++ b/Mathlib/Tactic/Widget/CommDiag.lean @@ -137,6 +137,4 @@ def commutativeSquarePresenter : ExprPresenter where end Widget -end Tactic - -end Mathlib +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Widget/InteractiveUnfold.lean b/Mathlib/Tactic/Widget/InteractiveUnfold.lean index d6b02f009dd2a..7d3eae135546f 100644 --- a/Mathlib/Tactic/Widget/InteractiveUnfold.lean +++ b/Mathlib/Tactic/Widget/InteractiveUnfold.lean @@ -161,7 +161,7 @@ def renderUnfolds (e : Expr) (occ : Option Nat) (loc : Option Name) (range : Lsp #[ { Html.ofComponent MakeEditLink (.ofReplaceRange doc.meta range tactic) - #[.text $ Format.pretty $ (← Meta.ppExpr unfold)] } + #[.text <| Format.pretty <| (← Meta.ppExpr unfold)] } ] } return
@@ -221,11 +221,11 @@ Click on a suggestion to replace `unfold?` by a tactic that performs this rewrit elab stx:"unfold?" : tactic => do let some range := (← getFileMap).rangeOfStx? stx | return Widget.savePanelWidgetInfo (hash UnfoldComponent.javascript) - (pure $ json% { replaceRange : $range }) stx + (pure <| json% { replaceRange : $range }) stx /-- `#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. -/ @@ -242,3 +242,7 @@ def elabUnfoldCommand : Command.CommandElab := fun stx => let unfolds := unfolds.toList.map (m! "· {·}") logInfo (m! "Unfolds for {e}:\n" ++ .joinSep unfolds "\n") + +end InteractiveUnfold + +end Mathlib.Tactic diff --git a/Mathlib/Tactic/Widget/SelectInsertParamsClass.lean b/Mathlib/Tactic/Widget/SelectInsertParamsClass.lean index 127473b69b56c..4c7be09054bee 100644 --- a/Mathlib/Tactic/Widget/SelectInsertParamsClass.lean +++ b/Mathlib/Tactic/Widget/SelectInsertParamsClass.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Patrick Massot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Patrick Massot -/ +import Mathlib.Init import Lean.Widget.InteractiveGoal import Lean.Elab.Deriving.Basic diff --git a/Mathlib/Tactic/Widget/StringDiagram.lean b/Mathlib/Tactic/Widget/StringDiagram.lean index 56a321a914335..9ba22761bcd5e 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 @@ -54,12 +62,13 @@ namespace Mathlib.Tactic open Lean Meta Elab open CategoryTheory -open Mathlib.Tactic.Coherence -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. -/ @@ -96,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 → ℕ @@ -121,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. -/ @@ -142,64 +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} [Context ρ] [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 (α × α) - | [] => [] - | [_] => [] - | (x :: y :: ys) => (x, y) :: pairs (y :: ys) +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 @@ -215,11 +235,11 @@ structure PenroseVar : Type where instance : ToString PenroseVar := ⟨fun v => v.ident ++ v.indices.foldl (fun s x => s ++ s!"_{x}") ""⟩ -/-- The penrose variable assciated with a node. -/ +/-- The penrose variable associated with a node. -/ def Node.toPenroseVar (n : Node) : PenroseVar := ⟨"E", [n.vPos, n.hPosSrc, n.hPosTar], n.e⟩ -/-- The penrose variable assciated with a strand. -/ +/-- The penrose variable associated with a strand. -/ def Strand.toPenroseVar (s : Strand) : PenroseVar := ⟨"f", [s.vPos, s.hPos], s.atom₁.e⟩ @@ -243,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 @@ -274,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. -/ @@ -318,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] @@ -361,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/Tactic/Zify.lean b/Mathlib/Tactic/Zify.lean index 8123df3c5de73..ff226759fce03 100644 --- a/Mathlib/Tactic/Zify.lean +++ b/Mathlib/Tactic/Zify.lean @@ -117,3 +117,7 @@ variable {R : Type*} [AddGroupWithOne R] @[norm_cast] theorem Nat.cast_sub_of_lt {m n} (h : m < n) : ((n - m : ℕ) : R) = n - m := Nat.cast_sub h.le + +end Zify + +end Mathlib.Tactic diff --git a/Mathlib/Testing/SlimCheck/Functions.lean b/Mathlib/Testing/SlimCheck/Functions.lean index 7f0f7d67f8cb1..80acb2790dfaf 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 @@ -324,18 +323,18 @@ 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 - simp only [List.NodupKeys, List.keys, comp, Prod.fst_toSigma, List.map_map] + simp only [List.NodupKeys, List.keys, comp_def, Prod.fst_toSigma, List.map_map] rwa [List.map_fst_zip _ _ (le_of_eq h₆)] theorem List.applyId_eq_self [DecidableEq α] {xs ys : List α} (x : α) : @@ -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 @@ -430,9 +429,9 @@ protected def shrink {α : Type} [DecidableEq α] : have h₄ : ys'.length ≤ xs'.length := le_of_eq (List.Perm.length_eq h₀.symm) pure ⟨(List.zip xs' ys').map Prod.toSigma, - by simp only [comp, List.map_fst_zip, List.map_snd_zip, *, Prod.fst_toSigma, + by simp only [comp_def, List.map_fst_zip, List.map_snd_zip, *, Prod.fst_toSigma, Prod.snd_toSigma, List.map_map], - by simp only [comp, List.map_snd_zip, *, Prod.snd_toSigma, List.map_map]⟩ + by simp only [comp_def, List.map_snd_zip, *, Prod.snd_toSigma, List.map_map]⟩ /-- Create an injective function from one list and a permutation of that list. -/ protected def mk (xs ys : List α) (h : xs ~ ys) (h' : ys.Nodup) : InjectiveFunction α := @@ -440,9 +439,9 @@ protected def mk (xs ys : List α) (h : xs ~ ys) (h' : ys.Nodup) : InjectiveFunc have h₁ : ys.length ≤ xs.length := le_of_eq h.length_eq.symm InjectiveFunction.mapToSelf (List.toFinmap' (xs.zip ys)) (by - simp only [List.toFinmap', comp, List.map_fst_zip, List.map_snd_zip, *, Prod.fst_toSigma, + simp only [List.toFinmap', comp_def, List.map_fst_zip, List.map_snd_zip, *, Prod.fst_toSigma, Prod.snd_toSigma, List.map_map]) - (by simp only [List.toFinmap', comp, List.map_snd_zip, *, Prod.snd_toSigma, List.map_map]) + (by simp only [List.toFinmap', comp_def, List.map_snd_zip, *, Prod.snd_toSigma, List.map_map]) protected theorem injective [DecidableEq α] (f : InjectiveFunction α) : Injective (apply f) := by cases' f with xs hperm hnodup @@ -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 a650357f85e5b..0f3d66842989e 100644 --- a/Mathlib/Testing/SlimCheck/Gen.lean +++ b/Mathlib/Testing/SlimCheck/Gen.lean @@ -92,7 +92,7 @@ def oneOf (xs : Array (Gen α)) (pos : 0 < xs.size := by decide) : Gen α := do /-- Given a list of examples, choose one to create an example. -/ def elements (xs : List α) (pos : 0 < xs.length) : Gen α := do let ⟨x, _, h2⟩ ← ULiftable.up <| chooseNatLt 0 xs.length pos - pure <| xs.get ⟨x, h2⟩ + pure <| xs[x] open List in /-- Generate a random permutation of a given list. -/ @@ -111,7 +111,7 @@ def prodOf {α : Type u} {β : Type v} (x : Gen α) (y : Gen β) : Gen (α × β end Gen -/-- Execute a `Gen` inside the `IO` monad using `size` as the example size-/ +/-- Execute a `Gen` inside the `IO` monad using `size` as the example size -/ def Gen.run {α : Type} (x : Gen α) (size : Nat) : BaseIO α := letI : MonadLift Id BaseIO := ⟨fun f => pure <| Id.run f⟩ IO.runRand (ReaderT.run x ⟨size⟩:) diff --git a/Mathlib/Testing/SlimCheck/Sampleable.lean b/Mathlib/Testing/SlimCheck/Sampleable.lean index 6e6da32e42935..f5cedcf3cb680 100644 --- a/Mathlib/Testing/SlimCheck/Sampleable.lean +++ b/Mathlib/Testing/SlimCheck/Sampleable.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Henrik Böving, Simon Hudon -/ import Mathlib.Algebra.Order.Ring.Int -import Mathlib.Init.Data.List.Instances +import Mathlib.Data.List.Monad import Mathlib.Testing.SlimCheck.Gen /-! @@ -220,7 +220,7 @@ instance Bool.sampleableExt : SampleableExt Bool := /-- This can be specialized into customized `SampleableExt Char` instances. The resulting instance has `1 / length` chances of making an unrestricted choice of characters -and it otherwise chooses a character from `chars` with uniform probabilities. -/ +and it otherwise chooses a character from `chars` with uniform probabilities. -/ def Char.sampleable (length : Nat) (chars : List Char) (pos : 0 < chars.length) : SampleableExt Char := mkSelfContained do @@ -256,7 +256,7 @@ instance List.sampleableExt [SampleableExt α] : SampleableExt (List α) where end Samplers -/-- An annotation for values that should never get shrinked. -/ +/-- An annotation for values that should never get shrunk. -/ def NoShrink (α : Type u) := α namespace NoShrink diff --git a/Mathlib/Testing/SlimCheck/Testable.lean b/Mathlib/Testing/SlimCheck/Testable.lean index e4ece33e569d8..af3278d4fc34d 100644 --- a/Mathlib/Testing/SlimCheck/Testable.lean +++ b/Mathlib/Testing/SlimCheck/Testable.lean @@ -423,7 +423,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..455d1c1792743 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,45 +114,6 @@ 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) : AlexandrovDiscrete β where isOpen_sInter S hS := by @@ -163,20 +122,6 @@ 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⟩ end lemma AlexandrovDiscrete.sup {t₁ t₂ : TopologicalSpace α} (_ : @AlexandrovDiscrete α t₁) @@ -194,7 +139,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,47 +165,25 @@ 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 diff --git a/Mathlib/Topology/Algebra/Algebra.lean b/Mathlib/Topology/Algebra/Algebra.lean index c229209194995..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 @@ -241,7 +241,7 @@ whose `TopologicalClosure` is `⊤` is sent to another such submodule. That is, the image of a dense subalgebra under a map with dense range is dense. -/ theorem _root_.DenseRange.topologicalClosure_map_subalgebra - [TopologicalSemiring B] {f : A →A[R] B} (hf' : DenseRange f) {s : Subalgebra R A} + [TopologicalSemiring B] {f : A →A[R] B} (hf' : DenseRange f) {s : Subalgebra R A} (hs : s.topologicalClosure = ⊤) : (s.map (f : A →ₐ[R] B)).topologicalClosure = ⊤ := by rw [SetLike.ext'_iff] at hs ⊢ simp only [Subalgebra.topologicalClosure_coe, coe_top, ← dense_iff_closure_eq, Subalgebra.coe_map, @@ -408,7 +408,7 @@ theorem fst_comp_prod (f : A →A[R] B) (g : A →A[R] C) : ext fun _x => rfl @[simp] -theorem snd_comp_prod (f : A →A[R] B) (g : A →A[R] C) : +theorem snd_comp_prod (f : A →A[R] B) (g : A →A[R] C) : (snd R B C).comp (f.prod g) = g := ext fun _x => rfl 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/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 53ea74c2fe338..7f721b2b8dbdd 100644 --- a/Mathlib/Topology/Algebra/ConstMulAction.lean +++ b/Mathlib/Topology/Algebra/ConstMulAction.lean @@ -79,7 +79,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) : @@ -141,6 +141,13 @@ theorem Inseparable.const_smul {x y : α} (h : Inseparable x y) (c : M) : Inseparable (c • x) (c • y) := 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) : + ContinuousConstSMul N β where + continuous_const_smul c := by + simpa only [Function.comp_def, hf, hg.continuous_iff] using hg.continuous.const_smul (f c) + end SMul section Monoid @@ -444,6 +451,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."] @@ -504,7 +516,7 @@ alias set_smul_mem_nhds_smul_iff := smul_mem_nhds_smul_iff₀ alias ⟨_, smul_mem_nhds_smul₀⟩ := smul_mem_nhds_smul_iff₀ -@[deprecated smul_mem_nhds_smul₀ (since := "2024-08-06")] +@[deprecated smul_mem_nhds_smul₀ (since := "2024-08-06")] theorem set_smul_mem_nhds_smul {c : G₀} {s : Set α} {x : α} (hs : s ∈ 𝓝 x) (hc : c ≠ 0) : c • s ∈ 𝓝 (c • x : α) := smul_mem_nhds_smul₀ hc hs diff --git a/Mathlib/Topology/Algebra/Constructions.lean b/Mathlib/Topology/Algebra/Constructions.lean index 4ca7adfa8c318..96db33647784a 100644 --- a/Mathlib/Topology/Algebra/Constructions.lean +++ b/Mathlib/Topology/Algebra/Constructions.lean @@ -140,7 +140,7 @@ 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, (· ∘ ·), + simp only [inducing_embedProduct.continuous_iff, embedProduct_apply, Function.comp_def, continuous_prod_mk, opHomeomorph.symm.inducing.continuous_iff, opHomeomorph_symm_apply, unop_op] 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..4e852f064519b 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 @@ -265,7 +269,7 @@ instance [T2Space B] : T2Space (ContinuousMonoidHom A B) := instance : TopologicalGroup (ContinuousMonoidHom A E) := let hi := inducing_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] @@ -280,7 +284,7 @@ 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 <| ContinuousMap.continuous_comp'.comp - ((inducing_toContinuousMap A B).prod_map (inducing_toContinuousMap B C)).continuous + ((inducing_toContinuousMap A B).prodMap (inducing_toContinuousMap B C)).continuous @[to_additive] theorem continuous_comp_left (f : ContinuousMonoidHom A B) : 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/FilterBasis.lean b/Mathlib/Topology/Algebra/FilterBasis.lean index 63619d775c916..e2732d46cdbb7 100644 --- a/Mathlib/Topology/Algebra/FilterBasis.lean +++ b/Mathlib/Topology/Algebra/FilterBasis.lean @@ -84,7 +84,7 @@ variable {G : Type u} [Group G] {B : GroupFilterBasis G} @[to_additive] instance : Membership (Set G) (GroupFilterBasis G) := - ⟨fun s f ↦ s ∈ f.sets⟩ + ⟨fun f s ↦ s ∈ f.sets⟩ @[to_additive] theorem one {U : Set G} : U ∈ B → (1 : G) ∈ U := @@ -149,10 +149,10 @@ theorem nhds_eq (B : GroupFilterBasis G) {x₀ : G} : @nhds G B.topology x₀ = filter_upwards [image_mem_map (B.mem_filter_of_mem V_in)] rintro _ ⟨x, hx, rfl⟩ calc - a • U ⊇ a • (V * V) := smul_set_mono hVU - _ ⊇ a • x • V := smul_set_mono <| smul_set_subset_smul hx - _ = (a * x) • V := smul_smul .. - _ ∈ (a * x) • B.filter := smul_set_mem_smul_filter <| B.mem_filter_of_mem V_in + (a * x) • V ∈ (a * x) • B.filter := smul_set_mem_smul_filter <| B.mem_filter_of_mem V_in + _ = a • x • V := smul_smul .. |>.symm + _ ⊆ a • (V * V) := smul_set_mono <| smul_set_subset_smul hx + _ ⊆ a • U := smul_set_mono hVU @[to_additive] theorem nhds_one_eq (B : GroupFilterBasis G) : @@ -224,7 +224,7 @@ namespace RingFilterBasis variable {R : Type u} [Ring R] (B : RingFilterBasis R) instance : Membership (Set R) (RingFilterBasis R) := - ⟨fun s B ↦ s ∈ B.sets⟩ + ⟨fun B s ↦ s ∈ B.sets⟩ theorem mul {U : Set R} (hU : U ∈ B) : ∃ V ∈ B, V * V ⊆ U := mul' hU @@ -284,7 +284,7 @@ variable {R M : Type*} [CommRing R] [TopologicalSpace R] [AddCommGroup M] [Modul (B : ModuleFilterBasis R M) instance GroupFilterBasis.hasMem : Membership (Set M) (ModuleFilterBasis R M) := - ⟨fun s B ↦ s ∈ B.sets⟩ + ⟨fun B s ↦ s ∈ B.sets⟩ theorem smul {U : Set M} (hU : U ∈ B) : ∃ V ∈ 𝓝 (0 : R), ∃ W ∈ B, V • W ⊆ U := B.smul' hU diff --git a/Mathlib/Topology/Algebra/Group/Basic.lean b/Mathlib/Topology/Algebra/Group/Basic.lean index 8b8f83b53c3bc..49c268a901a0c 100644 --- a/Mathlib/Topology/Algebra/Group/Basic.lean +++ b/Mathlib/Topology/Algebra/Group/Basic.lean @@ -5,10 +5,11 @@ Authors: Johannes Hölzl, Mario Carneiro, Patrick Massot -/ import Mathlib.GroupTheory.GroupAction.ConjAct import Mathlib.GroupTheory.GroupAction.Quotient -import Mathlib.GroupTheory.QuotientGroup import Mathlib.Topology.Algebra.Monoid import Mathlib.Topology.Algebra.Constructions +import Mathlib.Topology.Maps.OpenQuotient import Mathlib.Algebra.Order.Archimedean.Basic +import Mathlib.GroupTheory.QuotientGroup.Basic /-! # Topological groups @@ -164,7 +165,7 @@ theorem ContinuousInv.induced {α : Type*} {β : Type*} {F : Type*} [FunLike F @ContinuousInv α (tβ.induced f) _ := by let _tα := tβ.induced f refine ⟨continuous_induced_rng.2 ?_⟩ - simp only [Function.comp, map_inv] + simp only [Function.comp_def, map_inv] fun_prop @[to_additive] @@ -304,6 +305,10 @@ protected def Homeomorph.inv (G : Type*) [TopologicalSpace G] [InvolutiveInv G] lemma Homeomorph.coe_inv {G : Type*} [TopologicalSpace G] [InvolutiveInv G] [ContinuousInv G] : ⇑(Homeomorph.inv G) = Inv.inv := rfl +@[to_additive] +theorem nhds_inv (a : G) : 𝓝 a⁻¹ = (𝓝 a)⁻¹ := + ((Homeomorph.inv G).map_nhds_eq a).symm + @[to_additive] theorem isOpenMap_inv : IsOpenMap (Inv.inv : G → G) := (Homeomorph.inv _).isOpenMap @@ -376,7 +381,7 @@ end LatticeOps theorem Inducing.continuousInv {G H : Type*} [Inv G] [Inv H] [TopologicalSpace G] [TopologicalSpace H] [ContinuousInv H] {f : G → H} (hf : Inducing f) (hf_inv : ∀ x, f x⁻¹ = (f x)⁻¹) : ContinuousInv G := - ⟨hf.continuous_iff.2 <| by simpa only [(· ∘ ·), hf_inv] using hf.continuous.inv⟩ + ⟨hf.continuous_iff.2 <| by simpa only [Function.comp_def, hf_inv] using hf.continuous.inv⟩ section TopologicalGroup @@ -531,7 +536,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)] @@ -742,8 +747,8 @@ theorem continuous_of_continuousAt_one {M hom : Type*} [MulOneClass M] [Topologi (hf : ContinuousAt f 1) : Continuous f := continuous_iff_continuousAt.2 fun x => by - simpa only [ContinuousAt, ← map_mul_left_nhds_one x, tendsto_map'_iff, (· ∘ ·), map_mul, - map_one, mul_one] using hf.tendsto.const_mul (f x) + simpa only [ContinuousAt, ← map_mul_left_nhds_one x, tendsto_map'_iff, Function.comp_def, + map_mul, map_one, mul_one] using hf.tendsto.const_mul (f x) @[to_additive continuous_of_continuousAt_zero₂] theorem continuous_of_continuousAt_one₂ {H M : Type*} [CommMonoid M] [TopologicalSpace M] @@ -752,7 +757,7 @@ theorem continuous_of_continuousAt_one₂ {H M : Type*} [CommMonoid M] [Topologi (hl : ∀ x, ContinuousAt (f x) 1) (hr : ∀ y, ContinuousAt (f · y) 1) : Continuous (fun x : G × H ↦ f x.1 x.2) := continuous_iff_continuousAt.2 fun (x, y) => by simp only [ContinuousAt, nhds_prod_eq, ← map_mul_left_nhds_one x, ← map_mul_left_nhds_one y, - prod_map_map_eq, tendsto_map'_iff, (· ∘ ·), map_mul, MonoidHom.mul_apply] at * + prod_map_map_eq, tendsto_map'_iff, Function.comp_def, map_mul, MonoidHom.mul_apply] at * refine ((tendsto_const_nhds.mul ((hr y).comp tendsto_fst)).mul (((hl x).comp tendsto_snd).mul hf)).mono_right (le_of_eq ?_) simp only [map_one, mul_one, MonoidHom.one_apply] @@ -778,8 +783,8 @@ theorem ContinuousInv.of_nhds_one {G : Type*} [Group G] [TopologicalSpace G] refine ⟨continuous_iff_continuousAt.2 fun x₀ => ?_⟩ have : Tendsto (fun x => x₀⁻¹ * (x₀ * x⁻¹ * x₀⁻¹)) (𝓝 1) (map (x₀⁻¹ * ·) (𝓝 1)) := (tendsto_map.comp <| hconj x₀).comp hinv - simpa only [ContinuousAt, hleft x₀, hleft x₀⁻¹, tendsto_map'_iff, (· ∘ ·), mul_assoc, mul_inv_rev, - inv_mul_cancel_left] using this + simpa only [ContinuousAt, hleft x₀, hleft x₀⁻¹, tendsto_map'_iff, Function.comp_def, mul_assoc, + mul_inv_rev, inv_mul_cancel_left] using this @[to_additive] theorem TopologicalGroup.of_nhds_one' {G : Type u} [Group G] [TopologicalSpace G] @@ -806,7 +811,7 @@ theorem TopologicalGroup.of_nhds_one {G : Type u} [Group G] [TopologicalSpace G] replace hconj : ∀ x₀ : G, map (x₀ * · * x₀⁻¹) (𝓝 1) = 𝓝 1 := fun x₀ => map_eq_of_inverse (x₀⁻¹ * · * x₀⁻¹⁻¹) (by ext; simp [mul_assoc]) (hconj _) (hconj _) rw [← hconj x₀] - simpa [(· ∘ ·)] using hleft _ + simpa [Function.comp_def] using hleft _ @[to_additive] theorem TopologicalGroup.of_comm_of_nhds_one {G : Type u} [CommGroup G] [TopologicalSpace G] @@ -815,52 +820,7 @@ theorem TopologicalGroup.of_comm_of_nhds_one {G : Type u} [CommGroup G] [Topolog (hleft : ∀ x₀ : G, 𝓝 x₀ = map (x₀ * ·) (𝓝 1)) : TopologicalGroup G := TopologicalGroup.of_nhds_one hmul hinv hleft (by simpa using tendsto_id) -end TopologicalGroup - -section QuotientTopologicalGroup - -variable [TopologicalSpace G] [Group G] [TopologicalGroup G] (N : Subgroup G) (n : N.Normal) - -@[to_additive] -instance QuotientGroup.Quotient.topologicalSpace {G : Type*} [Group G] [TopologicalSpace G] - (N : Subgroup G) : TopologicalSpace (G ⧸ N) := - instTopologicalSpaceQuotient - -open QuotientGroup - -@[to_additive] -theorem QuotientGroup.isOpenMap_coe : IsOpenMap ((↑) : G → G ⧸ N) := by - intro s s_op - change IsOpen (((↑) : G → G ⧸ N) ⁻¹' ((↑) '' s)) - rw [QuotientGroup.preimage_image_mk N s] - exact isOpen_iUnion fun n => (continuous_mul_right _).isOpen_preimage s s_op - -@[to_additive] -instance topologicalGroup_quotient [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 := by - have quot := IsOpenMap.to_quotientMap - (QuotientGroup.isOpenMap_coe N) continuous_quot_mk (surjective_quot_mk _) - rw [quot.continuous_iff] - exact continuous_quot_mk.comp continuous_inv - -/-- 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 QuotientGroup.nhds_eq (x : G) : 𝓝 (x : G ⧸ N) = Filter.map (↑) (𝓝 x) := - le_antisymm ((QuotientGroup.isOpenMap_coe N).nhds_le x) continuous_quot_mk.continuousAt - -variable (G) -variable [FirstCountableTopology G] - +variable (G) in /-- Any first countable topological group has an antitone neighborhood basis `u : ℕ → Set G` for which `(u (n + 1)) ^ 2 ⊆ u n`. The existence of such a neighborhood basis is a key tool for `QuotientGroup.completeSpace` -/ @@ -868,7 +828,7 @@ which `(u (n + 1)) ^ 2 ⊆ u n`. The existence of such a neighborhood basis is a "Any first countable topological additive group has an antitone neighborhood basis `u : ℕ → set G` for which `u (n + 1) + u (n + 1) ⊆ u n`. The existence of such a neighborhood basis is a key tool for `QuotientAddGroup.completeSpace`"] -theorem TopologicalGroup.exists_antitone_basis_nhds_one : +theorem TopologicalGroup.exists_antitone_basis_nhds_one [FirstCountableTopology G] : ∃ u : ℕ → Set G, (𝓝 1).HasAntitoneBasis u ∧ ∀ n, u (n + 1) * u (n + 1) ⊆ u n := by rcases (𝓝 (1 : G)).exists_antitone_basis with ⟨u, hu, u_anti⟩ have := @@ -885,15 +845,88 @@ theorem TopologicalGroup.exists_antitone_basis_nhds_one : obtain ⟨φ, -, hφ, φ_anti_basis⟩ := HasAntitoneBasis.subbasis_with_rel ⟨hu, u_anti⟩ event_mul exact ⟨u ∘ φ, φ_anti_basis, fun n => hφ n.lt_succ_self⟩ -/-- In a first countable topological group `G` with normal subgroup `N`, `1 : G ⧸ N` has a -countable neighborhood basis. -/ +end TopologicalGroup + +namespace QuotientGroup + +variable [TopologicalSpace G] [Group G] + +@[to_additive] +instance instTopologicalSpace (N : Subgroup G) : TopologicalSpace (G ⧸ N) := + instTopologicalSpaceQuotient + +@[to_additive] +instance [CompactSpace G] (N : Subgroup G) : CompactSpace (G ⧸ N) := + Quotient.compactSpace + +@[to_additive] +theorem quotientMap_mk (N : Subgroup G) : QuotientMap (mk : G → G ⧸ N) := + quotientMap_quot_mk + +@[to_additive] +theorem continuous_mk {N : Subgroup G} : Continuous (mk : G → G ⧸ N) := + continuous_quot_mk + +section ContinuousMul + +variable [ContinuousMul G] {N : Subgroup G} + +@[to_additive] +theorem isOpenMap_coe : IsOpenMap ((↑) : G → G ⧸ N) := isOpenMap_quotient_mk'_mul + +@[to_additive] +theorem isOpenQuotientMap_mk : IsOpenQuotientMap (mk : G → G ⧸ N) := + MulAction.isOpenQuotientMap_quotientMk + +@[to_additive (attr := simp)] +theorem dense_preimage_mk {s : Set (G ⧸ N)} : Dense ((↑) ⁻¹' s : Set G) ↔ Dense s := + isOpenQuotientMap_mk.dense_preimage_iff + +@[to_additive] +theorem dense_image_mk {s : Set G} : + Dense (mk '' s : Set (G ⧸ N)) ↔ Dense (s * (N : Set G)) := by + rw [← dense_preimage_mk, preimage_image_mk_eq_mul] + +@[to_additive] +instance instContinuousSMul : ContinuousSMul G (G ⧸ N) where + continuous_smul := by + rw [← (IsOpenQuotientMap.id.prodMap isOpenQuotientMap_mk).continuous_comp_iff] + exact continuous_mk.comp continuous_mul + +variable (N) + +/-- Neighborhoods in the quotient are precisely the map of neighborhoods in the prequotient. -/ @[to_additive - "In a first countable topological additive group `G` with normal additive subgroup - `N`, `0 : G ⧸ N` has a countable neighborhood basis."] -instance QuotientGroup.nhds_one_isCountablyGenerated : (𝓝 (1 : G ⧸ N)).IsCountablyGenerated := - (QuotientGroup.nhds_eq N 1).symm ▸ map.isCountablyGenerated _ _ + "Neighborhoods in the quotient are precisely the map of neighborhoods in the prequotient."] +theorem nhds_eq (x : G) : 𝓝 (x : G ⧸ N) = Filter.map (↑) (𝓝 x) := + (isOpenQuotientMap_mk.map_nhds_eq _).symm + +@[to_additive] +instance instFirstCountableTopology [FirstCountableTopology G] : + FirstCountableTopology (G ⧸ N) where + nhds_generated_countable := mk_surjective.forall.2 fun x ↦ nhds_eq N x ▸ inferInstance + +@[to_additive (attr := deprecated (since := "2024-08-05"))] +theorem nhds_one_isCountablyGenerated [FirstCountableTopology G] [N.Normal] : + (𝓝 (1 : G ⧸ N)).IsCountablyGenerated := + inferInstance -end QuotientTopologicalGroup +end ContinuousMul + +variable [TopologicalGroup G] (N : Subgroup G) + +@[to_additive] +instance instTopologicalGroup [N.Normal] : TopologicalGroup (G ⧸ N) where + continuous_mul := by + rw [← (isOpenQuotientMap_mk.prodMap isOpenQuotientMap_mk).continuous_comp_iff] + exact continuous_mk.comp continuous_mul + continuous_inv := continuous_inv.quotient_map' _ + +@[to_additive (attr := deprecated (since := "2024-08-05"))] +theorem _root_.topologicalGroup_quotient [N.Normal] : TopologicalGroup (G ⧸ N) := + instTopologicalGroup N + +end QuotientGroup /-- A typeclass saying that `p : G × G ↦ p.1 - p.2` is a continuous function. This property automatically holds for topological additive groups but it also holds, e.g., for `ℝ≥0`. -/ @@ -1221,11 +1254,8 @@ theorem IsClosed.mul_right_of_isCompact (ht : IsClosed t) (hs : IsCompact s) : theorem QuotientGroup.isClosedMap_coe {H : Subgroup G} (hH : IsCompact (H : Set G)) : IsClosedMap ((↑) : G → G ⧸ H) := by intro t ht - rw [← quotientMap_quotient_mk'.isClosed_preimage] - convert ht.mul_right_of_isCompact hH - refine (QuotientGroup.preimage_image_mk_eq_iUnion_image _ _).trans ?_ - rw [iUnion_subtype, ← iUnion_mul_right_image] - rfl + 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) : @@ -1396,7 +1426,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 @@ -1597,7 +1627,7 @@ instance [LocallyCompactSpace G] (N : Subgroup G) : LocallyCompactSpace (G ⧸ N 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, + exact ⟨π '' s, QuotientGroup.isOpenMap_coe.image_mem_nhds s_mem, mapsTo'.mp hs, s_comp.image C⟩ end @@ -1846,8 +1876,6 @@ instance : SemilatticeInf (GroupTopology α) := instance : Inhabited (GroupTopology α) := ⟨⊤⟩ -local notation "cont" => @Continuous _ _ - /-- Infimum of a collection of group topologies. -/ @[to_additive "Infimum of a collection of additive group topologies"] instance : InfSet (GroupTopology α) where @@ -1915,3 +1943,5 @@ theorem coinduced_continuous {α β : Type*} [t : TopologicalSpace α] [Group β exact continuous_iff_coinduced_le.2 ht' end GroupTopology + +set_option linter.style.longFile 2100 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/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..5935b46b343e8 100644 --- a/Mathlib/Topology/Algebra/GroupCompletion.lean +++ b/Mathlib/Topology/Algebra/GroupCompletion.lean @@ -136,8 +136,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 +181,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 a363dc902e11b..b601051b87dc5 100644 --- a/Mathlib/Topology/Algebra/GroupWithZero.lean +++ b/Mathlib/Topology/Algebra/GroupWithZero.lean @@ -142,7 +142,7 @@ lemma nhds_inv₀ (hx : x ≠ 0) : 𝓝 x⁻¹ = (𝓝 x)⁻¹ := by lemma tendsto_inv_iff₀ {l : Filter α} {f : α → G₀} (hx : x ≠ 0) : Tendsto (fun x ↦ (f x)⁻¹) l (𝓝 x⁻¹) ↔ Tendsto f l (𝓝 x) := by - simp only [nhds_inv₀ hx, ← Filter.comap_inv, tendsto_comap_iff, (· ∘ ·), inv_inv] + simp only [nhds_inv₀ hx, ← Filter.comap_inv, tendsto_comap_iff, Function.comp_def, inv_inv] end NhdsInv @@ -300,7 +300,7 @@ theorem HasContinuousInv₀.of_nhds_one (h : Tendsto Inv.inv (𝓝 (1 : G₀)) ( have hx' := inv_ne_zero hx rw [ContinuousAt, ← map_mul_left_nhds_one₀ hx, ← nhds_translation_mul_inv₀ hx', tendsto_map'_iff, tendsto_comap_iff] - simpa only [(· ∘ ·), mul_inv_rev, mul_inv_cancel_right₀ hx'] + simpa only [Function.comp_def, mul_inv_rev, mul_inv_cancel_right₀ hx'] end map_comap diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean b/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean index 9642c81b12ef4..bc17c8afdc322 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Basic.lean @@ -204,7 +204,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) diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Constructions.lean b/Mathlib/Topology/Algebra/InfiniteSum/Constructions.lean index c68372a5f2ce0..b47e95b56f4ad 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Constructions.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Constructions.lean @@ -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.filter fun p ↦ p.1 ∈ t0, f p) atTop + (𝓝 <| ∏ b ∈ t0, g b) := by + simp only [← sigma_preimage_mk, prod_sigma] + refine tendsto_finset_prod _ fun b _ ↦ ?_ + change + Tendsto (fun t ↦ (fun t ↦ ∏ s ∈ t, f ⟨b, s⟩) (preimage t (Sigma.mk b) _)) atTop (𝓝 (g b)) + exact (hf b).comp (tendsto_finset_preimage_atTop_atTop (sigma_mk_injective)) + have : ∃ t, ∏ p ∈ t.filter (fun p ↦ p.1 ∈ t0), f p ∈ v ∧ s ⊆ t := + ((Tendsto.eventually_mem L (v_open.mem_nhds st0)).and (Ici_mem_atTop _)).exists + obtain ⟨t, tv, st⟩ := this + refine ⟨t.filter (fun p ↦ p.1 ∈ t0), fun x hx ↦ ?_, vu tv⟩ + 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 53d82a6d80536..92ae820ce40a0 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 /-! # Infinite sum and product over a topological monoid @@ -90,8 +91,10 @@ def Multipliable (f : β → α) : Prop := ∃ a, HasProd f a open scoped Classical in -/-- `∏' i, f i` is the product of `f` it exists, or 1 otherwise. -/ -@[to_additive "`∑' i, f i` is the sum of `f` it exists, or 0 otherwise."] +/-- `∏' i, f i` is the product of `f` if it exists and is unconditionally convergent, +or 1 otherwise. -/ +@[to_additive "`∑' i, f i` is the sum of `f` if it exists and is unconditionally convergent, +or 0 otherwise."] noncomputable irreducible_def tprod {β} (f : β → α) := if h : Multipliable f then /- Note that the product might not be uniquely defined if the topology is not separated. diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Group.lean b/Mathlib/Topology/Algebra/InfiniteSum/Group.lean index c73c289acf3f5..9532cd4e53ab9 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Group.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Group.lean @@ -3,6 +3,7 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl -/ +import Mathlib.SetTheory.Cardinal.Finite import Mathlib.Topology.Algebra.InfiniteSum.Basic import Mathlib.Topology.Algebra.UniformGroup @@ -179,7 +180,7 @@ theorem cauchySeq_finset_iff_prod_vanishing : ∀ e ∈ 𝓝 (1 : α), ∃ s : Finset β, ∀ t, Disjoint t s → (∏ b ∈ t, f b) ∈ e := by classical simp only [CauchySeq, cauchy_map_iff, and_iff_right atTop_neBot, prod_atTop_atTop_eq, - uniformity_eq_comap_nhds_one α, tendsto_comap_iff, (· ∘ ·), atTop_neBot, true_and] + uniformity_eq_comap_nhds_one α, tendsto_comap_iff, Function.comp_def, atTop_neBot, true_and] rw [tendsto_atTop'] constructor · intro h e he @@ -209,7 +210,7 @@ theorem cauchySeq_finset_iff_tprod_vanishing : refine ⟨s, fun t hts ↦ oe ?_⟩ by_cases ht : Multipliable fun a : t ↦ f a · classical - refine o_closed.mem_of_tendsto ht.hasProd (eventually_of_forall fun t' ↦ ?_) + refine o_closed.mem_of_tendsto ht.hasProd (Eventually.of_forall fun t' ↦ ?_) rw [← prod_subtype_map_embedding fun _ _ ↦ by rfl] apply hs simp_rw [Finset.mem_map] 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/Module.lean b/Mathlib/Topology/Algebra/InfiniteSum/Module.lean index 1201d78d799cc..e8ef8f1cd13dc 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Module.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Module.lean @@ -240,7 +240,7 @@ variable {G : Type*} [Group G] {Γ : Subgroup G} @[to_additive "Given a subgroup `Γ` of an additive group `G`, and a function `f : G → M`, we automorphize `f` to a function `G ⧸ Γ → M` by summing over `Γ` orbits, `g ↦ ∑' (γ : Γ), f(γ • g)`."] -noncomputable def QuotientGroup.automorphize (f : G → M) : G ⧸ Γ → M := MulAction.automorphize f +noncomputable def QuotientGroup.automorphize (f : G → M) : G ⧸ Γ → M := MulAction.automorphize f /-- Automorphization of a function into an `R`-`Module` distributes, that is, commutes with the `R`-scalar multiplication. -/ diff --git a/Mathlib/Topology/Algebra/InfiniteSum/NatInt.lean b/Mathlib/Topology/Algebra/InfiniteSum/NatInt.lean index 09d1d25020184..688be889d23d8 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/NatInt.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/NatInt.lean @@ -74,7 +74,7 @@ theorem even_mul_odd {f : ℕ → M} (he : HasProd (fun k ↦ f (2 * k)) m) have := mul_right_injective₀ (two_ne_zero' ℕ) replace ho := ((add_left_injective 1).comp this).hasProd_range_iff.2 ho refine (this.hasProd_range_iff.2 he).mul_isCompl ?_ ho - simpa [(· ∘ ·)] using Nat.isCompl_even_odd + simpa [Function.comp_def] using Nat.isCompl_even_odd end ContinuousMul @@ -324,7 +324,7 @@ lemma HasProd.nat_mul_neg_add_one {f : ℤ → M} (hf : HasProd f m) : · rw [prod_union, prod_image Nat.cast_injective.injOn, prod_image this.injOn, prod_mul_distrib] simp only [disjoint_iff_ne, mem_image, ne_eq, forall_exists_index, and_imp, - forall_apply_eq_imp_iff₂, not_false_eq_true, implies_true, forall_const] + forall_apply_eq_imp_iff₂, not_false_eq_true, implies_true, forall_const, reduceCtorEq] @[to_additive Summable.nat_add_neg_add_one] lemma Multipliable.nat_mul_neg_add_one {f : ℤ → M} (hf : Multipliable f) : @@ -358,7 +358,7 @@ lemma HasProd.of_nat_of_neg_add_one {f : ℤ → M} @[to_additive Summable.of_nat_of_neg_add_one] lemma Multipliable.of_nat_of_neg_add_one {f : ℤ → M} - (hf₁ : Multipliable fun n : ℕ ↦ f n) (hf₂ : Multipliable fun n : ℕ ↦ f (-(n + 1))) : + (hf₁ : Multipliable fun n : ℕ ↦ f n) (hf₂ : Multipliable fun n : ℕ ↦ f (-(n + 1))) : Multipliable f := (hf₁.hasProd.of_nat_of_neg_add_one hf₂.hasProd).multipliable diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Nonarchimedean.lean b/Mathlib/Topology/Algebra/InfiniteSum/Nonarchimedean.lean index 953e8155df310..30d1d7e493bc0 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Nonarchimedean.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Nonarchimedean.lean @@ -3,6 +3,7 @@ Copyright (c) 2024 Mitchell Lee. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mitchell Lee -/ +import Mathlib.Algebra.Group.Subgroup.Finite import Mathlib.Topology.Algebra.InfiniteSum.Group import Mathlib.Topology.Algebra.Nonarchimedean.Basic diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Order.lean b/Mathlib/Topology/Algebra/InfiniteSum/Order.lean index e0e206d0522bb..88fad0d581136 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Order.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Order.lean @@ -14,9 +14,7 @@ import Mathlib.Topology.Order.MonotoneConvergence This file provides lemmas about the interaction of infinite sums and products and order operations. -/ - open Finset Filter Function -open scoped Classical variable {ι κ α : Type*} @@ -42,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 @@ -91,8 +89,9 @@ theorem prod_le_hasProd (s : Finset ι) (hs : ∀ i, i ∉ s → 1 ≤ f i) (hf @[to_additive] theorem isLUB_hasProd (h : ∀ i, 1 ≤ f i) (hf : HasProd f a) : - IsLUB (Set.range fun s ↦ ∏ i ∈ s, f i) a := - isLUB_of_tendsto_atTop (Finset.prod_mono_set_of_one_le' h) hf + IsLUB (Set.range fun s ↦ ∏ i ∈ s, f i) a := by + classical + exact isLUB_of_tendsto_atTop (Finset.prod_mono_set_of_one_le' h) hf @[to_additive] theorem le_hasProd (hf : HasProd f a) (i : ι) (hb : ∀ j, j ≠ i → 1 ≤ f j) : f i ≤ a := @@ -169,6 +168,7 @@ variable [OrderedCommGroup α] [TopologicalSpace α] [TopologicalGroup α] @[to_additive] theorem hasProd_lt (h : f ≤ g) (hi : f i < g i) (hf : HasProd f a₁) (hg : HasProd g a₂) : a₁ < a₂ := by + classical have : update f i 1 ≤ update g i 1 := update_le_update_iff.mpr ⟨rfl.le, fun i _ ↦ h i⟩ have : 1 / f i * a₁ ≤ 1 / g i * a₂ := hasProd_le this (hf.update i 1) (hg.update i 1) simpa only [one_div, mul_inv_cancel_left] using mul_lt_mul_of_lt_of_le hi this @@ -223,8 +223,9 @@ theorem tprod_ne_one_iff (hf : Multipliable f) : ∏' i, f i ≠ 1 ↔ ∃ x, f rw [Ne, tprod_eq_one_iff hf, not_forall] @[to_additive] -theorem isLUB_hasProd' (hf : HasProd f a) : IsLUB (Set.range fun s ↦ ∏ i ∈ s, f i) a := - isLUB_of_tendsto_atTop (Finset.prod_mono_set' f) hf +theorem isLUB_hasProd' (hf : HasProd f a) : IsLUB (Set.range fun s ↦ ∏ i ∈ s, f i) a := by + classical + exact isLUB_of_tendsto_atTop (Finset.prod_mono_set' f) hf end CanonicallyOrderedCommMonoid @@ -287,4 +288,4 @@ theorem Summable.tendsto_atTop_of_pos [LinearOrderedField α] [TopologicalSpace {f : ℕ → α} (hf : Summable f⁻¹) (hf' : ∀ n, 0 < f n) : Tendsto f atTop atTop := inv_inv f ▸ Filter.Tendsto.inv_tendsto_zero <| tendsto_nhdsWithin_of_tendsto_nhds_of_eventually_within _ hf.tendsto_atTop_zero <| - eventually_of_forall fun _ ↦ inv_pos.2 (hf' _) + Eventually.of_forall fun _ ↦ inv_pos.2 (hf' _) diff --git a/Mathlib/Topology/Algebra/InfiniteSum/Ring.lean b/Mathlib/Topology/Algebra/InfiniteSum/Ring.lean index c98296b0fb61f..6a1e6ade12789 100644 --- a/Mathlib/Topology/Algebra/InfiniteSum/Ring.lean +++ b/Mathlib/Topology/Algebra/InfiniteSum/Ring.lean @@ -17,11 +17,8 @@ This file provides lemmas about the interaction between infinite sums and multip * `tsum_mul_tsum_eq_tsum_sum_antidiagonal`: Cauchy product formula -/ - open Filter Finset Function -open scoped Classical - variable {ι κ R α : Type*} section NonUnitalNonAssocSemiring @@ -51,10 +48,11 @@ theorem Summable.tsum_mul_left (a) (hf : Summable f) : ∑' i, a * f i = a * ∑ theorem Summable.tsum_mul_right (a) (hf : Summable f) : ∑' i, f i * a = (∑' i, f i) * a := (hf.hasSum.mul_right _).tsum_eq -theorem Commute.tsum_right (a) (h : ∀ i, Commute a (f i)) : Commute a (∑' i, f i) := - if hf : Summable f then - (hf.tsum_mul_left a).symm.trans ((congr_arg _ <| funext h).trans (hf.tsum_mul_right a)) - else (tsum_eq_zero_of_not_summable hf).symm ▸ Commute.zero_right _ +theorem Commute.tsum_right (a) (h : ∀ i, Commute a (f i)) : Commute a (∑' i, f i) := by + classical + by_cases hf : Summable f + · exact (hf.tsum_mul_left a).symm.trans ((congr_arg _ <| funext h).trans (hf.tsum_mul_right a)) + · exact (tsum_eq_zero_of_not_summable hf).symm ▸ Commute.zero_right _ theorem Commute.tsum_left (a) (h : ∀ i, Commute (f i) a) : Commute (∑' i, f i) a := (Commute.tsum_right _ fun i ↦ (h i).symm).symm @@ -92,14 +90,16 @@ theorem summable_mul_right_iff (h : a ≠ 0) : (Summable fun i ↦ f i * a) ↔ theorem summable_div_const_iff (h : a ≠ 0) : (Summable fun i ↦ f i / a) ↔ Summable f := by simpa only [div_eq_mul_inv] using summable_mul_right_iff (inv_ne_zero h) -theorem tsum_mul_left [T2Space α] : ∑' x, a * f x = a * ∑' x, f x := - if hf : Summable f then hf.tsum_mul_left a +theorem tsum_mul_left [T2Space α] : ∑' x, a * f x = a * ∑' x, f x := by + classical + exact if hf : Summable f then hf.tsum_mul_left a else if ha : a = 0 then by simp [ha] else by rw [tsum_eq_zero_of_not_summable hf, tsum_eq_zero_of_not_summable (mt (summable_mul_left_iff ha).mp hf), mul_zero] -theorem tsum_mul_right [T2Space α] : ∑' x, f x * a = (∑' x, f x) * a := - if hf : Summable f then hf.tsum_mul_right a +theorem tsum_mul_right [T2Space α] : ∑' x, f x * a = (∑' x, f x) * a := by + classical + exact if hf : Summable f then hf.tsum_mul_right a else if ha : a = 0 then by simp [ha] else by rw [tsum_eq_zero_of_not_summable hf, tsum_eq_zero_of_not_summable (mt (summable_mul_right_iff ha).mp hf), zero_mul] diff --git a/Mathlib/Topology/Algebra/Module/Alternating/Basic.lean b/Mathlib/Topology/Algebra/Module/Alternating/Basic.lean index c6b9bc5f30347..1b43517bdbae1 100644 --- a/Mathlib/Topology/Algebra/Module/Alternating/Basic.lean +++ b/Mathlib/Topology/Algebra/Module/Alternating/Basic.lean @@ -333,8 +333,8 @@ def _root_.ContinuousLinearEquiv.continuousAlternatingMapComp (e : M ≃L[R] M') M [⋀^ι]→L[R] N ≃ M' [⋀^ι]→L[R] N where toFun f := f.compContinuousLinearMap ↑e.symm invFun f := f.compContinuousLinearMap ↑e - left_inv f := by ext; simp [(· ∘ ·)] - right_inv f := by ext; simp [(· ∘ ·)] + left_inv f := by ext; simp [Function.comp_def] + right_inv f := by ext; simp [Function.comp_def] /-- A continuous linear equivalence of codomains defines an equivalence between continuous alternating maps. -/ @@ -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) @@ -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] @@ -618,12 +616,12 @@ def alternatization : ContinuousMultilinearMap R (fun _ : ι => M) N →+ M [⋀ theorem alternatization_apply_apply (v : ι → M) : alternatization f v = ∑ σ : Equiv.Perm ι, Equiv.Perm.sign σ • f (v ∘ σ) := by - simp [alternatization, (· ∘ ·)] + simp [alternatization, Function.comp_def] @[simp] theorem alternatization_apply_toAlternatingMap : (alternatization f).toAlternatingMap = MultilinearMap.alternatization f.1 := by ext v - simp [alternatization_apply_apply, MultilinearMap.alternatization_apply, (· ∘ ·)] + simp [alternatization_apply_apply, MultilinearMap.alternatization_apply, Function.comp_def] end ContinuousMultilinearMap diff --git a/Mathlib/Topology/Algebra/Module/Alternating/Topology.lean b/Mathlib/Topology/Algebra/Module/Alternating/Topology.lean new file mode 100644 index 0000000000000..32efbbd5a39c7 --- /dev/null +++ b/Mathlib/Topology/Algebra/Module/Alternating/Topology.lean @@ -0,0 +1,230 @@ +/- +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.Algebra.Module.Multilinear.Topology +import Mathlib.Topology.Algebra.Module.Alternating.Basic + +/-! +# Topology on continuous alternating maps + +In this file we define `UniformSpace` and `TopologicalSpace` structures +on the space of continuous alternating maps between topological vector spaces. + +The structures are induced by those on `ContinuousMultilinearMap`s, +and most of the lemmas follow from the corresponding lemmas about `ContinuousMultilinearMap`s. +-/ + +open Bornology Function Set +open scoped Topology UniformConvergence Filter + +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 (ContinuousMultilinearMap.continuous_eval_const _) + +end IsClosedRange + +section UniformAddGroup + +variable [UniformSpace F] [UniformAddGroup F] + +instance instUniformSpace : UniformSpace (E [⋀^ι]→L[𝕜] F) := + .comap toContinuousMultilinearMap inferInstance + +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) → _) := + isUniformEmbedding_toContinuousMultilinearMap.uniformContinuous + +theorem uniformContinuous_coe_fun [ContinuousSMul 𝕜 E] : + UniformContinuous (DFunLike.coe : (E [⋀^ι]→L[𝕜] F) → (ι → E) → F) := + ContinuousMultilinearMap.uniformContinuous_coe_fun.comp + uniformContinuous_toContinuousMultilinearMap + +theorem uniformContinuous_eval_const [ContinuousSMul 𝕜 E] (x : ι → E) : + UniformContinuous fun f : E [⋀^ι]→L[𝕜] F ↦ f x := + uniformContinuous_pi.1 uniformContinuous_coe_fun x + +instance instUniformAddGroup : UniformAddGroup (E [⋀^ι]→L[𝕜] F) := + 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) := + isUniformEmbedding_toContinuousMultilinearMap.uniformContinuousConstSMul fun _ _ ↦ rfl + +section CompleteSpace + +variable [ContinuousSMul 𝕜 E] [ContinuousConstSMul 𝕜 F] [CompleteSpace F] [T2Space F] + +open UniformOnFun in +theorem completeSpace (h : RestrictGenTopology {s : Set (ι → E) | IsVonNBounded 𝕜 s}) : + CompleteSpace (E [⋀^ι]→L[𝕜] F) := by + have := ContinuousMultilinearMap.completeSpace (F := F) h + rw [completeSpace_iff_isComplete_range + isUniformEmbedding_toContinuousMultilinearMap.isUniformInducing] + apply isClosed_range_toContinuousMultilinearMap.isComplete + +instance instCompleteSpace [TopologicalAddGroup E] [SequentialSpace (ι → E)] : + CompleteSpace (E [⋀^ι]→L[𝕜] F) := + completeSpace <| .of_seq fun _u x hux ↦ (hux.isVonNBounded_range 𝕜).insert x + +end CompleteSpace + +section RestrictScalars + +variable (𝕜' : Type*) [NontriviallyNormedField 𝕜'] [NormedAlgebra 𝕜' 𝕜] + [Module 𝕜' E] [IsScalarTower 𝕜' 𝕜 E] [Module 𝕜' F] [IsScalarTower 𝕜' 𝕜 F] [ContinuousSMul 𝕜 E] + +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) := + (isUniformEmbedding_restrictScalars 𝕜').uniformContinuous + +end RestrictScalars + +end UniformAddGroup + +variable [TopologicalSpace F] [TopologicalAddGroup F] + +lemma embedding_toContinuousMultilinearMap : + Embedding (toContinuousMultilinearMap : (E [⋀^ι]→L[𝕜] F → _)) := + letI := TopologicalAddGroup.toUniformSpace F + haveI := comm_topologicalAddGroup_is_uniform (G := F) + isUniformEmbedding_toContinuousMultilinearMap.embedding + +@[continuity, fun_prop] +lemma continuous_toContinuousMultilinearMap : + Continuous (toContinuousMultilinearMap : (E [⋀^ι]→L[𝕜] F → _)) := + embedding_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 + +instance instContinuousSMul [ContinuousSMul 𝕜 F] : ContinuousSMul 𝕜 (E [⋀^ι]→L[𝕜] F) := + embedding_toContinuousMultilinearMap.continuousSMul continuous_id rfl + +theorem hasBasis_nhds_zero_of_basis {ι' : Type*} {p : ι' → Prop} {b : ι' → Set F} + (h : (𝓝 (0 : F)).HasBasis p b) : + (𝓝 (0 : E [⋀^ι]→L[𝕜] F)).HasBasis + (fun Si : Set (ι → E) × ι' => IsVonNBounded 𝕜 Si.1 ∧ p Si.2) + fun Si => { f | MapsTo f Si.1 (b Si.2) } := by + rw [nhds_induced] + exact (ContinuousMultilinearMap.hasBasis_nhds_zero_of_basis h).comap _ + +theorem hasBasis_nhds_zero : + (𝓝 (0 : E [⋀^ι]→L[𝕜] F)).HasBasis + (fun SV : Set (ι → E) × Set F => IsVonNBounded 𝕜 SV.1 ∧ SV.2 ∈ 𝓝 0) + fun SV => { f | MapsTo f SV.1 SV.2 } := + hasBasis_nhds_zero_of_basis (Filter.basis_sets _) + +variable [ContinuousSMul 𝕜 E] + +lemma closedEmbedding_toContinuousMultilinearMap [T2Space F] : + ClosedEmbedding (toContinuousMultilinearMap : + (E [⋀^ι]→L[𝕜] F) → ContinuousMultilinearMap 𝕜 (fun _ : ι ↦ E) F) := + ⟨embedding_toContinuousMultilinearMap, isClosed_range_toContinuousMultilinearMap⟩ + +@[continuity, fun_prop] +theorem continuous_eval_const (x : ι → E) : + Continuous fun p : E [⋀^ι]→L[𝕜] F ↦ p x := + (ContinuousMultilinearMap.continuous_eval_const x).comp continuous_toContinuousMultilinearMap + +theorem continuous_coe_fun : + Continuous (DFunLike.coe : E [⋀^ι]→L[𝕜] F → (ι → E) → F) := + continuous_pi continuous_eval_const + +instance instT2Space [T2Space F] : T2Space (E [⋀^ι]→L[𝕜] F) := + .of_injective_continuous DFunLike.coe_injective continuous_coe_fun + +instance instT3Space [T2Space F] : T2Space (E [⋀^ι]→L[𝕜] F) := + letI : UniformSpace F := TopologicalAddGroup.toUniformSpace F + haveI : UniformAddGroup F := comm_topologicalAddGroup_is_uniform + inferInstance + +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) := + letI : UniformSpace F := TopologicalAddGroup.toUniformSpace F + haveI : UniformAddGroup F := comm_topologicalAddGroup_is_uniform + (isUniformEmbedding_restrictScalars _).embedding + +@[continuity, fun_prop] +theorem continuous_restrictScalars : + Continuous (restrictScalars 𝕜' : E [⋀^ι]→L[𝕜] F → E [⋀^ι]→L[𝕜'] F) := + embedding_restrictScalars.continuous + +variable (𝕜') in +/-- `ContinuousMultilinearMap.restrictScalars` as a `ContinuousLinearMap`. -/ +@[simps (config := .asFn) apply] +def restrictScalarsCLM [ContinuousConstSMul 𝕜' F] : + E [⋀^ι]→L[𝕜] F →L[𝕜'] E [⋀^ι]→L[𝕜'] F where + toFun := restrictScalars 𝕜' + map_add' _ _ := rfl + map_smul' _ _ := rfl + +end RestrictScalars + +variable (𝕜 E F) + +/-- The application of a multilinear map as a `ContinuousLinearMap`. -/ +def apply [ContinuousConstSMul 𝕜 F] (m : ι → E) : E [⋀^ι]→L[𝕜] F →L[𝕜] F where + toFun c := c m + map_add' _ _ := rfl + map_smul' _ _ := rfl + cont := continuous_eval_const m + +variable {𝕜 E F} + +@[simp] +lemma apply_apply [ContinuousConstSMul 𝕜 F] {m : ι → E} {c : E [⋀^ι]→L[𝕜] F} : + apply 𝕜 E F m c = c m := rfl + +theorem hasSum_eval {α : Type*} {p : α → E [⋀^ι]→L[𝕜] F} + {q : E [⋀^ι]→L[𝕜] F} (h : HasSum p q) (m : ι → E) : + HasSum (fun a => p a m) (q m) := + h.map (applyAddHom m) (continuous_eval_const m) + +theorem tsum_eval [T2Space F] {α : Type*} {p : α → E [⋀^ι]→L[𝕜] F} (hp : Summable p) + (m : ι → E) : (∑' a, p a) m = ∑' a, p a m := + (hasSum_eval hp.hasSum m).tsum_eq.symm + +end ContinuousAlternatingMap diff --git a/Mathlib/Topology/Algebra/Module/Basic.lean b/Mathlib/Topology/Algebra/Module/Basic.lean index ca811c376a395..a1479380641d5 100644 --- a/Mathlib/Topology/Algebra/Module/Basic.lean +++ b/Mathlib/Topology/Algebra/Module/Basic.lean @@ -7,7 +7,6 @@ Authors: Jan-David Salchow, Sébastien Gouëzel, Jean Lo, Yury Kudryashov, Fréd 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 @@ -44,8 +43,9 @@ theorem ContinuousSMul.of_nhds_zero [TopologicalRing R] [TopologicalAddGroup M] (hmulleft : ∀ m : M, Tendsto (fun a : R => a • m) (𝓝 0) (𝓝 0)) (hmulright : ∀ a : R, Tendsto (fun m : M => a • m) (𝓝 0) (𝓝 0)) : ContinuousSMul R M where continuous_smul := by + rw [← nhds_prod_eq] at hmul refine continuous_of_continuousAt_zero₂ (AddMonoidHom.smul : R →+ M →+ M) ?_ ?_ ?_ <;> - simpa [ContinuousAt, nhds_prod_eq] + simpa [ContinuousAt] end @@ -251,7 +251,7 @@ class ContinuousSemilinearMapClass (F : Type*) {R S : outParam Type*} [Semiring /-- `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₂`. -/ +`ContinuousSemilinearMapClass F (RingHom.id R) M M₂`. -/ abbrev ContinuousLinearMapClass (F : Type*) (R : outParam Type*) [Semiring R] (M : outParam Type*) [TopologicalSpace M] [AddCommMonoid M] (M₂ : outParam Type*) [TopologicalSpace M₂] [AddCommMonoid M₂] [Module R M] [Module R M₂] [FunLike F M M₂] := @@ -338,7 +338,7 @@ def linearMapOfMemClosureRangeCoe (f : M₁ → M₂) def linearMapOfTendsto (f : M₁ → M₂) (g : α → M₁ →ₛₗ[σ] M₂) [l.NeBot] (h : Tendsto (fun a x => g a x) l (𝓝 f)) : M₁ →ₛₗ[σ] M₂ := linearMapOfMemClosureRangeCoe f <| - mem_closure_of_tendsto h <| eventually_of_forall fun _ => Set.mem_range_self _ + mem_closure_of_tendsto h <| Eventually.of_forall fun _ => Set.mem_range_self _ variable (M₁ M₂ σ) @@ -726,6 +726,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₂) : @@ -1171,12 +1183,10 @@ 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 @@ -1315,10 +1325,9 @@ theorem intCast_apply [TopologicalAddGroup M] (z : ℤ) (m : M) : (↑z : M →L theorem smulRight_one_pow [TopologicalSpace R] [TopologicalRing R] (c : R) (n : ℕ) : smulRight (1 : R →L[R] R) c ^ n = smulRight (1 : R →L[R] R) (c ^ n) := by - induction' n with n ihn - · ext - simp - · rw [pow_succ, ihn, mul_def, smulRight_comp, smul_eq_mul, pow_succ'] + induction n with + | zero => ext; simp + | succ n ihn => rw [pow_succ, ihn, mul_def, smulRight_comp, smul_eq_mul, pow_succ'] section @@ -1638,8 +1647,6 @@ instance continuousSemilinearEquivClass : -- instance : CoeFun (M₁ ≃SL[σ₁₂] M₂) fun _ => M₁ → M₂ := -- ⟨fun f => f⟩ --- Porting note: Syntactic tautology. - theorem coe_apply (e : M₁ ≃SL[σ₁₂] M₂) (b : M₁) : (e : M₁ →SL[σ₁₂] M₂) b = e b := rfl @@ -1762,7 +1769,7 @@ theorem coe_refl : ↑(ContinuousLinearEquiv.refl R₁ M₁) = ContinuousLinearM theorem coe_refl' : ⇑(ContinuousLinearEquiv.refl R₁ M₁) = id := rfl -/-- The inverse of a continuous linear equivalence as a continuous linear equivalence-/ +/-- The inverse of a continuous linear equivalence as a continuous linear equivalence -/ @[symm] protected def symm (e : M₁ ≃SL[σ₁₂] M₂) : M₂ ≃SL[σ₂₁] M₁ := { e.toLinearEquiv.symm with @@ -1809,8 +1816,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₂) @@ -1903,9 +1910,7 @@ theorem self_comp_symm (e : M₁ ≃SL[σ₁₂] M₂) : (e : M₁ → M₂) ∘ exact apply_symm_apply e x @[simp] -theorem symm_symm (e : M₁ ≃SL[σ₁₂] M₂) : e.symm.symm = e := by - ext x - rfl +theorem symm_symm (e : M₁ ≃SL[σ₁₂] M₂) : e.symm.symm = e := rfl @[simp] theorem refl_symm : (ContinuousLinearEquiv.refl R₁ M₁).symm = ContinuousLinearEquiv.refl R₁ M₁ := @@ -1936,22 +1941,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₁) @@ -2235,8 +2245,6 @@ end ContinuousLinearEquiv namespace ContinuousLinearMap -open scoped Classical - variable {R : Type*} {M : Type*} {M₂ : Type*} [TopologicalSpace M] [TopologicalSpace M₂] section @@ -2245,6 +2253,7 @@ variable [Semiring R] variable [AddCommMonoid M₂] [Module R M₂] variable [AddCommMonoid M] [Module R M] +open Classical in /-- Introduce a function `inverse` from `M →L[R] M₂` to `M₂ →L[R] M`, which sends `f` to `f.symm` if `f` is a continuous linear equivalence and to `0` otherwise. This definition is somewhat ad hoc, but one needs a fully (rather than partially) defined inverse function for some purposes, including @@ -2370,21 +2379,20 @@ 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) := - _root_.topologicalAddGroup_quotient S.toAddSubgroup + 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) := @@ -2394,3 +2402,5 @@ instance t3_quotient_of_isClosed [TopologicalAddGroup M] [IsClosed (S : Set M)] end Submodule end Quotient + +set_option linter.style.longFile 2500 diff --git a/Mathlib/Topology/Algebra/Module/Cardinality.lean b/Mathlib/Topology/Algebra/Module/Cardinality.lean index c45fb8205558f..b5c7c62b830cd 100644 --- a/Mathlib/Topology/Algebra/Module/Cardinality.lean +++ b/Mathlib/Topology/Algebra/Module/Cardinality.lean @@ -77,7 +77,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 98892800dddf3..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 /-! @@ -212,7 +212,7 @@ variable (𝕜 A) [CommRing 𝕜] [NoZeroDivisors 𝕜] [TopologicalSpace 𝕜] /-- The **Gelfand transform** is an algebra homomorphism (over `𝕜`) from a topological `𝕜`-algebra `A` into the `𝕜`-algebra of continuous `𝕜`-valued functions on the `characterSpace 𝕜 A`. -The character space itself consists of all algebra homomorphisms from `A` to `𝕜`. -/ +The character space itself consists of all algebra homomorphisms from `A` to `𝕜`. -/ @[simps] def gelfandTransform : A →ₐ[𝕜] C(characterSpace 𝕜 A, 𝕜) where toFun a := diff --git a/Mathlib/Topology/Algebra/Module/FiniteDimension.lean b/Mathlib/Topology/Algebra/Module/FiniteDimension.lean index 8b1c1ca19d66a..2cf817161d306 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 @@ -490,8 +490,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} diff --git a/Mathlib/Topology/Algebra/Module/LinearPMap.lean b/Mathlib/Topology/Algebra/Module/LinearPMap.lean index bc1ef73338c9b..dc97ddf2c8859 100644 --- a/Mathlib/Topology/Algebra/Module/LinearPMap.lean +++ b/Mathlib/Topology/Algebra/Module/LinearPMap.lean @@ -85,8 +85,7 @@ theorem IsClosable.existsUnique {f : E →ₗ.[R] F} (hf : f.IsClosable) : refine exists_unique_of_exists_of_unique hf fun _ _ hy₁ hy₂ => eq_of_eq_graph ?_ rw [← hy₁, ← hy₂] -open scoped Classical - +open Classical in /-- If `f` is closable, then `f.closure` is the closure. Otherwise it is defined as `f.closure = f`. -/ noncomputable def closure (f : E →ₗ.[R] F) : E →ₗ.[R] F := diff --git a/Mathlib/Topology/Algebra/Module/Multilinear/Basic.lean b/Mathlib/Topology/Algebra/Module/Multilinear/Basic.lean index c4849ddb17994..ad413d2ba21ae 100644 --- a/Mathlib/Topology/Algebra/Module/Multilinear/Basic.lean +++ b/Mathlib/Topology/Algebra/Module/Multilinear/Basic.lean @@ -202,7 +202,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/Bounded.lean b/Mathlib/Topology/Algebra/Module/Multilinear/Bounded.lean index 6b8d509bb8ec2..85af2419a28c0 100644 --- a/Mathlib/Topology/Algebra/Module/Multilinear/Bounded.lean +++ b/Mathlib/Topology/Algebra/Module/Multilinear/Bounded.lean @@ -67,10 +67,7 @@ theorem image_multilinear' [Nonempty ι] {s : Set (∀ i, E i)} (hs : IsVonNBoun let ⟨i₀⟩ := ‹Nonempty ι› set y := I.piecewise (fun i ↦ c i • x i) x calc - a • f x = f (update y i₀ ((a / ∏ i ∈ I, c i) • y i₀)) := by - rw [f.map_smul, update_eq_self, f.map_piecewise_smul, div_eq_mul_inv, mul_smul, - inv_smul_smul₀ hc₀'] - _ ∈ V := hft fun i hi ↦ by + f (update y i₀ ((a / ∏ i ∈ I, c i) • y i₀)) ∈ V := hft fun i hi => by rcases eq_or_ne i i₀ with rfl | hne · simp_rw [update_same, y, I.piecewise_eq_of_mem _ _ hi, smul_smul] refine hc _ _ ?_ _ hx @@ -81,6 +78,9 @@ theorem image_multilinear' [Nonempty ι] {s : Set (∀ i, E i)} (hs : IsVonNBoun _ = ‖c i‖ := one_mul _ · simp_rw [update_noteq hne, y, I.piecewise_eq_of_mem _ _ hi] exact hc _ _ le_rfl _ hx + _ = a • f x := by + rw [f.map_smul, update_eq_self, f.map_piecewise_smul, div_eq_mul_inv, mul_smul, + inv_smul_smul₀ hc₀'] /-- The image of a von Neumann bounded set under a continuous multilinear map is von Neumann bounded. diff --git a/Mathlib/Topology/Algebra/Module/Multilinear/Topology.lean b/Mathlib/Topology/Algebra/Module/Multilinear/Topology.lean index fd88cf46b8e21..baf4b78201f9a 100644 --- a/Mathlib/Topology/Algebra/Module/Multilinear/Topology.lean +++ b/Mathlib/Topology/Algebra/Module/Multilinear/Topology.lean @@ -65,18 +65,21 @@ section UniformAddGroup variable [UniformSpace F] [UniformAddGroup F] -lemma uniformEmbedding_toUniformOnFun : - UniformEmbedding (toUniformOnFun : ContinuousMultilinearMap 𝕜 E F → _) where +lemma isUniformEmbedding_toUniformOnFun : + IsUniformEmbedding (toUniformOnFun : ContinuousMultilinearMap 𝕜 E F → _) where inj := DFunLike.coe_injective comap_uniformity := rfl +@[deprecated (since := "2024-10-01")] +alias uniformEmbedding_toUniformOnFun := isUniformEmbedding_toUniformOnFun + lemma embedding_toUniformOnFun : Embedding (toUniformOnFun : ContinuousMultilinearMap 𝕜 E F → _) := - uniformEmbedding_toUniformOnFun.embedding + isUniformEmbedding_toUniformOnFun.embedding 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,13 +88,15 @@ 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 + +section CompleteSpace variable [∀ i, ContinuousSMul 𝕜 (E i)] [ContinuousConstSMul 𝕜 F] [CompleteSpace F] [T2Space F] @@ -102,7 +107,7 @@ theorem completeSpace (h : RestrictGenTopology {s : Set (Π i, E i) | IsVonNBoun 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, + rw [completeSpace_iff_isComplete_range isUniformEmbedding_toUniformOnFun.isUniformInducing, range_toUniformOnFun] simp only [setOf_and, setOf_forall] apply_rules [IsClosed.isComplete, IsClosed.inter] @@ -116,6 +121,33 @@ instance instCompleteSpace [∀ i, TopologicalAddGroup (E i)] [SequentialSpace ( CompleteSpace (ContinuousMultilinearMap 𝕜 E F) := completeSpace <| .of_seq fun _u x hux ↦ (hux.isVonNBounded_range 𝕜).insert x +end CompleteSpace + +section RestrictScalars + +variable (𝕜' : Type*) [NontriviallyNormedField 𝕜'] [NormedAlgebra 𝕜' 𝕜] + [∀ i, Module 𝕜' (E i)] [∀ i, IsScalarTower 𝕜' 𝕜 (E i)] [Module 𝕜' F] [IsScalarTower 𝕜' 𝕜 F] + [∀ i, ContinuousSMul 𝕜 (E i)] + +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 [← 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) := + (isUniformEmbedding_restrictScalars 𝕜').uniformContinuous + +end RestrictScalars + end UniformAddGroup variable [TopologicalSpace F] [TopologicalAddGroup F] @@ -171,6 +203,35 @@ theorem continuous_coe_fun : instance instT2Space [T2Space F] : T2Space (ContinuousMultilinearMap 𝕜 E F) := .of_injective_continuous DFunLike.coe_injective continuous_coe_fun +section RestrictScalars + +variable {𝕜' : Type*} [NontriviallyNormedField 𝕜'] [NormedAlgebra 𝕜' 𝕜] + [∀ i, Module 𝕜' (E i)] [∀ i, IsScalarTower 𝕜' 𝕜 (E i)] [Module 𝕜' F] [IsScalarTower 𝕜' 𝕜 F] + +theorem embedding_restrictScalars : + Embedding + (restrictScalars 𝕜' : ContinuousMultilinearMap 𝕜 E F → ContinuousMultilinearMap 𝕜' E F) := + letI : UniformSpace F := TopologicalAddGroup.toUniformSpace F + haveI : UniformAddGroup F := comm_topologicalAddGroup_is_uniform + (isUniformEmbedding_restrictScalars _).embedding + +@[continuity, fun_prop] +theorem continuous_restrictScalars : + Continuous + (restrictScalars 𝕜' : ContinuousMultilinearMap 𝕜 E F → ContinuousMultilinearMap 𝕜' E F) := + embedding_restrictScalars.continuous + +variable (𝕜') in +/-- `ContinuousMultilinearMap.restrictScalars` as a `ContinuousLinearMap`. -/ +@[simps (config := .asFn) apply] +def restrictScalarsLinear [ContinuousConstSMul 𝕜' F] : + ContinuousMultilinearMap 𝕜 E F →L[𝕜'] ContinuousMultilinearMap 𝕜' E F where + toFun := restrictScalars 𝕜' + map_add' _ _ := rfl + map_smul' _ _ := rfl + +end RestrictScalars + variable (𝕜 E F) /-- The application of a multilinear map as a `ContinuousLinearMap`. -/ diff --git a/Mathlib/Topology/Algebra/Module/StrongTopology.lean b/Mathlib/Topology/Algebra/Module/StrongTopology.lean index a66e7b2cf135a..8e988265fd745 100644 --- a/Mathlib/Topology/Algebra/Module/StrongTopology.lean +++ b/Mathlib/Topology/Algebra/Module/StrongTopology.lean @@ -55,7 +55,8 @@ uniform convergence, bounded convergence -/ -open scoped Topology UniformConvergence +open scoped Topology UniformConvergence Uniformity +open Filter Set Function Bornology section General @@ -63,7 +64,8 @@ section General variable {𝕜₁ 𝕜₂ : Type*} [NormedField 𝕜₁] [NormedField 𝕜₂] (σ : 𝕜₁ →+* 𝕜₂) {E F : Type*} [AddCommGroup E] [Module 𝕜₁ E] [TopologicalSpace E] - [AddCommGroup F] [Module 𝕜₂ F] (F) + [AddCommGroup F] [Module 𝕜₂ F] +variable (F) /-- Given `E` and `F` two topological vector spaces and `𝔖 : Set (Set E)`, then `UniformConvergenceCLM σ F 𝔖` is a type synonym of `E →SL[σ] F` equipped with the "topology of @@ -91,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 @@ -102,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] @@ -116,23 +119,31 @@ 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 := +theorem isUniformEmbedding_coeFn [UniformSpace F] [UniformAddGroup F] (𝔖 : Set (Set E)) : + IsUniformEmbedding (α := UniformConvergenceCLM σ F 𝔖) (UniformOnFun.ofFun 𝔖 ∘ DFunLike.coe) := ⟨⟨rfl⟩, 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) (UniformOnFun.ofFun 𝔖 ∘ DFunLike.coe) := - UniformEmbedding.embedding (uniformEmbedding_coeFn _ _ _) + IsUniformEmbedding.embedding (isUniformEmbedding_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,7 +152,7 @@ instance instTopologicalAddGroup [TopologicalSpace F] [TopologicalAddGroup F] infer_instance 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𝔖 @@ -157,7 +168,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 @@ -184,11 +195,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 [(embedding_coeFn σ F 𝔖).toInducing.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 + (isUniformEmbedding_coeFn σ F 𝔖).isUniformInducing.uniformContinuousConstSMul fun _ _ ↦ by rfl instance instContinuousConstSMul (M : Type*) [Monoid M] [DistribMulAction M F] [SMulCommClass 𝕜₂ M F] @@ -239,7 +305,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) := @@ -247,10 +313,10 @@ 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 _ @@ -259,25 +325,29 @@ instance [TopologicalSpace F] [TopologicalAddGroup F] [ContinuousSMul 𝕜₁ E] 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)) + Set.mem_sUnion_of_mem (Set.mem_singleton x) (isVonNBounded_singleton x)) 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] @@ -290,6 +360,51 @@ 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 + variable (G) [TopologicalSpace F] [TopologicalSpace G] /-- Pre-composition by a *fixed* continuous linear map as a continuous linear map. @@ -361,15 +476,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 @@ -381,7 +499,7 @@ theorem embedding_restrictScalars : Embedding (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 _).embedding @[continuity, fun_prop] theorem continuous_restrictScalars : diff --git a/Mathlib/Topology/Algebra/Module/WeakBilin.lean b/Mathlib/Topology/Algebra/Module/WeakBilin.lean new file mode 100644 index 0000000000000..916301730f678 --- /dev/null +++ b/Mathlib/Topology/Algebra/Module/WeakBilin.lean @@ -0,0 +1,161 @@ +/- +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 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 diff --git a/Mathlib/Topology/Algebra/Module/WeakDual.lean b/Mathlib/Topology/Algebra/Module/WeakDual.lean index 8bc7353b3fce3..1a71efa833d83 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) @@ -266,6 +152,21 @@ instance instT2Space [T2Space 𝕜] : T2Space (WeakDual 𝕜 E) := WeakBilin.embedding <| show Function.Injective (topDualPairing 𝕜 E) from ContinuousLinearMap.coe_injective +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 /-- The weak topology is the topology coarsest topology on `E` such that all functionals @@ -274,6 +175,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 +196,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 +229,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 +237,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 +260,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 dd2ee7af35ad6..126c6636dd313 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 @@ -18,14 +18,10 @@ applications the underlying type is a monoid (multiplicative or additive), we do the definitions. -/ - universe u v -open scoped Classical open Set Filter TopologicalSpace - -open scoped Classical -open Topology Pointwise +open scoped Topology Pointwise variable {ι α M N X : Type*} [TopologicalSpace X] @@ -79,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 α] @@ -87,7 +83,7 @@ theorem ContinuousMul.induced {α : Type*} {β : Type*} {F : Type*} [FunLike F @ContinuousMul α (tβ.induced f) _ := by let tα := tβ.induced f refine ⟨continuous_induced_rng.2 ?_⟩ - simp only [Function.comp, map_mul] + simp only [Function.comp_def, map_mul] fun_prop @[to_additive (attr := continuity, fun_prop)] @@ -336,7 +332,7 @@ monoid homomorphisms"] def monoidHomOfTendsto (f : M₁ → M₂) (g : α → F) [l.NeBot] (h : Tendsto (fun a x => g a x) l (𝓝 f)) : M₁ →* M₂ := monoidHomOfMemClosureRangeCoe f <| - mem_closure_of_tendsto h <| eventually_of_forall fun _ => mem_range_self _ + mem_closure_of_tendsto h <| Eventually.of_forall fun _ => mem_range_self _ variable (M₁ M₂) diff --git a/Mathlib/Topology/Algebra/MulAction.lean b/Mathlib/Topology/Algebra/MulAction.lean index 30ec72337a896..91dc843aa0507 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⟩ @@ -85,7 +92,7 @@ theorem ContinuousSMul.induced {R : Type*} {α : Type*} {β : Type*} {F : Type*} (f : F) : @ContinuousSMul R α _ _ (tβ.induced f) := by let tα := tβ.induced f refine ⟨continuous_induced_rng.2 ?_⟩ - simp only [Function.comp, map_smul] + simp only [Function.comp_def, map_smul] fun_prop @[to_additive] @@ -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) : @@ -216,6 +223,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/Bases.lean b/Mathlib/Topology/Algebra/Nonarchimedean/Bases.lean index b1e78a20544fa..6fd78154fd5a4 100644 --- a/Mathlib/Topology/Algebra/Nonarchimedean/Bases.lean +++ b/Mathlib/Topology/Algebra/Nonarchimedean/Bases.lean @@ -327,7 +327,7 @@ theorem nonarchimedean (hB : SubmodulesBasis B) : @NonarchimedeanAddGroup M _ hB library_note "nonarchimedean non instances"/-- The non archimedean subgroup basis lemmas cannot be instances because some instances -(such as `MeasureTheory.AEEqFun.instAddMonoid` or `topological_add_group.to_has_continuous_add`) +(such as `MeasureTheory.AEEqFun.instAddMonoid` or `TopologicalAddGroup.toContinuousAdd`) cause the search for `@TopologicalAddGroup β ?m1 ?m2`, i.e. a search for a topological group where the topology/group structure are unknown. -/ diff --git a/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean b/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean index 6550bf2652504..227a2f3aaef68 100644 --- a/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean +++ b/Mathlib/Topology/Algebra/Nonarchimedean/Basic.lean @@ -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 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/OpenSubgroup.lean b/Mathlib/Topology/Algebra/OpenSubgroup.lean index 025b15e34f7a6..99c3a4c276f10 100644 --- a/Mathlib/Topology/Algebra/OpenSubgroup.lean +++ b/Mathlib/Topology/Algebra/OpenSubgroup.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 +Authors: Johan Commelin, Nailin Guan -/ import Mathlib.RingTheory.Ideal.Basic import Mathlib.Topology.Algebra.Ring.Basic @@ -10,7 +10,7 @@ import Mathlib.Topology.Sets.Opens /-! # Open subgroups of a topological groups -This files builds the lattice `OpenSubgroup G` of open subgroups in a topological group `G`, +This files builds the lattice `OpenSubgroup G` of open subgroups in a topological group `G`, and its additive version `OpenAddSubgroup`. This lattice has a top element, the subgroup of all elements, but no bottom element in general. The trivial subgroup which is the natural candidate bottom has no reason to be open (this happens only in discrete groups). @@ -135,8 +135,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 +170,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 +194,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 +245,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 +269,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 +327,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 +336,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 +364,92 @@ 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 diff --git a/Mathlib/Topology/Algebra/Order/Compact.lean b/Mathlib/Topology/Algebra/Order/Compact.lean index 79a810fef5137..1f1e14890b141 100644 --- a/Mathlib/Topology/Algebra/Order/Compact.lean +++ b/Mathlib/Topology/Algebra/Order/Compact.lean @@ -250,7 +250,8 @@ theorem cocompact_eq_atTop [NoMaxOrder α] [OrderBot α] theorem IsCompact.exists_isMinOn [ClosedIicTopology α] {s : Set β} (hs : IsCompact s) (ne_s : s.Nonempty) {f : β → α} (hf : ContinuousOn f s) : ∃ x ∈ s, IsMinOn f s x := by rcases (hs.image_of_continuousOn hf).exists_isLeast (ne_s.image f) with ⟨_, ⟨x, hxs, rfl⟩, hx⟩ - exact ⟨x, hxs, forall_mem_image.1 hx⟩ + refine ⟨x, hxs, forall_mem_image.1 (fun _ hb => hx <| mem_image_of_mem f ?_)⟩ + rwa [(image_id' s).symm] /-- If a continuous function lies strictly above `a` on a compact set, it has a lower bound strictly above `a`. -/ @@ -263,23 +264,11 @@ theorem IsCompact.exists_forall_le' [ClosedIicTopology α] [NoMaxOrder α] {f : · obtain ⟨x, hx, hx'⟩ := hs.exists_isMinOn hs' hf exact ⟨f x, hf' x hx, hx'⟩ -/-- The **extreme value theorem**: a continuous function realizes its minimum on a compact set. -/ -@[deprecated IsCompact.exists_isMinOn (since := "2023-02-06")] -theorem IsCompact.exists_forall_le [ClosedIicTopology α] {s : Set β} (hs : IsCompact s) - (ne_s : s.Nonempty) {f : β → α} (hf : ContinuousOn f s) : ∃ x ∈ s, ∀ y ∈ s, f x ≤ f y := - hs.exists_isMinOn ne_s hf - /-- The **extreme value theorem**: a continuous function realizes its maximum on a compact set. -/ theorem IsCompact.exists_isMaxOn [ClosedIciTopology α] {s : Set β} (hs : IsCompact s) (ne_s : s.Nonempty) {f : β → α} (hf : ContinuousOn f s) : ∃ x ∈ s, IsMaxOn f s x := IsCompact.exists_isMinOn (α := αᵒᵈ) hs ne_s hf -/-- The **extreme value theorem**: a continuous function realizes its maximum on a compact set. -/ -@[deprecated IsCompact.exists_isMaxOn (since := "2023-02-06")] -theorem IsCompact.exists_forall_ge [ClosedIciTopology α] {s : Set β} (hs : IsCompact s) - (ne_s : s.Nonempty) {f : β → α} (hf : ContinuousOn f s) : ∃ x ∈ s, ∀ y ∈ s, f y ≤ f x := - IsCompact.exists_isMaxOn hs ne_s hf - /-- The **extreme value theorem**: if a function `f` is continuous on a closed set `s` and it is larger than a value in its image away from compact sets, then it has a minimum on this set. -/ theorem ContinuousOn.exists_isMinOn' [ClosedIicTopology α] {s : Set β} {f : β → α} @@ -293,14 +282,6 @@ theorem ContinuousOn.exists_isMinOn' [ClosedIicTopology α] {s : Set β} {f : β by_cases hyK : y ∈ K exacts [hxf _ (Or.inr ⟨hyK, hy⟩), (hxf _ (Or.inl rfl)).trans (hKf ⟨hyK, hy⟩)] -/-- The **extreme value theorem**: if a function `f` is continuous on a closed set `s` and it is -larger than a value in its image away from compact sets, then it has a minimum on this set. -/ -@[deprecated ContinuousOn.exists_isMinOn' (since := "2023-02-06")] -theorem ContinuousOn.exists_forall_le' [ClosedIicTopology α] {s : Set β} {f : β → α} - (hf : ContinuousOn f s) (hsc : IsClosed s) {x₀ : β} (h₀ : x₀ ∈ s) - (hc : ∀ᶠ x in cocompact β ⊓ 𝓟 s, f x₀ ≤ f x) : ∃ x ∈ s, ∀ y ∈ s, f x ≤ f y := - hf.exists_isMinOn' hsc h₀ hc - /-- The **extreme value theorem**: if a function `f` is continuous on a closed set `s` and it is smaller than a value in its image away from compact sets, then it has a maximum on this set. -/ theorem ContinuousOn.exists_isMaxOn' [ClosedIciTopology α] {s : Set β} {f : β → α} @@ -308,14 +289,6 @@ theorem ContinuousOn.exists_isMaxOn' [ClosedIciTopology α] {s : Set β} {f : β (hc : ∀ᶠ x in cocompact β ⊓ 𝓟 s, f x ≤ f x₀) : ∃ x ∈ s, IsMaxOn f s x := ContinuousOn.exists_isMinOn' (α := αᵒᵈ) hf hsc h₀ hc -/-- The **extreme value theorem**: if a function `f` is continuous on a closed set `s` and it is -smaller than a value in its image away from compact sets, then it has a maximum on this set. -/ -@[deprecated ContinuousOn.exists_isMaxOn' (since := "2023-02-06")] -theorem ContinuousOn.exists_forall_ge' [ClosedIciTopology α] {s : Set β} {f : β → α} - (hf : ContinuousOn f s) (hsc : IsClosed s) {x₀ : β} (h₀ : x₀ ∈ s) - (hc : ∀ᶠ x in cocompact β ⊓ 𝓟 s, f x ≤ f x₀) : ∃ x ∈ s, ∀ y ∈ s, f y ≤ f x := - hf.exists_isMaxOn' hsc h₀ hc - /-- The **extreme value theorem**: if a continuous function `f` is larger than a value in its range away from compact sets, then it has a global minimum. -/ theorem Continuous.exists_forall_le' [ClosedIicTopology α] {f : β → α} (hf : Continuous f) @@ -490,13 +463,6 @@ theorem IsCompact.exists_isMaxOn_mem_subset [ClosedIciTopology α] {f : β → let ⟨x, hxt, hfx⟩ := ht.exists_isMaxOn ⟨z, hz⟩ hf ⟨x, by_contra fun hxs => (hfz x ⟨hxt, hxs⟩).not_le (hfx hz), hfx⟩ -@[deprecated IsCompact.exists_isMinOn_mem_subset (since := "2023-02-06")] -theorem IsCompact.exists_isLocalMinOn_mem_subset [ClosedIicTopology α] {f : β → α} {s t : Set β} - {z : β} (ht : IsCompact t) (hf : ContinuousOn f t) (hz : z ∈ t) - (hfz : ∀ z' ∈ t \ s, f z < f z') : ∃ x ∈ s, IsLocalMinOn f t x := - let ⟨x, hxs, h⟩ := ht.exists_isMinOn_mem_subset hf hz hfz - ⟨x, hxs, h.localize⟩ - -- Porting note: rfc: assume `t ∈ 𝓝ˢ s` (a.k.a. `s ⊆ interior t`) instead of `s ⊆ t` and -- `IsOpen s`? theorem IsCompact.exists_isLocalMin_mem_open [ClosedIicTopology α] {f : β → α} {s t : Set β} diff --git a/Mathlib/Topology/Algebra/Order/Field.lean b/Mathlib/Topology/Algebra/Order/Field.lean index 39438737e3443..b80ccdfcef320 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 @@ -75,7 +76,8 @@ tends to a negative constant `C` then `f * g` tends to `Filter.atBot`. -/ theorem Filter.Tendsto.atTop_mul_neg {C : 𝕜} (hC : C < 0) (hf : Tendsto f l atTop) (hg : Tendsto g l (𝓝 C)) : Tendsto (fun x => f x * g x) l atBot := by have := hf.atTop_mul (neg_pos.2 hC) hg.neg - simpa only [(· ∘ ·), neg_mul_eq_mul_neg, neg_neg] using tendsto_neg_atTop_atBot.comp this + simpa only [Function.comp_def, neg_mul_eq_mul_neg, neg_neg] using + tendsto_neg_atTop_atBot.comp this /-- In a linearly ordered field with the order topology, if `f` tends to a negative constant `C` and `g` tends to `Filter.atTop` then `f * g` tends to `Filter.atBot`. -/ @@ -88,14 +90,14 @@ tends to a positive constant `C` then `f * g` tends to `Filter.atBot`. -/ theorem Filter.Tendsto.atBot_mul {C : 𝕜} (hC : 0 < C) (hf : Tendsto f l atBot) (hg : Tendsto g l (𝓝 C)) : Tendsto (fun x => f x * g x) l atBot := by have := (tendsto_neg_atBot_atTop.comp hf).atTop_mul hC hg - simpa [(· ∘ ·)] using tendsto_neg_atTop_atBot.comp this + simpa [Function.comp_def] using tendsto_neg_atTop_atBot.comp this /-- In a linearly ordered field with the order topology, if `f` tends to `Filter.atBot` and `g` tends to a negative constant `C` then `f * g` tends to `Filter.atTop`. -/ theorem Filter.Tendsto.atBot_mul_neg {C : 𝕜} (hC : C < 0) (hf : Tendsto f l atBot) (hg : Tendsto g l (𝓝 C)) : Tendsto (fun x => f x * g x) l atTop := by have := (tendsto_neg_atBot_atTop.comp hf).atTop_mul_neg hC hg - simpa [(· ∘ ·)] using tendsto_neg_atBot_atTop.comp this + simpa [Function.comp_def] using tendsto_neg_atBot_atTop.comp this /-- In a linearly ordered field with the order topology, if `f` tends to a positive constant `C` and `g` tends to `Filter.atBot` then `f * g` tends to `Filter.atBot`. -/ @@ -193,10 +195,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 1eb2f5f1f2ad0..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⟩ @@ -146,7 +173,7 @@ theorem tendsto_fract_left' [OrderClosedTopology α] [TopologicalAddGroup α] (n theorem tendsto_fract_left [OrderClosedTopology α] [TopologicalAddGroup α] (n : ℤ) : Tendsto (fract : α → α) (𝓝[<] n) (𝓝[<] 1) := tendsto_nhdsWithin_of_tendsto_nhds_of_eventually_within _ (tendsto_fract_left' _) - (eventually_of_forall fract_lt_one) + (Eventually.of_forall fract_lt_one) theorem tendsto_fract_right' [OrderClosedTopology α] [TopologicalAddGroup α] (n : ℤ) : Tendsto (fract : α → α) (𝓝[≥] n) (𝓝 0) := @@ -155,7 +182,7 @@ theorem tendsto_fract_right' [OrderClosedTopology α] [TopologicalAddGroup α] ( theorem tendsto_fract_right [OrderClosedTopology α] [TopologicalAddGroup α] (n : ℤ) : Tendsto (fract : α → α) (𝓝[≥] n) (𝓝[≥] 0) := tendsto_nhdsWithin_of_tendsto_nhds_of_eventually_within _ (tendsto_fract_right' _) - (eventually_of_forall fract_nonneg) + (Eventually.of_forall fract_nonneg) local notation "I" => (Icc 0 1 : Set α) @@ -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/Group.lean b/Mathlib/Topology/Algebra/Order/Group.lean index ed113a88b9cf3..be3a1247cf1fa 100644 --- a/Mathlib/Topology/Algebra/Order/Group.lean +++ b/Mathlib/Topology/Algebra/Order/Group.lean @@ -15,9 +15,9 @@ topological group. We also prove continuity of `abs : G → G` and provide conve -/ -open Set Filter +open Set Filter Function -open Topology Filter +open scoped Topology variable {α G : Type*} [TopologicalSpace G] [LinearOrderedAddCommGroup G] [OrderTopology G] variable {l : Filter α} {f g : α → G} @@ -88,3 +88,39 @@ protected theorem ContinuousOn.abs (h : ContinuousOn f s) : ContinuousOn (fun x theorem tendsto_abs_nhdsWithin_zero : Tendsto (abs : G → G) (𝓝[≠] 0) (𝓝[>] 0) := (continuous_abs.tendsto' (0 : G) 0 abs_zero).inf <| tendsto_principal_principal.2 fun _x => abs_pos.2 + +/-- In a linearly ordered additive group, the integer multiples of an element are dense +iff they are the whole group. -/ +theorem denseRange_zsmul_iff_surjective {a : G} : + DenseRange (· • a : ℤ → G) ↔ Surjective (· • a : ℤ → G) := by + refine ⟨fun h ↦ ?_, fun h ↦ h.denseRange⟩ + wlog ha₀ : 0 < a generalizing a + · simp only [← range_iff_surjective, DenseRange] at * + rcases (not_lt.1 ha₀).eq_or_lt with rfl | hlt + · simpa only [smul_zero, range_const, dense_iff_closure_eq, closure_singleton] using h + · have H : range (· • -a : ℤ → G) = range (· • a : ℤ → G) := by + simpa only [smul_neg, ← neg_smul] using neg_surjective.range_comp (· • a) + rw [← H] + apply this <;> simpa only [H, neg_pos] + intro b + obtain ⟨m, hm, hm'⟩ : ∃ m : ℤ, m • a ∈ Ioo b (b + a + a) := by + have hne : (Ioo b (b + a + a)).Nonempty := ⟨b + a, by simpa⟩ + simpa using h.exists_mem_open isOpen_Ioo hne + rcases eq_or_ne b ((m - 1) • a) with rfl | hne; · simp + suffices (Ioo (m • a) ((m + 1) • a)).Nonempty by + rcases h.exists_mem_open isOpen_Ioo this with ⟨l, hl⟩ + have : m < l ∧ l < m + 1 := by simpa [zsmul_lt_zsmul_iff ha₀] using hl + omega + rcases hne.lt_or_lt with hlt | hlt + · refine ⟨b + a + a, hm', ?_⟩ + simpa only [add_smul, sub_smul, one_smul, lt_sub_iff_add_lt, add_lt_add_iff_right] using hlt + · use b + a + simp only [mem_Ioo, add_smul, sub_smul, one_smul, add_lt_add_iff_right] at hlt ⊢ + exact ⟨sub_lt_iff_lt_add.1 hlt, hm⟩ + +/-- In a nontrivial densely linearly ordered additive group, +the integer multiples of an element can't be dense. -/ +theorem not_denseRange_zsmul [Nontrivial G] [DenselyOrdered G] {a : G} : + ¬DenseRange (· • a : ℤ → G) := + denseRange_zsmul_iff_surjective.not.mpr fun h ↦ + not_isAddCyclic_of_denselyOrdered G ⟨⟨a, h⟩⟩ diff --git a/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean b/Mathlib/Topology/Algebra/Order/LiminfLimsup.lean index fa6d36430e5cf..2514169662c24 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 @@ -27,10 +27,8 @@ The same lemmas are true in `ℝ`, `ℝ × ℝ`, `ι → ℝ`, `EuclideanSpace duplication, we provide an ad hoc axiomatisation of the properties we need. -/ - open Filter TopologicalSpace - -open scoped Topology Classical +open scoped Topology universe u v @@ -136,13 +134,13 @@ instance (priority := 100) OrderBot.to_BoundedGENhdsClass [OrderBot α] : Bounde instance (priority := 100) OrderTopology.to_BoundedLENhdsClass [IsDirected α (· ≤ ·)] [OrderTopology α] : BoundedLENhdsClass α := ⟨fun a ↦ - ((isTop_or_exists_gt a).elim fun h ↦ ⟨a, eventually_of_forall h⟩) <| + ((isTop_or_exists_gt a).elim fun h ↦ ⟨a, Eventually.of_forall h⟩) <| Exists.imp fun _b ↦ ge_mem_nhds⟩ -- See note [lower instance priority] instance (priority := 100) OrderTopology.to_BoundedGENhdsClass [IsDirected α (· ≥ ·)] [OrderTopology α] : BoundedGENhdsClass α := - ⟨fun a ↦ ((isBot_or_exists_lt a).elim fun h ↦ ⟨a, eventually_of_forall h⟩) <| + ⟨fun a ↦ ((isBot_or_exists_lt a).elim fun h ↦ ⟨a, Eventually.of_forall h⟩) <| Exists.imp fun _b ↦ le_mem_nhds⟩ end Preorder @@ -169,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 := @@ -186,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] @@ -210,11 +208,10 @@ theorem tendsto_of_liminf_eq_limsup {f : Filter β} {u : β → α} {a : α} (hi and is greater than or equal to the `limsup` of `f`, then `f` tends to `a` along this filter. -/ 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) := - if hf : f = ⊥ then hf.symm ▸ tendsto_bot - else - haveI : NeBot f := ⟨hf⟩ - tendsto_of_liminf_eq_limsup (le_antisymm (le_trans (liminf_le_limsup h h') hsup) hinf) + (h' : f.IsBoundedUnder (· ≥ ·) u := by isBoundedDefault) : Tendsto u f (𝓝 a) := by + 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 @@ -245,13 +242,13 @@ variable [FirstCountableTopology α] {f : Filter β} [CountableInterFilter f] {u theorem eventually_le_limsup (hf : IsBoundedUnder (· ≤ ·) f u := by isBoundedDefault) : ∀ᶠ b in f, u b ≤ f.limsup u := by obtain ha | ha := isTop_or_exists_gt (f.limsup u) - · exact eventually_of_forall fun _ => ha _ + · exact Eventually.of_forall fun _ => ha _ by_cases H : IsGLB (Set.Ioi (f.limsup u)) (f.limsup u) · obtain ⟨u, -, -, hua, hu⟩ := H.exists_seq_antitone_tendsto ha have := fun n => eventually_lt_of_limsup_lt (hu n) hf exact (eventually_countable_forall.2 this).mono fun b hb => - ge_of_tendsto hua <| eventually_of_forall fun n => (hb _).le + ge_of_tendsto hua <| Eventually.of_forall fun n => (hb _).le · obtain ⟨x, hx, xa⟩ : ∃ x, (∀ ⦃b⦄, f.limsup u < b → x ≤ b) ∧ f.limsup u < x := by simp only [IsGLB, IsGreatest, lowerBounds, upperBounds, Set.mem_Ioi, Set.mem_setOf_eq, not_and, not_forall, not_le, exists_prop] at H @@ -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 x hx => le_antisymm hx bot_le, fun h => by rw [limsup_congr h] @@ -303,7 +300,7 @@ theorem Antitone.map_limsSup_of_continuousAt {F : Filter R} [NeBot F] {f : R → (cobdd : F.IsCobounded (· ≤ ·) := by isBoundedDefault) : f F.limsSup = F.liminf f := by apply le_antisymm - · rw [limsSup, f_decr.map_sInf_of_continuousAt' f_cont bdd_above cobdd] + · rw [limsSup, f_decr.map_csInf_of_continuousAt f_cont bdd_above cobdd] apply le_of_forall_lt intro c hc simp only [liminf, limsInf, eventually_map] at hc ⊢ @@ -328,7 +325,7 @@ theorem Antitone.map_limsSup_of_continuousAt {F : Filter R} [NeBot F] {f : R → by_contra! H have not_bot : ¬ IsBot F.limsSup := fun maybe_bot ↦ lt_irrefl (F.liminf f) <| lt_of_le_of_lt - (liminf_le_of_frequently_le (frequently_of_forall (fun r ↦ f_decr (maybe_bot r))) + (liminf_le_of_frequently_le (Frequently.of_forall (fun r ↦ f_decr (maybe_bot r))) (bdd_above.isBoundedUnder f_decr)) H obtain ⟨l, l_lt, h'l⟩ : ∃ l < F.limsSup, Set.Ioc l F.limsSup ⊆ { x : R | f x < F.liminf f } := by @@ -559,20 +556,41 @@ lemma liminf_add_const (F : Filter ι) [NeBot F] [Add R] [ContinuousAdd R] (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] + [CovariantClass R R (fun x y ↦ x + y) fun x y ↦ x ≤ y] (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] diff --git a/Mathlib/Topology/Algebra/Polynomial.lean b/Mathlib/Topology/Algebra/Polynomial.lean index 82175ebb00e13..663b8bd81dc20 100644 --- a/Mathlib/Topology/Algebra/Polynomial.lean +++ b/Mathlib/Topology/Algebra/Polynomial.lean @@ -6,7 +6,7 @@ Authors: Robert Y. Lewis import Mathlib.Algebra.Polynomial.AlgebraMap import Mathlib.Algebra.Polynomial.Inductions import Mathlib.Algebra.Polynomial.Splits -import Mathlib.Analysis.Normed.Field.Basic +import Mathlib.Analysis.Normed.Field.Lemmas import Mathlib.RingTheory.Polynomial.Vieta /-! @@ -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 afe0be4038552..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,44 +48,47 @@ 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 ↦ ?_⟩) fun k _ ↦ ⟨Real.pi / 2 ^ (k + 1), by positivity, le_rfl⟩).map Circle.exp rw [Set.mem_setOf_eq] at ht ⊢ refine lt_of_lt_of_le ht ?_ - rw [div_le_iff' (pow_pos two_pos _), ← div_le_iff hx] + rw [div_le_iff₀' (pow_pos two_pos _), ← div_le_iff₀ hx] refine (Nat.le_ceil (Real.pi / x)).trans ?_ exact_mod_cast (Nat.le_succ _).trans (Nat.lt_two_pow _).le -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 index 4834f7f44beb1..4a337be7878ae 100644 --- a/Mathlib/Topology/Algebra/ProperAction.lean +++ b/Mathlib/Topology/Algebra/ProperAction.lean @@ -14,8 +14,8 @@ import Mathlib.Topology.Sequences In this file we define proper action of a group on a topological space, and we prove that in this case the quotient space is T2. We also give equivalent definitions of proper action using ultrafilters and show the transfer of proper action to a closed subgroup. -We give sufficent conditions on the topological space such that the action is properly discontinuous -(see `ProperlyDiscontinuousSMul`) if and only if it is continuous in +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 @@ -73,9 +73,8 @@ class ProperSMul (G X : Type*) [TopologicalSpace G] [TopologicalSpace X] [Group attribute [to_additive existing] properSMul_iff -variable {G X Y Z : Type*} [Group G] [MulAction G X] [MulAction G Y] -variable [TopologicalSpace G] [TopologicalSpace X] [TopologicalSpace Y] -variable [TopologicalSpace Z] +variable {G X : Type*} [Group G] [MulAction G X] +variable [TopologicalSpace G] [TopologicalSpace X] /-- If a group acts properly then in particular it acts continuously. -/ @[to_additive "If a group acts properly then in particular it acts continuously."] @@ -86,7 +85,7 @@ instance (priority := 100) ProperSMul.toContinuousSMul [ProperSMul G X] : Contin /-- 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 +@[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`."] @@ -129,11 +128,9 @@ theorem t2Space_quotient_mulAction_of_properSMul [ProperSMul G X] : 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] + have : IsOpenQuotientMap (Prod.map π π) := + MulAction.isOpenQuotientMap_quotientMk.prodMap MulAction.isOpenQuotientMap_quotientMk + rw [← this.quotientMap.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, @@ -175,7 +172,7 @@ theorem properSMul_of_closedEmbedding {H : Type*} [Group H] [MulAction H X] [Top (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 h : IsProperMap (Prod.map f (fun x : X ↦ x)) := this.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] @@ -247,7 +244,7 @@ theorem properlyDiscontinuousSMul_iff_properSMul [T2Space X] [DiscreteTopology G 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 <| + (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. 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 84e24b6c25393..94cf82277f373 100644 --- a/Mathlib/Topology/Algebra/Ring/Basic.lean +++ b/Mathlib/Topology/Algebra/Ring/Basic.lean @@ -25,6 +25,7 @@ of topological (semi)rings. - The indexed product of topological (semi)rings is a topological (semi)ring. -/ +assert_not_exists Cardinal open Set Filter TopologicalSpace Function Topology Filter @@ -39,7 +40,7 @@ The `TopologicalSemiring` class should *only* be instantiated in the presence of `NonUnitalNonAssocSemiring` instance; if there is an instance of `NonUnitalNonAssocRing`, then `TopologicalRing` should be used. Note: in the presence of `NonAssocRing`, these classes are mathematically equivalent (see `TopologicalSemiring.continuousNeg_of_mul` or -`TopologicalSemiring.toTopologicalRing`). -/ +`TopologicalSemiring.toTopologicalRing`). -/ class TopologicalSemiring [TopologicalSpace α] [NonUnitalNonAssocSemiring α] extends ContinuousAdd α, ContinuousMul α : Prop diff --git a/Mathlib/Topology/Algebra/Ring/Ideal.lean b/Mathlib/Topology/Algebra/Ring/Ideal.lean index bd45ee761f821..aa3cf06eb57a1 100644 --- a/Mathlib/Topology/Algebra/Ring/Ideal.lean +++ b/Mathlib/Topology/Algebra/Ring/Ideal.lean @@ -51,26 +51,18 @@ 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.isOpenMap_coe : IsOpenMap (mk N) := + QuotientAddGroup.isOpenMap_coe + +theorem QuotientRing.isOpenQuotientMap_mk : IsOpenQuotientMap (mk N) := + QuotientAddGroup.isOpenQuotientMap_mk theorem QuotientRing.quotientMap_coe_coe : QuotientMap fun p : R × R => (mk N p.1, mk N p.2) := - 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 } + ((isOpenQuotientMap_mk N).prodMap (isOpenQuotientMap_mk N)).quotientMap + +instance topologicalRing_quotient : TopologicalRing (R ⧸ N) where + __ := QuotientAddGroup.instTopologicalAddGroup _ + continuous_mul := (QuotientRing.quotientMap_coe_coe N).continuous_iff.2 <| + continuous_quot_mk.comp continuous_mul end CommRing diff --git a/Mathlib/Topology/Algebra/SeparationQuotient.lean b/Mathlib/Topology/Algebra/SeparationQuotient.lean new file mode 100644 index 0000000000000..83775bba6cbe3 --- /dev/null +++ b/Mathlib/Topology/Algebra/SeparationQuotient.lean @@ -0,0 +1,474 @@ +/- +Copyright (c) 2024 Yury Kudryashov. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yury Kudryashov +-/ +import Mathlib.LinearAlgebra.Basis.VectorSpace +import Mathlib.Topology.Algebra.Module.Basic +import Mathlib.Topology.Maps.OpenQuotient + +/-! +# Algebraic operations on `SeparationQuotient` + +In this file we define algebraic operations (multiplication, addition etc) +on the separation quotient of a topological space with corresponding operation, +provided that the original operation is continuous. + +We also prove continuity of these operations +and show that they satisfy the same kind of laws (`Monoid` etc) as the original ones. + +Finally, we construct a section of the quotient map +which is a continuous linear map `SeparationQuotient E →L[K] E`. +-/ + +namespace SeparationQuotient + +section SMul + +variable {M X : Type*} [TopologicalSpace X] [SMul M X] [ContinuousConstSMul M X] + +@[to_additive] +instance instSMul : SMul M (SeparationQuotient X) where + smul c := Quotient.map' (c • ·) fun _ _ h ↦ h.const_smul c + +@[to_additive (attr := simp)] +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_mk.comp <| continuous_const_smul c + +@[to_additive] +instance instIsPretransitiveSMul [MulAction.IsPretransitive M X] : + MulAction.IsPretransitive M (SeparationQuotient X) where + exists_smul_eq := surjective_mk.forall₂.2 fun x y ↦ + (MulAction.exists_smul_eq M x y).imp fun _ ↦ congr_arg mk + +@[to_additive] +instance instIsCentralScalar [SMul Mᵐᵒᵖ X] [IsCentralScalar M X] : + IsCentralScalar M (SeparationQuotient X) where + op_smul_eq_smul a := surjective_mk.forall.2 (congr_arg mk <| op_smul_eq_smul a ·) + +variable {N : Type*} [SMul N X] + +@[to_additive] +instance instSMulCommClass [ContinuousConstSMul N X] [SMulCommClass M N X] : + SMulCommClass M N (SeparationQuotient X) := + surjective_mk.smulCommClass mk_smul mk_smul + +@[to_additive instVAddAssocClass] +instance instIsScalarTower [SMul M N] [ContinuousConstSMul N X] [IsScalarTower M N X] : + IsScalarTower M N (SeparationQuotient X) where + smul_assoc a b := surjective_mk.forall.2 fun x ↦ congr_arg mk <| smul_assoc a b x + +end SMul + +instance instContinuousSMul {M X : Type*} [SMul M X] [TopologicalSpace M] [TopologicalSpace X] + [ContinuousSMul M X] : ContinuousSMul M (SeparationQuotient X) where + continuous_smul := by + rw [(IsOpenQuotientMap.id.prodMap isOpenQuotientMap_mk).quotientMap.continuous_iff] + 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 + +@[to_additive] +instance instMulAction {M X : Type*} [Monoid M] [MulAction M X] [TopologicalSpace X] + [ContinuousConstSMul M X] : MulAction M (SeparationQuotient X) := + surjective_mk.mulAction mk mk_smul + +section Monoid + +variable {M : Type*} [TopologicalSpace M] + +@[to_additive] +instance instMul [Mul M] [ContinuousMul M] : Mul (SeparationQuotient M) where + mul := Quotient.map₂' (· * ·) fun _ _ h₁ _ _ h₂ ↦ Inseparable.mul h₁ h₂ + +@[to_additive (attr := simp)] +theorem mk_mul [Mul M] [ContinuousMul M] (a b : M) : mk (a * b) = mk a * mk b := rfl + + +@[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 + +@[to_additive] +instance instCommMagma [CommMagma M] [ContinuousMul M] : CommMagma (SeparationQuotient M) := + surjective_mk.commMagma mk mk_mul + +@[to_additive] +instance instSemigroup [Semigroup M] [ContinuousMul M] : Semigroup (SeparationQuotient M) := + surjective_mk.semigroup mk mk_mul + +@[to_additive] +instance instCommSemigroup [CommSemigroup M] [ContinuousMul M] : + CommSemigroup (SeparationQuotient M) := + surjective_mk.commSemigroup mk mk_mul + +@[to_additive] +instance instMulOneClass [MulOneClass M] [ContinuousMul M] : + MulOneClass (SeparationQuotient M) := + surjective_mk.mulOneClass mk mk_one mk_mul + +/-- `SeparationQuotient.mk` as a `MonoidHom`. -/ +@[to_additive (attr := simps) "`SeparationQuotient.mk` as an `AddMonoidHom`."] +def mkMonoidHom [MulOneClass M] [ContinuousMul M] : M →* SeparationQuotient M where + toFun := mk + map_mul' := mk_mul + map_one' := mk_one + +instance (priority := 900) instNSmul [AddMonoid M] [ContinuousAdd M] : + SMul ℕ (SeparationQuotient M) := + inferInstance + +@[to_additive existing instNSmul] +instance instPow [Monoid M] [ContinuousMul M] : Pow (SeparationQuotient M) ℕ where + pow x n := Quotient.map' (s₁ := inseparableSetoid M) (· ^ n) (fun _ _ h ↦ Inseparable.pow h n) x + +@[to_additive, simp] -- `mk_nsmul` is not a `simp` lemma because we have `mk_smul` +theorem mk_pow [Monoid M] [ContinuousMul M] (x : M) (n : ℕ) : mk (x ^ n) = (mk x) ^ n := rfl + +@[to_additive] +instance instMonoid [Monoid M] [ContinuousMul M] : Monoid (SeparationQuotient M) := + surjective_mk.monoid mk mk_one mk_mul mk_pow + +@[to_additive] +instance instCommMonoid [CommMonoid M] [ContinuousMul M] : CommMonoid (SeparationQuotient M) := + surjective_mk.commMonoid mk mk_one mk_mul mk_pow + +end Monoid + +section Group + +variable {G : Type*} [TopologicalSpace G] + +@[to_additive] +instance instInv [Inv G] [ContinuousInv G] : Inv (SeparationQuotient G) where + inv := Quotient.map' (·⁻¹) fun _ _ ↦ Inseparable.inv + +@[to_additive (attr := simp)] +theorem mk_inv [Inv G] [ContinuousInv G] (x : G) : mk x⁻¹ = (mk x)⁻¹ := rfl + +@[to_additive] +instance instContinuousInv [Inv G] [ContinuousInv G] : ContinuousInv (SeparationQuotient G) where + continuous_inv := quotientMap_mk.continuous_iff.2 <| continuous_mk.comp continuous_inv + +@[to_additive] +instance instInvolutiveInv [InvolutiveInv G] [ContinuousInv G] : + InvolutiveInv (SeparationQuotient G) := + surjective_mk.involutiveInv mk mk_inv + +@[to_additive] +instance instInvOneClass [InvOneClass G] [ContinuousInv G] : + InvOneClass (SeparationQuotient G) where + inv_one := congr_arg mk inv_one + +@[to_additive] +instance instDiv [Div G] [ContinuousDiv G] : Div (SeparationQuotient G) where + div := Quotient.map₂' (· / ·) fun _ _ h₁ _ _ h₂ ↦ (Inseparable.prod h₁ h₂).map continuous_div' + +@[to_additive (attr := simp)] +theorem mk_div [Div G] [ContinuousDiv G] (x y : G) : mk (x / y) = mk x / mk y := rfl + +@[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' + +instance instZSMul [AddGroup G] [TopologicalAddGroup G] : SMul ℤ (SeparationQuotient G) := + inferInstance + +@[to_additive existing] +instance instZPow [Group G] [TopologicalGroup G] : Pow (SeparationQuotient G) ℤ where + pow x n := Quotient.map' (s₁ := inseparableSetoid G) (· ^ n) (fun _ _ h ↦ Inseparable.zpow h n) x + +@[to_additive, simp] -- `mk_zsmul` is not a `simp` lemma because we have `mk_smul` +theorem mk_zpow [Group G] [TopologicalGroup G] (x : G) (n : ℤ) : mk (x ^ n) = (mk x) ^ n := rfl + +@[to_additive] +instance instGroup [Group G] [TopologicalGroup G] : Group (SeparationQuotient G) := + surjective_mk.group mk mk_one mk_mul mk_inv mk_div mk_pow mk_zpow + +@[to_additive] +instance instCommGroup [CommGroup G] [TopologicalGroup G] : CommGroup (SeparationQuotient G) := + surjective_mk.commGroup mk mk_one mk_mul mk_inv mk_div mk_pow mk_zpow + +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₀] + +instance instMulZeroClass [MulZeroClass M₀] [ContinuousMul M₀] : + MulZeroClass (SeparationQuotient M₀) := + surjective_mk.mulZeroClass mk mk_zero mk_mul + +instance instSemigroupWithZero [SemigroupWithZero M₀] [ContinuousMul M₀] : + SemigroupWithZero (SeparationQuotient M₀) := + surjective_mk.semigroupWithZero mk mk_zero mk_mul + +instance instMulZeroOneClass [MulZeroOneClass M₀] [ContinuousMul M₀] : + MulZeroOneClass (SeparationQuotient M₀) := + surjective_mk.mulZeroOneClass mk mk_zero mk_one mk_mul + +instance instMonoidWithZero [MonoidWithZero M₀] [ContinuousMul M₀] : + MonoidWithZero (SeparationQuotient M₀) := + surjective_mk.monoidWithZero mk mk_zero mk_one mk_mul mk_pow + +instance instCommMonoidWithZero [CommMonoidWithZero M₀] [ContinuousMul M₀] : + CommMonoidWithZero (SeparationQuotient M₀) := + surjective_mk.commMonoidWithZero mk mk_zero mk_one mk_mul mk_pow + +end MonoidWithZero + +section Ring + +variable {R : Type*} [TopologicalSpace R] + +instance instDistrib [Distrib R] [ContinuousMul R] [ContinuousAdd R] : + Distrib (SeparationQuotient R) := + surjective_mk.distrib mk mk_add mk_mul + +instance instLeftDistribClass [Mul R] [Add R] [LeftDistribClass R] + [ContinuousMul R] [ContinuousAdd R] : + LeftDistribClass (SeparationQuotient R) := + surjective_mk.leftDistribClass mk mk_add mk_mul + +instance instRightDistribClass [Mul R] [Add R] [RightDistribClass R] + [ContinuousMul R] [ContinuousAdd R] : + RightDistribClass (SeparationQuotient R) := + surjective_mk.rightDistribClass mk mk_add mk_mul + +instance instNonUnitalnonAssocSemiring [NonUnitalNonAssocSemiring R] + [TopologicalSemiring R] : NonUnitalNonAssocSemiring (SeparationQuotient R) := + surjective_mk.nonUnitalNonAssocSemiring mk mk_zero mk_add mk_mul mk_smul + +instance instNonUnitalSemiring [NonUnitalSemiring R] [TopologicalSemiring R] : + NonUnitalSemiring (SeparationQuotient R) := + surjective_mk.nonUnitalSemiring mk mk_zero mk_add mk_mul mk_smul + +instance instNatCast [NatCast R] : NatCast (SeparationQuotient R) where + natCast n := mk n + +@[simp, norm_cast] +theorem mk_natCast [NatCast R] (n : ℕ) : mk (n : R) = n := rfl + +@[simp] +theorem mk_ofNat [NatCast R] (n : ℕ) [n.AtLeastTwo] : + mk (no_index (OfNat.ofNat n) : R) = OfNat.ofNat n := + rfl + +instance instIntCast [IntCast R] : IntCast (SeparationQuotient R) where + intCast n := mk n + +@[simp, norm_cast] +theorem mk_intCast [IntCast R] (n : ℤ) : mk (n : R) = n := rfl + +instance instNonAssocSemiring [NonAssocSemiring R] [TopologicalSemiring R] : + NonAssocSemiring (SeparationQuotient R) := + surjective_mk.nonAssocSemiring mk mk_zero mk_one mk_add mk_mul mk_smul mk_natCast + +instance instNonUnitalNonAssocRing [NonUnitalNonAssocRing R] [TopologicalRing R] : + NonUnitalNonAssocRing (SeparationQuotient R) := + surjective_mk.nonUnitalNonAssocRing mk mk_zero mk_add mk_mul mk_neg mk_sub mk_smul mk_smul + +instance instNonUnitalRing [NonUnitalRing R] [TopologicalRing R] : + NonUnitalRing (SeparationQuotient R) := + surjective_mk.nonUnitalRing mk mk_zero mk_add mk_mul mk_neg mk_sub mk_smul mk_smul + +instance instNonAssocRing [NonAssocRing R] [TopologicalRing R] : + NonAssocRing (SeparationQuotient R) := + surjective_mk.nonAssocRing mk mk_zero mk_one mk_add mk_mul mk_neg mk_sub mk_smul mk_smul + mk_natCast mk_intCast + +instance instSemiring [Semiring R] [TopologicalSemiring R] : + Semiring (SeparationQuotient R) := + surjective_mk.semiring mk mk_zero mk_one mk_add mk_mul mk_smul mk_pow mk_natCast + +instance instRing [Ring R] [TopologicalRing R] : + Ring (SeparationQuotient R) := + surjective_mk.ring mk mk_zero mk_one mk_add mk_mul mk_neg mk_sub mk_smul mk_smul mk_pow + mk_natCast mk_intCast + +instance instNonUnitalNonAssocCommSemiring [NonUnitalNonAssocCommSemiring R] + [TopologicalSemiring R] : + NonUnitalNonAssocCommSemiring (SeparationQuotient R) := + surjective_mk.nonUnitalNonAssocCommSemiring mk mk_zero mk_add mk_mul mk_smul + +instance instNonUnitalCommSemiring [NonUnitalCommSemiring R] [TopologicalSemiring R] : + NonUnitalCommSemiring (SeparationQuotient R) := + surjective_mk.nonUnitalCommSemiring mk mk_zero mk_add mk_mul mk_smul + +instance instCommSemiring [CommSemiring R] [TopologicalSemiring R] : + CommSemiring (SeparationQuotient R) := + surjective_mk.commSemiring mk mk_zero mk_one mk_add mk_mul mk_smul mk_pow mk_natCast + +instance instHasDistribNeg [Mul R] [HasDistribNeg R] [ContinuousMul R] [ContinuousNeg R] : + HasDistribNeg (SeparationQuotient R) := + surjective_mk.hasDistribNeg mk mk_neg mk_mul + +instance instNonUnitalNonAssocCommRing [NonUnitalNonAssocCommRing R] [TopologicalRing R] : + NonUnitalNonAssocCommRing (SeparationQuotient R) := + surjective_mk.nonUnitalNonAssocCommRing mk mk_zero mk_add mk_mul mk_neg mk_sub mk_smul mk_smul + +instance instNonUnitalCommRing [NonUnitalCommRing R] [TopologicalRing R] : + NonUnitalCommRing (SeparationQuotient R) := + surjective_mk.nonUnitalCommRing mk mk_zero mk_add mk_mul mk_neg mk_sub mk_smul mk_smul + +instance instCommRing [CommRing R] [TopologicalRing R] : + CommRing (SeparationQuotient 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 + +variable {M A : Type*} [TopologicalSpace A] + +instance instDistribSMul [AddZeroClass A] [DistribSMul M A] + [ContinuousAdd A] [ContinuousConstSMul M A] : + DistribSMul M (SeparationQuotient A) := + surjective_mk.distribSMul mkAddMonoidHom mk_smul + +instance instDistribMulAction [Monoid M] [AddMonoid A] [DistribMulAction M A] + [ContinuousAdd A] [ContinuousConstSMul M A] : + DistribMulAction M (SeparationQuotient A) := + surjective_mk.distribMulAction mkAddMonoidHom mk_smul + +instance instMulDistribMulAction [Monoid M] [Monoid A] [MulDistribMulAction M A] + [ContinuousMul A] [ContinuousConstSMul M A] : + MulDistribMulAction M (SeparationQuotient A) := + surjective_mk.mulDistribMulAction mkMonoidHom mk_smul + +end DistribSMul + +section Module + +variable {R M : Type*} [Semiring R] [AddCommMonoid M] [Module R M] + [TopologicalSpace M] [ContinuousAdd M] [ContinuousConstSMul R M] + +instance instModule : Module R (SeparationQuotient M) := + surjective_mk.module R mkAddMonoidHom mk_smul + +variable (R M) + +/-- `SeparationQuotient.mk` as a continuous linear map. -/ +@[simps] +def mkCLM : M →L[R] SeparationQuotient M where + toFun := mk + map_add' := mk_add + map_smul' := mk_smul + +end Module + +section Algebra +variable {R A : Type*} [CommSemiring R] [Semiring A] [Algebra R A] + [TopologicalSpace A] [TopologicalSemiring A] [ContinuousConstSMul R A] + +instance instAlgebra : Algebra R (SeparationQuotient A) where + toRingHom := mkRingHom.comp (algebraMap R A) + commutes' r := Quotient.ind fun a => congrArg _ <| Algebra.commutes r a + smul_def' r := Quotient.ind fun a => congrArg _ <| Algebra.smul_def r a + +@[simp] +theorem mk_algebraMap (r : R) : mk (algebraMap R A r) = algebraMap R (SeparationQuotient A) r := + rfl + +end Algebra + +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, inducing_mk.continuous_iff.2 (by continuity)⟩, DFunLike.ext' hf⟩ + +/-- A continuous `K`-linear map from `SeparationQuotient E` to `E` +such that `mk (outCLM x) = x` for all `x`. -/ +noncomputable def outCLM : SeparationQuotient E →L[K] E := + (exists_out_continuousLinearMap K E).choose + +@[simp] +theorem mkCLM_comp_outCLM : mkCLM K E ∘L outCLM K E = .id K (SeparationQuotient E) := + (exists_out_continuousLinearMap K E).choose_spec + +variable {E} in +@[simp] +theorem mk_outCLM (x : SeparationQuotient E) : mk (outCLM K E x) = x := + DFunLike.congr_fun (mkCLM_comp_outCLM K E) x + +@[simp] +theorem mk_comp_outCLM : mk ∘ outCLM K E = id := funext (mk_outCLM K) + +variable {K} in +theorem postcomp_mkCLM_surjective {L : Type*} [Semiring L] (σ : L →+* K) + (F : Type*) [AddCommMonoid F] [Module L F] [TopologicalSpace F] : + Function.Surjective ((mkCLM K E).comp : (F →SL[σ] E) → (F →SL[σ] SeparationQuotient E)) := by + intro f + use (outCLM K E).comp f + rw [← ContinuousLinearMap.comp_assoc, mkCLM_comp_outCLM, ContinuousLinearMap.id_comp] + +/-- The `SeparationQuotient.outCLM K E` map is a topological embedding. -/ +theorem outCLM_embedding : Embedding (outCLM K E) := + Function.LeftInverse.embedding (mk_outCLM K) continuous_mk (map_continuous _) + +theorem outCLM_injective : Function.Injective (outCLM K E) := + (outCLM_embedding K E).injective + +end VectorSpace + +section VectorSpaceUniform + +variable (K E : Type*) [DivisionRing K] [AddCommGroup E] [Module K E] + [UniformSpace E] [UniformAddGroup E] [ContinuousConstSMul K E] + +theorem outCLM_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..0703fc4753013 100644 --- a/Mathlib/Topology/Algebra/StarSubalgebra.lean +++ b/Mathlib/Topology/Algebra/StarSubalgebra.lean @@ -146,7 +146,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 @@ -242,12 +242,12 @@ theorem induction_on {x y : A} 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) + have : StarHomClass F (↥(topologicalClosure (adjoin R {a}))) B := + inferInstanceAs (StarHomClass F (elementalStarAlgebra R a) B) refine StarAlgHomClass.ext_topologicalClosure hφ hψ fun x => ?_ refine adjoin_induction' x ?_ ?_ ?_ ?_ ?_ exacts [fun y hy => by simpa only [Set.mem_singleton_iff.mp hy] using h, fun r => by diff --git a/Mathlib/Topology/Algebra/UniformConvergence.lean b/Mathlib/Topology/Algebra/UniformConvergence.lean index adf3afef18aff..beee906368d6e 100644 --- a/Mathlib/Topology/Algebra/UniformConvergence.lean +++ b/Mathlib/Topology/Algebra/UniformConvergence.lean @@ -252,8 +252,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 c626826669020..da3fb454151fa 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,7 +145,7 @@ 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 @@ -176,7 +176,7 @@ 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 @@ -195,3 +195,20 @@ instance (priority := 100) completableTopField_of_complete (L : Type*) [Field L] calc map (fun x => x⁻¹) F ≤ map (fun x => x⁻¹) (𝓝 x) := map_mono hx _ ≤ 𝓝 x⁻¹ := continuousAt_inv₀ hx' + +variable {α β : Type*} [Field β] [b : UniformSpace β] [CompletableTopField β] + [Field α] + +/-- The pullback of a completable topological field along a uniform inducing +ring homomorphism is a completable topological field. -/ +theorem IsUniformInducing.completableTopField + [UniformSpace α] [T0Space α] + {f : α →+* β} (hf : IsUniformInducing f) : + CompletableTopField α := by + refine CompletableTopField.mk (fun F F_cau inf_F => ?_) + 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] diff --git a/Mathlib/Topology/Algebra/UniformGroup.lean b/Mathlib/Topology/Algebra/UniformGroup.lean index f667159ebd3f8..c05bd7340d340 100644 --- a/Mathlib/Topology/Algebra/UniformGroup.lean +++ b/Mathlib/Topology/Algebra/UniformGroup.lean @@ -93,6 +93,33 @@ theorem UniformContinuous.mul [UniformSpace β] {f : β → α} {g : β → α} 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 @@ -146,19 +173,22 @@ theorem uniformity_translate_mul (a : α) : ((𝓤 α).map fun x : α × α => ( (calc 𝓤 α = ((𝓤 α).map fun x : α × α => (x.1 * a⁻¹, x.2 * a⁻¹)).map fun x : α × α => - (x.1 * a, x.2 * a) := by simp [Filter.map_map, (· ∘ ·)] + (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 } +@[deprecated (since := "2024-10-01")] +alias uniformEmbedding_translate_mul := isUniformEmbedding_translate_mul + namespace MulOpposite @[to_additive] @@ -195,18 +225,21 @@ theorem uniformGroup_inf {u₁ u₂ : UniformSpace β} (h₁ : @UniformGroup β 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 @@ -270,7 +303,7 @@ 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 [(· ∘ ·)] + simp [Function.comp_def] @[to_additive] theorem uniformity_eq_comap_inv_mul_nhds_one_swapped : @@ -464,7 +497,7 @@ def TopologicalGroup.toUniformSpace : UniformSpace G where 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, (· ∘ ·), nhds_translation_div] + nhds_eq_comap_uniformity _ := by simp only [comap_comap, Function.comp_def, nhds_translation_div] attribute [local instance] TopologicalGroup.toUniformSpace @@ -568,7 +601,7 @@ theorem comm_topologicalGroup_is_uniform : UniformGroup G := by 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, div_eq_mul_inv, mul_inv_rev, inv_inv, mul_comm, mul_left_comm] at * + 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 @@ -597,7 +630,7 @@ variable [TopologicalSpace β] [Group β] variable [FunLike hom β α] [MonoidHomClass hom β α] {e : hom} @[to_additive] -theorem tendsto_div_comap_self (de : DenseInducing e) (x₀ : α) : +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)) = @@ -611,7 +644,7 @@ theorem tendsto_div_comap_self (de : DenseInducing e) (x₀ : α) : end -namespace DenseInducing +namespace IsDenseInducing variable {α : Type*} {β : Type*} {γ : Type*} {δ : Type*} variable {G : Type*} @@ -623,8 +656,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 +731,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 +773,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 @@ -829,7 +862,7 @@ instance QuotientGroup.completeSpace' (G : Type u) [Group G] [TopologicalSpace G exact fun m => ⟨m, fun n hmn => Nat.decreasingInduction' - (fun k _ _ hk => u_mul k ⟨_, hx' k, _, hk, div_mul_div_cancel' _ _ _⟩) hmn + (fun k _ _ hk => u_mul k ⟨_, hx' k, _, hk, div_mul_div_cancel _ _ _⟩) hmn (by simpa only [div_self'] using mem_of_mem_nhds (hu.mem _))⟩ /- Since `G` is complete, `x'` converges to some `x₀`, and so the image of this sequence under the quotient map converges to `↑x₀`. The image of `x'` is a convergent subsequence of `x`, and @@ -850,7 +883,7 @@ already equipped with a uniform structure. Even though `G` is equipped with a uniform structure, the quotient `G ⧸ N` does not inherit a uniform structure, so it is still provided manually via `TopologicalGroup.toUniformSpace`. In the most common use cases, this coincides (definitionally) with the uniform structure on the -quotient obtained via other means. -/ +quotient obtained via other means. -/ @[to_additive "The quotient `G ⧸ N` of a complete first countable uniform additive group `G` by a normal additive subgroup is itself complete. Consequently, quotients of Banach spaces by subspaces are complete. In contrast to `QuotientAddGroup.completeSpace'`, in this version diff --git a/Mathlib/Topology/Algebra/UniformMulAction.lean b/Mathlib/Topology/Algebra/UniformMulAction.lean index 4c23eda8c9359..3f0de8b6107d6 100644 --- a/Mathlib/Topology/Algebra/UniformMulAction.lean +++ b/Mathlib/Topology/Algebra/UniformMulAction.lean @@ -88,13 +88,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 +119,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..7ad0d76af8d94 100644 --- a/Mathlib/Topology/Algebra/UniformRing.lean +++ b/Mathlib/Topology/Algebra/UniformRing.lean @@ -38,7 +38,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 +47,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 +59,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 +70,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 +222,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 @@ -276,28 +276,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 a947a5a38370c..2c9ce7c08f2c8 100644 --- a/Mathlib/Topology/Algebra/Valued/NormedValued.lean +++ b/Mathlib/Topology/Algebra/Valued/NormedValued.lean @@ -4,6 +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.RingTheory.Valuation.RankOne import Mathlib.Topology.Algebra.Valued.ValuationTopology @@ -96,12 +97,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 diff --git a/Mathlib/Topology/Algebra/Valued/ValuationTopology.lean b/Mathlib/Topology/Algebra/Valued/ValuationTopology.lean index acf68e9cf8d30..22bb1f84d63f6 100644 --- a/Mathlib/Topology/Algebra/Valued/ValuationTopology.lean +++ b/Mathlib/Topology/Algebra/Valued/ValuationTopology.lean @@ -15,10 +15,7 @@ The main definition is a `Valued` type class which equips a ring with a valuatio values in a group with zero. Other instances are then deduced from this. -/ - -open scoped Classical -open Topology uniformity - +open scoped Topology uniformity open Set Valuation noncomputable section diff --git a/Mathlib/Topology/Algebra/Valued/ValuedField.lean b/Mathlib/Topology/Algebra/Valued/ValuedField.lean index 615d15555a9be..99151442537d6 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.toInducing.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 @@ -364,7 +364,7 @@ def integer : Subring K := (vK.v).integer @[inherit_doc] scoped notation "𝒪[" K "]" => Valued.integer K -/-- An abbrevation for `LocalRing.maximalIdeal 𝒪[K]` of a valued field `K`, enabling the notation +/-- An abbreviation for `LocalRing.maximalIdeal 𝒪[K]` of a valued field `K`, enabling the notation `𝓂[K]` for the maximal ideal in `𝒪[K]` of a valued field `K`. -/ @[reducible] def maximalIdeal : Ideal 𝒪[K] := LocalRing.maximalIdeal 𝒪[K] @@ -372,7 +372,7 @@ def maximalIdeal : Ideal 𝒪[K] := LocalRing.maximalIdeal 𝒪[K] @[inherit_doc] scoped notation "𝓂[" K "]" => maximalIdeal K -/-- An abbrevation for `LocalRing.ResidueField 𝒪[K]` of a `Valued` instance, enabling the notation +/-- An abbreviation for `LocalRing.ResidueField 𝒪[K]` of a `Valued` instance, enabling the notation `𝓀[K]` for the residue field of a valued field `K`. -/ @[reducible] def ResidueField := LocalRing.ResidueField (𝒪[K]) diff --git a/Mathlib/Topology/Algebra/WithZeroTopology.lean b/Mathlib/Topology/Algebra/WithZeroTopology.lean index ae51c607ad1c0..8b290b9995546 100644 --- a/Mathlib/Topology/Algebra/WithZeroTopology.lean +++ b/Mathlib/Topology/Algebra/WithZeroTopology.lean @@ -159,7 +159,7 @@ scoped instance (priority := 100) : ContinuousMul Γ₀ where rintro ⟨x, y⟩ wlog hle : x ≤ y generalizing x y · have := (this y x (le_of_not_le hle)).comp (continuous_swap.tendsto (x, y)) - simpa only [mul_comm, Function.comp, Prod.swap] using this + simpa only [mul_comm, Function.comp_def, Prod.swap] using this rcases eq_or_ne x 0 with (rfl | hx) <;> [rcases eq_or_ne y 0 with (rfl | hy); skip] · rw [zero_mul] refine ((hasBasis_nhds_zero.prod_nhds hasBasis_nhds_zero).tendsto_iff hasBasis_nhds_zero).2 @@ -169,7 +169,7 @@ scoped instance (priority := 100) : ContinuousMul Γ₀ where · rw [zero_mul, nhds_prod_eq, nhds_of_ne_zero hy, prod_pure, tendsto_map'_iff] refine (hasBasis_nhds_zero.tendsto_iff hasBasis_nhds_zero).2 fun γ hγ => ?_ refine ⟨γ / y, div_ne_zero hγ hy, fun x hx => ?_⟩ - calc x * y < γ / y * y := mul_lt_right₀ _ hx hy + calc x * y < γ / y * y := mul_lt_mul_of_pos_right hx (zero_lt_iff.2 hy) _ = γ := div_mul_cancel₀ _ hy · have hy : y ≠ 0 := ((zero_lt_iff.mpr hx).trans_le hle).ne' rw [nhds_prod_eq, nhds_of_ne_zero hx, nhds_of_ne_zero hy, prod_pure_pure] diff --git a/Mathlib/Topology/Baire/BaireMeasurable.lean b/Mathlib/Topology/Baire/BaireMeasurable.lean new file mode 100644 index 0000000000000..02a160951b95f --- /dev/null +++ b/Mathlib/Topology/Baire/BaireMeasurable.lean @@ -0,0 +1,181 @@ +/- +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.LocallyClosed +import Mathlib.MeasureTheory.Constructions.EventuallyMeasurable +import Mathlib.MeasureTheory.Constructions.BorelSpace.Basic + +/-! +# Baire category and Baire measurable sets + +This file defines some of the basic notions of Baire category and Baire measurable sets. + +## Main definitions + +First, we define the notation `=ᵇ`. This denotes eventual equality with respect to the filter of +`residual` sets in a topological space. + +A set `s` in a topological space `α` is called a `BaireMeasurableSet` or said to have the +*property of Baire* if it satisfies either of the following equivalent conditions: + +* There is a *Borel* set `u` such that `s =ᵇ u`. (This is our definition) +* There is an *open* set `u` such that `s =ᵇ u`. (See `BaireMeasurableSet.residual_eq_open`) + +-/ + +variable (α : Type*) {β : Type*} [TopologicalSpace α] [TopologicalSpace β] + +open Topology + +/-- Notation for `=ᶠ[residual _]`. That is, eventual equality with respect to +the filter of residual sets.-/ +scoped[Topology] notation:50 f " =ᵇ " g:50 => Filter.EventuallyEq (residual _) f g + +/-- Notation to say that a property of points in a topological space holds +almost everywhere in the sense of Baire category. That is, on a residual set. -/ +scoped[Topology] notation3 "∀ᵇ "(...)", "r:(scoped p => Filter.Eventually p <| residual _) => r + +/-- Notation to say that a property of points in a topological space holds on a non meager set. -/ +scoped[Topology] notation3 "∃ᵇ "(...)", "r:(scoped p => Filter.Frequently p <| residual _) => r + +variable {α} + +/-- We say a set is a `BaireMeasurableSet` if it differs from some Borel set by +a meager set. This forms a σ-algebra. + +It is equivalent, and a more standard definition, to say that the set differs from +some *open* set by a meager set. See `BaireMeasurableSet.iff_residualEq_isOpen` -/ +def BaireMeasurableSet (s : Set α) : Prop := + @MeasurableSet _ (EventuallyMeasurableSpace (borel _) (residual _)) s + +variable {s t : Set α} + +namespace BaireMeasurableSet + +theorem of_mem_residual (h : s ∈ residual _) : BaireMeasurableSet s := + eventuallyMeasurableSet_of_mem_filter (α := α) h + +theorem _root_.MeasurableSet.baireMeasurableSet [MeasurableSpace α] [BorelSpace α] + (h : MeasurableSet s) : BaireMeasurableSet s := by + borelize α + exact h.eventuallyMeasurableSet + +theorem _root_.IsOpen.baireMeasurableSet (h : IsOpen s) : BaireMeasurableSet s := by + borelize α + exact h.measurableSet.baireMeasurableSet + +theorem compl (h : BaireMeasurableSet s) : BaireMeasurableSet sᶜ := MeasurableSet.compl h + +theorem of_compl (h : BaireMeasurableSet sᶜ) : BaireMeasurableSet s := MeasurableSet.of_compl h + +theorem _root_.IsMeagre.baireMeasurableSet (h : IsMeagre s) : BaireMeasurableSet s := + (of_mem_residual h).of_compl + +theorem iUnion {ι : Sort*} [Countable ι] {s : ι → Set α} + (h : ∀ i, BaireMeasurableSet (s i)) : BaireMeasurableSet (⋃ i, s i) := + MeasurableSet.iUnion h + +theorem biUnion {ι : Type*} {s : ι → Set α} {t : Set ι} (ht : t.Countable) + (h : ∀ i ∈ t, BaireMeasurableSet (s i)) : BaireMeasurableSet (⋃ i ∈ t, s i) := + MeasurableSet.biUnion ht h + +theorem sUnion {s : Set (Set α)} (hs : s.Countable) + (h : ∀ t ∈ s, BaireMeasurableSet t) : BaireMeasurableSet (⋃₀ s) := + MeasurableSet.sUnion hs h + +theorem iInter {ι : Sort*} [Countable ι] {s : ι → Set α} + (h : ∀ i, BaireMeasurableSet (s i)) : BaireMeasurableSet (⋂ i, s i) := + MeasurableSet.iInter h + +theorem biInter {ι : Type*} {s : ι → Set α} {t : Set ι} (ht : t.Countable) + (h : ∀ i ∈ t, BaireMeasurableSet (s i)) : BaireMeasurableSet (⋂ i ∈ t, s i) := + MeasurableSet.biInter ht h + +theorem sInter {s : Set (Set α)} (hs : s.Countable) + (h : ∀ t ∈ s, BaireMeasurableSet t) : BaireMeasurableSet (⋂₀ s) := + MeasurableSet.sInter hs h + +theorem union (hs : BaireMeasurableSet s) (ht : BaireMeasurableSet t) : + BaireMeasurableSet (s ∪ t) := + MeasurableSet.union hs ht + +theorem inter (hs : BaireMeasurableSet s) (ht : BaireMeasurableSet t) : + BaireMeasurableSet (s ∩ t) := + MeasurableSet.inter hs ht + +theorem diff (hs : BaireMeasurableSet s) (ht : BaireMeasurableSet t) : + BaireMeasurableSet (s \ t) := + MeasurableSet.diff hs ht + +theorem congr (hs : BaireMeasurableSet s) (h : s =ᵇ t) : BaireMeasurableSet t := + EventuallyMeasurableSet.congr (α := α) hs h.symm + +end BaireMeasurableSet + +open Filter + +/--Any Borel set differs from some open set by a meager set. -/ +theorem MeasurableSet.residualEq_isOpen [MeasurableSpace α] [BorelSpace α] (h : MeasurableSet s) : + ∃ u : Set α, (IsOpen u) ∧ s =ᵇ u := by + apply h.induction_on_open (fun s hs => ⟨s, hs, EventuallyEq.rfl⟩) + · rintro s - ⟨u, uo, su⟩ + refine ⟨(closure u)ᶜ, isClosed_closure.isOpen_compl, + EventuallyEq.compl (su.trans <| EventuallyLE.antisymm subset_closure.eventuallyLE ?_)⟩ + have : (coborder u) ∈ residual _ := + residual_of_dense_open uo.isLocallyClosed.isOpen_coborder dense_coborder + rw [coborder_eq_union_closure_compl] at this + rw [EventuallyLE] + convert this + simp only [le_Prop_eq, imp_iff_or_not] + rfl --terrible + rintro s - - hs + choose u uo su using hs + exact ⟨⋃ i, u i, isOpen_iUnion uo, EventuallyEq.countable_iUnion su⟩ + +/--Any `BaireMeasurableSet` differs from some open set by a meager set. -/ +theorem BaireMeasurableSet.residualEq_isOpen (h : BaireMeasurableSet s) : + ∃ u : Set α, (IsOpen u) ∧ s =ᵇ u := by + borelize α + rcases h with ⟨t, ht, hst⟩ + rcases ht.residualEq_isOpen with ⟨u, hu, htu⟩ + exact ⟨u, hu, hst.trans htu⟩ + +/--A set is Baire measurable if and only if it differs from some open set by a meager set. -/ +theorem BaireMeasurableSet.iff_residualEq_isOpen : + BaireMeasurableSet s ↔ ∃ u : Set α, (IsOpen u) ∧ s =ᵇ u := + ⟨fun h => h.residualEq_isOpen , fun ⟨_, uo, ueq⟩ => uo.baireMeasurableSet.congr ueq.symm⟩ + +section Map + +open Set + +variable {f : α → β} + +theorem tendsto_residual_of_isOpenMap (hc : Continuous f) (ho : IsOpenMap f) : + Tendsto f (residual α) (residual β) := by + apply le_countableGenerate_iff_of_countableInterFilter.mpr + rintro t ⟨ht, htd⟩ + exact residual_of_dense_open (ht.preimage hc) (htd.preimage ho) + +/-- The preimage of a meager set under a continuous open map is meager. -/ +theorem IsMeagre.preimage_of_isOpenMap (hc : Continuous f) (ho : IsOpenMap f) + {s : Set β} (h : IsMeagre s) : IsMeagre (f ⁻¹' s) := + tendsto_residual_of_isOpenMap hc ho h + +/-- The preimage of a `BaireMeasurableSet` under a continuous open map is Baire measurable. -/ +theorem BaireMeasurableSet.preimage (hc : Continuous f) (ho : IsOpenMap f) + {s : Set β} (h : BaireMeasurableSet s) : BaireMeasurableSet (f⁻¹' s) := by + rcases h with ⟨u, hu, hsu⟩ + refine ⟨f ⁻¹' u, ?_, hsu.filter_mono <| tendsto_residual_of_isOpenMap hc ho⟩ + borelize α β + exact hc.measurable hu + +theorem Homeomorph.residual_map_eq (h : α ≃ₜ β) : (residual α).map h = residual β := by + refine le_antisymm (tendsto_residual_of_isOpenMap h.continuous h.isOpenMap) (le_map ?_) + simp_rw [← preimage_symm] + exact tendsto_residual_of_isOpenMap h.symm.continuous h.symm.isOpenMap + +end Map diff --git a/Mathlib/Topology/Bases.lean b/Mathlib/Topology/Bases.lean index 7930817c3788d..bc50dd33b1af8 100644 --- a/Mathlib/Topology/Bases.lean +++ b/Mathlib/Topology/Bases.lean @@ -65,7 +65,7 @@ variable {α : Type u} {β : Type*} [t : TopologicalSpace α] {B : Set (Set α)} it suffices to take unions of the basis sets to get a topology (without taking finite intersections as well). -/ structure IsTopologicalBasis (s : Set (Set α)) : Prop where - /-- For every point `x`, the set of `t ∈ s` such that `x ∈ t` is directed downwards. -/ + /-- For every point `x`, the set of `t ∈ s` such that `x ∈ t` is directed downwards. -/ exists_subset_inter : ∀ t₁ ∈ s, ∀ t₂ ∈ s, ∀ x ∈ t₁ ∩ t₂, ∃ t₃ ∈ s, x ∈ t₃ ∧ t₃ ⊆ t₁ ∩ t₂ /-- The sets from `s` cover the whole space. -/ sUnion_eq : ⋃₀ s = univ @@ -286,11 +286,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 @@ -382,9 +377,9 @@ instance {ι : Type*} {X : ι → Type*} [∀ i, TopologicalSpace (X i)] [∀ i, (htd i).exists_mem_open (huo i i.2).1 ⟨_, (huo i i.2).2⟩ choose y hyt hyu using this lift y to ∀ i : I, t i using hyt - refine ⟨f ⟨I, y⟩, huU fun i (hi : i ∈ I) ↦ ?_, mem_range_self _⟩ + refine ⟨f ⟨I, y⟩, huU fun i (hi : i ∈ I) ↦ ?_, mem_range_self ⟨I, y⟩⟩ simp only [f, dif_pos hi] - exact hyu _ + exact hyu ⟨i, _⟩ instance [SeparableSpace α] {r : α → α → Prop} : SeparableSpace (Quot r) := quotientMap_quot_mk.separableSpace @@ -476,7 +471,7 @@ theorem IsSeparable.univ_pi {ι : Type*} [Countable ι] {X : ι → Type*} {s : refine ⟨range g, countable_range g, fun f hf ↦ mem_closure_iff.2 fun o ho hfo ↦ ?_⟩ rcases isOpen_pi_iff.1 ho f hfo with ⟨I, u, huo, hI⟩ rsuffices ⟨f, hf⟩ : ∃ f : (i : I) → c i, g ⟨I, f⟩ ∈ Set.pi I u - · exact ⟨g ⟨I, f⟩, hI hf, mem_range_self _⟩ + · exact ⟨g ⟨I, f⟩, hI hf, mem_range_self ⟨I, f⟩⟩ suffices H : ∀ i ∈ I, (u i ∩ c i).Nonempty by choose f hfu hfc using H refine ⟨fun i ↦ ⟨f i i.2, hfc i i.2⟩, fun i (hi : i ∈ I) ↦ ?_⟩ @@ -802,9 +797,8 @@ instance {ι : Type*} {π : ι → Type*} [Countable ι] [∀ a, TopologicalSpac instance (priority := 100) SecondCountableTopology.to_separableSpace [SecondCountableTopology α] : SeparableSpace α := by choose p hp using fun s : countableBasis α => nonempty_of_mem_countableBasis s.2 - exact - ⟨⟨range p, countable_range _, - (isBasis_countableBasis α).dense_iff.2 fun o ho _ => ⟨p ⟨o, ho⟩, hp _, mem_range_self _⟩⟩⟩ + exact ⟨⟨range p, countable_range _, (isBasis_countableBasis α).dense_iff.2 fun o ho _ => + ⟨p ⟨o, ho⟩, hp ⟨o, _⟩, mem_range_self _⟩⟩⟩ /-- A countable open cover induces a second-countable topology if all open covers are themselves second countable. -/ diff --git a/Mathlib/Topology/Basic.lean b/Mathlib/Topology/Basic.lean index 4b628fa42662d..55a8aa4aec4ec 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 @@ -128,7 +129,7 @@ theorem Set.Finite.isOpen_biInter {s : Set α} {f : α → Set X} (hs : s.Finite theorem isOpen_iInter_of_finite [Finite ι] {s : ι → Set X} (h : ∀ i, IsOpen (s i)) : IsOpen (⋂ i, s i) := - (finite_range _).isOpen_sInter (forall_mem_range.2 h) + (finite_range _).isOpen_sInter (forall_mem_range.2 h) theorem isOpen_biInter_finset {s : Finset α} {f : α → Set X} (h : ∀ i ∈ s, IsOpen (f i)) : IsOpen (⋂ i ∈ s, f i) := @@ -156,6 +157,12 @@ theorem isClosed_const {p : Prop} : IsClosed { _x : X | p } := ⟨isOpen_const ( @[simp] theorem isClosed_univ : IsClosed (univ : Set X) := isClosed_const +lemma IsOpen.isLocallyClosed (hs : IsOpen s) : IsLocallyClosed s := + ⟨_, _, hs, isClosed_univ, (inter_univ _).symm⟩ + +lemma IsClosed.isLocallyClosed (hs : IsClosed s) : IsLocallyClosed s := + ⟨_, _, isOpen_univ, hs, (univ_inter _).symm⟩ + theorem IsClosed.union : IsClosed s₁ → IsClosed s₂ → IsClosed (s₁ ∪ s₂) := by simpa only [← isOpen_compl_iff, compl_union] using IsOpen.inter @@ -792,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 @@ -839,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 @@ -889,6 +898,11 @@ theorem Filter.HasBasis.clusterPt_iff {ιX ιF} {pX : ιX → Prop} {sX : ιX ClusterPt x F ↔ ∀ ⦃i⦄, pX i → ∀ ⦃j⦄, pF j → (sX i ∩ sF j).Nonempty := hX.inf_basis_neBot_iff hF +theorem Filter.HasBasis.clusterPt_iff_frequently {ι} {p : ι → Prop} {s : ι → Set X} {F : Filter X} + (hx : (𝓝 x).HasBasis p s) : ClusterPt x F ↔ ∀ i, p i → ∃ᶠ x in F, x ∈ s i := by + simp only [hx.clusterPt_iff F.basis_sets, Filter.frequently_iff, inter_comm (s _), + Set.Nonempty, id, mem_inter_iff] + theorem clusterPt_iff {F : Filter X} : ClusterPt x F ↔ ∀ ⦃U : Set X⦄, U ∈ 𝓝 x → ∀ ⦃V⦄, V ∈ F → (U ∩ V).Nonempty := inf_neBot_iff @@ -934,31 +948,57 @@ theorem clusterPt_iff_ultrafilter {f : Filter X} : ClusterPt x f ↔ ∃ u : Ultrafilter X, u ≤ f ∧ u ≤ 𝓝 x := by simp_rw [ClusterPt, ← le_inf_iff, exists_ultrafilter_iff, inf_comm] -theorem mapClusterPt_def {ι : Type*} (x : X) (F : Filter ι) (u : ι → X) : - MapClusterPt x F u ↔ ClusterPt x (map u F) := Iff.rfl +section MapClusterPt -theorem mapClusterPt_iff {ι : Type*} (x : X) (F : Filter ι) (u : ι → X) : - MapClusterPt x F u ↔ ∀ s ∈ 𝓝 x, ∃ᶠ a in F, u a ∈ s := by - simp_rw [MapClusterPt, ClusterPt, inf_neBot_iff_frequently_left, frequently_map] - rfl +variable {F : Filter α} {u : α → X} {x : X} + +theorem mapClusterPt_def : MapClusterPt x F u ↔ ClusterPt x (map u F) := Iff.rfl +alias ⟨MapClusterPt.clusterPt, _⟩ := mapClusterPt_def + +theorem MapClusterPt.mono {G : Filter α} (h : MapClusterPt x F u) (hle : F ≤ G) : + MapClusterPt x G u := + h.clusterPt.mono (map_mono hle) + +theorem MapClusterPt.tendsto_comp' [TopologicalSpace Y] {f : X → Y} {y : Y} + (hf : Tendsto f (𝓝 x ⊓ map u F) (𝓝 y)) (hu : MapClusterPt x F u) : MapClusterPt y F (f ∘ u) := + (tendsto_inf.2 ⟨hf, tendsto_map.mono_left inf_le_right⟩).neBot (hx := hu) -theorem mapClusterPt_iff_ultrafilter {ι : Type*} (x : X) (F : Filter ι) (u : ι → X) : - MapClusterPt x F u ↔ ∃ U : Ultrafilter ι, U ≤ F ∧ Tendsto u U (𝓝 x) := by +theorem MapClusterPt.tendsto_comp [TopologicalSpace Y] {f : X → Y} {y : Y} + (hf : Tendsto f (𝓝 x) (𝓝 y)) (hu : MapClusterPt x F u) : MapClusterPt y F (f ∘ u) := + hu.tendsto_comp' (hf.mono_left inf_le_left) + +theorem MapClusterPt.continuousAt_comp [TopologicalSpace Y] {f : X → Y} (hf : ContinuousAt f x) + (hu : MapClusterPt x F u) : MapClusterPt (f x) F (f ∘ u) := + hu.tendsto_comp hf + +theorem Filter.HasBasis.mapClusterPt_iff_frequently {ι : Sort*} {p : ι → Prop} {s : ι → Set X} + (hx : (𝓝 x).HasBasis p s) : MapClusterPt x F u ↔ ∀ i, p i → ∃ᶠ a in F, u a ∈ s i := by + simp_rw [MapClusterPt, hx.clusterPt_iff_frequently, frequently_map] + +theorem mapClusterPt_iff : MapClusterPt x F u ↔ ∀ s ∈ 𝓝 x, ∃ᶠ a in F, u a ∈ s := + (𝓝 x).basis_sets.mapClusterPt_iff_frequently + +theorem mapClusterPt_iff_ultrafilter : + MapClusterPt x F u ↔ ∃ U : Ultrafilter α, U ≤ F ∧ Tendsto u U (𝓝 x) := by simp_rw [MapClusterPt, ClusterPt, ← Filter.push_pull', map_neBot_iff, tendsto_iff_comap, ← le_inf_iff, exists_ultrafilter_iff, inf_comm] -theorem mapClusterPt_comp {X α β : Type*} {x : X} [TopologicalSpace X] {F : Filter α} {φ : α → β} - {u : β → X} : MapClusterPt x F (u ∘ φ) ↔ MapClusterPt x (map φ F) u := Iff.rfl +theorem mapClusterPt_comp {φ : α → β} {u : β → X} : + MapClusterPt x F (u ∘ φ) ↔ MapClusterPt x (map φ F) u := Iff.rfl -theorem mapClusterPt_of_comp {F : Filter α} {φ : β → α} {p : Filter β} - {u : α → X} [NeBot p] (h : Tendsto φ p F) (H : Tendsto (u ∘ φ) p (𝓝 x)) : - MapClusterPt x F u := by - have := - calc - map (u ∘ φ) p = map u (map φ p) := map_map - _ ≤ map u F := map_mono h - have : map (u ∘ φ) p ≤ 𝓝 x ⊓ map u F := le_inf H this - exact neBot_of_le this +theorem Filter.Tendsto.mapClusterPt [NeBot F] (h : Tendsto u F (𝓝 x)) : MapClusterPt x F u := + .of_le_nhds h + +theorem MapClusterPt.of_comp {φ : β → α} {p : Filter β} (h : Tendsto φ p F) + (H : MapClusterPt x p (u ∘ φ)) : MapClusterPt x F u := + H.clusterPt.mono <| map_mono h + +@[deprecated MapClusterPt.of_comp (since := "2024-09-07")] +theorem mapClusterPt_of_comp {φ : β → α} {p : Filter β} [NeBot p] + (h : Tendsto φ p F) (H : Tendsto (u ∘ φ) p (𝓝 x)) : MapClusterPt x F u := + .of_comp h H.mapClusterPt + +end MapClusterPt theorem accPt_sup (x : X) (F G : Filter X) : AccPt x (F ⊔ G) ↔ AccPt x F ∨ AccPt x G := by @@ -1085,7 +1125,7 @@ theorem mem_closure_iff_nhdsWithin_neBot : x ∈ closure s ↔ NeBot (𝓝[s] x) lemma nhdsWithin_neBot : (𝓝[s] x).NeBot ↔ ∀ ⦃t⦄, t ∈ 𝓝 x → (t ∩ s).Nonempty := by rw [nhdsWithin, inf_neBot_iff] exact forall₂_congr fun U _ ↦ - ⟨fun h ↦ h (mem_principal_self _), fun h u hsu ↦ h.mono $ inter_subset_inter_right _ hsu⟩ + ⟨fun h ↦ h (mem_principal_self _), fun h u hsu ↦ h.mono <| inter_subset_inter_right _ hsu⟩ @[gcongr] theorem nhdsWithin_mono (x : X) {s t : Set X} (h : s ⊆ t) : 𝓝[s] x ≤ 𝓝[t] x := @@ -1362,7 +1402,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} @@ -1451,7 +1491,7 @@ theorem Filter.EventuallyEq.continuousAt (h : f =ᶠ[𝓝 x] fun _ => y) : theorem continuous_of_const (h : ∀ x y, f x = f y) : Continuous f := continuous_iff_continuousAt.mpr fun x => - Filter.EventuallyEq.continuousAt <| eventually_of_forall fun y => h y x + Filter.EventuallyEq.continuousAt <| Eventually.of_forall fun y => h y x theorem continuousAt_id : ContinuousAt id x := continuous_id.continuousAt @@ -1738,3 +1778,5 @@ example [TopologicalSpace X] [TopologicalSpace Y] {x₀ : X} (f : X → X → Y) -- hf.comp_of_eq (continuousAt_id.prod continuousAt_id) rfl -- works ``` -/ + +set_option linter.style.longFile 1900 diff --git a/Mathlib/Topology/Bornology/Absorbs.lean b/Mathlib/Topology/Bornology/Absorbs.lean index ea21c3717d826..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. @@ -129,62 +132,74 @@ protected lemma add [AddZeroClass E] [DistribSMul M E] h₂.mp <| h₁.eventually.mono fun x hx₁ hx₂ ↦ by rw [smul_add]; exact add_subset_add hx₁ hx₂ protected lemma zero [Zero E] [SMulZeroClass M E] {s : Set E} (hs : 0 ∈ s) : Absorbs M s 0 := - eventually_of_forall fun _ ↦ zero_subset.2 <| zero_mem_smul_set hs + Eventually.of_forall fun _ ↦ zero_subset.2 <| zero_mem_smul_set hs 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/BoundedOperation.lean b/Mathlib/Topology/Bornology/BoundedOperation.lean index 9340172558c61..a322077983828 100644 --- a/Mathlib/Topology/Bornology/BoundedOperation.lean +++ b/Mathlib/Topology/Bornology/BoundedOperation.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kalle Kytölä -/ import Mathlib.Analysis.Normed.Group.Basic -import Mathlib.Analysis.Normed.Field.Basic +import Mathlib.Analysis.Normed.Field.Lemmas /-! # Bounded operations 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/Bornology/Hom.lean b/Mathlib/Topology/Bornology/Hom.lean index 756bc3fdd6d3d..fb444353548de 100644 --- a/Mathlib/Topology/Bornology/Hom.lean +++ b/Mathlib/Topology/Bornology/Hom.lean @@ -83,8 +83,6 @@ instance : FunLike (LocallyBoundedMap α β) α β where instance : LocallyBoundedMapClass (LocallyBoundedMap α β) α β where comap_cobounded_le f := f.comap_cobounded_le' --- Porting note: syntactic tautology because of the way coercions work - @[ext] theorem ext {f g : LocallyBoundedMap α β} (h : ∀ a, f a = g a) : f = g := DFunLike.ext f g h 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 19e8edca81f80..0306bef4b8f7d 100644 --- a/Mathlib/Topology/Category/CompHaus/Basic.lean +++ b/Mathlib/Topology/Category/CompHaus/Basic.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2020 Adam Topaz. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Adam Topaz, Bhavik Mehta +Authors: Adam Topaz, Bhavik Mehta, Dagur Asgeirsson -/ import Mathlib.CategoryTheory.Monad.Limits import Mathlib.Topology.StoneCech @@ -24,6 +24,11 @@ equivalence of categories in `CompactumToCompHaus.isEquivalence`. See `Mathlib/Topology/Category/Compactum.lean` for a more detailed discussion where these definitions are introduced. +## Implementation + +The category `CompHaus` is defined using the structure `CompHausLike`. See the file +`CompHausLike.Basic` for more information. + -/ @@ -219,6 +224,6 @@ theorem epi_iff_surjective {X Y : CompHaus.{u}} (f : X ⟶ Y) : Epi f ↔ Functi end CompHaus -/-- Every `CompHausLike` admits a functor to `CompHaus`. -/ +/-- Every `CompHausLike` admits a functor to `CompHaus`. -/ abbrev compHausLikeToCompHaus (P : TopCat → Prop) : CompHausLike P ⥤ CompHaus := CompHausLike.toCompHausLike (by simp only [implies_true]) 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 05401767a1c2c..ca9de369a082e 100644 --- a/Mathlib/Topology/Category/CompHausLike/Basic.lean +++ b/Mathlib/Topology/Category/CompHausLike/Basic.lean @@ -10,6 +10,54 @@ import Mathlib.Topology.Category.TopCat.Basic # Categories of Compact Hausdorff Spaces We construct the category of compact Hausdorff spaces satisfying an additional property `P`. + +## Implementation + +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: + +```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: + +```lean +structure Profinite where + toCompHaus : CompHaus + [isTotallyDisconnected : TotallyDisconnectedSpace toCompHaus] +``` + +The categories `Stonean` consisting of extremally disconnected compact Hausdorff spaces and +`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`. + +Using `CompHausLike`, we can now define +`CompHaus := CompHausLike (fun _ ↦ True)` +`Profinite := CompHausLike (fun X ↦ TotallyDisconnectedSpace X)`. +`Stonean := CompHausLike (fun X ↦ ExtremallyDisconnected X)`. +`LightProfinite := CompHausLike (fun X ↦ TotallyDisconnectedSpace X ∧ SecondCountableTopology X)`. + +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` +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 +`Profinite`. -/ universe u @@ -49,7 +97,7 @@ instance hasForget₂ : HasForget₂ (CompHausLike P) TopCat := variable (X : Type u) [TopologicalSpace X] [CompactSpace X] [T2Space X] -/-- This wraps the predicate `P : TopCat → Prop` in a typeclass. -/ +/-- This wraps the predicate `P : TopCat → Prop` in a typeclass. -/ class HasProp : Prop where hasProp : P (TopCat.of X) @@ -91,7 +139,7 @@ instance (X : CompHausLike.{u} P) : T2Space ((forget (CompHausLike P)).obj X) := variable {P} -/-- If `P` imples `P'`, then there is a functor from `CompHausLike P` to `CompHausLike P'`. -/ +/-- If `P` imples `P'`, then there is a functor from `CompHausLike P` to `CompHausLike P'`. -/ @[simps] def toCompHausLike {P P' : TopCat → Prop} (h : ∀ (X : CompHausLike P), P X.toTop → P' X.toTop) : CompHausLike P ⥤ CompHausLike P' where @@ -104,7 +152,7 @@ section variable {P P' : TopCat → Prop} (h : ∀ (X : CompHausLike P), P X.toTop → P' X.toTop) -/-- If `P` imples `P'`, then the functor from `CompHausLike P` to `CompHausLike P'` is fully +/-- If `P` imples `P'`, then the functor from `CompHausLike P` to `CompHausLike P'` is fully faithful. -/ def fullyFaithfulToCompHausLike : (toCompHausLike h).FullyFaithful := fullyFaithfulInducedFunctor _ @@ -207,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/Limits.lean b/Mathlib/Topology/Category/CompHausLike/Limits.lean index c3705bfeab520..845abc60f56e7 100644 --- a/Mathlib/Topology/Category/CompHausLike/Limits.lean +++ b/Mathlib/Topology/Category/CompHausLike/Limits.lean @@ -18,14 +18,14 @@ which may be useful due to their definitional properties. * `HasExplicitFiniteCoproducts`: A typeclass describing the property that forming all finite disjoint unions is stable under the property `P`. - Given this property, we deduce that `CompHausLike P` has finite coproducts and the inclusion - functors to other `CompHausLike P'` and to `TopCat` preserve them. + functors to other `CompHausLike P'` and to `TopCat` preserve them. * `HasExplicitPullbacks`: A typeclass describing the property that forming all "explicit pullbacks" is stable under the property `P`. Here, explicit pullbacks are defined as a subset of the product. - Given this property, we deduce that `CompHausLike P` has pullbacks and the inclusion - functors to other `CompHausLike P'` and to `TopCat` preserve them. + functors to other `CompHausLike P'` and to `TopCat` preserve them. - We also define a variant `HasExplicitPullbacksOfInclusions` which is says that explicit - pullbacks along inclusion maps into finite disjoint unions exist. `Stonean` has this property + pullbacks along inclusion maps into finite disjoint unions exist. `Stonean` has this property but not the stronger one. ## Main results @@ -127,7 +127,7 @@ class HasExplicitFiniteCoproducts : Prop where hasProp {α : Type w} [Finite α] (X : α → CompHausLike.{max u w} P) : HasExplicitFiniteCoproduct X /- -This linter complains that the universes `u` and `w` only occur together, but `w` appears by itself +This linter complains that the universes `u` and `w` only occur together, but `w` appears by itself in the indexing type of the coproduct. In almost all cases, `w` will be either `0` or `u`, but we want to allow both possibilities. -/ @@ -164,7 +164,7 @@ lemma Sigma.openEmbedding_ι (a : α) : change (Sigma.ι X a ≫ _) x = _ simp -/-- The functor to `TopCat` preserves finite coproducts if they exist. -/ +/-- The functor to `TopCat` preserves finite coproducts if they exist. -/ instance (P) [HasExplicitFiniteCoproducts.{0} P] : PreservesFiniteCoproducts (compHausLikeToTop P) := by refine ⟨fun J hJ ↦ ⟨fun {F} ↦ ?_⟩⟩ @@ -173,7 +173,7 @@ instance (P) [HasExplicitFiniteCoproducts.{0} P] : apply preservesColimitOfPreservesColimitCocone (CompHausLike.finiteCoproduct.isColimit _) exact TopCat.sigmaCofanIsColimit _ -/-- The functor to another `CompHausLike` preserves finite coproducts if they exist. -/ +/-- The functor to another `CompHausLike` preserves finite coproducts if they exist. -/ noncomputable instance {P' : TopCat.{u} → Prop} (h : ∀ (X : CompHausLike P), P X.toTop → P' X.toTop) : PreservesFiniteCoproducts (toCompHausLike h) := by @@ -275,18 +275,18 @@ def pullback.isLimit : Limits.IsLimit (pullback.cone f g) := instance : HasLimit (cospan f g) where exists_limit := ⟨⟨pullback.cone f g, pullback.isLimit f g⟩⟩ -/-- The functor to `TopCat` creates pullbacks if they exist. -/ +/-- The functor to `TopCat` creates pullbacks if they exist. -/ noncomputable instance : CreatesLimit (cospan f g) (compHausLikeToTop P) := by refine createsLimitOfFullyFaithfulOfIso (pullback f g) (((TopCat.pullbackConeIsLimit f g).conePointUniqueUpToIso (limit.isLimit _)) ≪≫ Limits.lim.mapIso (?_ ≪≫ (diagramIsoCospan _).symm)) exact Iso.refl _ -/-- The functor to `TopCat` preserves pullbacks. -/ +/-- The functor to `TopCat` preserves pullbacks. -/ noncomputable instance : PreservesLimit (cospan f g) (compHausLikeToTop P) := preservesLimitOfCreatesLimitAndHasLimit _ _ -/-- The functor to another `CompHausLike` preserves pullbacks. -/ +/-- The functor to another `CompHausLike` preserves pullbacks. -/ noncomputable instance {P' : TopCat → Prop} (h : ∀ (X : CompHausLike P), P X.toTop → P' X.toTop) : PreservesLimit (cospan f g) (toCompHausLike h) := by diff --git a/Mathlib/Topology/Category/CompHausLike/SigmaComparison.lean b/Mathlib/Topology/Category/CompHausLike/SigmaComparison.lean new file mode 100644 index 0000000000000..fc574ef66ea35 --- /dev/null +++ b/Mathlib/Topology/Category/CompHausLike/SigmaComparison.lean @@ -0,0 +1,66 @@ +/- +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.Category.CompHausLike.Limits +/-! + +# The sigma-comparison map + +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 inclusion maps `Sᵢ ⟶ S₁ ⊔ ... ⊔ Sₙ`, and it is an isomorphism when `X` preserves finite +products. +-/ + +universe u w + +open CategoryTheory Limits + +namespace CompHausLike + +variable {P : TopCat.{u} → Prop} [HasExplicitFiniteCoproducts.{u} P] + (X : (CompHausLike.{u} P)ᵒᵖ ⥤ Type max u w) [PreservesFiniteProducts X] + {α : Type u} [Finite α] (σ : α → Type u) + [∀ a, TopologicalSpace (σ a)] [∀ a, CompactSpace (σ a)] [∀ a, T2Space (σ a)] + [∀ a, HasProp P (σ a)] + +instance : HasProp P (Σ (a : α), (σ a)) := HasExplicitFiniteCoproducts.hasProp (fun a ↦ of P (σ a)) + +/-- +The comparison map from the value of a condensed set on a finite coproduct to the product of the +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 + +theorem sigmaComparison_eq_comp_isos : sigmaComparison X σ = + (X.mapIso (opCoproductIsoProduct' + (finiteCoproduct.isColimit.{u, u} (fun a ↦ of P (σ a))) + (productIsProduct fun x ↦ Opposite.op (of P (σ x))))).hom ≫ + (PreservesProduct.iso X fun a ↦ ⟨of P (σ a)⟩).hom ≫ + (Types.productIso.{u, max u w} fun a ↦ X.obj ⟨of P (σ a)⟩).hom := by + ext x a + simp only [Cofan.mk_pt, Fan.mk_pt, Functor.mapIso_hom, + PreservesProduct.iso_hom, types_comp_apply, Types.productIso_hom_comp_eval_apply] + have := congrFun (piComparison_comp_π X (fun a ↦ ⟨of P (σ a)⟩) a) + simp only [types_comp_apply] at this + rw [this, ← FunctorToTypes.map_comp_apply] + simp only [sigmaComparison] + apply congrFun + congr 2 + rw [← opCoproductIsoProduct_inv_comp_ι] + simp only [coe_of, Opposite.unop_op, unop_comp, Quiver.Hom.unop_op, Category.assoc] + simp only [opCoproductIsoProduct, ← unop_comp, opCoproductIsoProduct'_comp_self] + erw [IsColimit.fac] + rfl + +instance isIsoSigmaComparison : IsIso <| sigmaComparison X σ := by + rw [sigmaComparison_eq_comp_isos] + infer_instance + +end CompHausLike diff --git a/Mathlib/Topology/Category/CompactlyGenerated.lean b/Mathlib/Topology/Category/CompactlyGenerated.lean index 200b869bfa079..2563c6dffb796 100644 --- a/Mathlib/Topology/Category/CompactlyGenerated.lean +++ b/Mathlib/Topology/Category/CompactlyGenerated.lean @@ -9,7 +9,7 @@ import Mathlib.CategoryTheory.Elementwise # Compactly generated topological spaces -This file defines the category of compactly generated topological spaces. These are spaces `X` such +This file defines the category of compactly generated topological spaces. These are spaces `X` such that a map `f : X → Y` is continuous whenever the composition `S → X → Y` is continuous for all compact Hausdorff spaces `S` mapping continuously to `X`. diff --git a/Mathlib/Topology/Category/Compactum.lean b/Mathlib/Topology/Category/Compactum.lean index 7cd821aa6d9d6..1bb55e129ab03 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 diff --git a/Mathlib/Topology/Category/LightProfinite/AsLimit.lean b/Mathlib/Topology/Category/LightProfinite/AsLimit.lean index d5e2c6c5f4e62..48104258a6815 100644 --- a/Mathlib/Topology/Category/LightProfinite/AsLimit.lean +++ b/Mathlib/Topology/Category/LightProfinite/AsLimit.lean @@ -36,14 +36,14 @@ abbrev diagram : ℕᵒᵖ ⥤ LightProfinite := S.fintypeDiagram ⋙ FintypeCat /-- A cone over `S.diagram` whose cone point is isomorphic to `S`. -(Auxiliary definition, use `S.asLimitCone` instead.) +(Auxiliary definition, use `S.asLimitCone` instead.) -/ def asLimitConeAux : Cone S.diagram := let c : Cone (S.diagram ⋙ lightToProfinite) := S.toLightDiagram.cone let hc : IsLimit c := S.toLightDiagram.isLimit liftLimit hc -/-- An auxiliary isomorphism of cones used to prove that `S.asLimitConeAux` is a limit cone. -/ +/-- An auxiliary isomorphism of cones used to prove that `S.asLimitConeAux` is a limit cone. -/ def isoMapCone : lightToProfinite.mapCone S.asLimitConeAux ≅ S.toLightDiagram.cone := let c : Cone (S.diagram ⋙ lightToProfinite) := S.toLightDiagram.cone let hc : IsLimit c := S.toLightDiagram.isLimit @@ -51,7 +51,7 @@ def isoMapCone : lightToProfinite.mapCone S.asLimitConeAux ≅ S.toLightDiagram. /-- `S.asLimitConeAux` is indeed a limit cone. -(Auxiliary definition, use `S.asLimit` instead.) +(Auxiliary definition, use `S.asLimit` instead.) -/ def asLimitAux : IsLimit S.asLimitConeAux := let hc : IsLimit (lightToProfinite.mapCone S.asLimitConeAux) := diff --git a/Mathlib/Topology/Category/LightProfinite/Basic.lean b/Mathlib/Topology/Category/LightProfinite/Basic.lean index 73394bd6a5fbe..56a5871cbcd22 100644 --- a/Mathlib/Topology/Category/LightProfinite/Basic.lean +++ b/Mathlib/Topology/Category/LightProfinite/Basic.lean @@ -17,8 +17,14 @@ implemented as totally disconnected second countable compact Hausdorff spaces. This file also defines the category `LightDiagram`, which consists of those spaces that can be written as a sequential limit (in `Profinite`) of finite sets. -We define an equivalence of categories `LightProfinite ≌ LightDiagram` and prove that these are +We define an equivalence of categories `LightProfinite ≌ LightDiagram` and prove that these are essentially small categories. + +## Implementation + +The category `LightProfinite` is defined using the structure `CompHausLike`. See the file +`CompHausLike.Basic` for more information. + -/ /- The basic API for `LightProfinite` is largely copied from the API of `Profinite`; @@ -113,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 @@ -225,6 +236,9 @@ theorem epi_iff_surjective {X Y : LightProfinite.{u}} (f : X ⟶ Y) : · rw [← CategoryTheory.epi_iff_surjective] apply (forget LightProfinite).epi_of_epi_map +instance : lightToProfinite.PreservesEpimorphisms where + preserves f _ := (Profinite.epi_iff_surjective _).mpr ((epi_iff_surjective f).mp inferInstance) + end LightProfinite /-- A structure containing the data of sequential limit in `Profinite` of finite sets. -/ @@ -238,7 +252,7 @@ structure LightDiagram : Type (u+1) where namespace LightDiagram -/-- The underlying `Profinite` of a `LightDiagram`. -/ +/-- The underlying `Profinite` of a `LightDiagram`. -/ def toProfinite (S : LightDiagram) : Profinite := S.cone.pt @[simps!] @@ -380,7 +394,7 @@ instance : LightDiagram'.toLightFunctor.{u}.EssSurj where instance : LightDiagram'.toLightFunctor.IsEquivalence where -/-- The equivalence beween `LightDiagram` and a small category. -/ +/-- The equivalence between `LightDiagram` and a small category. -/ def LightDiagram.equivSmall : LightDiagram.{u} ≌ LightDiagram'.{u} := LightDiagram'.toLightFunctor.asEquivalence.symm diff --git a/Mathlib/Topology/Category/LightProfinite/Extend.lean b/Mathlib/Topology/Category/LightProfinite/Extend.lean new file mode 100644 index 0000000000000..4f7e5eb315b90 --- /dev/null +++ b/Mathlib/Topology/Category/LightProfinite/Extend.lean @@ -0,0 +1,198 @@ +/- +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.Category.LightProfinite.AsLimit +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 +epimorphic for all `n`. Then `G.obj S` is isomorphic to a limit indexed by +`StructuredArrow S toLightProfinite` (see `LightProfinite.Extend.isLimitCone`). + +We also provide the dual result for a functor of the form `G : LightProfiniteᵒᵖ ⥤ C`. + +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 `ℕᵒᵖ`. +-/ + +universe u + +open CategoryTheory Limits FintypeCat Functor + +attribute [local instance] FintypeCat.discreteTopology ConcreteCategory.instFunLike + +namespace LightProfinite + +variable {F : ℕᵒᵖ ⥤ FintypeCat.{u}} (c : Cone <| F ⋙ toLightProfinite) + +namespace Extend + +/-- +Given a sequential cone in `LightProfinite` consisting of finite sets, +we obtain a functor from the indexing category to `StructuredArrow c.pt toLightProfinite`. +-/ +@[simps] +def functor : ℕᵒᵖ ⥤ StructuredArrow c.pt toLightProfinite where + obj i := StructuredArrow.mk (c.π.app i) + map f := StructuredArrow.homMk (F.map f) (c.w f) + +-- We check that the original diagram factors through `LightProfinite.Extend.functor`. +example : functor c ⋙ StructuredArrow.proj c.pt toLightProfinite ≅ F := Iso.refl _ + +/-- +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⟩`. +-/ +@[simps! obj map] +def functorOp : ℕ ⥤ CostructuredArrow toLightProfinite.op ⟨c.pt⟩ := + (functor c).rightOp ⋙ StructuredArrow.toCostructuredArrow _ _ + +-- We check that the opposite of the original diagram factors through `Profinite.Extend.functorOp`. +example : functorOp c ⋙ CostructuredArrow.proj toLightProfinite.op ⟨c.pt⟩ ≅ F.rightOp := Iso.refl _ + +-- We check that `Profinite.Extend.functor` factors through `LightProfinite.Extend.functor`, +-- via the equivalence `StructuredArrow.post _ _ lightToProfinite`. +example : functor c ⋙ (StructuredArrow.post _ _ lightToProfinite) = + Profinite.Extend.functor (lightToProfinite.mapCone c) := rfl + +/-- +If the projection maps in the cone are epimorphic and the cone is limiting, then +`LightProfinite.Extend.functor` is initial. +-/ +theorem functor_initial (hc : IsLimit c) [∀ i, Epi (c.π.app i)] : Initial (functor c) := by + rw [initial_iff_comp_equivalence _ (StructuredArrow.post _ _ lightToProfinite)] + have : ∀ i, Epi ((lightToProfinite.mapCone c).π.app i) := + fun i ↦ inferInstanceAs (Epi (lightToProfinite.map (c.π.app i))) + exact Profinite.Extend.functor_initial _ (isLimitOfPreserves lightToProfinite hc) + +/-- +If the projection maps in the cone are epimorphic and the cone is limiting, then +`LightProfinite.Extend.functorOp` is final. +-/ +theorem functorOp_final (hc : IsLimit c) [∀ i, Epi (c.π.app i)] : Final (functorOp c) := by + have := functor_initial c hc + have : ((StructuredArrow.toCostructuredArrow toLightProfinite c.pt)).IsEquivalence := + (inferInstance : (structuredArrowOpEquivalence _ _).functor.IsEquivalence ) + have : (functor c).rightOp.Final := + inferInstanceAs ((opOpEquivalence ℕ).inverse ⋙ (functor c).op).Final + exact Functor.final_comp (functor c).rightOp _ + +section Limit + +variable {C : Type*} [Category C] (G : LightProfinite ⥤ C) + +/-- +Given a functor `G` from `LightProfinite` and `S : LightProfinite`, we obtain a cone on +`(StructuredArrow.proj S toLightProfinite ⋙ toLightProfinite ⋙ G)` with cone point `G.obj S`. + +Whiskering this cone with `LightProfinite.Extend.functor c` gives `G.mapCone c` as we check in the +example below. +-/ +def cone (S : LightProfinite) : + Cone (StructuredArrow.proj S toLightProfinite ⋙ toLightProfinite ⋙ G) where + 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]) } + +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, +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' + +end Limit + +section Colimit + +variable {C : Type*} [Category C] (G : LightProfiniteᵒᵖ ⥤ C) + +/-- +Given a functor `G` from `LightProfiniteᵒᵖ` and `S : LightProfinite`, we obtain a cocone on +`(CostructuredArrow.proj toLightProfinite.op ⟨S⟩ ⋙ toLightProfinite.op ⋙ G)` with cocone point +`G.obj ⟨S⟩`. + +Whiskering this cocone with `LightProfinite.Extend.functorOp c` gives `G.mapCocone c.op` as we +check in the example below. +-/ +@[simps] +def cocone (S : LightProfinite) : + Cocone (CostructuredArrow.proj toLightProfinite.op ⟨S⟩ ⋙ toLightProfinite.op ⋙ G) where + pt := G.obj ⟨S⟩ + ι := { + app := fun i ↦ G.map i.hom + naturality := fun _ _ f ↦ (by + 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]) } + +example : G.mapCocone c.op = (cocone G c.pt).whisker + ((opOpEquivalence ℕ).functor ⋙ functorOp c) := rfl + +/-- +If `c` is a limit cone, `G.mapCocone c.op` is a colimit cone and the projection maps in `c` +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) := + haveI := functorOp_final c hc + (Functor.final_comp (opOpEquivalence ℕ).functor (functorOp c)).isColimitWhiskerEquiv _ _ hc' + +end Colimit + +end Extend + +open Extend + +section LightProfiniteAsLimit + +variable (S : LightProfinite.{u}) + +/-- +A functor `StructuredArrow S toLightProfinite ⥤ FintypeCat` whose limit in `LightProfinite` is +isomorphic to `S`. +-/ +abbrev fintypeDiagram' : StructuredArrow S toLightProfinite ⥤ FintypeCat := + StructuredArrow.proj S toLightProfinite + +/-- An abbreviation for `S.fintypeDiagram' ⋙ toLightProfinite`. -/ +abbrev diagram' : StructuredArrow S toLightProfinite ⥤ LightProfinite := + S.fintypeDiagram' ⋙ toLightProfinite + +/-- A cone over `S.diagram'` whose cone point is `S`. -/ +def asLimitCone' : Cone (S.diagram') := cone (𝟭 _) S + +instance (i : ℕᵒᵖ) : Epi (S.asLimitCone.π.app i) := + (epi_iff_surjective _).mpr (S.proj_surjective _) + +/-- `S.asLimitCone'` is a limit cone. -/ +noncomputable def asLimit' : IsLimit S.asLimitCone' := isLimitCone _ (𝟭 _) S.asLimit S.asLimit + +/-- A bundled version of `S.asLimitCone'` and `S.asLimit'`. -/ +noncomputable def lim' : LimitCone S.diagram' := ⟨S.asLimitCone', S.asLimit'⟩ + +end LightProfiniteAsLimit + +end LightProfinite diff --git a/Mathlib/Topology/Category/LightProfinite/Sequence.lean b/Mathlib/Topology/Category/LightProfinite/Sequence.lean index 17d3590bd8020..ae729f14b1979 100644 --- a/Mathlib/Topology/Category/LightProfinite/Sequence.lean +++ b/Mathlib/Topology/Category/LightProfinite/Sequence.lean @@ -17,7 +17,7 @@ open CategoryTheory TopologicalSpace OnePoint namespace LightProfinite -/-- The continuous map from `ℕ∪{∞}` to `ℝ` sending `n` to `1/(n+1)` and `∞` to `0`. -/ +/-- The continuous map from `ℕ∪{∞}` to `ℝ` sending `n` to `1/(n+1)` and `∞` to `0`. -/ noncomputable def natUnionInftyEmbedding : C(OnePoint ℕ, ℝ) where toFun | ∞ => 0 @@ -26,7 +26,7 @@ noncomputable def natUnionInftyEmbedding : C(OnePoint ℕ, ℝ) where tendsto_one_div_add_atTop_nhds_zero_nat /-- -The continuous map from `ℕ∪{∞}` to `ℝ` sending `n` to `1/(n+1)` and `∞` to `0` is a closed +The continuous map from `ℕ∪{∞}` to `ℝ` sending `n` to `1/(n+1)` and `∞` to `0` is a closed embedding. -/ lemma closedEmbedding_natUnionInftyEmbedding : ClosedEmbedding natUnionInftyEmbedding := by diff --git a/Mathlib/Topology/Category/Profinite/Basic.lean b/Mathlib/Topology/Category/Profinite/Basic.lean index 2fcfa55ea7cfa..fdde9e65b27a8 100644 --- a/Mathlib/Topology/Category/Profinite/Basic.lean +++ b/Mathlib/Topology/Category/Profinite/Basic.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2020 Kevin Buzzard. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Kevin Buzzard, Calle Sönne +Authors: Kevin Buzzard, Calle Sönne, Dagur Asgeirsson -/ import Mathlib.CategoryTheory.FintypeCat import Mathlib.Topology.Category.CompHaus.Basic @@ -23,6 +23,9 @@ is called `Profinite.toTop`. A profinite type is defined to be a topological space which is compact, Hausdorff and totally disconnected. +The category `Profinite` is defined using the structure `CompHausLike`. See the file +`CompHausLike.Basic` for more information. + ## TODO * Define procategories and prove that `Profinite` is equivalent to `Pro (FintypeCat)`. @@ -46,7 +49,7 @@ abbrev Profinite := CompHausLike (fun X ↦ TotallyDisconnectedSpace X) namespace Profinite -instance (X : Type*) [TopologicalSpace X] +instance (X : Type*) [TopologicalSpace X] [TotallyDisconnectedSpace X] : HasProp (fun Y ↦ TotallyDisconnectedSpace Y) X := ⟨(inferInstance : TotallyDisconnectedSpace X)⟩ @@ -154,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 @@ -247,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 2777ca0f06433..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 @@ -54,7 +51,7 @@ instance : profiniteToCompHaus.ReflectsEffectiveEpis where ((Profinite.effectiveEpi_tfae f).out 0 2).mpr (((CompHaus.effectiveEpi_tfae _).out 0 2).mp h) /-- -An effective presentation of an `X : Profinite` with respect to the inclusion functor from `Stonean` +An effective presentation of an `X : Profinite` with respect to the inclusion functor from `Stonean` -/ noncomputable def profiniteToCompHausEffectivePresentation (X : CompHaus) : profiniteToCompHaus.EffectivePresentation X 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 new file mode 100644 index 0000000000000..2c00a5e5808e0 --- /dev/null +++ b/Mathlib/Topology/Category/Profinite/Extend.lean @@ -0,0 +1,217 @@ +/- +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.Category.Profinite.AsLimit +import Mathlib.Topology.Category.Profinite.CofilteredLimit +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 +epimorphic for all `i`. Then `G.obj S` is isomorphic to a limit indexed by +`StructuredArrow S toProfinite` (see `Profinite.Extend.isLimitCone`). + +We also provide the dual result for a functor of the form `G : Profiniteᵒᵖ ⥤ C`. + +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`. +-/ + +universe u w + +open CategoryTheory Limits FintypeCat Functor + +attribute [local instance] ConcreteCategory.instFunLike + +namespace Profinite + +variable {I : Type u} [SmallCategory I] [IsCofiltered I] + {F : I ⥤ FintypeCat.{max u w}} (c : Cone <| F ⋙ toProfinite) + +/-- +A continuous map from a profinite set to a finite set factors through one of the components of +the profinite set when written as a cofiltered limit of finite sets. +-/ +lemma exists_hom (hc : IsLimit c) {X : FintypeCat} (f : c.pt ⟶ toProfinite.obj X) : + ∃ (i : I) (g : F.obj i ⟶ X), f = c.π.app i ≫ toProfinite.map g := by + let _ : TopologicalSpace X := ⊥ + have : DiscreteTopology (toProfinite.obj X) := ⟨rfl⟩ + let f' : LocallyConstant c.pt (toProfinite.obj X) := + ⟨f, (IsLocallyConstant.iff_continuous _).mpr f.continuous⟩ + obtain ⟨i, g, h⟩ := exists_locallyConstant.{_, u} c hc f' + refine ⟨i, (g : _ → _), ?_⟩ + ext x + exact LocallyConstant.congr_fun h x + +namespace Extend + +/-- +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] +def functor : I ⥤ StructuredArrow c.pt toProfinite where + obj i := StructuredArrow.mk (c.π.app i) + map f := StructuredArrow.homMk (F.map f) (c.w f) + +-- We check that the original diagram factors through `Profinite.Extend.functor`. +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, +we obtain a functor from the opposite of the indexing category to +`CostructuredArrow toProfinite.op ⟨c.pt⟩`. +-/ +@[simps! obj map] +def functorOp : Iᵒᵖ ⥤ CostructuredArrow toProfinite.op ⟨c.pt⟩ := + (functor c).op ⋙ StructuredArrow.toCostructuredArrow _ _ + +-- We check that the opposite of the original diagram factors through `Profinite.Extend.functorOp`. +example : functorOp c ⋙ CostructuredArrow.proj toProfinite.op ⟨c.pt⟩ ≅ F.op := Iso.refl _ + +/-- +If the projection maps in the cone are epimorphic and the cone is limiting, then +`Profinite.Extend.functor` is initial. + +TODO: investigate how to weaken the assumption `∀ i, Epi (c.π.app i)` to +`∀ i, ∃ j (_ : j ⟶ i), Epi (c.π.app j)`. +-/ +lemma functor_initial (hc : IsLimit c) [∀ i, Epi (c.π.app i)] : Initial (functor c) := by + let e : I ≌ ULiftHom.{w} (ULift.{w} I) := ULiftHomULiftCategory.equiv _ + suffices (e.inverse ⋙ functor c).Initial from initial_of_equivalence_comp e.inverse (functor c) + rw [initial_iff_of_isCofiltered (F := e.inverse ⋙ functor c)] + constructor + · intro ⟨_, X, (f : c.pt ⟶ _)⟩ + obtain ⟨i, g, h⟩ := exists_hom c hc f + refine ⟨⟨i⟩, ⟨StructuredArrow.homMk g h.symm⟩⟩ + · intro ⟨_, X, (f : c.pt ⟶ _)⟩ ⟨i⟩ ⟨_, (s : F.obj i ⟶ X), (w : f = c.π.app i ≫ _)⟩ + ⟨_, (s' : F.obj i ⟶ X), (w' : f = c.π.app i ≫ _)⟩ + simp only [functor_obj, functor_map, StructuredArrow.hom_eq_iff, StructuredArrow.mk_right, + StructuredArrow.comp_right, StructuredArrow.homMk_right] + refine ⟨⟨i⟩, 𝟙 _, ?_⟩ + simp only [CategoryTheory.Functor.map_id, Category.id_comp] + rw [w] at w' + exact toProfinite.map_injective <| Epi.left_cancellation _ _ w' + +/-- +If the projection maps in the cone are epimorphic and the cone is limiting, then +`Profinite.Extend.functorOp` is final. +-/ +lemma functorOp_final (hc : IsLimit c) [∀ i, Epi (c.π.app i)] : Final (functorOp c) := by + have := functor_initial c hc + have : ((StructuredArrow.toCostructuredArrow toProfinite c.pt)).IsEquivalence := + (inferInstance : (structuredArrowOpEquivalence _ _).functor.IsEquivalence ) + exact Functor.final_comp (functor c).op _ + +section Limit + +variable {C : Type*} [Category C] (G : Profinite ⥤ C) + +/-- +Given a functor `G` from `Profinite` and `S : Profinite`, we obtain a cone on +`(StructuredArrow.proj S toProfinite ⋙ toProfinite ⋙ G)` with cone point `G.obj S`. + +Whiskering this cone with `Profinite.Extend.functor c` gives `G.mapCone c` as we check in the +example below. +-/ +@[simps] +def cone (S : Profinite) : + Cone (StructuredArrow.proj S toProfinite ⋙ toProfinite ⋙ G) where + 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]) } + +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, +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' + +end Limit + +section Colimit + +variable {C : Type*} [Category C] (G : Profiniteᵒᵖ ⥤ C) + +/-- +Given a functor `G` from `Profiniteᵒᵖ` and `S : Profinite`, we obtain a cocone on +`(CostructuredArrow.proj toProfinite.op ⟨S⟩ ⋙ toProfinite.op ⋙ G)` with cocone point `G.obj ⟨S⟩`. + +Whiskering this cocone with `Profinite.Extend.functorOp c` gives `G.mapCocone c.op` as we check in +the example below. +-/ +@[simps] +def cocone (S : Profinite) : + Cocone (CostructuredArrow.proj toProfinite.op ⟨S⟩ ⋙ toProfinite.op ⋙ G) where + pt := G.obj ⟨S⟩ + ι := { + app := fun i ↦ G.map i.hom + naturality := fun _ _ f ↦ (by + 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]) } + +example : G.mapCocone c.op = (cocone G c.pt).whisker (functorOp c) := rfl + +/-- +If `c` is a limit cone, `G.mapCocone c.op` is a colimit cone and the projection maps in `c` +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' + +end Colimit + +end Extend + +open Extend + +section ProfiniteAsLimit + +variable (S : Profinite.{u}) + +/-- +A functor `StructuredArrow S toProfinite ⥤ FintypeCat` whose limit in `Profinite` is isomorphic +to `S`. +-/ +abbrev fintypeDiagram' : StructuredArrow S toProfinite ⥤ FintypeCat := + StructuredArrow.proj S toProfinite + +/-- An abbreviation for `S.fintypeDiagram' ⋙ toProfinite`. -/ +abbrev diagram' : StructuredArrow S toProfinite ⥤ Profinite := + S.fintypeDiagram' ⋙ toProfinite + +/-- A cone over `S.diagram'` whose cone point is `S`. -/ +abbrev asLimitCone' : Cone (S.diagram') := cone (𝟭 _) S + +instance (i : DiscreteQuotient S) : Epi (S.asLimitCone.π.app i) := + (epi_iff_surjective _).mpr i.proj_surjective + +/-- `S.asLimitCone'` is a limit cone. -/ +noncomputable def asLimit' : IsLimit S.asLimitCone' := isLimitCone _ (𝟭 _) S.asLimit S.asLimit + +/-- A bundled version of `S.asLimitCone'` and `S.asLimit'`. -/ +noncomputable def lim' : LimitCone S.diagram' := ⟨S.asLimitCone', S.asLimit'⟩ + +end ProfiniteAsLimit + +end Profinite diff --git a/Mathlib/Topology/Category/Profinite/Nobeling.lean b/Mathlib/Topology/Category/Profinite/Nobeling.lean index 03bbf9e71818c..3807d5656a53a 100644 --- a/Mathlib/Topology/Category/Profinite/Nobeling.lean +++ b/Mathlib/Topology/Category/Profinite/Nobeling.lean @@ -18,16 +18,16 @@ This file proves Nöbeling's theorem. ## Main result * `LocallyConstant.freeOfProfinite`: Nöbeling's theorem. - For `S : Profinite`, the `ℤ`-module `LocallyConstant S ℤ` is free. + For `S : Profinite`, the `ℤ`-module `LocallyConstant S ℤ` is free. ## Proof idea We follow the proof of theorem 5.4 in [scholze2019condensed], in which the idea is to embed `S` in a product of `I` copies of `Bool` for some sufficiently large `I`, and then to choose a -well-ordering on `I` and use ordinal induction over that well-order. Here we can let `I` be -the set of clopen subsets of `S` since `S` is totally separated. +well-ordering on `I` and use ordinal induction over that well-order. Here we can let `I` be +the set of clopen subsets of `S` since `S` is totally separated. -The above means it suffices to prove the following statement: For a closed subset `C` of `I → Bool`, +The above means it suffices to prove the following statement: For a closed subset `C` of `I → Bool`, the `ℤ`-module `LocallyConstant C ℤ` is free. For `i : I`, let `e C i : LocallyConstant C ℤ` denote the map `fun f ↦ (if f.val i then 1 else 0)`. @@ -60,7 +60,7 @@ section Projections The purpose of this section is twofold. -Firstly, in the proof that the set `GoodProducts C` spans the whole module `LocallyConstant C ℤ`, +Firstly, in the proof that the set `GoodProducts C` spans the whole module `LocallyConstant C ℤ`, we need to project `C` down to finite discrete subsets and write `C` as a cofiltered limit of those. Secondly, in the inductive argument, we need to project `C` down to "smaller" sets satisfying the @@ -73,11 +73,11 @@ In this section we define the relevant projection maps and prove some compatibil * Let `J : I → Prop`. Then `Proj J : (I → Bool) → (I → Bool)` is the projection mapping everything that satisfies `J i` to itself, and everything else to `false`. -* The image of `C` under `Proj J` is denoted `π C J` and the corresponding map `C → π C J` is called - `ProjRestrict`. If `J` implies `K` we have a map `ProjRestricts : π C K → π C J`. +* The image of `C` under `Proj J` is denoted `π C J` and the corresponding map `C → π C J` is called + `ProjRestrict`. If `J` implies `K` we have a map `ProjRestricts : π C K → π C J`. * `spanCone_isLimit` establishes that when `C` is compact, it can be written as a limit of its - images under the maps `Proj (· ∈ s)` where `s : Finset I`. + images under the maps `Proj (· ∈ s)` where `s : Finset I`. -/ variable (J K L : I → Prop) [∀ i, Decidable (J i)] [∀ i, Decidable (K i)] [∀ i, Decidable (L i)] @@ -171,7 +171,7 @@ theorem projRestricts_comp_projRestrict (h : ∀ i, J i → K i) : variable (J) -/-- The objectwise map in the isomorphism `spanFunctor ≅ Profinite.indexFunctor`. -/ +/-- The objectwise map in the isomorphism `spanFunctor ≅ Profinite.indexFunctor`. -/ def iso_map : C(π C J, (IndexFunctor.obj C J)) := ⟨fun x ↦ ⟨fun i ↦ x.val i.val, by rcases x with ⟨x, y, hy, rfl⟩ @@ -197,7 +197,6 @@ lemma iso_map_bijective : Function.Bijective (iso_map C J) := by exact dif_pos i.prop variable {C} -variable (hC : IsCompact C) /-- For a given compact subset `C` of `I → Bool`, `spanFunctor` is the functor from the poset of finsets @@ -205,7 +204,7 @@ of `I` to `Profinite`, sending a finite subset set `J` to the image of `C` under `Proj J`. -/ noncomputable -def spanFunctor [∀ (s : Finset I) (i : I), Decidable (i ∈ s)] : +def spanFunctor [∀ (s : Finset I) (i : I), Decidable (i ∈ s)] (hC : IsCompact C) : (Finset I)ᵒᵖ ⥤ Profinite.{u} where obj s := @Profinite.of (π C (· ∈ (unop s))) _ (by rw [← isCompact_iff_compactSpace]; exact hC.image (continuous_proj _)) _ _ @@ -215,7 +214,8 @@ def spanFunctor [∀ (s : Finset I) (i : I), Decidable (i ∈ s)] : /-- The limit cone on `spanFunctor` with point `C`. -/ noncomputable -def spanCone [∀ (s : Finset I) (i : I), Decidable (i ∈ s)] : Cone (spanFunctor hC) where +def spanCone [∀ (s : Finset I) (i : I), Decidable (i ∈ s)] (hC : IsCompact C) : + Cone (spanFunctor hC) where pt := @Profinite.of C _ (by rwa [← isCompact_iff_compactSpace]) _ _ π := { app := fun s ↦ ⟨ProjRestrict C (· ∈ unop s), continuous_projRestrict _ _⟩ @@ -228,7 +228,7 @@ def spanCone [∀ (s : Finset I) (i : I), Decidable (i ∈ s)] : Cone (spanFunct /-- `spanCone` is a limit cone. -/ noncomputable -def spanCone_isLimit [∀ (s : Finset I) (i : I), Decidable (i ∈ s)] : +def spanCone_isLimit [∀ (s : Finset I) (i : I), Decidable (i ∈ s)] (hC : IsCompact C) : CategoryTheory.Limits.IsLimit (spanCone hC) := by refine (IsLimit.postcomposeHomEquiv (NatIso.ofComponents (fun s ↦ (CompHausLike.isoOfBijective _ (iso_map_bijective C (· ∈ unop s)))) ?_) (spanCone hC)) @@ -264,7 +264,7 @@ of `e`. * `Products I` is the type of lists of decreasing elements of `I`, so a typical element is `[i₁, i₂,..., iᵣ]` with `i₁ > i₂ > ... > iᵣ`. -* `Products.eval C` is the `C`-evaluation of a list. It takes a term `[i₁, i₂,..., iᵣ] : Products I` +* `Products.eval C` is the `C`-evaluation of a list. It takes a term `[i₁, i₂,..., iᵣ] : Products I` and returns the actual product `e C i₁ ··· e C iᵣ : LocallyConstant C ℤ`. * `GoodProducts C` is the set of `Products I` such that their `C`-evaluation cannot be written as @@ -272,7 +272,7 @@ of `e`. ### Main results -* `Products.evalFacProp` and `Products.evalFacProps` establish the fact that `Products.eval`  +* `Products.evalFacProp` and `Products.evalFacProps` establish the fact that `Products.eval` interacts nicely with the projection maps from the previous section. * `GoodProducts.span_iff_products`: the good products span `LocallyConstant C ℤ` iff all the @@ -359,7 +359,7 @@ theorem injective : Function.Injective (eval C) := by · exfalso; apply ha; rw [h] exact Submodule.subset_span ⟨b, ⟨h',rfl⟩⟩ -/-- The image of the good products in the module `LocallyConstant C ℤ`. -/ +/-- The image of the good products in the module `LocallyConstant C ℤ`. -/ def range := Set.range (GoodProducts.eval C) /-- The type of good products is equivalent to its image. -/ @@ -412,9 +412,9 @@ 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)] +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 intro i hi by_contra h' @@ -624,8 +624,8 @@ theorem GoodProducts.spanFin [IsWellOrder I (· < ·)] : rw [List.map_cons, List.prod_cons] intro ha specialize ih (by rw [List.chain'_cons'] at ha; exact ha.2) - rw [Finsupp.mem_span_image_iff_total] at ih - simp only [Finsupp.mem_supported, Finsupp.total_apply] at ih + rw [Finsupp.mem_span_image_iff_linearCombination] at ih + simp only [Finsupp.mem_supported, Finsupp.linearCombination_apply] at ih obtain ⟨c, hc, hc'⟩ := ih rw [← hc']; clear hc' have hmap := fun g ↦ map_finsupp_sum (LinearMap.mulLeft ℤ (e (π C (· ∈ s)) a)) c g @@ -667,7 +667,7 @@ theorem fin_comap_jointlySurjective (spanCone_isLimit hC.isCompact) f exact ⟨(Opposite.unop J), g, h⟩ -/-- The good products span all of `LocallyConstant C ℤ` if `C` is closed. -/ +/-- The good products span all of `LocallyConstant C ℤ` if `C` is closed. -/ theorem GoodProducts.span [IsWellOrder I (· < ·)] (hC : IsClosed C) : ⊤ ≤ Submodule.span ℤ (Set.range (eval C)) := by rw [span_iff_products] @@ -692,14 +692,14 @@ can be regarded as the set of all strictly smaller ordinals, allowing to apply o ### Main definitions -* `ord I i` is the term `i` of `I` regarded as an ordinal. +* `ord I i` is the term `i` of `I` regarded as an ordinal. -* `term I ho` is a sufficiently small ordinal regarded as a term of `I`. +* `term I ho` is a sufficiently small ordinal regarded as a term of `I`. -* `contained C o` is a predicate saying that `C` is "small" enough in relation to the ordinal `o` +* `contained C o` is a predicate saying that `C` is "small" enough in relation to the ordinal `o` to satisfy the inductive hypothesis. -* `P I` is the predicate on ordinals about linear independence of good products, which the rest of +* `P I` is the predicate on ordinals about linear independence of good products, which the rest of this file is spent on proving by induction. -/ @@ -711,7 +711,7 @@ def ord (i : I) : Ordinal := Ordinal.typein ((·<·) : I → I → Prop) i /-- An ordinal regarded as a term of `I`. -/ noncomputable def term {o : Ordinal} (ho : o < Ordinal.type ((·<·) : I → I → Prop)) : I := - Ordinal.enum ((·<·) : I → I → Prop) o ho + Ordinal.enum ((·<·) : I → I → Prop) ⟨o, ho⟩ variable {I} @@ -732,13 +732,13 @@ theorem ord_term {o : Ordinal} (ho : o < Ordinal.type ((·<·) : I → I → Pro · subst h exact ord_term_aux ho -/-- A predicate saying that `C` is "small" enough to satisfy the inductive hypothesis. -/ +/-- A predicate saying that `C` is "small" enough to satisfy the inductive hypothesis. -/ def contained (o : Ordinal) : Prop := ∀ f, f ∈ C → ∀ (i : I), f i = true → ord I i < o variable (I) in /-- The predicate on ordinals which we prove by induction, see `GoodProducts.P0`, -`GoodProducts.Plimit` and `GoodProducts.linearIndependentAux` in the section `Induction` below +`GoodProducts.Plimit` and `GoodProducts.linearIndependentAux` in the section `Induction` below -/ def P (o : Ordinal) : Prop := o ≤ Ordinal.type (·<· : I → I → Prop) → @@ -762,7 +762,7 @@ section Zero ## The zero case of the induction -In this case, we have `contained C 0` which means that `C` is either empty or a singleton. +In this case, we have `contained C 0` which means that `C` is either empty or a singleton. -/ instance : Subsingleton (LocallyConstant (∅ : Set (I → Bool)) ℤ) := @@ -776,7 +776,7 @@ instance : IsEmpty { l // Products.isGood (∅ : Set (I → Bool)) l } := theorem GoodProducts.linearIndependentEmpty {I} [LinearOrder I] : LinearIndependent ℤ (eval (∅ : Set (I → Bool))) := linearIndependent_empty_type -/-- The empty list as a `Products` -/ +/-- The empty list as a `Products` -/ def Products.nil : Products I := ⟨[], by simp only [List.chain'_nil]⟩ theorem Products.lt_nil_empty {I} [LinearOrder I] : { m : Products I | m < Products.nil } = ∅ := by @@ -848,13 +848,13 @@ precomposition with the projections defined in the section `Projections`. ### Main definitions -* `πs` and `πs'` are the `ℤ`-linear maps corresponding to `ProjRestrict` and `ProjRestricts`  +* `πs` and `πs'` are the `ℤ`-linear maps corresponding to `ProjRestrict` and `ProjRestricts` respectively. ### Main result -* We prove that `πs` and `πs'` interact well with `Products.eval` and the main application is the - theorem `isGood_mono` which says that the property `isGood` is "monotone" on ordinals. +* We prove that `πs` and `πs'` interact well with `Products.eval` and the main application is the + theorem `isGood_mono` which says that the property `isGood` is "monotone" on ordinals. -/ theorem contained_eq_proj (o : Ordinal) (h : contained C o) : @@ -963,7 +963,7 @@ section Limit We relate linear independence in `LocallyConstant (π C (ord I · < o')) ℤ` with linear independence in `LocallyConstant C ℤ`, where `contained C o` and `o' < o`. -When `o` is a limit ordinal, we prove that the good products in `LocallyConstant C ℤ` are linearly +When `o` is a limit ordinal, we prove that the good products in `LocallyConstant C ℤ` are linearly independent if and only if a certain directed union is linearly independent. Each term in this directed union is in bijection with the good products w.r.t. `π C (ord I · < o')` for an ordinal `o' < o`, and these are linearly independent by the inductive hypothesis. @@ -972,13 +972,13 @@ directed union is in bijection with the good products w.r.t. `π C (ord I · < o * `GoodProducts.smaller` is the image of good products coming from a smaller ordinal. -* `GoodProducts.range_equiv`: The image of the `GoodProducts` in `C` is equivalent to the union of - `smaller C o'` over all ordinals `o' < o`. +* `GoodProducts.range_equiv`: The image of the `GoodProducts` in `C` is equivalent to the union of + `smaller C o'` over all ordinals `o' < o`. ### Main results * `Products.limitOrdinal`: for `o` a limit ordinal such that `contained C o`, a product `l` is good - w.r.t. `C` iff it there exists an ordinal `o' < o` such that `l` is good w.r.t. + w.r.t. `C` iff it there exists an ordinal `o' < o` such that `l` is good w.r.t. `π C (ord I · < o')`. * `GoodProducts.linearIndependent_iff_union_smaller` is the result mentioned above, that the good @@ -988,8 +988,8 @@ directed union is in bijection with the good products w.r.t. `π C (ord I · < o namespace GoodProducts /-- -The image of the `GoodProducts` for `π C (ord I · < o)` in `LocallyConstant C ℤ`. The name `smaller` -refers to the setting in which we will use this, when we are mapping in `GoodProducts` from a +The image of the `GoodProducts` for `π C (ord I · < o)` in `LocallyConstant C ℤ`. The name `smaller` +refers to the setting in which we will use this, when we are mapping in `GoodProducts` from a smaller set, i.e. when `o` is a smaller ordinal than the one `C` is "contained" in. -/ def smaller (o : Ordinal) : Set (LocallyConstant C ℤ) := @@ -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 @@ -1085,7 +1085,7 @@ theorem GoodProducts.union : range C = ⋃ (e : {o' // o' < o}), (smaller C e.va exact Products.isGood_mono C (le_of_lt h) hl /-- -The image of the `GoodProducts` in `C` is equivalent to the union of `smaller C o'` over all +The image of the `GoodProducts` in `C` is equivalent to the union of `smaller C o'` over all ordinals `o' < o`. -/ def GoodProducts.range_equiv : range C ≃ ⋃ (e : {o' // o' < o}), (smaller C e.val) := @@ -1108,8 +1108,8 @@ section Successor ## The successor case in the induction -Here we assume that `o` is an ordinal such that `contained C (o+1)` and `o < I`. The element in `I` -corresponding to `o` is called `term I ho`, but in this informal docstring we refer to it simply as +Here we assume that `o` is an ordinal such that `contained C (o+1)` and `o < I`. The element in `I` +corresponding to `o` is called `term I ho`, but in this informal docstring we refer to it simply as `o`. This section follows the proof in [scholze2019condensed] quite closely. A translation of the @@ -1140,32 +1140,32 @@ corresponds to the last paragraph in the proof in [scholze2019condensed]. The main definitions in the section `ExactSequence` are all just notation explained in the table above. -The main definitions in the section `GoodProducts` are as follows: +The main definitions in the section `GoodProducts` are as follows: * `MaxProducts`: the set of good products that contain the ordinal `o` (since we have `contained C (o+1)`, these all start with `o`). * `GoodProducts.sum_equiv`: the equivalence between `GoodProducts C` and the disjoint union of - `MaxProducts C` and `GoodProducts (π C (ord I · < o))`. + `MaxProducts C` and `GoodProducts (π C (ord I · < o))`. ### Main results -* The main results in the section `ExactSequence` are `succ_mono` and `succ_exact` which together - say that the secuence given by `πs` and `Linear_CC'` is left exact: +* The main results in the section `ExactSequence` are `succ_mono` and `succ_exact` which together + say that the sequence given by `πs` and `Linear_CC'` is left exact: ``` f g 0 --→ LocallyConstant (π C (ord I · < o)) ℤ --→ LocallyConstant C ℤ --→ LocallyConstant C' ℤ ``` - where `f` is `πs` and `g` is `Linear_CC'`. + where `f` is `πs` and `g` is `Linear_CC'`. -The main results in the section `GoodProducts` are as follows: +The main results in the section `GoodProducts` are as follows: * `Products.max_eq_eval` says that the linear map on the right in the exact sequence, i.e. - `Linear_CC'`, takes the evaluation of a term of `MaxProducts` to the evaluation of the + `Linear_CC'`, takes the evaluation of a term of `MaxProducts` to the evaluation of the corresponding list with the leading `o` removed. -* `GoodProducts.maxTail_isGood` says that removing the leading `o` from a term of `MaxProducts C`  - yields a list which `isGood` with respect to `C'`. +* `GoodProducts.maxTail_isGood` says that removing the leading `o` from a term of `MaxProducts C` + yields a list which `isGood` with respect to `C'`. -/ variable {o : Ordinal} (hC : IsClosed C) (hsC : contained C (Order.succ o)) @@ -1245,7 +1245,7 @@ theorem swapTrue_mem_C1 (f : π (C1 C ho) (ord I · < o)) : contrapose! hsC exact ⟨hsC, Order.succ_le_of_lt (h'.lt_of_ne' h)⟩ -/-- The first way to map `C'` into `C`. -/ +/-- The first way to map `C'` into `C`. -/ def CC'₀ : C' C ho → C := fun g ↦ ⟨g.val,g.prop.1.1⟩ /-- The second way to map `C'` into `C`. -/ @@ -1268,7 +1268,7 @@ noncomputable def Linear_CC'₁ : LocallyConstant C ℤ →ₗ[ℤ] LocallyConstant (C' C ho) ℤ := LocallyConstant.comapₗ ℤ ⟨(CC'₁ C hsC ho), (continuous_CC'₁ C hsC ho)⟩ -/-- The difference between `Linear_CC'₁` and `Linear_CC'₀`. -/ +/-- The difference between `Linear_CC'₁` and `Linear_CC'₀`. -/ noncomputable def Linear_CC' : LocallyConstant C ℤ →ₗ[ℤ] LocallyConstant (C' C ho) ℤ := Linear_CC'₁ C hsC ho - Linear_CC'₀ C ho @@ -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 @@ -1424,7 +1424,8 @@ theorem sum_to_range : /-- The equivalence from the sum of `GoodProducts (π C (ord I · < o))` and `(MaxProducts C ho)` to `GoodProducts C`. -/ noncomputable -def sum_equiv : GoodProducts (π C (ord I · < o)) ⊕ (MaxProducts C ho) ≃ GoodProducts C := +def sum_equiv (hsC : contained C (Order.succ o)) (ho : o < Ordinal.type (·<· : I → I → Prop)) : + GoodProducts (π C (ord I · < o)) ⊕ (MaxProducts C ho) ≃ GoodProducts C := calc _ ≃ Set.range (sum_to C ho) := Equiv.ofInjective (sum_to C ho) (injective_sum_to C ho) _ ≃ _ := Equiv.Set.ofEq <| by rw [sum_to_range C ho, union_succ C hsC ho] @@ -1449,7 +1450,7 @@ theorem sum_equiv_comp_eval_eq_elim : eval C ∘ (sum_equiv C hsC ho).toFun = Then `SumEval C ho` is the map `u` in the diagram below. It is linearly independent if and only if `GoodProducts.eval C` is, see `linearIndependent_iff_sum`. The top row is the exact sequence given -by `succ_exact` and `succ_mono`. The left square commutes by `GoodProducts.square_commutes`. +by `succ_exact` and `succ_mono`. The left square commutes by `GoodProducts.square_commutes`. ``` 0 --→ N --→ M --→ P ↑ ↑ ↑ @@ -1477,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)] @@ -1608,20 +1609,20 @@ theorem good_lt_maxProducts (q : GoodProducts (π C (ord I · < o))) include hC hsC in /-- -Removing the leading `o` from a term of `MaxProducts C` yields a list which `isGood` with respect to +Removing the leading `o` from a term of `MaxProducts C` yields a list which `isGood` with respect to `C'`. -/ theorem maxTail_isGood (l : MaxProducts C ho) (h₁ : ⊤ ≤ Submodule.span ℤ (Set.range (eval (π C (ord I · < o))))) : l.val.Tail.isGood (C' C ho) := by have : Inhabited I := ⟨term I ho⟩ - -- Write `l.Tail` as a linear combination of smaller products: + -- Write `l.Tail` as a linear combination of smaller products: intro h - rw [Finsupp.mem_span_image_iff_total, ← max_eq_eval C hsC ho] at h + rw [Finsupp.mem_span_image_iff_linearCombination, ← max_eq_eval C hsC ho] at h obtain ⟨m, ⟨hmmem, hmsum⟩⟩ := h - rw [Finsupp.total_apply] at hmsum + rw [Finsupp.linearCombination_apply] at hmsum - -- Write the image of `l` under `Linear_CC'` as `Linear_CC'` applied to the linear combination + -- Write the image of `l` under `Linear_CC'` as `Linear_CC'` applied to the linear combination -- above, with leading `term I ho`'s added to each term: have : (Linear_CC' C hsC ho) (l.val.eval C) = (Linear_CC' C hsC ho) (Finsupp.sum m fun i a ↦ a • ((term I ho :: i.1).map (e C)).prod) := by @@ -1643,9 +1644,9 @@ 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 + -- Rewrite `this` using exact sequence manipulations to conclude that a term is in the range of -- the linear map `πs`: rw [← LinearMap.sub_mem_ker_iff, ← hse] at this obtain ⟨(n : LocallyConstant (π C (ord I · < o)) ℤ), hn⟩ := this @@ -1700,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₁ @@ -1721,16 +1722,16 @@ section Induction ## The induction -Here we put together the results of the sections `Zero`, `Limit` and `Successor` to prove the -predicate `P I o` holds for all ordinals `o`, and conclude with the main result: +Here we put together the results of the sections `Zero`, `Limit` and `Successor` to prove the +predicate `P I o` holds for all ordinals `o`, and conclude with the main result: -* `GoodProducts.linearIndependent` which says that `GoodProducts C` is linearly independent when `C` +* `GoodProducts.linearIndependent` which says that `GoodProducts C` is linearly independent when `C` is closed. We also define -* `GoodProducts.Basis` which uses `GoodProducts.linearIndependent` and `GoodProducts.span` to - define a basis for `LocallyConstant C ℤ`  +* `GoodProducts.Basis` which uses `GoodProducts.linearIndependent` and `GoodProducts.span` to + define a basis for `LocallyConstant C ℤ` -/ theorem GoodProducts.P0 : P I 0 := fun _ C _ hsC ↦ by @@ -1770,7 +1771,7 @@ theorem GoodProducts.linearIndependent (hC : IsClosed C) : GoodProducts.linearIndependentAux (Ordinal.type (·<· : I → I → Prop)) (le_refl _) C hC (fun _ _ _ _ ↦ Ordinal.typein_lt_type _ _) -/-- `GoodProducts C` as a `ℤ`-basis for `LocallyConstant C ℤ`. -/ +/-- `GoodProducts C` as a `ℤ`-basis for `LocallyConstant C ℤ`. -/ noncomputable def GoodProducts.Basis (hC : IsClosed C) : Basis (GoodProducts C) ℤ (LocallyConstant C ℤ) := @@ -1782,7 +1783,7 @@ variable {S : Profinite} {ι : S → I → Bool} (hι : ClosedEmbedding ι) include hι /-- -Given a profinite set `S` and a closed embedding `S → (I → Bool)`, the `ℤ`-module +Given a profinite set `S` and a closed embedding `S → (I → Bool)`, the `ℤ`-module `LocallyConstant C ℤ` is free. -/ theorem Nobeling_aux : Module.Free ℤ (LocallyConstant S ℤ) := Module.Free.of_equiv' @@ -1799,7 +1800,7 @@ noncomputable def Nobeling.ι : S → ({C : Set S // IsClopen C} → Bool) := fun s C => decide (s ∈ C.1) open scoped Classical in -/-- The map `Nobeling.ι` is a closed embedding. -/ +/-- The map `Nobeling.ι` is a closed embedding. -/ theorem Nobeling.embedding : ClosedEmbedding (Nobeling.ι S) := by apply Continuous.closedEmbedding · dsimp (config := { unfoldPartialApp := true }) [ι] @@ -1829,9 +1830,11 @@ end Profinite open Profinite NobelingProof -/-- Nöbeling's theorem: the `ℤ`-module `LocallyConstant S ℤ` is free for every `S : Profinite` -/ +/-- Nöbeling's theorem: the `ℤ`-module `LocallyConstant S ℤ` is free for every `S : Profinite` -/ 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) + +set_option linter.style.longFile 2000 diff --git a/Mathlib/Topology/Category/Profinite/Product.lean b/Mathlib/Topology/Category/Profinite/Product.lean index f79df72c64680..0224264e33b98 100644 --- a/Mathlib/Topology/Category/Profinite/Product.lean +++ b/Mathlib/Topology/Category/Profinite/Product.lean @@ -13,7 +13,7 @@ Hausdorff spaces as a cofiltered limit in `Profinite` indexed by `Finset ι`. ## Main definitions -- `Profinite.indexFunctor` is the functor `(Finset ι)ᵒᵖ ⥤ Profinite` indexing the limit. It maps +- `Profinite.indexFunctor` is the functor `(Finset ι)ᵒᵖ ⥤ Profinite` indexing the limit. It maps `J` to the restriction of `C` to `J` - `Profinite.indexCone` is a cone on `Profinite.indexFunctor` with cone point `C` @@ -78,23 +78,24 @@ end IndexFunctor variable [∀ i, T2Space (X i)] [∀ i, TotallyDisconnectedSpace (X i)] variable {C} -variable (hC : IsCompact C) open CategoryTheory Limits Opposite IndexFunctor /-- The functor from the poset of finsets of `ι` to `Profinite`, indexing the limit. -/ noncomputable -def indexFunctor : (Finset ι)ᵒᵖ ⥤ Profinite.{u} where +def indexFunctor (hC : IsCompact C) : (Finset ι)ᵒᵖ ⥤ Profinite.{u} where obj J := @Profinite.of (obj C (· ∈ (unop J))) _ (by rw [← isCompact_iff_compactSpace]; exact hC.image (Pi.continuous_precomp' _)) _ _ map h := map C (leOfHom h.unop) /-- The limit cone on `indexFunctor` -/ noncomputable -def indexCone : Cone (indexFunctor hC) where +def indexCone (hC : IsCompact C) : Cone (indexFunctor hC) where pt := @Profinite.of C _ (by rwa [← isCompact_iff_compactSpace]) _ _ π := { app := fun J ↦ π_app C (· ∈ unop J) } +variable (hC : IsCompact C) + instance isIso_indexCone_lift : IsIso ((limitConeIsLimit.{u, u} (indexFunctor hC)).lift (indexCone hC)) := haveI : CompactSpace C := by rwa [← isCompact_iff_compactSpace] 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/Sequential.lean b/Mathlib/Topology/Category/Sequential.lean index e7eccce4aeaf3..65e73b4a4fcb7 100644 --- a/Mathlib/Topology/Category/Sequential.lean +++ b/Mathlib/Topology/Category/Sequential.lean @@ -11,7 +11,7 @@ import Mathlib.Topology.Category.TopCat.Basic # The category of sequential topological spaces -We define the category `Sequential` of sequential topological spaces. We follow the ususal template +We define the category `Sequential` of sequential topological spaces. We follow the usual template for defining categories of topological spaces, by giving it the induced category structure from `TopCat`. -/ diff --git a/Mathlib/Topology/Category/Stonean/Adjunctions.lean b/Mathlib/Topology/Category/Stonean/Adjunctions.lean index d20e34fdfc9fb..dd99b65695aed 100644 --- a/Mathlib/Topology/Category/Stonean/Adjunctions.lean +++ b/Mathlib/Topology/Category/Stonean/Adjunctions.lean @@ -12,7 +12,7 @@ import Mathlib.Topology.StoneCech This file constructs the left adjoint `typeToStonean` to the forgetful functor from Stonean spaces to sets, using the Stone-Cech compactification. This allows to conclude that the monomorphisms in -`Stonean` are precisely the injective maps (see `Stonean.mono_iff_injective`). +`Stonean` are precisely the injective maps (see `Stonean.mono_iff_injective`). -/ universe u diff --git a/Mathlib/Topology/Category/Stonean/Basic.lean b/Mathlib/Topology/Category/Stonean/Basic.lean index 41c7eeabe0cde..47e784b8b878e 100644 --- a/Mathlib/Topology/Category/Stonean/Basic.lean +++ b/Mathlib/Topology/Category/Stonean/Basic.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2023 Adam Topaz. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Adam Topaz +Authors: Adam Topaz, Dagur Asgeirsson -/ import Mathlib.Topology.ExtremallyDisconnected import Mathlib.Topology.Category.CompHaus.Projective @@ -31,6 +31,11 @@ can be lifted along epimorphisms). spaces to compact Hausdorff spaces * `Stonean.toProfinite` : the functor from Stonean spaces to profinite spaces. +## Implementation + +The category `Stonean` is defined using the structure `CompHausLike`. See the file +`CompHausLike.Basic` for more information. + -/ universe u @@ -83,7 +88,7 @@ abbrev fullyFaithfulToCompHaus : toCompHaus.FullyFaithful := open CompHausLike -instance (X : Type*) [TopologicalSpace X] +instance (X : Type*) [TopologicalSpace X] [ExtremallyDisconnected X] : HasProp (fun Y ↦ ExtremallyDisconnected Y) X := ⟨(inferInstance : ExtremallyDisconnected X)⟩ @@ -116,7 +121,7 @@ def mkFinite (X : Type*) [Finite X] [TopologicalSpace X] [DiscreteTopology X] : apply isOpen_discrete (closure U) /-- -A morphism in `Stonean` is an epi iff it is surjective. +A morphism in `Stonean` is an epi iff it is surjective. -/ lemma epi_iff_surjective {X Y : Stonean} (f : X ⟶ Y) : Epi f ↔ Function.Surjective f := by @@ -186,7 +191,7 @@ end Stonean namespace CompHaus /-- If `X` is compact Hausdorff, `presentation X` is a Stonean space equipped with an epimorphism - down to `X` (see `CompHaus.presentation.π` and `CompHaus.presentation.epi_π`). It is a + down to `X` (see `CompHaus.presentation.π` and `CompHaus.presentation.epi_π`). It is a "constructive" witness to the fact that `CompHaus` has enough projectives. -/ noncomputable def presentation (X : CompHaus) : Stonean where @@ -253,7 +258,7 @@ end CompHaus namespace Profinite /-- If `X` is profinite, `presentation X` is a Stonean space equipped with an epimorphism down to - `X` (see `Profinite.presentation.π` and `Profinite.presentation.epi_π`). -/ + `X` (see `Profinite.presentation.π` and `Profinite.presentation.epi_π`). -/ noncomputable def presentation (X : Profinite) : Stonean where toTop := (profiniteToCompHaus.obj X).projectivePresentation.p.toTop diff --git a/Mathlib/Topology/Category/Stonean/EffectiveEpi.lean b/Mathlib/Topology/Category/Stonean/EffectiveEpi.lean index 6f0dcd7b65055..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 @@ -55,7 +52,7 @@ instance : Stonean.toCompHaus.ReflectsEffectiveEpis where (((CompHaus.effectiveEpi_tfae (Stonean.toCompHaus.map f)).out 0 2).mp h) /-- -An effective presentation of an `X : CompHaus` with respect to the inclusion functor from `Stonean` +An effective presentation of an `X : CompHaus` with respect to the inclusion functor from `Stonean` -/ noncomputable def stoneanToCompHausEffectivePresentation (X : CompHaus) : Stonean.toCompHaus.EffectivePresentation X 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/TopCat/Adjunctions.lean b/Mathlib/Topology/Category/TopCat/Adjunctions.lean index db65a15d38f8a..e42823dc49ca5 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 X => id } + counit := { app := fun X => ⟨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 X => ⟨id, continuous_top⟩ } + counit := { app := fun X => 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..ab44aa713d2eb 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 @@ -56,7 +56,7 @@ instance topologicalSpaceUnbundled (X : TopCat) : TopologicalSpace X := 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 diff --git a/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean b/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean index 841f550bb606f..35693a3a1dedc 100644 --- a/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean +++ b/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean @@ -4,14 +4,13 @@ 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`: -The effective epimorphisms in `TopCat` are precisely the quotient maps. +The effective epimorphisms in `TopCat` are precisely the quotient maps. -/ @@ -37,7 +36,7 @@ def effectiveEpiStructOfQuotientMap {B X : TopCat.{u}} (π : X ⟶ B) (hπ : Quo 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 + /- Uniqueness follows from the fact that `QuotientMap.lift` is an equivalence (given by `QuotientMap.liftEquiv`). -/ uniq e h g hm := by suffices g = hπ.liftEquiv ⟨e, @@ -49,21 +48,21 @@ def effectiveEpiStructOfQuotientMap {B X : TopCat.{u}} (π : X ⟶ B) (hπ : Quo simp only [QuotientMap.liftEquiv_symm_apply_coe, ContinuousMap.comp_apply, ← hm] rfl -/-- The effective epimorphisms in `TopCat` are precisely the quotient maps. -/ +/-- The effective epimorphisms in `TopCat` are precisely the quotient maps. -/ theorem effectiveEpi_iff_quotientMap {B X : TopCat.{u}} (π : X ⟶ B) : EffectiveEpi π ↔ QuotientMap π := 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 + /- Since `TopCat` has pullbacks, `π` is in fact a `RegularEpi`. This means that it exhibits `B` as a coequalizer of two maps into `X`. It suffices to prove that `π` followed by the isomorphism to an arbitrary coequalizer is a quotient map. -/ 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 + simpa [← Function.comp_assoc] using (homeoOfIso i).symm.quotientMap.comp this constructor - /- Effective epimorphisms are epimorphisms and epimorphisms in `TopCat` are surjective. -/ + /- Effective epimorphisms are epimorphisms and epimorphisms in `TopCat` are surjective. -/ · change Function.Surjective (π ≫ i.hom) rw [← epi_iff_surjective] infer_instance diff --git a/Mathlib/Topology/Category/TopCat/Limits/Basic.lean b/Mathlib/Topology/Category/TopCat/Limits/Basic.lean index 2c9ab0122ae91..b476fb65fb907 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 @@ -70,7 +70,7 @@ def limitConeIsLimit (F : J ⥤ TopCat.{max v u}) : IsLimit (limitCone.{v,u} F) { toFun := fun x => ⟨fun j => 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..dc77a067581bd 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 @@ -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 43cd610adcbfb..780074ed743fe 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 @@ -58,7 +58,7 @@ equipped with the product topology. -/ def piIsoPi {ι : Type v} (α : ι → TopCat.{max v u}) : ∏ᶜ α ≅ TopCat.of (∀ i, α i) := (limit.isLimit _).conePointUniqueUpToIso (piFanIsLimit.{v, u} α) - -- Specifying the universes in `piFanIsLimit` wasn't necessary when we had `TopCatMax`  + -- Specifying the universes in `piFanIsLimit` wasn't necessary when we had `TopCatMax` @[reassoc (attr := simp)] theorem piIsoPi_inv_π {ι : Type v} (α : ι → TopCat.{max v u}) (i : ι) : @@ -106,7 +106,7 @@ def sigmaCofanIsColimit {ι : Type v} (β : ι → TopCat.{max v u}) : IsColimit -/ def sigmaIsoSigma {ι : Type v} (α : ι → TopCat.{max v u}) : ∐ α ≅ TopCat.of (Σi, α i) := (colimit.isColimit _).coconePointUniqueUpToIso (sigmaCofanIsColimit.{v, u} α) - -- Specifying the universes in `sigmaCofanIsColimit` wasn't necessary when we had `TopCatMax`  + -- Specifying the universes in `sigmaCofanIsColimit` wasn't necessary when we had `TopCatMax` @[reassoc (attr := simp)] theorem sigmaIsoSigma_hom_ι {ι : Type v} (α : ι → TopCat.{max v u}) (i : ι) : @@ -236,12 +236,12 @@ 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) @@ -346,8 +346,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..3d1a8ae947989 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 @@ -214,17 +214,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 @@ -318,8 +315,7 @@ theorem fst_embedding_of_right_embedding {X Y S : TopCat} (f : X ⟶ S) {g : Y 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] + 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) @@ -343,8 +339,7 @@ theorem openEmbedding_of_pullback_open_embeddings {X Y S : TopCat} {f : X ⟶ 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] + rw [← coe_comp, ← limit.w _ WalkingCospan.Hom.inr] rfl theorem fst_iso_of_right_embedding_range_subset {X Y S : TopCat} (f : X ⟶ S) {g : Y ⟶ S} diff --git a/Mathlib/Topology/Category/TopCat/OpenNhds.lean b/Mathlib/Topology/Category/TopCat/OpenNhds.lean index c5465486c0688..d9325ee6922be 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 @@ -10,12 +10,12 @@ import Mathlib.Data.Set.Subsingleton # The category of open neighborhoods of a point Given an object `X` of the category `TopCat` of topological spaces and a point `x : X`, this file -builds the type `OpenNhds x` of open neighborhoods of `x` in `X` and endows it with the partial +builds the type `OpenNhds x` of open neighborhoods of `x` in `X` and endows it with the partial order given by inclusion and the corresponding category structure (as a full subcategory of the poset category `Set X`). This is used in `Topology.Sheaves.Stalks` to build the stalk of a sheaf at `x` as a limit over `OpenNhds x`. -## Main declarations +## Main declarations Besides `OpenNhds`, the main constructions here are: @@ -86,7 +86,7 @@ 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 := +theorem openEmbedding {x : X} (U : OpenNhds x) : OpenEmbedding U.1.inclusion' := U.1.openEmbedding /-- The preimage functor from neighborhoods of `f x` to neighborhoods of `x`. -/ @@ -144,9 +144,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 U => homOfLE fun x hxU => ⟨x, hxU, rfl⟩ } + counit := { app := fun V => homOfLE fun y ⟨_, hfxV, hxy⟩ => hxy ▸ hfxV } end IsOpenMap diff --git a/Mathlib/Topology/Category/TopCat/Opens.lean b/Mathlib/Topology/Category/TopCat/Opens.lean index 5bebad78ee1ff..988c19dba4faa 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 @@ -111,21 +111,21 @@ theorem toTopCat_map (X : TopCat.{u}) {U V : Opens X} {f : U ⟶ V} {x} {h} : /-- The inclusion map from an open subset to the whole space, as a morphism in `TopCat`. -/ @[simps (config := .asFn)] -def inclusion {X : TopCat.{u}} (U : Opens X) : (toTopCat X).obj U ⟶ X where +def inclusion' {X : TopCat.{u}} (U : Opens X) : (toTopCat X).obj U ⟶ X where toFun := _ continuous_toFun := continuous_subtype_val @[simp] -theorem coe_inclusion {X : TopCat} {U : Opens X} : - (inclusion U : U → X) = Subtype.val := rfl +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) := +theorem openEmbedding {X : TopCat.{u}} (U : Opens X) : OpenEmbedding (inclusion' U) := IsOpen.openEmbedding_subtype_val U.2 /-- 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 ⊤ + hom := inclusion' ⊤ inv := ⟨fun x => ⟨x, trivial⟩, continuous_def.2 fun U ⟨_, hS, hSU⟩ => hSU ▸ hS⟩ /-- `Opens.map f` gives the functor from open sets in Y to open set in X, @@ -280,10 +280,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 U => homOfLE fun x hxU => ⟨x, hxU, rfl⟩ } + counit := { app := fun V => homOfLE fun y ⟨_, hfxV, hxy⟩ => hxy ▸ hfxV } instance IsOpenMap.functorFullOfMono {X Y : TopCat} {f : X ⟶ Y} (hf : IsOpenMap f) [H : Mono f] : hf.functor.Full where @@ -310,7 +309,7 @@ theorem openEmbedding_obj_top {X : TopCat} (U : Opens X) : exact Set.image_univ.trans Subtype.range_coe @[simp] -theorem inclusion_map_eq_top {X : TopCat} (U : Opens X) : (Opens.map U.inclusion).obj U = ⊤ := by +theorem inclusion'_map_eq_top {X : TopCat} (U : Opens X) : (Opens.map U.inclusion').obj U = ⊤ := by ext1 exact Subtype.coe_preimage_self _ @@ -318,7 +317,7 @@ theorem inclusion_map_eq_top {X : TopCat} (U : Opens X) : (Opens.map U.inclusion theorem adjunction_counit_app_self {X : TopCat} (U : Opens X) : U.openEmbedding.isOpenMap.adjunction.counit.app U = eqToHom (by simp) := Subsingleton.elim _ _ -theorem inclusion_top_functor (X : TopCat) : +theorem inclusion'_top_functor (X : TopCat) : (@Opens.openEmbedding X ⊤).isOpenMap.functor = map (inclusionTopIso X).inv := by refine CategoryTheory.Functor.ext ?_ ?_ · intro U @@ -336,8 +335,8 @@ 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_forget_map_inclusion' {X : TopCat} (U : Opens X) : + Set.range ((forget TopCat).map (inclusion' U)) = (U : Set X) := by ext x constructor · rintro ⟨x, rfl⟩ @@ -347,10 +346,10 @@ lemma set_range_forget_map_inclusion {X : TopCat} (U : Opens X) : @[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.openEmbedding.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] + erw [set_range_forget_map_inclusion' U] rfl theorem map_functor_eq' {X U : TopCat} (f : U ⟶ X) (hf : OpenEmbedding f) (V) : @@ -359,7 +358,7 @@ theorem map_functor_eq' {X U : TopCat} (f : U ⟶ X) (hf : OpenEmbedding f) (V) @[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 := + ((Opens.map U.inclusion').obj <| U.openEmbedding.isOpenMap.functor.obj V) = V := TopologicalSpace.Opens.map_functor_eq' _ U.openEmbedding V @[simp] 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 4875f93370077..65ed0d1e00d83 100644 --- a/Mathlib/Topology/Category/TopCat/Yoneda.lean +++ b/Mathlib/Topology/Category/TopCat/Yoneda.lean @@ -57,7 +57,7 @@ theorem piComparison_fac {α : Type} (X : α → TopCat) : Equiv.coe_fn_symm_mk, comp_assoc, sigmaMk_apply, ← opCoproductIsoProduct_inv_comp_ι] rfl -/-- The universe polymorphic Yoneda presheaf on `TopCat` preserves finite products. -/ +/-- The universe polymorphic Yoneda presheaf on `TopCat` preserves finite products. -/ noncomputable instance : PreservesFiniteProducts (yonedaPresheaf'.{w, w'} Y) where preserves J _ := { preservesLimit := fun {K} => diff --git a/Mathlib/Topology/Category/TopCommRingCat.lean b/Mathlib/Topology/Category/TopCommRingCat.lean index 153f2b41ff795..b6734c03f35c7 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 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..ff10a04698b33 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 _⟩ diff --git a/Mathlib/Topology/CompactOpen.lean b/Mathlib/Topology/CompactOpen.lean index 24a3372bc22ad..0338dd8e2d361 100644 --- a/Mathlib/Topology/CompactOpen.lean +++ b/Mathlib/Topology/CompactOpen.lean @@ -3,7 +3,7 @@ Copyright (c) 2018 Reid Barton. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Reid Barton -/ -import Mathlib.Topology.ContinuousFunction.Basic +import Mathlib.Topology.ContinuousMap.Basic /-! # The compact-open topology @@ -93,6 +93,7 @@ theorem embedding_comp (g : C(Y, Z)) (hg : Embedding g) : Embedding (g.comp : C( ⟨inducing_comp g hg.1, fun _ _ ↦ (cancel_left hg.2).1⟩ /-- `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)) := continuous_compactOpen.2 fun K hK U hU ↦ by simpa only [mapsTo_image_iff] using isOpen_setOf_mapsTo (hK.image f.2) hU @@ -166,8 +167,6 @@ theorem continuous_eval [LocallyCompactPair X Y] : Continuous fun p : C(X, Y) × 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 - /-- Evaluation of a continuous map `f` at a point `x` is continuous in `f`. Porting note: merged `continuous_eval_const` with `continuous_eval_const'` removing unneeded @@ -277,7 +276,7 @@ theorem tendsto_compactOpen_iff_forall {ι : Type*} {l : Filter ι} (F : ι → Tendsto F l (𝓝 f) ↔ ∀ K, IsCompact K → Tendsto (fun i => (F i).restrict K) l (𝓝 (f.restrict K)) := by rw [compactOpen_eq_iInf_induced] - simp [nhds_iInf, nhds_induced, Filter.tendsto_comap_iff, Function.comp] + simp [nhds_iInf, nhds_induced, Filter.tendsto_comap_iff, Function.comp_def] /-- A family `F` of functions in `C(X, Y)` converges in the compact-open topology, if and only if it converges in the compact-open topology on each compact subset of `X`. -/ @@ -375,7 +374,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 @@ -389,7 +388,7 @@ 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) + apply continuous_eval.comp (continuous_eval.prodMap continuous_id) /-- The family of constant maps: `Y → C(X, Y)` as a continuous map. -/ def const' : C(Y, C(X, Y)) := diff --git a/Mathlib/Topology/Compactification/OnePoint.lean b/Mathlib/Topology/Compactification/OnePoint.lean index 0201f2ccbee78..7552539c3ada1 100644 --- a/Mathlib/Topology/Compactification/OnePoint.lean +++ b/Mathlib/Topology/Compactification/OnePoint.lean @@ -187,7 +187,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) := @@ -426,9 +426,12 @@ 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) := +theorem isDenseEmbedding_coe [NoncompactSpace X] : IsDenseEmbedding ((↑) : X → OnePoint X) := { openEmbedding_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 @@ -507,7 +510,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 diff --git a/Mathlib/Topology/Compactness/Compact.lean b/Mathlib/Topology/Compactness/Compact.lean index 1a468a8d2b236..b83613bdfbf38 100644 --- a/Mathlib/Topology/Compactness/Compact.lean +++ b/Mathlib/Topology/Compactness/Compact.lean @@ -229,11 +229,11 @@ theorem IsCompact.elim_directed_family_closed {ι : Type v} [hι : Nonempty ι] 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, @@ -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 diff --git a/Mathlib/Topology/Compactness/CompactlyGeneratedSpace.lean b/Mathlib/Topology/Compactness/CompactlyGeneratedSpace.lean index ebc17cc09ad5a..fbcd4585a405a 100644 --- a/Mathlib/Topology/Compactness/CompactlyGeneratedSpace.lean +++ b/Mathlib/Topology/Compactness/CompactlyGeneratedSpace.lean @@ -54,7 +54,7 @@ The compactly generated topology on a topological space `X`. This is the finest which makes all maps from compact Hausdorff spaces to `X`, which are continuous for the original topology, continuous. -Note: this definition should be used with an explicit universe parameter `u` for the size of the +Note: this definition should be used with an explicit universe parameter `u` for the size of the compact Hausdorff spaces mapping to `X`. -/ def TopologicalSpace.compactlyGenerated (X : Type w) [TopologicalSpace X] : TopologicalSpace X := 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 03b75fea6f233..6cbd814c5efbe 100644 --- a/Mathlib/Topology/Compactness/Lindelof.lean +++ b/Mathlib/Topology/Compactness/Lindelof.lean @@ -511,7 +511,7 @@ theorem IsClosed.isLindelof [LindelofSpace X] (h : IsClosed s) : IsLindelof s := theorem IsCompact.isLindelof (hs : IsCompact s) : IsLindelof s := by tauto -/-- A σ-compact set `s` is Lindelöf-/ +/-- A σ-compact set `s` is Lindelöf -/ theorem IsSigmaCompact.isLindelof (hs : IsSigmaCompact s) : IsLindelof s := by rw [IsSigmaCompact] at hs @@ -564,7 +564,7 @@ theorem Filter.coLindelof_neBot_iff : NeBot (Filter.coLindelof X) ↔ NonLindelo theorem not_LindelofSpace_iff : ¬LindelofSpace X ↔ NonLindelofSpace X := ⟨fun h₁ => ⟨fun h₂ => h₁ ⟨h₂⟩⟩, fun ⟨h₁⟩ ⟨h₂⟩ => h₁ h₂⟩ -/-- A compact space `X` is Lindelöf. -/ +/-- A compact space `X` is Lindelöf. -/ instance (priority := 100) [CompactSpace X] : LindelofSpace X := { isLindelof_univ := isCompact_univ.isLindelof} @@ -594,7 +594,7 @@ theorem Filter.comap_coLindelof_le {f : X → Y} (hf : Continuous f) : simpa using t.subset_preimage_image f theorem isLindelof_range [LindelofSpace X] {f : X → Y} (hf : Continuous f) : - IsLindelof (range f) := by rw [← image_univ]; exact isLindelof_univ.image hf + IsLindelof (range f) := by rw [← image_univ]; exact isLindelof_univ.image hf theorem isLindelof_diagonal [LindelofSpace X] : IsLindelof (diagonal X) := @range_diag X ▸ isLindelof_range (continuous_id.prod_mk continuous_id) @@ -692,7 +692,7 @@ for open sets in the definition, and then conclude that this holds for all sets def IsHereditarilyLindelof (s : Set X) := ∀ t ⊆ s, IsLindelof t -/-- Type class for Hereditarily Lindelöf spaces. -/ +/-- Type class for Hereditarily Lindelöf spaces. -/ class HereditarilyLindelofSpace (X : Type*) [TopologicalSpace X] : Prop where /-- In a Hereditarily Lindelöf space, `Set.univ` is a Hereditarily Lindelöf set. -/ isHereditarilyLindelof_univ : IsHereditarilyLindelof (univ : Set X) diff --git a/Mathlib/Topology/Compactness/LocallyCompact.lean b/Mathlib/Topology/Compactness/LocallyCompact.lean index 1881270210e57..e0c44089ecd15 100644 --- a/Mathlib/Topology/Compactness/LocallyCompact.lean +++ b/Mathlib/Topology/Compactness/LocallyCompact.lean @@ -76,9 +76,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 +166,37 @@ 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⟩ +/-- If `f` is a topology inducing map with a locally compact codomain and a locally closed range, +then the domain of `f` is a locally compact space. -/ +theorem Inducing.locallyCompactSpace [LocallyCompactSpace Y] {f : X → Y} (hf : Inducing f) + (h : IsLocallyClosed (range f)) : LocallyCompactSpace X := by + 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] + 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 + hf.toInducing.locallyCompactSpace hf.isClosed_range.isLocallyClosed + +protected theorem OpenEmbedding.locallyCompactSpace [LocallyCompactSpace Y] {f : X → Y} + (hf : OpenEmbedding f) : LocallyCompactSpace X := + hf.toInducing.locallyCompactSpace hf.isOpen_range.isLocallyClosed + +protected theorem IsLocallyClosed.locallyCompactSpace [LocallyCompactSpace X] {s : Set X} + (hs : IsLocallyClosed s) : LocallyCompactSpace s := + embedding_subtype_val.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/Connected/Basic.lean b/Mathlib/Topology/Connected/Basic.lean index 8d8d2a542f23d..54b61ed7b660c 100644 --- a/Mathlib/Topology/Connected/Basic.lean +++ b/Mathlib/Topology/Connected/Basic.lean @@ -506,7 +506,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⟩ diff --git a/Mathlib/Topology/Connected/PathConnected.lean b/Mathlib/Topology/Connected/PathConnected.lean index 07fea44bddd1e..644fcb694b3a8 100644 --- a/Mathlib/Topology/Connected/PathConnected.lean +++ b/Mathlib/Topology/Connected/PathConnected.lean @@ -33,7 +33,7 @@ Then there are corresponding relative notions for `F : Set X`. * `LocPathConnectedSpace X` is a predicate class asserting that `X` is locally path-connected: each point has a basis of path-connected neighborhoods (we do *not* ask these to be open). -## Main theorems +## Main theorems * `Joined` and `JoinedIn F` are transitive relations. @@ -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 @@ -200,7 +200,7 @@ instance topologicalSpace : TopologicalSpace (Path x y) := 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 + (continuous_induced_dom (α := Path x y)).prodMap continuous_id @[continuity] theorem _root_.Continuous.path_eval {Y} [TopologicalSpace Y] {f : Y → Path x y} {g : Y → I} @@ -247,7 +247,6 @@ theorem extend_zero : γ.extend 0 = x := by simp theorem extend_one : γ.extend 1 = y := by simp -@[simp] theorem extend_extends' {a b : X} (γ : Path a b) (t : (Icc 0 1 : Set ℝ)) : γ.extend t = γ t := IccExtend_val _ γ t @@ -424,7 +423,7 @@ 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) := @@ -434,7 +433,7 @@ theorem continuous_symm : Continuous (symm : Path x y → Path y x) := 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] @@ -448,12 +447,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' ℝ)] diff --git a/Mathlib/Topology/Connected/Separation.lean b/Mathlib/Topology/Connected/Separation.lean index 57db6948dc729..8ce21856914c0 100644 --- a/Mathlib/Topology/Connected/Separation.lean +++ b/Mathlib/Topology/Connected/Separation.lean @@ -11,7 +11,7 @@ import Mathlib.Topology.Separation This file provides an instance `T2Space X` given `TotallySeparatedSpace X`. ## TODO -* Move the last part of `Topology/Separation` to this file. +* Move the last part of `Topology/Separation` to this file. -/ diff --git a/Mathlib/Topology/Connected/TotallyDisconnected.lean b/Mathlib/Topology/Connected/TotallyDisconnected.lean index 0da1004c037f4..b7f1ff02b4fb4 100644 --- a/Mathlib/Topology/Connected/TotallyDisconnected.lean +++ b/Mathlib/Topology/Connected/TotallyDisconnected.lean @@ -195,7 +195,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 +210,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,7 +264,6 @@ 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] diff --git a/Mathlib/Topology/Constructions.lean b/Mathlib/Topology/Constructions.lean index 51eb2dee9f145..b4bf95ad2f9e1 100644 --- a/Mathlib/Topology/Constructions.lean +++ b/Mathlib/Topology/Constructions.lean @@ -3,6 +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, Patrick Massot -/ +import Mathlib.Data.Finset.Piecewise +import Mathlib.Order.Filter.Curry import Mathlib.Topology.Maps.Basic import Mathlib.Topology.NhdsSet @@ -398,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} @@ -409,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 -/ @@ -419,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 -/ @@ -431,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) : @@ -514,6 +518,22 @@ theorem Filter.HasBasis.prod_nhds' {ιX ιY : Type*} {pX : ιX → Prop} {pY : (𝓝 p).HasBasis (fun i : ιX × ιY => pX i.1 ∧ pY i.2) fun i => sx i.1 ×ˢ sy i.2 := hx.prod_nhds hy +theorem MapClusterPt.curry_prodMap {α β : Type*} + {f : α → X} {g : β → Y} {la : Filter α} {lb : Filter β} {x : X} {y : Y} + (hf : MapClusterPt x la f) (hg : MapClusterPt y lb g) : + MapClusterPt (x, y) (la.curry lb) (.map f g) := by + rw [mapClusterPt_iff] at hf hg + rw [((𝓝 x).basis_sets.prod_nhds (𝓝 y).basis_sets).mapClusterPt_iff_frequently] + rintro ⟨s, t⟩ ⟨hs, ht⟩ + rw [frequently_curry_iff] + exact (hf s hs).mono fun x hx ↦ (hg t ht).mono fun y hy ↦ ⟨hx, hy⟩ + +theorem MapClusterPt.prodMap {α β : Type*} + {f : α → X} {g : β → Y} {la : Filter α} {lb : Filter β} {x : X} {y : Y} + (hf : MapClusterPt x la f) (hg : MapClusterPt y lb g) : + MapClusterPt (x, y) (la ×ˢ lb) (.map f g) := + (hf.curry_prodMap hg).mono <| map_mono curry_le_prod + theorem mem_nhds_prod_iff' {x : X} {y : Y} {s : Set (X × Y)} : s ∈ 𝓝 (x, y) ↔ ∃ u v, IsOpen u ∧ x ∈ u ∧ IsOpen v ∧ y ∈ v ∧ u ×ˢ v ⊆ s := ((nhds_basis_opens x).prod_nhds (nhds_basis_opens y)).mem_iff.trans <| by @@ -564,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) : @@ -600,7 +626,7 @@ theorem prod_generateFrom_generateFrom_eq {X Y : Type*} {s : Set (Set X)} {t : S (hs : ⋃₀ s = univ) (ht : ⋃₀ t = univ) : @instTopologicalSpaceProd X Y (generateFrom s) (generateFrom t) = generateFrom (image2 (· ×ˢ ·) s t) := - let G := generateFrom (image2 (· ×ˢ ·) s t) + let G := generateFrom (image2 (· ×ˢ ·) s t) le_antisymm (le_generateFrom fun g ⟨u, hu, v, hv, g_eq⟩ => g_eq.symm ▸ @@ -710,9 +736,15 @@ 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 quotientMap_snd [Nonempty X] : QuotientMap (Prod.snd : X × Y → Y) := + isOpenMap_snd.to_quotientMap continuous_snd Prod.snd_surjective + theorem closure_prod_eq {s : Set X} {t : Set Y} : closure (s ×ˢ t) = closure s ×ˢ closure t := ext fun ⟨a, b⟩ => by simp_rw [mem_prod, mem_closure_iff_nhdsWithin_neBot, nhdsWithin_prod_eq, prod_neBot] @@ -752,40 +784,50 @@ 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) : +@[deprecated (since := "2024-10-05")] alias DenseRange.prod_map := DenseRange.prodMap + +theorem Inducing.prodMap {f : X → Y} {g : Z → W} (hf : Inducing f) (hg : Inducing g) : Inducing (Prod.map f g) := inducing_iff_nhds.2 fun (x, z) => by simp_rw [Prod.map_def, nhds_prod_eq, hf.nhds_eq_comap, hg.nhds_eq_comap, prod_comap_comap_eq] +@[deprecated (since := "2024-10-05")] alias Inducing.prod_map := Inducing.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, + simp_rw [inducing_iff, instTopologicalSpaceProd, induced_inf, induced_compose, Function.comp_def, induced_const, top_inf_eq] @[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, + simp_rw [inducing_iff, instTopologicalSpaceProd, induced_inf, induced_compose, Function.comp_def, induced_const, inf_top_eq] -theorem Embedding.prod_map {f : X → Y} {g : Z → W} (hf : Embedding f) (hg : Embedding g) : +theorem Embedding.prodMap {f : X → Y} {g : Z → W} (hf : Embedding f) (hg : Embedding g) : Embedding (Prod.map f g) := - { hf.toInducing.prod_map hg.toInducing with + { hf.toInducing.prodMap hg.toInducing with inj := fun ⟨x₁, z₁⟩ ⟨x₂, z₂⟩ => by simp [hf.inj.eq_iff, hg.inj.eq_iff] } -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-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 OpenEmbedding.prodMap {f : X → Y} {g : Z → W} (hf : OpenEmbedding f) + (hg : OpenEmbedding g) : OpenEmbedding (Prod.map f g) := + openEmbedding_of_embedding_open (hf.1.prodMap hg.1) (hf.isOpenMap.prodMap hg.isOpenMap) + +@[deprecated (since := "2024-10-05")] alias OpenEmbedding.prod := OpenEmbedding.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 @@ -793,6 +835,10 @@ theorem embedding_graph {f : X → Y} (hf : Continuous f) : Embedding fun x => ( 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 +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 section Bool @@ -841,6 +887,10 @@ theorem continuous_inl : Continuous (@inl X Y) := ⟨fun _ => And.left⟩ -- 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] +lemma continuous_sum_swap : Continuous (@Sum.swap X Y) := + Continuous.sum_elim continuous_inr continuous_inl + theorem isOpen_sum_iff {s : Set (X ⊕ Y)} : IsOpen s ↔ IsOpen (inl ⁻¹' s) ∧ IsOpen (inr ⁻¹' s) := Iff.rfl @@ -905,7 +955,11 @@ theorem Continuous.sum_map {f : X → Y} {g : Z → W} (hf : Continuous f) (hg : theorem isOpenMap_sum {f : X ⊕ Y → Z} : IsOpenMap f ↔ (IsOpenMap fun a => f (inl a)) ∧ IsOpenMap fun b => f (inr b) := by - simp only [isOpenMap_iff_nhds_le, Sum.forall, nhds_inl, nhds_inr, Filter.map_map, comp] + simp only [isOpenMap_iff_nhds_le, Sum.forall, nhds_inl, nhds_inr, Filter.map_map, comp_def] + +theorem IsOpenMap.sumMap {f : X → Y} {g : Z → W} (hf : IsOpenMap f) (hg : IsOpenMap g) : + IsOpenMap (Sum.map f g) := by + exact isOpenMap_sum.2 ⟨isOpenMap_inl.comp hf,isOpenMap_inr.comp hg⟩ @[simp] theorem isOpenMap_sum_elim {f : X → Z} {g : Y → Z} : @@ -931,7 +985,7 @@ 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⟩ @@ -1053,7 +1107,7 @@ theorem embedding_inclusion {s t : Set X} (h : s ⊆ t) : Embedding (inclusion h embedding_subtype_val.codRestrict _ _ /-- 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. -/ +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 @@ -1086,7 +1140,7 @@ 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) := @@ -1112,7 +1166,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 @@ -1129,7 +1183,7 @@ variable {ι : Type*} {π : ι → Type*} {κ : Type*} [TopologicalSpace X] [T : ∀ i, TopologicalSpace (π i)] {f : X → ∀ i : ι, π i} theorem continuous_pi_iff : Continuous f ↔ ∀ i, Continuous fun a => f a i := by - simp only [continuous_iInf_rng, continuous_induced_rng, comp] + simp only [continuous_iInf_rng, continuous_induced_rng, comp_def] @[continuity, fun_prop] theorem continuous_pi (h : ∀ i, Continuous fun a => f a i) : Continuous f := @@ -1187,17 +1241,51 @@ theorem Pi.continuous_postcomp [TopologicalSpace Y] {g : X → Y} (hg : Continuo lemma Pi.induced_precomp' {ι' : Type*} (φ : ι' → ι) : induced (fun (f : (∀ i, π i)) (j : ι') ↦ f (φ j)) Pi.topologicalSpace = ⨅ i', induced (eval (φ i')) (T (φ i')) := by - simp [Pi.topologicalSpace, induced_iInf, induced_compose, comp] + simp [Pi.topologicalSpace, induced_iInf, induced_compose, comp_def] lemma Pi.induced_precomp [TopologicalSpace Y] {ι' : Type*} (φ : ι' → ι) : induced (· ∘ φ) Pi.topologicalSpace = ⨅ 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 @@ -1372,7 +1460,7 @@ theorem pi_generateFrom_eq_finite {π : ι → Type*} {g : ∀ a, Set (Set (π a theorem induced_to_pi {X : Type*} (f : X → ∀ i, π i) : induced f Pi.topologicalSpace = ⨅ i, induced (f · i) inferInstance := by - simp_rw [Pi.topologicalSpace, induced_iInf, induced_compose, Function.comp] + simp_rw [Pi.topologicalSpace, induced_iInf, induced_compose, Function.comp_def] /-- Suppose `π i` is a family of topological spaces indexed by `i : ι`, and `X` is a type endowed with a family of maps `f i : X → π i` for every `i : ι`, hence inducing a @@ -1494,7 +1582,7 @@ 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] + continuous_sigma_iff.trans <| by simp only [Sigma.map, embedding_sigmaMk.continuous_iff, comp_def] @[continuity, fun_prop] theorem Continuous.sigma_map {f₁ : ι → κ} {f₂ : ∀ i, σ i → τ (f₁ i)} (hf : ∀ i, Continuous (f₂ i)) : @@ -1502,7 +1590,7 @@ theorem Continuous.sigma_map {f₁ : ι → κ} {f₂ : ∀ i, σ i → τ (f₁ continuous_sigma_map.2 hf theorem isOpenMap_sigma {f : Sigma σ → X} : IsOpenMap f ↔ ∀ i, IsOpenMap fun a => f ⟨i, a⟩ := by - simp only [isOpenMap_iff_nhds_le, Sigma.forall, Sigma.nhds_eq, map_map, comp] + simp only [isOpenMap_iff_nhds_le, Sigma.forall, Sigma.nhds_eq, map_map, comp_def] theorem isOpenMap_sigma_map {f₁ : ι → κ} {f₂ : ∀ i, σ i → τ (f₁ i)} : IsOpenMap (Sigma.map f₁ f₂) ↔ ∀ i, IsOpenMap (f₂ i) := @@ -1572,8 +1660,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. -/ @@ -1594,3 +1682,5 @@ theorem Filter.Eventually.prod_nhdsSet {p : X × Y → Prop} {px : X → Prop} { nhdsSet_prod_le _ _ (mem_of_superset (prod_mem_prod hs ht) fun _ ⟨hx, hy⟩ ↦ hp hx hy) end NhdsSet + +set_option linter.style.longFile 1700 diff --git a/Mathlib/Topology/ContinuousFunction/Algebra.lean b/Mathlib/Topology/ContinuousMap/Algebra.lean similarity index 99% rename from Mathlib/Topology/ContinuousFunction/Algebra.lean rename to Mathlib/Topology/ContinuousMap/Algebra.lean index c3143c043f066..4e62f17e049be 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 @@ -14,7 +14,7 @@ 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 +295,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`. -/ @@ -550,7 +550,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)] diff --git a/Mathlib/Topology/ContinuousFunction/Basic.lean b/Mathlib/Topology/ContinuousMap/Basic.lean similarity index 77% rename from Mathlib/Topology/ContinuousFunction/Basic.lean rename to Mathlib/Topology/ContinuousMap/Basic.lean index b24e4f2ee999c..bd8aca0de948b 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,14 +31,9 @@ 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-/ +/-! ### Continuous maps -/ namespace ContinuousMap @@ -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) := @@ -304,7 +203,7 @@ def sigma (f : ∀ i, C(X i, A)) : C((Σ i, X i), A) where variable (A X) in /-- Giving a continuous map out of a disjoint union is the same as giving a continuous map out of -each term. This is a version of `Equiv.piCurry` for continuous maps. +each term. This is a version of `Equiv.piCurry` for continuous maps. -/ @[simps] def sigmaEquiv : (∀ i, C(X i, A)) ≃ C((Σ i, X i), A) where @@ -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,8 +363,8 @@ 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 := quotientMap_quot_mk.continuous_iff.mpr (map_continuous f) + continuous_invFun := continuous_quotient_mk'.comp (map_continuous f') namespace QuotientMap @@ -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 `QuotientMap.lift` commutes: ``` g X --→ Z diff --git a/Mathlib/Topology/ContinuousFunction/Bounded.lean b/Mathlib/Topology/ContinuousMap/Bounded.lean similarity index 99% rename from Mathlib/Topology/ContinuousFunction/Bounded.lean rename to Mathlib/Topology/ContinuousMap/Bounded.lean index fe002c06a38ed..01840e85e6d01 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 @@ -228,12 +228,12 @@ theorem tendsto_iff_tendstoUniformly {ι : Type*} {F : ι → α →ᵇ β} {f : (fun h => tendstoUniformly_iff.2 fun ε ε0 => (Metric.tendsto_nhds.mp h ε ε0).mp - (eventually_of_forall fun n hn x => + (Eventually.of_forall fun n hn x => lt_of_le_of_lt (dist_coe_le_dist x) (dist_comm (F n) f ▸ hn))) fun h => Metric.tendsto_nhds.mpr fun _ ε_pos => (h _ (dist_mem_uniformity <| half_pos ε_pos)).mp - (eventually_of_forall fun n hn => + (Eventually.of_forall fun n hn => lt_of_le_of_lt ((dist_le (half_pos ε_pos).le).mpr fun x => dist_comm (f x) (F n x) ▸ le_of_lt (hn x)) (half_lt_self ε_pos)) @@ -246,7 +246,7 @@ theorem inducing_coeFn : Inducing (UniformFun.ofFun ∘ (⇑) : (α →ᵇ β) UniformFun.tendsto_iff_tendstoUniformly] simp [comp_def] --- TODO: upgrade to a `UniformEmbedding` +-- TODO: upgrade to a `IsUniformEmbedding` theorem embedding_coeFn : Embedding (UniformFun.ofFun ∘ (⇑) : (α →ᵇ β) → α →ᵤ β) := ⟨inducing_coeFn, fun _ _ h => ext fun x => congr_fun h x⟩ @@ -307,7 +307,7 @@ instance instCompleteSpace [CompleteSpace β] : CompleteSpace (α →ᵇ β) := refine ((tendsto_order.1 b_lim).2 ε ε0).mono fun n hn x => ?_ rw [dist_comm] exact lt_of_le_of_lt (fF_bdd x n) hn - exact this.continuous (eventually_of_forall fun N => (f N).continuous) + exact this.continuous (Eventually.of_forall fun N => (f N).continuous) · -- Check that `F` is bounded rcases (f 0).bounded with ⟨C, hC⟩ refine ⟨C + (b 0 + b 0), fun x y => ?_⟩ @@ -524,7 +524,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 ⊢ @@ -1513,3 +1513,5 @@ lemma norm_sub_nonneg (f : α →ᵇ ℝ) : end end BoundedContinuousFunction + +set_option linter.style.longFile 1700 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 77c4cda47593d..ca3851110e939 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,10 +145,14 @@ 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] -end +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) -instance [CompleteSpace β] : CompleteSpace C(α, β) := - (isometryEquivBoundedOfCompact α β).completeSpace +end -- TODO at some point we will need lemmas characterising this norm! -- At the moment the only way to reason about it is to transfer `f : C(α,E)` back to `α →ᵇ E`. @@ -153,13 +169,17 @@ theorem _root_.BoundedContinuousFunction.norm_toContinuousMap_eq (f : α →ᵇ open BoundedContinuousFunction -instance : NormedAddCommGroup C(α, E) := - { ContinuousMap.metricSpace _ _, - ContinuousMap.instAddCommGroupContinuousMap with - dist_eq := fun x y => by - rw [← norm_mkOfCompact, ← dist_mkOfCompact, dist_eq_norm, mkOfCompact_sub] - dist := dist - norm := norm } +instance : SeminormedAddCommGroup C(α, E) where + __ := ContinuousMap.instPseudoMetricSpace _ _ + __ := ContinuousMap.instAddCommGroupContinuousMap + dist_eq x y := by + rw [← norm_mkOfCompact, ← dist_mkOfCompact, dist_eq_norm, mkOfCompact_sub] + dist := dist + norm := norm + +instance {E : Type*} [NormedAddCommGroup E] : NormedAddCommGroup C(α, E) where + __ : SeminormedAddCommGroup C(α, E) := inferInstance + __ : MetricSpace C(α, E) := inferInstance instance [Nonempty α] [One E] [NormOneClass E] : NormOneClass C(α, E) where norm_one := by simp only [← norm_mkOfCompact, mkOfCompact_one, norm_one] @@ -205,6 +225,11 @@ theorem neg_norm_le_apply (f : C(α, ℝ)) (x : α) : -‖f‖ ≤ f x := theorem norm_eq_iSup_norm : ‖f‖ = ⨆ x : α, ‖f x‖ := (mkOfCompact f).norm_eq_iSup_norm +-- A version with better keys +instance {X : Type*} [TopologicalSpace X] (K : TopologicalSpace.Compacts X) : + CompactSpace (K : Set X) := + TopologicalSpace.Compacts.instCompactSpaceSubtypeMem .. + theorem norm_restrict_mono_set {X : Type*} [TopologicalSpace X] (f : C(X, E)) {K L : TopologicalSpace.Compacts X} (hKL : K ≤ L) : ‖f.restrict K‖ ≤ ‖f.restrict L‖ := (norm_le _ (norm_nonneg _)).mpr fun x => norm_coe_le_norm (f.restrict L) <| Set.inclusion hKL x @@ -213,11 +238,40 @@ end section -variable {R : Type*} [NormedRing R] +variable {R : Type*} + +instance [NonUnitalSeminormedRing R] : NonUnitalSeminormedRing C(α, R) where + __ : SeminormedAddCommGroup C(α, R) := inferInstance + __ : NonUnitalRing C(α, R) := inferInstance + norm_mul f g := norm_mul_le (mkOfCompact f) (mkOfCompact g) + +instance [NonUnitalSeminormedCommRing R] : NonUnitalSeminormedCommRing C(α, R) where + __ : NonUnitalSeminormedRing C(α, R) := inferInstance + __ : NonUnitalCommRing C(α, R) := inferInstance + +instance [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 : NormedRing C(α, R) := - { (inferInstance : NormedAddCommGroup C(α, R)), ContinuousMap.instRing with - norm_mul := fun f g => norm_mul_le (mkOfCompact f) (mkOfCompact g) } +instance [NormedCommRing R] : NormedCommRing C(α, R) where + __ : NormedRing C(α, R) := inferInstance + __ : CommRing C(α, R) := inferInstance end @@ -226,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 @@ -285,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 } @@ -299,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. @@ -333,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 @@ -380,7 +434,8 @@ 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 + [TopologicalSpace Y] [CompactSpace Y] [PseudoMetricSpace 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 ?_ @@ -391,14 +446,15 @@ def compRightContinuousMap {X Y : Type*} (T : Type*) [TopologicalSpace X] [Compa @[simp] theorem compRightContinuousMap_apply {X Y : Type*} (T : Type*) [TopologicalSpace X] - [CompactSpace X] [TopologicalSpace Y] [CompactSpace Y] [MetricSpace T] (f : C(X, Y)) + [CompactSpace X] [TopologicalSpace Y] [CompactSpace Y] [PseudoMetricSpace 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 + [TopologicalSpace Y] [CompactSpace Y] [PseudoMetricSpace 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 _) @@ -406,7 +462,7 @@ def compRightHomeomorph {X Y : Type*} (T : Type*) [TopologicalSpace X] [CompactS 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)) : + [PseudoMetricSpace A] [TopologicalSemiring A] [Algebra R A] (f : C(X, Y)) : Continuous (compRightAlgHom R A f) := map_continuous (compRightContinuousMap A f) @@ -455,7 +511,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) := @@ -471,7 +527,7 @@ end NormedSpace section CStarRing variable {α : Type*} {β : Type*} -variable [TopologicalSpace α] [NormedRing β] [StarRing β] +variable [TopologicalSpace α] [NonUnitalNormedRing β] [StarRing β] instance [CompactSpace α] [CStarRing β] : CStarRing C(α, β) where norm_mul_self_le f := by diff --git a/Mathlib/Topology/ContinuousFunction/CompactlySupported.lean b/Mathlib/Topology/ContinuousMap/CompactlySupported.lean similarity index 98% rename from Mathlib/Topology/ContinuousFunction/CompactlySupported.lean rename to Mathlib/Topology/ContinuousMap/CompactlySupported.lean index d8d72123235af..cea48f4937a02 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) diff --git a/Mathlib/Topology/ContinuousFunction/ContinuousMapZero.lean b/Mathlib/Topology/ContinuousMap/ContinuousMapZero.lean similarity index 89% rename from Mathlib/Topology/ContinuousFunction/ContinuousMapZero.lean rename to Mathlib/Topology/ContinuousMap/ContinuousMapZero.lean index 76f9a54f3d595..5fa65e8b7c342 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 @@ -95,6 +95,14 @@ lemma closedEmbedding_toContinuousMap [T1Space R] : rw [range_toContinuousMap] exact isClosed_singleton.preimage <| ContinuousMap.continuous_eval_const 0 +@[fun_prop] +lemma continuous_comp_left {X Y Z : Type*} [TopologicalSpace X] + [TopologicalSpace Y] [TopologicalSpace Z] [Zero X] [Zero Y] [Zero Z] (f : C(X, Y)₀) : + Continuous fun g : C(Y, Z)₀ ↦ g.comp f := by + rw [continuous_induced_rng] + show Continuous fun g : C(Y, Z)₀ ↦ (g : C(Y, Z)).comp (f : C(X, Y)) + fun_prop + /-- The identity function as an element of `C(s, R)₀` when `0 ∈ (s : Set R)`. -/ @[simps!] protected def id {s : Set R} [Zero s] (h0 : ((0 : s) : R) = 0) : C(s, R)₀ := @@ -260,20 +268,26 @@ 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 + completeSpace_iff_isComplete_range isUniformEmbedding_toContinuousMap.isUniformInducing |>.mpr closedEmbedding_toContinuousMap.isClosed_range.isComplete -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 +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 + +@[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`. -/ @@ -283,12 +297,12 @@ def _root_.UniformEquiv.arrowCongrLeft₀ {Y : Type*} [TopologicalSpace Y] [Zero invFun g := g.comp ⟨f.toContinuousMap, 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 <| + uniformContinuous_toFun := isUniformEmbedding_toContinuousMap.uniformContinuous_iff.mpr <| ContinuousMap.uniformContinuous_comp_left f.symm.toContinuousMap |>.comp - uniformEmbedding_toContinuousMap.uniformContinuous - uniformContinuous_invFun := uniformEmbedding_toContinuousMap.uniformContinuous_iff.mpr <| + isUniformEmbedding_toContinuousMap.uniformContinuous + uniformContinuous_invFun := isUniformEmbedding_toContinuousMap.uniformContinuous_iff.mpr <| ContinuousMap.uniformContinuous_comp_left f.toContinuousMap |>.comp - uniformEmbedding_toContinuousMap.uniformContinuous + isUniformEmbedding_toContinuousMap.uniformContinuous end UniformSpace @@ -332,7 +346,7 @@ 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))‖ diff --git a/Mathlib/Topology/ContinuousMap/Defs.lean b/Mathlib/Topology/ContinuousMap/Defs.lean new file mode 100644 index 0000000000000..f576214a27758 --- /dev/null +++ b/Mathlib/Topology/ContinuousMap/Defs.lean @@ -0,0 +1,136 @@ +/- +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 + +@[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 99% rename from Mathlib/Topology/ContinuousFunction/Ideals.lean rename to Mathlib/Topology/ContinuousMap/Ideals.lean index e40d94ca79034..5edb4350d5274 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 @@ -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] 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 94% rename from Mathlib/Topology/ContinuousFunction/Ordered.lean rename to Mathlib/Topology/ContinuousMap/Ordered.lean index 0b4780410756f..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 @@ -85,7 +85,7 @@ section Extend variable [LinearOrder α] [OrderTopology α] {a b : α} (h : a ≤ b) -/-- Extend a continuous function `f : C(Set.Icc a b, β)` to a function `f : C(α, β)`. -/ +/-- Extend a continuous function `f : C(Set.Icc a b, β)` to a function `f : C(α, β)`. -/ def IccExtend (f : C(Set.Icc a b, β)) : C(α, β) where toFun := Set.IccExtend h f diff --git a/Mathlib/Topology/ContinuousFunction/Polynomial.lean b/Mathlib/Topology/ContinuousMap/Polynomial.lean similarity index 98% rename from Mathlib/Topology/ContinuousFunction/Polynomial.lean rename to Mathlib/Topology/ContinuousMap/Polynomial.lean index 3fd434d44adc3..83a3dd5e6a0ed 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 diff --git a/Mathlib/Topology/ContinuousFunction/Sigma.lean b/Mathlib/Topology/ContinuousMap/Sigma.lean similarity index 97% rename from Mathlib/Topology/ContinuousFunction/Sigma.lean rename to Mathlib/Topology/ContinuousMap/Sigma.lean index c5bdc0f0b7351..320fd5cc4ab1f 100644 --- a/Mathlib/Topology/ContinuousFunction/Sigma.lean +++ b/Mathlib/Topology/ContinuousMap/Sigma.lean @@ -25,7 +25,7 @@ because it is easier to use an equivalence in applications. ## TODO Some results in this file can be generalized to the case when `X` is a preconnected space. However, -if `X` is empty, then any index `i` will work, so there is no 1-to-1 corespondence. +if `X` is empty, then any index `i` will work, so there is no 1-to-1 correspondence. ## Keywords @@ -63,7 +63,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) diff --git a/Mathlib/Topology/ContinuousFunction/StarOrdered.lean b/Mathlib/Topology/ContinuousMap/StarOrdered.lean similarity index 97% rename from Mathlib/Topology/ContinuousFunction/StarOrdered.lean rename to Mathlib/Topology/ContinuousMap/StarOrdered.lean index 18882fe259d74..b894be96cbeb1 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 -/ diff --git a/Mathlib/Topology/ContinuousFunction/StoneWeierstrass.lean b/Mathlib/Topology/ContinuousMap/StoneWeierstrass.lean similarity index 98% rename from Mathlib/Topology/ContinuousFunction/StoneWeierstrass.lean rename to Mathlib/Topology/ContinuousMap/StoneWeierstrass.lean index 57b51d1724771..643b6ad6595d6 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 diff --git a/Mathlib/Topology/ContinuousFunction/T0Sierpinski.lean b/Mathlib/Topology/ContinuousMap/T0Sierpinski.lean similarity index 97% rename from Mathlib/Topology/ContinuousFunction/T0Sierpinski.lean rename to Mathlib/Topology/ContinuousMap/T0Sierpinski.lean index 48655f0023ded..4e9903ccc7400 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. diff --git a/Mathlib/Topology/ContinuousFunction/Units.lean b/Mathlib/Topology/ContinuousMap/Units.lean similarity index 98% rename from Mathlib/Topology/ContinuousFunction/Units.lean rename to Mathlib/Topology/ContinuousMap/Units.lean index a8c880cf3a2bc..0337bcc434faa 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 diff --git a/Mathlib/Topology/ContinuousFunction/Weierstrass.lean b/Mathlib/Topology/ContinuousMap/Weierstrass.lean similarity index 97% rename from Mathlib/Topology/ContinuousFunction/Weierstrass.lean rename to Mathlib/Topology/ContinuousMap/Weierstrass.lean index dfc2335f23237..fbfdd66fb2023 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 @@ -32,7 +32,7 @@ theorem polynomialFunctions_closure_eq_top' : (polynomialFunctions I).topologica rintro f - refine Filter.Frequently.mem_closure ?_ refine Filter.Tendsto.frequently (bernsteinApproximation_uniform f) ?_ - apply frequently_of_forall + apply Frequently.of_forall intro n simp only [SetLike.mem_coe] apply Subalgebra.sum_mem diff --git a/Mathlib/Topology/ContinuousFunction/ZeroAtInfty.lean b/Mathlib/Topology/ContinuousMap/ZeroAtInfty.lean similarity index 98% rename from Mathlib/Topology/ContinuousFunction/ZeroAtInfty.lean rename to Mathlib/Topology/ContinuousMap/ZeroAtInfty.lean index 586b078cd9837..b9c5713bf06fd 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 @@ -16,7 +16,7 @@ compact space, this type has nice properties. ## TODO -* Create more intances of algebraic structures (e.g., `NonUnitalSemiring`) once the necessary +* Create more instances of algebraic structures (e.g., `NonUnitalSemiring`) once the necessary type classes (e.g., `TopologicalRing`) are sufficiently generalized. * Relate the unitization of `C₀(α, β)` to the Alexandroff compactification. -/ @@ -416,7 +416,7 @@ theorem isClosed_range_toBCF : IsClosed (range (toBCF : C₀(α, β) → α → refine Metric.tendsto_nhds.mpr fun ε hε => ?_ obtain ⟨_, hg, g, rfl⟩ := hf (ball f (ε / 2)) (ball_mem_nhds f <| half_pos hε) refine (Metric.tendsto_nhds.mp (zero_at_infty g) (ε / 2) (half_pos hε)).mp - (eventually_of_forall fun x hx => ?_) + (Eventually.of_forall fun x hx => ?_) calc dist (f x) 0 ≤ dist (g.toBCF x) (f x) + dist (g x) 0 := dist_triangle_left _ _ _ _ < dist g.toBCF f + ε / 2 := add_lt_add_of_le_of_lt (dist_coe_le_dist x) hx @@ -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 44d171d882c3f..7608fd4158dbb 100644 --- a/Mathlib/Topology/ContinuousOn.lean +++ b/Mathlib/Topology/ContinuousOn.lean @@ -3,6 +3,7 @@ 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 /-! @@ -53,12 +54,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 @@ -384,7 +393,7 @@ theorem tendsto_nhdsWithin_iff {a : α} {l : Filter β} {s : Set α} {f : β → theorem tendsto_nhdsWithin_range {a : α} {l : Filter β} {f : β → α} : Tendsto f l (𝓝[range f] a) ↔ Tendsto f l (𝓝 a) := ⟨fun h => h.mono_right inf_le_left, fun h => - tendsto_inf.2 ⟨h, tendsto_principal.2 <| eventually_of_forall mem_range_self⟩⟩ + tendsto_inf.2 ⟨h, tendsto_principal.2 <| Eventually.of_forall mem_range_self⟩⟩ theorem Filter.EventuallyEq.eq_of_nhdsWithin {s : Set α} {f g : α → β} {a : α} (h : f =ᶠ[𝓝[s] a] g) (hmem : a ∈ s) : f a = g a := @@ -608,7 +617,7 @@ theorem continuous_of_cover_nhds {ι : Sort*} {f : α → β} {s : ι → Set α 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} := @@ -684,8 +693,7 @@ theorem continuousWithinAt_singleton {f : α → β} {x : α} : ContinuousWithin @[simp] theorem continuousWithinAt_insert_self {f : α → β} {x : α} {s : Set α} : 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] alias ⟨_, ContinuousWithinAt.insert_self⟩ := continuousWithinAt_insert_self @@ -711,7 +719,7 @@ theorem continuousWithinAt_update_same [DecidableEq α] {f : α → β} {s : Set 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 + tendsto_congr' <| eventually_nhdsWithin_iff.2 <| Eventually.of_forall fun z hz => update_noteq hz.2 _ _ @[simp] @@ -1138,7 +1146,8 @@ theorem IsOpen.ite' {s s' t : Set α} (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 * - convert continuous_piecewise (fun x hx => propext (ht x hx)) hs.continuousOn hs'.continuousOn + convert + continuous_piecewise (fun x hx => propext (ht x hx)) hs.continuousOn hs'.continuousOn using 2 rename_i x by_cases hx : x ∈ t <;> simp [hx] 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 201785096951d..2b89c259917e8 100644 --- a/Mathlib/Topology/Defs/Induced.lean +++ b/Mathlib/Topology/Defs/Induced.lean @@ -124,6 +124,8 @@ structure ClosedEmbedding (f : X → Y) extends Embedding f : Prop where /-- 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. -/ -def QuotientMap {X : Type*} {Y : Type*} [tX : TopologicalSpace X] [tY : TopologicalSpace Y] - (f : X → Y) : Prop := - Function.Surjective f ∧ tY = tX.coinduced f +@[mk_iff quotientMap_iff'] +structure QuotientMap {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 diff --git a/Mathlib/Topology/DenseEmbedding.lean b/Mathlib/Topology/DenseEmbedding.lean index b6754581c6062..210caa3dca529 100644 --- a/Mathlib/Topology/DenseEmbedding.lean +++ b/Mathlib/Topology/DenseEmbedding.lean @@ -11,14 +11,14 @@ import Mathlib.Topology.Bases 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,30 @@ 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 : α → β) +structure IsDenseInducing [TopologicalSpace α] [TopologicalSpace β] (i : α → β) extends Inducing 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) := +theorem nhds_eq_comap (di : IsDenseInducing i) : ∀ a : α, 𝓝 a = comap i (𝓝 <| i a) := di.toInducing.nhds_eq_comap -protected theorem continuous (di : DenseInducing i) : Continuous i := +protected theorem continuous (di : IsDenseInducing i) : Continuous i := di.toInducing.continuous -theorem closure_range (di : DenseInducing i) : closure (range i) = univ := +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 +64,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] 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 +81,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 + toInducing := de₁.toInducing.prodMap de₂.toInducing + 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 +105,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 +114,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 +125,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 -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 +166,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 + 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,61 +192,66 @@ 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 := + (H : ∀ (a : α), ∀ s ∈ 𝓝 a, ∃ t ∈ 𝓝 (i a), ∀ b, i b ∈ t → b ∈ s) : IsDenseInducing i := { toInducing := inducing_iff_nhds.2 fun a => le_antisymm (c.tendsto _).le_comap (by simpa [Filter.le_def] using H a) 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 } + +@[deprecated (since := "2024-09-30")] +alias DenseEmbedding.mk' := IsDenseEmbedding.mk' -namespace DenseEmbedding +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 := +theorem to_embedding (de : IsDenseEmbedding e) : Embedding e := { induced := de.induced inj := de.inj } -/-- 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) := +protected theorem subtype (de : IsDenseEmbedding e) (p : α → Prop) : + IsDenseEmbedding (subtypeEmb p e) := { dense := dense_iff_closure_eq.2 <| by ext ⟨x, hx⟩ @@ -253,20 +261,26 @@ protected theorem subtype (de : DenseEmbedding e) (p : α → Prop) : induced := (induced_iff_nhds_eq _).2 fun ⟨x, hx⟩ => by simp [subtypeEmb, nhds_subtype_eq_comap, de.toInducing.nhds_eq_comap, comap_comap, - (· ∘ ·)] } - -theorem dense_image (de : DenseEmbedding e) {s : Set α} : Dense (e '' s) ↔ Dense s := - de.toDenseInducing.dense_image + Function.comp_def] } -end DenseEmbedding +theorem dense_image (de : IsDenseEmbedding e) {s : Set α} : Dense (e '' s) ↔ Dense s := + de.toIsDenseInducing.dense_image -theorem denseEmbedding_id {α : Type*} [TopologicalSpace α] : DenseEmbedding (id : α → α) := +protected lemma id {α : Type*} [TopologicalSpace α] : IsDenseEmbedding (id : α → α) := { embedding_id with dense := denseRange_id } -theorem Dense.denseEmbedding_val [TopologicalSpace α] {s : Set α} (hs : Dense s) : - DenseEmbedding ((↑) : s → α) := +end IsDenseEmbedding + +@[deprecated (since := "2024-09-30")] +alias denseEmbedding_id := IsDenseEmbedding.id + +theorem Dense.isDenseEmbedding_val [TopologicalSpace α] {s : Set α} (hs : Dense s) : + IsDenseEmbedding ((↑) : s → α) := { embedding_subtype_val with dense := hs.denseRange_val } +@[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 := have : univ ⊆ { b | p b } := @@ -279,14 +293,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,9 +333,9 @@ 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 => ?_⟩ diff --git a/Mathlib/Topology/DiscreteQuotient.lean b/Mathlib/Topology/DiscreteQuotient.lean index 6c041809ef504..ed3253cad0993 100644 --- a/Mathlib/Topology/DiscreteQuotient.lean +++ b/Mathlib/Topology/DiscreteQuotient.lean @@ -182,7 +182,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 @@ -348,7 +348,7 @@ open Classical in If `X` is a compact space, then we associate to any discrete quotient on `X` a finite set of clopen subsets of `X`, given by the fibers of `proj`. -TODO: prove that these form a partition of `X`  +TODO: prove that these form a partition of `X` -/ noncomputable def finsetClopens [CompactSpace X] (d : DiscreteQuotient X) : Finset (Clopens X) := have : Fintype d := Fintype.ofFinite _ @@ -368,7 +368,7 @@ lemma comp_finsetClopens [CompactSpace X] : simpa [← h] using Quotient.mk_eq_iff_out (s := d.toSetoid) · exact fun ⟨y, h⟩ ↦ ⟨d.proj y, by ext; simp [h, proj]⟩ -/-- `finsetClopens X` is injective. -/ +/-- `finsetClopens X` is injective. -/ theorem finsetClopens_inj [CompactSpace X] : (finsetClopens X).Injective := by apply Function.Injective.of_comp (f := Set.image (fun (t : Clopens X) ↦ t.carrier) ∘ Finset.toSet) diff --git a/Mathlib/Topology/DiscreteSubset.lean b/Mathlib/Topology/DiscreteSubset.lean index 4122752067f57..5238fbf4e8e1e 100644 --- a/Mathlib/Topology/DiscreteSubset.lean +++ b/Mathlib/Topology/DiscreteSubset.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2023 Oliver Nash. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Oliver Nash, Bhavik Mehta +Authors: Oliver Nash, Bhavik Mehta, Daniel Weber -/ import Mathlib.Topology.Constructions import Mathlib.Topology.Separation @@ -30,8 +30,9 @@ see `IsClosed.tendsto_coe_cofinite_iff`. ## Co-discrete open sets -In a topological space the sets which are open with discrete complement form a filter. We -formalise this as `Filter.codiscrete`. +We define the filter `Filter.codiscreteWithin S`, which is the supremum of all `𝓝[S \ {x}] x`. +This is the filter of all open codiscrete sets within S. We also define `Filter.codiscrete` as +`Filter.codiscreteWithin univ`, which is the filter of all open codiscrete sets in the space. -/ @@ -95,17 +96,53 @@ theorem isClosed_and_discrete_iff {S : Set X} : · refine ⟨fun hx ↦ ?_, fun _ ↦ H⟩ simpa [disjoint_iff, nhdsWithin, inf_assoc, hx] using H -/-- In any topological space, the open sets with with discrete complement form a filter. -/ -def Filter.codiscrete (X : Type*) [TopologicalSpace X] : Filter X where - sets := {U | IsOpen U ∧ DiscreteTopology ↑Uᶜ} - univ_sets := ⟨isOpen_univ, compl_univ.symm ▸ Subsingleton.discreteTopology⟩ - sets_of_superset := by - intro U V hU hV - simp_rw [← isClosed_compl_iff, isClosed_and_discrete_iff] at hU ⊢ - exact fun x ↦ (hU x).mono_right (principal_mono.mpr <| compl_subset_compl.mpr hV) - inter_sets := by - intro U V hU hV - simp_rw [← isClosed_compl_iff, isClosed_and_discrete_iff] at hU hV ⊢ - exact fun x ↦ compl_inter U V ▸ sup_principal ▸ disjoint_sup_right.mpr ⟨hU x, hV x⟩ +/-- The filter of sets with no accumulation points inside a set `S : Set X`, implemented +as the supremum over all punctured neighborhoods within `S`. -/ +def Filter.codiscreteWithin (S : Set X) : Filter X := ⨆ x ∈ S, 𝓝[S \ {x}] x + +lemma mem_codiscreteWithin {S T : Set X} : + S ∈ codiscreteWithin T ↔ ∀ x ∈ T, Disjoint (𝓝[≠] x) (𝓟 (T \ S)) := by + simp only [codiscreteWithin, mem_iSup, mem_nhdsWithin, disjoint_principal_right, subset_def, + mem_diff, mem_inter_iff, mem_compl_iff] + congr! 7 with x - u y + tauto + +lemma mem_codiscreteWithin_accPt {S T : Set X} : + S ∈ codiscreteWithin T ↔ ∀ x ∈ T, ¬AccPt x (𝓟 (T \ S)) := by + simp only [mem_codiscreteWithin, disjoint_iff, AccPt, not_neBot] + +/-- In any topological space, the open sets with discrete complement form a filter, +defined as the supremum of all punctured neighborhoods. + +See `Filter.mem_codiscrete'` for the equivalence. -/ +def Filter.codiscrete (X : Type*) [TopologicalSpace X] : Filter X := codiscreteWithin Set.univ + +lemma mem_codiscrete {S : Set X} : + S ∈ codiscrete X ↔ ∀ x, Disjoint (𝓝[≠] x) (𝓟 Sᶜ) := by + simp [codiscrete, mem_codiscreteWithin, compl_eq_univ_diff] + +lemma mem_codiscrete_accPt {S : Set X} : + S ∈ codiscrete X ↔ ∀ x, ¬AccPt x (𝓟 Sᶜ) := by + simp only [mem_codiscrete, disjoint_iff, AccPt, not_neBot] + +lemma mem_codiscrete' {S : Set X} : + S ∈ codiscrete X ↔ IsOpen S ∧ DiscreteTopology ↑Sᶜ := by + rw [mem_codiscrete, ← isClosed_compl_iff, isClosed_and_discrete_iff] + +lemma mem_codiscrete_subtype_iff_mem_codiscreteWithin {S : Set X} {U : Set S} : + U ∈ codiscrete S ↔ (↑) '' U ∈ codiscreteWithin S := by + simp [mem_codiscrete, disjoint_principal_right, compl_compl, Subtype.forall, + mem_codiscreteWithin] + congr! with x hx + constructor + · rw [nhdsWithin_subtype, mem_comap] + rintro ⟨t, ht1, ht2⟩ + rw [mem_nhdsWithin] at ht1 ⊢ + obtain ⟨u, hu1, hu2, hu3⟩ := ht1 + refine ⟨u, hu1, hu2, fun v hv ↦ ?_⟩ + simpa using fun hv2 ↦ ⟨hv2, ht2 <| hu3 <| by simpa [hv2]⟩ + · suffices Tendsto (↑) (𝓝[≠] (⟨x, hx⟩ : S)) (𝓝[≠] x) by convert tendsto_def.mp this _; ext; simp + exact tendsto_nhdsWithin_of_tendsto_nhds_of_eventually_within _ + continuous_subtype_val.continuousWithinAt <| eventually_mem_nhdsWithin.mono (by simp) end codiscrete_filter diff --git a/Mathlib/Topology/EMetricSpace/Basic.lean b/Mathlib/Topology/EMetricSpace/Basic.lean index 7845b2fb5b6dd..0aba00ba4c0d7 100644 --- a/Mathlib/Topology/EMetricSpace/Basic.lean +++ b/Mathlib/Topology/EMetricSpace/Basic.lean @@ -3,130 +3,27 @@ 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.Real import Mathlib.Order.Interval.Finset.Nat -import Mathlib.Topology.UniformSpace.Pi +import Mathlib.Topology.EMetricSpace.Defs import Mathlib.Topology.UniformSpace.UniformConvergence import Mathlib.Topology.UniformSpace.UniformEmbedding /-! # Extended metric spaces -This file is devoted to the definition and study of `EMetricSpace`s, i.e., metric -spaces in which the distance is allowed to take the value ∞. This extended distance is -called `edist`, and takes values in `ℝ≥0∞`. - -Many definitions and theorems expected on emetric spaces are already introduced on uniform spaces -and topological spaces. For example: open and closed sets, compactness, completeness, continuity and -uniform continuity. - -The class `EMetricSpace` therefore extends `UniformSpace` (and `TopologicalSpace`). - -Since a lot of elementary properties don't require `eq_of_edist_eq_zero` we start setting up the -theory of `PseudoEMetricSpace`, where we don't require `edist x y = 0 → x = y` and we specialize -to `EMetricSpace` at the end. +Further results about extended metric spaces. -/ open Set Filter -open scoped Uniformity Topology NNReal ENNReal Pointwise universe u v w variable {α : Type u} {β : Type v} {X : Type*} -/-- Characterizing uniformities associated to a (generalized) distance function `D` -in terms of the elements of the uniformity. -/ -theorem uniformity_dist_of_mem_uniformity [LinearOrder β] {U : Filter (α × α)} (z : β) - (D : α → α → β) (H : ∀ s, s ∈ U ↔ ∃ ε > z, ∀ {a b : α}, D a b < ε → (a, b) ∈ s) : - U = ⨅ ε > z, 𝓟 { p : α × α | D p.1 p.2 < ε } := - HasBasis.eq_biInf ⟨fun s => by simp only [H, subset_def, Prod.forall, mem_setOf]⟩ - -/-- `EDist α` means that `α` is equipped with an extended distance. -/ -@[ext] -class EDist (α : Type*) where - edist : α → α → ℝ≥0∞ - -export EDist (edist) - -/-- Creating a uniform space from an extended distance. -/ -def uniformSpaceOfEDist (edist : α → α → ℝ≥0∞) (edist_self : ∀ x : α, edist x x = 0) - (edist_comm : ∀ x y : α, edist x y = edist y x) - (edist_triangle : ∀ x y z : α, edist x z ≤ edist x y + edist y z) : UniformSpace α := - .ofFun edist edist_self edist_comm edist_triangle fun ε ε0 => - ⟨ε / 2, ENNReal.half_pos ε0.ne', fun _ h₁ _ h₂ => - (ENNReal.add_lt_add h₁ h₂).trans_eq (ENNReal.add_halves _)⟩ - --- the uniform structure is embedded in the emetric space structure --- to avoid instance diamond issues. See Note [forgetful inheritance]. -/-- Extended (pseudo) metric spaces, with an extended distance `edist` possibly taking the -value ∞ - -Each pseudo_emetric space induces a canonical `UniformSpace` and hence a canonical -`TopologicalSpace`. -This is enforced in the type class definition, by extending the `UniformSpace` structure. When -instantiating a `PseudoEMetricSpace` structure, the uniformity fields are not necessary, they -will be filled in by default. There is a default value for the uniformity, that can be substituted -in cases of interest, for instance when instantiating a `PseudoEMetricSpace` structure -on a product. - -Continuity of `edist` is proved in `Topology.Instances.ENNReal` --/ -class PseudoEMetricSpace (α : Type u) extends EDist α : Type u where - edist_self : ∀ x : α, edist x x = 0 - edist_comm : ∀ x y : α, edist x y = edist y x - edist_triangle : ∀ x y z : α, edist x z ≤ edist x y + edist y z - toUniformSpace : UniformSpace α := uniformSpaceOfEDist edist edist_self edist_comm edist_triangle - uniformity_edist : 𝓤 α = ⨅ ε > 0, 𝓟 { p : α × α | edist p.1 p.2 < ε } := by rfl - -attribute [instance] PseudoEMetricSpace.toUniformSpace - -/- Pseudoemetric spaces are less common than metric spaces. Therefore, we work in a dedicated -namespace, while notions associated to metric spaces are mostly in the root namespace. -/ - -/-- Two pseudo emetric space structures with the same edistance function coincide. -/ -@[ext] -protected theorem PseudoEMetricSpace.ext {α : Type*} {m m' : PseudoEMetricSpace α} - (h : m.toEDist = m'.toEDist) : m = m' := by - cases' m with ed _ _ _ U hU - cases' m' with ed' _ _ _ U' hU' - congr 1 - exact UniformSpace.ext (((show ed = ed' from h) ▸ hU).trans hU'.symm) +open scoped Uniformity Topology NNReal ENNReal Pointwise variable [PseudoEMetricSpace α] -export PseudoEMetricSpace (edist_self edist_comm edist_triangle) - -attribute [simp] edist_self - -/-- Triangle inequality for the extended distance -/ -theorem edist_triangle_left (x y z : α) : edist x y ≤ edist z x + edist z y := by - rw [edist_comm z]; apply edist_triangle - -theorem edist_triangle_right (x y z : α) : edist x y ≤ edist x z + edist y z := by - rw [edist_comm y]; apply edist_triangle - -theorem edist_congr_right {x y z : α} (h : edist x y = 0) : edist x z = edist y z := by - apply le_antisymm - · rw [← zero_add (edist y z), ← h] - apply edist_triangle - · rw [edist_comm] at h - rw [← zero_add (edist x z), ← h] - apply edist_triangle - -theorem edist_congr_left {x y z : α} (h : edist x y = 0) : edist z x = edist z y := by - rw [edist_comm z x, edist_comm z y] - apply edist_congr_right h - --- new theorem -theorem edist_congr {w x y z : α} (hl : edist w x = 0) (hr : edist y z = 0) : - edist w y = edist x z := - (edist_congr_right hl).trans (edist_congr_left hr) - -theorem edist_triangle4 (x y z t : α) : edist x t ≤ edist x y + edist y z + edist z t := - calc - edist x t ≤ edist x z + edist z t := edist_triangle x z t - _ ≤ edist x y + edist y z + edist z t := add_le_add_right (edist_triangle x y z) _ - /-- The triangle (polygon) inequality for sequences of points; `Finset.Ico` version. -/ theorem edist_le_Ico_sum_edist (f : ℕ → α) {m n} (h : m ≤ n) : edist (f m) (f n) ≤ ∑ i ∈ Finset.Ico m n, edist (f i) (f (i + 1)) := by @@ -159,138 +56,40 @@ theorem edist_le_range_sum_of_edist_le {f : ℕ → α} (n : ℕ) {d : ℕ → edist (f 0) (f n) ≤ ∑ i ∈ Finset.range n, d i := Nat.Ico_zero_eq_range ▸ edist_le_Ico_sum_of_edist_le (zero_le n) fun _ => hd -/-- Reformulation of the uniform structure in terms of the extended distance -/ -theorem uniformity_pseudoedist : 𝓤 α = ⨅ ε > 0, 𝓟 { p : α × α | edist p.1 p.2 < ε } := - PseudoEMetricSpace.uniformity_edist - -theorem uniformSpace_edist : - ‹PseudoEMetricSpace α›.toUniformSpace = - uniformSpaceOfEDist edist edist_self edist_comm edist_triangle := - UniformSpace.ext uniformity_pseudoedist - -theorem uniformity_basis_edist : - (𝓤 α).HasBasis (fun ε : ℝ≥0∞ => 0 < ε) fun ε => { p : α × α | edist p.1 p.2 < ε } := - (@uniformSpace_edist α _).symm ▸ UniformSpace.hasBasis_ofFun ⟨1, one_pos⟩ _ _ _ _ _ - -/-- Characterization of the elements of the uniformity in terms of the extended distance -/ -theorem mem_uniformity_edist {s : Set (α × α)} : - s ∈ 𝓤 α ↔ ∃ ε > 0, ∀ {a b : α}, edist a b < ε → (a, b) ∈ s := - uniformity_basis_edist.mem_uniformity_iff - -/-- Given `f : β → ℝ≥0∞`, if `f` sends `{i | p i}` to a set of positive numbers -accumulating to zero, then `f i`-neighborhoods of the diagonal form a basis of `𝓤 α`. - -For specific bases see `uniformity_basis_edist`, `uniformity_basis_edist'`, -`uniformity_basis_edist_nnreal`, and `uniformity_basis_edist_inv_nat`. -/ -protected theorem EMetric.mk_uniformity_basis {β : Type*} {p : β → Prop} {f : β → ℝ≥0∞} - (hf₀ : ∀ x, p x → 0 < f x) (hf : ∀ ε, 0 < ε → ∃ x, p x ∧ f x ≤ ε) : - (𝓤 α).HasBasis p fun x => { p : α × α | edist p.1 p.2 < f x } := by - refine ⟨fun s => uniformity_basis_edist.mem_iff.trans ?_⟩ - constructor - · rintro ⟨ε, ε₀, hε⟩ - rcases hf ε ε₀ with ⟨i, hi, H⟩ - exact ⟨i, hi, fun x hx => hε <| lt_of_lt_of_le hx.out H⟩ - · exact fun ⟨i, hi, H⟩ => ⟨f i, hf₀ i hi, H⟩ - -/-- Given `f : β → ℝ≥0∞`, if `f` sends `{i | p i}` to a set of positive numbers -accumulating to zero, then closed `f i`-neighborhoods of the diagonal form a basis of `𝓤 α`. - -For specific bases see `uniformity_basis_edist_le` and `uniformity_basis_edist_le'`. -/ -protected theorem EMetric.mk_uniformity_basis_le {β : Type*} {p : β → Prop} {f : β → ℝ≥0∞} - (hf₀ : ∀ x, p x → 0 < f x) (hf : ∀ ε, 0 < ε → ∃ x, p x ∧ f x ≤ ε) : - (𝓤 α).HasBasis p fun x => { p : α × α | edist p.1 p.2 ≤ f x } := by - refine ⟨fun s => uniformity_basis_edist.mem_iff.trans ?_⟩ - constructor - · rintro ⟨ε, ε₀, hε⟩ - rcases exists_between ε₀ with ⟨ε', hε'⟩ - rcases hf ε' hε'.1 with ⟨i, hi, H⟩ - exact ⟨i, hi, fun x hx => hε <| lt_of_le_of_lt (le_trans hx.out H) hε'.2⟩ - · exact fun ⟨i, hi, H⟩ => ⟨f i, hf₀ i hi, fun x hx => H (le_of_lt hx.out)⟩ - -theorem uniformity_basis_edist_le : - (𝓤 α).HasBasis (fun ε : ℝ≥0∞ => 0 < ε) fun ε => { p : α × α | edist p.1 p.2 ≤ ε } := - EMetric.mk_uniformity_basis_le (fun _ => id) fun ε ε₀ => ⟨ε, ε₀, le_refl ε⟩ - -theorem uniformity_basis_edist' (ε' : ℝ≥0∞) (hε' : 0 < ε') : - (𝓤 α).HasBasis (fun ε : ℝ≥0∞ => ε ∈ Ioo 0 ε') fun ε => { p : α × α | edist p.1 p.2 < ε } := - EMetric.mk_uniformity_basis (fun _ => And.left) fun ε ε₀ => - let ⟨δ, hδ⟩ := exists_between hε' - ⟨min ε δ, ⟨lt_min ε₀ hδ.1, lt_of_le_of_lt (min_le_right _ _) hδ.2⟩, min_le_left _ _⟩ - -theorem uniformity_basis_edist_le' (ε' : ℝ≥0∞) (hε' : 0 < ε') : - (𝓤 α).HasBasis (fun ε : ℝ≥0∞ => ε ∈ Ioo 0 ε') fun ε => { p : α × α | edist p.1 p.2 ≤ ε } := - EMetric.mk_uniformity_basis_le (fun _ => And.left) fun ε ε₀ => - let ⟨δ, hδ⟩ := exists_between hε' - ⟨min ε δ, ⟨lt_min ε₀ hδ.1, lt_of_le_of_lt (min_le_right _ _) hδ.2⟩, min_le_left _ _⟩ - -theorem uniformity_basis_edist_nnreal : - (𝓤 α).HasBasis (fun ε : ℝ≥0 => 0 < ε) fun ε => { p : α × α | edist p.1 p.2 < ε } := - EMetric.mk_uniformity_basis (fun _ => ENNReal.coe_pos.2) fun _ε ε₀ => - let ⟨δ, hδ⟩ := ENNReal.lt_iff_exists_nnreal_btwn.1 ε₀ - ⟨δ, ENNReal.coe_pos.1 hδ.1, le_of_lt hδ.2⟩ - -theorem uniformity_basis_edist_nnreal_le : - (𝓤 α).HasBasis (fun ε : ℝ≥0 => 0 < ε) fun ε => { p : α × α | edist p.1 p.2 ≤ ε } := - EMetric.mk_uniformity_basis_le (fun _ => ENNReal.coe_pos.2) fun _ε ε₀ => - let ⟨δ, hδ⟩ := ENNReal.lt_iff_exists_nnreal_btwn.1 ε₀ - ⟨δ, ENNReal.coe_pos.1 hδ.1, le_of_lt hδ.2⟩ - -theorem uniformity_basis_edist_inv_nat : - (𝓤 α).HasBasis (fun _ => True) fun n : ℕ => { p : α × α | edist p.1 p.2 < (↑n)⁻¹ } := - EMetric.mk_uniformity_basis (fun n _ ↦ ENNReal.inv_pos.2 <| ENNReal.natCast_ne_top n) fun _ε ε₀ ↦ - let ⟨n, hn⟩ := ENNReal.exists_inv_nat_lt (ne_of_gt ε₀) - ⟨n, trivial, le_of_lt hn⟩ - -theorem uniformity_basis_edist_inv_two_pow : - (𝓤 α).HasBasis (fun _ => True) fun n : ℕ => { p : α × α | edist p.1 p.2 < 2⁻¹ ^ n } := - EMetric.mk_uniformity_basis (fun _ _ => ENNReal.pow_pos (ENNReal.inv_pos.2 ENNReal.two_ne_top) _) - fun _ε ε₀ => - let ⟨n, hn⟩ := ENNReal.exists_inv_two_pow_lt (ne_of_gt ε₀) - ⟨n, trivial, le_of_lt hn⟩ - -/-- Fixed size neighborhoods of the diagonal belong to the uniform structure -/ -theorem edist_mem_uniformity {ε : ℝ≥0∞} (ε0 : 0 < ε) : { p : α × α | edist p.1 p.2 < ε } ∈ 𝓤 α := - mem_uniformity_edist.2 ⟨ε, ε0, id⟩ - namespace EMetric -instance (priority := 900) instIsCountablyGeneratedUniformity : IsCountablyGenerated (𝓤 α) := - isCountablyGenerated_of_seq ⟨_, uniformity_basis_edist_inv_nat.eq_iInf⟩ - --- Porting note: changed explicit/implicit -/-- ε-δ characterization of uniform continuity on a set for pseudoemetric spaces -/ -theorem uniformContinuousOn_iff [PseudoEMetricSpace β] {f : α → β} {s : Set α} : - UniformContinuousOn f s ↔ - ∀ ε > 0, ∃ δ > 0, ∀ {a}, a ∈ s → ∀ {b}, b ∈ s → edist a b < δ → edist (f a) (f b) < ε := - uniformity_basis_edist.uniformContinuousOn_iff uniformity_basis_edist - -/-- ε-δ characterization of uniform continuity on pseudoemetric spaces -/ -theorem uniformContinuous_iff [PseudoEMetricSpace β] {f : α → β} : - UniformContinuous f ↔ ∀ ε > 0, ∃ δ > 0, ∀ {a b : α}, edist a b < δ → edist (f a) (f b) < ε := - uniformity_basis_edist.uniformContinuous_iff uniformity_basis_edist - -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 α} : @@ -348,306 +147,15 @@ end EMetric open EMetric -/-- Auxiliary function to replace the uniformity on a pseudoemetric space with -a uniformity which is equal to the original one, but maybe not defeq. -This is useful if one wants to construct a pseudoemetric space with a -specified uniformity. See Note [forgetful inheritance] explaining why having definitionally -the right uniformity is often important. --/ -def PseudoEMetricSpace.replaceUniformity {α} [U : UniformSpace α] (m : PseudoEMetricSpace α) - (H : 𝓤[U] = 𝓤[PseudoEMetricSpace.toUniformSpace]) : PseudoEMetricSpace α where - edist := @edist _ m.toEDist - edist_self := edist_self - edist_comm := edist_comm - edist_triangle := edist_triangle - toUniformSpace := U - uniformity_edist := H.trans (@PseudoEMetricSpace.uniformity_edist α _) - -/-- The extended pseudometric induced by a function taking values in a pseudoemetric space. -/ -def PseudoEMetricSpace.induced {α β} (f : α → β) (m : PseudoEMetricSpace β) : - PseudoEMetricSpace α where - edist x y := edist (f x) (f y) - edist_self _ := edist_self _ - edist_comm _ _ := edist_comm _ _ - edist_triangle _ _ _ := edist_triangle _ _ _ - toUniformSpace := UniformSpace.comap f m.toUniformSpace - uniformity_edist := (uniformity_basis_edist.comap (Prod.map f f)).eq_biInf - -/-- Pseudoemetric space instance on subsets of pseudoemetric spaces -/ -instance {α : Type*} {p : α → Prop} [PseudoEMetricSpace α] : PseudoEMetricSpace (Subtype p) := - PseudoEMetricSpace.induced Subtype.val ‹_› - -/-- The extended pseudodistance on a subset of a pseudoemetric space is the restriction of -the original pseudodistance, by definition -/ -theorem Subtype.edist_eq {p : α → Prop} (x y : Subtype p) : edist x y = edist (x : α) y := rfl - -namespace MulOpposite - -/-- Pseudoemetric space instance on the multiplicative opposite of a pseudoemetric space. -/ -@[to_additive "Pseudoemetric space instance on the additive opposite of a pseudoemetric space."] -instance {α : Type*} [PseudoEMetricSpace α] : PseudoEMetricSpace αᵐᵒᵖ := - PseudoEMetricSpace.induced unop ‹_› - -@[to_additive] -theorem edist_unop (x y : αᵐᵒᵖ) : edist (unop x) (unop y) = edist x y := rfl - -@[to_additive] -theorem edist_op (x y : α) : edist (op x) (op y) = edist x y := rfl - -end MulOpposite - -section ULift - -instance : PseudoEMetricSpace (ULift α) := PseudoEMetricSpace.induced ULift.down ‹_› - -theorem ULift.edist_eq (x y : ULift α) : edist x y = edist x.down y.down := rfl - -@[simp] -theorem ULift.edist_up_up (x y : α) : edist (ULift.up x) (ULift.up y) = edist x y := rfl - -end ULift - -/-- The product of two pseudoemetric spaces, with the max distance, is an extended -pseudometric spaces. We make sure that the uniform structure thus constructed is the one -corresponding to the product of uniform spaces, to avoid diamond problems. -/ -instance Prod.pseudoEMetricSpaceMax [PseudoEMetricSpace β] : PseudoEMetricSpace (α × β) where - 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 := - 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 - simp [PseudoEMetricSpace.uniformity_edist, ← iInf_inf_eq, setOf_and] - toUniformSpace := inferInstance - -theorem Prod.edist_eq [PseudoEMetricSpace β] (x y : α × β) : - edist x y = max (edist x.1 y.1) (edist x.2 y.2) := - rfl - -section Pi - -open Finset - -variable {π : β → Type*} [Fintype β] - --- Porting note: reordered instances -instance [∀ b, EDist (π b)] : EDist (∀ b, π b) where - edist f g := Finset.sup univ fun b => edist (f b) (g b) - -theorem edist_pi_def [∀ b, EDist (π b)] (f g : ∀ b, π b) : - edist f g = Finset.sup univ fun b => edist (f b) (g b) := - rfl - -theorem edist_le_pi_edist [∀ b, EDist (π b)] (f g : ∀ b, π b) (b : β) : - edist (f b) (g b) ≤ edist f g := - le_sup (f := fun b => edist (f b) (g b)) (Finset.mem_univ b) - -theorem edist_pi_le_iff [∀ b, EDist (π b)] {f g : ∀ b, π b} {d : ℝ≥0∞} : - edist f g ≤ d ↔ ∀ b, edist (f b) (g b) ≤ d := - Finset.sup_le_iff.trans <| by simp only [Finset.mem_univ, forall_const] - -theorem edist_pi_const_le (a b : α) : (edist (fun _ : β => a) fun _ => b) ≤ edist a b := - edist_pi_le_iff.2 fun _ => le_rfl - -@[simp] -theorem edist_pi_const [Nonempty β] (a b : α) : (edist (fun _ : β => a) fun _ => b) = edist a b := - Finset.sup_const univ_nonempty (edist a b) - -/-- The product of a finite number of pseudoemetric spaces, with the max distance, is still -a pseudoemetric space. -This construction would also work for infinite products, but it would not give rise -to the product topology. Hence, we only formalize it in the good situation of finitely many -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) _) - (add_le_add (edist_le_pi_edist _ _ _) (edist_le_pi_edist _ _ _)) - toUniformSpace := Pi.uniformSpace _ - uniformity_edist := by - simp only [Pi.uniformity, PseudoEMetricSpace.uniformity_edist, comap_iInf, gt_iff_lt, - preimage_setOf_eq, comap_principal, edist_pi_def] - rw [iInf_comm]; congr; funext ε - rw [iInf_comm]; congr; funext εpos - simp [setOf_forall, εpos] - -end Pi - namespace EMetric variable {x y z : α} {ε ε₁ ε₂ : ℝ≥0∞} {s t : Set α} -/-- `EMetric.ball x ε` is the set of all points `y` with `edist y x < ε` -/ -def ball (x : α) (ε : ℝ≥0∞) : Set α := - { y | edist y x < ε } - -@[simp] theorem mem_ball : y ∈ ball x ε ↔ edist y x < ε := Iff.rfl - -theorem mem_ball' : y ∈ ball x ε ↔ edist x y < ε := by rw [edist_comm, mem_ball] - -/-- `EMetric.closedBall x ε` is the set of all points `y` with `edist y x ≤ ε` -/ -def closedBall (x : α) (ε : ℝ≥0∞) := - { y | edist y x ≤ ε } - -@[simp] theorem mem_closedBall : y ∈ closedBall x ε ↔ edist y x ≤ ε := Iff.rfl - -theorem mem_closedBall' : y ∈ closedBall x ε ↔ edist x y ≤ ε := by rw [edist_comm, mem_closedBall] - -@[simp] -theorem closedBall_top (x : α) : closedBall x ∞ = univ := - eq_univ_of_forall fun _ => mem_setOf.2 le_top - -theorem ball_subset_closedBall : ball x ε ⊆ closedBall x ε := fun _ h => le_of_lt h.out - -theorem pos_of_mem_ball (hy : y ∈ ball x ε) : 0 < ε := - lt_of_le_of_lt (zero_le _) hy - -theorem mem_ball_self (h : 0 < ε) : x ∈ ball x ε := by - rwa [mem_ball, edist_self] - -theorem mem_closedBall_self : x ∈ closedBall x ε := by - rw [mem_closedBall, edist_self]; apply zero_le - -theorem mem_ball_comm : x ∈ ball y ε ↔ y ∈ ball x ε := by rw [mem_ball', mem_ball] - -theorem mem_closedBall_comm : x ∈ closedBall y ε ↔ y ∈ closedBall x ε := by - rw [mem_closedBall', mem_closedBall] - -@[gcongr] -theorem ball_subset_ball (h : ε₁ ≤ ε₂) : ball x ε₁ ⊆ ball x ε₂ := fun _y (yx : _ < ε₁) => - lt_of_lt_of_le yx h - -@[gcongr] -theorem closedBall_subset_closedBall (h : ε₁ ≤ ε₂) : closedBall x ε₁ ⊆ closedBall x ε₂ := - fun _y (yx : _ ≤ ε₁) => le_trans yx h - -theorem ball_disjoint (h : ε₁ + ε₂ ≤ edist x y) : Disjoint (ball x ε₁) (ball y ε₂) := - Set.disjoint_left.mpr fun z h₁ h₂ => - (edist_triangle_left x y z).not_lt <| (ENNReal.add_lt_add h₁ h₂).trans_le h - -theorem ball_subset (h : edist x y + ε₁ ≤ ε₂) (h' : edist x y ≠ ∞) : ball x ε₁ ⊆ ball y ε₂ := - fun z zx => - calc - edist z y ≤ edist z x + edist x y := edist_triangle _ _ _ - _ = edist x y + edist z x := add_comm _ _ - _ < edist x y + ε₁ := ENNReal.add_lt_add_left h' zx - _ ≤ ε₂ := h - -theorem exists_ball_subset_ball (h : y ∈ ball x ε) : ∃ ε' > 0, ball y ε' ⊆ ball x ε := by - have : 0 < ε - edist y x := by simpa using h - refine ⟨ε - edist y x, this, ball_subset ?_ (ne_top_of_lt h)⟩ - exact (add_tsub_cancel_of_le (mem_ball.mp h).le).le - -theorem ball_eq_empty_iff : ball x ε = ∅ ↔ ε = 0 := - eq_empty_iff_forall_not_mem.trans - ⟨fun h => le_bot_iff.1 (le_of_not_gt fun ε0 => h _ (mem_ball_self ε0)), fun ε0 _ h => - not_lt_of_le (le_of_eq ε0) (pos_of_mem_ball h)⟩ - -theorem ordConnected_setOf_closedBall_subset (x : α) (s : Set α) : - OrdConnected { r | closedBall x r ⊆ s } := - ⟨fun _ _ _ h₁ _ h₂ => (closedBall_subset_closedBall h₂.2).trans h₁⟩ - -theorem ordConnected_setOf_ball_subset (x : α) (s : Set α) : OrdConnected { r | ball x r ⊆ s } := - ⟨fun _ _ _ h₁ _ h₂ => (ball_subset_ball h₂.2).trans h₁⟩ - -/-- Relation “two points are at a finite edistance” is an equivalence relation. -/ -def edistLtTopSetoid : Setoid α where - r x y := edist x y < ⊤ - iseqv := - ⟨fun x => by rw [edist_self]; exact ENNReal.coe_lt_top, - fun h => by rwa [edist_comm], fun hxy hyz => - lt_of_le_of_lt (edist_triangle _ _ _) (ENNReal.add_lt_top.2 ⟨hxy, hyz⟩)⟩ - -@[simp] -theorem ball_zero : ball x 0 = ∅ := by rw [EMetric.ball_eq_empty_iff] - -theorem nhds_basis_eball : (𝓝 x).HasBasis (fun ε : ℝ≥0∞ => 0 < ε) (ball x) := - nhds_basis_uniformity uniformity_basis_edist - -theorem nhdsWithin_basis_eball : (𝓝[s] x).HasBasis (fun ε : ℝ≥0∞ => 0 < ε) fun ε => ball x ε ∩ s := - nhdsWithin_hasBasis nhds_basis_eball s - -theorem nhds_basis_closed_eball : (𝓝 x).HasBasis (fun ε : ℝ≥0∞ => 0 < ε) (closedBall x) := - nhds_basis_uniformity uniformity_basis_edist_le - -theorem nhdsWithin_basis_closed_eball : - (𝓝[s] x).HasBasis (fun ε : ℝ≥0∞ => 0 < ε) fun ε => closedBall x ε ∩ s := - nhdsWithin_hasBasis nhds_basis_closed_eball s - -theorem nhds_eq : 𝓝 x = ⨅ ε > 0, 𝓟 (ball x ε) := - nhds_basis_eball.eq_biInf - -theorem mem_nhds_iff : s ∈ 𝓝 x ↔ ∃ ε > 0, ball x ε ⊆ s := - nhds_basis_eball.mem_iff - -theorem mem_nhdsWithin_iff : s ∈ 𝓝[t] x ↔ ∃ ε > 0, ball x ε ∩ t ⊆ s := - nhdsWithin_basis_eball.mem_iff - -section - -variable [PseudoEMetricSpace β] {f : α → β} - -theorem tendsto_nhdsWithin_nhdsWithin {t : Set β} {a b} : - Tendsto f (𝓝[s] a) (𝓝[t] b) ↔ - ∀ ε > 0, ∃ δ > 0, ∀ ⦃x⦄, x ∈ s → edist x a < δ → f x ∈ t ∧ edist (f x) b < ε := - (nhdsWithin_basis_eball.tendsto_iff nhdsWithin_basis_eball).trans <| - forall₂_congr fun ε _ => exists_congr fun δ => and_congr_right fun _ => - forall_congr' fun x => by simp; tauto - -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] - -theorem tendsto_nhds_nhds {a b} : - Tendsto f (𝓝 a) (𝓝 b) ↔ ∀ ε > 0, ∃ δ > 0, ∀ ⦃x⦄, edist x a < δ → edist (f x) b < ε := - nhds_basis_eball.tendsto_iff nhds_basis_eball - -end - -theorem isOpen_iff : IsOpen s ↔ ∀ x ∈ s, ∃ ε > 0, ball x ε ⊆ s := by - simp [isOpen_iff_nhds, mem_nhds_iff] - -theorem isOpen_ball : IsOpen (ball x ε) := - isOpen_iff.2 fun _ => exists_ball_subset_ball - -theorem isClosed_ball_top : IsClosed (ball x ⊤) := - isOpen_compl_iff.1 <| isOpen_iff.2 fun _y hy => - ⟨⊤, ENNReal.coe_lt_top, fun _z hzy hzx => - hy (edistLtTopSetoid.trans (edistLtTopSetoid.symm hzy) hzx)⟩ - -theorem ball_mem_nhds (x : α) {ε : ℝ≥0∞} (ε0 : 0 < ε) : ball x ε ∈ 𝓝 x := - isOpen_ball.mem_nhds (mem_ball_self ε0) - -theorem closedBall_mem_nhds (x : α) {ε : ℝ≥0∞} (ε0 : 0 < ε) : closedBall x ε ∈ 𝓝 x := - mem_of_superset (ball_mem_nhds x ε0) ball_subset_closedBall - -theorem ball_prod_same [PseudoEMetricSpace β] (x : α) (y : β) (r : ℝ≥0∞) : - ball x r ×ˢ ball y r = ball (x, y) r := - ext fun z => by simp [Prod.edist_eq] - -theorem closedBall_prod_same [PseudoEMetricSpace β] (x : α) (y : β) (r : ℝ≥0∞) : - closedBall x r ×ˢ closedBall y r = closedBall (x, y) r := - ext fun z => by simp [Prod.edist_eq] - -/-- ε-characterization of the closure in pseudoemetric spaces -/ -theorem mem_closure_iff : x ∈ closure s ↔ ∀ ε > 0, ∃ y ∈ s, edist x y < ε := - (mem_closure_iff_nhds_basis nhds_basis_eball).trans <| by simp only [mem_ball, edist_comm x] - -theorem tendsto_nhds {f : Filter β} {u : β → α} {a : α} : - Tendsto u f (𝓝 a) ↔ ∀ ε > 0, ∀ᶠ x in f, edist (u x) a < ε := - nhds_basis_eball.tendsto_right_iff - -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] - 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 -/ @@ -682,64 +190,9 @@ theorem totallyBounded_iff' {s : Set α} : section Compact --- Porting note (#11215): TODO: generalize to a uniform space with metrizable uniformity -/-- For a set `s` in a pseudo emetric space, if for every `ε > 0` there exists a countable -set that is `ε`-dense in `s`, then there exists a countable subset `t ⊆ s` that is dense in `s`. -/ -theorem subset_countable_closure_of_almost_dense_set (s : Set α) - (hs : ∀ ε > 0, ∃ t : Set α, t.Countable ∧ s ⊆ ⋃ x ∈ t, closedBall x ε) : - ∃ t, t ⊆ s ∧ t.Countable ∧ s ⊆ closure t := by - rcases s.eq_empty_or_nonempty with (rfl | ⟨x₀, hx₀⟩) - · exact ⟨∅, empty_subset _, countable_empty, empty_subset _⟩ - choose! T hTc hsT using fun n : ℕ => hs n⁻¹ (by simp) - have : ∀ r x, ∃ y ∈ s, closedBall x r ∩ s ⊆ closedBall y (r * 2) := fun r x => by - rcases (closedBall x r ∩ s).eq_empty_or_nonempty with (he | ⟨y, hxy, hys⟩) - · refine ⟨x₀, hx₀, ?_⟩ - rw [he] - exact empty_subset _ - · refine ⟨y, hys, fun z hz => ?_⟩ - calc - edist z y ≤ edist z x + edist y x := edist_triangle_right _ _ _ - _ ≤ r + r := add_le_add hz.1 hxy - _ = r * 2 := (mul_two r).symm - choose f hfs hf using this - refine - ⟨⋃ n : ℕ, f n⁻¹ '' T n, iUnion_subset fun n => image_subset_iff.2 fun z _ => hfs _ _, - countable_iUnion fun n => (hTc n).image _, ?_⟩ - refine fun x hx => mem_closure_iff.2 fun ε ε0 => ?_ - rcases ENNReal.exists_inv_nat_lt (ENNReal.half_pos ε0.lt.ne').ne' with ⟨n, hn⟩ - rcases mem_iUnion₂.1 (hsT n hx) with ⟨y, hyn, hyx⟩ - refine ⟨f n⁻¹ y, mem_iUnion.2 ⟨n, mem_image_of_mem _ hyn⟩, ?_⟩ - calc - edist x (f n⁻¹ y) ≤ (n : ℝ≥0∞)⁻¹ * 2 := hf _ _ ⟨hyx, hx⟩ - _ < ε := ENNReal.mul_lt_of_lt_div hn - -open TopologicalSpace in -/-- If a set `s` is separable in a (pseudo extended) metric space, then it admits a countable dense -subset. This is not obvious, as the countable set whose closure covers `s` given by the definition -of separability does not need in general to be contained in `s`. -/ -theorem _root_.TopologicalSpace.IsSeparable.exists_countable_dense_subset - {s : Set α} (hs : IsSeparable s) : ∃ t, t ⊆ s ∧ t.Countable ∧ s ⊆ closure t := by - have : ∀ ε > 0, ∃ t : Set α, t.Countable ∧ s ⊆ ⋃ x ∈ t, closedBall x ε := fun ε ε0 => by - rcases hs with ⟨t, htc, hst⟩ - refine ⟨t, htc, hst.trans fun x hx => ?_⟩ - rcases mem_closure_iff.1 hx ε ε0 with ⟨y, hyt, hxy⟩ - exact mem_iUnion₂.2 ⟨y, hyt, mem_closedBall.2 hxy.le⟩ - exact subset_countable_closure_of_almost_dense_set _ this - -open TopologicalSpace in -/-- If a set `s` is separable, then the corresponding subtype is separable in a (pseudo extended) -metric space. This is not obvious, as the countable set whose closure covers `s` does not need in -general to be contained in `s`. -/ -theorem _root_.TopologicalSpace.IsSeparable.separableSpace {s : Set α} (hs : IsSeparable s) : - SeparableSpace s := by - 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] - -- Porting note (#11215): TODO: generalize to metrizable spaces /-- A compact set in a pseudo emetric space is separable, i.e., it is a subset of the closure of a -countable set. -/ +countable set. -/ theorem subset_countable_closure_of_compact {s : Set α} (hs : IsCompact s) : ∃ t, t ⊆ s ∧ t.Countable ∧ s ⊆ closure t := by refine subset_countable_closure_of_almost_dense_set s fun ε hε => ?_ @@ -777,153 +230,10 @@ theorem secondCountable_of_almost_dense_set end SecondCountable -section Diam - -/-- The diameter of a set in a pseudoemetric space, named `EMetric.diam` -/ -noncomputable def diam (s : Set α) := - ⨆ (x ∈ s) (y ∈ s), edist x y - -theorem diam_eq_sSup (s : Set α) : diam s = sSup (image2 edist s s) := sSup_image2.symm - -theorem diam_le_iff {d : ℝ≥0∞} : diam s ≤ d ↔ ∀ x ∈ s, ∀ y ∈ s, edist x y ≤ d := by - simp only [diam, iSup_le_iff] - -theorem diam_image_le_iff {d : ℝ≥0∞} {f : β → α} {s : Set β} : - diam (f '' s) ≤ d ↔ ∀ x ∈ s, ∀ y ∈ s, edist (f x) (f y) ≤ d := by - simp only [diam_le_iff, forall_mem_image] - -theorem edist_le_of_diam_le {d} (hx : x ∈ s) (hy : y ∈ s) (hd : diam s ≤ d) : edist x y ≤ d := - diam_le_iff.1 hd x hx y hy - -/-- If two points belong to some set, their edistance is bounded by the diameter of the set -/ -theorem edist_le_diam_of_mem (hx : x ∈ s) (hy : y ∈ s) : edist x y ≤ diam s := - edist_le_of_diam_le hx hy le_rfl - -/-- If the distance between any two points in a set is bounded by some constant, this constant -bounds the diameter. -/ -theorem diam_le {d : ℝ≥0∞} (h : ∀ x ∈ s, ∀ y ∈ s, edist x y ≤ d) : diam s ≤ d := - diam_le_iff.2 h - -/-- The diameter of a subsingleton vanishes. -/ -theorem diam_subsingleton (hs : s.Subsingleton) : diam s = 0 := - nonpos_iff_eq_zero.1 <| diam_le fun _x hx y hy => (hs hx hy).symm ▸ edist_self y ▸ le_rfl - -/-- The diameter of the empty set vanishes -/ -@[simp] -theorem diam_empty : diam (∅ : Set α) = 0 := - diam_subsingleton subsingleton_empty - -/-- The diameter of a singleton vanishes -/ -@[simp] -theorem diam_singleton : diam ({x} : Set α) = 0 := - diam_subsingleton subsingleton_singleton - -@[to_additive (attr := simp)] -theorem diam_one [One α] : diam (1 : Set α) = 0 := - diam_singleton - -theorem diam_iUnion_mem_option {ι : Type*} (o : Option ι) (s : ι → Set α) : - diam (⋃ i ∈ o, s i) = ⨆ i ∈ o, diam (s i) := by cases o <;> simp - -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] - -theorem diam_pair : diam ({x, y} : Set α) = edist x y := by - simp only [iSup_singleton, diam_insert, diam_singleton, ENNReal.max_zero_right] - -theorem diam_triple : diam ({x, y, z} : Set α) = max (max (edist x y) (edist x z)) (edist y z) := by - simp only [diam_insert, iSup_insert, iSup_singleton, diam_singleton, ENNReal.max_zero_right, - ENNReal.sup_eq_max] - -/-- The diameter is monotonous with respect to inclusion -/ -@[gcongr] -theorem diam_mono {s t : Set α} (h : s ⊆ t) : diam s ≤ diam t := - diam_le fun _x hx _y hy => edist_le_diam_of_mem (h hx) (h hy) - -/-- The diameter of a union is controlled by the diameter of the sets, and the edistance -between two points in the sets. -/ -theorem diam_union {t : Set α} (xs : x ∈ s) (yt : y ∈ t) : - diam (s ∪ t) ≤ diam s + edist x y + diam t := by - have A : ∀ a ∈ s, ∀ b ∈ t, edist a b ≤ diam s + edist x y + diam t := fun a ha b hb => - calc - edist a b ≤ edist a x + edist x y + edist y b := edist_triangle4 _ _ _ _ - _ ≤ diam s + edist x y + diam t := - add_le_add (add_le_add (edist_le_diam_of_mem ha xs) le_rfl) (edist_le_diam_of_mem yt hb) - refine diam_le fun a ha b hb => ?_ - cases' (mem_union _ _ _).1 ha with h'a h'a <;> cases' (mem_union _ _ _).1 hb with h'b h'b - · calc - edist a b ≤ diam s := edist_le_diam_of_mem h'a h'b - _ ≤ diam s + (edist x y + diam t) := le_self_add - _ = diam s + edist x y + diam t := (add_assoc _ _ _).symm - · exact A a h'a b h'b - · have Z := A b h'b a h'a - rwa [edist_comm] at Z - · calc - edist a b ≤ diam t := edist_le_diam_of_mem h'a h'b - _ ≤ diam s + edist x y + diam t := le_add_self - -theorem diam_union' {t : Set α} (h : (s ∩ t).Nonempty) : diam (s ∪ t) ≤ diam s + diam t := by - let ⟨x, ⟨xs, xt⟩⟩ := h - simpa using diam_union xs xt - -theorem diam_closedBall {r : ℝ≥0∞} : diam (closedBall x r) ≤ 2 * r := - diam_le fun a ha b hb => - calc - edist a b ≤ edist a x + edist b x := edist_triangle_right _ _ _ - _ ≤ r + r := add_le_add ha hb - _ = 2 * r := (two_mul r).symm - -theorem diam_ball {r : ℝ≥0∞} : diam (ball x r) ≤ 2 * r := - le_trans (diam_mono ball_subset_closedBall) diam_closedBall - -theorem diam_pi_le_of_le {π : β → Type*} [Fintype β] [∀ b, PseudoEMetricSpace (π b)] - {s : ∀ b : β, Set (π b)} {c : ℝ≥0∞} (h : ∀ b, diam (s b) ≤ c) : diam (Set.pi univ s) ≤ c := by - refine diam_le fun x hx y hy => edist_pi_le_iff.mpr ?_ - rw [mem_univ_pi] at hx hy - exact fun b => diam_le_iff.1 (h b) (x b) (hx b) (y b) (hy b) - -end Diam - end EMetric ---namespace -/-- We now define `EMetricSpace`, extending `PseudoEMetricSpace`. -/ -class EMetricSpace (α : Type u) extends PseudoEMetricSpace α : Type u where - eq_of_edist_eq_zero : ∀ {x y : α}, edist x y = 0 → x = y - -@[ext] -protected theorem EMetricSpace.ext - {α : Type*} {m m' : EMetricSpace α} (h : m.toEDist = m'.toEDist) : m = m' := by - cases m - cases m' - congr - ext1 - assumption - variable {γ : Type w} [EMetricSpace γ] -export EMetricSpace (eq_of_edist_eq_zero) - -/-- Characterize the equality of points by the vanishing of their extended distance -/ -@[simp] -theorem edist_eq_zero {x y : γ} : edist x y = 0 ↔ x = y := - ⟨eq_of_edist_eq_zero, fun h => h ▸ edist_self _⟩ - -@[simp] -theorem zero_eq_edist {x y : γ} : 0 = edist x y ↔ x = y := eq_comm.trans edist_eq_zero - -theorem edist_le_zero {x y : γ} : edist x y ≤ 0 ↔ x = y := - nonpos_iff_eq_zero.trans edist_eq_zero - -@[simp] -theorem edist_pos {x y : γ} : 0 < edist x y ↔ x ≠ y := by simp [← not_le] - -/-- Two points coincide if their distance is `< ε` for all positive ε -/ -theorem eq_of_forall_edist_le {x y : γ} (h : ∀ ε > 0, edist x y ≤ ε) : x = y := - eq_of_edist_eq_zero (eq_of_le_of_forall_le_of_dense bot_le h) - -- see Note [lower instance priority] /-- An emetric space is separated -/ instance (priority := 100) EMetricSpace.instT0Space : T0Space γ where @@ -931,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`; @@ -945,66 +258,12 @@ abbrev EMetricSpace.ofT0PseudoEMetricSpace (α : Type*) [PseudoEMetricSpace α] { ‹PseudoEMetricSpace α› with eq_of_edist_eq_zero := fun h => (EMetric.inseparable_iff.2 h).eq } -/-- Auxiliary function to replace the uniformity on an emetric space with -a uniformity which is equal to the original one, but maybe not defeq. -This is useful if one wants to construct an emetric space with a -specified uniformity. See Note [forgetful inheritance] explaining why having definitionally -the right uniformity is often important. --/ -def EMetricSpace.replaceUniformity {γ} [U : UniformSpace γ] (m : EMetricSpace γ) - (H : 𝓤[U] = 𝓤[PseudoEMetricSpace.toUniformSpace]) : EMetricSpace γ where - edist := @edist _ m.toEDist - edist_self := edist_self - eq_of_edist_eq_zero := @eq_of_edist_eq_zero _ _ - edist_comm := edist_comm - edist_triangle := edist_triangle - toUniformSpace := U - uniformity_edist := H.trans (@PseudoEMetricSpace.uniformity_edist γ _) - -/-- The extended metric induced by an injective function taking values in an emetric space. -/ -def EMetricSpace.induced {γ β} (f : γ → β) (hf : Function.Injective f) (m : EMetricSpace β) : - EMetricSpace γ := - { PseudoEMetricSpace.induced f m.toPseudoEMetricSpace with - eq_of_edist_eq_zero := fun h => hf (edist_eq_zero.1 h) } - -/-- EMetric space instance on subsets of emetric spaces -/ -instance {α : Type*} {p : α → Prop} [EMetricSpace α] : EMetricSpace (Subtype p) := - EMetricSpace.induced Subtype.val Subtype.coe_injective ‹_› - -/-- EMetric space instance on the multiplicative opposite of an emetric space. -/ -@[to_additive "EMetric space instance on the additive opposite of an emetric space."] -instance {α : Type*} [EMetricSpace α] : EMetricSpace αᵐᵒᵖ := - EMetricSpace.induced MulOpposite.unop MulOpposite.unop_injective ‹_› - -instance {α : Type*} [EMetricSpace α] : EMetricSpace (ULift α) := - EMetricSpace.induced ULift.down ULift.down_injective ‹_› - /-- The product of two emetric spaces, with the max distance, is an extended metric spaces. We make sure that the uniform structure thus constructed is the one corresponding to the product of uniform spaces, to avoid diamond problems. -/ instance Prod.emetricSpaceMax [EMetricSpace β] : EMetricSpace (γ × β) := .ofT0PseudoEMetricSpace _ -/-- Reformulation of the uniform structure in terms of the extended distance -/ -theorem uniformity_edist : 𝓤 γ = ⨅ ε > 0, 𝓟 { p : γ × γ | edist p.1 p.2 < ε } := - PseudoEMetricSpace.uniformity_edist - -section Pi - -open Finset - -variable {π : β → Type*} [Fintype β] - -/-- The product of a finite number of emetric spaces, with the max distance, is still -an emetric space. -This construction would also work for infinite products, but it would not give rise -to the product topology. Hence, we only formalize it in the good situation of finitely many -spaces. -/ -instance emetricSpacePi [∀ b, EMetricSpace (π b)] : EMetricSpace (∀ b, π b) := - .ofT0PseudoEMetricSpace _ - -end Pi - namespace EMetric /-- A compact set in an emetric space is separable, i.e., it is the closure of a countable set. -/ @@ -1013,21 +272,6 @@ theorem countable_closure_of_compact {s : Set γ} (hs : IsCompact s) : rcases subset_countable_closure_of_compact hs with ⟨t, hts, htc, hsub⟩ exact ⟨t, hts, htc, hsub.antisymm (closure_minimal hts hs.isClosed)⟩ -section Diam - -variable {s : Set γ} - -theorem diam_eq_zero_iff : diam s = 0 ↔ s.Subsingleton := - ⟨fun h _x hx _y hy => edist_le_zero.1 <| h ▸ edist_le_diam_of_mem hx hy, diam_subsingleton⟩ - -theorem diam_pos_iff : 0 < diam s ↔ s.Nontrivial := by - simp only [pos_iff_ne_zero, Ne, diam_eq_zero_iff, Set.not_subsingleton_iff] - -theorem diam_pos_iff' : 0 < diam s ↔ ∃ x ∈ s, ∃ y ∈ s, x ≠ y := by - simp only [diam_pos_iff, Set.Nontrivial, exists_prop] - -end Diam - end EMetric /-! @@ -1051,70 +295,3 @@ instance [PseudoEMetricSpace X] : EMetricSpace (SeparationQuotient X) := toUniformSpace := inferInstance, uniformity_edist := comap_injective (surjective_mk.prodMap surjective_mk) <| by simp [comap_mk_uniformity, PseudoEMetricSpace.uniformity_edist] } _ - -/-! -### `Additive`, `Multiplicative` - -The distance on those type synonyms is inherited without change. --/ - - -open Additive Multiplicative - -section - -variable [EDist X] - -instance : EDist (Additive X) := ‹EDist X› -instance : EDist (Multiplicative X) := ‹EDist X› - -@[simp] -theorem edist_ofMul (a b : X) : edist (ofMul a) (ofMul b) = edist a b := - rfl - -@[simp] -theorem edist_ofAdd (a b : X) : edist (ofAdd a) (ofAdd b) = edist a b := - rfl - -@[simp] -theorem edist_toMul (a b : Additive X) : edist (toMul a) (toMul b) = edist a b := - rfl - -@[simp] -theorem edist_toAdd (a b : Multiplicative X) : edist (toAdd a) (toAdd b) = edist a b := - rfl - -end - -instance [PseudoEMetricSpace X] : PseudoEMetricSpace (Additive X) := ‹PseudoEMetricSpace X› -instance [PseudoEMetricSpace X] : PseudoEMetricSpace (Multiplicative X) := ‹PseudoEMetricSpace X› -instance [EMetricSpace X] : EMetricSpace (Additive X) := ‹EMetricSpace X› -instance [EMetricSpace X] : EMetricSpace (Multiplicative X) := ‹EMetricSpace X› - -/-! -### Order dual - -The distance on this type synonym is inherited without change. --/ - - -open OrderDual - -section - -variable [EDist X] - -instance : EDist Xᵒᵈ := ‹EDist X› - -@[simp] -theorem edist_toDual (a b : X) : edist (toDual a) (toDual b) = edist a b := - rfl - -@[simp] -theorem edist_ofDual (a b : Xᵒᵈ) : edist (ofDual a) (ofDual b) = edist a b := - rfl - -end - -instance [PseudoEMetricSpace X] : PseudoEMetricSpace Xᵒᵈ := ‹PseudoEMetricSpace X› -instance [EMetricSpace X] : EMetricSpace Xᵒᵈ := ‹EMetricSpace X› diff --git a/Mathlib/Topology/EMetricSpace/Defs.lean b/Mathlib/Topology/EMetricSpace/Defs.lean new file mode 100644 index 0000000000000..2b6096cad74f3 --- /dev/null +++ b/Mathlib/Topology/EMetricSpace/Defs.lean @@ -0,0 +1,698 @@ +/- +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.Inv +import Mathlib.Topology.UniformSpace.OfFun + +/-! +# Extended metric spaces + +This file is devoted to the definition and study of `EMetricSpace`s, i.e., metric +spaces in which the distance is allowed to take the value ∞. This extended distance is +called `edist`, and takes values in `ℝ≥0∞`. + +Many definitions and theorems expected on emetric spaces are already introduced on uniform spaces +and topological spaces. For example: open and closed sets, compactness, completeness, continuity and +uniform continuity. + +The class `EMetricSpace` therefore extends `UniformSpace` (and `TopologicalSpace`). + +Since a lot of elementary properties don't require `eq_of_edist_eq_zero` we start setting up the +theory of `PseudoEMetricSpace`, where we don't require `edist x y = 0 → x = y` and we specialize +to `EMetricSpace` at the end. +-/ + +assert_not_exists Nat.instLocallyFiniteOrder +assert_not_exists IsUniformEmbedding +assert_not_exists TendstoUniformlyOnFilter + +open Set Filter + +universe u v w + +variable {α : Type u} {β : Type v} {X : Type*} + +/-- Characterizing uniformities associated to a (generalized) distance function `D` +in terms of the elements of the uniformity. -/ +theorem uniformity_dist_of_mem_uniformity [LinearOrder β] {U : Filter (α × α)} (z : β) + (D : α → α → β) (H : ∀ s, s ∈ U ↔ ∃ ε > z, ∀ {a b : α}, D a b < ε → (a, b) ∈ s) : + U = ⨅ ε > z, 𝓟 { p : α × α | D p.1 p.2 < ε } := + HasBasis.eq_biInf ⟨fun s => by simp only [H, subset_def, Prod.forall, mem_setOf]⟩ + +open scoped Uniformity Topology Filter NNReal ENNReal Pointwise + +/-- `EDist α` means that `α` is equipped with an extended distance. -/ +@[ext] +class EDist (α : Type*) where + edist : α → α → ℝ≥0∞ + +export EDist (edist) + +/-- Creating a uniform space from an extended distance. -/ +def uniformSpaceOfEDist (edist : α → α → ℝ≥0∞) (edist_self : ∀ x : α, edist x x = 0) + (edist_comm : ∀ x y : α, edist x y = edist y x) + (edist_triangle : ∀ x y z : α, edist x z ≤ edist x y + edist y z) : UniformSpace α := + .ofFun edist edist_self edist_comm edist_triangle fun ε ε0 => + ⟨ε / 2, ENNReal.half_pos ε0.ne', fun _ h₁ _ h₂ => + (ENNReal.add_lt_add h₁ h₂).trans_eq (ENNReal.add_halves _)⟩ + +-- the uniform structure is embedded in the emetric space structure +-- to avoid instance diamond issues. See Note [forgetful inheritance]. +/-- Extended (pseudo) metric spaces, with an extended distance `edist` possibly taking the +value ∞ + +Each pseudo_emetric space induces a canonical `UniformSpace` and hence a canonical +`TopologicalSpace`. +This is enforced in the type class definition, by extending the `UniformSpace` structure. When +instantiating a `PseudoEMetricSpace` structure, the uniformity fields are not necessary, they +will be filled in by default. There is a default value for the uniformity, that can be substituted +in cases of interest, for instance when instantiating a `PseudoEMetricSpace` structure +on a product. + +Continuity of `edist` is proved in `Topology.Instances.ENNReal` +-/ +class PseudoEMetricSpace (α : Type u) extends EDist α : Type u where + edist_self : ∀ x : α, edist x x = 0 + edist_comm : ∀ x y : α, edist x y = edist y x + edist_triangle : ∀ x y z : α, edist x z ≤ edist x y + edist y z + toUniformSpace : UniformSpace α := uniformSpaceOfEDist edist edist_self edist_comm edist_triangle + uniformity_edist : 𝓤 α = ⨅ ε > 0, 𝓟 { p : α × α | edist p.1 p.2 < ε } := by rfl + +attribute [instance] PseudoEMetricSpace.toUniformSpace + +/- Pseudoemetric spaces are less common than metric spaces. Therefore, we work in a dedicated +namespace, while notions associated to metric spaces are mostly in the root namespace. -/ + +/-- Two pseudo emetric space structures with the same edistance function coincide. -/ +@[ext] +protected theorem PseudoEMetricSpace.ext {α : Type*} {m m' : PseudoEMetricSpace α} + (h : m.toEDist = m'.toEDist) : m = m' := by + cases' m with ed _ _ _ U hU + cases' m' with ed' _ _ _ U' hU' + congr 1 + exact UniformSpace.ext (((show ed = ed' from h) ▸ hU).trans hU'.symm) + +variable [PseudoEMetricSpace α] + +export PseudoEMetricSpace (edist_self edist_comm edist_triangle) + +attribute [simp] edist_self + +/-- Triangle inequality for the extended distance -/ +theorem edist_triangle_left (x y z : α) : edist x y ≤ edist z x + edist z y := by + rw [edist_comm z]; apply edist_triangle + +theorem edist_triangle_right (x y z : α) : edist x y ≤ edist x z + edist y z := by + rw [edist_comm y]; apply edist_triangle + +theorem edist_congr_right {x y z : α} (h : edist x y = 0) : edist x z = edist y z := by + apply le_antisymm + · rw [← zero_add (edist y z), ← h] + apply edist_triangle + · rw [edist_comm] at h + rw [← zero_add (edist x z), ← h] + apply edist_triangle + +theorem edist_congr_left {x y z : α} (h : edist x y = 0) : edist z x = edist z y := by + rw [edist_comm z x, edist_comm z y] + apply edist_congr_right h + +-- new theorem +theorem edist_congr {w x y z : α} (hl : edist w x = 0) (hr : edist y z = 0) : + edist w y = edist x z := + (edist_congr_right hl).trans (edist_congr_left hr) + +theorem edist_triangle4 (x y z t : α) : edist x t ≤ edist x y + edist y z + edist z t := + calc + edist x t ≤ edist x z + edist z t := edist_triangle x z t + _ ≤ edist x y + edist y z + edist z t := add_le_add_right (edist_triangle x y z) _ + +/-- Reformulation of the uniform structure in terms of the extended distance -/ +theorem uniformity_pseudoedist : 𝓤 α = ⨅ ε > 0, 𝓟 { p : α × α | edist p.1 p.2 < ε } := + PseudoEMetricSpace.uniformity_edist + +theorem uniformSpace_edist : + ‹PseudoEMetricSpace α›.toUniformSpace = + uniformSpaceOfEDist edist edist_self edist_comm edist_triangle := + UniformSpace.ext uniformity_pseudoedist + +theorem uniformity_basis_edist : + (𝓤 α).HasBasis (fun ε : ℝ≥0∞ => 0 < ε) fun ε => { p : α × α | edist p.1 p.2 < ε } := + (@uniformSpace_edist α _).symm ▸ UniformSpace.hasBasis_ofFun ⟨1, one_pos⟩ _ _ _ _ _ + +/-- Characterization of the elements of the uniformity in terms of the extended distance -/ +theorem mem_uniformity_edist {s : Set (α × α)} : + s ∈ 𝓤 α ↔ ∃ ε > 0, ∀ {a b : α}, edist a b < ε → (a, b) ∈ s := + uniformity_basis_edist.mem_uniformity_iff + +/-- Given `f : β → ℝ≥0∞`, if `f` sends `{i | p i}` to a set of positive numbers +accumulating to zero, then `f i`-neighborhoods of the diagonal form a basis of `𝓤 α`. + +For specific bases see `uniformity_basis_edist`, `uniformity_basis_edist'`, +`uniformity_basis_edist_nnreal`, and `uniformity_basis_edist_inv_nat`. -/ +protected theorem EMetric.mk_uniformity_basis {β : Type*} {p : β → Prop} {f : β → ℝ≥0∞} + (hf₀ : ∀ x, p x → 0 < f x) (hf : ∀ ε, 0 < ε → ∃ x, p x ∧ f x ≤ ε) : + (𝓤 α).HasBasis p fun x => { p : α × α | edist p.1 p.2 < f x } := by + refine ⟨fun s => uniformity_basis_edist.mem_iff.trans ?_⟩ + constructor + · rintro ⟨ε, ε₀, hε⟩ + rcases hf ε ε₀ with ⟨i, hi, H⟩ + exact ⟨i, hi, fun x hx => hε <| lt_of_lt_of_le hx.out H⟩ + · exact fun ⟨i, hi, H⟩ => ⟨f i, hf₀ i hi, H⟩ + +/-- Given `f : β → ℝ≥0∞`, if `f` sends `{i | p i}` to a set of positive numbers +accumulating to zero, then closed `f i`-neighborhoods of the diagonal form a basis of `𝓤 α`. + +For specific bases see `uniformity_basis_edist_le` and `uniformity_basis_edist_le'`. -/ +protected theorem EMetric.mk_uniformity_basis_le {β : Type*} {p : β → Prop} {f : β → ℝ≥0∞} + (hf₀ : ∀ x, p x → 0 < f x) (hf : ∀ ε, 0 < ε → ∃ x, p x ∧ f x ≤ ε) : + (𝓤 α).HasBasis p fun x => { p : α × α | edist p.1 p.2 ≤ f x } := by + refine ⟨fun s => uniformity_basis_edist.mem_iff.trans ?_⟩ + constructor + · rintro ⟨ε, ε₀, hε⟩ + rcases exists_between ε₀ with ⟨ε', hε'⟩ + rcases hf ε' hε'.1 with ⟨i, hi, H⟩ + exact ⟨i, hi, fun x hx => hε <| lt_of_le_of_lt (le_trans hx.out H) hε'.2⟩ + · exact fun ⟨i, hi, H⟩ => ⟨f i, hf₀ i hi, fun x hx => H (le_of_lt hx.out)⟩ + +theorem uniformity_basis_edist_le : + (𝓤 α).HasBasis (fun ε : ℝ≥0∞ => 0 < ε) fun ε => { p : α × α | edist p.1 p.2 ≤ ε } := + EMetric.mk_uniformity_basis_le (fun _ => id) fun ε ε₀ => ⟨ε, ε₀, le_refl ε⟩ + +theorem uniformity_basis_edist' (ε' : ℝ≥0∞) (hε' : 0 < ε') : + (𝓤 α).HasBasis (fun ε : ℝ≥0∞ => ε ∈ Ioo 0 ε') fun ε => { p : α × α | edist p.1 p.2 < ε } := + EMetric.mk_uniformity_basis (fun _ => And.left) fun ε ε₀ => + let ⟨δ, hδ⟩ := exists_between hε' + ⟨min ε δ, ⟨lt_min ε₀ hδ.1, lt_of_le_of_lt (min_le_right _ _) hδ.2⟩, min_le_left _ _⟩ + +theorem uniformity_basis_edist_le' (ε' : ℝ≥0∞) (hε' : 0 < ε') : + (𝓤 α).HasBasis (fun ε : ℝ≥0∞ => ε ∈ Ioo 0 ε') fun ε => { p : α × α | edist p.1 p.2 ≤ ε } := + EMetric.mk_uniformity_basis_le (fun _ => And.left) fun ε ε₀ => + let ⟨δ, hδ⟩ := exists_between hε' + ⟨min ε δ, ⟨lt_min ε₀ hδ.1, lt_of_le_of_lt (min_le_right _ _) hδ.2⟩, min_le_left _ _⟩ + +theorem uniformity_basis_edist_nnreal : + (𝓤 α).HasBasis (fun ε : ℝ≥0 => 0 < ε) fun ε => { p : α × α | edist p.1 p.2 < ε } := + EMetric.mk_uniformity_basis (fun _ => ENNReal.coe_pos.2) fun _ε ε₀ => + let ⟨δ, hδ⟩ := ENNReal.lt_iff_exists_nnreal_btwn.1 ε₀ + ⟨δ, ENNReal.coe_pos.1 hδ.1, le_of_lt hδ.2⟩ + +theorem uniformity_basis_edist_nnreal_le : + (𝓤 α).HasBasis (fun ε : ℝ≥0 => 0 < ε) fun ε => { p : α × α | edist p.1 p.2 ≤ ε } := + EMetric.mk_uniformity_basis_le (fun _ => ENNReal.coe_pos.2) fun _ε ε₀ => + let ⟨δ, hδ⟩ := ENNReal.lt_iff_exists_nnreal_btwn.1 ε₀ + ⟨δ, ENNReal.coe_pos.1 hδ.1, le_of_lt hδ.2⟩ + +theorem uniformity_basis_edist_inv_nat : + (𝓤 α).HasBasis (fun _ => True) fun n : ℕ => { p : α × α | edist p.1 p.2 < (↑n)⁻¹ } := + EMetric.mk_uniformity_basis (fun n _ ↦ ENNReal.inv_pos.2 <| ENNReal.natCast_ne_top n) fun _ε ε₀ ↦ + let ⟨n, hn⟩ := ENNReal.exists_inv_nat_lt (ne_of_gt ε₀) + ⟨n, trivial, le_of_lt hn⟩ + +theorem uniformity_basis_edist_inv_two_pow : + (𝓤 α).HasBasis (fun _ => True) fun n : ℕ => { p : α × α | edist p.1 p.2 < 2⁻¹ ^ n } := + EMetric.mk_uniformity_basis (fun _ _ => ENNReal.pow_pos (ENNReal.inv_pos.2 ENNReal.two_ne_top) _) + fun _ε ε₀ => + let ⟨n, hn⟩ := ENNReal.exists_inv_two_pow_lt (ne_of_gt ε₀) + ⟨n, trivial, le_of_lt hn⟩ + +/-- Fixed size neighborhoods of the diagonal belong to the uniform structure -/ +theorem edist_mem_uniformity {ε : ℝ≥0∞} (ε0 : 0 < ε) : { p : α × α | edist p.1 p.2 < ε } ∈ 𝓤 α := + mem_uniformity_edist.2 ⟨ε, ε0, id⟩ + +namespace EMetric + +instance (priority := 900) instIsCountablyGeneratedUniformity : IsCountablyGenerated (𝓤 α) := + isCountablyGenerated_of_seq ⟨_, uniformity_basis_edist_inv_nat.eq_iInf⟩ + +-- Porting note: changed explicit/implicit +/-- ε-δ characterization of uniform continuity on a set for pseudoemetric spaces -/ +theorem uniformContinuousOn_iff [PseudoEMetricSpace β] {f : α → β} {s : Set α} : + UniformContinuousOn f s ↔ + ∀ ε > 0, ∃ δ > 0, ∀ {a}, a ∈ s → ∀ {b}, b ∈ s → edist a b < δ → edist (f a) (f b) < ε := + uniformity_basis_edist.uniformContinuousOn_iff uniformity_basis_edist + +/-- ε-δ characterization of uniform continuity on pseudoemetric spaces -/ +theorem uniformContinuous_iff [PseudoEMetricSpace β] {f : α → β} : + UniformContinuous f ↔ ∀ ε > 0, ∃ δ > 0, ∀ {a b : α}, edist a b < δ → edist (f a) (f b) < ε := + uniformity_basis_edist.uniformContinuous_iff uniformity_basis_edist + +end EMetric + +open EMetric + +/-- Auxiliary function to replace the uniformity on a pseudoemetric space with +a uniformity which is equal to the original one, but maybe not defeq. +This is useful if one wants to construct a pseudoemetric space with a +specified uniformity. See Note [forgetful inheritance] explaining why having definitionally +the right uniformity is often important. +See note [reducible non-instances]. +-/ +abbrev PseudoEMetricSpace.replaceUniformity {α} [U : UniformSpace α] (m : PseudoEMetricSpace α) + (H : 𝓤[U] = 𝓤[PseudoEMetricSpace.toUniformSpace]) : PseudoEMetricSpace α where + edist := @edist _ m.toEDist + edist_self := edist_self + edist_comm := edist_comm + edist_triangle := edist_triangle + toUniformSpace := U + uniformity_edist := H.trans (@PseudoEMetricSpace.uniformity_edist α _) + +/-- The extended pseudometric induced by a function taking values in a pseudoemetric space. +See note [reducible non-instances]. -/ +abbrev PseudoEMetricSpace.induced {α β} (f : α → β) (m : PseudoEMetricSpace β) : + PseudoEMetricSpace α where + edist x y := edist (f x) (f y) + edist_self _ := edist_self _ + edist_comm _ _ := edist_comm _ _ + edist_triangle _ _ _ := edist_triangle _ _ _ + toUniformSpace := UniformSpace.comap f m.toUniformSpace + uniformity_edist := (uniformity_basis_edist.comap (Prod.map f f)).eq_biInf + +/-- Pseudoemetric space instance on subsets of pseudoemetric spaces -/ +instance {α : Type*} {p : α → Prop} [PseudoEMetricSpace α] : PseudoEMetricSpace (Subtype p) := + PseudoEMetricSpace.induced Subtype.val ‹_› + +/-- The extended pseudodistance on a subset of a pseudoemetric space is the restriction of +the original pseudodistance, by definition -/ +theorem Subtype.edist_eq {p : α → Prop} (x y : Subtype p) : edist x y = edist (x : α) y := rfl + +namespace MulOpposite + +/-- Pseudoemetric space instance on the multiplicative opposite of a pseudoemetric space. -/ +@[to_additive "Pseudoemetric space instance on the additive opposite of a pseudoemetric space."] +instance {α : Type*} [PseudoEMetricSpace α] : PseudoEMetricSpace αᵐᵒᵖ := + PseudoEMetricSpace.induced unop ‹_› + +@[to_additive] +theorem edist_unop (x y : αᵐᵒᵖ) : edist (unop x) (unop y) = edist x y := rfl + +@[to_additive] +theorem edist_op (x y : α) : edist (op x) (op y) = edist x y := rfl + +end MulOpposite + +section ULift + +instance : PseudoEMetricSpace (ULift α) := PseudoEMetricSpace.induced ULift.down ‹_› + +theorem ULift.edist_eq (x y : ULift α) : edist x y = edist x.down y.down := rfl + +@[simp] +theorem ULift.edist_up_up (x y : α) : edist (ULift.up x) (ULift.up y) = edist x y := rfl + +end ULift + +/-- The product of two pseudoemetric spaces, with the max distance, is an extended +pseudometric spaces. We make sure that the uniform structure thus constructed is the one +corresponding to the product of uniform spaces, to avoid diamond problems. -/ +instance Prod.pseudoEMetricSpaceMax [PseudoEMetricSpace β] : PseudoEMetricSpace (α × β) where + 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 := + 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 + simp [PseudoEMetricSpace.uniformity_edist, ← iInf_inf_eq, setOf_and] + toUniformSpace := inferInstance + +theorem Prod.edist_eq [PseudoEMetricSpace β] (x y : α × β) : + edist x y = max (edist x.1 y.1) (edist x.2 y.2) := + rfl + +namespace EMetric + +variable {x y z : α} {ε ε₁ ε₂ : ℝ≥0∞} {s t : Set α} + +/-- `EMetric.ball x ε` is the set of all points `y` with `edist y x < ε` -/ +def ball (x : α) (ε : ℝ≥0∞) : Set α := + { y | edist y x < ε } + +@[simp] theorem mem_ball : y ∈ ball x ε ↔ edist y x < ε := Iff.rfl + +theorem mem_ball' : y ∈ ball x ε ↔ edist x y < ε := by rw [edist_comm, mem_ball] + +/-- `EMetric.closedBall x ε` is the set of all points `y` with `edist y x ≤ ε` -/ +def closedBall (x : α) (ε : ℝ≥0∞) := + { y | edist y x ≤ ε } + +@[simp] theorem mem_closedBall : y ∈ closedBall x ε ↔ edist y x ≤ ε := Iff.rfl + +theorem mem_closedBall' : y ∈ closedBall x ε ↔ edist x y ≤ ε := by rw [edist_comm, mem_closedBall] + +@[simp] +theorem closedBall_top (x : α) : closedBall x ∞ = univ := + eq_univ_of_forall fun _ => mem_setOf.2 le_top + +theorem ball_subset_closedBall : ball x ε ⊆ closedBall x ε := fun _ h => le_of_lt h.out + +theorem pos_of_mem_ball (hy : y ∈ ball x ε) : 0 < ε := + lt_of_le_of_lt (zero_le _) hy + +theorem mem_ball_self (h : 0 < ε) : x ∈ ball x ε := by + rwa [mem_ball, edist_self] + +theorem mem_closedBall_self : x ∈ closedBall x ε := by + rw [mem_closedBall, edist_self]; apply zero_le + +theorem mem_ball_comm : x ∈ ball y ε ↔ y ∈ ball x ε := by rw [mem_ball', mem_ball] + +theorem mem_closedBall_comm : x ∈ closedBall y ε ↔ y ∈ closedBall x ε := by + rw [mem_closedBall', mem_closedBall] + +@[gcongr] +theorem ball_subset_ball (h : ε₁ ≤ ε₂) : ball x ε₁ ⊆ ball x ε₂ := fun _y (yx : _ < ε₁) => + lt_of_lt_of_le yx h + +@[gcongr] +theorem closedBall_subset_closedBall (h : ε₁ ≤ ε₂) : closedBall x ε₁ ⊆ closedBall x ε₂ := + fun _y (yx : _ ≤ ε₁) => le_trans yx h + +theorem ball_disjoint (h : ε₁ + ε₂ ≤ edist x y) : Disjoint (ball x ε₁) (ball y ε₂) := + Set.disjoint_left.mpr fun z h₁ h₂ => + (edist_triangle_left x y z).not_lt <| (ENNReal.add_lt_add h₁ h₂).trans_le h + +theorem ball_subset (h : edist x y + ε₁ ≤ ε₂) (h' : edist x y ≠ ∞) : ball x ε₁ ⊆ ball y ε₂ := + fun z zx => + calc + edist z y ≤ edist z x + edist x y := edist_triangle _ _ _ + _ = edist x y + edist z x := add_comm _ _ + _ < edist x y + ε₁ := ENNReal.add_lt_add_left h' zx + _ ≤ ε₂ := h + +theorem exists_ball_subset_ball (h : y ∈ ball x ε) : ∃ ε' > 0, ball y ε' ⊆ ball x ε := by + have : 0 < ε - edist y x := by simpa using h + refine ⟨ε - edist y x, this, ball_subset ?_ (ne_top_of_lt h)⟩ + exact (add_tsub_cancel_of_le (mem_ball.mp h).le).le + +theorem ball_eq_empty_iff : ball x ε = ∅ ↔ ε = 0 := + eq_empty_iff_forall_not_mem.trans + ⟨fun h => le_bot_iff.1 (le_of_not_gt fun ε0 => h _ (mem_ball_self ε0)), fun ε0 _ h => + not_lt_of_le (le_of_eq ε0) (pos_of_mem_ball h)⟩ + +theorem ordConnected_setOf_closedBall_subset (x : α) (s : Set α) : + OrdConnected { r | closedBall x r ⊆ s } := + ⟨fun _ _ _ h₁ _ h₂ => (closedBall_subset_closedBall h₂.2).trans h₁⟩ + +theorem ordConnected_setOf_ball_subset (x : α) (s : Set α) : OrdConnected { r | ball x r ⊆ s } := + ⟨fun _ _ _ h₁ _ h₂ => (ball_subset_ball h₂.2).trans h₁⟩ + +/-- Relation “two points are at a finite edistance” is an equivalence relation. -/ +def edistLtTopSetoid : Setoid α where + r x y := edist x y < ⊤ + iseqv := + ⟨fun x => by rw [edist_self]; exact ENNReal.coe_lt_top, + fun h => by rwa [edist_comm], fun hxy hyz => + lt_of_le_of_lt (edist_triangle _ _ _) (ENNReal.add_lt_top.2 ⟨hxy, hyz⟩)⟩ + +@[simp] +theorem ball_zero : ball x 0 = ∅ := by rw [EMetric.ball_eq_empty_iff] + +theorem nhds_basis_eball : (𝓝 x).HasBasis (fun ε : ℝ≥0∞ => 0 < ε) (ball x) := + nhds_basis_uniformity uniformity_basis_edist + +theorem nhdsWithin_basis_eball : (𝓝[s] x).HasBasis (fun ε : ℝ≥0∞ => 0 < ε) fun ε => ball x ε ∩ s := + nhdsWithin_hasBasis nhds_basis_eball s + +theorem nhds_basis_closed_eball : (𝓝 x).HasBasis (fun ε : ℝ≥0∞ => 0 < ε) (closedBall x) := + nhds_basis_uniformity uniformity_basis_edist_le + +theorem nhdsWithin_basis_closed_eball : + (𝓝[s] x).HasBasis (fun ε : ℝ≥0∞ => 0 < ε) fun ε => closedBall x ε ∩ s := + nhdsWithin_hasBasis nhds_basis_closed_eball s + +theorem nhds_eq : 𝓝 x = ⨅ ε > 0, 𝓟 (ball x ε) := + nhds_basis_eball.eq_biInf + +theorem mem_nhds_iff : s ∈ 𝓝 x ↔ ∃ ε > 0, ball x ε ⊆ s := + nhds_basis_eball.mem_iff + +theorem mem_nhdsWithin_iff : s ∈ 𝓝[t] x ↔ ∃ ε > 0, ball x ε ∩ t ⊆ s := + nhdsWithin_basis_eball.mem_iff + +section + +variable [PseudoEMetricSpace β] {f : α → β} + +theorem tendsto_nhdsWithin_nhdsWithin {t : Set β} {a b} : + Tendsto f (𝓝[s] a) (𝓝[t] b) ↔ + ∀ ε > 0, ∃ δ > 0, ∀ ⦃x⦄, x ∈ s → edist x a < δ → f x ∈ t ∧ edist (f x) b < ε := + (nhdsWithin_basis_eball.tendsto_iff nhdsWithin_basis_eball).trans <| + forall₂_congr fun ε _ => exists_congr fun δ => and_congr_right fun _ => + forall_congr' fun x => by simp; tauto + +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] + +theorem tendsto_nhds_nhds {a b} : + Tendsto f (𝓝 a) (𝓝 b) ↔ ∀ ε > 0, ∃ δ > 0, ∀ ⦃x⦄, edist x a < δ → edist (f x) b < ε := + nhds_basis_eball.tendsto_iff nhds_basis_eball + +end + +theorem isOpen_iff : IsOpen s ↔ ∀ x ∈ s, ∃ ε > 0, ball x ε ⊆ s := by + simp [isOpen_iff_nhds, mem_nhds_iff] + +theorem isOpen_ball : IsOpen (ball x ε) := + isOpen_iff.2 fun _ => exists_ball_subset_ball + +theorem isClosed_ball_top : IsClosed (ball x ⊤) := + isOpen_compl_iff.1 <| isOpen_iff.2 fun _y hy => + ⟨⊤, ENNReal.coe_lt_top, fun _z hzy hzx => + hy (edistLtTopSetoid.trans (edistLtTopSetoid.symm hzy) hzx)⟩ + +theorem ball_mem_nhds (x : α) {ε : ℝ≥0∞} (ε0 : 0 < ε) : ball x ε ∈ 𝓝 x := + isOpen_ball.mem_nhds (mem_ball_self ε0) + +theorem closedBall_mem_nhds (x : α) {ε : ℝ≥0∞} (ε0 : 0 < ε) : closedBall x ε ∈ 𝓝 x := + mem_of_superset (ball_mem_nhds x ε0) ball_subset_closedBall + +theorem ball_prod_same [PseudoEMetricSpace β] (x : α) (y : β) (r : ℝ≥0∞) : + ball x r ×ˢ ball y r = ball (x, y) r := + ext fun z => by simp [Prod.edist_eq] + +theorem closedBall_prod_same [PseudoEMetricSpace β] (x : α) (y : β) (r : ℝ≥0∞) : + closedBall x r ×ˢ closedBall y r = closedBall (x, y) r := + ext fun z => by simp [Prod.edist_eq] + +/-- ε-characterization of the closure in pseudoemetric spaces -/ +theorem mem_closure_iff : x ∈ closure s ↔ ∀ ε > 0, ∃ y ∈ s, edist x y < ε := + (mem_closure_iff_nhds_basis nhds_basis_eball).trans <| by simp only [mem_ball, edist_comm x] + +theorem tendsto_nhds {f : Filter β} {u : β → α} {a : α} : + Tendsto u f (𝓝 a) ↔ ∀ ε > 0, ∀ᶠ x in f, edist (u x) a < ε := + nhds_basis_eball.tendsto_right_iff + +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, mem_Ici, mem_ball] + +section Compact + +-- Porting note (#11215): TODO: generalize to a uniform space with metrizable uniformity +/-- For a set `s` in a pseudo emetric space, if for every `ε > 0` there exists a countable +set that is `ε`-dense in `s`, then there exists a countable subset `t ⊆ s` that is dense in `s`. -/ +theorem subset_countable_closure_of_almost_dense_set (s : Set α) + (hs : ∀ ε > 0, ∃ t : Set α, t.Countable ∧ s ⊆ ⋃ x ∈ t, closedBall x ε) : + ∃ t, t ⊆ s ∧ t.Countable ∧ s ⊆ closure t := by + rcases s.eq_empty_or_nonempty with (rfl | ⟨x₀, hx₀⟩) + · exact ⟨∅, empty_subset _, countable_empty, empty_subset _⟩ + choose! T hTc hsT using fun n : ℕ => hs n⁻¹ (by simp) + have : ∀ r x, ∃ y ∈ s, closedBall x r ∩ s ⊆ closedBall y (r * 2) := fun r x => by + rcases (closedBall x r ∩ s).eq_empty_or_nonempty with (he | ⟨y, hxy, hys⟩) + · refine ⟨x₀, hx₀, ?_⟩ + rw [he] + exact empty_subset _ + · refine ⟨y, hys, fun z hz => ?_⟩ + calc + edist z y ≤ edist z x + edist y x := edist_triangle_right _ _ _ + _ ≤ r + r := add_le_add hz.1 hxy + _ = r * 2 := (mul_two r).symm + choose f hfs hf using this + refine + ⟨⋃ n : ℕ, f n⁻¹ '' T n, iUnion_subset fun n => image_subset_iff.2 fun z _ => hfs _ _, + countable_iUnion fun n => (hTc n).image _, ?_⟩ + refine fun x hx => mem_closure_iff.2 fun ε ε0 => ?_ + rcases ENNReal.exists_inv_nat_lt (ENNReal.half_pos ε0.lt.ne').ne' with ⟨n, hn⟩ + rcases mem_iUnion₂.1 (hsT n hx) with ⟨y, hyn, hyx⟩ + refine ⟨f n⁻¹ y, mem_iUnion.2 ⟨n, mem_image_of_mem _ hyn⟩, ?_⟩ + calc + edist x (f n⁻¹ y) ≤ (n : ℝ≥0∞)⁻¹ * 2 := hf _ _ ⟨hyx, hx⟩ + _ < ε := ENNReal.mul_lt_of_lt_div hn + +open TopologicalSpace in +/-- If a set `s` is separable in a (pseudo extended) metric space, then it admits a countable dense +subset. This is not obvious, as the countable set whose closure covers `s` given by the definition +of separability does not need in general to be contained in `s`. -/ +theorem _root_.TopologicalSpace.IsSeparable.exists_countable_dense_subset + {s : Set α} (hs : IsSeparable s) : ∃ t, t ⊆ s ∧ t.Countable ∧ s ⊆ closure t := by + have : ∀ ε > 0, ∃ t : Set α, t.Countable ∧ s ⊆ ⋃ x ∈ t, closedBall x ε := fun ε ε0 => by + rcases hs with ⟨t, htc, hst⟩ + refine ⟨t, htc, hst.trans fun x hx => ?_⟩ + rcases mem_closure_iff.1 hx ε ε0 with ⟨y, hyt, hxy⟩ + exact mem_iUnion₂.2 ⟨y, hyt, mem_closedBall.2 hxy.le⟩ + exact subset_countable_closure_of_almost_dense_set _ this + +open TopologicalSpace in +/-- If a set `s` is separable, then the corresponding subtype is separable in a (pseudo extended) +metric space. This is not obvious, as the countable set whose closure covers `s` does not need in +general to be contained in `s`. -/ +theorem _root_.TopologicalSpace.IsSeparable.separableSpace {s : Set α} (hs : IsSeparable s) : + SeparableSpace s := by + 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] + +end Compact + +end EMetric + +--namespace +/-- We now define `EMetricSpace`, extending `PseudoEMetricSpace`. -/ +class EMetricSpace (α : Type u) extends PseudoEMetricSpace α : Type u where + eq_of_edist_eq_zero : ∀ {x y : α}, edist x y = 0 → x = y + +@[ext] +protected theorem EMetricSpace.ext + {α : Type*} {m m' : EMetricSpace α} (h : m.toEDist = m'.toEDist) : m = m' := by + cases m + cases m' + congr + ext1 + assumption + +variable {γ : Type w} [EMetricSpace γ] + +export EMetricSpace (eq_of_edist_eq_zero) + +/-- Characterize the equality of points by the vanishing of their extended distance -/ +@[simp] +theorem edist_eq_zero {x y : γ} : edist x y = 0 ↔ x = y := + ⟨eq_of_edist_eq_zero, fun h => h ▸ edist_self _⟩ + +@[simp] +theorem zero_eq_edist {x y : γ} : 0 = edist x y ↔ x = y := eq_comm.trans edist_eq_zero + +theorem edist_le_zero {x y : γ} : edist x y ≤ 0 ↔ x = y := + nonpos_iff_eq_zero.trans edist_eq_zero + +@[simp] +theorem edist_pos {x y : γ} : 0 < edist x y ↔ x ≠ y := by simp [← not_le] + +/-- Two points coincide if their distance is `< ε` for all positive ε -/ +theorem eq_of_forall_edist_le {x y : γ} (h : ∀ ε > 0, edist x y ≤ ε) : x = y := + eq_of_edist_eq_zero (eq_of_le_of_forall_le_of_dense bot_le h) + +/-- Auxiliary function to replace the uniformity on an emetric space with +a uniformity which is equal to the original one, but maybe not defeq. +This is useful if one wants to construct an emetric space with a +specified uniformity. See Note [forgetful inheritance] explaining why having definitionally +the right uniformity is often important. +See note [reducible non-instances]. +-/ +abbrev EMetricSpace.replaceUniformity {γ} [U : UniformSpace γ] (m : EMetricSpace γ) + (H : 𝓤[U] = 𝓤[PseudoEMetricSpace.toUniformSpace]) : EMetricSpace γ where + edist := @edist _ m.toEDist + edist_self := edist_self + eq_of_edist_eq_zero := @eq_of_edist_eq_zero _ _ + edist_comm := edist_comm + edist_triangle := edist_triangle + toUniformSpace := U + uniformity_edist := H.trans (@PseudoEMetricSpace.uniformity_edist γ _) + +/-- The extended metric induced by an injective function taking values in an emetric space. +See Note [reducible non-instances]. -/ +abbrev EMetricSpace.induced {γ β} (f : γ → β) (hf : Function.Injective f) (m : EMetricSpace β) : + EMetricSpace γ := + { PseudoEMetricSpace.induced f m.toPseudoEMetricSpace with + eq_of_edist_eq_zero := fun h => hf (edist_eq_zero.1 h) } + +/-- EMetric space instance on subsets of emetric spaces -/ +instance {α : Type*} {p : α → Prop} [EMetricSpace α] : EMetricSpace (Subtype p) := + EMetricSpace.induced Subtype.val Subtype.coe_injective ‹_› + +/-- EMetric space instance on the multiplicative opposite of an emetric space. -/ +@[to_additive "EMetric space instance on the additive opposite of an emetric space."] +instance {α : Type*} [EMetricSpace α] : EMetricSpace αᵐᵒᵖ := + EMetricSpace.induced MulOpposite.unop MulOpposite.unop_injective ‹_› + +instance {α : Type*} [EMetricSpace α] : EMetricSpace (ULift α) := + EMetricSpace.induced ULift.down ULift.down_injective ‹_› + +/-- Reformulation of the uniform structure in terms of the extended distance -/ +theorem uniformity_edist : 𝓤 γ = ⨅ ε > 0, 𝓟 { p : γ × γ | edist p.1 p.2 < ε } := + PseudoEMetricSpace.uniformity_edist + +/-! +### `Additive`, `Multiplicative` + +The distance on those type synonyms is inherited without change. +-/ + + +open Additive Multiplicative + +section + +variable [EDist X] + +instance : EDist (Additive X) := ‹EDist X› +instance : EDist (Multiplicative X) := ‹EDist X› + +@[simp] +theorem edist_ofMul (a b : X) : edist (ofMul a) (ofMul b) = edist a b := + rfl + +@[simp] +theorem edist_ofAdd (a b : X) : edist (ofAdd a) (ofAdd b) = edist a b := + rfl + +@[simp] +theorem edist_toMul (a b : Additive X) : edist (toMul a) (toMul b) = edist a b := + rfl + +@[simp] +theorem edist_toAdd (a b : Multiplicative X) : edist (toAdd a) (toAdd b) = edist a b := + rfl + +end + +instance [PseudoEMetricSpace X] : PseudoEMetricSpace (Additive X) := ‹PseudoEMetricSpace X› +instance [PseudoEMetricSpace X] : PseudoEMetricSpace (Multiplicative X) := ‹PseudoEMetricSpace X› +instance [EMetricSpace X] : EMetricSpace (Additive X) := ‹EMetricSpace X› +instance [EMetricSpace X] : EMetricSpace (Multiplicative X) := ‹EMetricSpace X› + +/-! +### Order dual + +The distance on this type synonym is inherited without change. +-/ + + +open OrderDual + +section + +variable [EDist X] + +instance : EDist Xᵒᵈ := ‹EDist X› + +@[simp] +theorem edist_toDual (a b : X) : edist (toDual a) (toDual b) = edist a b := + rfl + +@[simp] +theorem edist_ofDual (a b : Xᵒᵈ) : edist (ofDual a) (ofDual b) = edist a b := + rfl + +end + +instance [PseudoEMetricSpace X] : PseudoEMetricSpace Xᵒᵈ := ‹PseudoEMetricSpace X› +instance [EMetricSpace X] : EMetricSpace Xᵒᵈ := ‹EMetricSpace X› diff --git a/Mathlib/Topology/EMetricSpace/Diam.lean b/Mathlib/Topology/EMetricSpace/Diam.lean new file mode 100644 index 0000000000000..18895f5377d0d --- /dev/null +++ b/Mathlib/Topology/EMetricSpace/Diam.lean @@ -0,0 +1,148 @@ +/- +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.EMetricSpace.Pi + +/-! +# Diameters of sets in extended metric spaces + +-/ + + +open Set Filter Classical + +open scoped Uniformity Topology Filter NNReal ENNReal Pointwise + +universe u v w + +variable {α β : Type*} {s : Set α} {x y z : α} + +namespace EMetric + +section +variable [PseudoEMetricSpace α] + +/-- The diameter of a set in a pseudoemetric space, named `EMetric.diam` -/ +noncomputable def diam (s : Set α) := + ⨆ (x ∈ s) (y ∈ s), edist x y + +theorem diam_eq_sSup (s : Set α) : diam s = sSup (image2 edist s s) := sSup_image2.symm + +theorem diam_le_iff {d : ℝ≥0∞} : diam s ≤ d ↔ ∀ x ∈ s, ∀ y ∈ s, edist x y ≤ d := by + simp only [diam, iSup_le_iff] + +theorem diam_image_le_iff {d : ℝ≥0∞} {f : β → α} {s : Set β} : + diam (f '' s) ≤ d ↔ ∀ x ∈ s, ∀ y ∈ s, edist (f x) (f y) ≤ d := by + simp only [diam_le_iff, forall_mem_image] + +theorem edist_le_of_diam_le {d} (hx : x ∈ s) (hy : y ∈ s) (hd : diam s ≤ d) : edist x y ≤ d := + diam_le_iff.1 hd x hx y hy + +/-- If two points belong to some set, their edistance is bounded by the diameter of the set -/ +theorem edist_le_diam_of_mem (hx : x ∈ s) (hy : y ∈ s) : edist x y ≤ diam s := + edist_le_of_diam_le hx hy le_rfl + +/-- If the distance between any two points in a set is bounded by some constant, this constant +bounds the diameter. -/ +theorem diam_le {d : ℝ≥0∞} (h : ∀ x ∈ s, ∀ y ∈ s, edist x y ≤ d) : diam s ≤ d := + diam_le_iff.2 h + +/-- The diameter of a subsingleton vanishes. -/ +theorem diam_subsingleton (hs : s.Subsingleton) : diam s = 0 := + nonpos_iff_eq_zero.1 <| diam_le fun _x hx y hy => (hs hx hy).symm ▸ edist_self y ▸ le_rfl + +/-- The diameter of the empty set vanishes -/ +@[simp] +theorem diam_empty : diam (∅ : Set α) = 0 := + diam_subsingleton subsingleton_empty + +/-- The diameter of a singleton vanishes -/ +@[simp] +theorem diam_singleton : diam ({x} : Set α) = 0 := + diam_subsingleton subsingleton_singleton + +@[to_additive (attr := simp)] +theorem diam_one [One α] : diam (1 : Set α) = 0 := + diam_singleton + +theorem diam_iUnion_mem_option {ι : Type*} (o : Option ι) (s : ι → Set α) : + diam (⋃ i ∈ o, s i) = ⨆ i ∈ o, diam (s i) := by cases o <;> simp + +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, 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] + +theorem diam_triple : diam ({x, y, z} : Set α) = max (max (edist x y) (edist x z)) (edist y z) := by + simp only [diam_insert, iSup_insert, iSup_singleton, diam_singleton, ENNReal.max_zero_right, + ENNReal.sup_eq_max] + +/-- The diameter is monotonous with respect to inclusion -/ +@[gcongr] +theorem diam_mono {s t : Set α} (h : s ⊆ t) : diam s ≤ diam t := + diam_le fun _x hx _y hy => edist_le_diam_of_mem (h hx) (h hy) + +/-- The diameter of a union is controlled by the diameter of the sets, and the edistance +between two points in the sets. -/ +theorem diam_union {t : Set α} (xs : x ∈ s) (yt : y ∈ t) : + diam (s ∪ t) ≤ diam s + edist x y + diam t := by + have A : ∀ a ∈ s, ∀ b ∈ t, edist a b ≤ diam s + edist x y + diam t := fun a ha b hb => + calc + edist a b ≤ edist a x + edist x y + edist y b := edist_triangle4 _ _ _ _ + _ ≤ diam s + edist x y + diam t := + add_le_add (add_le_add (edist_le_diam_of_mem ha xs) le_rfl) (edist_le_diam_of_mem yt hb) + refine diam_le fun a ha b hb => ?_ + cases' (mem_union _ _ _).1 ha with h'a h'a <;> cases' (mem_union _ _ _).1 hb with h'b h'b + · calc + edist a b ≤ diam s := edist_le_diam_of_mem h'a h'b + _ ≤ diam s + (edist x y + diam t) := le_self_add + _ = diam s + edist x y + diam t := (add_assoc _ _ _).symm + · exact A a h'a b h'b + · have Z := A b h'b a h'a + rwa [edist_comm] at Z + · calc + edist a b ≤ diam t := edist_le_diam_of_mem h'a h'b + _ ≤ diam s + edist x y + diam t := le_add_self + +theorem diam_union' {t : Set α} (h : (s ∩ t).Nonempty) : diam (s ∪ t) ≤ diam s + diam t := by + let ⟨x, ⟨xs, xt⟩⟩ := h + simpa using diam_union xs xt + +theorem diam_closedBall {r : ℝ≥0∞} : diam (closedBall x r) ≤ 2 * r := + diam_le fun a ha b hb => + calc + edist a b ≤ edist a x + edist b x := edist_triangle_right _ _ _ + _ ≤ r + r := add_le_add ha hb + _ = 2 * r := (two_mul r).symm + +theorem diam_ball {r : ℝ≥0∞} : diam (ball x r) ≤ 2 * r := + le_trans (diam_mono ball_subset_closedBall) diam_closedBall + +theorem diam_pi_le_of_le {π : β → Type*} [Fintype β] [∀ b, PseudoEMetricSpace (π b)] + {s : ∀ b : β, Set (π b)} {c : ℝ≥0∞} (h : ∀ b, diam (s b) ≤ c) : diam (Set.pi univ s) ≤ c := by + refine diam_le fun x hx y hy => edist_pi_le_iff.mpr ?_ + rw [mem_univ_pi] at hx hy + exact fun b => diam_le_iff.1 (h b) (x b) (hx b) (y b) (hy b) + +end + +section +variable [EMetricSpace β] {s : Set β} + +theorem diam_eq_zero_iff : diam s = 0 ↔ s.Subsingleton := + ⟨fun h _x hx _y hy => edist_le_zero.1 <| h ▸ edist_le_diam_of_mem hx hy, diam_subsingleton⟩ + +theorem diam_pos_iff : 0 < diam s ↔ s.Nontrivial := by + simp only [pos_iff_ne_zero, Ne, diam_eq_zero_iff, Set.not_subsingleton_iff] + +theorem diam_pos_iff' : 0 < diam s ↔ ∃ x ∈ s, ∃ y ∈ s, x ≠ y := by + simp only [diam_pos_iff, Set.Nontrivial, exists_prop] + +end + +end EMetric diff --git a/Mathlib/Topology/EMetricSpace/Lipschitz.lean b/Mathlib/Topology/EMetricSpace/Lipschitz.lean index b36604dea713c..dc80b6180d219 100644 --- a/Mathlib/Topology/EMetricSpace/Lipschitz.lean +++ b/Mathlib/Topology/EMetricSpace/Lipschitz.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Rohan Mitta, Kevin Buzzard, Alistair Tucker, Johannes Hölzl, Yury Kudryashov -/ import Mathlib.Logic.Function.Iterate -import Mathlib.Topology.EMetricSpace.Basic +import Mathlib.Topology.EMetricSpace.Diam import Mathlib.Tactic.GCongr /-! @@ -59,11 +59,11 @@ def LipschitzOnWith (K : ℝ≥0) (f : α → β) (s : Set α) := ∀ ⦃x⦄, x ∈ s → ∀ ⦃y⦄, y ∈ s → edist (f x) (f y) ≤ K * edist x y /-- `f : α → β` is called **locally Lipschitz continuous** iff every point `x` -has a neighourhood on which `f` is Lipschitz. -/ +has a neighbourhood on which `f` is Lipschitz. -/ def LocallyLipschitz (f : α → β) : Prop := ∀ x, ∃ K, ∃ t ∈ 𝓝 x, LipschitzOnWith K f t /-- `f : α → β` is called **locally Lipschitz continuous** on `s` iff every point `x` of `s` -has a neighourhood within `s` on which `f` is Lipschitz. -/ +has a neighbourhood within `s` on which `f` is Lipschitz. -/ def LocallyLipschitzOn (s : Set α) (f : α → β) : Prop := ∀ ⦃x⦄, x ∈ s → ∃ K, ∃ t ∈ 𝓝[s] x, LipschitzOnWith K f t @@ -89,6 +89,9 @@ lemma LocallyLipschitzOn.mono (hf : LocallyLipschitzOn t f) (h : s ⊆ t) : Loca @[simp] lemma locallyLipschitzOn_univ : LocallyLipschitzOn univ f ↔ LocallyLipschitz f := by simp [LocallyLipschitzOn, LocallyLipschitz] +protected lemma LocallyLipschitz.locallyLipschitzOn (h : LocallyLipschitz f) : + LocallyLipschitzOn s f := (locallyLipschitzOn_univ.2 h).mono s.subset_univ + theorem lipschitzOnWith_iff_restrict : LipschitzOnWith K f s ↔ LipschitzWith K (s.restrict f) := by simp only [LipschitzOnWith, LipschitzWith, SetCoe.forall', restrict, Subtype.edist_eq] @@ -125,9 +128,9 @@ namespace LipschitzWith open EMetric variable [PseudoEMetricSpace α] [PseudoEMetricSpace β] [PseudoEMetricSpace γ] -variable {K : ℝ≥0} {f : α → β} {x y : α} {r : ℝ≥0∞} +variable {K : ℝ≥0} {f : α → β} {x y : α} {r : ℝ≥0∞} {s : Set α} -protected theorem lipschitzOnWith (h : LipschitzWith K f) (s : Set α) : LipschitzOnWith K f s := +protected theorem lipschitzOnWith (h : LipschitzWith K f) : LipschitzOnWith K f s := fun x _ y _ => h x y theorem edist_le_mul (h : LipschitzWith K f) (x y : α) : edist (f x) (f y) ≤ K * edist x y := @@ -149,7 +152,7 @@ theorem mapsTo_emetric_ball (h : LipschitzWith K f) (hK : K ≠ 0) (x : α) (r : theorem edist_lt_top (hf : LipschitzWith K f) {x y : α} (h : edist x y ≠ ⊤) : edist (f x) (f y) < ⊤ := - (hf x y).trans_lt <| ENNReal.mul_lt_top ENNReal.coe_ne_top h + (hf x y).trans_lt <| ENNReal.mul_lt_top ENNReal.coe_lt_top h.lt_top theorem mul_edist_le (h : LipschitzWith K f) (x y : α) : (K⁻¹ : ℝ≥0∞) * edist (f x) (f y) ≤ edist x y := by diff --git a/Mathlib/Topology/EMetricSpace/Paracompact.lean b/Mathlib/Topology/EMetricSpace/Paracompact.lean index db4fdd6346d82..f7e7082bc036a 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.EMetricSpace.Basic import Mathlib.Topology.Compactness.Paracompact +import Mathlib.Topology.EMetricSpace.Basic +import Mathlib.SetTheory.Cardinal.Basic /-! # (Extended) metric spaces are paracompact diff --git a/Mathlib/Topology/EMetricSpace/Pi.lean b/Mathlib/Topology/EMetricSpace/Pi.lean new file mode 100644 index 0000000000000..bbf987884575b --- /dev/null +++ b/Mathlib/Topology/EMetricSpace/Pi.lean @@ -0,0 +1,90 @@ +/- +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.EMetricSpace.Basic +import Mathlib.Topology.UniformSpace.Pi + +/-! +# Indexed product of extended metric spaces +-/ + +open Set Filter + +universe u v w + +variable {α : Type u} {β : Type v} {X : Type*} + +open scoped Uniformity Topology NNReal ENNReal Pointwise + +variable [PseudoEMetricSpace α] + +open EMetric + +section Pi + +open Finset + +variable {π : β → Type*} [Fintype β] + +-- Porting note: reordered instances +instance [∀ b, EDist (π b)] : EDist (∀ b, π b) where + edist f g := Finset.sup univ fun b => edist (f b) (g b) + +theorem edist_pi_def [∀ b, EDist (π b)] (f g : ∀ b, π b) : + edist f g = Finset.sup univ fun b => edist (f b) (g b) := + rfl + +theorem edist_le_pi_edist [∀ b, EDist (π b)] (f g : ∀ b, π b) (b : β) : + edist (f b) (g b) ≤ edist f g := + le_sup (f := fun b => edist (f b) (g b)) (Finset.mem_univ b) + +theorem edist_pi_le_iff [∀ b, EDist (π b)] {f g : ∀ b, π b} {d : ℝ≥0∞} : + edist f g ≤ d ↔ ∀ b, edist (f b) (g b) ≤ d := + Finset.sup_le_iff.trans <| by simp only [Finset.mem_univ, forall_const] + +theorem edist_pi_const_le (a b : α) : (edist (fun _ : β => a) fun _ => b) ≤ edist a b := + edist_pi_le_iff.2 fun _ => le_rfl + +@[simp] +theorem edist_pi_const [Nonempty β] (a b : α) : (edist (fun _ : β => a) fun _ => b) = edist a b := + Finset.sup_const univ_nonempty (edist a b) + +/-- The product of a finite number of pseudoemetric spaces, with the max distance, is still +a pseudoemetric space. +This construction would also work for infinite products, but it would not give rise +to the product topology. Hence, we only formalize it in the good situation of finitely many +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) _) + (add_le_add (edist_le_pi_edist _ _ _) (edist_le_pi_edist _ _ _)) + toUniformSpace := Pi.uniformSpace _ + uniformity_edist := by + simp only [Pi.uniformity, PseudoEMetricSpace.uniformity_edist, comap_iInf, gt_iff_lt, + preimage_setOf_eq, comap_principal, edist_pi_def] + rw [iInf_comm]; congr; funext ε + rw [iInf_comm]; congr; funext εpos + simp [setOf_forall, εpos] + +end Pi + +variable {γ : Type w} [EMetricSpace γ] + +section Pi + +open Finset + +variable {π : β → Type*} [Fintype β] + +/-- The product of a finite number of emetric spaces, with the max distance, is still +an emetric space. +This construction would also work for infinite products, but it would not give rise +to the product topology. Hence, we only formalize it in the good situation of finitely many +spaces. -/ +instance emetricSpacePi [∀ b, EMetricSpace (π b)] : EMetricSpace (∀ b, π b) := + .ofT0PseudoEMetricSpace _ + +end Pi diff --git a/Mathlib/Topology/ExtendFrom.lean b/Mathlib/Topology/ExtendFrom.lean index e425d7ce55e1a..1c043eb2756ea 100644 --- a/Mathlib/Topology/ExtendFrom.lean +++ b/Mathlib/Topology/ExtendFrom.lean @@ -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..fcf995f4c441a --- /dev/null +++ b/Mathlib/Topology/Exterior.lean @@ -0,0 +1,98 @@ +/- +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 {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 {ι : Sort*} (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] + +@[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..f81a6b4448fd2 100644 --- a/Mathlib/Topology/ExtremallyDisconnected.lean +++ b/Mathlib/Topology/ExtremallyDisconnected.lean @@ -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 4606e9604e100..39a1e8d2edc2b 100644 --- a/Mathlib/Topology/FiberBundle/Basic.lean +++ b/Mathlib/Topology/FiberBundle/Basic.lean @@ -439,7 +439,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 +469,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 +479,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 +493,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 +508,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] @@ -674,7 +674,7 @@ instance fiberBundle : FiberBundle F Z.Fiber where totalSpaceMk_inducing' b := inducing_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 [(· ∘ ·), localTrivAt_apply_mk, Trivialization.coe_coe, + simp only [Function.comp_def, localTrivAt_apply_mk, Trivialization.coe_coe, ← (embedding_prod_mk b).nhds_eq_comap] convert_to 𝓝 x = 𝓝 x ⊓ 𝓟 univ · congr diff --git a/Mathlib/Topology/FiberBundle/Constructions.lean b/Mathlib/Topology/FiberBundle/Constructions.lean index 01fe742ebee19..b5cac2629b8cf 100644 --- a/Mathlib/Topology/FiberBundle/Constructions.lean +++ b/Mathlib/Topology/FiberBundle/Constructions.lean @@ -138,13 +138,12 @@ theorem Prod.continuous_to_fun : ContinuousOn (Prod.toFun' e₁ e₂) have hf₁ : Continuous f₁ := (Prod.inducing_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₁ @@ -176,8 +175,7 @@ theorem Prod.right_inv {x : B × F₁ × F₂} theorem Prod.continuous_inv_fun : ContinuousOn (Prod.invFun' e₁ e₂) ((e₁.baseSet ∩ e₂.baseSet) ×ˢ univ) := by rw [(Prod.inducing_diag F₁ E₁ F₂ E₂).continuousOn_iff] - 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) + 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 _⟩⟩ @@ -226,7 +224,7 @@ variable [∀ x, Zero (E₁ x)] [∀ x, Zero (E₂ x)] [∀ x : B, TopologicalSp 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) + exact (totalSpaceMk_inducing F₁ E₁ b).prodMap (totalSpaceMk_inducing F₂ E₂ b) trivializationAtlas' := { e | ∃ (e₁ : Trivialization F₁ (π F₁ E₁)) (e₂ : Trivialization F₂ (π F₂ E₂)) (_ : MemTrivializationAtlas e₁) (_ : MemTrivializationAtlas e₂), @@ -292,7 +290,7 @@ variable [TopologicalSpace F] [TopologicalSpace B] theorem Pullback.continuous_totalSpaceMk [∀ x, TopologicalSpace (E x)] [FiberBundle F E] {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, induced_const, top_inf_eq, pullbackTopology_def] + induced_inf, Function.comp_def, induced_const, top_inf_eq, pullbackTopology_def] exact le_of_eq (FiberBundle.totalSpaceMk_inducing F E (f x)).induced variable {E F} @@ -309,7 +307,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 +315,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] @@ -330,11 +328,11 @@ noncomputable def Trivialization.pullback (e : Trivialization F (π F E)) (f : K e.continuousOn.comp (Pullback.continuous_lift F E f).continuousOn Subset.rfl) continuousOn_invFun := by dsimp only - simp_rw [(inducing_pullbackTotalSpaceEmbedding F E f).continuousOn_iff, Function.comp, + simp_rw [(inducing_pullbackTotalSpaceEmbedding F E f).continuousOn_iff, Function.comp_def, 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 diff --git a/Mathlib/Topology/FiberBundle/Trivialization.lean b/Mathlib/Topology/FiberBundle/Trivialization.lean index d5a5d504ff3af..87a1362341a73 100644 --- a/Mathlib/Topology/FiberBundle/Trivialization.lean +++ b/Mathlib/Topology/FiberBundle/Trivialization.lean @@ -74,7 +74,7 @@ variable (e : Pretrivialization F proj) {x : Z} /-- Coercion of a pretrivialization to a function. We don't use `e.toFun` in the `CoeFun` instance because it is actually `e.toPartialEquiv.toFun`, so `simp` will apply lemmas about `toPartialEquiv`. While we may want to switch to this behavior later, doing it mid-port will break a -lot of proofs. -/ +lot of proofs. -/ @[coe] def toFun' : Z → (B × F) := e.toFun instance : CoeFun (Pretrivialization F proj) fun _ => Z → B × F := ⟨toFun'⟩ @@ -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] @@ -282,7 +282,7 @@ lemma ext' (e e' : Trivialization F proj) (h₁ : e.toPartialHomeomorph = e'.toP /-- Coercion of a trivialization to a function. We don't use `e.toFun` in the `CoeFun` instance because it is actually `e.toPartialEquiv.toFun`, so `simp` will apply lemmas about `toPartialEquiv`. While we may want to switch to this behavior later, doing it mid-port will break a -lot of proofs. -/ +lot of proofs. -/ @[coe] def toFun' : Z → (B × F) := e.toFun /-- Natural identification as a `Pretrivialization`. -/ @@ -418,7 +418,7 @@ theorem preimageHomeomorph_apply {s : Set B} (hb : s ⊆ e.baseSet) (p : proj e.preimageHomeomorph hb p = (⟨proj p, p.2⟩, (e p).2) := Prod.ext (Subtype.ext (e.proj_toFun p (e.mem_source.mpr (hb p.2)))) rfl -/-- Auxilliary definition to avoid looping in `dsimp` +/-- Auxiliary definition to avoid looping in `dsimp` with `Trivialization.preimageHomeomorph_symm_apply`. -/ protected def preimageHomeomorph_symm_apply.aux {s : Set B} (hb : s ⊆ e.baseSet) := (e.preimageHomeomorph hb).symm @@ -438,7 +438,7 @@ theorem sourceHomeomorphBaseSetProd_apply (p : e.source) : e.sourceHomeomorphBaseSetProd p = (⟨proj p, e.mem_source.mp p.2⟩, (e p).2) := e.preimageHomeomorph_apply subset_rfl ⟨p, e.mem_source.mp p.2⟩ -/-- Auxilliary definition to avoid looping in `dsimp` +/-- Auxiliary definition to avoid looping in `dsimp` with `Trivialization.sourceHomeomorphBaseSetProd_symm_apply`. -/ protected def sourceHomeomorphBaseSetProd_symm_apply.aux := e.sourceHomeomorphBaseSetProd.symm @@ -465,7 +465,7 @@ theorem preimageSingletonHomeomorph_symm_apply {b : B} (hb : b ∈ e.baseSet) (p ⟨e.symm (b, p), by rw [mem_preimage, e.proj_symm_apply' hb, mem_singleton_iff]⟩ := rfl -/-- In the domain of a bundle trivialization, the projection is continuous-/ +/-- In the domain of a bundle trivialization, the projection is continuous -/ theorem continuousAt_proj (ex : x ∈ e.source) : ContinuousAt proj x := (e.map_proj_nhds ex).le @@ -475,7 +475,7 @@ protected def compHomeomorph {Z' : Type*} [TopologicalSpace Z'] (h : Z' ≃ₜ Z toPartialHomeomorph := h.toPartialHomeomorph.trans e.toPartialHomeomorph baseSet := e.baseSet open_baseSet := e.open_baseSet - source_eq := by simp [source_eq, preimage_preimage, (· ∘ ·)] + source_eq := by simp [source_eq, preimage_preimage, Function.comp_def] target_eq := by simp [target_eq] proj_toFun p hp := by have hp : h p ∈ e.source := by simpa using hp 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 abaddb408699f..17a22a272b238 100644 --- a/Mathlib/Topology/Filter.lean +++ b/Mathlib/Topology/Filter.lean @@ -71,7 +71,7 @@ theorem nhds_eq (l : Filter α) : 𝓝 l = l.lift' (Iic ∘ 𝓟) := (· ∘ ·), mem_Iic, le_principal_iff] theorem nhds_eq' (l : Filter α) : 𝓝 l = l.lift' fun s => { l' | s ∈ l' } := by - simpa only [(· ∘ ·), Iic_principal] using nhds_eq l + simpa only [Function.comp_def, Iic_principal] using nhds_eq l protected theorem tendsto_nhds {la : Filter α} {lb : Filter β} {f : α → Filter β} : Tendsto f la (𝓝 lb) ↔ ∀ s ∈ lb, ∀ᶠ a in la, s ∈ f a := by @@ -105,7 +105,7 @@ theorem mem_nhds_iff' {l : Filter α} {S : Set (Filter α)} : @[simp] theorem nhds_bot : 𝓝 (⊥ : Filter α) = pure ⊥ := by - simp [nhds_eq, (· ∘ ·), lift'_bot monotone_principal.Iic] + simp [nhds_eq, Function.comp_def, lift'_bot monotone_principal.Iic] @[simp] theorem nhds_top : 𝓝 (⊤ : Filter α) = ⊤ := by simp [nhds_eq] @@ -131,8 +131,8 @@ theorem monotone_nhds : Monotone (𝓝 : Filter α → Filter (Filter α)) := Monotone.of_map_inf nhds_inf theorem sInter_nhds (l : Filter α) : ⋂₀ { s | s ∈ 𝓝 l } = Iic l := by - simp_rw [nhds_eq, (· ∘ ·), sInter_lift'_sets monotone_principal.Iic, Iic, le_principal_iff, - ← setOf_forall, ← Filter.le_def] + simp_rw [nhds_eq, Function.comp_def, sInter_lift'_sets monotone_principal.Iic, Iic, + le_principal_iff, ← setOf_forall, ← Filter.le_def] @[simp] theorem nhds_mono {l₁ l₂ : Filter α} : 𝓝 l₁ ≤ 𝓝 l₂ ↔ l₁ ≤ l₂ := by diff --git a/Mathlib/Topology/Germ.lean b/Mathlib/Topology/Germ.lean index ea5f439b093ec..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 @@ -117,7 +114,7 @@ theorem forall_restrictGermPredicate_iff {P : ∀ x : X, Germ (𝓝 x) Y → Pro theorem forall_restrictGermPredicate_of_forall {P : ∀ x : X, Germ (𝓝 x) Y → Prop} (h : ∀ x, P x f) : ∀ x, RestrictGermPredicate P A x f := - forall_restrictGermPredicate_iff.mpr (eventually_of_forall h) + forall_restrictGermPredicate_iff.mpr (Eventually.of_forall h) end RestrictGermPredicate namespace Filter.Germ diff --git a/Mathlib/Topology/Gluing.lean b/Mathlib/Topology/Gluing.lean index 701ab09498e3c..c6d7656eb38bc 100644 --- a/Mathlib/Topology/Gluing.lean +++ b/Mathlib/Topology/Gluing.lean @@ -153,7 +153,7 @@ theorem eqvGen_of_π_eq -- Porting note: was `{x y : ∐ D.U} (h : 𝖣.π x = 𝖣.π y)` {x y : sigmaObj (β := D.toGlueData.J) (C := TopCat) D.toGlueData.U} (h : 𝖣.π x = 𝖣.π y) : - EqvGen + Relation.EqvGen -- Porting note: was (Types.CoequalizerRel 𝖣.diagram.fstSigmaMap 𝖣.diagram.sndSigmaMap) (Types.CoequalizerRel (X := sigmaObj (β := D.toGlueData.diagram.L) (C := TopCat) (D.toGlueData.diagram).left) @@ -167,10 +167,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 [← ι_preservesColimitsIso_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) _ := @@ -200,7 +198,7 @@ theorem ι_eq_iff_rel (i j : D.J) (x : D.U i) (y : D.U j) : show _ = Sigma.mk j y from ConcreteCategory.congr_hom (sigmaIsoSigma.{_, u} D.U).inv_hom_id _] change InvImage D.Rel (sigmaIsoSigma.{_, u} D.U).hom _ _ rw [← (InvImage.equivalence _ _ D.rel_equiv).eqvGen_iff] - refine EqvGen.mono ?_ (D.eqvGen_of_π_eq h : _) + refine Relation.EqvGen.mono ?_ (D.eqvGen_of_π_eq h : _) rintro _ _ ⟨x⟩ obtain ⟨⟨⟨i, j⟩, y⟩, rfl⟩ := (ConcreteCategory.bijective_of_isIso (sigmaIsoSigma.{u, u} _).inv).2 x @@ -216,8 +214,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 @@ -266,8 +263,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 @@ -342,17 +338,14 @@ instance (h : MkCore.{u}) (i j : h.J) : IsIso (h.t i j) := by /-- (Implementation) the restricted transition map to be fed into `TopCat.GlueData`. -/ def MkCore.t' (h : MkCore.{u}) (i j k : h.J) : - pullback (h.V i j).inclusion (h.V i k).inclusion ⟶ - pullback (h.V j k).inclusion (h.V j i).inclusion := by + pullback (h.V i j).inclusion' (h.V i k).inclusion' ⟶ + pullback (h.V j k).inclusion' (h.V j i).inclusion' := by refine (pullbackIsoProdSubtype _ _).hom ≫ ⟨?_, ?_⟩ ≫ (pullbackIsoProdSubtype _ _).inv · intro x 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 @@ -361,7 +354,7 @@ def mk' (h : MkCore.{u}) : TopCat.GlueData where J := h.J U := h.U V i := (Opens.toTopCat _).obj (h.V i.1 i.2) - f i j := (h.V i j).inclusion + f i j := (h.V i j).inclusion' f_id i := by -- Porting note (#12129): additional beta reduction needed beta_reduce @@ -383,7 +376,7 @@ 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 + -- The next 6 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 @@ -392,10 +385,7 @@ def mk' (h : MkCore.{u}) : TopCat.GlueData where 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 [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' @@ -410,7 +400,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 i 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 ?_ ?_ @@ -429,13 +419,13 @@ This map is an open embedding (`fromOpenSubsetsGlue_openEmbedding`), 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 x => 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`. @[simp, elementwise nosimp] theorem ι_fromOpenSubsetsGlue (i : J) : - (ofOpenSubsets U).toGlueData.ι i ≫ fromOpenSubsetsGlue U = Opens.inclusion _ := + (ofOpenSubsets U).toGlueData.ι i ≫ fromOpenSubsetsGlue U = Opens.inclusion' _ := Multicoequalizer.π_desc _ _ _ _ _ theorem fromOpenSubsetsGlue_injective : Function.Injective (fromOpenSubsetsGlue U) := by @@ -457,10 +447,10 @@ theorem fromOpenSubsetsGlue_isOpenMap : IsOpenMap (fromOpenSubsetsGlue U) := by rw [isOpen_iff_forall_mem_open] rintro _ ⟨x, hx, rfl⟩ obtain ⟨i, ⟨x, hx'⟩, rfl⟩ := (ofOpenSubsets U).ι_jointly_surjective x - use fromOpenSubsetsGlue U '' s ∩ Set.range (@Opens.inclusion (TopCat.of α) (U i)) + 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] + · rw [← Set.image_preimage_eq_inter_range] apply (Opens.openEmbedding (X := TopCat.of α) (U i)).isOpenMap convert hs i using 1 erw [← ι_fromOpenSubsetsGlue, coe_comp, Set.preimage_comp] 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 0e17099d1db0a..6d33a57317001 100644 --- a/Mathlib/Topology/Homeomorph.lean +++ b/Mathlib/Topology/Homeomorph.lean @@ -27,11 +27,11 @@ directions continuous. We denote homeomorphisms with the notation `≃ₜ`. -/ -open Set Filter +open Set Filter Function open Topology -variable {X : Type*} {Y : Type*} {Z : Type*} +variable {X Y W Z : Type*} -- not all spaces are homeomorphic to each other /-- Homeomorphism between `X` and `Y`, also called topological isomorphism -/ @@ -47,18 +47,18 @@ infixl:25 " ≃ₜ " => Homeomorph namespace Homeomorph -variable [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] +variable [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace W] [TopologicalSpace Z] {X' Y' : Type*} [TopologicalSpace X'] [TopologicalSpace Y'] 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 + 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 instance : CoeFun (X ≃ₜ Y) fun _ ↦ X → Y := ⟨DFunLike.coe⟩ @@ -308,9 +308,12 @@ protected theorem t2Space [T2Space X] (h : X ≃ₜ Y) : T2Space Y := protected theorem t3Space [T3Space X] (h : X ≃ₜ Y) : T3Space Y := h.symm.embedding.t3Space -protected theorem denseEmbedding (h : X ≃ₜ Y) : DenseEmbedding h := +theorem isDenseEmbedding (h : X ≃ₜ Y) : IsDenseEmbedding 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 @@ -404,6 +407,7 @@ theorem locallyCompactSpace_iff (h : X ≃ₜ Y) : fun _ => h.closedEmbedding.locallyCompactSpace⟩ /-- If a bijective map `e : X ≃ Y` is continuous and open, then it is a homeomorphism. -/ +@[simps toEquiv] def homeomorphOfContinuousOpen (e : X ≃ Y) (h₁ : Continuous e) (h₂ : IsOpenMap e) : X ≃ₜ Y where continuous_toFun := h₁ continuous_invFun := by @@ -413,6 +417,14 @@ def homeomorphOfContinuousOpen (e : X ≃ Y) (h₁ : Continuous e) (h₂ : IsOpe 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 + +@[simp] +theorem homeomorphOfContinuousOpen_symm_apply (e : X ≃ Y) (h₁ : Continuous e) (h₂ : IsOpenMap e) : + ⇑(homeomorphOfContinuousOpen e h₁ h₂).symm = e.symm := rfl + @[simp] theorem comp_continuousOn_iff (h : X ≃ₜ Y) (f : Z → X) (s : Set Z) : ContinuousOn (h ∘ f) s ↔ ContinuousOn f s := @@ -442,14 +454,14 @@ theorem comp_continuousWithinAt_iff (h : X ≃ₜ Y) (f : Z → X) (s : Set Z) ( 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 @@ -486,8 +498,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] @@ -499,9 +509,81 @@ theorem prodCongr_symm (h₁ : X ≃ₜ X') (h₂ : Y ≃ₜ Y') : theorem coe_prodCongr (h₁ : X ≃ₜ X') (h₂ : Y ≃ₜ Y') : ⇑(h₁.prodCongr h₂) = Prod.map h₁ h₂ := rfl -section +-- Commutativity and associativity of the disjoint union of topological spaces, +-- and the sum with an empty space. +section sum + +variable (X Y W Z) + +/-- `X ⊕ Y` is homeomorphic to `Y ⊕ X`. -/ +def sumComm : X ⊕ Y ≃ₜ Y ⊕ X where + toEquiv := Equiv.sumComm X Y + continuous_toFun := continuous_sum_swap + continuous_invFun := continuous_sum_swap + +@[simp] +theorem sumComm_symm : (sumComm X Y).symm = sumComm Y X := + rfl + +@[simp] +theorem coe_sumComm : ⇑(sumComm X Y) = Sum.swap := + rfl + +@[continuity, fun_prop] +lemma continuous_sumAssoc : Continuous (Equiv.sumAssoc X Y Z) := + Continuous.sum_elim (by fun_prop) (by fun_prop) + +@[continuity, fun_prop] +lemma continuous_sumAssoc_symm : Continuous (Equiv.sumAssoc X Y Z).symm := + Continuous.sum_elim (by fun_prop) (by fun_prop) + +/-- `(X ⊕ Y) ⊕ Z` is homeomorphic to `X ⊕ (Y ⊕ Z)`. -/ +def sumAssoc : (X ⊕ Y) ⊕ Z ≃ₜ X ⊕ Y ⊕ Z where + toEquiv := Equiv.sumAssoc X Y Z + continuous_toFun := continuous_sumAssoc X Y Z + continuous_invFun := continuous_sumAssoc_symm X Y Z + +@[simp] +lemma sumAssoc_toEquiv : (sumAssoc X Y Z).toEquiv = Equiv.sumAssoc X Y Z := rfl + +/-- Four-way commutativity of the disjoint union. The name matches `add_add_add_comm`. -/ +def sumSumSumComm : (X ⊕ Y) ⊕ W ⊕ Z ≃ₜ (X ⊕ W) ⊕ Y ⊕ Z where + toEquiv := Equiv.sumSumSumComm X Y W Z + continuous_toFun := by + unfold Equiv.sumSumSumComm + dsimp only + have : Continuous (Sum.map (Sum.map (@id X) ⇑(Equiv.sumComm Y W)) (@id Z)) := by continuity + fun_prop + continuous_invFun := by + unfold Equiv.sumSumSumComm + dsimp only + have : Continuous (Sum.map (Sum.map (@id X) (Equiv.sumComm Y W).symm) (@id Z)) := by continuity + fun_prop + +@[simp] +lemma sumSumSumComm_toEquiv : (sumSumSumComm X Y W Z).toEquiv = (Equiv.sumSumSumComm X Y W Z) := rfl -variable (X Y Z) +@[simp] +lemma sumSumSumComm_symm : (sumSumSumComm X Y W Z).symm = (sumSumSumComm X W Y Z) := rfl + +/-- The sum of `X` with any empty topological space is homeomorphic to `X`. -/ +@[simps! (config := .asFn) apply] +def sumEmpty [IsEmpty Y] : X ⊕ Y ≃ₜ X where + toEquiv := Equiv.sumEmpty X Y + continuous_toFun := Continuous.sum_elim continuous_id (by fun_prop) + continuous_invFun := continuous_inl + +/-- The sum of `X` with any empty topological space is homeomorphic to `X`. -/ +def emptySum [IsEmpty Y] : Y ⊕ X ≃ₜ X := (sumComm Y X).trans (sumEmpty X Y) + +@[simp] theorem coe_emptySum [IsEmpty Y] : (emptySum X Y).toEquiv = Equiv.emptySum Y X := rfl + +end sum + +-- Commutativity and associativity of the product of top. spaces, and the product with `PUnit`. +section prod + +variable (X Y W Z) /-- `X × Y` is homeomorphic to `Y × X`. -/ def prodComm : X × Y ≃ₜ Y × X where @@ -523,6 +605,25 @@ def prodAssoc : (X × Y) × Z ≃ₜ X × Y × Z where continuous_invFun := (continuous_fst.prod_mk continuous_snd.fst).prod_mk continuous_snd.snd toEquiv := Equiv.prodAssoc X Y Z +@[simp] +lemma prodAssoc_toEquiv : (prodAssoc X Y Z).toEquiv = Equiv.prodAssoc X Y Z := rfl + +/-- Four-way commutativity of `prod`. The name matches `mul_mul_mul_comm`. -/ +def prodProdProdComm : (X × Y) × W × Z ≃ₜ (X × W) × Y × Z where + toEquiv := Equiv.prodProdProdComm X Y W Z + continuous_toFun := by + unfold Equiv.prodProdProdComm + dsimp only + fun_prop + continuous_invFun := by + unfold Equiv.prodProdProdComm + dsimp only + fun_prop + +@[simp] +theorem prodProdProdComm_symm : (prodProdProdComm X Y W Z).symm = prodProdProdComm X W Y Z := + rfl + /-- `X × {*}` is homeomorphic to `X`. -/ @[simps! (config := .asFn) apply] def prodPUnit : X × PUnit ≃ₜ X where @@ -543,7 +644,7 @@ def homeomorphOfUnique [Unique X] [Unique Y] : X ≃ₜ Y := continuous_toFun := continuous_const continuous_invFun := continuous_const } -end +end prod /-- `Equiv.piCongrLeft` as a homeomorphism: this is the natural homeomorphism `Π i, Y (e i) ≃ₜ Π j, Y j` obtained from a bijection `ι ≃ ι'`. -/ @@ -589,12 +690,13 @@ def ulift.{u, v} {X : Type u} [TopologicalSpace X] : ULift.{v, u} X ≃ₜ X whe section Distrib /-- `(X ⊕ Y) × Z` is homeomorphic to `X × Z ⊕ Y × Z`. -/ +@[simps!] 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) := @@ -603,11 +705,12 @@ def prodSumDistrib : X × (Y ⊕ Z) ≃ₜ (X × Y) ⊕ (X × Z) := variable {ι : Type*} {X : ι → Type*} [∀ i, TopologicalSpace (X i)] /-- `(Σ i, X i) × Y` is homeomorphic to `Σ i, (X i × Y)`. -/ +@[simps! apply symm_apply toEquiv] 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 @@ -755,3 +858,108 @@ def homeoOfEquivCompactToT2 [CompactSpace X] [T2Space Y] {f : X ≃ Y} (hf : Con continuous_invFun := hf.continuous_symm_of_equiv_compact_to_t2 } end Continuous + +variable [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] + {W : Type*} [TopologicalSpace W] {f : X → Y} + +/-- Predicate saying that `f` is a homeomorphism. + +This should be used only when `f` is a concrete function whose continuous inverse is not easy to +write down. Otherwise, `Homeomorph` should be preferred as it bundles the continuous inverse. + +Having both `Homeomorph` and `IsHomeomorph` is justified by the fact that so many function +properties are unbundled in the topology part of the library, and by the fact that a homeomorphism +is not merely a continuous bijection, that is `IsHomeomorph f` is not equivalent to +`Continuous f ∧ Bijective f` but to `Continuous f ∧ Bijective f ∧ IsOpenMap f`. -/ +structure IsHomeomorph (f : X → Y) : Prop where + continuous : Continuous f + isOpenMap : IsOpenMap f + bijective : Bijective f + +protected theorem Homeomorph.isHomeomorph (h : X ≃ₜ Y) : IsHomeomorph h := + ⟨h.continuous, h.isOpenMap, h.bijective⟩ + +namespace IsHomeomorph +variable (hf : IsHomeomorph f) +include hf + +protected lemma injective : Function.Injective f := hf.bijective.injective +protected lemma surjective : Function.Surjective f := hf.bijective.surjective + +variable (f) in +/-- Bundled homeomorphism constructed from a map that is a homeomorphism. -/ +@[simps! toEquiv apply symm_apply] +noncomputable def homeomorph : X ≃ₜ Y where + continuous_toFun := hf.1 + continuous_invFun := by + rw [continuous_iff_continuousOn_univ, ← hf.bijective.2.range_eq] + exact hf.isOpenMap.continuousOn_range_of_leftInverse (leftInverse_surjInv hf.bijective) + toEquiv := Equiv.ofBijective f hf.bijective + +protected lemma isClosedMap : IsClosedMap f := (hf.homeomorph f).isClosedMap +protected lemma inducing : Inducing f := (hf.homeomorph f).inducing +protected lemma quotientMap : QuotientMap f := (hf.homeomorph f).quotientMap +protected lemma embedding : Embedding f := (hf.homeomorph f).embedding +protected lemma openEmbedding : OpenEmbedding f := (hf.homeomorph f).openEmbedding +protected lemma closedEmbedding : ClosedEmbedding f := (hf.homeomorph f).closedEmbedding +lemma isDenseEmbedding : IsDenseEmbedding f := (hf.homeomorph f).isDenseEmbedding + +@[deprecated (since := "2024-09-30")] +alias denseEmbedding := isDenseEmbedding + +end IsHomeomorph + +/-- A map is a homeomorphism iff it is the map underlying a bundled homeomorphism `h : X ≃ₜ Y`. -/ +lemma isHomeomorph_iff_exists_homeomorph : IsHomeomorph f ↔ ∃ h : X ≃ₜ Y, h = f := + ⟨fun hf => ⟨hf.homeomorph f, rfl⟩, fun ⟨h, h'⟩ => h' ▸ h.isHomeomorph⟩ + +/-- A map is a homeomorphism iff it is continuous and has a continuous inverse. -/ +lemma isHomeomorph_iff_exists_inverse : IsHomeomorph f ↔ Continuous f ∧ ∃ g : Y → X, + LeftInverse g f ∧ RightInverse g f ∧ Continuous g := by + refine ⟨fun hf ↦ ⟨hf.continuous, ?_⟩, fun ⟨hf, g, hg⟩ ↦ ?_⟩ + · let h := hf.homeomorph f + exact ⟨h.symm, h.left_inv, h.right_inv, h.continuous_invFun⟩ + · 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, + h.1.inj, h.2⟩ + +/-- 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 := + ⟨fun hf => ⟨hf.continuous, hf.isClosedMap, hf.bijective⟩, fun ⟨hf, hf', hf''⟩ => + ⟨hf, fun _ hu => isClosed_compl_iff.1 (image_compl_eq hf'' ▸ hf' _ hu.isClosed_compl), hf''⟩⟩ + +/-- A map from a compact space to a T2 space is a homeomorphism iff it is continuous and + bijective. -/ +lemma isHomeomorph_iff_continuous_bijective [CompactSpace X] [T2Space Y] : + IsHomeomorph f ↔ Continuous f ∧ Bijective f := by + rw [isHomeomorph_iff_continuous_isClosedMap_bijective] + refine and_congr_right fun hf ↦ ?_ + rw [eq_true hf.isClosedMap, true_and] + +protected lemma IsHomeomorph.id : IsHomeomorph (@id X) := ⟨continuous_id, .id, bijective_id⟩ + +lemma IsHomeomorph.comp {g : Y → Z} (hg : IsHomeomorph g) (hf : IsHomeomorph f) : + IsHomeomorph (g ∘ f) := ⟨hg.1.comp hf.1, hg.2.comp hf.2, hg.3.comp hf.3⟩ + +lemma IsHomeomorph.sumMap {g : Z → W} (hf : IsHomeomorph f) (hg : IsHomeomorph g) : + 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.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⟩ + +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)) : + IsHomeomorph (fun (x : ∀ i, X i) i ↦ f i (x i)) := + (Homeomorph.piCongrRight fun i ↦ (h i).homeomorph (f i)).isHomeomorph diff --git a/Mathlib/Topology/Homotopy/Basic.lean b/Mathlib/Topology/Homotopy/Basic.lean index 75273bcf06755..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 @@ -160,7 +160,6 @@ theorem extend_apply_of_one_le (F : Homotopy f₀ f₁) {t : ℝ} (ht : 1 ≤ t) rw [← F.apply_one] exact ContinuousMap.congr_fun (Set.IccExtend_of_right_le (zero_le_one' ℝ) F.curry ht) x -@[simp] theorem extend_apply_coe (F : Homotopy f₀ f₁) (t : I) (x : X) : F.extend t x = F (t, x) := ContinuousMap.congr_fun (Set.IccExtend_val (zero_le_one' ℝ) F.curry t) x diff --git a/Mathlib/Topology/Homotopy/HSpaces.lean b/Mathlib/Topology/Homotopy/HSpaces.lean index b6ecf5d805502..15648773fa822 100644 --- a/Mathlib/Topology/Homotopy/HSpaces.lean +++ b/Mathlib/Topology/Homotopy/HSpaces.lean @@ -170,7 +170,7 @@ theorem qRight_zero_left (θ : I) : qRight (0, θ) = 0 := theorem qRight_one_left (θ : I) : qRight (1, θ) = 1 := Set.projIcc_of_right_le _ <| - (le_div_iff <| add_pos zero_lt_one).2 <| by + (le_div_iff₀ <| add_pos zero_lt_one).2 <| by dsimp only rw [coe_one, one_mul, mul_one, add_comm, ← one_add_one_eq_two] simp only [add_le_add_iff_right] diff --git a/Mathlib/Topology/Homotopy/HomotopyGroup.lean b/Mathlib/Topology/Homotopy/HomotopyGroup.lean index 93fad3a1199db..daaa41db02500 100644 --- a/Mathlib/Topology/Homotopy/HomotopyGroup.lean +++ b/Mathlib/Topology/Homotopy/HomotopyGroup.lean @@ -185,7 +185,7 @@ 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.prodMap (ContinuousMap.continuous_curry.comp <| (ContinuousMap.continuous_comp_left _).comp continuous_subtype_val) continuous_id) diff --git a/Mathlib/Topology/Inseparable.lean b/Mathlib/Topology/Inseparable.lean index d2089d77aed05..a179072f0d072 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 @@ -358,7 +354,7 @@ lemma specializingMap_iff_isClosed_image_closure_singleton (hf : Continuous f) : exact isClosed_closure lemma IsClosedMap.specializingMap (hf : IsClosedMap f) : SpecializingMap f := - specializingMap_iff_stableUnderSpecialization_image_singleton.mpr $ + specializingMap_iff_stableUnderSpecialization_image_singleton.mpr <| fun _ ↦ (hf _ isClosed_closure).stableUnderSpecialization lemma Inducing.specializingMap (hf : Inducing f) (h : StableUnderSpecialization (range f)) : @@ -541,6 +537,10 @@ instance [Inhabited X] : Inhabited (SeparationQuotient X) := instance [Subsingleton X] : Subsingleton (SeparationQuotient X) := surjective_mk.subsingleton +@[to_additive] instance [One X] : One (SeparationQuotient X) := ⟨mk 1⟩ + +@[to_additive (attr := simp)] theorem mk_one [One X] : mk (1 : X) = 1 := rfl + theorem preimage_image_mk_open (hs : IsOpen s) : mk ⁻¹' (mk '' s) = s := by refine Subset.antisymm ?_ (subset_preimage_image _ _) rintro x ⟨y, hys, hxy⟩ @@ -549,6 +549,9 @@ theorem preimage_image_mk_open (hs : IsOpen s) : mk ⁻¹' (mk '' s) = s := by theorem isOpenMap_mk : IsOpenMap (mk : X → SeparationQuotient X) := fun s hs => quotientMap_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⟩ @@ -600,14 +603,8 @@ 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 quotientMap_prodMap_mk : QuotientMap (Prod.map mk mk : X × Y → _) := + (isOpenQuotientMap_mk.prodMap isOpenQuotientMap_mk).quotientMap /-- Lift a map `f : X → α` such that `Inseparable x y → f x = f y` to a map `SeparationQuotient X → α`. -/ diff --git a/Mathlib/Topology/Instances/AddCircle.lean b/Mathlib/Topology/Instances/AddCircle.lean index 988b0aced090f..3295ee564f992 100644 --- a/Mathlib/Topology/Instances/AddCircle.lean +++ b/Mathlib/Topology/Instances/AddCircle.lean @@ -112,7 +112,6 @@ theorem continuousAt_toIocMod (hx : (x : 𝕜 ⧸ zmultiples p) ≠ a) : Continu end Continuity /-- The "additive circle": `𝕜 ⧸ (ℤ ∙ p)`. See also `Circle` and `Real.angle`. -/ -@[nolint unusedArguments] abbrev AddCircle [LinearOrderedAddCommGroup 𝕜] (p : 𝕜) := 𝕜 ⧸ zmultiples p @@ -462,7 +461,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] diff --git a/Mathlib/Topology/Instances/Complex.lean b/Mathlib/Topology/Instances/Complex.lean index d3dad6f31c97f..717f60129dd83 100644 --- a/Mathlib/Topology/Instances/Complex.lean +++ b/Mathlib/Topology/Instances/Complex.lean @@ -5,10 +5,10 @@ Authors: Xavier Roblot -/ import Mathlib.Analysis.Complex.Basic import Mathlib.Data.Complex.FiniteDimensional -import Mathlib.FieldTheory.IntermediateField import Mathlib.LinearAlgebra.FiniteDimensional import Mathlib.Topology.Algebra.Field import Mathlib.Topology.Algebra.UniformRing +import Mathlib.FieldTheory.IntermediateField.Basic /-! # Some results about the topology of ℂ @@ -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,13 +52,13 @@ 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 @@ -76,7 +76,7 @@ theorem Complex.uniformContinuous_ringHom_eq_id_or_conj (K : Subfield ℂ) {ψ : -- 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 + · exact (IsDenseInducing.extend_eq di hc.continuous _).symm · rw [← ofReal.coe_rangeRestrict, hr] rfl obtain ⟨r, hr⟩ := SetLike.coe_mem (j (ι x)) @@ -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/Discrete.lean b/Mathlib/Topology/Instances/Discrete.lean index b937256b9520c..3a0fe98aa800a 100644 --- a/Mathlib/Topology/Instances/Discrete.lean +++ b/Mathlib/Topology/Instances/Discrete.lean @@ -5,7 +5,6 @@ Authors: Rémy Degenne -/ import Mathlib.Order.SuccPred.Basic import Mathlib.Topology.Order.Basic -import Mathlib.Topology.Metrizable.Uniformity /-! # Instances related to the discrete topology @@ -43,7 +42,7 @@ theorem DiscreteTopology.secondCountableTopology_of_encodable {α : Type*} [TopologicalSpace α] [DiscreteTopology α] [Countable α] : SecondCountableTopology α := DiscreteTopology.secondCountableTopology_of_countable -theorem bot_topologicalSpace_eq_generateFrom_of_pred_succOrder {α} [PartialOrder α] [PredOrder α] +theorem bot_topologicalSpace_eq_generateFrom_of_pred_succOrder {α} [LinearOrder α] [PredOrder α] [SuccOrder α] [NoMinOrder α] [NoMaxOrder α] : (⊥ : TopologicalSpace α) = generateFrom { s | ∃ a, s = Ioi a ∨ s = Iio a } := by refine (eq_bot_of_singletons_open fun a => ?_).symm @@ -57,7 +56,7 @@ theorem bot_topologicalSpace_eq_generateFrom_of_pred_succOrder {α} [PartialOrde · exact isOpen_generateFrom_of_mem ⟨succ a, Or.inr rfl⟩ · exact isOpen_generateFrom_of_mem ⟨pred a, Or.inl rfl⟩ -theorem discreteTopology_iff_orderTopology_of_pred_succ' [PartialOrder α] [PredOrder α] +theorem discreteTopology_iff_orderTopology_of_pred_succ' [LinearOrder α] [PredOrder α] [SuccOrder α] [NoMinOrder α] [NoMaxOrder α] : DiscreteTopology α ↔ OrderTopology α := by refine ⟨fun h => ⟨?_⟩, fun h => ⟨?_⟩⟩ · rw [h.eq_bot] @@ -66,7 +65,7 @@ theorem discreteTopology_iff_orderTopology_of_pred_succ' [PartialOrder α] [Pred exact bot_topologicalSpace_eq_generateFrom_of_pred_succOrder.symm instance (priority := 100) DiscreteTopology.orderTopology_of_pred_succ' [h : DiscreteTopology α] - [PartialOrder α] [PredOrder α] [SuccOrder α] [NoMinOrder α] [NoMaxOrder α] : OrderTopology α := + [LinearOrder α] [PredOrder α] [SuccOrder α] [NoMinOrder α] [NoMaxOrder α] : OrderTopology α := discreteTopology_iff_orderTopology_of_pred_succ'.1 h theorem LinearOrder.bot_topologicalSpace_eq_generateFrom {α} [LinearOrder α] [PredOrder α] @@ -110,8 +109,3 @@ theorem discreteTopology_iff_orderTopology_of_pred_succ [LinearOrder α] [PredOr instance (priority := 100) DiscreteTopology.orderTopology_of_pred_succ [h : DiscreteTopology α] [LinearOrder α] [PredOrder α] [SuccOrder α] : OrderTopology α := discreteTopology_iff_orderTopology_of_pred_succ.mp h - -instance (priority := 100) DiscreteTopology.metrizableSpace [DiscreteTopology α] : - MetrizableSpace α := by - obtain rfl := DiscreteTopology.eq_bot (α := α) - exact @UniformSpace.metrizableSpace α ⊥ (isCountablyGenerated_principal _) _ diff --git a/Mathlib/Topology/Instances/ENNReal.lean b/Mathlib/Topology/Instances/ENNReal.lean index 7d4f1adcd31f9..5623966b95601 100644 --- a/Mathlib/Topology/Instances/ENNReal.lean +++ b/Mathlib/Topology/Instances/ENNReal.lean @@ -9,6 +9,8 @@ import Mathlib.Topology.Instances.NNReal import Mathlib.Topology.EMetricSpace.Lipschitz import Mathlib.Topology.Metrizable.Basic import Mathlib.Topology.Order.T5 +import Mathlib.Topology.MetricSpace.Pseudo.Real +import Mathlib.Topology.Metrizable.Uniformity /-! # Topology on extended non-negative reals @@ -89,7 +91,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 + ((openEmbedding_coe.prodMap openEmbedding_coe).map_nhds_eq (r, p)).symm theorem continuous_ofReal : Continuous ENNReal.ofReal := (continuous_coe_iff.2 continuous_id).comp continuous_real_toNNReal @@ -265,8 +267,8 @@ instance : ContinuousAdd ℝ≥0∞ := by · exact tendsto_nhds_top_mono' continuousAt_fst fun p => le_add_right le_rfl rcases b with (_ | b) · exact tendsto_nhds_top_mono' continuousAt_snd fun p => le_add_left le_rfl - simp only [ContinuousAt, some_eq_coe, nhds_coe_coe, ← coe_add, tendsto_map'_iff, (· ∘ ·), - tendsto_coe, tendsto_add] + simp only [ContinuousAt, some_eq_coe, nhds_coe_coe, ← coe_add, tendsto_map'_iff, + Function.comp_def, tendsto_coe, tendsto_add] protected theorem tendsto_atTop_zero [Nonempty β] [SemilatticeSup β] {f : β → ℝ≥0∞} : Tendsto f atTop (𝓝 0) ↔ ∀ ε > 0, ∃ N, ∀ n ≥ N, f n ≤ ε := @@ -289,7 +291,7 @@ theorem tendsto_sub : ∀ {a b : ℝ≥0∞}, (a ≠ ∞ ∨ b ≠ ∞) → (lt_mem_nhds <| @coe_lt_top (a + 1))).mono fun x hx => tsub_eq_zero_iff_le.2 (hx.1.trans hx.2).le | (a : ℝ≥0), (b : ℝ≥0), _ => by - simp only [nhds_coe_coe, tendsto_map'_iff, ← ENNReal.coe_sub, (· ∘ ·), tendsto_coe] + simp only [nhds_coe_coe, tendsto_map'_iff, ← ENNReal.coe_sub, Function.comp_def, tendsto_coe] exact continuous_sub.tendsto (a, b) protected theorem Tendsto.sub {f : Filter α} {ma : α → ℝ≥0∞} {mb : α → ℝ≥0∞} {a b : ℝ≥0∞} @@ -314,10 +316,11 @@ protected theorem tendsto_mul (ha : a ≠ 0 ∨ b ≠ ∞) (hb : b ≠ 0 ∨ a induction b with | top => simp only [ne_eq, or_false, not_true_eq_false] at ha - simpa [(· ∘ ·), mul_comm, mul_top ha] + simpa [Function.comp_def, mul_comm, mul_top ha] using (ht a ha).comp (continuous_swap.tendsto (ofNNReal a, ∞)) | coe b => - simp only [nhds_coe_coe, ← coe_mul, tendsto_coe, tendsto_map'_iff, (· ∘ ·), tendsto_mul] + simp only [nhds_coe_coe, ← coe_mul, tendsto_coe, tendsto_map'_iff, Function.comp_def, + tendsto_mul] protected theorem Tendsto.mul {f : Filter α} {ma : α → ℝ≥0∞} {mb : α → ℝ≥0∞} {a b : ℝ≥0∞} (hma : Tendsto ma f (𝓝 a)) (ha : a ≠ 0 ∨ b ≠ ∞) (hmb : Tendsto mb f (𝓝 b)) @@ -354,7 +357,7 @@ theorem tendsto_finset_prod_of_ne_top {ι : Type*} {f : ι → α → ℝ≥0∞ simp only [Finset.prod_insert has] apply Tendsto.mul (h _ (Finset.mem_insert_self _ _)) · right - exact (prod_lt_top fun i hi => h' _ (Finset.mem_insert_of_mem hi)).ne + exact prod_ne_top fun i hi => h' _ (Finset.mem_insert_of_mem hi) · exact IH (fun i hi => h _ (Finset.mem_insert_of_mem hi)) fun i hi => h' _ (Finset.mem_insert_of_mem hi) · exact Or.inr (h' _ (Finset.mem_insert_self _ _)) @@ -387,11 +390,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 @@ -403,7 +406,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 @@ -420,7 +423,7 @@ theorem continuous_sub_right (a : ℝ≥0∞) : Continuous fun x : ℝ≥0∞ => · 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)) := @@ -430,36 +433,30 @@ theorem le_of_forall_lt_one_mul_le {x y : ℝ≥0∞} (h : ∀ a < 1, a * x ≤ have : Tendsto (· * x) (𝓝[<] 1) (𝓝 (1 * x)) := (ENNReal.continuousAt_mul_const (Or.inr one_ne_zero)).mono_left inf_le_left rw [one_mul] at this - exact le_of_tendsto this (eventually_nhdsWithin_iff.2 <| eventually_of_forall h) + 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_iInf_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 @@ -501,115 +498,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_iSup_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_iSup_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⟩ : @@ -617,19 +509,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) @@ -802,7 +682,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 @@ -1166,7 +1046,7 @@ theorem tsum_comp_le_tsum_of_inj {β : Type*} {f : α → ℝ} (hf : Summable f) {i : β → α} (hi : Function.Injective i) : tsum (f ∘ i) ≤ tsum f := by lift f to α → ℝ≥0 using hn rw [NNReal.summable_coe] at hf - simpa only [(· ∘ ·), ← NNReal.coe_tsum] using NNReal.tsum_comp_le_tsum_of_inj hf hi + simpa only [Function.comp_def, ← NNReal.coe_tsum] using NNReal.tsum_comp_le_tsum_of_inj hf hi /-- Comparison test of convergence of series of non-negative real numbers. -/ theorem Summable.of_nonneg_of_le {f g : β → ℝ} (hg : ∀ b, 0 ≤ g b) (hgf : ∀ b, g b ≤ f b) @@ -1233,7 +1113,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. -/ @@ -1457,9 +1337,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∞) : @@ -1467,14 +1349,14 @@ 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 @@ -1497,7 +1379,7 @@ lemma liminf_toReal_eq {ι : Type*} {F : Filter ι} [NeBot F] {b : ℝ≥0∞} ( have key := Monotone.map_liminf_of_continuousAt (F := F) (monotone_truncateToReal b_ne_top) xs (continuous_truncateToReal b_ne_top).continuousAt (IsBoundedUnder.isCoboundedUnder_ge ⟨b, by simpa only [eventually_map] using le_b⟩) - ⟨0, eventually_of_forall (by simp)⟩ + ⟨0, Eventually.of_forall (by simp)⟩ rw [key] rfl @@ -1514,7 +1396,7 @@ lemma limsup_toReal_eq {ι : Type*} {F : Filter ι} [NeBot F] {b : ℝ≥0∞} ( have key := Monotone.map_limsup_of_continuousAt (F := F) (monotone_truncateToReal b_ne_top) xs (continuous_truncateToReal b_ne_top).continuousAt ⟨b, by simpa only [eventually_map] using le_b⟩ - (IsBoundedUnder.isCoboundedUnder_le ⟨0, eventually_of_forall (by simp)⟩) + (IsBoundedUnder.isCoboundedUnder_le ⟨0, Eventually.of_forall (by simp)⟩) rw [key] rfl diff --git a/Mathlib/Topology/Instances/ENat.lean b/Mathlib/Topology/Instances/ENat.lean new file mode 100644 index 0000000000000..ee7773df5b64b --- /dev/null +++ b/Mathlib/Topology/Instances/ENat.lean @@ -0,0 +1,126 @@ +/- +Copyright (c) 2022 Peter Nelson. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Peter Nelson +-/ +import Mathlib.Data.ENat.Basic +import Mathlib.Topology.Algebra.Monoid +import Mathlib.Topology.Instances.Discrete +import Mathlib.Order.Interval.Set.WithBotTop + +/-! +# Topology on extended natural numbers +-/ + +open Set Filter +open scoped Topology + +namespace ENat + +/-- +Topology on `ℕ∞`. + +Note: this is different from the `EMetricSpace` topology. The `EMetricSpace` topology has +`IsOpen {∞}`, but all neighborhoods of `∞` in `ℕ∞` contain infinite intervals. +-/ +instance : TopologicalSpace ℕ∞ := Preorder.topology ℕ∞ + +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 openEmbedding_natCast : OpenEmbedding ((↑) : ℕ → ℕ∞) := + ⟨embedding_natCast, range_natCast ▸ isOpen_Iio⟩ + +theorem nhds_natCast (n : ℕ) : 𝓝 (n : ℕ∞) = pure (n : ℕ∞) := by + simp [← openEmbedding_natCast.map_nhds_eq] + +@[simp] +protected theorem nhds_eq_pure {n : ℕ∞} (h : n ≠ ⊤) : 𝓝 n = pure n := by + lift n to ℕ using h + simp [nhds_natCast] + +theorem isOpen_singleton {x : ℕ∞} (hx : x ≠ ⊤) : IsOpen {x} := by + rw [isOpen_singleton_iff_nhds_eq_pure, ENat.nhds_eq_pure hx] + +theorem mem_nhds_iff {x : ℕ∞} {s : Set ℕ∞} (hx : x ≠ ⊤) : s ∈ 𝓝 x ↔ x ∈ s := by + simp [hx] + +theorem mem_nhds_natCast_iff (n : ℕ) {s : Set ℕ∞} : s ∈ 𝓝 (n : ℕ∞) ↔ (n : ℕ∞) ∈ s := + mem_nhds_iff (coe_ne_top _) + +theorem tendsto_nhds_top_iff_natCast_lt {α : Type*} {l : Filter α} {f : α → ℕ∞} : + Tendsto f l (𝓝 ⊤) ↔ ∀ n : ℕ, ∀ᶠ a in l, n < f a := by + simp_rw [nhds_top_order, lt_top_iff_ne_top, tendsto_iInf, tendsto_principal] + exact Option.ball_ne_none + +instance : ContinuousAdd ℕ∞ := by + refine ⟨continuous_iff_continuousAt.2 fun (a, b) ↦ ?_⟩ + match a, b with + | ⊤, _ => exact tendsto_nhds_top_mono' continuousAt_fst fun p ↦ le_add_right le_rfl + | (a : ℕ), ⊤ => exact tendsto_nhds_top_mono' continuousAt_snd fun p ↦ le_add_left le_rfl + | (a : ℕ), (b : ℕ) => simp [ContinuousAt, nhds_prod_eq, tendsto_pure_nhds] + +instance : ContinuousMul ℕ∞ where + continuous_mul := + have key (a : ℕ∞) : ContinuousAt (· * ·).uncurry (a, ⊤) := by + rcases (zero_le a).eq_or_gt with rfl | ha + · simp [ContinuousAt, nhds_prod_eq] + · simp only [ContinuousAt, Function.uncurry, mul_top ha.ne'] + refine tendsto_nhds_top_mono continuousAt_snd ?_ + filter_upwards [continuousAt_fst (lt_mem_nhds ha)] with (x, y) (hx : 0 < x) + exact le_mul_of_one_le_left (zero_le y) (Order.one_le_iff_pos.2 hx) + continuous_iff_continuousAt.2 <| Prod.forall.2 fun + | (a : ℕ∞), ⊤ => key a + | ⊤, (b : ℕ∞) => + ((key b).comp_of_eq (continuous_swap.tendsto (⊤, b)) rfl).congr <| + .of_forall fun _ ↦ mul_comm .. + | (a : ℕ), (b : ℕ) => by + simp [ContinuousAt, nhds_prod_eq, tendsto_pure_nhds] + +protected theorem continuousAt_sub {a b : ℕ∞} (h : a ≠ ⊤ ∨ b ≠ ⊤) : + ContinuousAt (· - ·).uncurry (a, b) := by + match a, b, h with + | (a : ℕ), (b : ℕ), _ => + simpa [ContinuousAt, nhds_prod_eq] using tendsto_pure_nhds _ _ + | (a : ℕ), ⊤, _ => + suffices ∀ᶠ b in 𝓝 ⊤, (a - b : ℕ∞) = 0 by + simpa [ContinuousAt, nhds_prod_eq] + 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 + simpa [ContinuousAt, nhds_prod_eq, (· ∘ ·), lt_tsub_iff_left, tendsto_nhds_top_iff_natCast_lt] + exact fun n ↦ lt_mem_nhds <| WithTop.coe_lt_top (b + n) + +end ENat + +theorem Filter.Tendsto.enatSub {α : Type*} {l : Filter α} {f g : α → ℕ∞} {a b : ℕ∞} + (hf : Tendsto f l (𝓝 a)) (hg : Tendsto g l (𝓝 b)) (h : a ≠ ⊤ ∨ b ≠ ⊤) : + Tendsto (fun x ↦ f x - g x) l (𝓝 (a - b)) := + (ENat.continuousAt_sub h).tendsto.comp (hf.prod_mk_nhds hg) + +variable {X : Type*} [TopologicalSpace X] {f g : X → ℕ∞} {s : Set X} {x : X} + +nonrec theorem ContinuousWithinAt.enatSub + (hf : ContinuousWithinAt f s x) (hg : ContinuousWithinAt g s x) (h : f x ≠ ⊤ ∨ g x ≠ ⊤) : + ContinuousWithinAt (fun x ↦ f x - g x) s x := + hf.enatSub hg h + +nonrec theorem ContinuousAt.enatSub + (hf : ContinuousAt f x) (hg : ContinuousAt g x) (h : f x ≠ ⊤ ∨ g x ≠ ⊤) : + ContinuousAt (fun x ↦ f x - g x) x := + hf.enatSub hg h + +nonrec theorem ContinuousOn.enatSub + (hf : ContinuousOn f s) (hg : ContinuousOn g s) (h : ∀ x ∈ s, f x ≠ ⊤ ∨ g x ≠ ⊤) : + ContinuousOn (fun x ↦ f x - g x) s := fun x hx ↦ + (hf x hx).enatSub (hg x hx) (h x hx) + +nonrec theorem Continuous.enatSub + (hf : Continuous f) (hg : Continuous g) (h : ∀ x, f x ≠ ⊤ ∨ g x ≠ ⊤) : + Continuous (fun x ↦ f x - g x) := + continuous_iff_continuousAt.2 fun x ↦ hf.continuousAt.enatSub hg.continuousAt (h x) diff --git a/Mathlib/Topology/Instances/EReal.lean b/Mathlib/Topology/Instances/EReal.lean index 9da4bbc6a3b9b..4d970aa153cb8 100644 --- a/Mathlib/Topology/Instances/EReal.lean +++ b/Mathlib/Topology/Instances/EReal.lean @@ -70,7 +70,7 @@ theorem nhds_coe {r : ℝ} : 𝓝 (r : EReal) = (𝓝 r).map (↑) := 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 + ((openEmbedding_coe.prodMap openEmbedding_coe).map_nhds_eq (r, p)).symm theorem tendsto_toReal {a : EReal} (ha : a ≠ ⊤) (h'a : a ≠ ⊥) : Tendsto EReal.toReal (𝓝 a) (𝓝 a.toReal) := by @@ -145,84 +145,67 @@ 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] -/-! ### Liminfs and Limsups -/ +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 -section LimInfSup +lemma tendsto_toReal_atBot : Tendsto EReal.toReal (𝓝[≠] ⊥) atBot := by + rw [nhdsWithin_bot, tendsto_map'_iff] + exact tendsto_id -variable {α : Type*} {f : Filter α} {u v : α → EReal} {a b : EReal} +/-! ### Infs and Sups -/ -lemma liminf_le_liminf (h : u ≤ᶠ[f] v) : - liminf u f ≤ liminf v f := Filter.liminf_le_liminf h +variable {α : Type*} {u v : α → EReal} -lemma limsup_le_limsup (h : u ≤ᶠ[f] v) : - limsup u f ≤ limsup v f := Filter.limsup_le_limsup h +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 -/-- This lemma is superseded by `limsup_add_le_of_le` (weaker hypothesis) and -`limsup_add_lt_of_lt` (stronger thesis). -/ -private lemma limsup_add_le_of_lt (ha : limsup u f < a) (hb : limsup v f < b) : - limsup (u + v) f ≤ a + b := by - rcases eq_or_neBot f with (rfl | _) - · simp only [limsup_bot, bot_le] - rw [← @limsup_const EReal α _ f _ (a + b)] - apply limsup_le_limsup (Eventually.mp (Eventually.and (eventually_lt_of_limsup_lt ha) - (eventually_lt_of_limsup_lt hb)) (eventually_of_forall _)) - simp only [Pi.add_apply, and_imp] - intro x - exact fun ux_lt_a vx_lt_b ↦ add_le_add (le_of_lt ux_lt_a) (le_of_lt vx_lt_b) +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 limsup_add_lt_of_lt (ha : limsup u f < a) (hb : limsup v f < b) : - limsup (u + v) f < a + b := by - obtain ⟨c, hc, hca⟩ := DenselyOrdered.dense _ _ ha - obtain ⟨d, hd, hdb⟩ := DenselyOrdered.dense _ _ hb - exact (limsup_add_le_of_lt hc hd).trans_lt (add_lt_add hca hdb) +/-! ### Liminfs and Limsups -/ -lemma limsup_add_bot_of_ne_top (h : limsup u f = ⊥) (h' : limsup v f ≠ ⊤) : - limsup (u + v) f = ⊥ := by - apply le_bot_iff.1 - apply (le_iff_le_forall_real_gt ⊥ (limsup (u + v) f)).1 - intro x - rcases exists_between_coe_real (h'.lt_top) with ⟨y, ⟨hy, _⟩⟩ - rw [← sub_add_cancel x y, coe_add (x - y) y, coe_sub x y] - intro _ - apply @limsup_add_le_of_lt α f u v (x - y) y _ hy - rw [h, ← coe_sub x y] - exact bot_lt_coe (x - y) - -lemma limsup_add_le_add_limsup - (h : limsup u f ≠ ⊥ ∨ limsup v f ≠ ⊤) (h' : limsup u f ≠ ⊤ ∨ limsup v f ≠ ⊥) : - limsup (u + v) f ≤ (limsup u f) + (limsup v f) := by - rcases eq_bot_or_bot_lt (limsup u f) with (u_bot | u_nbot) - · have v_ntop := h.neg_resolve_left u_bot - rw [limsup_add_bot_of_ne_top u_bot v_ntop]; exact bot_le - rcases eq_bot_or_bot_lt (limsup v f) with (v_bot | v_nbot) - · have u_ntop := h'.neg_resolve_right v_bot - rw [add_comm, limsup_add_bot_of_ne_top v_bot u_ntop]; exact bot_le - rcases eq_top_or_lt_top (limsup v f) with (v_top | v_ntop) - · rw [v_top, add_top_of_ne_bot (ne_of_gt u_nbot)]; exact le_top - have limsup_v_real := coe_toReal (ne_of_lt v_ntop) (ne_of_gt v_nbot) - apply (le_iff_le_forall_real_gt _ _).1 - intros x hx - rcases lt_iff_exists_real_btwn.1 hx with ⟨y, ⟨sum_lt_y, y_lt_x⟩⟩ - have key₁ : limsup u f < (y - limsup v f) := by - apply lt_of_eq_of_lt _ (sub_lt_sub_of_lt_of_le sum_lt_y (le_of_eq (Eq.refl (limsup v f))) - (ne_of_gt v_nbot) (ne_of_lt v_ntop)) - rw [← limsup_v_real, add_sub_cancel_right] - have key₂ : limsup v f < limsup v f + x - y := by - rw [← limsup_v_real]; norm_cast; norm_cast at y_lt_x; linarith - apply le_of_le_of_eq (limsup_add_le_of_lt key₁ key₂) - rw [← limsup_v_real]; norm_cast; linarith +section LimInfSup -lemma limsup_add_le_of_le (ha : limsup u f < a) (hb : limsup v f ≤ b) : - limsup (u + v) f ≤ a + b := by - rcases lt_or_eq_of_le hb with (hb | hb) - · exact limsup_add_le_of_lt ha hb - by_cases hb' : b = ⊤ - · convert le_top - on_goal 1 => rw [hb'] - -- This closes both remaining goals at once. - exact add_top_of_ne_bot ha.ne_bot - exact (limsup_add_le_add_limsup (hb ▸ Or.inr hb') (Or.inl ha.ne_top)).trans - (add_le_add ha.le hb.le) +variable {α : Type*} {f : Filter α} {u v : α → EReal} lemma liminf_neg : liminf (- v) f = - limsup v f := EReal.negOrderIso.limsup_apply.symm @@ -230,58 +213,64 @@ lemma liminf_neg : liminf (- v) f = - limsup v f := lemma limsup_neg : limsup (- v) f = - liminf v f := EReal.negOrderIso.liminf_apply.symm +lemma add_liminf_le_liminf_add : (liminf u f) + (liminf v f) ≤ liminf (u + v) f := by + refine add_le_of_forall_add_le 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 lt_trans c_ab (add_lt_add a_x b_x) + +lemma limsup_add_le_add_limsup (h : limsup u f ≠ ⊥ ∨ limsup v f ≠ ⊤) + (h' : limsup u f ≠ ⊤ ∨ limsup v f ≠ ⊥) : + limsup (u + v) f ≤ (limsup u f) + (limsup v f) := by + refine le_add_of_forall_le_add 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 (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 ↦ + 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 ↦ + 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 + +variable {a b : EReal} + +lemma limsup_add_bot_of_ne_top (h : limsup u f = ⊥) (h' : limsup v f ≠ ⊤) : + limsup (u + v) f = ⊥ := by + apply le_bot_iff.1 (le_trans (limsup_add_le_add_limsup (Or.inr h') _) _) + · rw [h]; exact Or.inl bot_ne_top + · rw [h, bot_add] + +lemma limsup_add_le_of_le (ha : limsup u f < a) (hb : limsup v f ≤ b) : + limsup (u + v) f ≤ a + b := by + rcases eq_top_or_lt_top b with (rfl | h) + · rw [add_top_of_ne_bot ha.ne_bot]; exact le_top + · exact le_trans (limsup_add_le_add_limsup (Or.inr (lt_of_le_of_lt hb h).ne) (Or.inl ha.ne_top)) + (add_le_add ha.le hb) + lemma liminf_add_gt_of_gt (ha : a < liminf u f) (hb : b < liminf v f) : - a + b < liminf (u + v) f := by - have ha' : a ≠ ⊤ := ha.ne_top - have hb' : b ≠ ⊤ := hb.ne_top - have h : limsup (-(u + v)) f = limsup (-u + -v) f := by - apply limsup_congr - filter_upwards [eventually_lt_of_lt_liminf ha, eventually_lt_of_lt_liminf hb] with x hax hbx - dsimp - rw [neg_add (Or.inl hax.ne_bot) (Or.inr hbx.ne_bot), sub_eq_add_neg] - rw [← neg_lt_neg_iff, ← limsup_neg] at ha hb ⊢ - rw [neg_add (Or.inr hb') (Or.inl ha'), h] - exact limsup_add_lt_of_lt ha hb + a + b < liminf (u + v) f := + lt_of_lt_of_le (add_lt_add ha hb) add_liminf_le_liminf_add lemma liminf_add_top_of_ne_bot (h : liminf u f = ⊤) (h' : liminf v f ≠ ⊥) : liminf (u + v) f = ⊤ := by - apply top_le_iff.1 ((ge_iff_le_forall_real_lt (liminf (u + v) f) ⊤).1 _) - intro x - rcases exists_between_coe_real (Ne.bot_lt h') with ⟨y, ⟨_, hy⟩⟩ - intro _ - rw [← sub_add_cancel x y, coe_add (x - y) y] - exact coe_sub x y ▸ @liminf_add_gt_of_gt α f u v (x - y) y - (h ▸ coe_sub x y ▸ coe_lt_top (x-y)) hy |>.le - -lemma add_liminf_le_liminf_add : (liminf u f) + (liminf v f) ≤ liminf (u + v) f := by - by_cases hu : liminf u f = ⊥ - · simp_all - by_cases hv : liminf v f = ⊥ - · simp_all - have h' : limsup (-(u + v)) f = limsup (-u + -v) f := by - apply limsup_congr - filter_upwards [eventually_lt_of_lt_liminf (bot_lt_iff_ne_bot.mpr hu), - eventually_lt_of_lt_liminf (bot_lt_iff_ne_bot.mpr hv)] with x hux hvx - dsimp - rw [neg_add (Or.inl hux.ne_bot) (Or.inr hvx.ne_bot), sub_eq_add_neg] - rw [← neg_le_neg_iff, neg_add (Or.inl hu) (Or.inr hv), sub_eq_add_neg] - rw [← neg_inj, neg_bot] at hu hv - simp_rw [← limsup_neg] at hu hv ⊢ - exact h' ▸ limsup_add_le_add_limsup (Or.inr hv) (Or.inl hu) + apply top_le_iff.1 (le_trans _ (add_liminf_le_liminf_add)) + rw [h, top_add_of_ne_bot h'] lemma limsup_le_iff {b : EReal} : limsup u f ≤ b ↔ ∀ c : ℝ, b < c → ∀ᶠ a : α in f, u a ≤ c := by - rw [← le_iff_le_forall_real_gt] - refine ⟨?_, ?_⟩ <;> intro h c b_lt_c - · rcases exists_between_coe_real b_lt_c with ⟨d, b_lt_d, d_lt_c⟩ - specialize h d b_lt_d - have key := Filter.eventually_lt_of_limsup_lt (lt_of_le_of_lt h d_lt_c) - apply Filter.mem_of_superset key + rw [← le_of_forall_lt_iff_le] + refine ⟨?_, ?_⟩ <;> intro h c b_c + · rcases exists_between_coe_real b_c with ⟨d, b_d, d_c⟩ + apply mem_of_superset (eventually_lt_of_limsup_lt (lt_of_le_of_lt (h d b_d) d_c)) rw [Set.setOf_subset_setOf] - exact fun a h' ↦ le_of_lt h' - · rcases eq_or_neBot f with (rfl | _) + exact fun _ h' ↦ h'.le + · rcases eq_or_neBot f with rfl | _ · simp only [limsup_bot, bot_le] - · specialize h c b_lt_c - exact @Filter.limsup_const EReal α _ f _ (c : EReal) ▸ limsup_le_limsup h + · exact (limsup_le_of_le) (h c b_c) end LimInfSup @@ -289,8 +278,8 @@ end LimInfSup theorem continuousAt_add_coe_coe (a b : ℝ) : ContinuousAt (fun p : EReal × EReal => p.1 + p.2) (a, b) := by - simp only [ContinuousAt, nhds_coe_coe, ← coe_add, tendsto_map'_iff, (· ∘ ·), tendsto_coe, - tendsto_add] + simp only [ContinuousAt, nhds_coe_coe, ← coe_add, tendsto_map'_iff, Function.comp_def, + tendsto_coe, tendsto_add] theorem continuousAt_add_top_coe (a : ℝ) : ContinuousAt (fun p : EReal × EReal => p.1 + p.2) (⊤, a) := by @@ -301,7 +290,7 @@ theorem continuousAt_add_top_coe (a : ℝ) : theorem continuousAt_add_coe_top (a : ℝ) : ContinuousAt (fun p : EReal × EReal => p.1 + p.2) (a, ⊤) := by - simpa only [add_comm, (· ∘ ·), ContinuousAt, Prod.swap] + simpa only [add_comm, Function.comp_def, ContinuousAt, Prod.swap] using Tendsto.comp (continuousAt_add_top_coe a) (continuous_swap.tendsto ((a : EReal), ⊤)) theorem continuousAt_add_top_top : ContinuousAt (fun p : EReal × EReal => p.1 + p.2) (⊤, ⊤) := by @@ -319,7 +308,7 @@ theorem continuousAt_add_bot_coe (a : ℝ) : theorem continuousAt_add_coe_bot (a : ℝ) : ContinuousAt (fun p : EReal × EReal => p.1 + p.2) (a, ⊥) := by - simpa only [add_comm, (· ∘ ·), ContinuousAt, Prod.swap] + simpa only [add_comm, Function.comp_def, ContinuousAt, Prod.swap] using Tendsto.comp (continuousAt_add_bot_coe a) (continuous_swap.tendsto ((a : EReal), ⊥)) theorem continuousAt_add_bot_bot : ContinuousAt (fun p : EReal × EReal => p.1 + p.2) (⊥, ⊥) := by @@ -369,7 +358,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] @@ -386,7 +375,7 @@ private lemma continuousAt_mul_symm3 {a b : EReal} private lemma continuousAt_mul_coe_coe (a b : ℝ) : ContinuousAt (fun p : EReal × EReal ↦ p.1 * p.2) (a, b) := by simp [ContinuousAt, EReal.nhds_coe_coe, ← EReal.coe_mul, Filter.tendsto_map'_iff, - (· ∘ ·), EReal.tendsto_coe, tendsto_mul] + Function.comp_def, EReal.tendsto_coe, tendsto_mul] private lemma continuousAt_mul_top_top : ContinuousAt (fun p : EReal × EReal ↦ p.1 * p.2) (⊤, ⊤) := by diff --git a/Mathlib/Topology/Instances/Int.lean b/Mathlib/Topology/Instances/Int.lean index 1c532fee6a853..5ee25d7b929f2 100644 --- a/Mathlib/Topology/Instances/Int.lean +++ b/Mathlib/Topology/Instances/Int.lean @@ -8,8 +8,8 @@ import Mathlib.Data.Int.SuccPred import Mathlib.Data.Int.ConditionallyCompleteOrder import Mathlib.Topology.Instances.Discrete import Mathlib.Topology.MetricSpace.Bounded -import Mathlib.Topology.MetricSpace.Pseudo.Lemmas -import Mathlib.Order.Filter.Archimedean +import Mathlib.Order.Filter.AtTopBot.Archimedean +import Mathlib.Topology.MetricSpace.Basic /-! # Topology on the integers @@ -39,13 +39,16 @@ 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 + +@[deprecated (since := "2024-10-01")] +alias uniformEmbedding_coe_real := isUniformEmbedding_coe_real theorem closedEmbedding_coe_real : ClosedEmbedding ((↑) : ℤ → ℝ) := closedEmbedding_of_pairwise_le_dist zero_lt_one pairwise_one_le_dist -instance : MetricSpace ℤ := Int.uniformEmbedding_coe_real.comapMetricSpace _ +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/NNReal.lean b/Mathlib/Topology/Instances/NNReal.lean index e12bda18c19cc..6f0a140493505 100644 --- a/Mathlib/Topology/Instances/NNReal.lean +++ b/Mathlib/Topology/Instances/NNReal.lean @@ -6,6 +6,7 @@ Authors: Johan Commelin import Mathlib.Data.NNReal.Star import Mathlib.Topology.Algebra.InfiniteSum.Order import Mathlib.Topology.Algebra.InfiniteSum.Ring +import Mathlib.Topology.ContinuousMap.Basic import Mathlib.Topology.Instances.Real import Mathlib.Topology.MetricSpace.Isometry @@ -75,6 +76,9 @@ instance : ContinuousStar ℝ≥0 where continuous_star := continuous_id section coe +lemma isOpen_Ico_zero {x : NNReal} : IsOpen (Set.Ico 0 x) := + Ico_bot (a := x) ▸ isOpen_Iio + variable {α : Type*} open Filter Finset @@ -90,6 +94,11 @@ noncomputable def _root_.ContinuousMap.realToNNReal : C(ℝ, ℝ≥0) := theorem continuous_coe : Continuous ((↑) : ℝ≥0 → ℝ) := continuous_subtype_val +lemma _root_.ContinuousOn.ofReal_map_toNNReal {f : ℝ≥0 → ℝ≥0} {s : Set ℝ} {t : Set ℝ≥0} + (hf : ContinuousOn f t) (h : Set.MapsTo Real.toNNReal s t) : + ContinuousOn (fun x ↦ f x.toNNReal : ℝ → ℝ) s := + continuous_subtype_val.comp_continuousOn <| hf.comp continuous_real_toNNReal.continuousOn h + /-- Embedding of `ℝ≥0` to `ℝ` as a bundled continuous map. -/ @[simps (config := .asFn)] def _root_.ContinuousMap.coeNNRealReal : C(ℝ≥0, ℝ) := @@ -254,7 +263,7 @@ section Monotone /-- A monotone, bounded above sequence `f : ℕ → ℝ` has a finite limit. -/ theorem _root_.Real.tendsto_of_bddAbove_monotone {f : ℕ → ℝ} (h_bdd : BddAbove (Set.range f)) (h_mon : Monotone f) : ∃ r : ℝ, Tendsto f atTop (𝓝 r) := by - obtain ⟨B, hB⟩ := Real.exists_isLUB (Set.range_nonempty f) h_bdd + obtain ⟨B, hB⟩ := Real.exists_isLUB (Set.range_nonempty f) h_bdd exact ⟨B, tendsto_atTop_isLUB h_mon hB⟩ /-- An antitone, bounded below sequence `f : ℕ → ℝ` has a finite limit. -/ diff --git a/Mathlib/Topology/Instances/Nat.lean b/Mathlib/Topology/Instances/Nat.lean index def7fa44e4af2..e90ce1cbe65b7 100644 --- a/Mathlib/Topology/Instances/Nat.lean +++ b/Mathlib/Topology/Instances/Nat.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.Topology.Instances.Int +import Mathlib.Data.Nat.Lattice /-! # Topology on the natural numbers @@ -30,13 +31,16 @@ 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 + +@[deprecated (since := "2024-10-01")] +alias uniformEmbedding_coe_real := isUniformEmbedding_coe_real theorem closedEmbedding_coe_real : ClosedEmbedding ((↑) : ℕ → ℝ) := closedEmbedding_of_pairwise_le_dist zero_lt_one pairwise_one_le_dist -instance : MetricSpace ℕ := Nat.uniformEmbedding_coe_real.comapMetricSpace _ +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 ce48d2b2344a3..715361b5de0d9 100644 --- a/Mathlib/Topology/Instances/Rat.lean +++ b/Mathlib/Topology/Instances/Rat.lean @@ -30,14 +30,20 @@ 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 isDenseEmbedding_coe_real : IsDenseEmbedding ((↑) : ℚ → ℝ) := + isUniformEmbedding_coe_real.isDenseEmbedding Rat.denseRange_cast + +@[deprecated (since := "2024-09-30")] +alias denseEmbedding_coe_real := isDenseEmbedding_coe_real theorem embedding_coe_real : Embedding ((↑) : ℚ → ℝ) := - denseEmbedding_coe_real.to_embedding + isDenseEmbedding_coe_real.to_embedding theorem continuous_coe_real : Continuous ((↑) : ℚ → ℝ) := uniformContinuous_coe_real.continuous @@ -48,8 +54,11 @@ 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 @@ -58,8 +67,11 @@ theorem Nat.closedEmbedding_coe_rat : ClosedEmbedding ((↑) : ℕ → ℚ) := 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.closedEmbedding_coe_rat : ClosedEmbedding ((↑) : ℤ → ℚ) := closedEmbedding_of_pairwise_le_dist zero_lt_one <| by simpa using Int.pairwise_one_le_dist @@ -69,10 +81,10 @@ namespace Rat instance : NoncompactSpace ℚ := Int.closedEmbedding_coe_rat.noncompactSpace theorem uniformContinuous_add : UniformContinuous fun p : ℚ × ℚ => p.1 + p.2 := - Rat.uniformEmbedding_coe_real.toUniformInducing.uniformContinuous_iff.2 <| by - simp only [(· ∘ ·), Rat.cast_add] + 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 +106,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 b85ff2b228d17..1f633201490d0 100644 --- a/Mathlib/Topology/Instances/RatLemmas.lean +++ b/Mathlib/Topology/Instances/RatLemmas.lean @@ -6,6 +6,7 @@ Authors: Yury Kudryashov import Mathlib.Topology.Instances.Irrational import Mathlib.Topology.Instances.Rat import Mathlib.Topology.Compactification.OnePoint +import Mathlib.Topology.Metrizable.Uniformity /-! # Additional lemmas about the topology on rational numbers @@ -35,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) @@ -71,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 139a67e9753bb..16325c2f3e0ab 100644 --- a/Mathlib/Topology/Instances/Real.lean +++ b/Mathlib/Topology/Instances/Real.lean @@ -3,14 +3,16 @@ 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.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.UniformMulAction 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 /-! 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/KrullDimension.lean b/Mathlib/Topology/KrullDimension.lean index b5387350eed0f..b5eee2e982ae4 100644 --- a/Mathlib/Topology/KrullDimension.lean +++ b/Mathlib/Topology/KrullDimension.lean @@ -12,17 +12,52 @@ 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 (WithTop ℕ) := +noncomputable def topologicalKrullDim (T : Type*) [TopologicalSpace T] : WithBot ℕ∞ := 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 : ClosedEmbedding 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 ClosedEmbedding.topologicalKrullDim_le (f : X → Y) (hf : ClosedEmbedding f) : + topologicalKrullDim X ≤ topologicalKrullDim Y := + krullDim_le_of_strictMono _ (IrreducibleCloseds.map_strictMono hf) + +/-- The topological Krull dimension is invariant under homeomorphisms -/ +theorem IsHomeomorph.topologicalKrullDim_eq (f : X → Y) (h : IsHomeomorph f) : + topologicalKrullDim X = topologicalKrullDim Y := + have fwd : topologicalKrullDim X ≤ topologicalKrullDim Y := + ClosedEmbedding.topologicalKrullDim_le f h.closedEmbedding + have bwd : topologicalKrullDim Y ≤ topologicalKrullDim X := + ClosedEmbedding.topologicalKrullDim_le (h.homeomorph f).symm + (h.homeomorph f).symm.closedEmbedding + le_antisymm fwd bwd diff --git a/Mathlib/Topology/List.lean b/Mathlib/Topology/List.lean index 563dc61834ff2..f9e3f9ddbdfc3 100644 --- a/Mathlib/Topology/List.lean +++ b/Mathlib/Topology/List.lean @@ -86,7 +86,7 @@ theorem tendsto_cons_iff {β : Type*} {f : List α → β} {b : Filter β} {a : have : 𝓝 (a::l) = (𝓝 a ×ˢ 𝓝 l).map fun p : α × List α => p.1::p.2 := by simp only [nhds_cons, Filter.prod_eq, (Filter.map_def _ _).symm, (Filter.seq_eq_filter_seq _ _).symm] - simp [-Filter.map_def, (· ∘ ·), functor_norm] + simp [-Filter.map_def, Function.comp_def, functor_norm] rw [this, Filter.tendsto_map'_iff]; rfl theorem continuous_cons : Continuous fun x : α × List α => (x.1::x.2 : List α) := @@ -124,7 +124,7 @@ theorem tendsto_insertNth' {a : α} : have : 𝓝 a ×ˢ 𝓝 (a'::l) = (𝓝 a ×ˢ (𝓝 a' ×ˢ 𝓝 l)).map fun p : α × α × List α => (p.1, p.2.1::p.2.2) := by simp only [nhds_cons, Filter.prod_eq, ← Filter.map_def, ← Filter.seq_eq_filter_seq] - simp [-Filter.map_def, (· ∘ ·), functor_norm] + simp [-Filter.map_def, Function.comp_def, functor_norm] rw [this, tendsto_map'_iff] exact (tendsto_fst.comp tendsto_snd).cons diff --git a/Mathlib/Topology/LocalAtTarget.lean b/Mathlib/Topology/LocalAtTarget.lean index 62a0b258ffe46..184b90a9c30e4 100644 --- a/Mathlib/Topology/LocalAtTarget.lean +++ b/Mathlib/Topology/LocalAtTarget.lean @@ -23,7 +23,7 @@ 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 @@ -108,7 +108,10 @@ theorem isLocallyClosed_iff_coe_preimage_of_iSup_eq_top (s : Set β) : IsLocallyClosed s ↔ ∀ i, IsLocallyClosed ((↑) ⁻¹' s : Set (U i)) := by simp_rw [isLocallyClosed_iff_isOpen_coborder] rw [isOpen_iff_coe_preimage_of_iSup_eq_top hU] - exact forall_congr' fun i ↦ by rw [(U i).isOpen.openEmbedding_subtype_val.coborder_preimage] + 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 _ + rw [this] theorem isOpenMap_iff_isOpenMap_of_iSup_eq_top : IsOpenMap f ↔ ∀ i, IsOpenMap ((U i).1.restrictPreimage f) := by @@ -147,8 +150,8 @@ theorem inducing_iff_inducing_of_iSup_eq_top (h : Continuous f) : (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 [← OpenEmbedding.map_nhds_eq (h.1 _ (U i).2).openEmbedding_subtype_val ⟨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) diff --git a/Mathlib/Topology/LocallyClosed.lean b/Mathlib/Topology/LocallyClosed.lean index 90d7577eba4a9..fd260f0e11c03 100644 --- a/Mathlib/Topology/LocallyClosed.lean +++ b/Mathlib/Topology/LocallyClosed.lean @@ -61,6 +61,17 @@ lemma coborder_eq_compl_frontier_iff : simp_rw [coborder_eq_union_frontier_compl, union_eq_right, subset_compl_iff_disjoint_left, disjoint_frontier_iff_isOpen] +theorem coborder_eq_union_closure_compl {s : Set X} : coborder s = s ∪ (closure s)ᶜ := by + rw [coborder, compl_eq_comm, compl_union, compl_compl, inter_comm] + rfl + +/-- The coborder of any set is dense -/ +theorem dense_coborder {s : Set X} : + Dense (coborder s) := by + rw [dense_iff_closure_eq, coborder_eq_union_closure_compl, closure_union, ← univ_subset_iff] + refine _root_.subset_trans ?_ (union_subset_union_right _ (subset_closure)) + simp + alias ⟨_, IsOpen.coborder_eq⟩ := coborder_eq_compl_frontier_iff lemma IsOpenMap.coborder_preimage_subset (hf : IsOpenMap f) (s : Set Y) : @@ -88,12 +99,6 @@ lemma isClosed_preimage_val_coborder : IsClosed (coborder s ↓∩ s) := by rw [isClosed_preimage_val, inter_eq_right.mpr subset_coborder, coborder_inter_closure] -lemma IsOpen.isLocallyClosed (hs : IsOpen s) : IsLocallyClosed s := - ⟨_, _, hs, isClosed_univ, (inter_univ _).symm⟩ - -lemma IsClosed.isLocallyClosed (hs : IsClosed s) : IsLocallyClosed s := - ⟨_, _, isOpen_univ, hs, (univ_inter _).symm⟩ - lemma IsLocallyClosed.inter (hs : IsLocallyClosed s) (ht : IsLocallyClosed t) : IsLocallyClosed (s ∩ t) := by obtain ⟨U₁, Z₁, hU₁, hZ₁, rfl⟩ := hs @@ -145,8 +150,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] @@ -155,23 +160,23 @@ 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 + | H => by convert H.isLocallyClosed.image inducing_subtype_val (by simpa using isClosed_closure.isLocallyClosed) simpa using subset_closure diff --git a/Mathlib/Topology/LocallyConstant/Algebra.lean b/Mathlib/Topology/LocallyConstant/Algebra.lean index 1e70ce1a80c57..986f83f29a8ac 100644 --- a/Mathlib/Topology/LocallyConstant/Algebra.lean +++ b/Mathlib/Topology/LocallyConstant/Algebra.lean @@ -186,7 +186,7 @@ instance [NonAssocSemiring Y] : NonAssocSemiring (LocallyConstant X Y) := Function.Injective.nonAssocSemiring DFunLike.coe DFunLike.coe_injective' rfl rfl (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) fun _ => rfl -/-- The constant-function embedding, as a ring hom. -/ +/-- The constant-function embedding, as a ring hom. -/ @[simps] def constRingHom [NonAssocSemiring Y] : Y →+* LocallyConstant X Y := { constMonoidHom, constAddMonoidHom with toFun := const X } @@ -347,7 +347,7 @@ lemma ker_comapₗ [Semiring R] [AddCommMonoid Z] [Module R Z] (f : C(X, Y)) LinearMap.ker (comapₗ R f : LocallyConstant Y Z →ₗ[R] LocallyConstant X Z) = ⊥ := LinearMap.ker_eq_bot_of_injective <| comap_injective _ hfs -/-- `LocallyConstant.congrLeft` as a linear equivalence. -/ +/-- `LocallyConstant.congrLeft` as a linear equivalence. -/ @[simps!] def congrLeftₗ (R : Type*) [Semiring R] [AddCommMonoid Z] [Module R Z] (e : X ≃ₜ Y) : LocallyConstant X Z ≃ₗ[R] LocallyConstant Y Z where @@ -362,7 +362,7 @@ def congrLeftRingEquiv [Semiring Z] (e : X ≃ₜ Y) : __ := comapMonoidHom ⟨_, e.symm.continuous⟩ __ := comapAddMonoidHom ⟨_, e.symm.continuous⟩ -/-- `LocallyConstant.congrLeft` as an `AlgEquiv`. -/ +/-- `LocallyConstant.congrLeft` as an `AlgEquiv`. -/ @[simps!] def congrLeftₐ (R : Type*) [CommSemiring R] [Semiring Z] [Algebra R Z] (e : X ≃ₜ Y) : LocallyConstant X Z ≃ₐ[R] LocallyConstant Y Z where @@ -406,7 +406,7 @@ def mapₐ (R : Type*) [CommSemiring R] [Semiring Y] [Algebra R Y] [Semiring Z] toRingHom := mapRingHom f commutes' _ := by aesop -/-- `LocallyConstant.congrRight` as a linear equivalence. -/ +/-- `LocallyConstant.congrRight` as a linear equivalence. -/ @[simps!] def congrRightₗ (R : Type*) [Semiring R] [AddCommMonoid Y] [Module R Y] [AddCommMonoid Z] [Module R Z] (e : Y ≃ₗ[R] Z) : @@ -422,7 +422,7 @@ def congrRightRingEquiv [Semiring Y] [Semiring Z] (e : Y ≃+* Z) : __ := mapMonoidHom e.toMonoidHom __ := mapAddMonoidHom e.toAddMonoidHom -/-- `LocallyConstant.congrRight` as an `AlgEquiv`. -/ +/-- `LocallyConstant.congrRight` as an `AlgEquiv`. -/ @[simps!] def congrRightₐ (R : Type*) [CommSemiring R] [Semiring Y] [Algebra R Y] [Semiring Z] [Algebra R Z] (e : Y ≃ₐ[R] Z) : LocallyConstant X Y ≃ₐ[R] LocallyConstant X Z where diff --git a/Mathlib/Topology/LocallyConstant/Basic.lean b/Mathlib/Topology/LocallyConstant/Basic.lean index 4e3ac23a0989d..401cf78da5d19 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⟩ @@ -99,7 +96,7 @@ theorem iff_continuous {_ : TopologicalSpace Y} [DiscreteTopology Y] (f : X → ⟨IsLocallyConstant.continuous, fun h s => h.isOpen_preimage s (isOpen_discrete _)⟩ theorem of_constant (f : X → Y) (h : ∀ x y, f x = f y) : IsLocallyConstant f := - (iff_eventually_eq f).2 fun _ => eventually_of_forall fun _ => h _ _ + (iff_eventually_eq f).2 fun _ => Eventually.of_forall fun _ => h _ _ protected theorem const (y : Y) : IsLocallyConstant (Function.const X y) := of_constant _ fun _ _ => rfl @@ -465,7 +462,7 @@ end Indicator section Equiv /-- -The equivalence between `LocallyConstant X Z` and `LocallyConstant Y Z` given a +The equivalence between `LocallyConstant X Z` and `LocallyConstant Y Z` given a homeomorphism `X ≃ₜ Y` -/ @[simps] @@ -480,7 +477,7 @@ def congrLeft [TopologicalSpace Y] (e : X ≃ₜ Y) : LocallyConstant X Z ≃ Lo simp [comap_comap] /-- -The equivalence between `LocallyConstant X Y` and `LocallyConstant X Z` given an +The equivalence between `LocallyConstant X Y` and `LocallyConstant X Z` given an equivalence `Y ≃ Z` -/ @[simps] @@ -556,7 +553,7 @@ lemma piecewise_apply_right {C₁ C₂ : Set X} (h₁ : IsClosed C₁) (h₂ : I · exact hfg x ⟨h, hx⟩ · rfl -/-- A variant of `LocallyConstant.piecewise` where the two closed sets cover a subset. +/-- A variant of `LocallyConstant.piecewise` where the two closed sets cover a subset. TODO: Generalise this construction to `ContinuousMap`. -/ def piecewise' {C₀ C₁ C₂ : Set X} (h₀ : C₀ ⊆ C₁ ∪ C₂) (h₁ : IsClosed C₁) diff --git a/Mathlib/Topology/LocallyFinite.lean b/Mathlib/Topology/LocallyFinite.lean index 62ae2d2ecfd21..fef472c111a08 100644 --- a/Mathlib/Topology/LocallyFinite.lean +++ b/Mathlib/Topology/LocallyFinite.lean @@ -183,7 +183,7 @@ end LocallyFinite @[simp] theorem Equiv.locallyFinite_comp_iff (e : ι' ≃ ι) : LocallyFinite (f ∘ e) ↔ LocallyFinite f := - ⟨fun h => by simpa only [(· ∘ ·), e.apply_symm_apply] using h.comp_injective e.symm.injective, + ⟨fun h => by simpa only [comp_def, e.apply_symm_apply] using h.comp_injective e.symm.injective, fun h => h.comp_injective e.injective⟩ theorem locallyFinite_sum {f : ι ⊕ ι' → Set X} : @@ -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 3f1b53b0f9042..de7a4ffef4499 100644 --- a/Mathlib/Topology/Maps/Basic.lean +++ b/Mathlib/Topology/Maps/Basic.lean @@ -233,7 +233,7 @@ section QuotientMap variable [TopologicalSpace X] [TopologicalSpace Y] [TopologicalSpace Z] theorem quotientMap_iff : QuotientMap f ↔ Surjective f ∧ ∀ s : Set Y, IsOpen s ↔ IsOpen (f ⁻¹' s) := - and_congr Iff.rfl TopologicalSpace.ext_iff + (quotientMap_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) := @@ -246,13 +246,13 @@ protected theorem id : QuotientMap (@id X) := ⟨fun x => ⟨x, rfl⟩, coinduced_id.symm⟩ protected theorem comp (hg : QuotientMap g) (hf : QuotientMap f) : QuotientMap (g ∘ f) := - ⟨hg.left.comp hf.left, by rw [hg.right, hf.right, coinduced_compose]⟩ + ⟨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 := ⟨hgf.1.of_comp, le_antisymm - (by rw [hgf.right, ← coinduced_compose]; exact coinduced_mono hf.coinduced_le) + (by rw [hgf.eq_coinduced, ← coinduced_compose]; exact coinduced_mono hf.coinduced_le) hg.coinduced_le⟩ theorem of_inverse {g : Y → X} (hf : Continuous f) (hg : Continuous g) (h : LeftInverse g f) : @@ -260,14 +260,11 @@ theorem of_inverse {g : Y → X} (hf : Continuous f) (hg : Continuous g) (h : Le QuotientMap.of_quotientMap_compose hf hg <| h.comp_eq_id.symm ▸ QuotientMap.id protected theorem continuous_iff (hf : QuotientMap f) : Continuous g ↔ Continuous (g ∘ f) := by - rw [continuous_iff_coinduced_le, continuous_iff_coinduced_le, hf.right, coinduced_compose] + rw [continuous_iff_coinduced_le, continuous_iff_coinduced_le, hf.eq_coinduced, coinduced_compose] protected theorem continuous (hf : QuotientMap f) : Continuous f := hf.continuous_iff.mp continuous_id -protected theorem surjective (hf : QuotientMap f) : Surjective f := - hf.1 - protected theorem isOpen_preimage (hf : QuotientMap f) {s : Set Y} : IsOpen (f ⁻¹' s) ↔ IsOpen s := ((quotientMap_iff.1 hf).2 s).symm @@ -383,7 +380,7 @@ protected theorem Inducing.isOpenMap (hi : Inducing f) (ho : IsOpen (range f)) : /-- 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 ↦ + Dense (f ⁻¹' s) := fun x ↦ hf.preimage_closure_subset_closure_preimage <| hs (f x) end OpenMap @@ -524,7 +521,7 @@ theorem openEmbedding_iff_embedding_open : 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] + simp only [openEmbedding_iff_embedding_open, embedding_iff, inducing_iff_nhds, *, and_true] exact fun x => le_antisymm (h₁.tendsto _).le_comap (@comap_map _ _ (𝓝 x) _ h₂ ▸ comap_mono (h₃.nhds_le _)) diff --git a/Mathlib/Topology/Maps/OpenQuotient.lean b/Mathlib/Topology/Maps/OpenQuotient.lean new file mode 100644 index 0000000000000..88433f7a190fd --- /dev/null +++ b/Mathlib/Topology/Maps/OpenQuotient.lean @@ -0,0 +1,64 @@ +/- +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 quotientMap (h : IsOpenQuotientMap f) : QuotientMap f := + h.isOpenMap.to_quotientMap h.continuous h.surjective + +theorem iff_isOpenMap_quotientMap : IsOpenQuotientMap f ↔ IsOpenMap f ∧ QuotientMap f := + ⟨fun h ↦ ⟨h.isOpenMap, h.quotientMap⟩, fun ⟨ho, hq⟩ ↦ ⟨hq.surjective, hq.continuous, ho⟩⟩ + +theorem of_isOpenMap_quotientMap (ho : IsOpenMap f) (hq : QuotientMap f) : + IsOpenQuotientMap f := + iff_isOpenMap_quotientMap.2 ⟨ho, hq⟩ + +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.quotientMap.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 d2534f6fc6eac..00bd0a3bd8677 100644 --- a/Mathlib/Topology/Maps/Proper/Basic.lean +++ b/Mathlib/Topology/Maps/Proper/Basic.lean @@ -174,12 +174,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 +197,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)) : @@ -279,8 +281,11 @@ lemma isProperMap_of_isClosedMap_of_inj (f_cont : Continuous f) (f_inj : f.Injec @[simp] lemma Homeomorph.isProperMap (e : X ≃ₜ Y) : IsProperMap e := isProperMap_of_isClosedMap_of_inj e.continuous e.injective e.isClosedMap +protected lemma IsHomeomorph.isProperMap (hf : IsHomeomorph f) : IsProperMap f := + isProperMap_of_isClosedMap_of_inj hf.continuous hf.injective hf.isClosedMap + /-- The identity is proper. -/ -@[simp] lemma isProperMap_id : IsProperMap (id : X → X) := (Homeomorph.refl X).isProperMap +@[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 := @@ -413,7 +418,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 @@ -441,7 +446,7 @@ theorem isProperMap_iff_isClosedMap_filter {X : Type u} {Y : Type v} [Topologica -- `𝒰`. Furthermore, each `(f, pure)(x) = (f × id)(x, pure x)` is clearly an element of -- the closed set `(f × id) '' F`, thus the limit `(y, 𝒰)` also belongs to that set. this.mem_of_tendsto (hy.prod_mk_nhds (Filter.tendsto_pure_self (𝒰 : Filter X))) - (eventually_of_forall fun x ↦ ⟨⟨x, pure x⟩, subset_closure rfl, rfl⟩) + (Eventually.of_forall fun x ↦ ⟨⟨x, pure x⟩, subset_closure rfl, rfl⟩) -- The above shows that `(y, 𝒰) = (f x, 𝒰)`, for some `x : X` such that `(x, 𝒰) ∈ F`. rcases this with ⟨⟨x, _⟩, hx, ⟨_, _⟩⟩ -- We already know that `f x = y`, so to finish the proof we just have to check that `𝒰` tends diff --git a/Mathlib/Topology/Maps/Proper/UniversallyClosed.lean b/Mathlib/Topology/Maps/Proper/UniversallyClosed.lean index aee1d663c4d09..1ad05fe6e8fab 100644 --- a/Mathlib/Topology/Maps/Proper/UniversallyClosed.lean +++ b/Mathlib/Topology/Maps/Proper/UniversallyClosed.lean @@ -31,7 +31,7 @@ theorem isProperMap_iff_isClosedMap_ultrafilter {X : Type u} {Y : Type v} [Topol have := H.2 F isClosed_closure have : (y, 𝒰) ∈ Prod.map f id '' F := this.mem_of_tendsto (hy.prod_mk_nhds (Ultrafilter.tendsto_pure_self 𝒰)) - (eventually_of_forall fun x ↦ ⟨⟨x, pure x⟩, subset_closure rfl, rfl⟩) + (Eventually.of_forall fun x ↦ ⟨⟨x, pure x⟩, subset_closure rfl, rfl⟩) rcases this with ⟨⟨x, _⟩, hx, ⟨_, _⟩⟩ refine ⟨x, rfl, fun U hU ↦ Ultrafilter.compl_not_mem_iff.mp fun hUc ↦ ?_⟩ rw [mem_closure_iff_nhds] at hx diff --git a/Mathlib/Topology/MetricSpace/Algebra.lean b/Mathlib/Topology/MetricSpace/Algebra.lean index c2d744b24f070..e185b9abdc3ba 100644 --- a/Mathlib/Topology/MetricSpace/Algebra.lean +++ b/Mathlib/Topology/MetricSpace/Algebra.lean @@ -4,7 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Heather Macbeth -/ import Mathlib.Topology.Algebra.MulAction +import Mathlib.Topology.Algebra.UniformMulAction import Mathlib.Topology.MetricSpace.Lipschitz +import Mathlib.Topology.Algebra.SeparationQuotient /-! # Compatibility of algebraic operations with metric space structures @@ -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 @@ -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 7a5a8a6646dec..67c88ebcb3216 100644 --- a/Mathlib/Topology/MetricSpace/Antilipschitz.lean +++ b/Mathlib/Topology/MetricSpace/Antilipschitz.lean @@ -33,9 +33,9 @@ open Set Filter Bornology def AntilipschitzWith [PseudoEMetricSpace α] [PseudoEMetricSpace β] (K : ℝ≥0) (f : α → β) := ∀ x y, edist x y ≤ K * edist (f x) (f y) -theorem AntilipschitzWith.edist_lt_top [PseudoEMetricSpace α] [PseudoMetricSpace β] {K : ℝ≥0} - {f : α → β} (h : AntilipschitzWith K f) (x y : α) : edist x y < ⊤ := - (h x y).trans_lt <| ENNReal.mul_lt_top ENNReal.coe_ne_top (edist_ne_top _ _) +protected lemma AntilipschitzWith.edist_lt_top [PseudoEMetricSpace α] [PseudoMetricSpace β] + {K : ℝ≥0} {f : α → β} (h : AntilipschitzWith K f) (x y : α) : edist x y < ⊤ := + (h x y).trans_lt <| ENNReal.mul_lt_top ENNReal.coe_lt_top (edist_lt_top _ _) theorem AntilipschitzWith.edist_ne_top [PseudoEMetricSpace α] [PseudoMetricSpace β] {K : ℝ≥0} {f : α → β} (h : AntilipschitzWith K f) (x y : α) : edist x y ≠ ⊤ := @@ -143,18 +143,22 @@ 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) : @@ -164,7 +168,7 @@ theorem isClosed_range {α β : Type*} [PseudoEMetricSpace α] [EMetricSpace β] theorem closedEmbedding {α : 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 } + { (hf.isUniformEmbedding hfc).embedding with isClosed_range := hf.isClosed_range hfc } 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 692a477a5e8a4..185ec4912deba 100644 --- a/Mathlib/Topology/MetricSpace/Basic.lean +++ b/Mathlib/Topology/MetricSpace/Basic.lean @@ -3,26 +3,14 @@ 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.MetricSpace.Pseudo.Basic import Mathlib.Topology.MetricSpace.Pseudo.Lemmas +import Mathlib.Topology.MetricSpace.Pseudo.Pi +import Mathlib.Topology.MetricSpace.Defs /-! -# Metric spaces +# Basic properties of metric spaces, and instances. -This file defines metric spaces and shows some of their basic properties. - -Many definitions and theorems expected on metric spaces are already introduced on uniform spaces and -topological spaces. This includes open and closed sets, compactness, completeness, continuity -and uniform continuity. - -TODO (anyone): Add "Main results" section. - -## Implementation notes -A lot of elementary properties don't require `eq_of_dist_eq_zero`, hence are stated and proven -for `PseudoMetricSpace`s in `PseudoMetric.lean`. - -## Tags - -metric, pseudo_metric, dist -/ open Set Filter Bornology @@ -30,98 +18,28 @@ open scoped NNReal Uniformity universe u v w -variable {α : Type u} {β : Type v} {X ι : Type*} +variable {α : Type u} {β : Type v} {X : Type*} variable [PseudoMetricSpace α] - -/-- We now define `MetricSpace`, extending `PseudoMetricSpace`. -/ -class MetricSpace (α : Type u) extends PseudoMetricSpace α : Type u where - eq_of_dist_eq_zero : ∀ {x y : α}, dist x y = 0 → x = y - -/-- Two metric space structures with the same distance coincide. -/ -@[ext] -theorem MetricSpace.ext {α : Type*} {m m' : MetricSpace α} (h : m.toDist = m'.toDist) : - m = m' := by - cases m; cases m'; congr; ext1; assumption - -/-- Construct a metric space structure whose underlying topological space structure -(definitionally) agrees which a pre-existing topology which is compatible with a given distance -function. -/ -def MetricSpace.ofDistTopology {α : Type u} [TopologicalSpace α] (dist : α → α → ℝ) - (dist_self : ∀ x : α, dist x x = 0) (dist_comm : ∀ x y : α, dist x y = dist y x) - (dist_triangle : ∀ x y z : α, dist x z ≤ dist x y + dist y z) - (H : ∀ s : Set α, IsOpen s ↔ ∀ x ∈ s, ∃ ε > 0, ∀ y, dist x y < ε → y ∈ s) - (eq_of_dist_eq_zero : ∀ x y : α, dist x y = 0 → x = y) : MetricSpace α := - { PseudoMetricSpace.ofDistTopology dist dist_self dist_comm dist_triangle H with - eq_of_dist_eq_zero := eq_of_dist_eq_zero _ _ } - variable {γ : Type w} [MetricSpace γ] -theorem eq_of_dist_eq_zero {x y : γ} : dist x y = 0 → x = y := - MetricSpace.eq_of_dist_eq_zero - -@[simp] -theorem dist_eq_zero {x y : γ} : dist x y = 0 ↔ x = y := - Iff.intro eq_of_dist_eq_zero fun this => this ▸ dist_self _ - -@[simp] -theorem zero_eq_dist {x y : γ} : 0 = dist x y ↔ x = y := by rw [eq_comm, dist_eq_zero] - -theorem dist_ne_zero {x y : γ} : dist x y ≠ 0 ↔ x ≠ y := by - simpa only [not_iff_not] using dist_eq_zero - -@[simp] -theorem dist_le_zero {x y : γ} : dist x y ≤ 0 ↔ x = y := by - simpa [le_antisymm_iff, dist_nonneg] using @dist_eq_zero _ _ x y - -@[simp] -theorem dist_pos {x y : γ} : 0 < dist x y ↔ x ≠ y := by - simpa only [not_le] using not_congr dist_le_zero - -theorem eq_of_forall_dist_le {x y : γ} (h : ∀ ε > 0, dist x y ≤ ε) : x = y := - eq_of_dist_eq_zero (eq_of_le_of_forall_le_of_dense dist_nonneg h) - -/-- Deduce the equality of points from the vanishing of the nonnegative distance-/ -theorem eq_of_nndist_eq_zero {x y : γ} : nndist x y = 0 → x = y := by - simp only [NNReal.eq_iff, ← dist_nndist, imp_self, NNReal.coe_zero, dist_eq_zero] - -/-- Characterize the equality of points as the vanishing of the nonnegative distance-/ -@[simp] -theorem nndist_eq_zero {x y : γ} : nndist x y = 0 ↔ x = y := by - simp only [NNReal.eq_iff, ← dist_nndist, imp_self, NNReal.coe_zero, dist_eq_zero] - -@[simp] -theorem zero_eq_nndist {x y : γ} : 0 = nndist x y ↔ x = y := by - simp only [NNReal.eq_iff, ← dist_nndist, imp_self, NNReal.coe_zero, zero_eq_dist] - namespace Metric variable {x : γ} {s : Set γ} -@[simp] theorem closedBall_zero : closedBall x 0 = {x} := Set.ext fun _ => dist_le_zero - -@[simp] theorem sphere_zero : sphere x 0 = {x} := Set.ext fun _ => dist_eq_zero - -theorem subsingleton_closedBall (x : γ) {r : ℝ} (hr : r ≤ 0) : (closedBall x r).Subsingleton := by - rcases hr.lt_or_eq with (hr | rfl) - · rw [closedBall_eq_empty.2 hr] - exact subsingleton_empty - · rw [closedBall_zero] - exact subsingleton_singleton - -theorem subsingleton_sphere (x : γ) {r : ℝ} (hr : r ≤ 0) : (sphere x r).Subsingleton := - (subsingleton_closedBall x hr).anti sphere_subset_closedBall - -- see Note [lower instance priority] instance (priority := 100) _root_.MetricSpace.instT0Space : T0Space γ where t0 _ _ h := eq_of_dist_eq_zero <| Metric.inseparable_iff.1 h /-- 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 α] : @@ -145,38 +63,15 @@ theorem closedEmbedding_of_pairwise_le_dist {α : Type*} [TopologicalSpace α] [ /-- 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 -end Metric +@[deprecated (since := "2024-10-01")] +alias uniformEmbedding_bot_of_pairwise_le_dist := isUniformEmbedding_bot_of_pairwise_le_dist -/-- Build a new metric space from an old one where the bundled uniform structure is provably -(but typically non-definitionaly) equal to some given uniform structure. -See Note [forgetful inheritance]. --/ -def MetricSpace.replaceUniformity {γ} [U : UniformSpace γ] (m : MetricSpace γ) - (H : 𝓤[U] = 𝓤[PseudoEMetricSpace.toUniformSpace]) : MetricSpace γ where - toPseudoMetricSpace := PseudoMetricSpace.replaceUniformity m.toPseudoMetricSpace H - eq_of_dist_eq_zero := @eq_of_dist_eq_zero _ _ - -theorem MetricSpace.replaceUniformity_eq {γ} [U : UniformSpace γ] (m : MetricSpace γ) - (H : 𝓤[U] = 𝓤[PseudoEMetricSpace.toUniformSpace]) : m.replaceUniformity H = m := by - ext; rfl - -/-- Build a new metric space from an old one where the bundled topological structure is provably -(but typically non-definitionaly) equal to some given topological structure. -See Note [forgetful inheritance]. --/ -abbrev MetricSpace.replaceTopology {γ} [U : TopologicalSpace γ] (m : MetricSpace γ) - (H : U = m.toPseudoMetricSpace.toUniformSpace.toTopologicalSpace) : MetricSpace γ := - @MetricSpace.replaceUniformity γ (m.toUniformSpace.replaceTopology H) m rfl - -theorem MetricSpace.replaceTopology_eq {γ} [U : TopologicalSpace γ] (m : MetricSpace γ) - (H : U = m.toPseudoMetricSpace.toUniformSpace.toTopologicalSpace) : - m.replaceTopology H = m := by - ext; rfl +end Metric /-- One gets a metric space from an emetric space if the edistance is everywhere finite, by pushing the edistance to reals. We set it up so that the edist and the @@ -196,20 +91,6 @@ def EMetricSpace.toMetricSpace {α : Type u} [EMetricSpace α] (h : ∀ x y : α MetricSpace α := EMetricSpace.toMetricSpaceOfDist (fun x y => ENNReal.toReal (edist x y)) h fun _ _ => rfl -/-- Build a new metric space from an old one where the bundled bornology structure is provably -(but typically non-definitionaly) equal to some given bornology structure. -See Note [forgetful inheritance]. --/ -def MetricSpace.replaceBornology {α} [B : Bornology α] (m : MetricSpace α) - (H : ∀ s, @IsBounded _ B s ↔ @IsBounded _ PseudoMetricSpace.toBornology s) : MetricSpace α := - { PseudoMetricSpace.replaceBornology _ H, m with toBornology := B } - -theorem MetricSpace.replaceBornology_eq {α} [m : MetricSpace α] [B : Bornology α] - (H : ∀ s, @IsBounded _ B s ↔ @IsBounded _ PseudoMetricSpace.toBornology s) : - MetricSpace.replaceBornology _ H = m := by - ext - rfl - /-- Metric space structure pulled back by an injective function. Injectivity is necessary to ensure that `dist x y = 0` only if `x = y`. -/ abbrev MetricSpace.induced {γ β} (f : γ → β) (hf : Function.Injective f) (m : MetricSpace β) : @@ -219,10 +100,13 @@ 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 : α → β) @@ -237,27 +121,6 @@ instance Subtype.metricSpace {α : Type*} {p : α → Prop} [MetricSpace α] : instance {α : Type*} [MetricSpace α] : MetricSpace αᵐᵒᵖ := MetricSpace.induced MulOpposite.unop MulOpposite.unop_injective ‹_› -instance : MetricSpace Empty where - dist _ _ := 0 - dist_self _ := rfl - dist_comm _ _ := rfl - edist _ _ := 0 - eq_of_dist_eq_zero _ := Subsingleton.elim _ _ - dist_triangle _ _ _ := show (0 : ℝ) ≤ 0 + 0 by rw [add_zero] - toUniformSpace := inferInstance - uniformity_dist := Subsingleton.elim _ _ - -instance : MetricSpace PUnit.{u + 1} where - dist _ _ := 0 - dist_self _ := rfl - dist_comm _ _ := rfl - edist _ _ := 0 - eq_of_dist_eq_zero _ := Subsingleton.elim _ _ - dist_triangle _ _ _ := show (0 : ℝ) ≤ 0 + 0 by rw [add_zero] - toUniformSpace := inferInstance - uniformity_dist := by - simp (config := { contextual := true }) [principal_univ, eq_top_of_neBot (𝓤 PUnit)] - section Real /-- Instantiate the reals as a metric space. -/ @@ -342,44 +205,8 @@ end EqRel The distance on those type synonyms is inherited without change. -/ - open Additive Multiplicative -section - -variable [Dist X] - -instance : Dist (Additive X) := ‹Dist X› -instance : Dist (Multiplicative X) := ‹Dist X› - -@[simp] theorem dist_ofMul (a b : X) : dist (ofMul a) (ofMul b) = dist a b := rfl - -@[simp] theorem dist_ofAdd (a b : X) : dist (ofAdd a) (ofAdd b) = dist a b := rfl - -@[simp] theorem dist_toMul (a b : Additive X) : dist (toMul a) (toMul b) = dist a b := rfl - -@[simp] theorem dist_toAdd (a b : Multiplicative X) : dist (toAdd a) (toAdd b) = dist a b := rfl - -end - -section - -variable [PseudoMetricSpace X] - -instance : PseudoMetricSpace (Additive X) := ‹PseudoMetricSpace X› -instance : PseudoMetricSpace (Multiplicative X) := ‹PseudoMetricSpace X› - -@[simp] theorem nndist_ofMul (a b : X) : nndist (ofMul a) (ofMul b) = nndist a b := rfl - -@[simp] theorem nndist_ofAdd (a b : X) : nndist (ofAdd a) (ofAdd b) = nndist a b := rfl - -@[simp] theorem nndist_toMul (a b : Additive X) : nndist (toMul a) (toMul b) = nndist a b := rfl - -@[simp] -theorem nndist_toAdd (a b : Multiplicative X) : nndist (toAdd a) (toAdd b) = nndist a b := rfl - -end - instance [MetricSpace X] : MetricSpace (Additive X) := ‹MetricSpace X› instance [MetricSpace X] : MetricSpace (Multiplicative X) := ‹MetricSpace X› @@ -394,28 +221,4 @@ The distance on this type synonym is inherited without change. open OrderDual -section - -variable [Dist X] - -instance : Dist Xᵒᵈ := ‹Dist X› - -@[simp] theorem dist_toDual (a b : X) : dist (toDual a) (toDual b) = dist a b := rfl - -@[simp] theorem dist_ofDual (a b : Xᵒᵈ) : dist (ofDual a) (ofDual b) = dist a b := rfl - -end - -section - -variable [PseudoMetricSpace X] - -instance : PseudoMetricSpace Xᵒᵈ := ‹PseudoMetricSpace X› - -@[simp] theorem nndist_toDual (a b : X) : nndist (toDual a) (toDual b) = nndist a b := rfl - -@[simp] theorem nndist_ofDual (a b : Xᵒᵈ) : nndist (ofDual a) (ofDual b) = nndist a b := rfl - -end - instance [MetricSpace X] : MetricSpace Xᵒᵈ := ‹MetricSpace X› 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 19380e29c112e..5ce1a3fd60a5e 100644 --- a/Mathlib/Topology/MetricSpace/Bounded.lean +++ b/Mathlib/Topology/MetricSpace/Bounded.lean @@ -6,6 +6,7 @@ Authors: Jeremy Avigad, Robert Y. Lewis, Johannes Hölzl, Mario Carneiro, Sébas import Mathlib.Topology.Algebra.Order.Compact import Mathlib.Topology.MetricSpace.ProperSpace import Mathlib.Topology.MetricSpace.Cauchy +import Mathlib.Topology.EMetricSpace.Diam /-! ## Boundedness in (pseudo)-metric spaces @@ -15,7 +16,7 @@ This file contains one definition, and various results on boundedness in pseudo- Defined in terms of `EMetric.diam`, for better handling of the case when it should be infinite. * `isBounded_iff_subset_closedBall`: a non-empty set is bounded if and only if - it is is included in some closed ball + it is included in some closed ball * describing the cobounded filter, relating to the cocompact filter * `IsCompact.isBounded`: compact sets are bounded * `TotallyBounded.isBounded`: totally bounded sets are bounded diff --git a/Mathlib/Topology/MetricSpace/CauSeqFilter.lean b/Mathlib/Topology/MetricSpace/CauSeqFilter.lean index 8bf22f3af496b..c057c66bf50bb 100644 --- a/Mathlib/Topology/MetricSpace/CauSeqFilter.lean +++ b/Mathlib/Topology/MetricSpace/CauSeqFilter.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Robert Y. Lewis, Sébastien Gouëzel -/ import Mathlib.Analysis.Normed.Field.Basic +import Mathlib.Topology.MetricSpace.Cauchy /-! # Completeness in terms of `Cauchy` filters vs `isCauSeq` sequences diff --git a/Mathlib/Topology/MetricSpace/Cauchy.lean b/Mathlib/Topology/MetricSpace/Cauchy.lean index f6af5f9a89078..cec514c737140 100644 --- a/Mathlib/Topology/MetricSpace/Cauchy.lean +++ b/Mathlib/Topology/MetricSpace/Cauchy.lean @@ -4,6 +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.Topology.MetricSpace.Pseudo.Lemmas +import Mathlib.Topology.EMetricSpace.Basic /-! ## Cauchy sequences in (pseudo-)metric spaces @@ -87,7 +88,7 @@ theorem Metric.uniformCauchySeqOn_iff {γ : Type*} {F : β → γ → α} {s : S exact hab (hN b.fst hbl.ge b.snd hbr.ge x hx) /-- If the distance between `s n` and `s m`, `n ≤ m` is bounded above by `b n` -and `b` converges to zero, then `s` is a Cauchy sequence. -/ +and `b` converges to zero, then `s` is a Cauchy sequence. -/ theorem cauchySeq_of_le_tendsto_0' {s : β → α} (b : β → ℝ) (h : ∀ n m : β, n ≤ m → dist (s n) (s m) ≤ b n) (h₀ : Tendsto b atTop (𝓝 0)) : CauchySeq s := Metric.cauchySeq_iff'.2 fun ε ε0 => (h₀.eventually (gt_mem_nhds ε0)).exists.imp fun N hN n hn => @@ -96,7 +97,7 @@ theorem cauchySeq_of_le_tendsto_0' {s : β → α} (b : β → ℝ) _ < ε := hN /-- If the distance between `s n` and `s m`, `n, m ≥ N` is bounded above by `b N` -and `b` converges to zero, then `s` is a Cauchy sequence. -/ +and `b` converges to zero, then `s` is a Cauchy sequence. -/ theorem cauchySeq_of_le_tendsto_0 {s : β → α} (b : β → ℝ) (h : ∀ n m N : β, N ≤ n → N ≤ m → dist (s n) (s m) ≤ b N) (h₀ : Tendsto b atTop (𝓝 0)) : CauchySeq s := diff --git a/Mathlib/Topology/MetricSpace/Closeds.lean b/Mathlib/Topology/MetricSpace/Closeds.lean index 0c09e5375464a..2dd3375fbcd8e 100644 --- a/Mathlib/Topology/MetricSpace/Closeds.lean +++ b/Mathlib/Topology/MetricSpace/Closeds.lean @@ -117,7 +117,7 @@ instance Closeds.completeSpace [CompleteSpace α] : CompleteSpace (Closeds α) : apply hs <;> simp exact ⟨⟨z', z'_mem⟩, le_of_lt hz'⟩ use fun k => Nat.recOn k ⟨x, hx⟩ fun l z => (this l z).choose - simp only [Nat.add_zero, Nat.zero_eq, Nat.rec_zero, Nat.rec_add_one, true_and] + simp only [Nat.add_zero, Nat.rec_zero, Nat.rec_add_one, true_and] exact fun k => (this k _).choose_spec -- it follows from the previous bound that `z` is a Cauchy sequence have : CauchySeq fun k => (z k : α) := cauchySeq_of_edist_le_geometric_two (B n) (B_ne_top n) hz @@ -232,9 +232,12 @@ instance NonemptyCompacts.emetricSpace : EMetricSpace (NonemptyCompacts α) wher 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.embedding.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 23dc6110e8e0c..2fcec8e182a86 100644 --- a/Mathlib/Topology/MetricSpace/Contracting.lean +++ b/Mathlib/Topology/MetricSpace/Contracting.lean @@ -130,7 +130,7 @@ theorem edist_efixedPoint_le (hf : ContractingWith K f) {x : α} (hx : edist x ( theorem edist_efixedPoint_lt_top (hf : ContractingWith K f) {x : α} (hx : edist x (f x) ≠ ∞) : edist x (efixedPoint f hf x hx) < ∞ := (hf.edist_efixedPoint_le hx).trans_lt - (ENNReal.mul_lt_top hx <| ENNReal.inv_ne_top.2 hf.one_sub_K_ne_zero) + (ENNReal.mul_ne_top hx <| ENNReal.inv_ne_top.2 hf.one_sub_K_ne_zero).lt_top theorem efixedPoint_eq_of_edist_lt_top (hf : ContractingWith K f) {x : α} (hx : edist x (f x) ≠ ∞) {y : α} (hy : edist y (f y) ≠ ∞) (h : edist x y ≠ ∞) : @@ -205,7 +205,7 @@ theorem edist_efixedPoint_lt_top' {s : Set α} (hsc : IsComplete s) (hsf : MapsT (hf : ContractingWith K <| hsf.restrict f s s) {x : α} (hxs : x ∈ s) (hx : edist x (f x) ≠ ∞) : edist x (efixedPoint' f hsc hsf hf x hxs hx) < ∞ := (hf.edist_efixedPoint_le' hsc hsf hxs hx).trans_lt - (ENNReal.mul_lt_top hx <| ENNReal.inv_ne_top.2 hf.one_sub_K_ne_zero) + (ENNReal.mul_ne_top hx <| ENNReal.inv_ne_top.2 hf.one_sub_K_ne_zero).lt_top /-- If a globally contracting map `f` has two complete forward-invariant sets `s`, `t`, and `x ∈ s` is at a finite distance from `y ∈ t`, then the `efixedPoint'` constructed by `x` @@ -247,7 +247,7 @@ theorem dist_le_mul (x y : α) : dist (f x) (f y) ≤ K * dist x y := theorem dist_inequality (x y) : dist x y ≤ (dist x (f x) + dist y (f y)) / (1 - K) := suffices dist x y ≤ dist x (f x) + dist y (f y) + K * dist x y by - rwa [le_div_iff hf.one_sub_K_pos, mul_comm, _root_.sub_mul, one_mul, sub_le_iff_le_add] + rwa [le_div_iff₀ hf.one_sub_K_pos, mul_comm, _root_.sub_mul, one_mul, sub_le_iff_le_add] calc dist x y ≤ dist x (f x) + dist y (f y) + dist (f x) (f y) := dist_triangle4_right _ _ _ _ _ ≤ dist x (f x) + dist y (f y) + K * dist x y := add_le_add_left (hf.dist_le_mul _ _) _ diff --git a/Mathlib/Topology/MetricSpace/Defs.lean b/Mathlib/Topology/MetricSpace/Defs.lean new file mode 100644 index 0000000000000..3ce13e989e61a --- /dev/null +++ b/Mathlib/Topology/MetricSpace/Defs.lean @@ -0,0 +1,256 @@ +/- +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.MetricSpace.Pseudo.Defs + +/-! +# Metric spaces + +This file defines metric spaces and shows some of their basic properties. + +Many definitions and theorems expected on metric spaces are already introduced on uniform spaces and +topological spaces. This includes open and closed sets, compactness, completeness, continuity +and uniform continuity. + +TODO (anyone): Add "Main results" section. + +## Implementation notes +A lot of elementary properties don't require `eq_of_dist_eq_zero`, hence are stated and proven +for `PseudoMetricSpace`s in `PseudoMetric.lean`. + +## Tags + +metric, pseudo_metric, dist +-/ + +open Set Filter Bornology +open scoped NNReal Uniformity + +universe u v w + +variable {α : Type u} {β : Type v} {X ι : Type*} +variable [PseudoMetricSpace α] + +/-- We now define `MetricSpace`, extending `PseudoMetricSpace`. -/ +class MetricSpace (α : Type u) extends PseudoMetricSpace α : Type u where + eq_of_dist_eq_zero : ∀ {x y : α}, dist x y = 0 → x = y + +/-- Two metric space structures with the same distance coincide. -/ +@[ext] +theorem MetricSpace.ext {α : Type*} {m m' : MetricSpace α} (h : m.toDist = m'.toDist) : + m = m' := by + cases m; cases m'; congr; ext1; assumption + +/-- Construct a metric space structure whose underlying topological space structure +(definitionally) agrees which a pre-existing topology which is compatible with a given distance +function. -/ +def MetricSpace.ofDistTopology {α : Type u} [TopologicalSpace α] (dist : α → α → ℝ) + (dist_self : ∀ x : α, dist x x = 0) (dist_comm : ∀ x y : α, dist x y = dist y x) + (dist_triangle : ∀ x y z : α, dist x z ≤ dist x y + dist y z) + (H : ∀ s : Set α, IsOpen s ↔ ∀ x ∈ s, ∃ ε > 0, ∀ y, dist x y < ε → y ∈ s) + (eq_of_dist_eq_zero : ∀ x y : α, dist x y = 0 → x = y) : MetricSpace α := + { PseudoMetricSpace.ofDistTopology dist dist_self dist_comm dist_triangle H with + eq_of_dist_eq_zero := eq_of_dist_eq_zero _ _ } + +variable {γ : Type w} [MetricSpace γ] + +theorem eq_of_dist_eq_zero {x y : γ} : dist x y = 0 → x = y := + MetricSpace.eq_of_dist_eq_zero + +@[simp] +theorem dist_eq_zero {x y : γ} : dist x y = 0 ↔ x = y := + Iff.intro eq_of_dist_eq_zero fun this => this ▸ dist_self _ + +@[simp] +theorem zero_eq_dist {x y : γ} : 0 = dist x y ↔ x = y := by rw [eq_comm, dist_eq_zero] + +theorem dist_ne_zero {x y : γ} : dist x y ≠ 0 ↔ x ≠ y := by + simpa only [not_iff_not] using dist_eq_zero + +@[simp] +theorem dist_le_zero {x y : γ} : dist x y ≤ 0 ↔ x = y := by + simpa [le_antisymm_iff, dist_nonneg] using @dist_eq_zero _ _ x y + +@[simp] +theorem dist_pos {x y : γ} : 0 < dist x y ↔ x ≠ y := by + simpa only [not_le] using not_congr dist_le_zero + +theorem eq_of_forall_dist_le {x y : γ} (h : ∀ ε > 0, dist x y ≤ ε) : x = y := + eq_of_dist_eq_zero (eq_of_le_of_forall_le_of_dense dist_nonneg h) + +/-- Deduce the equality of points from the vanishing of the nonnegative distance -/ +theorem eq_of_nndist_eq_zero {x y : γ} : nndist x y = 0 → x = y := by + simp only [NNReal.eq_iff, ← dist_nndist, imp_self, NNReal.coe_zero, dist_eq_zero] + +/-- Characterize the equality of points as the vanishing of the nonnegative distance -/ +@[simp] +theorem nndist_eq_zero {x y : γ} : nndist x y = 0 ↔ x = y := by + simp only [NNReal.eq_iff, ← dist_nndist, imp_self, NNReal.coe_zero, dist_eq_zero] + +@[simp] +theorem zero_eq_nndist {x y : γ} : 0 = nndist x y ↔ x = y := by + simp only [NNReal.eq_iff, ← dist_nndist, imp_self, NNReal.coe_zero, zero_eq_dist] + +namespace Metric + +variable {x : γ} {s : Set γ} + +@[simp] theorem closedBall_zero : closedBall x 0 = {x} := Set.ext fun _ => dist_le_zero + +@[simp] theorem sphere_zero : sphere x 0 = {x} := Set.ext fun _ => dist_eq_zero + +theorem subsingleton_closedBall (x : γ) {r : ℝ} (hr : r ≤ 0) : (closedBall x r).Subsingleton := by + rcases hr.lt_or_eq with (hr | rfl) + · rw [closedBall_eq_empty.2 hr] + exact subsingleton_empty + · rw [closedBall_zero] + exact subsingleton_singleton + +theorem subsingleton_sphere (x : γ) {r : ℝ} (hr : r ≤ 0) : (sphere x r).Subsingleton := + (subsingleton_closedBall x hr).anti sphere_subset_closedBall + +end Metric + +/-- Build a new metric space from an old one where the bundled uniform structure is provably +(but typically non-definitionaly) equal to some given uniform structure. +See Note [forgetful inheritance]. +See Note [reducible non-instances]. +-/ +abbrev MetricSpace.replaceUniformity {γ} [U : UniformSpace γ] (m : MetricSpace γ) + (H : 𝓤[U] = 𝓤[PseudoEMetricSpace.toUniformSpace]) : MetricSpace γ where + toPseudoMetricSpace := PseudoMetricSpace.replaceUniformity m.toPseudoMetricSpace H + eq_of_dist_eq_zero := @eq_of_dist_eq_zero _ _ + +theorem MetricSpace.replaceUniformity_eq {γ} [U : UniformSpace γ] (m : MetricSpace γ) + (H : 𝓤[U] = 𝓤[PseudoEMetricSpace.toUniformSpace]) : m.replaceUniformity H = m := by + ext; rfl + +/-- Build a new metric space from an old one where the bundled topological structure is provably +(but typically non-definitionaly) equal to some given topological structure. +See Note [forgetful inheritance]. +See Note [reducible non-instances]. +-/ +abbrev MetricSpace.replaceTopology {γ} [U : TopologicalSpace γ] (m : MetricSpace γ) + (H : U = m.toPseudoMetricSpace.toUniformSpace.toTopologicalSpace) : MetricSpace γ := + @MetricSpace.replaceUniformity γ (m.toUniformSpace.replaceTopology H) m rfl + +theorem MetricSpace.replaceTopology_eq {γ} [U : TopologicalSpace γ] (m : MetricSpace γ) + (H : U = m.toPseudoMetricSpace.toUniformSpace.toTopologicalSpace) : + m.replaceTopology H = m := by + ext; rfl + +/-- Build a new metric space from an old one where the bundled bornology structure is provably +(but typically non-definitionaly) equal to some given bornology structure. +See Note [forgetful inheritance]. +See Note [reducible non-instances]. +-/ +abbrev MetricSpace.replaceBornology {α} [B : Bornology α] (m : MetricSpace α) + (H : ∀ s, @IsBounded _ B s ↔ @IsBounded _ PseudoMetricSpace.toBornology s) : MetricSpace α := + { PseudoMetricSpace.replaceBornology _ H, m with toBornology := B } + +theorem MetricSpace.replaceBornology_eq {α} [m : MetricSpace α] [B : Bornology α] + (H : ∀ s, @IsBounded _ B s ↔ @IsBounded _ PseudoMetricSpace.toBornology s) : + MetricSpace.replaceBornology _ H = m := by + ext + rfl + +instance : MetricSpace Empty where + dist _ _ := 0 + dist_self _ := rfl + dist_comm _ _ := rfl + edist _ _ := 0 + eq_of_dist_eq_zero _ := Subsingleton.elim _ _ + dist_triangle _ _ _ := show (0 : ℝ) ≤ 0 + 0 by rw [add_zero] + toUniformSpace := inferInstance + uniformity_dist := Subsingleton.elim _ _ + +instance : MetricSpace PUnit.{u + 1} where + dist _ _ := 0 + dist_self _ := rfl + dist_comm _ _ := rfl + edist _ _ := 0 + eq_of_dist_eq_zero _ := Subsingleton.elim _ _ + dist_triangle _ _ _ := show (0 : ℝ) ≤ 0 + 0 by rw [add_zero] + toUniformSpace := inferInstance + uniformity_dist := by + simp (config := { contextual := true }) [principal_univ, eq_top_of_neBot (𝓤 PUnit)] + +/-! +### `Additive`, `Multiplicative` + +The distance on those type synonyms is inherited without change. +-/ + + +open Additive Multiplicative + +section + +variable [Dist X] + +instance : Dist (Additive X) := ‹Dist X› +instance : Dist (Multiplicative X) := ‹Dist X› + +@[simp] theorem dist_ofMul (a b : X) : dist (ofMul a) (ofMul b) = dist a b := rfl + +@[simp] theorem dist_ofAdd (a b : X) : dist (ofAdd a) (ofAdd b) = dist a b := rfl + +@[simp] theorem dist_toMul (a b : Additive X) : dist (toMul a) (toMul b) = dist a b := rfl + +@[simp] theorem dist_toAdd (a b : Multiplicative X) : dist (toAdd a) (toAdd b) = dist a b := rfl + +end + +section + +variable [PseudoMetricSpace X] + +@[simp] theorem nndist_ofMul (a b : X) : nndist (ofMul a) (ofMul b) = nndist a b := rfl + +@[simp] theorem nndist_ofAdd (a b : X) : nndist (ofAdd a) (ofAdd b) = nndist a b := rfl + +@[simp] theorem nndist_toMul (a b : Additive X) : nndist (toMul a) (toMul b) = nndist a b := rfl + +@[simp] +theorem nndist_toAdd (a b : Multiplicative X) : nndist (toAdd a) (toAdd b) = nndist a b := rfl + +end + +instance [MetricSpace X] : MetricSpace (Additive X) := ‹MetricSpace X› +instance [MetricSpace X] : MetricSpace (Multiplicative X) := ‹MetricSpace X› + +/-! +### Order dual + +The distance on this type synonym is inherited without change. +-/ + +open OrderDual + +section + +variable [Dist X] + +instance : Dist Xᵒᵈ := ‹Dist X› + +@[simp] theorem dist_toDual (a b : X) : dist (toDual a) (toDual b) = dist a b := rfl + +@[simp] theorem dist_ofDual (a b : Xᵒᵈ) : dist (ofDual a) (ofDual b) = dist a b := rfl + +end + +section + +variable [PseudoMetricSpace X] + +instance : PseudoMetricSpace Xᵒᵈ := ‹PseudoMetricSpace X› + +@[simp] theorem nndist_toDual (a b : X) : nndist (toDual a) (toDual b) = nndist a b := rfl + +@[simp] theorem nndist_ofDual (a b : Xᵒᵈ) : nndist (ofDual a) (ofDual b) = nndist a b := rfl + +end + +instance [MetricSpace X] : MetricSpace Xᵒᵈ := ‹MetricSpace X› diff --git a/Mathlib/Topology/MetricSpace/Dilation.lean b/Mathlib/Topology/MetricSpace/Dilation.lean index c68a245846375..a2b542947d55f 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 @@ -370,12 +370,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).inducing.tendsto_nhds_iff /-- A dilation is continuous. -/ theorem toContinuous : Continuous (f : α → β) := @@ -406,11 +409,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).inducing.continuousOn_iff.symm theorem comp_continuous_iff {γ} [TopologicalSpace γ] {g : γ → α} : Continuous ((f : α → β) ∘ g) ↔ Continuous g := - (Dilation.uniformInducing f).inducing.continuous_iff.symm + (Dilation.isUniformInducing f).inducing.continuous_iff.symm end PseudoEmetricDilation @@ -420,14 +423,16 @@ 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 + (Dilation.isUniformEmbedding f).embedding /-- A dilation from a complete emetric space is a closed embedding -/ protected theorem closedEmbedding [CompleteSpace α] [EMetricSpace β] [DilationClass F α β] (f : F) : diff --git a/Mathlib/Topology/MetricSpace/Equicontinuity.lean b/Mathlib/Topology/MetricSpace/Equicontinuity.lean index 6f24d5e53aa5a..a6b57e7e49085 100644 --- a/Mathlib/Topology/MetricSpace/Equicontinuity.lean +++ b/Mathlib/Topology/MetricSpace/Equicontinuity.lean @@ -3,8 +3,8 @@ Copyright (c) 2022 Anatole Dedecker. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Anatole Dedecker -/ -import Mathlib.Topology.MetricSpace.Pseudo.Lemmas import Mathlib.Topology.UniformSpace.Equicontinuity +import Mathlib.Topology.MetricSpace.Pseudo.Lemmas /-! # Equicontinuity in metric spaces diff --git a/Mathlib/Topology/MetricSpace/Gluing.lean b/Mathlib/Topology/MetricSpace/Gluing.lean index 9091ef227ff5c..e3f3f1233ca43 100644 --- a/Mathlib/Topology/MetricSpace/Gluing.lean +++ b/Mathlib/Topology/MetricSpace/Gluing.lean @@ -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 ?_ @@ -580,8 +579,7 @@ attribute [local instance] inductivePremetric def InductiveLimit (I : ∀ n, Isometry (f n)) : Type _ := @SeparationQuotient _ (inductivePremetric I).toUniformSpace.toTopologicalSpace -set_option autoImplicit true in -instance : MetricSpace (InductiveLimit (f := f) I) := +instance {I : ∀ (n : ℕ), Isometry (f n)} : MetricSpace (InductiveLimit (f := f) I) := inferInstanceAs <| MetricSpace <| @SeparationQuotient _ (inductivePremetric I).toUniformSpace.toTopologicalSpace diff --git a/Mathlib/Topology/MetricSpace/GromovHausdorff.lean b/Mathlib/Topology/MetricSpace/GromovHausdorff.lean index fbeb7156e42d0..8b58e2adf2ada 100644 --- a/Mathlib/Topology/MetricSpace/GromovHausdorff.lean +++ b/Mathlib/Topology/MetricSpace/GromovHausdorff.lean @@ -255,7 +255,7 @@ theorem hausdorffDist_optimal {X : Type u} [MetricSpace X] [CompactSpace X] [Non rcases exists_mem_of_nonempty X with ⟨xX, _⟩ have : ∃ y ∈ range Ψ, dist (Φ xX) y < diam (univ : Set X) + 1 + diam (univ : Set Y) := by rw [Ψrange] - have : Φ xX ∈ ↑p := Φrange.subst (mem_range_self _) + have : Φ xX ∈ (p : Set _) := Φrange ▸ (mem_range_self _) exact exists_dist_lt_of_hausdorffDist_lt this bound (hausdorffEdist_ne_top_of_nonempty_of_bounded p.nonempty q.nonempty @@ -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 => @@ -315,7 +315,7 @@ theorem hausdorffDist_optimal {X : Type u} [MetricSpace X] [CompactSpace X] [Non refine le_trans this (le_of_forall_le_of_dense fun r hr => ?_) have I1 : ∀ x : X, (⨅ y, Fb (inl x, inr y)) ≤ r := by intro x - have : f (inl x) ∈ ↑p := Φrange.subst (mem_range_self _) + have : f (inl x) ∈ (p : Set _) := Φrange ▸ (mem_range_self _) rcases exists_dist_lt_of_hausdorffDist_lt this hr (hausdorffEdist_ne_top_of_nonempty_of_bounded p.nonempty q.nonempty p.isCompact.isBounded q.isCompact.isBounded) with @@ -331,7 +331,7 @@ theorem hausdorffDist_optimal {X : Type u} [MetricSpace X] [CompactSpace X] [Non have I2 : ∀ y : Y, (⨅ x, Fb (inl x, inr y)) ≤ r := by intro y - have : f (inr y) ∈ ↑q := Ψrange.subst (mem_range_self _) + have : f (inr y) ∈ (q : Set _) := Ψrange ▸ (mem_range_self _) rcases exists_dist_lt_of_hausdorffDist_lt' this hr (hausdorffEdist_ne_top_of_nonempty_of_bounded p.nonempty q.nonempty p.isCompact.isBounded q.isCompact.isBounded) with @@ -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 @@ -940,7 +940,7 @@ limit of the `Y n`, and finally let `Z` be the completion of `Z0`. The images `X2 n` of `X n` in `Z` are at Hausdorff distance `< 1/2^n` by construction, hence they form a Cauchy sequence for the Hausdorff distance. By completeness (of `Z`, and therefore of its set of nonempty compact subsets), they converge to a limit `L`. This is the nonempty -compact metric space we are looking for. -/ +compact metric space we are looking for. -/ variable (X : ℕ → Type) [∀ n, MetricSpace (X n)] [∀ n, CompactSpace (X n)] [∀ n, Nonempty (X n)] /-- Auxiliary structure used to glue metric spaces below, recording an isometric embedding diff --git a/Mathlib/Topology/MetricSpace/GromovHausdorffRealized.lean b/Mathlib/Topology/MetricSpace/GromovHausdorffRealized.lean index 73e63a878282e..9a6979a644bb1 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 @@ -100,7 +100,7 @@ private theorem maxVar_bound [CompactSpace X] [Nonempty X] [CompactSpace Y] [Non _ ≤ diam (range inl : Set (X ⊕ Y)) + dist (inl default) (inr default) + diam (range inr : Set (X ⊕ Y)) := (diam_union (mem_range_self _) (mem_range_self _)) - _ = diam (univ : Set X) + (dist default default + 1 + dist default default) + + _ = diam (univ : Set X) + (dist (α := X) default default + 1 + dist (α := Y) default default) + diam (univ : Set Y) := by rw [isometry_inl.diam_range, isometry_inr.diam_range] rfl @@ -142,10 +142,10 @@ private theorem candidates_dist_bound (fA : f ∈ candidates X Y) : | inl x, inl y => calc f (inl x, inl y) = dist x y := candidates_dist_inl fA x y - _ = dist (inl x) (inl y) := by + _ = dist (α := X ⊕ Y) (inl x) (inl y) := by rw [@Sum.dist_eq X Y] rfl - _ = 1 * dist (inl x) (inl y) := by ring + _ = 1 * dist (α := X ⊕ Y) (inl x) (inl y) := by ring _ ≤ maxVar X Y * dist (inl x) (inl y) := by gcongr; exact one_le_maxVar X Y | inl x, inr y => calc @@ -160,10 +160,10 @@ private theorem candidates_dist_bound (fA : f ∈ candidates X Y) : | inr x, inr y => calc f (inr x, inr y) = dist x y := candidates_dist_inr fA x y - _ = dist (inr x) (inr y) := by + _ = dist (α := X ⊕ Y) (inr x) (inr y) := by rw [@Sum.dist_eq X Y] rfl - _ = 1 * dist (inr x) (inr y) := by ring + _ = 1 * dist (α := X ⊕ Y) (inr x) (inr y) := by ring _ ≤ maxVar X Y * dist (inr x) (inr y) := by gcongr; exact one_le_maxVar X Y /-- Technical lemma to prove that candidates are Lipschitz -/ diff --git a/Mathlib/Topology/MetricSpace/HausdorffDimension.lean b/Mathlib/Topology/MetricSpace/HausdorffDimension.lean index d33c00ae8e600..46a5798a92a07 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] @@ -262,7 +262,7 @@ theorem HolderOnWith.dimH_image_le (h : HolderOnWith C r f s) (hr : 0 < r) : borelize X Y refine dimH_le fun d hd => ?_ have := h.hausdorffMeasure_image_le hr d.coe_nonneg - rw [hd, ENNReal.coe_rpow_of_nonneg _ d.coe_nonneg, top_le_iff] at this + rw [hd, ← ENNReal.coe_rpow_of_nonneg _ d.coe_nonneg, top_le_iff] at this have Hrd : μH[(r * d : ℝ≥0)] s = ⊤ := by contrapose this exact ENNReal.mul_ne_top ENNReal.coe_ne_top this @@ -322,7 +322,7 @@ namespace LipschitzWith /-- If `f` is a Lipschitz continuous map, then `dimH (f '' s) ≤ dimH s`. -/ theorem dimH_image_le (h : LipschitzWith K f) (s : Set X) : dimH (f '' s) ≤ dimH s := - (h.lipschitzOnWith s).dimH_image_le + h.lipschitzOnWith.dimH_image_le /-- If `f` is a Lipschitz continuous map, then the Hausdorff dimension of its range is at most the Hausdorff dimension of its domain. -/ @@ -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/Holder.lean b/Mathlib/Topology/MetricSpace/Holder.lean index c60629e1cc045..da0e2b14c4f81 100644 --- a/Mathlib/Topology/MetricSpace/Holder.lean +++ b/Mathlib/Topology/MetricSpace/Holder.lean @@ -106,7 +106,7 @@ theorem comp {Cg rg : ℝ≥0} {g : Y → Z} {t : Set Y} (hg : HolderOnWith Cg r HolderOnWith (Cg * Cf ^ (rg : ℝ)) (rg * rf) (g ∘ f) s := by intro x hx y hy rw [ENNReal.coe_mul, mul_comm rg, NNReal.coe_mul, ENNReal.rpow_mul, mul_assoc, - ← ENNReal.coe_rpow_of_nonneg _ rg.coe_nonneg, ← ENNReal.mul_rpow_of_nonneg _ _ rg.coe_nonneg] + ENNReal.coe_rpow_of_nonneg _ rg.coe_nonneg, ← ENNReal.mul_rpow_of_nonneg _ _ rg.coe_nonneg] exact hg.edist_le_of_le (hst hx) (hst hy) (hf.edist_le hx hy) theorem comp_holderWith {Cg rg : ℝ≥0} {g : Y → Z} {t : Set Y} (hg : HolderOnWith Cg rg g t) @@ -190,11 +190,23 @@ theorem ediam_image_le (hf : HolderWith C r f) (s : Set X) : EMetric.diam_image_le_iff.2 fun _ hx _ hy => hf.edist_le_of_le <| EMetric.edist_le_diam_of_mem hx hy +lemma const {y : Y} : + HolderWith C r (Function.const X y) := fun x₁ x₂ => by + simp only [Function.const_apply, edist_self, zero_le] + +lemma zero [Zero Y] : HolderWith C r (0 : X → Y) := .const + +lemma of_isEmpty [IsEmpty X] : HolderWith C r f := isEmptyElim + +lemma mono {C' : ℝ≥0} (hf : HolderWith C r f) (h : C ≤ C') : + HolderWith C' r f := + fun x₁ x₂ ↦ (hf x₁ x₂).trans (mul_right_mono (coe_le_coe.2 h)) + end HolderWith end Emetric -section Metric +section PseudoMetric variable [PseudoMetricSpace X] [PseudoMetricSpace Y] {C r : ℝ≥0} {f : X → Y} @@ -202,7 +214,7 @@ namespace HolderWith theorem nndist_le_of_le (hf : HolderWith C r f) {x y : X} {d : ℝ≥0} (hd : nndist x y ≤ d) : nndist (f x) (f y) ≤ C * d ^ (r : ℝ) := by - rw [← ENNReal.coe_le_coe, ← edist_nndist, ENNReal.coe_mul, ← + rw [← ENNReal.coe_le_coe, ← edist_nndist, ENNReal.coe_mul, ENNReal.coe_rpow_of_nonneg _ r.coe_nonneg] apply hf.edist_le_of_le rwa [edist_nndist, ENNReal.coe_le_coe] @@ -223,4 +235,40 @@ theorem dist_le (hf : HolderWith C r f) (x y : X) : dist (f x) (f y) ≤ C * dis end HolderWith +end PseudoMetric + +section Metric + +variable [PseudoMetricSpace X] [MetricSpace Y] {C r : ℝ≥0} {f : X → Y} + +@[simp] +lemma holderWith_zero_iff : HolderWith 0 r f ↔ ∀ x₁ x₂, f x₁ = f x₂ := by + refine ⟨fun h x₁ x₂ => ?_, fun h x₁ x₂ => h x₁ x₂ ▸ ?_⟩ + · specialize h x₁ x₂ + simp [ENNReal.coe_zero, zero_mul, nonpos_iff_eq_zero, edist_eq_zero] at h + assumption + · simp only [edist_self, ENNReal.coe_zero, zero_mul, le_refl] + end Metric + +section SeminormedAddCommGroup + +variable [PseudoMetricSpace X] [SeminormedAddCommGroup Y] {C C' r : ℝ≥0} {f g : X → Y} + +namespace HolderWith + +lemma add (hf : HolderWith C r f) (hg : HolderWith C' r g) : + HolderWith (C + C') r (f + g) := fun x₁ x₂ => by + refine le_trans (edist_add_add_le _ _ _ _) <| le_trans (add_le_add (hf x₁ x₂) (hg x₁ x₂)) ?_ + rw [coe_add, add_mul] + +lemma smul {α} [NormedDivisionRing α] [Module α Y] [BoundedSMul α Y] (a : α) + (hf : HolderWith C r f) : HolderWith (C * ‖a‖₊) r (a • f) := fun x₁ x₂ => by + rw [Pi.smul_apply, coe_mul, Pi.smul_apply, edist_smul₀, mul_comm (C : ℝ≥0∞), + ENNReal.smul_def, smul_eq_mul, mul_assoc] + gcongr + exact hf x₁ x₂ + +end HolderWith + +end SeminormedAddCommGroup diff --git a/Mathlib/Topology/MetricSpace/Infsep.lean b/Mathlib/Topology/MetricSpace/Infsep.lean index 027a2e3139f9c..e451f9e7817b3 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 @@ -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 b2464d0e4b65a..0640a68f619aa 100644 --- a/Mathlib/Topology/MetricSpace/Isometry.lean +++ b/Mathlib/Topology/MetricSpace/Isometry.lean @@ -28,7 +28,7 @@ open Function Set open scoped Topology ENNReal /-- An isometry (also known as isometric embedding) is a map preserving the edistance -between pseudoemetric spaces, or equivalently the distance between pseudometric space. -/ +between pseudoemetric spaces, or equivalently the distance between pseudometric space. -/ def Isometry [PseudoEMetricSpace α] [PseudoEMetricSpace β] (f : α → β) : Prop := ∀ x1 x2 : α, edist (f x1) (f x2) = edist x1 x2 @@ -84,10 +84,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 +100,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.inducing.tendsto_nhds_iff /-- An isometry is continuous. -/ protected theorem continuous (hf : Isometry f) : Continuous f := @@ -144,11 +149,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.inducing.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.inducing.continuous_iff.symm end PseudoEmetricIsometry @@ -162,12 +167,14 @@ 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 + hf.isUniformEmbedding.embedding /-- An isometry from a complete emetric space is a closed embedding -/ theorem closedEmbedding [CompleteSpace α] [EMetricSpace γ] {f : α → γ} (hf : Isometry f) : @@ -226,11 +233,14 @@ 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 : α → β} @@ -465,7 +475,7 @@ 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 ‹_› 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/Lipschitz.lean b/Mathlib/Topology/MetricSpace/Lipschitz.lean index 68c14362debf9..75a374b12a72f 100644 --- a/Mathlib/Topology/MetricSpace/Lipschitz.lean +++ b/Mathlib/Topology/MetricSpace/Lipschitz.lean @@ -320,7 +320,7 @@ variable [PseudoMetricSpace α] [PseudoMetricSpace β] {f : α → β} theorem continuousAt_of_locally_lipschitz {x : α} {r : ℝ} (hr : 0 < r) (K : ℝ) (h : ∀ y, dist y x < r → dist (f y) (f x) ≤ K * dist y x) : ContinuousAt f x := by -- We use `h` to squeeze `dist (f y) (f x)` between `0` and `K * dist y x` - refine tendsto_iff_dist_tendsto_zero.2 (squeeze_zero' (eventually_of_forall fun _ => dist_nonneg) + refine tendsto_iff_dist_tendsto_zero.2 (squeeze_zero' (Eventually.of_forall fun _ => dist_nonneg) (mem_of_superset (ball_mem_nhds _ hr) h) ?_) -- Then show that `K * dist y x` tends to zero as `y → x` refine (continuous_const.mul (continuous_id.dist continuous_const)).tendsto' _ _ ?_ diff --git a/Mathlib/Topology/MetricSpace/MetricSeparated.lean b/Mathlib/Topology/MetricSpace/MetricSeparated.lean index 61ef5d09400f4..2529db5502ed7 100644 --- a/Mathlib/Topology/MetricSpace/MetricSeparated.lean +++ b/Mathlib/Topology/MetricSpace/MetricSeparated.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.Topology.EMetricSpace.Basic +import Mathlib.Topology.EMetricSpace.Defs /-! # Metric separated pairs of sets 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 5be13837cfe9c..6db429aedccbf 100644 --- a/Mathlib/Topology/MetricSpace/Polish.lean +++ b/Mathlib/Topology/MetricSpace/Polish.lean @@ -3,11 +3,12 @@ Copyright (c) 2022 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ +import Mathlib.Analysis.Normed.Field.Basic +import Mathlib.Topology.Instances.Nat import Mathlib.Topology.MetricSpace.PiNat import Mathlib.Topology.MetricSpace.Isometry import Mathlib.Topology.MetricSpace.Gluing import Mathlib.Topology.Sets.Opens -import Mathlib.Analysis.Normed.Field.Basic /-! # Polish spaces @@ -145,7 +146,7 @@ theorem _root_.ClosedEmbedding.polishSpace [TopologicalSpace α] [TopologicalSpa letI : MetricSpace α := hf.toEmbedding.comapMetricSpace f haveI : SecondCountableTopology α := hf.toEmbedding.secondCountableTopology have : CompleteSpace α := by - rw [completeSpace_iff_isComplete_range hf.toEmbedding.to_isometry.uniformInducing] + rw [completeSpace_iff_isComplete_range hf.toEmbedding.to_isometry.isUniformInducing] exact hf.isClosed_range.isComplete infer_instance @@ -255,6 +256,8 @@ theorem dist_val_le_dist (x y : CompleteCopy s) : dist x.1 y.1 ≤ dist x y := le_add_of_nonneg_right (abs_nonneg _) instance : TopologicalSpace (CompleteCopy s) := inferInstanceAs (TopologicalSpace s) +instance [SecondCountableTopology α] : SecondCountableTopology (CompleteCopy s) := + inferInstanceAs (SecondCountableTopology s) instance : T0Space (CompleteCopy s) := inferInstanceAs (T0Space s) /-- A metric space structure on a subset `s` of a metric space, designed to make it complete @@ -315,8 +318,8 @@ instance instCompleteSpace [CompleteSpace α] : CompleteSpace (CompleteCopy s) : rw [← s.isOpen.isClosed_compl.not_mem_iff_infDist_pos ⟨x, xs⟩]; exact not_not.symm have I : ∀ n, 1 / C ≤ infDist (u n).1 sᶜ := fun n ↦ by have : 0 < infDist (u n).1 sᶜ := Hmem.1 (u n).2 - rw [div_le_iff' Cpos] - exact (div_le_iff this).1 (hC n).le + rw [div_le_iff₀' Cpos] + exact (div_le_iff₀ this).1 (hC n).le have I' : 1 / C ≤ infDist x sᶜ := have : Tendsto (fun n => infDist (u n).1 sᶜ) atTop (𝓝 (infDist x sᶜ)) := ((continuous_infDist_pt (sᶜ : Set α)).tendsto x).comp xlim @@ -328,7 +331,6 @@ theorem _root_.IsOpen.polishSpace {α : Type*} [TopologicalSpace α] [PolishSpac (hs : IsOpen s) : PolishSpace s := by letI := upgradePolishSpace α lift s to Opens α using hs - have : SecondCountableTopology s.CompleteCopy := inferInstanceAs (SecondCountableTopology s) exact inferInstanceAs (PolishSpace s.CompleteCopy) end CompleteCopy @@ -365,7 +367,13 @@ theorem _root_.IsClosed.isClopenable [TopologicalSpace α] [PolishSpace α] {s : · rw [← f.induced_symm] exact f.symm.polishSpace_induced · rw [isOpen_coinduced, isOpen_sum_iff] - simp [f, preimage_preimage] + simp only [preimage_preimage, f] + have inl (x : s) : (Equiv.Set.sumCompl s) (Sum.inl x) = x := Equiv.Set.sumCompl_apply_inl .. + have inr (x : ↑sᶜ) : (Equiv.Set.sumCompl s) (Sum.inr x) = x := Equiv.Set.sumCompl_apply_inr .. + simp_rw [inl, inr, Subtype.coe_preimage_self] + simp only [isOpen_univ, true_and] + rw [Subtype.preimage_coe_compl'] + simp theorem IsClopenable.compl [TopologicalSpace α] {s : Set α} (hs : IsClopenable s) : IsClopenable sᶜ := by diff --git a/Mathlib/Topology/MetricSpace/ProperSpace.lean b/Mathlib/Topology/MetricSpace/ProperSpace.lean index b44aeb37c523e..e8df38ca5e7a0 100644 --- a/Mathlib/Topology/MetricSpace/ProperSpace.lean +++ b/Mathlib/Topology/MetricSpace/ProperSpace.lean @@ -4,9 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ -import Mathlib.Topology.MetricSpace.Pseudo.Lemmas import Mathlib.Topology.Order.IsLUB import Mathlib.Topology.Support +import Mathlib.Topology.MetricSpace.Pseudo.Basic +import Mathlib.Topology.MetricSpace.Pseudo.Lemmas +import Mathlib.Topology.MetricSpace.Pseudo.Pi /-! ## Proper spaces diff --git a/Mathlib/Topology/MetricSpace/Pseudo/Basic.lean b/Mathlib/Topology/MetricSpace/Pseudo/Basic.lean new file mode 100644 index 0000000000000..550dee230352d --- /dev/null +++ b/Mathlib/Topology/MetricSpace/Pseudo/Basic.lean @@ -0,0 +1,253 @@ +/- +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.Real +import Mathlib.Tactic.Bound.Attribute +import Mathlib.Topology.EMetricSpace.Basic +import Mathlib.Topology.MetricSpace.Pseudo.Defs + +/-! +## Pseudo-metric spaces + +Further results about pseudo-metric spaces. + +-/ + +open Set Filter TopologicalSpace Bornology +open scoped ENNReal NNReal Uniformity Topology + +universe u v w + +variable {α : Type u} {β : Type v} {X ι : Type*} + +variable [PseudoMetricSpace α] + +/-- The triangle (polygon) inequality for sequences of points; `Finset.Ico` version. -/ +theorem dist_le_Ico_sum_dist (f : ℕ → α) {m n} (h : m ≤ n) : + dist (f m) (f n) ≤ ∑ i ∈ Finset.Ico m n, dist (f i) (f (i + 1)) := by + induction n, h using Nat.le_induction with + | base => rw [Finset.Ico_self, Finset.sum_empty, dist_self] + | succ n hle ihn => + calc + dist (f m) (f (n + 1)) ≤ dist (f m) (f n) + dist (f n) (f (n + 1)) := dist_triangle _ _ _ + _ ≤ (∑ i ∈ Finset.Ico m n, _) + _ := add_le_add ihn le_rfl + _ = ∑ i ∈ Finset.Ico m (n + 1), _ := by + { rw [Nat.Ico_succ_right_eq_insert_Ico hle, Finset.sum_insert, add_comm]; simp } + +/-- The triangle (polygon) inequality for sequences of points; `Finset.range` version. -/ +theorem dist_le_range_sum_dist (f : ℕ → α) (n : ℕ) : + dist (f 0) (f n) ≤ ∑ i ∈ Finset.range n, dist (f i) (f (i + 1)) := + Nat.Ico_zero_eq_range ▸ dist_le_Ico_sum_dist f (Nat.zero_le n) + +/-- A version of `dist_le_Ico_sum_dist` with each intermediate distance replaced +with an upper estimate. -/ +theorem dist_le_Ico_sum_of_dist_le {f : ℕ → α} {m n} (hmn : m ≤ n) {d : ℕ → ℝ} + (hd : ∀ {k}, m ≤ k → k < n → dist (f k) (f (k + 1)) ≤ d k) : + dist (f m) (f n) ≤ ∑ i ∈ Finset.Ico m n, d i := + le_trans (dist_le_Ico_sum_dist f hmn) <| + Finset.sum_le_sum fun _k hk => hd (Finset.mem_Ico.1 hk).1 (Finset.mem_Ico.1 hk).2 + +/-- A version of `dist_le_range_sum_dist` with each intermediate distance replaced +with an upper estimate. -/ +theorem dist_le_range_sum_of_dist_le {f : ℕ → α} (n : ℕ) {d : ℕ → ℝ} + (hd : ∀ {k}, k < n → dist (f k) (f (k + 1)) ≤ d k) : + dist (f 0) (f n) ≤ ∑ i ∈ Finset.range n, d i := + Nat.Ico_zero_eq_range ▸ dist_le_Ico_sum_of_dist_le (zero_le n) fun _ => hd + +namespace Metric + +-- instantiate pseudometric space as a topology +variable {x y z : α} {δ ε ε₁ ε₂ : ℝ} {s : Set α} + +nonrec theorem isUniformInducing_iff [PseudoMetricSpace β] {f : α → β} : + IsUniformInducing f ↔ UniformContinuous f ∧ + ∀ δ > 0, ∃ ε > 0, ∀ {a b : α}, dist (f a) (f b) < ε → dist a b < δ := + isUniformInducing_iff'.trans <| Iff.rfl.and <| + ((uniformity_basis_dist.comap _).le_basis_iff uniformity_basis_dist).trans <| by + simp only [subset_def, Prod.forall, gt_iff_lt, preimage_setOf_eq, Prod.map_apply, mem_setOf] + +@[deprecated (since := "2024-10-05")] +alias uniformInducing_iff := isUniformInducing_iff + +nonrec theorem isUniformEmbedding_iff [PseudoMetricSpace β] {f : α → β} : + IsUniformEmbedding f ↔ Function.Injective f ∧ UniformContinuous f ∧ + ∀ δ > 0, ∃ ε > 0, ∀ {a b : α}, dist (f a) (f b) < ε → dist a b < δ := by + rw [isUniformEmbedding_iff, and_comm, 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_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, (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 ε := + uniformity_basis_dist.totallyBounded_iff + +/-- A pseudometric space is totally bounded if one can reconstruct up to any ε>0 any element of the +space from finitely many data. -/ +theorem totallyBounded_of_finite_discretization {s : Set α} + (H : ∀ ε > (0 : ℝ), + ∃ (β : Type u) (_ : Fintype β) (F : s → β), ∀ x y, F x = F y → dist (x : α) y < ε) : + TotallyBounded s := by + rcases s.eq_empty_or_nonempty with hs | hs + · rw [hs] + exact totallyBounded_empty + rcases hs with ⟨x0, hx0⟩ + haveI : Inhabited s := ⟨⟨x0, hx0⟩⟩ + refine totallyBounded_iff.2 fun ε ε0 => ?_ + rcases H ε ε0 with ⟨β, fβ, F, hF⟩ + let Finv := Function.invFun F + refine ⟨range (Subtype.val ∘ Finv), finite_range _, fun x xs => ?_⟩ + let x' := Finv (F ⟨x, xs⟩) + have : F x' = F ⟨x, xs⟩ := Function.invFun_eq ⟨⟨x, xs⟩, rfl⟩ + simp only [Set.mem_iUnion, Set.mem_range] + exact ⟨_, ⟨F ⟨x, xs⟩, rfl⟩, hF _ _ this.symm⟩ + +theorem finite_approx_of_totallyBounded {s : Set α} (hs : TotallyBounded s) : + ∀ ε > 0, ∃ t, t ⊆ s ∧ Set.Finite t ∧ s ⊆ ⋃ y ∈ t, ball y ε := by + intro ε ε_pos + rw [totallyBounded_iff_subset] at hs + exact hs _ (dist_mem_uniformity ε_pos) + +/-- Expressing uniform convergence using `dist` -/ +theorem tendstoUniformlyOnFilter_iff {F : ι → β → α} {f : β → α} {p : Filter ι} {p' : Filter β} : + TendstoUniformlyOnFilter F f p p' ↔ + ∀ ε > 0, ∀ᶠ n : ι × β in p ×ˢ p', dist (f n.snd) (F n.fst n.snd) < ε := by + refine ⟨fun H ε hε => H _ (dist_mem_uniformity hε), fun H u hu => ?_⟩ + rcases mem_uniformity_dist.1 hu with ⟨ε, εpos, hε⟩ + exact (H ε εpos).mono fun n hn => hε hn + +/-- Expressing locally uniform convergence on a set using `dist`. -/ +theorem tendstoLocallyUniformlyOn_iff [TopologicalSpace β] {F : ι → β → α} {f : β → α} + {p : Filter ι} {s : Set β} : + TendstoLocallyUniformlyOn F f p s ↔ + ∀ ε > 0, ∀ x ∈ s, ∃ t ∈ 𝓝[s] x, ∀ᶠ n in p, ∀ y ∈ t, dist (f y) (F n y) < ε := by + refine ⟨fun H ε hε => H _ (dist_mem_uniformity hε), fun H u hu x hx => ?_⟩ + rcases mem_uniformity_dist.1 hu with ⟨ε, εpos, hε⟩ + rcases H ε εpos x hx with ⟨t, ht, Ht⟩ + exact ⟨t, ht, Ht.mono fun n hs x hx => hε (hs x hx)⟩ + +/-- Expressing uniform convergence on a set using `dist`. -/ +theorem tendstoUniformlyOn_iff {F : ι → β → α} {f : β → α} {p : Filter ι} {s : Set β} : + TendstoUniformlyOn F f p s ↔ ∀ ε > 0, ∀ᶠ n in p, ∀ x ∈ s, dist (f x) (F n x) < ε := by + refine ⟨fun H ε hε => H _ (dist_mem_uniformity hε), fun H u hu => ?_⟩ + rcases mem_uniformity_dist.1 hu with ⟨ε, εpos, hε⟩ + exact (H ε εpos).mono fun n hs x hx => hε (hs x hx) + +/-- Expressing locally uniform convergence using `dist`. -/ +theorem tendstoLocallyUniformly_iff [TopologicalSpace β] {F : ι → β → α} {f : β → α} + {p : Filter ι} : + TendstoLocallyUniformly F f p ↔ + ∀ ε > 0, ∀ x : β, ∃ t ∈ 𝓝 x, ∀ᶠ n in p, ∀ y ∈ t, dist (f y) (F n y) < ε := by + simp only [← tendstoLocallyUniformlyOn_univ, tendstoLocallyUniformlyOn_iff, nhdsWithin_univ, + mem_univ, forall_const, exists_prop] + +/-- Expressing uniform convergence using `dist`. -/ +theorem tendstoUniformly_iff {F : ι → β → α} {f : β → α} {p : Filter ι} : + TendstoUniformly F f p ↔ ∀ ε > 0, ∀ᶠ n in p, ∀ x, dist (f x) (F n x) < ε := by + rw [← tendstoUniformlyOn_univ, tendstoUniformlyOn_iff] + simp + +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 + +/-- 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) : + ∃ ε > 0, Metric.ball x ε ∩ s = {x} := + nhds_basis_ball.exists_inter_eq_singleton_of_mem_discrete hx + +/-- Given a point `x` in a discrete subset `s` of a pseudometric space, there is a closed ball +of positive radius centered at `x` and intersecting `s` only at `x`. -/ +theorem exists_closedBall_inter_eq_singleton_of_discrete [DiscreteTopology s] {x : α} (hx : x ∈ s) : + ∃ ε > 0, Metric.closedBall x ε ∩ s = {x} := + nhds_basis_closedBall.exists_inter_eq_singleton_of_mem_discrete hx + +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 [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 + +theorem cauchySeq_iff_tendsto_dist_atTop_0 [Nonempty β] [SemilatticeSup β] {u : β → α} : + CauchySeq u ↔ Tendsto (fun n : β × β => dist (u n.1) (u n.2)) atTop (𝓝 0) := by + rw [cauchySeq_iff_tendsto, Metric.uniformity_eq_comap_nhds_zero, tendsto_comap_iff, + Function.comp_def] + simp_rw [Prod.map_fst, Prod.map_snd] + +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 + 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 := 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 + +end Metric + +/-- A compact set is separable. -/ +theorem IsCompact.isSeparable {s : Set α} (hs : IsCompact s) : IsSeparable s := + haveI : CompactSpace s := isCompact_iff_compactSpace.mp hs + .of_subtype s + +namespace Metric + +section SecondCountable + +open TopologicalSpace + +/-- A pseudometric space is second countable if, for every `ε > 0`, there is a countable set which +is `ε`-dense. -/ +theorem secondCountable_of_almost_dense_set + (H : ∀ ε > (0 : ℝ), ∃ s : Set α, s.Countable ∧ ∀ x, ∃ y ∈ s, dist x y ≤ ε) : + SecondCountableTopology α := by + refine EMetric.secondCountable_of_almost_dense_set fun ε ε0 => ?_ + rcases ENNReal.lt_iff_exists_nnreal_btwn.1 ε0 with ⟨ε', ε'0, ε'ε⟩ + choose s hsc y hys hyx using H ε' (mod_cast ε'0) + refine ⟨s, hsc, iUnion₂_eq_univ_iff.2 fun x => ⟨y x, hys _, le_trans ?_ ε'ε.le⟩⟩ + exact mod_cast hyx x + +end SecondCountable + +end Metric diff --git a/Mathlib/Topology/MetricSpace/Pseudo/Constructions.lean b/Mathlib/Topology/MetricSpace/Pseudo/Constructions.lean index 06c84c99cc8fb..764f2c2b7f1f1 100644 --- a/Mathlib/Topology/MetricSpace/Pseudo/Constructions.lean +++ b/Mathlib/Topology/MetricSpace/Pseudo/Constructions.lean @@ -5,11 +5,12 @@ Authors: Jeremy Avigad, Robert Y. Lewis, Johannes Hölzl, Mario Carneiro, Sébas -/ import Mathlib.Topology.Bornology.Constructions import Mathlib.Topology.MetricSpace.Pseudo.Defs +import Mathlib.Topology.UniformSpace.UniformEmbedding /-! -# Product of pseudo-metric spaces and other constructions +# Products of pseudometric spaces and other constructions -This file constructs the infinity distance on finite products of normed groups and provides +This file constructs the supremum distance on binary products of pseudometric spaces and provides instances for type synonyms. -/ @@ -43,10 +44,13 @@ def Inducing.comapPseudoMetricSpace {α β} [TopologicalSpace α] [m : PseudoMet /-- 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 ‹_› @@ -232,152 +236,3 @@ protected lemma Filter.Tendsto.nndist {f g : β → α} {x : Filter β} {a b : (hf : Tendsto f x (𝓝 a)) (hg : Tendsto g x (𝓝 b)) : Tendsto (fun x => nndist (f x) (g x)) x (𝓝 (nndist a b)) := (continuous_nndist.tendsto (a, b)).comp (hf.prod_mk_nhds hg) - -section Pi - -open Finset - -variable {π : β → Type*} [Fintype β] [∀ b, PseudoMetricSpace (π b)] - -/-- A finite product of pseudometric spaces is a pseudometric space, with the sup distance. -/ -instance pseudoMetricSpacePi : PseudoMetricSpace (∀ b, π b) := by - /- we construct the instance from the pseudoemetric space instance to avoid checking again that - the uniformity is the same as the product uniformity, but we register nevertheless a nice - formula for the distance -/ - let i := PseudoEMetricSpace.toPseudoMetricSpaceOfDist - (fun f g : ∀ b, π b => ((sup univ fun b => nndist (f b) (g b) : ℝ≥0) : ℝ)) - (fun f g => ((Finset.sup_lt_iff bot_lt_top).2 fun b _ => edist_lt_top _ _).ne) - (fun f g => by - simp only [edist_pi_def, edist_nndist, ← ENNReal.coe_finset_sup, ENNReal.coe_toReal]) - refine i.replaceBornology fun s => ?_ - simp only [← isBounded_def, isBounded_iff_eventually, ← forall_isBounded_image_eval_iff, - forall_mem_image, ← Filter.eventually_all, Function.eval_apply, @dist_nndist (π _)] - refine eventually_congr ((eventually_ge_atTop 0).mono fun C hC ↦ ?_) - lift C to ℝ≥0 using hC - refine ⟨fun H x hx y hy ↦ NNReal.coe_le_coe.2 <| Finset.sup_le fun b _ ↦ H b hx hy, - fun H b x hx y hy ↦ NNReal.coe_le_coe.2 ?_⟩ - simpa only using Finset.sup_le_iff.1 (NNReal.coe_le_coe.1 <| H hx hy) b (Finset.mem_univ b) - -lemma nndist_pi_def (f g : ∀ b, π b) : nndist f g = sup univ fun b => nndist (f b) (g b) := rfl - -lemma dist_pi_def (f g : ∀ b, π b) : dist f g = (sup univ fun b => nndist (f b) (g b) : ℝ≥0) := rfl - -lemma nndist_pi_le_iff {f g : ∀ b, π b} {r : ℝ≥0} : - nndist f g ≤ r ↔ ∀ b, nndist (f b) (g b) ≤ r := by simp [nndist_pi_def] - -lemma nndist_pi_lt_iff {f g : ∀ b, π b} {r : ℝ≥0} (hr : 0 < r) : - nndist f g < r ↔ ∀ b, nndist (f b) (g b) < r := by - rw [← bot_eq_zero'] at hr - simp [nndist_pi_def, Finset.sup_lt_iff hr] - -lemma nndist_pi_eq_iff {f g : ∀ b, π b} {r : ℝ≥0} (hr : 0 < r) : - nndist f g = r ↔ (∃ i, nndist (f i) (g i) = r) ∧ ∀ b, nndist (f b) (g b) ≤ r := by - rw [eq_iff_le_not_lt, nndist_pi_lt_iff hr, nndist_pi_le_iff, not_forall, and_comm] - simp_rw [not_lt, and_congr_left_iff, le_antisymm_iff] - intro h - refine exists_congr fun b => ?_ - apply (and_iff_right <| h _).symm - -lemma dist_pi_lt_iff {f g : ∀ b, π b} {r : ℝ} (hr : 0 < r) : - dist f g < r ↔ ∀ b, dist (f b) (g b) < r := by - lift r to ℝ≥0 using hr.le - exact nndist_pi_lt_iff hr - -lemma dist_pi_le_iff {f g : ∀ b, π b} {r : ℝ} (hr : 0 ≤ r) : - dist f g ≤ r ↔ ∀ b, dist (f b) (g b) ≤ r := by - lift r to ℝ≥0 using hr - exact nndist_pi_le_iff - -lemma dist_pi_eq_iff {f g : ∀ b, π b} {r : ℝ} (hr : 0 < r) : - dist f g = r ↔ (∃ i, dist (f i) (g i) = r) ∧ ∀ b, dist (f b) (g b) ≤ r := by - lift r to ℝ≥0 using hr.le - simp_rw [← coe_nndist, NNReal.coe_inj, nndist_pi_eq_iff hr, NNReal.coe_le_coe] - -lemma dist_pi_le_iff' [Nonempty β] {f g : ∀ b, π b} {r : ℝ} : - dist f g ≤ r ↔ ∀ b, dist (f b) (g b) ≤ r := by - by_cases hr : 0 ≤ r - · exact dist_pi_le_iff hr - · exact iff_of_false (fun h => hr <| dist_nonneg.trans h) fun h => - hr <| dist_nonneg.trans <| h <| Classical.arbitrary _ - -lemma dist_pi_const_le (a b : α) : (dist (fun _ : β => a) fun _ => b) ≤ dist a b := - (dist_pi_le_iff dist_nonneg).2 fun _ => le_rfl - -lemma nndist_pi_const_le (a b : α) : (nndist (fun _ : β => a) fun _ => b) ≤ nndist a b := - nndist_pi_le_iff.2 fun _ => le_rfl - -@[simp] -lemma dist_pi_const [Nonempty β] (a b : α) : (dist (fun _ : β => a) fun _ => b) = dist a b := by - simpa only [dist_edist] using congr_arg ENNReal.toReal (edist_pi_const a b) - -@[simp] -lemma nndist_pi_const [Nonempty β] (a b : α) : (nndist (fun _ : β => a) fun _ => b) = nndist a b := - NNReal.eq <| dist_pi_const a b - -lemma nndist_le_pi_nndist (f g : ∀ b, π b) (b : β) : nndist (f b) (g b) ≤ nndist f g := by - rw [← ENNReal.coe_le_coe, ← edist_nndist, ← edist_nndist] - exact edist_le_pi_edist f g b - -lemma dist_le_pi_dist (f g : ∀ b, π b) (b : β) : dist (f b) (g b) ≤ dist f g := by - simp only [dist_nndist, NNReal.coe_le_coe, nndist_le_pi_nndist f g b] - -/-- An open ball in a product space is a product of open balls. See also `ball_pi'` -for a version assuming `Nonempty β` instead of `0 < r`. -/ -lemma ball_pi (x : ∀ b, π b) {r : ℝ} (hr : 0 < r) : - ball x r = Set.pi univ fun b => ball (x b) r := by - ext p - simp [dist_pi_lt_iff hr] - -/-- An open ball in a product space is a product of open balls. See also `ball_pi` -for a version assuming `0 < r` instead of `Nonempty β`. -/ -lemma ball_pi' [Nonempty β] (x : ∀ b, π b) (r : ℝ) : - ball x r = Set.pi univ fun b => ball (x b) r := - (lt_or_le 0 r).elim (ball_pi x) fun hr => by simp [ball_eq_empty.2 hr] - -/-- A closed ball in a product space is a product of closed balls. See also `closedBall_pi'` -for a version assuming `Nonempty β` instead of `0 ≤ r`. -/ -lemma closedBall_pi (x : ∀ b, π b) {r : ℝ} (hr : 0 ≤ r) : - closedBall x r = Set.pi univ fun b => closedBall (x b) r := by - ext p - simp [dist_pi_le_iff hr] - -/-- A closed ball in a product space is a product of closed balls. See also `closedBall_pi` -for a version assuming `0 ≤ r` instead of `Nonempty β`. -/ -lemma closedBall_pi' [Nonempty β] (x : ∀ b, π b) (r : ℝ) : - closedBall x r = Set.pi univ fun b => closedBall (x b) r := - (le_or_lt 0 r).elim (closedBall_pi x) fun hr => by simp [closedBall_eq_empty.2 hr] - -/-- A sphere in a product space is a union of spheres on each component restricted to the closed -ball. -/ -lemma sphere_pi (x : ∀ b, π b) {r : ℝ} (h : 0 < r ∨ Nonempty β) : - sphere x r = (⋃ i : β, Function.eval i ⁻¹' sphere (x i) r) ∩ closedBall x r := by - obtain hr | rfl | hr := lt_trichotomy r 0 - · simp [hr] - · rw [closedBall_eq_sphere_of_nonpos le_rfl, eq_comm, Set.inter_eq_right] - letI := h.resolve_left (lt_irrefl _) - inhabit β - refine subset_iUnion_of_subset default ?_ - intro x hx - replace hx := hx.le - rw [dist_pi_le_iff le_rfl] at hx - exact le_antisymm (hx default) dist_nonneg - · ext - simp [dist_pi_eq_iff hr, dist_pi_le_iff hr.le] - -@[simp] -lemma Fin.nndist_insertNth_insertNth {n : ℕ} {α : Fin (n + 1) → Type*} - [∀ i, PseudoMetricSpace (α i)] (i : Fin (n + 1)) (x y : α i) (f g : ∀ j, α (i.succAbove j)) : - nndist (i.insertNth x f) (i.insertNth y g) = max (nndist x y) (nndist f g) := - eq_of_forall_ge_iff fun c => by simp [nndist_pi_le_iff, i.forall_iff_succAbove] - -@[simp] -lemma Fin.dist_insertNth_insertNth {n : ℕ} {α : Fin (n + 1) → Type*} - [∀ i, PseudoMetricSpace (α i)] (i : Fin (n + 1)) (x y : α i) (f g : ∀ j, α (i.succAbove j)) : - dist (i.insertNth x f) (i.insertNth y g) = max (dist x y) (dist f g) := by - simp only [dist_nndist, Fin.nndist_insertNth_insertNth, NNReal.coe_max] - -end Pi - -instance : PseudoMetricSpace (Additive α) := ‹_› -instance : PseudoMetricSpace (Multiplicative α) := ‹_› -instance : PseudoMetricSpace αᵒᵈ := ‹_› diff --git a/Mathlib/Topology/MetricSpace/Pseudo/Defs.lean b/Mathlib/Topology/MetricSpace/Pseudo/Defs.lean index 282e00a70e43b..89df0d0b39ba3 100644 --- a/Mathlib/Topology/MetricSpace/Pseudo/Defs.lean +++ b/Mathlib/Topology/MetricSpace/Pseudo/Defs.lean @@ -3,8 +3,9 @@ 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.EMetricSpace.Basic +import Mathlib.Data.ENNReal.Real import Mathlib.Tactic.Bound.Attribute +import Mathlib.Topology.EMetricSpace.Defs /-! ## Pseudo-metric spaces @@ -195,38 +196,6 @@ theorem dist_triangle4_right (x₁ y₁ x₂ y₂ : α) : rw [add_right_comm, dist_comm y₁] apply dist_triangle4 -/-- The triangle (polygon) inequality for sequences of points; `Finset.Ico` version. -/ -theorem dist_le_Ico_sum_dist (f : ℕ → α) {m n} (h : m ≤ n) : - dist (f m) (f n) ≤ ∑ i ∈ Finset.Ico m n, dist (f i) (f (i + 1)) := by - induction n, h using Nat.le_induction with - | base => rw [Finset.Ico_self, Finset.sum_empty, dist_self] - | succ n hle ihn => - calc - dist (f m) (f (n + 1)) ≤ dist (f m) (f n) + dist (f n) (f (n + 1)) := dist_triangle _ _ _ - _ ≤ (∑ i ∈ Finset.Ico m n, _) + _ := add_le_add ihn le_rfl - _ = ∑ i ∈ Finset.Ico m (n + 1), _ := by - { rw [Nat.Ico_succ_right_eq_insert_Ico hle, Finset.sum_insert, add_comm]; simp } - -/-- The triangle (polygon) inequality for sequences of points; `Finset.range` version. -/ -theorem dist_le_range_sum_dist (f : ℕ → α) (n : ℕ) : - dist (f 0) (f n) ≤ ∑ i ∈ Finset.range n, dist (f i) (f (i + 1)) := - Nat.Ico_zero_eq_range ▸ dist_le_Ico_sum_dist f (Nat.zero_le n) - -/-- A version of `dist_le_Ico_sum_dist` with each intermediate distance replaced -with an upper estimate. -/ -theorem dist_le_Ico_sum_of_dist_le {f : ℕ → α} {m n} (hmn : m ≤ n) {d : ℕ → ℝ} - (hd : ∀ {k}, m ≤ k → k < n → dist (f k) (f (k + 1)) ≤ d k) : - dist (f m) (f n) ≤ ∑ i ∈ Finset.Ico m n, d i := - le_trans (dist_le_Ico_sum_dist f hmn) <| - Finset.sum_le_sum fun _k hk => hd (Finset.mem_Ico.1 hk).1 (Finset.mem_Ico.1 hk).2 - -/-- A version of `dist_le_range_sum_dist` with each intermediate distance replaced -with an upper estimate. -/ -theorem dist_le_range_sum_of_dist_le {f : ℕ → α} (n : ℕ) {d : ℕ → ℝ} - (hd : ∀ {k}, k < n → dist (f k) (f (k + 1)) ≤ d k) : - dist (f 0) (f n) ≤ ∑ i ∈ Finset.range n, d i := - Nat.Ico_zero_eq_range ▸ dist_le_Ico_sum_of_dist_le (zero_le n) fun _ => hd - theorem swap_dist : Function.swap (@dist α _) = dist := by funext x y; exact dist_comm _ _ theorem abs_dist_sub_le (x y z : α) : |dist x z - dist y z| ≤ dist x y := @@ -294,15 +263,15 @@ theorem edist_lt_coe {x y : α} {c : ℝ≥0} : edist x y < c ↔ nndist x y < c theorem edist_le_coe {x y : α} {c : ℝ≥0} : edist x y ≤ c ↔ nndist x y ≤ c := by rw [edist_nndist, ENNReal.coe_le_coe] -/-- In a pseudometric space, the extended distance is always finite-/ +/-- In a pseudometric space, the extended distance is always finite -/ theorem edist_lt_top {α : Type*} [PseudoMetricSpace α] (x y : α) : edist x y < ⊤ := (edist_dist x y).symm ▸ ENNReal.ofReal_lt_top -/-- In a pseudometric space, the extended distance is always finite-/ +/-- In a pseudometric space, the extended distance is always finite -/ theorem edist_ne_top (x y : α) : edist x y ≠ ⊤ := (edist_lt_top x y).ne -/-- `nndist x x` vanishes-/ +/-- `nndist x x` vanishes -/ @[simp] theorem nndist_self (a : α) : nndist a a = 0 := NNReal.coe_eq_zero.1 (dist_self a) -- Porting note: `dist_nndist` and `coe_nndist` moved up @@ -330,7 +299,7 @@ theorem nndist_dist (x y : α) : nndist x y = Real.toNNReal (dist x y) := by theorem nndist_comm (x y : α) : nndist x y = nndist y x := NNReal.eq <| dist_comm x y -/-- Triangle inequality for the nonnegative distance-/ +/-- Triangle inequality for the nonnegative distance -/ theorem nndist_triangle (x y z : α) : nndist x z ≤ nndist x y + nndist y z := dist_triangle _ _ _ @@ -713,98 +682,6 @@ theorem uniformContinuousOn_iff_le [PseudoMetricSpace β] {f : α → β} {s : S ∀ ε > 0, ∃ δ > 0, ∀ x ∈ s, ∀ y ∈ s, dist x y ≤ δ → dist (f x) (f y) ≤ ε := Metric.uniformity_basis_dist_le.uniformContinuousOn_iff Metric.uniformity_basis_dist_le -nonrec theorem uniformInducing_iff [PseudoMetricSpace β] {f : α → β} : - UniformInducing f ↔ UniformContinuous f ∧ - ∀ δ > 0, ∃ ε > 0, ∀ {a b : α}, dist (f a) (f b) < ε → dist a b < δ := - uniformInducing_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 ∧ - ∀ δ > 0, ∃ ε > 0, ∀ {a b : α}, dist (f a) (f b) < ε → dist a b < δ := by - rw [uniformEmbedding_iff, and_comm, uniformInducing_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) : - (∀ ε > 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⟩ - -theorem totallyBounded_iff {s : Set α} : - TotallyBounded s ↔ ∀ ε > 0, ∃ t : Set α, t.Finite ∧ s ⊆ ⋃ y ∈ t, ball y ε := - uniformity_basis_dist.totallyBounded_iff - -/-- A pseudometric space is totally bounded if one can reconstruct up to any ε>0 any element of the -space from finitely many data. -/ -theorem totallyBounded_of_finite_discretization {s : Set α} - (H : ∀ ε > (0 : ℝ), - ∃ (β : Type u) (_ : Fintype β) (F : s → β), ∀ x y, F x = F y → dist (x : α) y < ε) : - TotallyBounded s := by - rcases s.eq_empty_or_nonempty with hs | hs - · rw [hs] - exact totallyBounded_empty - rcases hs with ⟨x0, hx0⟩ - haveI : Inhabited s := ⟨⟨x0, hx0⟩⟩ - refine totallyBounded_iff.2 fun ε ε0 => ?_ - rcases H ε ε0 with ⟨β, fβ, F, hF⟩ - let Finv := Function.invFun F - refine ⟨range (Subtype.val ∘ Finv), finite_range _, fun x xs => ?_⟩ - let x' := Finv (F ⟨x, xs⟩) - have : F x' = F ⟨x, xs⟩ := Function.invFun_eq ⟨⟨x, xs⟩, rfl⟩ - simp only [Set.mem_iUnion, Set.mem_range] - exact ⟨_, ⟨F ⟨x, xs⟩, rfl⟩, hF _ _ this.symm⟩ - -theorem finite_approx_of_totallyBounded {s : Set α} (hs : TotallyBounded s) : - ∀ ε > 0, ∃ t, t ⊆ s ∧ Set.Finite t ∧ s ⊆ ⋃ y ∈ t, ball y ε := by - intro ε ε_pos - rw [totallyBounded_iff_subset] at hs - exact hs _ (dist_mem_uniformity ε_pos) - -/-- Expressing uniform convergence using `dist` -/ -theorem tendstoUniformlyOnFilter_iff {F : ι → β → α} {f : β → α} {p : Filter ι} {p' : Filter β} : - TendstoUniformlyOnFilter F f p p' ↔ - ∀ ε > 0, ∀ᶠ n : ι × β in p ×ˢ p', dist (f n.snd) (F n.fst n.snd) < ε := by - refine ⟨fun H ε hε => H _ (dist_mem_uniformity hε), fun H u hu => ?_⟩ - rcases mem_uniformity_dist.1 hu with ⟨ε, εpos, hε⟩ - exact (H ε εpos).mono fun n hn => hε hn - -/-- Expressing locally uniform convergence on a set using `dist`. -/ -theorem tendstoLocallyUniformlyOn_iff [TopologicalSpace β] {F : ι → β → α} {f : β → α} - {p : Filter ι} {s : Set β} : - TendstoLocallyUniformlyOn F f p s ↔ - ∀ ε > 0, ∀ x ∈ s, ∃ t ∈ 𝓝[s] x, ∀ᶠ n in p, ∀ y ∈ t, dist (f y) (F n y) < ε := by - refine ⟨fun H ε hε => H _ (dist_mem_uniformity hε), fun H u hu x hx => ?_⟩ - rcases mem_uniformity_dist.1 hu with ⟨ε, εpos, hε⟩ - rcases H ε εpos x hx with ⟨t, ht, Ht⟩ - exact ⟨t, ht, Ht.mono fun n hs x hx => hε (hs x hx)⟩ - -/-- Expressing uniform convergence on a set using `dist`. -/ -theorem tendstoUniformlyOn_iff {F : ι → β → α} {f : β → α} {p : Filter ι} {s : Set β} : - TendstoUniformlyOn F f p s ↔ ∀ ε > 0, ∀ᶠ n in p, ∀ x ∈ s, dist (f x) (F n x) < ε := by - refine ⟨fun H ε hε => H _ (dist_mem_uniformity hε), fun H u hu => ?_⟩ - rcases mem_uniformity_dist.1 hu with ⟨ε, εpos, hε⟩ - exact (H ε εpos).mono fun n hs x hx => hε (hs x hx) - -/-- Expressing locally uniform convergence using `dist`. -/ -theorem tendstoLocallyUniformly_iff [TopologicalSpace β] {F : ι → β → α} {f : β → α} - {p : Filter ι} : - TendstoLocallyUniformly F f p ↔ - ∀ ε > 0, ∀ x : β, ∃ t ∈ 𝓝 x, ∀ᶠ n in p, ∀ y ∈ t, dist (f y) (F n y) < ε := by - simp only [← tendstoLocallyUniformlyOn_univ, tendstoLocallyUniformlyOn_iff, nhdsWithin_univ, - mem_univ, forall_const, exists_prop] - -/-- Expressing uniform convergence using `dist`. -/ -theorem tendstoUniformly_iff {F : ι → β → α} {f : β → α} {p : Filter ι} : - TendstoUniformly F f p ↔ ∀ ε > 0, ∀ᶠ n in p, ∀ x, dist (f x) (F n x) < ε := by - rw [← tendstoUniformlyOn_univ, tendstoUniformlyOn_iff] - simp - -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 - theorem nhds_basis_ball : (𝓝 x).HasBasis (0 < ·) (ball x) := nhds_basis_uniformity uniformity_basis_dist @@ -889,7 +766,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 < ε := @@ -949,18 +826,6 @@ theorem isOpen_singleton_iff {α : Type*} [PseudoMetricSpace α] {x : α} : IsOpen ({x} : Set α) ↔ ∃ ε > 0, ∀ y, dist y x < ε → y = x := by simp [isOpen_iff, subset_singleton_iff, mem_ball] -/-- 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) : - ∃ ε > 0, Metric.ball x ε ∩ s = {x} := - nhds_basis_ball.exists_inter_eq_singleton_of_mem_discrete hx - -/-- Given a point `x` in a discrete subset `s` of a pseudometric space, there is a closed ball -of positive radius centered at `x` and intersecting `s` only at `x`. -/ -theorem exists_closedBall_inter_eq_singleton_of_discrete [DiscreteTopology s] {x : α} (hx : x ∈ s) : - ∃ ε > 0, Metric.closedBall x ε ∩ s = {x} := - nhds_basis_closedBall.exists_inter_eq_singleton_of_mem_discrete hx - theorem _root_.Dense.exists_dist_lt {s : Set α} (hs : Dense s) (x : α) {ε : ℝ} (hε : 0 < ε) : ∃ y ∈ s, dist x y < ε := by have : (ball x ε).Nonempty := by simp [hε] @@ -1052,12 +917,10 @@ theorem Metric.emetric_closedBall_nnreal {x : α} {ε : ℝ≥0} : theorem Metric.emetric_ball_top (x : α) : EMetric.ball x ⊤ = univ := eq_univ_of_forall fun _ => edist_lt_top _ _ -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] - /-- Build a new pseudometric space from an old one where the bundled uniform structure is provably (but typically non-definitionaly) equal to some given uniform structure. See Note [forgetful inheritance]. +See Note [reducible non-instances]. -/ abbrev PseudoMetricSpace.replaceUniformity {α} [U : UniformSpace α] (m : PseudoMetricSpace α) (H : 𝓤[U] = 𝓤[PseudoEMetricSpace.toUniformSpace]) : PseudoMetricSpace α := @@ -1073,11 +936,13 @@ theorem PseudoMetricSpace.replaceUniformity_eq {α} [U : UniformSpace α] (m : P -- ensure that the bornology is unchanged when replacing the uniformity. example {α} [U : UniformSpace α] (m : PseudoMetricSpace α) (H : 𝓤[U] = 𝓤[PseudoEMetricSpace.toUniformSpace]) : - (PseudoMetricSpace.replaceUniformity m H).toBornology = m.toBornology := rfl + (PseudoMetricSpace.replaceUniformity m H).toBornology = m.toBornology := by + with_reducible_and_instances rfl /-- Build a new pseudo metric space from an old one where the bundled topological structure is provably (but typically non-definitionaly) equal to some given topological structure. See Note [forgetful inheritance]. +See Note [reducible non-instances]. -/ abbrev PseudoMetricSpace.replaceTopology {γ} [U : TopologicalSpace γ] (m : PseudoMetricSpace γ) (H : U = m.toUniformSpace.toTopologicalSpace) : PseudoMetricSpace γ := @@ -1120,6 +985,7 @@ abbrev PseudoEMetricSpace.toPseudoMetricSpace {α : Type u} [PseudoEMetricSpace /-- Build a new pseudometric space from an old one where the bundled bornology structure is provably (but typically non-definitionaly) equal to some given bornology structure. See Note [forgetful inheritance]. +See Note [reducible non-instances]. -/ abbrev PseudoMetricSpace.replaceBornology {α} [B : Bornology α] (m : PseudoMetricSpace α) (H : ∀ s, @IsBounded _ B s ↔ @IsBounded _ PseudoMetricSpace.toBornology s) : @@ -1138,7 +1004,8 @@ theorem PseudoMetricSpace.replaceBornology_eq {α} [m : PseudoMetricSpace α] [B -- ensure that the uniformity is unchanged when replacing the bornology. example {α} [B : Bornology α] (m : PseudoMetricSpace α) (H : ∀ s, @IsBounded _ B s ↔ @IsBounded _ PseudoMetricSpace.toBornology s) : - (PseudoMetricSpace.replaceBornology m H).toUniformSpace = m.toUniformSpace := rfl + (PseudoMetricSpace.replaceBornology m H).toUniformSpace = m.toUniformSpace := by + with_reducible_and_instances rfl section Real @@ -1186,12 +1053,6 @@ theorem Metric.uniformity_eq_comap_nhds_zero : simp only [mem_uniformity_dist, (nhds_basis_ball.comap _).mem_iff] simp [subset_def, Real.dist_0_eq_abs] -theorem cauchySeq_iff_tendsto_dist_atTop_0 [Nonempty β] [SemilatticeSup β] {u : β → α} : - CauchySeq u ↔ Tendsto (fun n : β × β => dist (u n.1) (u n.2)) atTop (𝓝 0) := by - rw [cauchySeq_iff_tendsto, Metric.uniformity_eq_comap_nhds_zero, tendsto_comap_iff, - Function.comp_def] - simp_rw [Prod.map_fst, Prod.map_snd] - theorem tendsto_uniformity_iff_dist_tendsto_zero {f : ι → α × α} {p : Filter ι} : Tendsto f p (𝓤 α) ↔ Tendsto (fun x => dist (f x).1 (f x).2) p (𝓝 0) := by rw [Metric.uniformity_eq_comap_nhds_zero, tendsto_comap_iff, Function.comp_def] @@ -1222,7 +1083,7 @@ theorem dist_dist_dist_le (x y x' y' : α) : dist (dist x y) (dist x' y') ≤ di theorem nhds_comap_dist (a : α) : ((𝓝 (0 : ℝ)).comap (dist · a)) = 𝓝 a := by simp only [@nhds_eq_comap_uniformity α, Metric.uniformity_eq_comap_nhds_zero, comap_comap, - (· ∘ ·), dist_comm] + Function.comp_def, dist_comm] theorem tendsto_iff_dist_tendsto_zero {f : β → α} {x : Filter β} {a : α} : Tendsto f x (𝓝 a) ↔ Tendsto (fun b => dist (f b) a) x (𝓝 0) := by @@ -1235,7 +1096,7 @@ variable {x y z : α} {ε ε₁ ε₂ : ℝ} {s : Set α} theorem ball_subset_interior_closedBall : ball x ε ⊆ interior (closedBall x ε) := interior_maximal ball_subset_closedBall isOpen_ball -/-- ε-characterization of the closure in pseudometric spaces-/ +/-- ε-characterization of the closure in pseudometric spaces -/ theorem mem_closure_iff {s : Set α} {a : α} : a ∈ closure s ↔ ∀ ε > 0, ∃ b ∈ s, dist a b < ε := (mem_closure_iff_nhds_basis nhds_basis_ball).trans <| by simp only [mem_ball, dist_comm] @@ -1259,22 +1120,6 @@ theorem dense_iff {s : Set α} : Dense s ↔ ∀ x, ∀ r > 0, (ball x r ∩ s). theorem denseRange_iff {f : β → α} : DenseRange f ↔ ∀ x, ∀ r > 0, ∃ y, dist x (f y) < r := forall_congr' fun x => by simp only [mem_closure_iff, exists_range_iff] --- 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 - 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 := 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 - /-- If a map is continuous on a separable set `s`, then the image of `s` is also separable. -/ theorem _root_.ContinuousOn.isSeparable_image [TopologicalSpace β] {f : α → β} {s : Set α} (hf : ContinuousOn f s) (hs : IsSeparable s) : IsSeparable (f '' s) := by @@ -1283,11 +1128,6 @@ theorem _root_.ContinuousOn.isSeparable_image [TopologicalSpace β] {f : α → end Metric -/-- A compact set is separable. -/ -theorem IsCompact.isSeparable {s : Set α} (hs : IsCompact s) : IsSeparable s := - haveI : CompactSpace s := isCompact_iff_compactSpace.mp hs - .of_subtype s - section Compact /-- Any compact set in a pseudometric space can be covered by finitely many balls of a given @@ -1302,27 +1142,6 @@ alias IsCompact.finite_cover_balls := finite_cover_balls_of_compact end Compact -namespace Metric - -section SecondCountable - -open TopologicalSpace - -/-- A pseudometric space is second countable if, for every `ε > 0`, there is a countable set which -is `ε`-dense. -/ -theorem secondCountable_of_almost_dense_set - (H : ∀ ε > (0 : ℝ), ∃ s : Set α, s.Countable ∧ ∀ x, ∃ y ∈ s, dist x y ≤ ε) : - SecondCountableTopology α := by - refine EMetric.secondCountable_of_almost_dense_set fun ε ε0 => ?_ - rcases ENNReal.lt_iff_exists_nnreal_btwn.1 ε0 with ⟨ε', ε'0, ε'ε⟩ - choose s hsc y hys hyx using H ε' (mod_cast ε'0) - refine ⟨s, hsc, iUnion₂_eq_univ_iff.2 fun x => ⟨y x, hys _, le_trans ?_ ε'ε.le⟩⟩ - exact mod_cast hyx x - -end SecondCountable - -end Metric - theorem lebesgue_number_lemma_of_metric {s : Set α} {ι : Sort*} {c : ι → Set α} (hs : IsCompact s) (hc₁ : ∀ i, IsOpen (c i)) (hc₂ : s ⊆ ⋃ i, c i) : ∃ δ > 0, ∀ x ∈ s, ∃ i, ball x δ ⊆ c i := by simpa only [ball, UniformSpace.ball, preimage_setOf_eq, dist_comm] @@ -1331,3 +1150,7 @@ theorem lebesgue_number_lemma_of_metric {s : Set α} {ι : Sort*} {c : ι → Se theorem lebesgue_number_lemma_of_metric_sUnion {s : Set α} {c : Set (Set α)} (hs : IsCompact s) (hc₁ : ∀ t ∈ c, IsOpen t) (hc₂ : s ⊆ ⋃₀ c) : ∃ δ > 0, ∀ x ∈ s, ∃ t ∈ c, ball x δ ⊆ t := by rw [sUnion_eq_iUnion] at hc₂; simpa using lebesgue_number_lemma_of_metric hs (by simpa) hc₂ + +instance : PseudoMetricSpace (Additive α) := ‹_› +instance : PseudoMetricSpace (Multiplicative α) := ‹_› +instance : PseudoMetricSpace αᵒᵈ := ‹_› diff --git a/Mathlib/Topology/MetricSpace/Pseudo/Lemmas.lean b/Mathlib/Topology/MetricSpace/Pseudo/Lemmas.lean index 04b7530b136fa..2a58189df2473 100644 --- a/Mathlib/Topology/MetricSpace/Pseudo/Lemmas.lean +++ b/Mathlib/Topology/MetricSpace/Pseudo/Lemmas.lean @@ -3,9 +3,8 @@ 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.Set.Pointwise.Interval -import Mathlib.Topology.MetricSpace.Pseudo.Constructions import Mathlib.Topology.Order.DenselyOrdered +import Mathlib.Topology.MetricSpace.Pseudo.Constructions /-! # Extra lemmas about pseudo-metric spaces @@ -16,24 +15,6 @@ open scoped NNReal Topology variable {ι α : Type*} [PseudoMetricSpace α] -lemma Real.dist_left_le_of_mem_uIcc {x y z : ℝ} (h : y ∈ uIcc x z) : dist x y ≤ dist x z := by - simpa only [dist_comm x] using abs_sub_left_of_mem_uIcc h - -lemma Real.dist_right_le_of_mem_uIcc {x y z : ℝ} (h : y ∈ uIcc x z) : dist y z ≤ dist x z := by - simpa only [dist_comm _ z] using abs_sub_right_of_mem_uIcc h - -lemma Real.dist_le_of_mem_uIcc {x y x' y' : ℝ} (hx : x ∈ uIcc x' y') (hy : y ∈ uIcc x' y') : - dist x y ≤ dist x' y' := - abs_sub_le_of_uIcc_subset_uIcc <| uIcc_subset_uIcc (by rwa [uIcc_comm]) (by rwa [uIcc_comm]) - -lemma Real.dist_le_of_mem_Icc {x y x' y' : ℝ} (hx : x ∈ Icc x' y') (hy : y ∈ Icc x' y') : - dist x y ≤ y' - x' := by - simpa only [Real.dist_eq, abs_of_nonpos (sub_nonpos.2 <| hx.1.trans hx.2), neg_sub] using - Real.dist_le_of_mem_uIcc (Icc_subset_uIcc hx) (Icc_subset_uIcc hy) - -lemma Real.dist_le_of_mem_Icc_01 {x y : ℝ} (hx : x ∈ Icc (0 : ℝ) 1) (hy : y ∈ Icc (0 : ℝ) 1) : - dist x y ≤ 1 := by simpa only [sub_zero] using Real.dist_le_of_mem_Icc hx hy - instance : OrderTopology ℝ := orderTopology_of_nhds_abs fun x => by simp only [nhds_basis_ball.eq_biInf, ball, Real.dist_eq, abs_sub_comm] @@ -51,7 +32,7 @@ lemma squeeze_zero' {α} {f g : α → ℝ} {t₀ : Filter α} (hf : ∀ᶠ t in and `tendsto_of_tendsto_of_tendsto_of_le_of_le'` for the general case. -/ lemma squeeze_zero {α} {f g : α → ℝ} {t₀ : Filter α} (hf : ∀ t, 0 ≤ f t) (hft : ∀ t, f t ≤ g t) (g0 : Tendsto g t₀ (𝓝 0)) : Tendsto f t₀ (𝓝 0) := - squeeze_zero' (eventually_of_forall hf) (eventually_of_forall hft) g0 + squeeze_zero' (Eventually.of_forall hf) (Eventually.of_forall hft) g0 /-- If `u` is a neighborhood of `x`, then for small enough `r`, the closed ball `Metric.closedBall x r` is contained in `u`. -/ @@ -109,13 +90,3 @@ lemma exists_isCompact_closedBall [WeaklyLocallyCompactSpace α] (x : α) : simpa only [and_comm] using (this.and self_mem_nhdsWithin).exists end Metric - -namespace Real -variable {π : ι → Type*} [Fintype ι] [∀ i, PseudoMetricSpace (π i)] {x y x' y' : ι → ℝ} - -lemma dist_le_of_mem_pi_Icc (hx : x ∈ Icc x' y') (hy : y ∈ Icc x' y') : dist x y ≤ dist x' y' := by - refine (dist_pi_le_iff dist_nonneg).2 fun b => - (Real.dist_le_of_mem_uIcc ?_ ?_).trans (dist_le_pi_dist x' y' b) <;> refine Icc_subset_uIcc ?_ - exacts [⟨hx.1 _, hx.2 _⟩, ⟨hy.1 _, hy.2 _⟩] - -end Real diff --git a/Mathlib/Topology/MetricSpace/Pseudo/Pi.lean b/Mathlib/Topology/MetricSpace/Pseudo/Pi.lean new file mode 100644 index 0000000000000..92a7c3925b2a1 --- /dev/null +++ b/Mathlib/Topology/MetricSpace/Pseudo/Pi.lean @@ -0,0 +1,160 @@ +/- +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.Bornology.Constructions +import Mathlib.Topology.EMetricSpace.Pi +import Mathlib.Topology.MetricSpace.Pseudo.Defs + +/-! +# Product of pseudometric spaces + +This file constructs the infinity distance on finite products of pseudometric spaces. +-/ + +open Bornology Filter Metric Set +open scoped NNReal Topology + +variable {α β : Type*} [PseudoMetricSpace α] + +open Finset + +variable {π : β → Type*} [Fintype β] [∀ b, PseudoMetricSpace (π b)] + +/-- A finite product of pseudometric spaces is a pseudometric space, with the sup distance. -/ +instance pseudoMetricSpacePi : PseudoMetricSpace (∀ b, π b) := by + /- we construct the instance from the pseudoemetric space instance to avoid checking again that + the uniformity is the same as the product uniformity, but we register nevertheless a nice + formula for the distance -/ + let i := PseudoEMetricSpace.toPseudoMetricSpaceOfDist + (fun f g : ∀ b, π b => ((sup univ fun b => nndist (f b) (g b) : ℝ≥0) : ℝ)) + (fun f g => ((Finset.sup_lt_iff bot_lt_top).2 fun b _ => edist_lt_top _ _).ne) + (fun f g => by + simp only [edist_pi_def, edist_nndist, ← ENNReal.coe_finset_sup, ENNReal.coe_toReal]) + refine i.replaceBornology fun s => ?_ + simp only [← isBounded_def, isBounded_iff_eventually, ← forall_isBounded_image_eval_iff, + forall_mem_image, ← Filter.eventually_all, Function.eval_apply, @dist_nndist (π _)] + refine eventually_congr ((eventually_ge_atTop 0).mono fun C hC ↦ ?_) + lift C to ℝ≥0 using hC + refine ⟨fun H x hx y hy ↦ NNReal.coe_le_coe.2 <| Finset.sup_le fun b _ ↦ H b hx hy, + fun H b x hx y hy ↦ NNReal.coe_le_coe.2 ?_⟩ + simpa only using Finset.sup_le_iff.1 (NNReal.coe_le_coe.1 <| H hx hy) b (Finset.mem_univ b) + +lemma nndist_pi_def (f g : ∀ b, π b) : nndist f g = sup univ fun b => nndist (f b) (g b) := rfl + +lemma dist_pi_def (f g : ∀ b, π b) : dist f g = (sup univ fun b => nndist (f b) (g b) : ℝ≥0) := rfl + +lemma nndist_pi_le_iff {f g : ∀ b, π b} {r : ℝ≥0} : + nndist f g ≤ r ↔ ∀ b, nndist (f b) (g b) ≤ r := by simp [nndist_pi_def] + +lemma nndist_pi_lt_iff {f g : ∀ b, π b} {r : ℝ≥0} (hr : 0 < r) : + nndist f g < r ↔ ∀ b, nndist (f b) (g b) < r := by + rw [← bot_eq_zero'] at hr + simp [nndist_pi_def, Finset.sup_lt_iff hr] + +lemma nndist_pi_eq_iff {f g : ∀ b, π b} {r : ℝ≥0} (hr : 0 < r) : + nndist f g = r ↔ (∃ i, nndist (f i) (g i) = r) ∧ ∀ b, nndist (f b) (g b) ≤ r := by + rw [eq_iff_le_not_lt, nndist_pi_lt_iff hr, nndist_pi_le_iff, not_forall, and_comm] + simp_rw [not_lt, and_congr_left_iff, le_antisymm_iff] + intro h + refine exists_congr fun b => ?_ + apply (and_iff_right <| h _).symm + +lemma dist_pi_lt_iff {f g : ∀ b, π b} {r : ℝ} (hr : 0 < r) : + dist f g < r ↔ ∀ b, dist (f b) (g b) < r := by + lift r to ℝ≥0 using hr.le + exact nndist_pi_lt_iff hr + +lemma dist_pi_le_iff {f g : ∀ b, π b} {r : ℝ} (hr : 0 ≤ r) : + dist f g ≤ r ↔ ∀ b, dist (f b) (g b) ≤ r := by + lift r to ℝ≥0 using hr + exact nndist_pi_le_iff + +lemma dist_pi_eq_iff {f g : ∀ b, π b} {r : ℝ} (hr : 0 < r) : + dist f g = r ↔ (∃ i, dist (f i) (g i) = r) ∧ ∀ b, dist (f b) (g b) ≤ r := by + lift r to ℝ≥0 using hr.le + simp_rw [← coe_nndist, NNReal.coe_inj, nndist_pi_eq_iff hr, NNReal.coe_le_coe] + +lemma dist_pi_le_iff' [Nonempty β] {f g : ∀ b, π b} {r : ℝ} : + dist f g ≤ r ↔ ∀ b, dist (f b) (g b) ≤ r := by + by_cases hr : 0 ≤ r + · exact dist_pi_le_iff hr + · exact iff_of_false (fun h => hr <| dist_nonneg.trans h) fun h => + hr <| dist_nonneg.trans <| h <| Classical.arbitrary _ + +lemma dist_pi_const_le (a b : α) : (dist (fun _ : β => a) fun _ => b) ≤ dist a b := + (dist_pi_le_iff dist_nonneg).2 fun _ => le_rfl + +lemma nndist_pi_const_le (a b : α) : (nndist (fun _ : β => a) fun _ => b) ≤ nndist a b := + nndist_pi_le_iff.2 fun _ => le_rfl + +@[simp] +lemma dist_pi_const [Nonempty β] (a b : α) : (dist (fun _ : β => a) fun _ => b) = dist a b := by + simpa only [dist_edist] using congr_arg ENNReal.toReal (edist_pi_const a b) + +@[simp] +lemma nndist_pi_const [Nonempty β] (a b : α) : (nndist (fun _ : β => a) fun _ => b) = nndist a b := + NNReal.eq <| dist_pi_const a b + +lemma nndist_le_pi_nndist (f g : ∀ b, π b) (b : β) : nndist (f b) (g b) ≤ nndist f g := by + rw [← ENNReal.coe_le_coe, ← edist_nndist, ← edist_nndist] + exact edist_le_pi_edist f g b + +lemma dist_le_pi_dist (f g : ∀ b, π b) (b : β) : dist (f b) (g b) ≤ dist f g := by + simp only [dist_nndist, NNReal.coe_le_coe, nndist_le_pi_nndist f g b] + +/-- An open ball in a product space is a product of open balls. See also `ball_pi'` +for a version assuming `Nonempty β` instead of `0 < r`. -/ +lemma ball_pi (x : ∀ b, π b) {r : ℝ} (hr : 0 < r) : + ball x r = Set.pi univ fun b => ball (x b) r := by + ext p + simp [dist_pi_lt_iff hr] + +/-- An open ball in a product space is a product of open balls. See also `ball_pi` +for a version assuming `0 < r` instead of `Nonempty β`. -/ +lemma ball_pi' [Nonempty β] (x : ∀ b, π b) (r : ℝ) : + ball x r = Set.pi univ fun b => ball (x b) r := + (lt_or_le 0 r).elim (ball_pi x) fun hr => by simp [ball_eq_empty.2 hr] + +/-- A closed ball in a product space is a product of closed balls. See also `closedBall_pi'` +for a version assuming `Nonempty β` instead of `0 ≤ r`. -/ +lemma closedBall_pi (x : ∀ b, π b) {r : ℝ} (hr : 0 ≤ r) : + closedBall x r = Set.pi univ fun b => closedBall (x b) r := by + ext p + simp [dist_pi_le_iff hr] + +/-- A closed ball in a product space is a product of closed balls. See also `closedBall_pi` +for a version assuming `0 ≤ r` instead of `Nonempty β`. -/ +lemma closedBall_pi' [Nonempty β] (x : ∀ b, π b) (r : ℝ) : + closedBall x r = Set.pi univ fun b => closedBall (x b) r := + (le_or_lt 0 r).elim (closedBall_pi x) fun hr => by simp [closedBall_eq_empty.2 hr] + +/-- A sphere in a product space is a union of spheres on each component restricted to the closed +ball. -/ +lemma sphere_pi (x : ∀ b, π b) {r : ℝ} (h : 0 < r ∨ Nonempty β) : + sphere x r = (⋃ i : β, Function.eval i ⁻¹' sphere (x i) r) ∩ closedBall x r := by + obtain hr | rfl | hr := lt_trichotomy r 0 + · simp [hr] + · rw [closedBall_eq_sphere_of_nonpos le_rfl, eq_comm, Set.inter_eq_right] + letI := h.resolve_left (lt_irrefl _) + inhabit β + refine subset_iUnion_of_subset default ?_ + intro x hx + replace hx := hx.le + rw [dist_pi_le_iff le_rfl] at hx + exact le_antisymm (hx default) dist_nonneg + · ext + simp [dist_pi_eq_iff hr, dist_pi_le_iff hr.le] + +@[simp] +lemma Fin.nndist_insertNth_insertNth {n : ℕ} {α : Fin (n + 1) → Type*} + [∀ i, PseudoMetricSpace (α i)] (i : Fin (n + 1)) (x y : α i) (f g : ∀ j, α (i.succAbove j)) : + nndist (i.insertNth x f) (i.insertNth y g) = max (nndist x y) (nndist f g) := + eq_of_forall_ge_iff fun c => by simp [nndist_pi_le_iff, i.forall_iff_succAbove] + +@[simp] +lemma Fin.dist_insertNth_insertNth {n : ℕ} {α : Fin (n + 1) → Type*} + [∀ i, PseudoMetricSpace (α i)] (i : Fin (n + 1)) (x y : α i) (f g : ∀ j, α (i.succAbove j)) : + dist (i.insertNth x f) (i.insertNth y g) = max (dist x y) (dist f g) := by + simp only [dist_nndist, Fin.nndist_insertNth_insertNth, NNReal.coe_max] diff --git a/Mathlib/Topology/MetricSpace/Pseudo/Real.lean b/Mathlib/Topology/MetricSpace/Pseudo/Real.lean new file mode 100644 index 0000000000000..ae477178577c5 --- /dev/null +++ b/Mathlib/Topology/MetricSpace/Pseudo/Real.lean @@ -0,0 +1,45 @@ +/- +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.Set.Pointwise.Interval +import Mathlib.Topology.MetricSpace.Pseudo.Pi + +/-! +# Lemmas about distances between points in intervals in `ℝ`. +-/ + +open Bornology Filter Metric Set +open scoped NNReal Topology + +namespace Real + +variable {ι α : Type*} [PseudoMetricSpace α] + +lemma dist_left_le_of_mem_uIcc {x y z : ℝ} (h : y ∈ uIcc x z) : dist x y ≤ dist x z := by + simpa only [dist_comm x] using abs_sub_left_of_mem_uIcc h + +lemma dist_right_le_of_mem_uIcc {x y z : ℝ} (h : y ∈ uIcc x z) : dist y z ≤ dist x z := by + simpa only [dist_comm _ z] using abs_sub_right_of_mem_uIcc h + +lemma dist_le_of_mem_uIcc {x y x' y' : ℝ} (hx : x ∈ uIcc x' y') (hy : y ∈ uIcc x' y') : + dist x y ≤ dist x' y' := + abs_sub_le_of_uIcc_subset_uIcc <| uIcc_subset_uIcc (by rwa [uIcc_comm]) (by rwa [uIcc_comm]) + +lemma dist_le_of_mem_Icc {x y x' y' : ℝ} (hx : x ∈ Icc x' y') (hy : y ∈ Icc x' y') : + dist x y ≤ y' - x' := by + simpa only [Real.dist_eq, abs_of_nonpos (sub_nonpos.2 <| hx.1.trans hx.2), neg_sub] using + Real.dist_le_of_mem_uIcc (Icc_subset_uIcc hx) (Icc_subset_uIcc hy) + +lemma dist_le_of_mem_Icc_01 {x y : ℝ} (hx : x ∈ Icc (0 : ℝ) 1) (hy : y ∈ Icc (0 : ℝ) 1) : + dist x y ≤ 1 := by simpa only [sub_zero] using Real.dist_le_of_mem_Icc hx hy + +variable {π : ι → Type*} [Fintype ι] [∀ i, PseudoMetricSpace (π i)] {x y x' y' : ι → ℝ} + +lemma dist_le_of_mem_pi_Icc (hx : x ∈ Icc x' y') (hy : y ∈ Icc x' y') : dist x y ≤ dist x' y' := by + refine (dist_pi_le_iff dist_nonneg).2 fun b => + (Real.dist_le_of_mem_uIcc ?_ ?_).trans (dist_le_pi_dist x' y' b) <;> refine Icc_subset_uIcc ?_ + exacts [⟨hx.1 _, hx.2 _⟩, ⟨hy.1 _, hy.2 _⟩] + +end Real diff --git a/Mathlib/Topology/MetricSpace/Sequences.lean b/Mathlib/Topology/MetricSpace/Sequences.lean index 2f1d5f1bb5afb..ed02f21cdebd7 100644 --- a/Mathlib/Topology/MetricSpace/Sequences.lean +++ b/Mathlib/Topology/MetricSpace/Sequences.lean @@ -7,7 +7,7 @@ import Mathlib.Topology.Sequences import Mathlib.Topology.MetricSpace.Bounded /-! -# Sequencial compacts in metric spaces +# Sequential compacts in metric spaces In this file we prove 2 versions of Bolzano-Weierstrass theorem for proper metric spaces. -/ @@ -39,4 +39,4 @@ theorem tendsto_subseq_of_frequently_bounded (hs : IsBounded s) {x : ℕ → X} every bounded sequence has a converging subsequence. -/ theorem tendsto_subseq_of_bounded (hs : IsBounded s) {x : ℕ → X} (hx : ∀ n, x n ∈ s) : ∃ a ∈ closure s, ∃ φ : ℕ → ℕ, StrictMono φ ∧ Tendsto (x ∘ φ) atTop (𝓝 a) := - tendsto_subseq_of_frequently_bounded hs <| frequently_of_forall hx + tendsto_subseq_of_frequently_bounded hs <| Frequently.of_forall hx 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..50b3c349f536c 100644 --- a/Mathlib/Topology/MetricSpace/ThickenedIndicator.lean +++ b/Mathlib/Topology/MetricSpace/ThickenedIndicator.lean @@ -4,7 +4,7 @@ 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.Topology.ContinuousMap.Bounded import Mathlib.Topology.MetricSpace.Thickening /-! @@ -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/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/Uniformity.lean b/Mathlib/Topology/Metrizable/Uniformity.lean index 84aa5a4ff45ae..3dc4176d75c21 100644 --- a/Mathlib/Topology/Metrizable/Uniformity.lean +++ b/Mathlib/Topology/Metrizable/Uniformity.lean @@ -154,12 +154,12 @@ theorem le_two_mul_dist_ofPreNNDist (d : X → X → ℝ≥0) (dist_self : ∀ x have hMl' : length (take M l) = M := (length_take _ _).trans (min_eq_left hMl.le) refine (ihn _ hMl _ _ _ hMl').trans ?_ convert hMs.1.out - rw [take_zipWith, take, take_succ, getElem?_append hMl, getElem?_eq_getElem hMl, + rw [take_zipWith, take, take_succ, getElem?_append_left hMl, getElem?_eq_getElem hMl, ← 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 ?_ @@ -206,7 +206,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] @@ -225,7 +225,7 @@ protected theorem UniformSpace.metrizable_uniformity (X : Type*) [UniformSpace X refine PseudoMetricSpace.le_two_mul_dist_ofPreNNDist _ _ _ fun x₁ x₂ x₃ x₄ => ?_ by_cases H : ∃ n, (x₁, x₄) ∉ U n · refine (dif_pos H).trans_le ?_ - rw [← NNReal.div_le_iff' two_ne_zero, ← mul_one_div (_ ^ _), ← pow_succ] + rw [← div_le_iff₀' zero_lt_two, ← mul_one_div (_ ^ _), ← pow_succ] simp only [le_max_iff, hle_d, ← not_and_or] rintro ⟨h₁₂, h₂₃, h₃₄⟩ refine Nat.find_spec H (hU_comp (lt_add_one <| Nat.find H) ?_) @@ -240,9 +240,9 @@ protected theorem UniformSpace.metrizable_uniformity (X : Type*) [UniformSpace X · refine fun n _ => ⟨n + 1, trivial, fun x hx => ?_⟩ rw [mem_setOf_eq] at hx contrapose! hx - refine le_trans ?_ ((div_le_iff' (zero_lt_two' ℝ)).2 (hd_le x.1 x.2)) + refine le_trans ?_ ((div_le_iff₀' zero_lt_two).2 (hd_le x.1 x.2)) rwa [← NNReal.coe_two, ← NNReal.coe_div, ← NNReal.coe_pow, NNReal.coe_le_coe, pow_succ, - mul_one_div, NNReal.div_le_iff two_ne_zero, div_mul_cancel₀ _ (two_ne_zero' ℝ≥0), hle_d] + mul_one_div, div_le_iff₀ zero_lt_two, div_mul_cancel₀ _ two_ne_zero, hle_d] /-- A `PseudoMetricSpace` instance compatible with a given `UniformSpace` structure. -/ protected noncomputable def UniformSpace.pseudoMetricSpace (X : Type*) [UniformSpace X] @@ -282,3 +282,10 @@ lemma TotallyBounded.isSeparable [UniformSpace X] [i : IsCountablyGenerated ( exact EMetric.ball_subset_closedBall obtain ⟨t, _, htc, hts⟩ := EMetric.subset_countable_closure_of_almost_dense_set s h' exact ⟨t, htc, hts⟩ + +open TopologicalSpace in +instance (priority := 100) DiscreteTopology.metrizableSpace + {α} [TopologicalSpace α] [DiscreteTopology α] : + MetrizableSpace α := by + obtain rfl := DiscreteTopology.eq_bot (α := α) + exact @UniformSpace.metrizableSpace α ⊥ (isCountablyGenerated_principal _) _ diff --git a/Mathlib/Topology/Metrizable/Urysohn.lean b/Mathlib/Topology/Metrizable/Urysohn.lean index f136cbf094264..bddb6a6ead668 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 diff --git a/Mathlib/Topology/NhdsSet.lean b/Mathlib/Topology/NhdsSet.lean index 5580d18fa47ef..3a3f45b2eeff7 100644 --- a/Mathlib/Topology/NhdsSet.lean +++ b/Mathlib/Topology/NhdsSet.lean @@ -144,7 +144,7 @@ theorem nhdsSet_insert (x : X) (s : Set X) : 𝓝ˢ (insert x s) = 𝓝 x ⊔ rw [insert_eq, nhdsSet_union, nhdsSet_singleton] /-- Preimage of a set neighborhood of `t` under a continuous map `f` is a set neighborhood of `s` -provided that `f` maps `s` to `t`. -/ +provided that `f` maps `s` to `t`. -/ theorem Continuous.tendsto_nhdsSet {f : X → Y} {t : Set Y} (hf : Continuous f) (hst : MapsTo f s t) : Tendsto f (𝓝ˢ s) (𝓝ˢ t) := ((hasBasis_nhdsSet s).tendsto_iff (hasBasis_nhdsSet t)).mpr fun U hU => diff --git a/Mathlib/Topology/NoetherianSpace.lean b/Mathlib/Topology/NoetherianSpace.lean index 74d4532b5976c..9c2e714b18849 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 @@ -78,18 +76,15 @@ 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 +92,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, @@ -156,7 +155,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 7f45468c25312..89f1e3ee2fa58 100644 --- a/Mathlib/Topology/OmegaCompletePartialOrder.lean +++ b/Mathlib/Topology/OmegaCompletePartialOrder.lean @@ -39,21 +39,19 @@ variable (α : Type u) [OmegaCompletePartialOrder α] /-- The characteristic function of open sets is monotone and preserves the limits of chains. -/ def IsOpen (s : Set α) : Prop := - Continuous' fun x ↦ x ∈ s + ωScottContinuous fun x ↦ x ∈ s -theorem isOpen_univ : IsOpen α univ := - ⟨fun _ _ _ _ ↦ mem_univ _, @CompleteLattice.top_continuous α Prop _ _⟩ +theorem isOpen_univ : IsOpen α univ := @CompleteLattice.ωScottContinuous.top α Prop _ _ theorem IsOpen.inter (s t : Set α) : IsOpen α s → IsOpen α t → IsOpen α (s ∩ t) := - CompleteLattice.inf_continuous' + CompleteLattice.ωScottContinuous.inf theorem isOpen_sUnion (s : Set (Set α)) (hs : ∀ t ∈ s, IsOpen α t) : IsOpen α (⋃₀ s) := by simp only [IsOpen] at hs ⊢ - convert CompleteLattice.sSup_continuous' (setOf ⁻¹' s) hs - simp only [sSup_apply, setOf_bijective.surjective.exists, exists_prop, mem_preimage, - SetCoe.exists, iSup_Prop_eq, mem_setOf_eq, mem_sUnion] + convert CompleteLattice.ωScottContinuous.sSup hs + aesop -theorem IsOpen.isUpperSet {s : Set α} (hs : IsOpen α s) : IsUpperSet s := hs.fst +theorem IsOpen.isUpperSet {s : Set α} (hs : IsOpen α s) : IsUpperSet s := hs.monotone end Scott @@ -80,6 +78,8 @@ def notBelow := theorem notBelow_isOpen : IsOpen (notBelow y) := by have h : Monotone (notBelow y) := fun x z hle ↦ mt hle.trans + 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, Function.comp_apply, exists_imp, not_forall] @@ -96,13 +96,15 @@ theorem isωSup_ωSup {α} [OmegaCompletePartialOrder α] (c : Chain α) : IsωS · apply ωSup_le theorem scottContinuous_of_continuous {α β} [OmegaCompletePartialOrder α] - [OmegaCompletePartialOrder β] (f : Scott α → Scott β) (hf : Continuous f) : - OmegaCompletePartialOrder.Continuous' f := by + [OmegaCompletePartialOrder β] (f : Scott α → Scott β) (hf : _root_.Continuous f) : + OmegaCompletePartialOrder.ωScottContinuous f := by + rw [ωScottContinuous_iff_monotone_map_ωSup] have h : Monotone f := fun x y h ↦ by have hf : IsUpperSet {x | ¬f x ≤ f y} := ((notBelow_isOpen (f y)).preimage hf).isUpperSet simpa only [mem_setOf_eq, le_refl, not_true, imp_false, not_not] using hf h refine ⟨h, fun c ↦ eq_of_forall_ge_iff fun z ↦ ?_⟩ - rcases (notBelow_isOpen z).preimage hf with ⟨hf, hf'⟩ + rcases (notBelow_isOpen z).preimage hf with hf'' + let hf' := hf''.monotone_map_ωSup.2 specialize hf' c simp only [OrderHom.coe_mk, mem_preimage, notBelow, mem_setOf_eq] at hf' rw [← not_iff_not] @@ -112,11 +114,9 @@ theorem scottContinuous_of_continuous {α β} [OmegaCompletePartialOrder α] theorem continuous_of_scottContinuous {α β} [OmegaCompletePartialOrder α] [OmegaCompletePartialOrder β] (f : Scott α → Scott β) - (hf : OmegaCompletePartialOrder.Continuous' f) : Continuous f := by + (hf : ωScottContinuous f) : Continuous f := by rw [continuous_def] intro s hs - change Continuous' (s ∘ f) - cases' hs with hs hs' - cases' hf with hf hf' - apply Continuous.of_bundled - apply continuous_comp _ _ hf' hs' + 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 83b1b248e808d..c1c9b629e8592 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 @@ -520,6 +517,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 +618,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 @@ -740,6 +740,15 @@ theorem map_nhds_induced_of_surjective [T : TopologicalSpace α] {f : β → α} (a : β) : map f (@nhds β (TopologicalSpace.induced f T) a) = 𝓝 (f a) := by rw [nhds_induced, map_comap_of_surjective hf] +theorem continuous_nhdsAdjoint_dom [TopologicalSpace β] {f : α → β} {a : α} {l : Filter α} : + Continuous[nhdsAdjoint a l, _] f ↔ Tendsto f l (𝓝 (f a)) := by + simp_rw [continuous_iff_le_induced, gc_nhds _ _, nhds_induced, tendsto_iff_comap] + +theorem coinduced_nhdsAdjoint (f : α → β) (a : α) (l : Filter α) : + coinduced f (nhdsAdjoint a l) = nhdsAdjoint (f a) (map f l) := + eq_of_forall_ge_iff fun _ ↦ by + rw [gc_nhds, ← continuous_iff_coinduced_le, continuous_nhdsAdjoint_dom, Tendsto] + end Constructions section Induced @@ -864,8 +873,16 @@ theorem isOpen_iSup_iff {s : Set α} : IsOpen[⨆ i, t i] s ↔ ∀ i, IsOpen[t show s ∈ {s | IsOpen[iSup t] s} ↔ s ∈ { x : Set α | ∀ i : ι, IsOpen[t i] x } by simp [setOf_isOpen_iSup] +theorem isOpen_sSup_iff {s : Set α} {T : Set (TopologicalSpace α)} : + IsOpen[sSup T] s ↔ ∀ t ∈ T, IsOpen[t] s := by + simp only [sSup_eq_iSup, isOpen_iSup_iff] + set_option tactic.skipAssignedInstances false in theorem isClosed_iSup_iff {s : Set α} : IsClosed[⨆ i, t i] s ↔ ∀ i, IsClosed[t i] s := by simp [← @isOpen_compl_iff _ _ (⨆ i, t i), ← @isOpen_compl_iff _ _ (t _), isOpen_iSup_iff] +theorem isClosed_sSup_iff {s : Set α} {T : Set (TopologicalSpace α)} : + IsClosed[sSup T] s ↔ ∀ t ∈ T, IsClosed[t] s := by + simp only [sSup_eq_iSup, isClosed_iSup_iff] + end iInf diff --git a/Mathlib/Topology/Order/Basic.lean b/Mathlib/Topology/Order/Basic.lean index e7570fcfdd2cf..3e2cc3f13ebe9 100644 --- a/Mathlib/Topology/Order/Basic.lean +++ b/Mathlib/Topology/Order/Basic.lean @@ -144,8 +144,8 @@ hold everywhere. -/ theorem tendsto_of_tendsto_of_tendsto_of_le_of_le [OrderTopology α] {f g h : β → α} {b : Filter β} {a : α} (hg : Tendsto g b (𝓝 a)) (hh : Tendsto h b (𝓝 a)) (hgf : g ≤ f) (hfh : f ≤ h) : Tendsto f b (𝓝 a) := - tendsto_of_tendsto_of_tendsto_of_le_of_le' hg hh (eventually_of_forall hgf) - (eventually_of_forall hfh) + tendsto_of_tendsto_of_tendsto_of_le_of_le' hg hh (Eventually.of_forall hgf) + (Eventually.of_forall hfh) theorem nhds_order_unbounded [OrderTopology α] {a : α} (hu : ∃ u, a < u) (hl : ∃ l, l < a) : 𝓝 a = ⨅ (l) (_ : l < a) (u) (_ : a < u), 𝓟 (Ioo l u) := by @@ -320,11 +320,11 @@ theorem tendsto_nhds_bot_mono [TopologicalSpace β] [Preorder β] [OrderBot β] theorem tendsto_nhds_top_mono' [TopologicalSpace β] [Preorder β] [OrderTop β] [OrderTopology β] {l : Filter α} {f g : α → β} (hf : Tendsto f l (𝓝 ⊤)) (hg : f ≤ g) : Tendsto g l (𝓝 ⊤) := - tendsto_nhds_top_mono hf (eventually_of_forall hg) + tendsto_nhds_top_mono hf (Eventually.of_forall hg) theorem tendsto_nhds_bot_mono' [TopologicalSpace β] [Preorder β] [OrderBot β] [OrderTopology β] {l : Filter α} {f g : α → β} (hf : Tendsto f l (𝓝 ⊥)) (hg : g ≤ f) : Tendsto g l (𝓝 ⊥) := - tendsto_nhds_bot_mono hf (eventually_of_forall hg) + tendsto_nhds_bot_mono hf (Eventually.of_forall hg) section LinearOrder diff --git a/Mathlib/Topology/Order/Bornology.lean b/Mathlib/Topology/Order/Bornology.lean index 0c7dfd80bd711..e2307a276340e 100644 --- a/Mathlib/Topology/Order/Bornology.lean +++ b/Mathlib/Topology/Order/Bornology.lean @@ -71,10 +71,10 @@ protected lemma BddAbove.isBounded (hs₀ : BddAbove s) (hs₁ : BddBelow s) : I isBounded_iff_bddBelow_bddAbove.2 ⟨hs₁, hs₀⟩ lemma BddBelow.isBounded_inter (hs : BddBelow s) (ht : BddAbove t) : IsBounded (s ∩ t) := - (hs.mono inter_subset_left).isBounded $ ht.mono inter_subset_right + (hs.mono inter_subset_left).isBounded <| ht.mono inter_subset_right lemma BddAbove.isBounded_inter (hs : BddAbove s) (ht : BddBelow t) : IsBounded (s ∩ t) := - (hs.mono inter_subset_left).isBounded $ ht.mono inter_subset_right + (hs.mono inter_subset_left).isBounded <| ht.mono inter_subset_right instance OrderDual.instIsOrderBornology : IsOrderBornology αᵒᵈ where isBounded_iff_bddBelow_bddAbove s := by diff --git a/Mathlib/Topology/Order/Category/FrameAdjunction.lean b/Mathlib/Topology/Order/Category/FrameAdjunction.lean index 66dd40b808326..e44b0f9de9062 100644 --- a/Mathlib/Topology/Order/Category/FrameAdjunction.lean +++ b/Mathlib/Topology/Order/Category/FrameAdjunction.lean @@ -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/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 00431baf1a323..9b86197c50a9e 100644 --- a/Mathlib/Topology/Order/IntermediateValue.lean +++ b/Mathlib/Topology/Order/IntermediateValue.lean @@ -443,7 +443,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] @@ -641,7 +641,7 @@ theorem Continuous.strictMonoOn_of_inj_rigidity {f : α → δ} let t := max b y have hsa : s ≤ a := min_le_left a x have hbt : b ≤ t := le_max_left b y - have hst : s ≤ t := hsa.trans $ hbt.trans' hab.le + have hst : s ≤ t := hsa.trans <| hbt.trans' hab.le have hf_mono_st : StrictMonoOn f (Icc s t) ∨ StrictAntiOn f (Icc s t) := by letI := Icc.completeLinearOrder hst have := Continuous.strictMono_of_inj_boundedOrder' (f := Set.restrict (Icc s t) f) diff --git a/Mathlib/Topology/Order/IsLUB.lean b/Mathlib/Topology/Order/IsLUB.lean index 85085029dc118..2d6f0f82dc720 100644 --- a/Mathlib/Topology/Order/IsLUB.lean +++ b/Mathlib/Topology/Order/IsLUB.lean @@ -53,8 +53,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 +71,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 +116,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..945cc85292c34 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 @@ -94,8 +94,7 @@ 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 @@ -144,7 +143,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.toHomeomorphOfInducing ⟨by erw [IsLawson.topology_eq_lawson (α := α), induced_id]; rfl⟩ theorem isOpen_preimage_ofLawson {S : Set α} : IsOpen (ofLawson ⁻¹' S) ↔ (lawson α).IsOpen S := Iff.rfl diff --git a/Mathlib/Topology/Order/LeftRightNhds.lean b/Mathlib/Topology/Order/LeftRightNhds.lean index 626dbfd4cd1b9..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.Algebra.Ring.Pointwise.Set +import Mathlib.Order.Filter.AtTopBot.Group import Mathlib.Topology.Order.Basic -import Mathlib.Data.Set.Pointwise.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/LowerUpperTopology.lean b/Mathlib/Topology/Order/LowerUpperTopology.lean index 0f131e2cfc173..95dc12c92c61f 100644 --- a/Mathlib/Topology/Order/LowerUpperTopology.lean +++ b/Mathlib/Topology/Order/LowerUpperTopology.lean @@ -68,14 +68,14 @@ def upper (α : Type*) [Preorder α] : TopologicalSpace α := generateFrom {s | /-- Type synonym for a preorder equipped with the lower set topology. -/ def WithLower (α : Type*) := α -variable {α β} +variable {α β : Type*} namespace WithLower -/-- `toLower` is the identity function to the `WithLower` of a type. -/ +/-- `toLower` is the identity function to the `WithLower` of a type. -/ @[match_pattern] def toLower : α ≃ WithLower α := Equiv.refl _ -/-- `ofLower` is the identity function from the `WithLower` of a type. -/ +/-- `ofLower` is the identity function from the `WithLower` of a type. -/ @[match_pattern] def ofLower : WithLower α ≃ α := Equiv.refl _ @[simp] lemma to_WithLower_symm_eq : (@toLower α).symm = ofLower := rfl @@ -116,10 +116,10 @@ end WithLower def WithUpper (α : Type*) := α namespace WithUpper -/-- `toUpper` is the identity function to the `WithUpper` of a type. -/ +/-- `toUpper` is the identity function to the `WithUpper` of a type. -/ @[match_pattern] def toUpper : α ≃ WithUpper α := Equiv.refl _ -/-- `ofUpper` is the identity function from the `WithUpper` of a type. -/ +/-- `ofUpper` is the identity function from the `WithUpper` of a type. -/ @[match_pattern] def ofUpper : WithUpper α ≃ α := Equiv.refl _ @[simp] lemma to_WithUpper_symm_eq {α} : (@toUpper α).symm = ofUpper := 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 @@ -281,6 +277,61 @@ instance (priority := 90) t0Space : T0Space α := end PartialOrder +section LinearOrder + +variable [LinearOrder α] [TopologicalSpace α] [IsLower α] + +lemma isTopologicalBasis_insert_univ_subbasis : + IsTopologicalBasis (insert univ {s : Set α | ∃ a, (Ici a)ᶜ = s}) := + isTopologicalBasis_of_subbasis_of_inter (by rw [topology_eq α, lower]) (by + rintro _ ⟨b, rfl⟩ _ ⟨c, rfl⟩ + use b ⊓ c + rw [compl_Ici, compl_Ici, compl_Ici, Iio_inter_Iio]) + +end LinearOrder + +section CompleteLinearOrder + +variable [CompleteLinearOrder α] [t : TopologicalSpace α] [IsLower α] + +lemma isTopologicalSpace_basis (U : Set α) : IsOpen U ↔ U = univ ∨ ∃ a, (Ici a)ᶜ = U := by + by_cases hU : U = univ + · simp only [hU, isOpen_univ, compl_Ici, true_or] + refine ⟨?_, isTopologicalBasis_insert_univ_subbasis.isOpen⟩ + intro hO + apply Or.inr + convert IsTopologicalBasis.open_eq_sUnion isTopologicalBasis_insert_univ_subbasis hO + constructor + · intro ⟨a, ha⟩ + use {U} + constructor + · apply subset_trans (singleton_subset_iff.mpr _) (subset_insert _ _) + use a + · rw [sUnion_singleton] + · intro ⟨S, hS1, hS2⟩ + have hUS : univ ∉ S := by + by_contra hUS' + apply hU + rw [hS2] + exact sUnion_eq_univ_iff.mpr (fun a => ⟨univ, hUS', trivial⟩) + use sSup {a | (Ici a)ᶜ ∈ S} + rw [hS2, sUnion_eq_compl_sInter_compl, compl_inj_iff] + apply le_antisymm + · intro b hb + simp only [sInter_image, mem_iInter, mem_compl_iff] + intro s hs + obtain ⟨a,ha⟩ := (subset_insert_iff_of_not_mem hUS).mp hS1 hs + subst hS2 ha + simp_all only [compl_Ici, mem_Ici, sSup_le_iff, mem_setOf_eq, mem_Iio, not_lt] + · intro b hb + rw [mem_Ici, sSup_le_iff] + intro c hc + simp only [sInter_image, mem_iInter] at hb + rw [← not_lt, ← mem_Iio, ← compl_Ici] + exact hb _ hc + +end CompleteLinearOrder + end IsLower @@ -344,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 @@ -365,6 +409,25 @@ instance (priority := 90) t0Space : T0Space α := end PartialOrder +section LinearOrder + +variable [LinearOrder α] [TopologicalSpace α] [IsUpper α] + +lemma isTopologicalBasis_insert_univ_subbasis : + IsTopologicalBasis (insert univ {s : Set α | ∃ a, (Iic a)ᶜ = s}) := + IsLower.isTopologicalBasis_insert_univ_subbasis (α := αᵒᵈ) + +end LinearOrder + +section CompleteLinearOrder + +variable [CompleteLinearOrder α] [t : TopologicalSpace α] [IsUpper α] + +lemma isTopologicalSpace_basis (U : Set α) : IsOpen U ↔ U = univ ∨ ∃ a, (Iic a)ᶜ = U := + IsLower.isTopologicalSpace_basis (α := αᵒᵈ) U + +end CompleteLinearOrder + end IsUpper instance instIsLowerProd [Preorder α] [TopologicalSpace α] [IsLower α] @@ -435,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 367caf03ec925..c807d80f962d5 100644 --- a/Mathlib/Topology/Order/Monotone.lean +++ b/Mathlib/Topology/Order/Monotone.lean @@ -28,65 +28,122 @@ variable [ConditionallyCompleteLinearOrder α] [TopologicalSpace α] [OrderTopol /-- A monotone function continuous at the supremum of a nonempty set sends this supremum to the supremum of the image of this set. -/ -theorem Monotone.map_sSup_of_continuousAt' {f : α → β} {A : Set α} (Cf : ContinuousAt f (sSup A)) - (Mf : Monotone f) (A_nonemp : A.Nonempty) (A_bdd : BddAbove A := by bddDefault) : +theorem MonotoneOn.map_csSup_of_continuousWithinAt {f : α → β} {A : Set α} + (Cf : ContinuousWithinAt f A (sSup A)) + (Mf : MonotoneOn f A) (A_nonemp : A.Nonempty) (A_bdd : BddAbove A := by bddDefault) : f (sSup A) = sSup (f '' A) := --This is a particular case of the more general `IsLUB.isLUB_of_tendsto` - .symm <| ((isLUB_csSup A_nonemp A_bdd).isLUB_of_tendsto (Mf.monotoneOn _) A_nonemp <| - Cf.mono_left inf_le_left).csSup_eq (A_nonemp.image f) + .symm <| ((isLUB_csSup A_nonemp A_bdd).isLUB_of_tendsto Mf A_nonemp <| + Cf.mono_left fun ⦃_⦄ a ↦ a).csSup_eq (A_nonemp.image f) + +/-- A monotone function continuous at the supremum of a nonempty set sends this supremum to +the supremum of the image of this set. -/ +theorem Monotone.map_csSup_of_continuousAt {f : α → β} {A : Set α} + (Cf : ContinuousAt f (sSup A)) (Mf : Monotone f) (A_nonemp : A.Nonempty) + (A_bdd : BddAbove A := by bddDefault) : f (sSup A) = sSup (f '' A) := + MonotoneOn.map_csSup_of_continuousWithinAt Cf.continuousWithinAt + (Mf.monotoneOn _) A_nonemp A_bdd + +@[deprecated (since := "2024-08-26")] alias Monotone.map_sSup_of_continuousAt' := + Monotone.map_csSup_of_continuousAt /-- A monotone function continuous at the indexed supremum over a nonempty `Sort` sends this indexed supremum to the indexed supremum of the composition. -/ -theorem Monotone.map_iSup_of_continuousAt' {ι : Sort*} [Nonempty ι] {f : α → β} {g : ι → α} +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_sSup_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 + +/-- A monotone function continuous at the infimum of a nonempty set sends this infimum to +the infimum of the image of this set. -/ +theorem MonotoneOn.map_csInf_of_continuousWithinAt {f : α → β} {A : Set α} + (Cf : ContinuousWithinAt f A (sInf A)) + (Mf : MonotoneOn f A) (A_nonemp : A.Nonempty) (A_bdd : BddBelow A := by bddDefault) : + f (sInf A) = sInf (f '' A) := + MonotoneOn.map_csSup_of_continuousWithinAt (α := αᵒᵈ) (β := βᵒᵈ) Cf Mf.dual A_nonemp A_bdd /-- A monotone function continuous at the infimum of a nonempty set sends this infimum to the infimum of the image of this set. -/ -theorem Monotone.map_sInf_of_continuousAt' {f : α → β} {A : Set α} (Cf : ContinuousAt f (sInf A)) +theorem Monotone.map_csInf_of_continuousAt {f : α → β} {A : Set α} (Cf : ContinuousAt f (sInf A)) (Mf : Monotone f) (A_nonemp : A.Nonempty) (A_bdd : BddBelow A := by bddDefault) : f (sInf A) = sInf (f '' A) := - Monotone.map_sSup_of_continuousAt' (α := αᵒᵈ) (β := βᵒᵈ) Cf Mf.dual A_nonemp A_bdd + Monotone.map_csSup_of_continuousAt (α := αᵒᵈ) (β := βᵒᵈ) Cf Mf.dual A_nonemp A_bdd + +@[deprecated (since := "2024-08-26")] alias Monotone.map_sInf_of_continuousAt' := + Monotone.map_csInf_of_continuousAt /-- A monotone function continuous at the indexed infimum over a nonempty `Sort` sends this indexed infimum to the indexed infimum of the composition. -/ -theorem Monotone.map_iInf_of_continuousAt' {ι : Sort*} [Nonempty ι] {f : α → β} {g : ι → α} +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_sInf_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 + +/-- An antitone function continuous at the infimum of a nonempty set sends this infimum to +the supremum of the image of this set. -/ +theorem AntitoneOn.map_csInf_of_continuousWithinAt {f : α → β} {A : Set α} + (Cf : ContinuousWithinAt f A (sInf A)) + (Af : AntitoneOn f A) (A_nonemp : A.Nonempty) (A_bdd : BddBelow A := by bddDefault) : + f (sInf A) = sSup (f '' A) := + MonotoneOn.map_csInf_of_continuousWithinAt (β := βᵒᵈ) Cf Af.dual_right A_nonemp A_bdd /-- An antitone function continuous at the infimum of a nonempty set sends this infimum to the supremum of the image of this set. -/ -theorem Antitone.map_sInf_of_continuousAt' {f : α → β} {A : Set α} (Cf : ContinuousAt f (sInf A)) +theorem Antitone.map_csInf_of_continuousAt {f : α → β} {A : Set α} (Cf : ContinuousAt f (sInf A)) (Af : Antitone f) (A_nonemp : A.Nonempty) (A_bdd : BddBelow A := by bddDefault) : f (sInf A) = sSup (f '' A) := - Monotone.map_sInf_of_continuousAt' (β := βᵒᵈ) Cf Af.dual_right A_nonemp A_bdd + Monotone.map_csInf_of_continuousAt (β := βᵒᵈ) Cf Af.dual_right A_nonemp A_bdd + +@[deprecated (since := "2024-08-26")] alias Antitone.map_sInf_of_continuousAt' := + Antitone.map_csInf_of_continuousAt /-- An antitone function continuous at the indexed infimum over a nonempty `Sort` sends this indexed infimum to the indexed supremum of the composition. -/ -theorem Antitone.map_iInf_of_continuousAt' {ι : Sort*} [Nonempty ι] {f : α → β} {g : ι → α} +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_sInf_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 + +/-- An antitone function continuous at the supremum of a nonempty set sends this supremum to +the infimum of the image of this set. -/ +theorem AntitoneOn.map_csSup_of_continuousWithinAt {f : α → β} {A : Set α} + (Cf : ContinuousWithinAt f A (sSup A)) + (Af : AntitoneOn f A) (A_nonemp : A.Nonempty) (A_bdd : BddAbove A := by bddDefault) : + f (sSup A) = sInf (f '' A) := + MonotoneOn.map_csSup_of_continuousWithinAt (β := βᵒᵈ) Cf Af.dual_right A_nonemp A_bdd /-- An antitone function continuous at the supremum of a nonempty set sends this supremum to the infimum of the image of this set. -/ -theorem Antitone.map_sSup_of_continuousAt' {f : α → β} {A : Set α} (Cf : ContinuousAt f (sSup A)) +theorem Antitone.map_csSup_of_continuousAt {f : α → β} {A : Set α} (Cf : ContinuousAt f (sSup A)) (Af : Antitone f) (A_nonemp : A.Nonempty) (A_bdd : BddAbove A := by bddDefault) : f (sSup A) = sInf (f '' A) := - Monotone.map_sSup_of_continuousAt' (β := βᵒᵈ) Cf Af.dual_right A_nonemp A_bdd + Monotone.map_csSup_of_continuousAt (β := βᵒᵈ) Cf Af.dual_right A_nonemp A_bdd + +@[deprecated (since := "2024-08-26")] alias Antitone.map_sSup_of_continuousAt' := + Antitone.map_csSup_of_continuousAt /-- An antitone function continuous at the indexed supremum over a nonempty `Sort` sends this indexed supremum to the indexed infimum of the composition. -/ -theorem Antitone.map_iSup_of_continuousAt' {ι : Sort*} [Nonempty ι] {f : α → β} {g : ι → α} +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_sSup_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 end ConditionallyCompleteLinearOrder @@ -109,18 +166,32 @@ theorem IsClosed.sInf_mem {s : Set α} (hs : s.Nonempty) (hc : IsClosed s) : sIn /-- A monotone function `f` sending `bot` to `bot` and continuous at the supremum of a set sends this supremum to the supremum of the image of this set. -/ -theorem Monotone.map_sSup_of_continuousAt {f : α → β} {s : Set α} (Cf : ContinuousAt f (sSup s)) - (Mf : Monotone f) (fbot : f ⊥ = ⊥) : f (sSup s) = sSup (f '' s) := by +theorem MonotoneOn.map_sSup_of_continuousWithinAt {f : α → β} {s : Set α} + (Cf : ContinuousWithinAt f s (sSup s)) + (Mf : MonotoneOn f s) (fbot : f ⊥ = ⊥) : f (sSup s) = sSup (f '' s) := by rcases s.eq_empty_or_nonempty with h | h · simp [h, fbot] - · exact Mf.map_sSup_of_continuousAt' Cf h + · exact Mf.map_csSup_of_continuousWithinAt Cf h + +/-- A monotone function `f` sending `bot` to `bot` and continuous at the supremum of a set sends +this supremum to the supremum of the image of this set. -/ +theorem Monotone.map_sSup_of_continuousAt {f : α → β} {s : Set α} (Cf : ContinuousAt f (sSup s)) + (Mf : Monotone f) (fbot : f ⊥ = ⊥) : f (sSup s) = sSup (f '' s) := + MonotoneOn.map_sSup_of_continuousWithinAt Cf.continuousWithinAt (Mf.monotoneOn _) fbot /-- If a monotone function sending `bot` to `bot` is continuous at the indexed supremum over a `Sort`, then it sends this indexed supremum to the indexed supremum of the composition. -/ 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. -/ +theorem MonotoneOn.map_sInf_of_continuousWithinAt {f : α → β} {s : Set α} + (Cf : ContinuousWithinAt f s (sInf s)) (Mf : MonotoneOn f s) (ftop : f ⊤ = ⊤) : + f (sInf s) = sInf (f '' s) := + MonotoneOn.map_sSup_of_continuousWithinAt (α := αᵒᵈ) (β := βᵒᵈ) Cf Mf.dual ftop /-- 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. -/ @@ -134,6 +205,14 @@ theorem Monotone.map_iInf_of_continuousAt {ι : Sort*} {f : α → β} {g : ι (Cf : ContinuousAt f (iInf g)) (Mf : Monotone f) (ftop : f ⊤ = ⊤) : f (iInf g) = iInf (f ∘ g) := Monotone.map_iSup_of_continuousAt (α := αᵒᵈ) (β := βᵒᵈ) Cf Mf.dual ftop +/-- An antitone function `f` sending `bot` to `top` and continuous at the supremum of a set sends +this supremum to the infimum of the image of this set. -/ +theorem AntitoneOn.map_sSup_of_continuousWithinAt {f : α → β} {s : Set α} + (Cf : ContinuousWithinAt f s (sSup s)) (Af : AntitoneOn f s) (fbot : f ⊥ = ⊤) : + f (sSup s) = sInf (f '' s) := + MonotoneOn.map_sSup_of_continuousWithinAt + (show ContinuousWithinAt (OrderDual.toDual ∘ f) s (sSup s) from Cf) Af fbot + /-- An antitone function `f` sending `bot` to `top` and continuous at the supremum of a set sends this supremum to the infimum of the image of this set. -/ theorem Antitone.map_sSup_of_continuousAt {f : α → β} {s : Set α} (Cf : ContinuousAt f (sSup s)) @@ -149,6 +228,14 @@ theorem Antitone.map_iSup_of_continuousAt {ι : Sort*} {f : α → β} {g : ι Monotone.map_iSup_of_continuousAt (show ContinuousAt (OrderDual.toDual ∘ f) (iSup g) from Cf) Af fbot +/-- An antitone function `f` sending `top` to `bot` and continuous at the infimum of a set sends +this infimum to the supremum of the image of this set. -/ +theorem AntitoneOn.map_sInf_of_continuousWithinAt {f : α → β} {s : Set α} + (Cf : ContinuousWithinAt f s (sInf s)) (Af : AntitoneOn f s) (ftop : f ⊤ = ⊥) : + f (sInf s) = sSup (f '' s) := + MonotoneOn.map_sInf_of_continuousWithinAt + (show ContinuousWithinAt (OrderDual.toDual ∘ f) s (sInf s) from Cf) Af ftop + /-- An antitone function `f` sending `top` to `bot` and continuous at the infimum of a set sends this infimum to the supremum of the image of this set. -/ theorem Antitone.map_sInf_of_continuousAt {f : α → β} {s : Set α} (Cf : ContinuousAt f (sInf s)) @@ -192,72 +279,60 @@ theorem IsClosed.isGreatest_csSup {s : Set α} (hc : IsClosed s) (hs : s.Nonempt IsGreatest s (sSup s) := IsClosed.isLeast_csInf (α := αᵒᵈ) hc hs B -/-- If a monotone function is continuous at the supremum of a nonempty bounded above set `s`, -then it sends this supremum to the supremum of the image of `s`. -/ -theorem Monotone.map_csSup_of_continuousAt {f : α → β} {s : Set α} (Cf : ContinuousAt f (sSup s)) - (Mf : Monotone f) (ne : s.Nonempty) (H : BddAbove s) : f (sSup s) = sSup (f '' s) := by - refine ((isLUB_csSup (ne.image f) (Mf.map_bddAbove H)).unique ?_).symm - refine (isLUB_csSup ne H).isLUB_of_tendsto (fun x _ y _ xy => Mf xy) ne ?_ - exact Cf.mono_left inf_le_left - -/-- If a monotone function is continuous at the indexed supremum of a bounded function on -a nonempty `Sort`, then it sends this supremum to the supremum of the composition. -/ -theorem Monotone.map_ciSup_of_continuousAt {f : α → β} {g : γ → α} (Cf : ContinuousAt f (⨆ i, g i)) - (Mf : Monotone f) (H : BddAbove (range g)) : f (⨆ i, g i) = ⨆ i, f (g i) := by - rw [iSup, Mf.map_csSup_of_continuousAt Cf (range_nonempty _) H, ← range_comp, iSup]; rfl - -/-- If a monotone function is continuous at the infimum of a nonempty bounded below set `s`, -then it sends this infimum to the infimum of the image of `s`. -/ -theorem Monotone.map_csInf_of_continuousAt {f : α → β} {s : Set α} (Cf : ContinuousAt f (sInf s)) - (Mf : Monotone f) (ne : s.Nonempty) (H : BddBelow s) : f (sInf s) = sInf (f '' s) := - Monotone.map_csSup_of_continuousAt (α := αᵒᵈ) (β := βᵒᵈ) Cf Mf.dual ne H - -/-- A continuous monotone function sends indexed infimum to indexed infimum in conditionally -complete linear order, under a boundedness assumption. -/ -theorem Monotone.map_ciInf_of_continuousAt {f : α → β} {g : γ → α} (Cf : ContinuousAt f (⨅ i, g i)) - (Mf : Monotone f) (H : BddBelow (range g)) : f (⨅ i, g i) = ⨅ i, f (g i) := - Monotone.map_ciSup_of_continuousAt (α := αᵒᵈ) (β := βᵒᵈ) Cf Mf.dual H - -/-- If an antitone function is continuous at the supremum of a nonempty bounded above set `s`, -then it sends this supremum to the infimum of the image of `s`. -/ -theorem Antitone.map_csSup_of_continuousAt {f : α → β} {s : Set α} (Cf : ContinuousAt f (sSup s)) - (Af : Antitone f) (ne : s.Nonempty) (H : BddAbove s) : f (sSup s) = sInf (f '' s) := - Monotone.map_csSup_of_continuousAt (show ContinuousAt (OrderDual.toDual ∘ f) (sSup s) from Cf) Af - ne H - -/-- If an antitone function is continuous at the indexed supremum of a bounded function on -a nonempty `Sort`, then it sends this supremum to the infimum of the composition. -/ -theorem Antitone.map_ciSup_of_continuousAt {f : α → β} {g : γ → α} (Cf : ContinuousAt f (⨆ i, g i)) - (Af : Antitone f) (H : BddAbove (range g)) : f (⨆ i, g i) = ⨅ i, f (g i) := - Monotone.map_ciSup_of_continuousAt (show ContinuousAt (OrderDual.toDual ∘ f) (⨆ i, g i) from Cf) - Af H - -/-- If an antitone function is continuous at the infimum of a nonempty bounded below set `s`, -then it sends this infimum to the supremum of the image of `s`. -/ -theorem Antitone.map_csInf_of_continuousAt {f : α → β} {s : Set α} (Cf : ContinuousAt f (sInf s)) - (Af : Antitone f) (ne : s.Nonempty) (H : BddBelow s) : f (sInf s) = sSup (f '' s) := - Monotone.map_csInf_of_continuousAt (show ContinuousAt (OrderDual.toDual ∘ f) (sInf s) from Cf) Af - ne H - -/-- A continuous antitone function sends indexed infimum to indexed supremum in conditionally -complete linear order, under a boundedness assumption. -/ -theorem Antitone.map_ciInf_of_continuousAt {f : α → β} {g : γ → α} (Cf : ContinuousAt f (⨅ i, g i)) - (Af : Antitone f) (H : BddBelow (range g)) : f (⨅ i, g i) = ⨆ i, f (g i) := - Monotone.map_ciInf_of_continuousAt (show ContinuousAt (OrderDual.toDual ∘ f) (⨅ i, g i) from Cf) - Af H - -/-- A monotone map has a limit to the left of any point `x`, equal to `sSup (f '' (Iio x))`. -/ -theorem Monotone.tendsto_nhdsWithin_Iio {α β : Type*} [LinearOrder α] [TopologicalSpace α] +lemma MonotoneOn.tendsto_nhdsWithin_Ioo_left {α β : Type*} [LinearOrder α] [TopologicalSpace α] [OrderTopology α] [ConditionallyCompleteLinearOrder β] [TopologicalSpace β] [OrderTopology β] - {f : α → β} (Mf : Monotone f) (x : α) : Tendsto f (𝓝[<] x) (𝓝 (sSup (f '' Iio x))) := by + {f : α → β} {x y : α} (h_nonempty : (Ioo y x).Nonempty) (Mf : MonotoneOn f (Ioo y x)) + (h_bdd : BddAbove (f '' Ioo y x)) : + Tendsto f (𝓝[<] x) (𝓝 (sSup (f '' Ioo y x))) := by + refine tendsto_order.2 ⟨fun l hl => ?_, fun m hm => ?_⟩ + · obtain ⟨z, ⟨yz, zx⟩, lz⟩ : ∃ a : α, a ∈ Ioo y x ∧ l < f a := by + simpa only [mem_image, exists_prop, exists_exists_and_eq_and] using + exists_lt_of_lt_csSup (h_nonempty.image _) hl + refine mem_of_superset (Ioo_mem_nhdsWithin_Iio' zx) fun w hw => ?_ + exact lz.trans_le <| Mf ⟨yz, zx⟩ ⟨yz.trans_le hw.1.le, hw.2⟩ hw.1.le + · rcases h_nonempty with ⟨_, hy, hx⟩ + refine mem_of_superset (Ioo_mem_nhdsWithin_Iio' (hy.trans hx)) fun w hw => lt_of_le_of_lt ?_ hm + exact le_csSup h_bdd (mem_image_of_mem _ hw) + +lemma MonotoneOn.tendsto_nhdsWithin_Ioo_right {α β : Type*} [LinearOrder α] [TopologicalSpace α] + [OrderTopology α] [ConditionallyCompleteLinearOrder β] [TopologicalSpace β] [OrderTopology β] + {f : α → β} {x y : α} (h_nonempty : (Ioo x y).Nonempty) (Mf : MonotoneOn f (Ioo x y)) + (h_bdd : BddBelow (f '' Ioo x y)) : + Tendsto f (𝓝[>] x) (𝓝 (sInf (f '' Ioo x y))) := by + refine tendsto_order.2 ⟨fun l hl => ?_, fun m hm => ?_⟩ + · rcases h_nonempty with ⟨p, hy, hx⟩ + refine mem_of_superset (Ioo_mem_nhdsWithin_Ioi' (hy.trans hx)) fun w hw => hl.trans_le ?_ + exact csInf_le h_bdd (mem_image_of_mem _ hw) + · obtain ⟨z, ⟨xz, zy⟩, zm⟩ : ∃ a : α, a ∈ Ioo x y ∧ f a < m := by + simpa [mem_image, exists_prop, exists_exists_and_eq_and] using + exists_lt_of_csInf_lt (h_nonempty.image _) hm + refine mem_of_superset (Ioo_mem_nhdsWithin_Ioi' xz) fun w hw => ?_ + exact (Mf ⟨hw.1, hw.2.trans zy⟩ ⟨xz, zy⟩ hw.2.le).trans_lt zm + +lemma MonotoneOn.tendsto_nhdsWithin_Iio {α β : Type*} [LinearOrder α] [TopologicalSpace α] + [OrderTopology α] [ConditionallyCompleteLinearOrder β] [TopologicalSpace β] [OrderTopology β] + {f : α → β} {x : α} (Mf : MonotoneOn f (Iio x)) (h_bdd : BddAbove (f '' Iio x)) : + Tendsto f (𝓝[<] x) (𝓝 (sSup (f '' Iio x))) := by rcases eq_empty_or_nonempty (Iio x) with (h | h); · simp [h] refine tendsto_order.2 ⟨fun l hl => ?_, fun m hm => ?_⟩ · obtain ⟨z, zx, lz⟩ : ∃ a : α, a < x ∧ l < f a := by simpa only [mem_image, exists_prop, exists_exists_and_eq_and] using exists_lt_of_lt_csSup (h.image _) hl - exact mem_of_superset (Ioo_mem_nhdsWithin_Iio' zx) fun y hy => lz.trans_le (Mf hy.1.le) - · refine mem_of_superset self_mem_nhdsWithin fun _ hy => lt_of_le_of_lt ?_ hm - exact le_csSup (Mf.map_bddAbove bddAbove_Iio) (mem_image_of_mem _ hy) + exact mem_of_superset (Ioo_mem_nhdsWithin_Iio' zx) fun y hy => lz.trans_le (Mf zx hy.2 hy.1.le) + · refine mem_of_superset self_mem_nhdsWithin fun y hy => lt_of_le_of_lt ?_ hm + exact le_csSup h_bdd (mem_image_of_mem _ hy) + +lemma MonotoneOn.tendsto_nhdsWithin_Ioi {α β : Type*} [LinearOrder α] [TopologicalSpace α] + [OrderTopology α] [ConditionallyCompleteLinearOrder β] [TopologicalSpace β] [OrderTopology β] + {f : α → β} {x : α} (Mf : MonotoneOn f (Ioi x)) (h_bdd : BddBelow (f '' Ioi x)) : + Tendsto f (𝓝[>] x) (𝓝 (sInf (f '' Ioi x))) := + MonotoneOn.tendsto_nhdsWithin_Iio (α := αᵒᵈ) (β := βᵒᵈ) Mf.dual h_bdd + +/-- A monotone map has a limit to the left of any point `x`, equal to `sSup (f '' (Iio x))`. -/ +theorem Monotone.tendsto_nhdsWithin_Iio {α β : Type*} [LinearOrder α] [TopologicalSpace α] + [OrderTopology α] [ConditionallyCompleteLinearOrder β] [TopologicalSpace β] [OrderTopology β] + {f : α → β} (Mf : Monotone f) (x : α) : Tendsto f (𝓝[<] x) (𝓝 (sSup (f '' Iio x))) := + MonotoneOn.tendsto_nhdsWithin_Iio (Mf.monotoneOn _) (Mf.map_bddAbove bddAbove_Iio) /-- A monotone map has a limit to the right of any point `x`, equal to `sInf (f '' (Ioi x))`. -/ theorem Monotone.tendsto_nhdsWithin_Ioi {α β : Type*} [LinearOrder α] [TopologicalSpace α] @@ -265,4 +340,42 @@ theorem Monotone.tendsto_nhdsWithin_Ioi {α β : Type*} [LinearOrder α] [Topolo {f : α → β} (Mf : Monotone f) (x : α) : Tendsto f (𝓝[>] x) (𝓝 (sInf (f '' Ioi x))) := Monotone.tendsto_nhdsWithin_Iio (α := αᵒᵈ) (β := βᵒᵈ) Mf.dual x +lemma AntitoneOn.tendsto_nhdsWithin_Ioo_left {α β : Type*} [LinearOrder α] [TopologicalSpace α] + [OrderTopology α] [ConditionallyCompleteLinearOrder β] [TopologicalSpace β] [OrderTopology β] + {f : α → β} {x y : α} (h_nonempty : (Ioo y x).Nonempty) (Af : AntitoneOn f (Ioo y x)) + (h_bdd : BddBelow (f '' Ioo y x)) : + Tendsto f (𝓝[<] x) (𝓝 (sInf (f '' Ioo y x))) := + MonotoneOn.tendsto_nhdsWithin_Ioo_left h_nonempty Af.dual_right h_bdd + +lemma AntitoneOn.tendsto_nhdsWithin_Ioo_right {α β : Type*} [LinearOrder α] [TopologicalSpace α] + [OrderTopology α] [ConditionallyCompleteLinearOrder β] [TopologicalSpace β] [OrderTopology β] + {f : α → β} {x y : α} (h_nonempty : (Ioo x y).Nonempty) (Af : AntitoneOn f (Ioo x y)) + (h_bdd : BddAbove (f '' Ioo x y)) : + Tendsto f (𝓝[>] x) (𝓝 (sSup (f '' Ioo x y))) := + MonotoneOn.tendsto_nhdsWithin_Ioo_right h_nonempty Af.dual_right h_bdd + +lemma AntitoneOn.tendsto_nhdsWithin_Iio {α β : Type*} [LinearOrder α] [TopologicalSpace α] + [OrderTopology α] [ConditionallyCompleteLinearOrder β] [TopologicalSpace β] [OrderTopology β] + {f : α → β} {x : α} (Af : AntitoneOn f (Iio x)) (h_bdd : BddBelow (f '' Iio x)) : + Tendsto f (𝓝[<] x) (𝓝 (sInf (f '' Iio x))) := + MonotoneOn.tendsto_nhdsWithin_Iio Af.dual_right h_bdd + +lemma AntitoneOn.tendsto_nhdsWithin_Ioi {α β : Type*} [LinearOrder α] [TopologicalSpace α] + [OrderTopology α] [ConditionallyCompleteLinearOrder β] [TopologicalSpace β] [OrderTopology β] + {f : α → β} {x : α} (Af : AntitoneOn f (Ioi x)) (h_bdd : BddAbove (f '' Ioi x)) : + Tendsto f (𝓝[>] x) (𝓝 (sSup (f '' Ioi x))) := + MonotoneOn.tendsto_nhdsWithin_Ioi Af.dual_right h_bdd + +/-- An antitone map has a limit to the left of any point `x`, equal to `sInf (f '' (Iio x))`. -/ +theorem Antitone.tendsto_nhdsWithin_Iio {α β : Type*} [LinearOrder α] [TopologicalSpace α] + [OrderTopology α] [ConditionallyCompleteLinearOrder β] [TopologicalSpace β] [OrderTopology β] + {f : α → β} (Af : Antitone f) (x : α) : Tendsto f (𝓝[<] x) (𝓝 (sInf (f '' Iio x))) := + Monotone.tendsto_nhdsWithin_Iio Af.dual_right x + +/-- An antitone map has a limit to the right of any point `x`, equal to `sSup (f '' (Ioi x))`. -/ +theorem Antitone.tendsto_nhdsWithin_Ioi {α β : Type*} [LinearOrder α] [TopologicalSpace α] + [OrderTopology α] [ConditionallyCompleteLinearOrder β] [TopologicalSpace β] [OrderTopology β] + {f : α → β} (Af : Antitone f) (x : α) : Tendsto f (𝓝[>] x) (𝓝 (sSup (f '' Ioi x))) := + Monotone.tendsto_nhdsWithin_Ioi Af.dual_right x + end ConditionallyCompleteLinearOrder diff --git a/Mathlib/Topology/Order/MonotoneConvergence.lean b/Mathlib/Topology/Order/MonotoneConvergence.lean index 320b7751381fa..bad7ee58b291e 100644 --- a/Mathlib/Topology/Order/MonotoneConvergence.lean +++ b/Mathlib/Topology/Order/MonotoneConvergence.lean @@ -67,7 +67,7 @@ instance (priority := 100) LinearOrder.supConvergenceClass [TopologicalSpace α] · rcases ha.exists_between hb with ⟨c, hcs, bc, bca⟩ lift c to s using hcs exact (eventually_ge_atTop c).mono fun x hx => bc.trans_le hx - · exact eventually_of_forall fun x => (ha.1 x.2).trans_lt hb + · exact Eventually.of_forall fun x => (ha.1 x.2).trans_lt hb -- see Note [lower instance priority] instance (priority := 100) LinearOrder.infConvergenceClass [TopologicalSpace α] [LinearOrder α] diff --git a/Mathlib/Topology/Order/OrderClosed.lean b/Mathlib/Topology/Order/OrderClosed.lean index f4a952a37cc45..e2763d592bc24 100644 --- a/Mathlib/Topology/Order/OrderClosed.lean +++ b/Mathlib/Topology/Order/OrderClosed.lean @@ -129,7 +129,7 @@ theorem le_of_tendsto {x : Filter β} [NeBot x] (lim : Tendsto f x (𝓝 a)) theorem le_of_tendsto' {x : Filter β} [NeBot x] (lim : Tendsto f x (𝓝 a)) (h : ∀ c, f c ≤ b) : a ≤ b := - le_of_tendsto lim (eventually_of_forall h) + le_of_tendsto lim (Eventually.of_forall h) @[simp] lemma upperBounds_closure (s : Set α) : upperBounds (closure s : Set α) = upperBounds s := ext fun a ↦ by simp_rw [mem_upperBounds_iff_subset_Iic, isClosed_Iic.closure_subset_iff] @@ -352,7 +352,7 @@ theorem ge_of_tendsto {x : Filter β} [NeBot x] (lim : Tendsto f x (𝓝 a)) theorem ge_of_tendsto' {x : Filter β} [NeBot x] (lim : Tendsto f x (𝓝 a)) (h : ∀ c, b ≤ f c) : b ≤ a := - ge_of_tendsto lim (eventually_of_forall h) + ge_of_tendsto lim (Eventually.of_forall h) @[simp] lemma lowerBounds_closure (s : Set α) : lowerBounds (closure s : Set α) = lowerBounds s := ext fun a ↦ by simp_rw [mem_lowerBounds_iff_subset_Ici, isClosed_Ici.closure_subset_iff] @@ -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 @@ -580,7 +580,7 @@ alias tendsto_le_of_eventuallyLE := le_of_tendsto_of_tendsto theorem le_of_tendsto_of_tendsto' {f g : β → α} {b : Filter β} {a₁ a₂ : α} [NeBot b] (hf : Tendsto f b (𝓝 a₁)) (hg : Tendsto g b (𝓝 a₂)) (h : ∀ x, f x ≤ g x) : a₁ ≤ a₂ := - le_of_tendsto_of_tendsto hf hg (eventually_of_forall h) + le_of_tendsto_of_tendsto hf hg (Eventually.of_forall h) @[simp] theorem closure_le_eq [TopologicalSpace β] {f g : β → α} (hf : Continuous f) (hg : Continuous g) : diff --git a/Mathlib/Topology/Order/ScottTopology.lean b/Mathlib/Topology/Order/ScottTopology.lean index 2dc2f2655354e..747074b163cfb 100644 --- a/Mathlib/Topology/Order/ScottTopology.lean +++ b/Mathlib/Topology/Order/ScottTopology.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Christopher Hoskin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Christopher Hoskin -/ +import Mathlib.Order.ScottContinuity import Mathlib.Topology.Order.UpperLowerSetTopology /-! @@ -106,7 +107,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 @@ -123,7 +124,7 @@ namespace Topology /-! ### Scott-Hausdorff topology -/ section ScottHausdorff -variable [Preorder α] {s : Set α} +variable [Preorder α] /-- The Scott-Hausdorff topology. @@ -163,13 +164,7 @@ variable {α} 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_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⟩ - -lemma isClosed_of_isUpperSet (h : IsUpperSet s) : IsClosed s := - isOpen_compl_iff.1 <| isOpen_of_isLowerSet h.compl + a ∈ s → ∃ b ∈ d, Ici b ∩ d ⊆ s := by rw [topology_eq_scottHausdorff (α := α)]; rfl lemma dirSupInacc_of_isOpen (h : IsOpen s) : DirSupInacc s := fun d hd₁ hd₂ a hda hd₃ ↦ by @@ -181,6 +176,20 @@ lemma dirSupClosed_of_isClosed (h : IsClosed s) : DirSupClosed s := end IsScottHausdorff end ScottHausdorff +section ScottHausdorff +namespace IsScottHausdorff + +variable {s : Set α} [Preorder α] {t : TopologicalSpace α} [IsScottHausdorff α] + +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⟩ + +lemma isClosed_of_isUpperSet (h : IsUpperSet s) : IsClosed s := + isOpen_compl_iff.1 <| isOpen_of_isLowerSet h.compl + +end IsScottHausdorff +end ScottHausdorff + /-! ### Scott topology -/ section Scott @@ -216,7 +225,7 @@ lemma topology_eq : ‹_› = scott α := topology_eq_scott variable {α} {s : Set α} {a : α} lemma isOpen_iff_isUpperSet_and_scottHausdorff_open : - IsOpen s ↔ IsUpperSet s ∧ IsOpen[scottHausdorff α] s := by erw [topology_eq α]; rfl + IsOpen s ↔ IsUpperSet s ∧ IsOpen[scottHausdorff α] s := by rw [topology_eq α]; rfl lemma isOpen_iff_isUpperSet_and_dirSupInacc : IsOpen s ↔ IsUpperSet s ∧ DirSupInacc s := by rw [isOpen_iff_isUpperSet_and_scottHausdorff_open] @@ -297,27 +306,47 @@ end PartialOrder section CompleteLinearOrder -variable [CompleteLinearOrder α] [TopologicalSpace α] [Topology.IsScott α] +variable [CompleteLinearOrder α] -lemma isOpen_iff_Iic_compl_or_univ (U : Set α) : - IsOpen U ↔ (∃ (a : α), U = (Iic a)ᶜ) ∨ U = univ := by +lemma isOpen_iff_Iic_compl_or_univ [TopologicalSpace α] [Topology.IsScott α] (U : Set α) : + IsOpen U ↔ U = univ ∨ ∃ a, (Iic a)ᶜ = U := by constructor · intro hU rcases eq_empty_or_nonempty Uᶜ with eUc | neUc - · exact Or.inr (compl_empty_iff.mp eUc) - · apply Or.inl + · exact Or.inl (compl_empty_iff.mp eUc) + · apply Or.inr use sSup Uᶜ - rw [eq_compl_comm, le_antisymm_iff] - exact ⟨(isLowerSet_of_isClosed hU.isClosed_compl).Iic_subset - (dirSupClosed_iff_forall_sSup.mp (dirSupClosed_of_isClosed hU.isClosed_compl) - neUc (isChain_of_trichotomous Uᶜ).directedOn le_rfl), - fun _ ha ↦ le_sSup ha⟩ - · rintro (⟨a,rfl⟩ | rfl) - · exact isClosed_Iic.isOpen_compl + rw [compl_eq_comm, le_antisymm_iff] + exact ⟨fun _ ha ↦ le_sSup ha, (isLowerSet_of_isClosed hU.isClosed_compl).Iic_subset + (dirSupClosed_iff_forall_sSup.mp (dirSupClosed_of_isClosed hU.isClosed_compl) + neUc (isChain_of_trichotomous Uᶜ).directedOn le_rfl)⟩ + · rintro (rfl | ⟨a, rfl⟩) · exact isOpen_univ + · exact isClosed_Iic.isOpen_compl + +-- 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 + 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] + +/- The upper topology on a complete linear order is the Scott topology -/ +instance [TopologicalSpace α] [IsUpper α] : IsScott α where + topology_eq_scott := by + rw [scott_eq_upper_of_completeLinearOrder] + exact IsUpper.topology_eq α end CompleteLinearOrder +lemma isOpen_iff_scottContinuous_mem [Preorder α] {s : Set α} [TopologicalSpace α] [IsScott α] : + IsOpen s ↔ ScottContinuous fun x ↦ x ∈ s := by + rw [scottContinuous_iff_continuous] + exact isOpen_iff_continuous_mem + end IsScott /-- @@ -367,8 +396,8 @@ end Scott variable [Preorder α] lemma scottHausdorff_le_lower : scottHausdorff α ≤ lower α := - fun s h => @IsScottHausdorff.isOpen_of_isLowerSet _ _ (scottHausdorff α) _ _ - <| (@IsLower.isLowerSet_of_isOpen (Topology.WithLower α) _ _ _ s h) + fun s h => IsScottHausdorff.isOpen_of_isLowerSet (t := scottHausdorff α) + <| (@IsLower.isLowerSet_of_isOpen (Topology.WithLower α) _ _ _ s h) variable [TopologicalSpace α] @@ -382,7 +411,7 @@ lemma IsScott.scottHausdorff_le [IsScott α] : scottHausdorff α ≤ ‹Topologi lemma IsLower.scottHausdorff_le [IsLower α] : scottHausdorff α ≤ ‹TopologicalSpace α› := fun _ h ↦ - @IsScottHausdorff.isOpen_of_isLowerSet _ _ (scottHausdorff α) _ _ + IsScottHausdorff.isOpen_of_isLowerSet (t := scottHausdorff α) <| IsLower.isLowerSet_of_isOpen h end Topology diff --git a/Mathlib/Topology/Order/UpperLowerSetTopology.lean b/Mathlib/Topology/Order/UpperLowerSetTopology.lean index ff3fc1e7a3de2..02681dbd9f86d 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 /-! @@ -74,10 +74,10 @@ def WithUpperSet (α : Type*) := α namespace WithUpperSet -/-- `toUpperSet` is the identity function to the `WithUpperSet` of a type. -/ +/-- `toUpperSet` is the identity function to the `WithUpperSet` of a type. -/ @[match_pattern] def toUpperSet : α ≃ WithUpperSet α := Equiv.refl _ -/-- `ofUpperSet` is the identity function from the `WithUpperSet` of a type. -/ +/-- `ofUpperSet` is the identity function from the `WithUpperSet` of a type. -/ @[match_pattern] def ofUpperSet : WithUpperSet α ≃ α := Equiv.refl _ @[simp] lemma to_WithUpperSet_symm_eq : (@toUpperSet α).symm = ofUpperSet := rfl @@ -120,10 +120,10 @@ def WithLowerSet (α : Type*) := α namespace WithLowerSet -/-- `toLowerSet` is the identity function to the `WithLowerSet` of a type. -/ +/-- `toLowerSet` is the identity function to the `WithLowerSet` of a type. -/ @[match_pattern] def toLowerSet : α ≃ WithLowerSet α := Equiv.refl _ -/-- `ofLowerSet` is the identity function from the `WithLowerSet` of a type. -/ +/-- `ofLowerSet` is the identity function from the `WithLowerSet` of a type. -/ @[match_pattern] def ofLowerSet : WithLowerSet α ≃ α := Equiv.refl _ @[simp] lemma to_WithLowerSet_symm_eq : (@toLowerSet α).symm = ofLowerSet := rfl diff --git a/Mathlib/Topology/PartialHomeomorph.lean b/Mathlib/Topology/PartialHomeomorph.lean index ee0f1334ee46f..98e7d2e0d5f74 100644 --- a/Mathlib/Topology/PartialHomeomorph.lean +++ b/Mathlib/Topology/PartialHomeomorph.lean @@ -210,11 +210,6 @@ theorem replaceEquiv_eq_self (e' : PartialEquiv X Y) theorem source_preimage_target : e.source ⊆ e ⁻¹' e.target := e.mapsTo -@[deprecated toPartialEquiv_injective (since := "2023-02-18")] -theorem eq_of_partialEquiv_eq {e e' : PartialHomeomorph X Y} - (h : e.toPartialEquiv = e'.toPartialEquiv) : e = e' := - toPartialEquiv_injective h - theorem eventually_left_inverse {x} (hx : x ∈ e.source) : ∀ᶠ y in 𝓝 x, e.symm (e y) = y := (e.open_source.eventually_mem hx).mono e.left_inv' @@ -366,7 +361,7 @@ theorem eventually_nhdsWithin' {x : X} (p : X → Prop) {s : Set X} /-- This lemma is useful in the manifold library in the case that `e` is a chart. It states that locally around `e x` the set `e.symm ⁻¹' s` is the same as the set intersected with the target - of `e` and some other neighborhood of `f x` (which will be the source of a chart on `Z`). -/ + of `e` and some other neighborhood of `f x` (which will be the source of a chart on `Z`). -/ theorem preimage_eventuallyEq_target_inter_preimage_inter {e : PartialHomeomorph X Y} {s : Set X} {t : Set Z} {x : X} {f : X → Z} (hf : ContinuousWithinAt f s x) (hxe : x ∈ e.source) (ht : t ∈ 𝓝 (f x)) : @@ -375,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) := @@ -1007,7 +1002,7 @@ theorem continuousOn_iff_continuousOn_comp_right {f : Y → Z} {s : Set Y} (h : /-- Continuity within a set at a point can be read under left composition with a local homeomorphism if a neighborhood of the initial point is sent to the source of the local -homeomorphism-/ +homeomorphism -/ theorem continuousWithinAt_iff_continuousWithinAt_comp_left {f : Z → X} {s : Set Z} {x : Z} (hx : f x ∈ e.source) (h : f ⁻¹' e.source ∈ 𝓝[s] x) : ContinuousWithinAt f s x ↔ ContinuousWithinAt (e ∘ f) s x := by @@ -1020,7 +1015,7 @@ theorem continuousWithinAt_iff_continuousWithinAt_comp_left {f : Z → X} {s : S exact this.congr (fun y hy => by simp [e.left_inv hy.2]) (by simp [e.left_inv hx]) /-- Continuity at a point can be read under left composition with a partial homeomorphism if a -neighborhood of the initial point is sent to the source of the partial homeomorphism-/ +neighborhood of the initial point is sent to the source of the partial homeomorphism -/ theorem continuousAt_iff_continuousAt_comp_left {f : Z → X} {x : Z} (h : f ⁻¹' e.source ∈ 𝓝 x) : ContinuousAt f x ↔ ContinuousAt (e ∘ f) x := by have hx : f x ∈ e.source := (mem_of_mem_nhds h : _) @@ -1074,7 +1069,7 @@ theorem nhds_eq_comap_inf_principal {x} (hx : x ∈ e.source) : lift x to e.source using hx rw [← e.open_source.nhdsWithin_eq x.2, ← map_nhds_subtype_val, ← map_comap_setCoe_val, e.toHomeomorphSourceTarget.nhds_eq_comap, nhds_subtype_eq_comap] - simp only [(· ∘ ·), toHomeomorphSourceTarget_apply_coe, comap_comap] + simp only [Function.comp_def, toHomeomorphSourceTarget_apply_coe, comap_comap] /-- If a partial homeomorphism has source and target equal to univ, then it induces a homeomorphism between the whole spaces, expressed in this definition. -/ diff --git a/Mathlib/Topology/PartitionOfUnity.lean b/Mathlib/Topology/PartitionOfUnity.lean index a98ad48c12803..661a124cbc7d4 100644 --- a/Mathlib/Topology/PartitionOfUnity.lean +++ b/Mathlib/Topology/PartitionOfUnity.lean @@ -4,8 +4,7 @@ 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.Topology.ContinuousMap.Algebra import Mathlib.Topology.Compactness.Paracompact import Mathlib.Topology.ShrinkingLemma import Mathlib.Topology.UrysohnsLemma @@ -140,7 +139,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 +311,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' diff --git a/Mathlib/Topology/Perfect.lean b/Mathlib/Topology/Perfect.lean index 31622ec28846e..c390399234943 100644 --- a/Mathlib/Topology/Perfect.lean +++ b/Mathlib/Topology/Perfect.lean @@ -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/RestrictGenTopology.lean b/Mathlib/Topology/RestrictGen.lean similarity index 85% rename from Mathlib/Topology/RestrictGenTopology.lean rename to Mathlib/Topology/RestrictGen.lean index faa7f586f6d16..782e359360a79 100644 --- a/Mathlib/Topology/RestrictGenTopology.lean +++ b/Mathlib/Topology/RestrictGen.lean @@ -83,7 +83,7 @@ lemma of_seq [SequentialSpace X] rcases isClosed_induced_iff.1 (ht _ (h hux)) with ⟨s, hsc, hst⟩ rw [Subtype.preimage_val_eq_preimage_val_iff, Set.ext_iff] at hst suffices x ∈ s by specialize hst x; simp_all - refine hsc.mem_of_tendsto hux <| eventually_of_forall fun k ↦ ?_ + refine hsc.mem_of_tendsto hux <| Eventually.of_forall fun k ↦ ?_ specialize hst (u k) simp_all @@ -91,4 +91,16 @@ lemma of_seq [SequentialSpace X] lemma isCompact_of_seq [SequentialSpace X] : RestrictGenTopology {K : Set X | IsCompact K} := of_seq fun _u _x hux ↦ hux.isCompact_insert_range +/-- If each point of the space has a neighborhood from the family `S`, +then the topology is generated by its restrictions to the sets of `S`. -/ +lemma of_nhds (h : ∀ x, ∃ s ∈ S, s ∈ 𝓝 x) : RestrictGenTopology S := + of_continuous_prop fun _f hf ↦ continuous_iff_continuousAt.2 fun x ↦ + let ⟨s, hsS, hsx⟩ := h x + (hf s hsS).continuousAt hsx + +/-- A weakly locally compact space is compactly generated. -/ +lemma isCompact_of_weaklyLocallyCompact [WeaklyLocallyCompactSpace X] : + RestrictGenTopology {K : Set X | IsCompact K} := + of_nhds exists_compact_mem_nhds + end RestrictGenTopology diff --git a/Mathlib/Topology/Semicontinuous.lean b/Mathlib/Topology/Semicontinuous.lean index b48b959356b6c..28c129606e374 100644 --- a/Mathlib/Topology/Semicontinuous.lean +++ b/Mathlib/Topology/Semicontinuous.lean @@ -169,10 +169,10 @@ theorem LowerSemicontinuous.lowerSemicontinuousOn (h : LowerSemicontinuous f) (s theorem lowerSemicontinuousWithinAt_const : LowerSemicontinuousWithinAt (fun _x => z) s x := - fun _y hy => Filter.eventually_of_forall fun _x => hy + fun _y hy => Filter.Eventually.of_forall fun _x => hy theorem lowerSemicontinuousAt_const : LowerSemicontinuousAt (fun _x => z) x := fun _y hy => - Filter.eventually_of_forall fun _x => hy + Filter.Eventually.of_forall fun _x => hy theorem lowerSemicontinuousOn_const : LowerSemicontinuousOn (fun _x => z) s := fun _x _hx => lowerSemicontinuousWithinAt_const @@ -193,7 +193,7 @@ theorem IsOpen.lowerSemicontinuous_indicator (hs : IsOpen s) (hy : 0 ≤ y) : by_cases h : x ∈ s <;> simp [h] at hz · filter_upwards [hs.mem_nhds h] simp (config := { contextual := true }) [hz] - · refine Filter.eventually_of_forall fun x' => ?_ + · refine Filter.Eventually.of_forall fun x' => ?_ by_cases h' : x' ∈ s <;> simp [h', hz.trans_le hy, hz] theorem IsOpen.lowerSemicontinuousOn_indicator (hs : IsOpen s) (hy : 0 ≤ y) : @@ -212,7 +212,7 @@ theorem IsClosed.lowerSemicontinuous_indicator (hs : IsClosed s) (hy : y ≤ 0) LowerSemicontinuous (indicator s fun _x => y) := by intro x z hz by_cases h : x ∈ s <;> simp [h] at hz - · refine Filter.eventually_of_forall fun x' => ?_ + · refine Filter.Eventually.of_forall fun x' => ?_ by_cases h' : x' ∈ s <;> simp [h', hz, hz.trans_le hy] · filter_upwards [hs.isOpen_compl.mem_nhds h] simp (config := { contextual := true }) [hz] @@ -358,7 +358,7 @@ theorem ContinuousAt.comp_lowerSemicontinuousWithinAt {g : γ → δ} {f : α _ ≤ g (f a) := gmon (min_le_right _ _) · simp only [not_exists, not_lt] at h - exact Filter.eventually_of_forall fun a => hy.trans_le (gmon (h (f a))) + exact Filter.Eventually.of_forall fun a => hy.trans_le (gmon (h (f a))) theorem ContinuousAt.comp_lowerSemicontinuousAt {g : γ → δ} {f : α → γ} (hg : ContinuousAt g (f x)) (hf : LowerSemicontinuousAt f x) (gmon : Monotone g) : LowerSemicontinuousAt (g ∘ f) x := by @@ -473,7 +473,7 @@ theorem LowerSemicontinuousWithinAt.add' {f g : α → γ} (hf : LowerSemicontin y < f x + min (g z) (g x) := h this _ ≤ f z + g z := add_le_add (hx₁ (f z)) (min_le_left _ _) · simp only [not_exists, not_lt] at hx₁ hx₂ - apply Filter.eventually_of_forall + apply Filter.Eventually.of_forall intro z have : (f x, g x) ∈ u ×ˢ v := ⟨xu, xv⟩ calc @@ -625,7 +625,7 @@ theorem lowerSemicontinuousOn_biSup {p : ι → Prop} {f : ∀ i, p i → α → theorem lowerSemicontinuous_ciSup {f : ι → α → δ'} (bdd : ∀ x, BddAbove (range fun i => f i x)) (h : ∀ i, LowerSemicontinuous (f i)) : LowerSemicontinuous fun x' => ⨆ i, f i x' := fun x => - lowerSemicontinuousAt_ciSup (eventually_of_forall bdd) fun i => h i x + lowerSemicontinuousAt_ciSup (Eventually.of_forall bdd) fun i => h i x theorem lowerSemicontinuous_iSup {f : ι → α → δ} (h : ∀ i, LowerSemicontinuous (f i)) : LowerSemicontinuous fun x' => ⨆ i, f i x' := @@ -711,10 +711,10 @@ theorem UpperSemicontinuous.upperSemicontinuousOn (h : UpperSemicontinuous f) (s theorem upperSemicontinuousWithinAt_const : UpperSemicontinuousWithinAt (fun _x => z) s x := - fun _y hy => Filter.eventually_of_forall fun _x => hy + fun _y hy => Filter.Eventually.of_forall fun _x => hy theorem upperSemicontinuousAt_const : UpperSemicontinuousAt (fun _x => z) x := fun _y hy => - Filter.eventually_of_forall fun _x => hy + Filter.Eventually.of_forall fun _x => hy theorem upperSemicontinuousOn_const : UpperSemicontinuousOn (fun _x => z) s := fun _x _hx => upperSemicontinuousWithinAt_const @@ -1054,7 +1054,7 @@ theorem upperSemicontinuousOn_biInf {p : ι → Prop} {f : ∀ i, p i → α → theorem upperSemicontinuous_ciInf {f : ι → α → δ'} (bdd : ∀ x, BddBelow (range fun i => f i x)) (h : ∀ i, UpperSemicontinuous (f i)) : UpperSemicontinuous fun x' => ⨅ i, f i x' := fun x => - upperSemicontinuousAt_ciInf (eventually_of_forall bdd) fun i => h i x + upperSemicontinuousAt_ciInf (Eventually.of_forall bdd) fun i => h i x theorem upperSemicontinuous_iInf {f : ι → α → δ} (h : ∀ i, UpperSemicontinuous (f i)) : UpperSemicontinuous fun x' => ⨅ i, f i x' := fun x => upperSemicontinuousAt_iInf fun i => h i x @@ -1094,7 +1094,7 @@ theorem continuousWithinAt_iff_lower_upperSemicontinuousWithinAt {f : α → γ} apply hu exact ⟨Hl (f a), lfa⟩ · simp only [not_exists, not_lt] at Hu - apply Filter.eventually_of_forall + apply Filter.Eventually.of_forall intro a have : f a = f x := le_antisymm (Hu _) (Hl _) rw [this] diff --git a/Mathlib/Topology/Separation.lean b/Mathlib/Topology/Separation.lean index 949fd616fcc6b..98e4bd5cdac2f 100644 --- a/Mathlib/Topology/Separation.lean +++ b/Mathlib/Topology/Separation.lean @@ -259,7 +259,7 @@ end SeparatedNhds /-- A T₀ space, also known as a Kolmogorov space, is a topological space such that for every pair `x ≠ y`, there is an open set containing one but not the other. We formulate the definition in terms -of the `Inseparable` relation. -/ +of the `Inseparable` relation. -/ class T0Space (X : Type u) [TopologicalSpace X] : Prop where /-- Two inseparable points in a T₀ space are equal. -/ t0 : ∀ ⦃x y : X⦄, Inseparable x y → x = y @@ -576,30 +576,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 @@ -974,13 +972,13 @@ theorem Filter.HasBasis.exists_inter_eq_singleton_of_mem_discrete {ι : Type*} { exact ⟨i, hi, hix.antisymm <| singleton_subset_iff.2 ⟨mem_of_mem_nhds <| hb.mem_of_mem hi, hx⟩⟩ /-- A point `x` in a discrete subset `s` of a topological space admits a neighbourhood -that only meets `s` at `x`. -/ +that only meets `s` at `x`. -/ theorem nhds_inter_eq_singleton_of_mem_discrete {s : Set X} [DiscreteTopology s] {x : X} (hx : x ∈ s) : ∃ U ∈ 𝓝 x, U ∩ s = {x} := by simpa using (𝓝 x).basis_sets.exists_inter_eq_singleton_of_mem_discrete hx /-- Let `x` be a point in a discrete subset `s` of a topological space, then there exists an open -set that only meets `s` at `x`. -/ +set that only meets `s` at `x`. -/ theorem isOpen_inter_eq_singleton_of_mem_discrete {s : Set X} [DiscreteTopology s] {x : X} (hx : x ∈ s) : ∃ U : Set X, IsOpen U ∧ U ∩ s = {x} := by obtain ⟨U, hU_nhds, hU_inter⟩ := nhds_inter_eq_singleton_of_mem_discrete hx @@ -1045,6 +1043,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] @@ -1103,7 +1112,7 @@ theorem exists_isCompact_superset_iff {s : Set X} : alias exists_compact_superset_iff := exists_isCompact_superset_iff /-- If `K` and `L` are disjoint compact sets in an R₁ topological space -and `L` is also closed, then `K` and `L` have disjoint neighborhoods. -/ +and `L` is also closed, then `K` and `L` have disjoint neighborhoods. -/ theorem SeparatedNhds.of_isCompact_isCompact_isClosed {K L : Set X} (hK : IsCompact K) (hL : IsCompact L) (h'L : IsClosed L) (hd : Disjoint K L) : SeparatedNhds K L := by simp_rw [separatedNhds_iff_disjoint, hK.disjoint_nhdsSet_left, hL.disjoint_nhdsSet_right, @@ -1382,11 +1391,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 := @@ -1410,6 +1419,22 @@ theorem IsCompact.nhdsSet_inter_eq [T2Space X] {s t : Set X} (hs : IsCompact s) · exact le_iSup₂_of_le x ⟨hxs, hyt⟩ (inf_idem _).le · exact (disjoint_nhds_nhds.mpr hne).eq_bot ▸ bot_le +/-- In a `T2Space X`, for a compact set `t` and a point `x` outside `t`, there are open sets `U`, +`V` that separate `t` and `x`.-/ +lemma IsCompact.separation_of_not_mem {X : Type u_1} [TopologicalSpace X] [T2Space X] {x : X} + {t : Set X} (H1 : IsCompact t) (H2 : x ∉ t) : + ∃ (U : Set X), ∃ (V : Set X), IsOpen U ∧ IsOpen V ∧ t ⊆ U ∧ x ∈ V ∧ Disjoint U V := by + simpa [SeparatedNhds] using SeparatedNhds.of_isCompact_isCompact_isClosed H1 isCompact_singleton + isClosed_singleton <| disjoint_singleton_right.mpr H2 + +/-- In a `T2Space X`, for a compact set `t` and a point `x` outside `t`, `𝓝ˢ t` and `𝓝 x` are +disjoint. -/ +lemma IsCompact.disjoint_nhdsSet_nhds {X : Type u_1} [TopologicalSpace X] [T2Space X] {x : X} + {t : Set X} (H1 : IsCompact t) (H2 : x ∉ t) : + Disjoint (𝓝ˢ t) (𝓝 x) := by + simpa using SeparatedNhds.disjoint_nhdsSet <| .of_isCompact_isCompact_isClosed H1 + isCompact_singleton isClosed_singleton <| disjoint_singleton_right.mpr H2 + /-- If a function `f` is - injective on a compact set `s`; @@ -1426,7 +1451,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 @@ -1738,6 +1763,25 @@ theorem SeparatedNhds.of_isCompact_isCompact [T2Space X] {s t : Set X} (hs : IsC @[deprecated (since := "2024-01-28")] alias separatedNhds_of_isCompact_isCompact := SeparatedNhds.of_isCompact_isCompact +/-- In a `T2Space X`, for disjoint closed sets `s t` such that `closure sᶜ` is compact, +there are neighbourhoods that separate `s` and `t`.-/ +lemma SeparatedNhds.of_isClosed_isCompact_closure_compl_isClosed [T2Space X] {s : Set X} + {t : Set X} (H1 : IsClosed s) (H2 : IsCompact (closure sᶜ)) (H3 : IsClosed t) + (H4 : Disjoint s t) : SeparatedNhds s t := by + -- Since `t` is a closed subset of the compact set `closure sᶜ`, it is compact. + have ht : IsCompact t := .of_isClosed_subset H2 H3 <| H4.subset_compl_left.trans subset_closure + -- we split `s` into its frontier and its interior. + rw [← diff_union_of_subset (interior_subset (s := s))] + -- since `t ⊆ sᶜ`, which is open, and `interior s` is open, we have + -- `SeparatedNhds (interior s) t`, which leaves us only with the frontier. + refine .union_left ?_ ⟨interior s, sᶜ, isOpen_interior, H1.isOpen_compl, le_rfl, + H4.subset_compl_left, disjoint_compl_right.mono_left interior_subset⟩ + -- Since the frontier of `s` is compact (as it is a subset of `closure sᶜ`), we simply apply + -- `SeparatedNhds_of_isCompact_isCompact`. + rw [← H1.frontier_eq, frontier_eq_closure_inter_closure, H1.closure_eq] + refine .of_isCompact_isCompact ?_ ht (disjoint_of_subset_left inter_subset_left H4) + exact H2.of_isClosed_subset (H1.inter isClosed_closure) inter_subset_right + section SeparatedFinset theorem SeparatedNhds.of_finset_finset [T2Space X] (s t : Finset X) (h : Disjoint s t) : @@ -1845,7 +1889,7 @@ of filters `𝓝ˢ s` and `𝓝 a`. -/ @[mk_iff] class RegularSpace (X : Type u) [TopologicalSpace X] : Prop where /-- If `a` is a point that does not belong to a closed set `s`, then `a` and `s` admit disjoint - neighborhoods. -/ + neighborhoods. -/ regular : ∀ {s : Set X} {a}, IsClosed s → a ∉ s → Disjoint (𝓝ˢ s) (𝓝 a) theorem regularSpace_TFAE (X : Type u) [TopologicalSpace X] : @@ -1855,30 +1899,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) : @@ -1910,6 +1952,7 @@ alias RegularSpace.ofExistsMemNhdsIsClosedSubset := RegularSpace.of_exists_mem_n instance (priority := 100) [WeaklyLocallyCompactSpace X] [R1Space X] : RegularSpace X := .of_hasBasis isCompact_isClosed_basis_nhds fun _ _ ⟨_, _, h⟩ ↦ h +section variable [RegularSpace X] {x : X} {s : Set X} theorem disjoint_nhdsSet_nhds : Disjoint (𝓝ˢ s) (𝓝 x) ↔ x ∉ closure s := by @@ -2022,9 +2065,11 @@ lemma SeparatedNhds.of_isCompact_isClosed {s t : Set X} @[deprecated (since := "2024-01-28")] alias separatedNhds_of_isCompact_isClosed := SeparatedNhds.of_isCompact_isClosed +end + /-- This technique to witness `HasSeparatingCover` in regular Lindelöf topological spaces will be used to prove regular Lindelöf spaces are normal. -/ -lemma IsClosed.HasSeparatingCover {s t : Set X} [LindelofSpace X] +lemma IsClosed.HasSeparatingCover {s t : Set X} [LindelofSpace X] [RegularSpace X] (s_cl : IsClosed s) (t_cl : IsClosed t) (st_dis : Disjoint s t) : HasSeparatingCover s t := by -- `IsLindelof.indexed_countable_subcover` requires the space be Nonempty rcases isEmpty_or_nonempty X with empty_X | nonempty_X @@ -2133,7 +2178,7 @@ end T25 section T3 /-- A T₃ space is a T₀ space which is a regular space. Any T₃ space is a T₁ space, a T₂ space, and -a T₂.₅ space. -/ +a T₂.₅ space. -/ class T3Space (X : Type u) [TopologicalSpace X] extends T0Space X, RegularSpace X : Prop instance (priority := 90) instT3Space [T0Space X] [RegularSpace X] : T3Space X := ⟨⟩ @@ -2226,6 +2271,7 @@ instance (priority := 100) NormalSpace.of_compactSpace_r1Space [CompactSpace X] NormalSpace X where normal _s _t hs ht := .of_isCompact_isCompact_isClosed hs.isCompact ht.isCompact ht +set_option pp.universes true in /-- A regular topological space with a Lindelöf topology is a normal space. A consequence of e.g. Corollaries 20.8 and 20.10 of [Willard's *General Topology*][zbMATH02107988] (without the assumption of Hausdorff). -/ @@ -2514,7 +2560,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⟩ @@ -2530,7 +2576,7 @@ theorem isTopologicalBasis_isClopen : IsTopologicalBasis { s : Set X | IsClopen tauto /-- Every member of an open set in a compact Hausdorff totally disconnected space - is contained in a clopen set contained in the open set. -/ + is contained in a clopen set contained in the open set. -/ theorem compact_exists_isClopen_in_isOpen {x : X} {U : Set X} (is_open : IsOpen U) (memU : x ∈ U) : ∃ V : Set X, IsClopen V ∧ x ∈ V ∧ V ⊆ U := isTopologicalBasis_isClopen.mem_nhds_iff.1 (is_open.mem_nhds memU) @@ -2605,3 +2651,5 @@ instance ConnectedComponents.t2 [T2Space X] [CompactSpace X] : T2Space (Connecte rw [ConnectedComponents.quotientMap_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 diff --git a/Mathlib/Topology/Sequences.lean b/Mathlib/Topology/Sequences.lean index 4729f9ccd86bf..2e0e2de87c365 100644 --- a/Mathlib/Topology/Sequences.lean +++ b/Mathlib/Topology/Sequences.lean @@ -94,7 +94,7 @@ theorem isSeqClosed_iff {s : Set X} : IsSeqClosed s ↔ seqClosure s = s := /-- A set is sequentially closed if it is closed. -/ protected theorem IsClosed.isSeqClosed {s : Set X} (hc : IsClosed s) : IsSeqClosed s := - fun _u _x hu hx => hc.mem_of_tendsto hx (eventually_of_forall hu) + fun _u _x hu hx => hc.mem_of_tendsto hx (Eventually.of_forall hu) theorem seqClosure_eq_closure [FrechetUrysohnSpace X] (s : Set X) : seqClosure s = closure s := seqClosure_subset_closure.antisymm <| FrechetUrysohnSpace.closure_subset_seqClosure s @@ -121,7 +121,7 @@ theorem tendsto_nhds_iff_seq_tendsto [FrechetUrysohnSpace X] {f : X → Y} {a : refine ⟨closure (f ⁻¹' s), ⟨mt ?_ hbs, isClosed_closure⟩, fun x => mt fun hx => subset_closure hx⟩ rw [← seqClosure_eq_closure] rintro ⟨u, hus, hu⟩ - exact hsc.mem_of_tendsto (h u hu) (eventually_of_forall hus) + exact hsc.mem_of_tendsto (h u hu) (Eventually.of_forall hus) /-- An alternative construction for `FrechetUrysohnSpace`: if sequential convergence implies convergence, then the space is a Fréchet-Urysohn space. -/ @@ -158,7 +158,7 @@ theorem Inducing.frechetUrysohnSpace [FrechetUrysohnSpace Y] {f : X → Y} (hf : rcases hx with ⟨u, hus, hu⟩ choose v hv hvu using hus refine ⟨v, hv, ?_⟩ - simpa only [hf.tendsto_nhds_iff, (· ∘ ·), hvu] + simpa only [hf.tendsto_nhds_iff, Function.comp_def, hvu] /-- Subtype of a Fréchet-Urysohn space is a Fréchet-Urysohn space. -/ instance Subtype.instFrechetUrysohnSpace [FrechetUrysohnSpace X] {p : X → Prop} : @@ -254,7 +254,7 @@ open FirstCountableTopology protected theorem IsCompact.isSeqCompact {s : Set X} (hs : IsCompact s) : IsSeqCompact s := fun _x x_in => - let ⟨a, a_in, ha⟩ := hs (tendsto_principal.mpr (eventually_of_forall x_in)) + let ⟨a, a_in, ha⟩ := hs (tendsto_principal.mpr (Eventually.of_forall x_in)) ⟨a, a_in, tendsto_subseq ha⟩ theorem IsCompact.tendsto_subseq' {s : Set X} {x : ℕ → X} (hs : IsCompact s) @@ -315,7 +315,7 @@ theorem IsSeqCompact.exists_tendsto_of_frequently_mem (hs : IsSeqCompact s) {u : theorem IsSeqCompact.exists_tendsto (hs : IsSeqCompact s) {u : ℕ → X} (hu : ∀ n, u n ∈ s) (huc : CauchySeq u) : ∃ x ∈ s, Tendsto u atTop (𝓝 x) := - hs.exists_tendsto_of_frequently_mem (frequently_of_forall hu) huc + hs.exists_tendsto_of_frequently_mem (Frequently.of_forall hu) huc /-- A sequentially compact set in a uniform space is totally bounded. -/ protected theorem IsSeqCompact.totallyBounded (h : IsSeqCompact s) : TotallyBounded s := by @@ -328,7 +328,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/Closeds.lean b/Mathlib/Topology/Sets/Closeds.lean index 5953aae8fe8e1..3a3de1ae74dbf 100644 --- a/Mathlib/Topology/Sets/Closeds.lean +++ b/Mathlib/Topology/Sets/Closeds.lean @@ -63,6 +63,9 @@ theorem coe_mk (s : Set α) (h) : (mk s h : Set α) = s := protected def closure (s : Set α) : Closeds α := ⟨closure s, isClosed_closure⟩ +@[simp] +theorem mem_closure {s : Set α} {x : α} : x ∈ Closeds.closure s ↔ x ∈ closure s := .rfl + theorem gc : GaloisConnection Closeds.closure ((↑) : Closeds α → Set α) := fun _ U => ⟨subset_closure.trans, fun h => closure_minimal h U.closed⟩ diff --git a/Mathlib/Topology/Sets/Opens.lean b/Mathlib/Topology/Sets/Opens.lean index fad80ae1e1cf9..cf7ecc4c6353c 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 @@ -75,6 +75,9 @@ instance : SetLike (Opens α) α where instance : CanLift (Set α) (Opens α) (↑) IsOpen := ⟨fun s h => ⟨⟨s, h⟩, rfl⟩⟩ +instance instSecondCountableOpens [SecondCountableTopology α] (U : Opens α) : + SecondCountableTopology U := inferInstanceAs (SecondCountableTopology U.1) + theorem «forall» {p : Opens α → Prop} : (∀ U, p U) ↔ ∀ (U : Set α) (hU : IsOpen U), p ⟨U, hU⟩ := ⟨fun h _ _ => h _, fun h _ => h _ _⟩ @@ -104,6 +107,9 @@ theorem ext {U V : Opens α} (h : (U : Set α) = V) : U = V := theorem coe_inj {U V : Opens α} : (U : Set α) = V ↔ U = V := SetLike.ext'_iff.symm +/-- A version of `Set.inclusion` not requiring definitional abuse -/ +abbrev inclusion {U V : Opens α} (h : U ≤ V) : U → V := Set.inclusion h + protected theorem isOpen (U : Opens α) : IsOpen (U : Set α) := U.is_open' @@ -115,14 +121,18 @@ def Simps.coe (U : Opens α) : Set α := U initialize_simps_projections Opens (carrier → coe) /-- The interior of a set, as an element of `Opens`. -/ -nonrec def interior (s : Set α) : Opens α := +@[simps] +protected def interior (s : Set α) : Opens α := ⟨interior s, isOpen_interior⟩ -theorem gc : GaloisConnection ((↑) : Opens α → Set α) interior := fun U _ => +@[simp] +theorem mem_interior {s : Set α} {x : α} : x ∈ Opens.interior s ↔ x ∈ _root_.interior s := .rfl + +theorem gc : GaloisConnection ((↑) : Opens α → Set α) Opens.interior := fun U _ => ⟨fun h => interior_maximal h U.isOpen, fun h => le_trans h interior_subset⟩ /-- The galois coinsertion between sets and opens. -/ -def gi : GaloisCoinsertion (↑) (@interior α _) where +def gi : GaloisCoinsertion (↑) (@Opens.interior α _) where choice s hs := ⟨s, interior_eq_iff_isOpen.mp <| le_antisymm interior_subset hs⟩ gc := gc u_l_le _ := interior_subset @@ -347,6 +357,9 @@ theorem comap_mono (f : C(α, β)) {s t : Opens β} (h : s ≤ t) : comap f s theorem coe_comap (f : C(α, β)) (U : Opens β) : ↑(comap f U) = f ⁻¹' U := rfl +@[simp] +theorem mem_comap {f : C(α, β)} {U : Opens β} {x : α} : x ∈ comap f U ↔ f x ∈ U := .rfl + protected theorem comap_comp (g : C(β, γ)) (f : C(α, β)) : comap (g.comp f) = (comap f).comp (comap g) := rfl 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/Init.lean b/Mathlib/Topology/Sheaves/Init.lean index 61db5393fa545..fad0482e9171f 100644 --- a/Mathlib/Topology/Sheaves/Init.lean +++ b/Mathlib/Topology/Sheaves/Init.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jujian Zhang -/ +import Mathlib.Init import Aesop /-! diff --git a/Mathlib/Topology/Sheaves/Limits.lean b/Mathlib/Topology/Sheaves/Limits.lean index bd475bdcbd6cf..af880e9d7ae36 100644 --- a/Mathlib/Topology/Sheaves/Limits.lean +++ b/Mathlib/Topology/Sheaves/Limits.lean @@ -1,11 +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.Topology.Sheaves.Sheaf import Mathlib.CategoryTheory.Sites.Limits -import Mathlib.CategoryTheory.Limits.FunctorCategory +import Mathlib.CategoryTheory.Limits.FunctorCategory.Basic /-! # Presheaves in `C` have limits and colimits when `C` does. diff --git a/Mathlib/Topology/Sheaves/LocalPredicate.lean b/Mathlib/Topology/Sheaves/LocalPredicate.lean index 2c3ef5febbef1..c9213520cca76 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 @@ -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/MayerVietoris.lean b/Mathlib/Topology/Sheaves/MayerVietoris.lean new file mode 100644 index 0000000000000..c50c3418dc9ee --- /dev/null +++ b/Mathlib/Topology/Sheaves/MayerVietoris.lean @@ -0,0 +1,69 @@ +/- +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.Sites.MayerVietorisSquare +import Mathlib.CategoryTheory.Sites.Spaces + +/-! +# Mayer-Vietoris squares + +Given two open subsets `U` and `V` of a topological space `T`, +we construct the associated Mayer-Vietoris square: +``` +U ⊓ V ---> U + | | + v v + V ---> U ⊔ V +``` + +-/ + +universe u + +namespace Opens + +open CategoryTheory Limits TopologicalSpace + +variable {T : Type u} [TopologicalSpace T] + +/-- A square consisting of opens `X₂ ⊓ X₃`, `X₂`, `X₃` and `X₂ ⊔ X₃` is +a Mayer-Vietoris square. -/ +@[simps! toSquare] +noncomputable def mayerVietorisSquare' (sq : Square (Opens T)) + (h₄ : sq.X₄ = sq.X₂ ⊔ sq.X₃) (h₁ : sq.X₁ = sq.X₂ ⊓ sq.X₃) : + (Opens.grothendieckTopology T).MayerVietorisSquare := + GrothendieckTopology.MayerVietorisSquare.mk_of_isPullback + (J := (Opens.grothendieckTopology T)) sq + (Square.IsPullback.mk _ (by + refine PullbackCone.IsLimit.mk _ ?_ ?_ ?_ ?_ + · intro s + apply homOfLE + rw [h₁, le_inf_iff] + exact ⟨leOfHom s.fst, leOfHom s.snd⟩ + all_goals intros; apply Subsingleton.elim)) + (fun x hx ↦ by + rw [h₄] at hx + obtain (hx|hx) := hx + · exact ⟨_, _, ⟨Sieve.ofArrows_mk _ _ WalkingPair.left, hx⟩⟩ + · exact ⟨_, _, ⟨Sieve.ofArrows_mk _ _ WalkingPair.right, hx⟩⟩) + +/-- The Mayer-Vietoris square attached to two open subsets +of a topological space. -/ +@[simps!] +noncomputable def mayerVietorisSquare (U V : Opens T): + (Opens.grothendieckTopology T).MayerVietorisSquare := + mayerVietorisSquare' + { X₁ := U ⊓ V + X₂ := U + X₃ := V + X₄ := U ⊔ V + f₁₂ := homOfLE inf_le_left + f₁₃ := homOfLE inf_le_right + f₂₄ := homOfLE le_sup_left + f₃₄ := homOfLE le_sup_right + fac := Subsingleton.elim _ _ } rfl rfl + +end Opens diff --git a/Mathlib/Topology/Sheaves/Operations.lean b/Mathlib/Topology/Sheaves/Operations.lean index c45d513f7dc54..c982c9d8e3618 100644 --- a/Mathlib/Topology/Sheaves/Operations.lean +++ b/Mathlib/Topology/Sheaves/Operations.lean @@ -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 4469bab7e876e..6b2b727509484 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 +/-- push forward of a presheaf -/ +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} (α : ℱ ⟶ 𝒢) @@ -291,7 +291,7 @@ def pullbackInvIsoPushforwardHom {X Y : TopCat.{v}} (H : X ≅ Y) : variable {C} -/-- If `f '' U` is open, then `f⁻¹ℱ U ≅ ℱ (f '' U)`. -/ +/-- If `f '' U` is open, then `f⁻¹ℱ U ≅ ℱ (f '' U)`. -/ def pullbackObjObjOfImageOpen {X Y : TopCat.{v}} (f : X ⟶ Y) (ℱ : Y.Presheaf C) (U : Opens X) (H : IsOpen (f '' SetLike.coe U)) : ((pullback C f).obj ℱ).obj (op U) ≅ ℱ.obj (op ⟨_, H⟩) := by let x : CostructuredArrow (Opens.map f).op (op U) := CostructuredArrow.mk @@ -303,7 +303,7 @@ def pullbackObjObjOfImageOpen {X Y : TopCat.{v}} (f : X ⟶ Y) (ℱ : Y.Presheaf refine (homOfLE ?_).op apply (Set.image_subset f s.pt.hom.unop.le).trans exact Set.image_preimage.l_u_le (SetLike.coe s.pt.left.unop) - · simp [autoParam, eq_iff_true_of_subsingleton] } + · simp [eq_iff_true_of_subsingleton] } exact IsColimit.coconePointUniqueUpToIso ((Opens.map f).op.isPointwiseLeftKanExtensionLanUnit ℱ (op U)) (colimitOfDiagramTerminal hx _) diff --git a/Mathlib/Topology/Sheaves/PresheafOfFunctions.lean b/Mathlib/Topology/Sheaves/PresheafOfFunctions.lean index 24ed94958851d..6049ed866f9d8 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 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 650373c48901f..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 @@ -98,7 +98,7 @@ def IsSheafOpensLeCover : Prop := section -variable {Y : Opens X} (hY : Y = iSup U) +variable {Y : Opens X} -- Porting note: split it out to prevent timeout /-- Given a family of opens `U` and an open `Y` equal to the union of opens in `U`, we may @@ -107,7 +107,7 @@ variable {Y : Opens X} (hY : Y = iSup U) in the sieve. This full subcategory is equivalent to `OpensLeCover U`, the (poset) category of opens contained in some `U i`. -/ @[simps] -def generateEquivalenceOpensLe_functor' : +def generateEquivalenceOpensLe_functor' (hY : Y = iSup U) : (FullSubcategory fun f : Over Y => (Sieve.generate (presieveOfCoveringAux U Y)).arrows f.hom) ⥤ OpensLeCover U := { obj := fun f => @@ -123,7 +123,7 @@ def generateEquivalenceOpensLe_functor' : in the sieve. This full subcategory is equivalent to `OpensLeCover U`, the (poset) category of opens contained in some `U i`. -/ @[simps] -def generateEquivalenceOpensLe_inverse' : +def generateEquivalenceOpensLe_inverse' (hY : Y = iSup U) : OpensLeCover U ⥤ (FullSubcategory fun f : Over Y => (Sieve.generate (presieveOfCoveringAux U Y)).arrows f.hom) where @@ -146,12 +146,12 @@ def generateEquivalenceOpensLe_inverse' : in the sieve. This full subcategory is equivalent to `OpensLeCover U`, the (poset) category of opens contained in some `U i`. -/ @[simps] -def generateEquivalenceOpensLe : +def generateEquivalenceOpensLe (hY : Y = iSup U) : (FullSubcategory fun f : Over Y => (Sieve.generate (presieveOfCoveringAux U Y)).arrows f.hom) ≌ OpensLeCover U where -- Porting note: split it out to prevent timeout - functor := generateEquivalenceOpensLe_functor' _ _ - inverse := generateEquivalenceOpensLe_inverse' _ _ + functor := generateEquivalenceOpensLe_functor' _ hY + inverse := generateEquivalenceOpensLe_inverse' _ hY unitIso := eqToIso <| CategoryTheory.Functor.ext (by rintro ⟨⟨_, _⟩, _⟩; dsimp; congr) (by intros; refine Over.OverMorphism.ext ?_; aesop_cat) @@ -162,7 +162,7 @@ def generateEquivalenceOpensLe : associated to the sieve generated by the presieve associated to `U` with indexing category changed using the above equivalence. -/ @[simps] -def whiskerIsoMapGenerateCocone : +def whiskerIsoMapGenerateCocone (hY : Y = iSup U) : (F.mapCone (opensLeCoverCocone U).op).whisker (generateEquivalenceOpensLe U hY).op.functor ≅ F.mapCone (Sieve.generate (presieveOfCoveringAux U Y)).arrows.cocone.op where hom := @@ -188,7 +188,7 @@ def whiskerIsoMapGenerateCocone : the natural cone associated to `F` and `U` used in the definition of `F.IsSheafOpensLeCover` is a limit cone iff the natural cone associated to `F` and the sieve generated by the presieve associated to `U` is a limit cone. -/ -def isLimitOpensLeEquivGenerate₁ : +def isLimitOpensLeEquivGenerate₁ (hY : Y = iSup U) : IsLimit (F.mapCone (opensLeCoverCocone U).op) ≃ IsLimit (F.mapCone (Sieve.generate (presieveOfCoveringAux U Y)).arrows.cocone.op) := (IsLimit.whiskerEquivalenceEquiv (generateEquivalenceOpensLe U hY).op).trans diff --git a/Mathlib/Topology/Sheaves/SheafCondition/PairwiseIntersections.lean b/Mathlib/Topology/Sheaves/SheafCondition/PairwiseIntersections.lean index 7dcee720fc546..9677da6bdf32e 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 diff --git a/Mathlib/Topology/Sheaves/SheafOfFunctions.lean b/Mathlib/Topology/Sheaves/SheafOfFunctions.lean index e3707c87c39cc..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 @@ -75,7 +75,7 @@ theorem toTypes_isSheaf (T : X → Type u) : (presheafToTypes X T).IsSheaf := -- We verify that the non-dependent version is an immediate consequence: /-- The presheaf of not-necessarily-continuous functions to -a target type `T` satsifies the sheaf condition. +a target type `T` satisfies the sheaf condition. -/ theorem toType_isSheaf (T : Type u) : (presheafToType X T).IsSheaf := toTypes_isSheaf X fun _ => T 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..a1bfb6d86c2ef 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,35 +272,36 @@ 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` -/ @@ -304,9 +312,8 @@ protected def unit : 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 Y := + 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 70176d5a489ac..74df85eb39c03 100644 --- a/Mathlib/Topology/Sheaves/Stalks.lean +++ b/Mathlib/Topology/Sheaves/Stalks.lean @@ -1,12 +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, Justus Springer +Authors: Kim Morrison, Justus Springer -/ import Mathlib.Topology.Category.TopCat.OpenNhds import Mathlib.Topology.Sheaves.Presheaf import Mathlib.Topology.Sheaves.SheafCondition.UniqueGluing -import Mathlib.CategoryTheory.Adjunction.Evaluation import Mathlib.CategoryTheory.Limits.Types import Mathlib.CategoryTheory.Limits.Preserves.Filtered import Mathlib.CategoryTheory.Limits.Final @@ -61,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}} @@ -88,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) @@ -142,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 @@ -216,19 +247,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] @@ -247,20 +278,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, @@ -268,11 +299,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) : @@ -280,7 +311,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 @@ -291,8 +322,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⁻¹ℱ)ₓ`. -/ @@ -331,14 +362,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} @@ -390,8 +419,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)] @@ -400,7 +429,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 @@ -410,7 +439,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} _ @@ -422,13 +451,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] @@ -436,10 +464,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₁ @@ -455,16 +483,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) : @@ -474,7 +502,7 @@ instance stalkFunctor_preserves_mono (x : X) : (app_injective_iff_stalkFunctor_map_injective f.1).mpr (fun c => (ConcreteCategory.mono_iff_injective_of_preservesPullback (f.1.app (op c))).mp - ((NatTrans.mono_iff_mono_app _ f.1).mp + ((NatTrans.mono_iff_mono_app f.1).mp (CategoryTheory.presheaf_mono_of_mono ..) <| op c)) x⟩ @@ -486,9 +514,9 @@ theorem stalk_mono_of_mono {F G : Sheaf C X} (f : F ⟶ G) [Mono f] : theorem mono_of_stalk_mono {F G : Sheaf C X} (f : F ⟶ G) [∀ x, Mono <| (stalkFunctor C x).map f.1] : Mono f := (Sheaf.Hom.mono_iff_presheaf_mono _ _ _).mpr <| - (NatTrans.mono_iff_mono_app _ _).mpr fun U => + (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) : @@ -500,10 +528,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`. @@ -524,36 +555,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) @@ -564,9 +595,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 @@ -598,11 +629,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/Sober.lean b/Mathlib/Topology/Sober.lean index 05385bd2df372..a4717443959a5 100644 --- a/Mathlib/Topology/Sober.lean +++ b/Mathlib/Topology/Sober.lean @@ -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 diff --git a/Mathlib/Topology/Specialization.lean b/Mathlib/Topology/Specialization.lean index 53b1665a0beab..1c7ce45b4bb4b 100644 --- a/Mathlib/Topology/Specialization.lean +++ b/Mathlib/Topology/Specialization.lean @@ -5,7 +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.ContinuousMap.Basic import Mathlib.Topology.Separation import Mathlib.Topology.Order.UpperLowerSetTopology @@ -26,7 +26,7 @@ variable {α β γ : Type*} /-- `toEquiv` is the "identity" function to the `Specialization` of a type. -/ @[match_pattern] def toEquiv : α ≃ Specialization α := Equiv.refl _ -/-- `ofEquiv` is the identity function from the `Specialization` of a type. -/ +/-- `ofEquiv` is the identity function from the `Specialization` of a type. -/ @[match_pattern] def ofEquiv : Specialization α ≃ α := Equiv.refl _ @[simp] lemma toEquiv_symm : (@toEquiv α).symm = ofEquiv := rfl @@ -63,7 +63,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 695abf50017b4..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 @@ -57,9 +57,9 @@ end Unbundled /-- The type of spectral maps from `α` to `β`. -/ structure SpectralMap (α β : Type*) [TopologicalSpace α] [TopologicalSpace β] where - /-- function between topological spaces-/ + /-- function between topological spaces -/ toFun : α → β - /-- proof that `toFun` is a spectral map-/ + /-- proof that `toFun` is a spectral map -/ spectral' : IsSpectralMap toFun section @@ -69,7 +69,7 @@ section You should extend this class when you extend `SpectralMap`. -/ class SpectralMapClass (F α β : Type*) [TopologicalSpace α] [TopologicalSpace β] [FunLike F α β] : Prop where - /-- statement that `F` is a type of spectral maps-/ + /-- statement that `F` is a type of spectral maps -/ map_spectral (f : F) : IsSpectralMap f end diff --git a/Mathlib/Topology/StoneCech.lean b/Mathlib/Topology/StoneCech.lean index 629e0e1ffa49c..3beed85e1b698 100644 --- a/Mathlib/Topology/StoneCech.lean +++ b/Mathlib/Topology/StoneCech.lean @@ -13,7 +13,7 @@ Construction of the Stone-Čech compactification using ultrafilters. For any topological space `α`, we build a compact Hausdorff space `StoneCech α` and a continuous map `stoneCechUnit : α → StoneCech α` which is minimal in the sense of the following universal property: for any compact Hausdorff space `β` and every map `f : α → β` such that -`hf : Continuous f`, there is a unique map `stoneCechExtend hf : StoneCech α → β` such that +`hf : Continuous f`, there is a unique map `stoneCechExtend hf : StoneCech α → β` such that `stoneCechExtend_extends : stoneCechExtend hf ∘ stoneCechUnit = f`. Continuity of this extension is asserted by `continuous_stoneCechExtend` and uniqueness by `stoneCech_hom_ext`. @@ -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 @@ -221,7 +224,7 @@ section PreStoneCech variable (α : Type u) [TopologicalSpace α] -/-- Auxilliary construction towards the Stone-Čech compactification of a topological space. +/-- Auxiliary construction towards the Stone-Čech compactification of a topological space. It should not be used after the Stone-Čech compactification is constructed. -/ def PreStoneCech : Type u := Quot fun F G : Ultrafilter α ↦ ∃ x, (F : Filter α) ≤ 𝓝 x ∧ (G : Filter α) ≤ 𝓝 x diff --git a/Mathlib/Topology/Support.lean b/Mathlib/Topology/Support.lean index fbccca79fa36f..c0f19ee3e63a7 100644 --- a/Mathlib/Topology/Support.lean +++ b/Mathlib/Topology/Support.lean @@ -4,6 +4,7 @@ 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 @@ -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 @@ -212,15 +213,8 @@ theorem comp₂_left (hf : HasCompactMulSupport f) (hf₂ : HasCompactMulSupport f₂) (hm : m 1 1 = 1) : HasCompactMulSupport fun x => m (f x) (f₂ x) := by rw [hasCompactMulSupport_iff_eventuallyEq] at hf hf₂ ⊢ - #adaptation_note /-- `nightly-2024-03-11` - If we *either* (1) remove the type annotations on the - binders in the following `fun` or (2) revert `simp only` to `simp_rw`, `to_additive` fails - because an `OfNat.ofNat 1` is not replaced with `0`. Notably, as of this nightly, what used to - look like `OfNat.ofNat (nat_lit 1) x` in the proof term now looks like - `OfNat.ofNat (OfNat.ofNat (α := ℕ) (nat_lit 1)) x`, and this seems to trip up `to_additive`. - -/ - filter_upwards [hf, hf₂] using fun x (hx : f x = (1 : α → β) x) (hx₂ : f₂ x = (1 : α → γ) x) => by - simp only [hx, hx₂, Pi.one_apply, hm] + filter_upwards [hf, hf₂] with x hx hx₂ + simp_rw [hx, hx₂, Pi.one_apply, hm] @[to_additive] lemma isCompact_preimage [TopologicalSpace β] @@ -300,18 +294,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 ⊢ @@ -322,7 +331,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 ⊢ @@ -336,7 +345,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 ⊢ @@ -350,7 +359,7 @@ end MulZeroClass section OrderedAddGroup -variable {α β : Type*} [TopologicalSpace α] [AddGroup β] [Lattice β] +variable [TopologicalSpace α] [AddGroup β] [Lattice β] [CovariantClass β β (· + ·) (· ≤ ·)] protected theorem HasCompactSupport.abs {f : α → β} (hf : HasCompactSupport f) : diff --git a/Mathlib/Topology/TietzeExtension.lean b/Mathlib/Topology/TietzeExtension.lean index 55ec301b782ca..b1e175559e9fd 100644 --- a/Mathlib/Topology/TietzeExtension.lean +++ b/Mathlib/Topology/TietzeExtension.lean @@ -227,9 +227,10 @@ theorem exists_extension_norm_eq_of_closedEmbedding' (f : X →ᵇ ℝ) (e : C(X Function.iterate_succ_apply' _ _ _ have hgf : ∀ n, dist ((g n).compContinuous e) f ≤ (2 / 3) ^ n * ‖f‖ := by intro n - induction' n with n ihn - · simp [g0] - · rw [g_succ n, add_compContinuous, ← dist_sub_right, add_sub_cancel_left, pow_succ', mul_assoc] + induction n with + | zero => simp [g0] + | succ n ihn => + rw [g_succ n, add_compContinuous, ← dist_sub_right, add_sub_cancel_left, pow_succ', mul_assoc] refine (hF_dist _).trans (mul_le_mul_of_nonneg_left ?_ (by norm_num1)) rwa [← dist_eq_norm'] have hg_dist : ∀ n, dist (g n) (g (n + 1)) ≤ 1 / 3 * ‖f‖ * (2 / 3) ^ n := by @@ -305,7 +306,7 @@ theorem exists_extension_forall_mem_Icc_of_closedEmbedding (f : X →ᵇ ℝ) {a 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₂`. -/ +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) : ∃ g : Y →ᵇ ℝ, (∀ y, ∃ x₁ x₂, g y ∈ Icc (f x₁) (f x₂)) ∧ g ∘ e = f := by @@ -339,7 +340,7 @@ theorem exists_extension_forall_exists_le_ge_of_closedEmbedding [Nonempty X] (f · exact ⟨g, fun y => ⟨x, hg_mem _⟩, hgf⟩ /- Otherwise, `g ⁻¹' {a}` is disjoint with `range e ∪ g ⁻¹' (Ici c)`, hence there exists a function `dg : Y → ℝ` such that `dg ∘ e = 0`, `dg y = 0` whenever `c ≤ g y`, `dg y = c - a` - whenever `g y = a`, and `0 ≤ dg y ≤ c - a` for all `y`. -/ + whenever `g y = a`, and `0 ≤ dg y ≤ c - a` for all `y`. -/ have hd : Disjoint (range e ∪ g ⁻¹' Ici c) (g ⁻¹' {a}) := by refine disjoint_union_left.2 ⟨?_, Disjoint.preimage _ ?_⟩ · rw [Set.disjoint_left] diff --git a/Mathlib/Topology/UniformSpace/AbsoluteValue.lean b/Mathlib/Topology/UniformSpace/AbsoluteValue.lean index fb21530f3f80a..55efcadaf7133 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 diff --git a/Mathlib/Topology/UniformSpace/AbstractCompletion.lean b/Mathlib/Topology/UniformSpace/AbstractCompletion.lean index 9f7d1efc35a9c..ce9024be56637 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.inducing, 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 @@ -187,7 +189,7 @@ theorem map_unique {f : α → β} {g : hatα → hatβ} (hg : UniformContinuous pkg.funext (pkg.continuous_map _ _) hg.continuous <| by intro a change pkg.extend (ι' ∘ f) _ = _ - simp_rw [(· ∘ ·), h, ← comp_apply (f := g)] + simp_rw [Function.comp_def, h, ← comp_apply (f := g)] rw [pkg.extend_coe (hg.comp pkg.uniformContinuous_coe)] @[simp] @@ -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 2be2900a38f6e..351606b63c56c 100644 --- a/Mathlib/Topology/UniformSpace/Ascoli.lean +++ b/Mathlib/Topology/UniformSpace/Ascoli.lean @@ -20,14 +20,14 @@ 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 `IsUniformInducing`: `Equicontinuous.isUniformInducing_uniformFun_iff_pi` - in terms of `Inducing`: `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 `IsUniformInducing`: `EquicontinuousOn.isUniformInducing_uniformOnFun_iff_pi'` - in terms of `Inducing`: `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. @@ -39,7 +39,7 @@ a family of compact subsets of `X`, and `α` is a uniform space. embeddings instead of subspaces with the subspace topology. This is done because, in practice, one would rarely work with `X →ᵤ[𝔖] α` directly, so we need to provide API for bringing back the statements to various other types, such as `C(X, Y)` or `E →L[𝕜] F`. To counteract this, all - statements (as well as most proofs!) are documented quite thouroughly. + statements (as well as most proofs!) are documented quite thoroughly. * A lot of statements assume `∀ K ∈ 𝔖, EquicontinuousOn F K` instead of the more natural `EquicontinuousOn F (⋃₀ 𝔖)`. This is in order to keep the most generality, as the first statement @@ -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 = @@ -89,7 +88,7 @@ theorem Equicontinuous.comap_uniformFun_eq [CompactSpace X] (F_eqcont : Equicont refine le_antisymm (UniformSpace.comap_mono UniformFun.uniformContinuous_toFun) ?_ -- A bit of rewriting to get a nice intermediate statement. change comap _ _ ≤ comap _ _ - simp_rw [Pi.uniformity, Filter.comap_iInf, comap_comap, Function.comp] + simp_rw [Pi.uniformity, Filter.comap_iInf, comap_comap, Function.comp_def] refine ((UniformFun.hasBasis_uniformity X α).comap (Prod.map F F)).ge_iff.mpr ?_ -- Core of the proof: we need to show that, for any entourage `U` in `α`, -- the set `𝐓(U) := {(i,j) : ι × ι | ∀ x : X, (F i x, F j x) ∈ U}` belongs to the filter @@ -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 `ι`. @@ -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) @@ -220,7 +223,7 @@ theorem EquicontinuousOn.comap_uniformOnFun_eq {𝔖 : Set (Set X)} (𝔖_compac have H1 : (UniformOnFun.uniformSpace X α 𝔖).comap F = ⨅ (K ∈ 𝔖), (UniformFun.uniformSpace _ _).comap (K.restrict ∘ F) := by simp_rw [UniformOnFun.uniformSpace, UniformSpace.comap_iInf, ← UniformSpace.comap_comap, - UniformFun.ofFun, Equiv.coe_fn_mk, UniformOnFun.toFun, UniformOnFun.ofFun, Function.comp, + UniformFun.ofFun, Equiv.coe_fn_mk, UniformOnFun.toFun, UniformOnFun.ofFun, Function.comp_def, UniformFun, Equiv.coe_fn_symm_mk] -- Now, note that a similar fact is true for the uniform structure on `X → α` induced by -- the map `(⋃₀ 𝔖).restrict : (X → α) → ((⋃₀ 𝔖) → α)`: it is equal to the one induced by @@ -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 @@ -379,7 +390,7 @@ theorem EquicontinuousOn.isClosed_range_pi_of_uniformOnFun' mapClusterPt_iff_ultrafilter, range_comp, Subtype.coe_injective.surjective_comp_right.forall, ← restrict_eq, ← EquicontinuousOn.tendsto_uniformOnFun_iff_pi' 𝔖_compact F_eqcont] exact fun f ⟨u, _, hu⟩ ↦ mem_image_of_mem _ <| H.mem_of_tendsto hu <| - eventually_of_forall mem_range_self + Eventually.of_forall mem_range_self /-- Let `X` be a topological space, `𝔖` a covering of `X` by compact subsets, and `α` a uniform space. An equicontinuous subset of `X → α` is closed in the topology of uniform @@ -495,7 +506,8 @@ theorem ArzelaAscoli.isCompact_of_equicontinuous 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 ContinuousMap.isUniformEmbedding_toUniformOnFunIsCompact.inducing.comp + inducing_subtype_val · 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 37b930b9377e6..caab9ab1db8cb 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 α] @@ -564,16 +562,16 @@ theorem comp_comp_symm_mem_uniformity_sets {s : Set (α × α)} (hs : s ∈ 𝓤 ### Balls in uniform spaces -/ +namespace UniformSpace + /-- The ball around `(x : β)` with respect to `(V : Set (β × β))`. Intended to be used for `V ∈ 𝓤 β`, but this is not needed for the definition. Recovers the -notions of metric space ball when `V = {p | dist p.1 p.2 < r }`. -/ -def UniformSpace.ball (x : β) (V : Set (β × β)) : Set β := - Prod.mk x ⁻¹' V +notions of metric space ball when `V = {p | dist p.1 p.2 < r }`. -/ +def ball (x : β) (V : Set (β × β)) : Set β := Prod.mk x ⁻¹' V open UniformSpace (ball) -theorem UniformSpace.mem_ball_self (x : α) {V : Set (α × α)} (hV : V ∈ 𝓤 α) : x ∈ ball x V := - refl_mem_uniformity hV +lemma mem_ball_self (x : α) {V : Set (α × α)} : V ∈ 𝓤 α → x ∈ ball x V := refl_mem_uniformity /-- The triangle inequality for `UniformSpace.ball` -/ theorem mem_ball_comp {V W : Set (β × β)} {x y z} (h : y ∈ ball x V) (h' : z ∈ ball y W) : @@ -612,11 +610,10 @@ theorem mem_comp_of_mem_ball {V W : Set (β × β)} {x y z : β} (hV : Symmetric rw [mem_ball_symmetry hV] at hx exact ⟨z, hx, hy⟩ -theorem UniformSpace.isOpen_ball (x : α) {V : Set (α × α)} (hV : IsOpen V) : IsOpen (ball x V) := +lemma isOpen_ball (x : α) {V : Set (α × α)} (hV : IsOpen V) : IsOpen (ball x V) := hV.preimage <| continuous_const.prod_mk continuous_id -theorem UniformSpace.isClosed_ball (x : α) {V : Set (α × α)} (hV : IsClosed V) : - IsClosed (ball x V) := +lemma isClosed_ball (x : α) {V : Set (α × α)} (hV : IsClosed V) : IsClosed (ball x V) := hV.preimage <| continuous_const.prod_mk continuous_id theorem mem_comp_comp {V W M : Set (β × β)} (hW' : SymmetricRel W) {p : β × β} : @@ -629,10 +626,14 @@ theorem mem_comp_comp {V W M : Set (β × β)} (hW' : SymmetricRel W) {p : β × rw [mem_ball_symmetry hW'] at z_in exact ⟨z, ⟨w, w_in, hwz⟩, z_in⟩ +end UniformSpace + /-! ### Neighborhoods in uniform spaces -/ +open UniformSpace + theorem mem_nhds_uniformity_iff_right {x : α} {s : Set α} : s ∈ 𝓝 x ↔ { p : α × α | p.1 = x → p.2 ∈ s } ∈ 𝓤 α := by simp only [nhds_eq_comap_uniformity, mem_comap_prod_mk] @@ -740,12 +741,12 @@ theorem tendsto_left_nhds_uniformity {a : α} : Tendsto (fun a' => (a, a')) ( theorem lift_nhds_left {x : α} {g : Set α → Filter β} (hg : Monotone g) : (𝓝 x).lift g = (𝓤 α).lift fun s : Set (α × α) => g (ball x s) := by rw [nhds_eq_comap_uniformity, comap_lift_eq2 hg] - simp_rw [ball, Function.comp] + simp_rw [ball, Function.comp_def] theorem lift_nhds_right {x : α} {g : Set α → Filter β} (hg : Monotone g) : (𝓝 x).lift g = (𝓤 α).lift fun s : Set (α × α) => g { y | (y, x) ∈ s } := by rw [nhds_eq_comap_uniformity', comap_lift_eq2 hg] - simp_rw [Function.comp, preimage] + simp_rw [Function.comp_def, preimage] theorem nhds_nhds_eq_uniformity_uniformity_prod {a b : α} : 𝓝 a ×ˢ 𝓝 b = (𝓤 α).lift fun s : Set (α × α) => @@ -891,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 => @@ -1110,12 +1110,17 @@ abbrev UniformSpace.comap (f : α → β) (u : UniformSpace β) : UniformSpace (comap_mono u.comp) toTopologicalSpace := u.toTopologicalSpace.induced f nhds_eq_comap_uniformity x := by - simp only [nhds_induced, nhds_eq_comap_uniformity, comap_comap, Function.comp] + simp only [nhds_induced, nhds_eq_comap_uniformity, comap_comap, Function.comp_def] 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 @@ -1358,6 +1363,8 @@ end MulOpposite section Prod +open UniformSpace + /- a similar product space is possible on the function space (uniformity of pointwise convergence), but we want to have the uniformity of uniform convergence on function spaces -/ instance instUniformSpaceProd [u₁ : UniformSpace α] [u₂ : UniformSpace β] : UniformSpace (α × β) := @@ -1383,7 +1390,7 @@ theorem uniformity_prod_eq_comap_prod [UniformSpace α] [UniformSpace β] : 𝓤 (α × β) = comap (fun p : (α × β) × α × β => ((p.1.1, p.2.1), (p.1.2, p.2.2))) (𝓤 α ×ˢ 𝓤 β) := by dsimp [SProd.sprod] - rw [uniformity_prod, Filter.prod, comap_inf, comap_comap, comap_comap]; rfl + rw [uniformity_prod, Filter.prod, Filter.comap_inf, Filter.comap_comap, Filter.comap_comap]; rfl theorem uniformity_prod_eq_prod [UniformSpace α] [UniformSpace β] : 𝓤 (α × β) = map (fun p : (α × α) × β × β => ((p.1.1, p.2.1), (p.1.2, p.2.2))) (𝓤 α ×ˢ 𝓤 β) := by @@ -1396,10 +1403,35 @@ theorem mem_uniformity_of_uniformContinuous_invariant [UniformSpace α] [Uniform rcases mem_prod_iff.1 (mem_map.1 <| hf hs) with ⟨u, hu, v, hv, huvt⟩ exact ⟨u, hu, fun a b c hab => @huvt ((_, _), (_, _)) ⟨hab, refl_mem_uniformity hv⟩⟩ -theorem mem_uniform_prod [t₁ : UniformSpace α] [t₂ : UniformSpace β] {a : Set (α × α)} - {b : Set (β × β)} (ha : a ∈ 𝓤 α) (hb : b ∈ 𝓤 β) : - { p : (α × β) × α × β | (p.1.1, p.2.1) ∈ a ∧ (p.1.2, p.2.2) ∈ b } ∈ 𝓤 (α × β) := by - rw [uniformity_prod]; exact inter_mem_inf (preimage_mem_comap ha) (preimage_mem_comap hb) +/-- An entourage of the diagonal in `α` and an entourage in `β` yield an entourage in `α × β` +once we permute coordinates.-/ +def entourageProd (u : Set (α × α)) (v : Set (β × β)) : Set ((α × β) × α × β) := + {((a₁, b₁),(a₂, b₂)) | (a₁, a₂) ∈ u ∧ (b₁, b₂) ∈ v} + +theorem mem_entourageProd {u : Set (α × α)} {v : Set (β × β)} {p : (α × β) × α × β} : + p ∈ entourageProd u v ↔ (p.1.1, p.2.1) ∈ u ∧ (p.1.2, p.2.2) ∈ v := Iff.rfl + +theorem entourageProd_mem_uniformity [t₁ : UniformSpace α] [t₂ : UniformSpace β] {u : Set (α × α)} + {v : Set (β × β)} (hu : u ∈ 𝓤 α) (hv : v ∈ 𝓤 β) : + entourageProd u v ∈ 𝓤 (α × β) := by + rw [uniformity_prod]; exact inter_mem_inf (preimage_mem_comap hu) (preimage_mem_comap hv) + +theorem ball_entourageProd (u : Set (α × α)) (v : Set (β × β)) (x : α × β) : + ball x (entourageProd u v) = ball x.1 u ×ˢ ball x.2 v := by + ext p; simp only [ball, entourageProd, Set.mem_setOf_eq, Set.mem_prod, Set.mem_preimage] + +theorem Filter.HasBasis.uniformity_prod {ιa ιb : Type*} [UniformSpace α] [UniformSpace β] + {pa : ιa → Prop} {pb : ιb → Prop} {sa : ιa → Set (α × α)} {sb : ιb → Set (β × β)} + (ha : (𝓤 α).HasBasis pa sa) (hb : (𝓤 β).HasBasis pb sb) : + (𝓤 (α × β)).HasBasis (fun i : ιa × ιb ↦ pa i.1 ∧ pb i.2) + (fun i ↦ entourageProd (sa i.1) (sb i.2)) := + (ha.comap _).inf (hb.comap _) + +theorem entourageProd_subset [UniformSpace α] [UniformSpace β] + {s : Set ((α × β) × α × β)} (h : s ∈ 𝓤 (α × β)) : + ∃ u ∈ 𝓤 α, ∃ v ∈ 𝓤 β, entourageProd u v ⊆ s := by + rcases (((𝓤 α).basis_sets.uniformity_prod (𝓤 β).basis_sets).mem_iff' s).1 h with ⟨w, hw⟩ + use w.1, hw.1.1, w.2, hw.1.2, hw.2 theorem tendsto_prod_uniformity_fst [UniformSpace α] [UniformSpace β] : Tendsto (fun p : (α × β) × α × β => (p.1.1, p.2.1)) (𝓤 (α × β)) (𝓤 α) := @@ -1432,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 := @@ -1451,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 -/ @@ -1464,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 -/ @@ -1477,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 @@ -1513,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 @@ -1705,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 β} : @@ -1766,3 +1800,5 @@ theorem Filter.Tendsto.congr_uniformity {α β} [UniformSpace β] {f g : α → theorem Uniform.tendsto_congr {α β} [UniformSpace β] {f g : α → β} {l : Filter α} {b : β} (hfg : Tendsto (fun x => (f x, g x)) l (𝓤 β)) : Tendsto f l (𝓝 b) ↔ Tendsto g l (𝓝 b) := ⟨fun h => h.congr_uniformity hfg, fun h => h.congr_uniformity hfg.uniformity_symm⟩ + +set_option linter.style.longFile 1900 diff --git a/Mathlib/Topology/UniformSpace/Cauchy.lean b/Mathlib/Topology/UniformSpace/Cauchy.lean index 6ade1b68d70e8..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. @@ -207,7 +208,7 @@ theorem Function.Bijective.cauchySeq_comp_iff {f : ℕ → ℕ} (hf : Bijective CauchySeq (u ∘ f) ↔ CauchySeq u := by refine ⟨fun H => ?_, fun H => H.comp_injective hf.injective⟩ lift f to ℕ ≃ ℕ using hf - simpa only [(· ∘ ·), f.apply_symm_apply] using H.comp_injective f.symm.injective + simpa only [Function.comp_def, f.apply_symm_apply] using H.comp_injective f.symm.injective theorem CauchySeq.subseq_subseq_mem {V : ℕ → Set (α × α)} (hV : ∀ n, V n ∈ 𝓤 α) {u : ℕ → α} (hu : CauchySeq u) {f g : ℕ → ℕ} (hf : Tendsto f atTop atTop) (hg : Tendsto g atTop atTop) : @@ -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 ∧ @@ -263,7 +264,7 @@ theorem Filter.Tendsto.subseq_mem_entourage {V : ℕ → Set (α × α)} (hV : theorem tendsto_nhds_of_cauchySeq_of_subseq [Preorder β] {u : β → α} (hu : CauchySeq u) {ι : Type*} {f : ι → β} {p : Filter ι} [NeBot p] (hf : Tendsto f p atTop) {a : α} (ha : Tendsto (u ∘ f) p (𝓝 a)) : Tendsto u atTop (𝓝 a) := - le_nhds_of_cauchy_adhp hu (mapClusterPt_of_comp hf ha) + le_nhds_of_cauchy_adhp hu (ha.mapClusterPt.of_comp hf) /-- Any shift of a Cauchy sequence is also a Cauchy sequence. -/ theorem cauchySeq_shift {u : ℕ → α} (k : ℕ) : CauchySeq (fun n ↦ u (n + k)) ↔ CauchySeq u := by @@ -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 : β → α} @@ -589,7 +590,7 @@ theorem totallyBounded_iff_filter {s : Set α} : have hb : HasAntitoneBasis f fun t : Finset α ↦ s \ ⋃ y ∈ t, { x | (x, y) ∈ d } := .iInf_principal fun _ _ ↦ diff_subset_diff_right ∘ biUnion_subset_biUnion_left have : Filter.NeBot f := hb.1.neBot_iff.2 fun _ ↦ - nonempty_diff.2 <| hd_cover _ (Finset.finite_toSet _) + diff_nonempty.2 <| hd_cover _ (Finset.finite_toSet _) have : f ≤ 𝓟 s := iInf_le_of_le ∅ (by simp) refine ⟨f, ‹_›, ‹_›, fun c hcf hc => ?_⟩ rcases mem_prod_same_iff.1 (hc.2 hd) with ⟨m, hm, hmd⟩ @@ -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 6c6f0ab1644d7..175d8d75ed946 100644 --- a/Mathlib/Topology/UniformSpace/Compact.lean +++ b/Mathlib/Topology/UniformSpace/Compact.lean @@ -134,14 +134,14 @@ def uniformSpaceOfCompactT2 [TopologicalSpace γ] [CompactSpace γ] [T2Space γ] -- So we have a contradiction exact hU₁₂.le_bot ⟨uw_in.2, wv_in.1⟩ nhds_eq_comap_uniformity x := by - simp_rw [nhdsSet_diagonal, comap_iSup, nhds_prod_eq, comap_prod, (· ∘ ·), comap_id'] + simp_rw [nhdsSet_diagonal, comap_iSup, nhds_prod_eq, comap_prod, Function.comp_def, comap_id'] rw [iSup_split_single _ x, comap_const_of_mem fun V => mem_of_mem_nhds] suffices ∀ y ≠ x, comap (fun _ : γ ↦ x) (𝓝 y) ⊓ 𝓝 y ≤ 𝓝 x by simpa intro y hxy simp [comap_const_of_not_mem (compl_singleton_mem_nhds hxy) (not_not_intro rfl)] /-! -### Heine-Cantor theorem +### Heine-Cantor theorem -/ @@ -151,7 +151,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 5014105f7a6b4..f13aaeff613af 100644 --- a/Mathlib/Topology/UniformSpace/CompactConvergence.lean +++ b/Mathlib/Topology/UniformSpace/CompactConvergence.lean @@ -151,6 +151,10 @@ def toUniformOnFunIsCompact (f : C(α, β)) : α →ᵤ[{K | IsCompact K}] β := theorem toUniformOnFun_toFun (f : C(α, β)) : UniformOnFun.toFun _ f.toUniformOnFunIsCompact = f := rfl +theorem range_toUniformOnFunIsCompact : + range (toUniformOnFunIsCompact) = {f : UniformOnFun α β {K | IsCompact K} | Continuous f} := + Set.ext fun f ↦ ⟨fun g ↦ g.choose_spec ▸ g.choose.2, fun hf ↦ ⟨⟨f, hf⟩, rfl⟩⟩ + open UniformSpace in /-- Uniform space structure on `C(α, β)`. @@ -159,7 +163,7 @@ which defines topology of uniform convergence on compact sets. We use `ContinuousMap.tendsto_iff_forall_compact_tendstoUniformlyOn` to show that the induced topology agrees with the compact-open topology and replace the topology with `compactOpen` to avoid non-defeq diamonds, -see Note [forgetful inheritance]. -/ +see Note [forgetful inheritance]. -/ instance compactConvergenceUniformSpace : UniformSpace C(α, β) := .replaceTopology (.comap toUniformOnFunIsCompact inferInstance) <| by refine TopologicalSpace.ext_nhds fun f ↦ eq_of_forall_le_iff fun l ↦ ?_ @@ -167,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` @@ -180,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 @@ -256,27 +263,33 @@ 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 -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 +@[deprecated (since := "2024-10-05")] +alias uniformInducing_comp := isUniformInducing_comp -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 +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 + +@[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)`. -/ @@ -330,7 +343,7 @@ theorem uniformSpace_eq_inf_precomp_of_cover {δ₁ δ₂ : Type*} [TopologicalS have h_preimage₂ : MapsTo (φ₂ ⁻¹' ·) 𝔖 𝔗₂ := fun K ↦ h_proper₂.isCompact_preimage have h_cover' : ∀ S ∈ 𝔖, S ⊆ range φ₁ ∪ range φ₂ := fun S _ ↦ h_cover ▸ subset_univ _ -- ... and we just pull it back. - simp_rw [compactConvergenceUniformSpace, replaceTopology_eq, inferInstanceAs, inferInstance, + simp_rw [compactConvergenceUniformSpace, replaceTopology_eq, UniformOnFun.uniformSpace_eq_inf_precomp_of_cover _ _ _ _ _ h_image₁ h_image₂ h_preimage₁ h_preimage₂ h_cover', UniformSpace.comap_inf, ← UniformSpace.comap_comap] @@ -351,9 +364,36 @@ theorem uniformSpace_eq_iInf_precomp_of_cover {δ : ι → Type*} [∀ i, Topolo inter_eq_right.mp ?_⟩ simp_rw [iUnion₂_inter, mem_setOf, iUnion_nonempty_self, ← iUnion_inter, h_cover, univ_inter] -- ... and we just pull it back. - simp_rw [compactConvergenceUniformSpace, replaceTopology_eq, inferInstanceAs, inferInstance, + simp_rw [compactConvergenceUniformSpace, replaceTopology_eq, UniformOnFun.uniformSpace_eq_iInf_precomp_of_cover _ _ _ h_image h_preimage h_cover', UniformSpace.comap_iInf, ← UniformSpace.comap_comap] rfl +section CompleteSpace + +variable [CompleteSpace β] + +/-- If the topology on `α` is generated by its restrictions to compact sets, then the space of +continuous maps `C(α, β)` is complete (wrt the compact convergence uniformity). + +Sufficient conditions on `α` to satisfy this condition are (weak) local compactness (see +`ContinuousMap.instCompleteSpaceOfWeaklyLocallyCompactSpace`) and sequential compactness (see +`ContinuousMap.instCompleteSpaceOfSequentialSpace`). -/ +lemma completeSpace_of_restrictGenTopology (h : RestrictGenTopology {K : Set α | IsCompact K}) : + CompleteSpace C(α, β) := by + rw [completeSpace_iff_isComplete_range + isUniformEmbedding_toUniformOnFunIsCompact.isUniformInducing, + range_toUniformOnFunIsCompact, ← completeSpace_coe_iff_isComplete] + exact (UniformOnFun.isClosed_setOf_continuous h).completeSpace_coe + +instance instCompleteSpaceOfWeaklyLocallyCompactSpace [WeaklyLocallyCompactSpace α] : + CompleteSpace C(α, β) := + completeSpace_of_restrictGenTopology RestrictGenTopology.isCompact_of_weaklyLocallyCompact + +instance instCompleteSpaceOfSequentialSpace [SequentialSpace α] : + CompleteSpace C(α, β) := + completeSpace_of_restrictGenTopology RestrictGenTopology.isCompact_of_seq + +end CompleteSpace + end ContinuousMap diff --git a/Mathlib/Topology/UniformSpace/CompareReals.lean b/Mathlib/Topology/UniformSpace/CompareReals.lean index 709fc27902447..c443d0a470a42 100644 --- a/Mathlib/Topology/UniformSpace/CompareReals.lean +++ b/Mathlib/Topology/UniformSpace/CompareReals.lean @@ -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..7444f5a467be3 100644 --- a/Mathlib/Topology/UniformSpace/CompleteSeparated.lean +++ b/Mathlib/Topology/UniformSpace/CompleteSeparated.lean @@ -27,20 +27,23 @@ 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) : +theorem IsUniformEmbedding.toClosedEmbedding [UniformSpace α] [UniformSpace β] [CompleteSpace α] + [T0Space β] {f : α → β} (hf : IsUniformEmbedding f) : ClosedEmbedding f := - ⟨hf.embedding, hf.toUniformInducing.isComplete_range.isClosed⟩ + ⟨hf.embedding, hf.isUniformInducing.isComplete_range.isClosed⟩ -namespace DenseInducing +@[deprecated (since := "2024-10-01")] +alias UniformEmbedding.toClosedEmbedding := IsUniformEmbedding.toClosedEmbedding + +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 6e6085fcbee0d..4d1365e733ea3 100644 --- a/Mathlib/Topology/UniformSpace/Completion.lean +++ b/Mathlib/Topology/UniformSpace/Completion.lean @@ -80,7 +80,7 @@ private theorem symm_gen : map Prod.swap ((𝓤 α).lift' gen) ≤ (𝓤 α).lif { p : CauchyFilter α × CauchyFilter α | s ∈ (p.2.val ×ˢ p.1.val : Filter (α × α)) } have h₁ : map Prod.swap ((𝓤 α).lift' gen) = (𝓤 α).lift' f := by delta gen - simp [map_lift'_eq, monotone_setOf, Filter.monotone_mem, Function.comp, + simp [map_lift'_eq, monotone_setOf, Filter.monotone_mem, Function.comp_def, image_swap_eq_preimage_swap] have h₂ : (𝓤 α).lift' f ≤ (𝓤 α).lift' gen := uniformity_lift_le_swap @@ -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,7 +208,7 @@ 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 => @@ -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 α).inducing 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 d047acb2e03e0..807c30865e06d 100644 --- a/Mathlib/Topology/UniformSpace/Equicontinuity.lean +++ b/Mathlib/Topology/UniformSpace/Equicontinuity.lean @@ -209,12 +209,12 @@ lemma uniformEquicontinuous_restrict_iff (F : ι → β → α) {S : Set β} : @[simp] lemma equicontinuousAt_empty [h : IsEmpty ι] (F : ι → X → α) (x₀ : X) : EquicontinuousAt F x₀ := - fun _ _ ↦ eventually_of_forall (fun _ ↦ h.elim) + fun _ _ ↦ Eventually.of_forall (fun _ ↦ h.elim) @[simp] lemma equicontinuousWithinAt_empty [h : IsEmpty ι] (F : ι → X → α) (S : Set X) (x₀ : X) : EquicontinuousWithinAt F S x₀ := - fun _ _ ↦ eventually_of_forall (fun _ ↦ h.elim) + fun _ _ ↦ Eventually.of_forall (fun _ ↦ h.elim) @[simp] lemma equicontinuous_empty [IsEmpty ι] (F : ι → X → α) : @@ -229,12 +229,12 @@ lemma equicontinuousOn_empty [IsEmpty ι] (F : ι → X → α) (S : Set X) : @[simp] lemma uniformEquicontinuous_empty [h : IsEmpty ι] (F : ι → β → α) : UniformEquicontinuous F := - fun _ _ ↦ eventually_of_forall (fun _ ↦ h.elim) + fun _ _ ↦ Eventually.of_forall (fun _ ↦ h.elim) @[simp] lemma uniformEquicontinuousOn_empty [h : IsEmpty ι] (F : ι → β → α) (S : Set β) : UniformEquicontinuousOn F S := - fun _ _ ↦ eventually_of_forall (fun _ ↦ h.elim) + fun _ _ ↦ Eventually.of_forall (fun _ ↦ h.elim) /-! ### Finite index type @@ -479,7 +479,7 @@ open UniformFun /-- A family `𝓕 : ι → X → α` is equicontinuous at `x₀` iff the function `swap 𝓕 : X → ι → α` is continuous at `x₀` *when `ι → α` is equipped with the topology of uniform convergence*. This is -very useful for developping the equicontinuity API, but it should not be used directly for other +very useful for developing the equicontinuity API, but it should not be used directly for other purposes. -/ theorem equicontinuousAt_iff_continuousAt {F : ι → X → α} {x₀ : X} : EquicontinuousAt F x₀ ↔ ContinuousAt (ofFun ∘ Function.swap F : X → ι →ᵤ α) x₀ := by @@ -489,7 +489,7 @@ theorem equicontinuousAt_iff_continuousAt {F : ι → X → α} {x₀ : X} : /-- A family `𝓕 : ι → X → α` is equicontinuous at `x₀` within `S` iff the function `swap 𝓕 : X → ι → α` is continuous at `x₀` within `S` *when `ι → α` is equipped with the topology of uniform convergence*. This is very useful for -developping the equicontinuity API, but it should not be used directly for other purposes. -/ +developing the equicontinuity API, but it should not be used directly for other purposes. -/ theorem equicontinuousWithinAt_iff_continuousWithinAt {F : ι → X → α} {S : Set X} {x₀ : X} : EquicontinuousWithinAt F S x₀ ↔ ContinuousWithinAt (ofFun ∘ Function.swap F : X → ι →ᵤ α) S x₀ := by @@ -498,7 +498,7 @@ theorem equicontinuousWithinAt_iff_continuousWithinAt {F : ι → X → α} {S : /-- A family `𝓕 : ι → X → α` is equicontinuous iff the function `swap 𝓕 : X → ι → α` is continuous *when `ι → α` is equipped with the topology of uniform convergence*. This is -very useful for developping the equicontinuity API, but it should not be used directly for other +very useful for developing the equicontinuity API, but it should not be used directly for other purposes. -/ theorem equicontinuous_iff_continuous {F : ι → X → α} : Equicontinuous F ↔ Continuous (ofFun ∘ Function.swap F : X → ι →ᵤ α) := by @@ -506,7 +506,7 @@ theorem equicontinuous_iff_continuous {F : ι → X → α} : /-- A family `𝓕 : ι → X → α` is equicontinuous on `S` iff the function `swap 𝓕 : X → ι → α` is continuous on `S` *when `ι → α` is equipped with the topology of uniform convergence*. This is -very useful for developping the equicontinuity API, but it should not be used directly for other +very useful for developing the equicontinuity API, but it should not be used directly for other purposes. -/ theorem equicontinuousOn_iff_continuousOn {F : ι → X → α} {S : Set X} : EquicontinuousOn F S ↔ ContinuousOn (ofFun ∘ Function.swap F : X → ι →ᵤ α) S := by @@ -514,7 +514,7 @@ theorem equicontinuousOn_iff_continuousOn {F : ι → X → α} {S : Set X} : /-- A family `𝓕 : ι → β → α` is uniformly equicontinuous iff the function `swap 𝓕 : β → ι → α` is uniformly continuous *when `ι → α` is equipped with the uniform structure of uniform convergence*. -This is very useful for developping the equicontinuity API, but it should not be used directly +This is very useful for developing the equicontinuity API, but it should not be used directly for other purposes. -/ theorem uniformEquicontinuous_iff_uniformContinuous {F : ι → β → α} : UniformEquicontinuous F ↔ UniformContinuous (ofFun ∘ Function.swap F : β → ι →ᵤ α) := by @@ -524,7 +524,7 @@ theorem uniformEquicontinuous_iff_uniformContinuous {F : ι → β → α} : /-- A family `𝓕 : ι → β → α` is uniformly equicontinuous on `S` iff the function `swap 𝓕 : β → ι → α` is uniformly continuous on `S` *when `ι → α` is equipped with the uniform structure of uniform convergence*. This is very useful -for developping the equicontinuity API, but it should not be used directly for other purposes. -/ +for developing the equicontinuity API, but it should not be used directly for other purposes. -/ theorem uniformEquicontinuousOn_iff_uniformContinuousOn {F : ι → β → α} {S : Set β} : UniformEquicontinuousOn F S ↔ UniformContinuousOn (ofFun ∘ Function.swap F : β → ι →ᵤ α) S := by rw [UniformContinuousOn, (UniformFun.hasBasis_uniformity ι α).tendsto_right_iff] @@ -704,59 +704,77 @@ 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).inducing 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).inducing 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 whith a map +this will be applied to `DFunLike` types, we state it for any topological space with a map to `X → α` satisfying the right continuity conditions. See also `Set.EquicontinuousWithinAt.closure` for a more familiar (but weaker) statement. @@ -778,7 +796,7 @@ theorem EquicontinuousWithinAt.closure' {A : Set Y} {u : Y → X → α} {S : Se /-- If a set of functions is equicontinuous at some `x₀`, the same is true for its closure in *any* topology for which evaluation at any point is continuous. Since this will be applied to -`DFunLike` types, we state it for any topological space whith a map to `X → α` satisfying the right +`DFunLike` types, we state it for any topological space with a map to `X → α` satisfying the right continuity conditions. See also `Set.EquicontinuousAt.closure` for a more familiar statement. -/ theorem EquicontinuousAt.closure' {A : Set Y} {u : Y → X → α} {x₀ : X} (hA : EquicontinuousAt (u ∘ (↑) : A → X → α) x₀) (hu : Continuous u) : @@ -802,7 +820,7 @@ protected theorem Set.EquicontinuousWithinAt.closure {A : Set (X → α)} {S : S /-- If a set of functions is equicontinuous, the same is true for its closure in *any* topology for which evaluation at any point is continuous. Since this will be applied to -`DFunLike` types, we state it for any topological space whith a map to `X → α` satisfying the right +`DFunLike` types, we state it for any topological space with a map to `X → α` satisfying the right continuity conditions. See also `Set.Equicontinuous.closure` for a more familiar statement. -/ theorem Equicontinuous.closure' {A : Set Y} {u : Y → X → α} (hA : Equicontinuous (u ∘ (↑) : A → X → α)) (hu : Continuous u) : @@ -810,7 +828,7 @@ theorem Equicontinuous.closure' {A : Set Y} {u : Y → X → α} /-- If a set of functions is equicontinuous on a set `S`, the same is true for its closure in *any* topology for which evaluation at any `x ∈ S` is continuous. Since this will be applied to -`DFunLike` types, we state it for any topological space whith a map to `X → α` satisfying the right +`DFunLike` types, we state it for any topological space with a map to `X → α` satisfying the right continuity conditions. See also `Set.EquicontinuousOn.closure` for a more familiar (but weaker) statement. -/ theorem EquicontinuousOn.closure' {A : Set Y} {u : Y → X → α} {S : Set X} @@ -832,7 +850,7 @@ protected theorem Set.EquicontinuousOn.closure {A : Set <| X → α} {S : Set X} /-- If a set of functions is uniformly equicontinuous on a set `S`, the same is true for its closure in *any* topology for which evaluation at any `x ∈ S` i continuous. Since this will be -applied to `DFunLike` types, we state it for any topological space whith a map to `β → α` satisfying +applied to `DFunLike` types, we state it for any topological space with a map to `β → α` satisfying the right continuity conditions. See also `Set.UniformEquicontinuousOn.closure` for a more familiar (but weaker) statement. -/ theorem UniformEquicontinuousOn.closure' {A : Set Y} {u : Y → β → α} {S : Set β} @@ -850,7 +868,7 @@ theorem UniformEquicontinuousOn.closure' {A : Set Y} {u : Y → β → α} {S : /-- If a set of functions is uniformly equicontinuous, the same is true for its closure in *any* topology for which evaluation at any point is continuous. Since this will be applied to -`DFunLike` types, we state it for any topological space whith a map to `β → α` satisfying the right +`DFunLike` types, we state it for any topological space with a map to `β → α` satisfying the right continuity conditions. See also `Set.UniformEquicontinuous.closure` for a more familiar statement. -/ theorem UniformEquicontinuous.closure' {A : Set Y} {u : Y → β → α} @@ -880,13 +898,13 @@ theorem Filter.Tendsto.continuousAt_of_equicontinuousAt {l : Filter ι} [l.NeBot {f : X → α} {x₀ : X} (h₁ : Tendsto F l (𝓝 f)) (h₂ : EquicontinuousAt F x₀) : ContinuousAt f x₀ := (equicontinuousAt_iff_range.mp h₂).closure.continuousAt - ⟨f, mem_closure_of_tendsto h₁ <| eventually_of_forall mem_range_self⟩ + ⟨f, mem_closure_of_tendsto h₁ <| Eventually.of_forall mem_range_self⟩ theorem Filter.Tendsto.uniformContinuous_of_uniformEquicontinuous {l : Filter ι} [l.NeBot] {F : ι → β → α} {f : β → α} (h₁ : Tendsto F l (𝓝 f)) (h₂ : UniformEquicontinuous F) : UniformContinuous f := (uniformEquicontinuous_iff_range.mp h₂).closure.uniformContinuous - ⟨f, mem_closure_of_tendsto h₁ <| eventually_of_forall mem_range_self⟩ + ⟨f, mem_closure_of_tendsto h₁ <| Eventually.of_forall mem_range_self⟩ ``` Unfortunately, the proofs get painful when dealing with the relative case as one needs to change @@ -905,7 +923,7 @@ theorem Filter.Tendsto.continuousWithinAt_of_equicontinuousWithinAt {l : Filter rcases mem_uniformity_isClosed hV with ⟨W, hW, hWclosed, hWV⟩ filter_upwards [h₃ W hW, eventually_mem_nhdsWithin] with x hx hxS using hVU <| ball_mono hWV (f x₀) <| hWclosed.mem_of_tendsto (h₂.prod_mk_nhds (h₁ x hxS)) <| - eventually_of_forall hx + Eventually.of_forall hx /-- If `𝓕 : ι → X → α` tends to `f : X → α` *pointwise* along some nontrivial filter, and if the family `𝓕` is equicontinuous at some `x₀ : X`, then the limit is continuous at `x₀`. -/ @@ -940,7 +958,7 @@ theorem Filter.Tendsto.uniformContinuousOn_of_uniformEquicontinuousOn {l : Filte filter_upwards [h₂ V hV, mem_inf_of_right (mem_principal_self _)] rintro ⟨x, y⟩ hxy ⟨hxS, hyS⟩ exact hVU <| hVclosed.mem_of_tendsto ((h₁ x hxS).prod_mk_nhds (h₁ y hyS)) <| - eventually_of_forall hxy + Eventually.of_forall hxy /-- If `𝓕 : ι → β → α` tends to `f : β → α` *pointwise* along some nontrivial filter, and if the family `𝓕` is uniformly equicontinuous, then the limit is uniformly continuous. -/ diff --git a/Mathlib/Topology/UniformSpace/Equiv.lean b/Mathlib/Topology/UniformSpace/Equiv.lean index d4be20cb620ad..6fb396f7b0004 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 := @@ -196,28 +196,35 @@ theorem image_preimage (h : α ≃ᵤ β) (s : Set β) : h '' (h ⁻¹' s) = s : 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/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 6c6f45b6814fc..783300913d8d4 100644 --- a/Mathlib/Topology/UniformSpace/Pi.lean +++ b/Mathlib/Topology/UniformSpace/Pi.lean @@ -42,7 +42,7 @@ instance [Countable ι] [∀ i, IsCountablyGenerated (𝓤 (α i))] : theorem uniformContinuous_pi {β : Type*} [UniformSpace β] {f : β → ∀ i, α i} : UniformContinuous f ↔ ∀ i, UniformContinuous fun x => f x i := by -- Porting note: required `Function.comp` to close - simp only [UniformContinuous, Pi.uniformity, tendsto_iInf, tendsto_comap_iff, Function.comp] + simp only [UniformContinuous, Pi.uniformity, tendsto_iInf, tendsto_comap_iff, Function.comp_def] variable (α) @@ -69,7 +69,7 @@ theorem Pi.uniformContinuous_postcomp {α : Type*} [UniformSpace α] {g : α → lemma Pi.uniformSpace_comap_precomp' (φ : ι' → ι) : UniformSpace.comap (fun g i' ↦ g (φ i')) (Pi.uniformSpace (fun i' ↦ α (φ i'))) = ⨅ i', UniformSpace.comap (eval (φ i')) (U (φ i')) := by - simp [Pi.uniformSpace_eq, UniformSpace.comap_iInf, ← UniformSpace.comap_comap, comp] + simp [Pi.uniformSpace_eq, UniformSpace.comap_iInf, ← UniformSpace.comap_comap, comp_def] lemma Pi.uniformSpace_comap_precomp (φ : ι' → ι) : UniformSpace.comap (· ∘ φ) (Pi.uniformSpace (fun _ ↦ β)) = @@ -122,9 +122,9 @@ 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, - Filter.comap_comap, (· ∘ ·), const, Prod.eta, comap_id'] + 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, setOf_forall] diff --git a/Mathlib/Topology/UniformSpace/Separation.lean b/Mathlib/Topology/UniformSpace/Separation.lean index 9d11da63e1ac6..f50de8d5deebd 100644 --- a/Mathlib/Topology/UniformSpace/Separation.lean +++ b/Mathlib/Topology/UniformSpace/Separation.lean @@ -218,7 +218,7 @@ instance instUniformSpace : UniformSpace (SeparationQuotient α) where exact @hUt (x, z) ⟨y', this.mem_open (UniformSpace.isOpen_ball _ hUo) hxyU, hyzU⟩ nhds_eq_comap_uniformity := surjective_mk.forall.2 fun x ↦ comap_injective surjective_mk <| by conv_lhs => rw [comap_mk_nhds_mk, nhds_eq_comap_uniformity, ← comap_map_mk_uniformity] - simp only [Filter.comap_comap, Function.comp, Prod.map_apply] + simp only [Filter.comap_comap, Function.comp_def, Prod.map_apply] theorem uniformity_eq : 𝓤 (SeparationQuotient α) = (𝓤 α).map (Prod.map mk mk) := rfl @@ -285,6 +285,6 @@ theorem map_id : map (@id α) = id := map_unique uniformContinuous_id rfl theorem map_comp {f : α → β} {g : β → γ} (hf : UniformContinuous f) (hg : UniformContinuous g) : map g ∘ map f = map (g ∘ f) := - (map_unique (hg.comp hf) <| by simp only [Function.comp, map_mk, hf, hg]).symm + (map_unique (hg.comp hf) <| by simp only [Function.comp_def, map_mk, hf, hg]).symm end SeparationQuotient diff --git a/Mathlib/Topology/UniformSpace/UniformConvergence.lean b/Mathlib/Topology/UniformSpace/UniformConvergence.lean index a5dbd62933646..3d5593d33b3b1 100644 --- a/Mathlib/Topology/UniformSpace/UniformConvergence.lean +++ b/Mathlib/Topology/UniformSpace/UniformConvergence.lean @@ -62,7 +62,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 +196,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 +389,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 +420,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 +489,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 +531,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 @@ -653,14 +686,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..00cd2deafccea 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 @@ -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 @@ -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 b674ec1daf22e..d70f7fb955c8f 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,102 +28,165 @@ 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, - Function.comp, Function.comp] + 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] + +@[deprecated (since := "2024-10-05")] +alias UniformInducing.uniformInducing_comp_iff := IsUniformInducing.isUniformInducing_comp_iff -theorem UniformInducing.uniformContinuousOn_iff {f : α → β} {g : β → γ} {S : Set α} - (hg : UniformInducing g) : +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.inducing {f : α → β} (h : IsUniformInducing f) : Inducing f := by obtain rfl := h.comap_uniformSpace exact inducing_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) := - ⟨by simp [(· ∘ ·), uniformity_prod, ← h₁.1, ← h₂.1, comap_inf, comap_comap]⟩ +@[deprecated (since := "2024-10-05")] +alias UniformInducing.inducing := IsUniformInducing.inducing + +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 := +@[deprecated (since := "2024-10-05")] +alias UniformInducing.prod := IsUniformInducing.prod + +lemma IsUniformInducing.isDenseInducing (h : IsUniformInducing f) (hd : DenseRange f) : + IsDenseInducing f := { dense := hd induced := h.inducing.induced } -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 +@[deprecated (since := "2024-10-05")] +alias UniformInducing.injective := IsUniformInducing.injective + /-! ### Uniform embeddings -/ @@ -130,70 +194,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 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] +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 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]⟩ +@[deprecated (since := "2024-10-01")] +alias UniformEmbedding.of_comp_iff := IsUniformEmbedding.of_comp_iff -theorem uniformEmbedding_inl : UniformEmbedding (Sum.inl : α → α ⊕ β) := - uniformEmbedding_iff'.2 ⟨Sum.inl_injective, uniformContinuous_inl, fun s hs => +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]⟩ + +@[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 := +@[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.inducing.injective⟩ -theorem uniformEmbedding_iff_uniformInducing [T0Space α] {f : α → β} : - UniformEmbedding f ↔ UniformInducing f := - ⟨UniformEmbedding.toUniformInducing, UniformInducing.uniformEmbedding⟩ +@[deprecated (since := "2024-10-05")] +alias UniformInducing.isUniformEmbedding := IsUniformInducing.isUniformEmbedding + +@[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,88 +322,148 @@ 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⟩ + +@[deprecated (since := "2024-10-01")] +alias uniformEmbedding_of_spaced_out := isUniformEmbedding_of_spaced_out -protected theorem UniformEmbedding.embedding {f : α → β} (h : UniformEmbedding f) : Embedding f := - { toInducing := h.toUniformInducing.inducing +protected lemma IsUniformEmbedding.embedding {f : α → β} (h : IsUniformEmbedding f) : Embedding f := + { toInducing := h.isUniformInducing.inducing inj := h.inj } -theorem UniformEmbedding.denseEmbedding {f : α → β} (h : UniformEmbedding f) (hd : DenseRange f) : - DenseEmbedding f := +@[deprecated (since := "2024-10-01")] +alias UniformEmbedding.embedding := IsUniformEmbedding.embedding + +theorem IsUniformEmbedding.isDenseEmbedding {f : α → β} (h : IsUniformEmbedding f) + (hd : DenseRange f) : IsDenseEmbedding f := { h.embedding with dense := hd } +@[deprecated (since := "2024-10-01")] +alias UniformEmbedding.isDenseEmbedding := IsUniformEmbedding.isDenseEmbedding + +@[deprecated (since := "2024-09-30")] +alias IsUniformEmbedding.denseEmbedding := IsUniformEmbedding.isDenseEmbedding + theorem closedEmbedding_of_spaced_out {α} [TopologicalSpace α] [DiscreteTopology α] [T0Space β] {f : α → β} {s : Set (β × β)} (hs : s ∈ 𝓤 β) (hf : Pairwise fun x y => (f x, f y) ∉ s) : ClosedEmbedding 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).embedding 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 ∈ 𝓤 α) : +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 rwa [← he₁.comap_uniformity, (uniformity_hasBasis_open_symmetric.comap _).mem_iff] at hs rcases he₂.dense.mem_nhds (UniformSpace.ball_mem_nhds b hU) with ⟨a, ha⟩ - refine ⟨a, mem_of_superset ?_ (closure_mono <| image_subset _ <| ball_mono hs a)⟩ + refine ⟨a, mem_of_superset ?_ (closure_mono <| image_subset _ <| UniformSpace.ball_mono hs a)⟩ have ho : IsOpen (UniformSpace.ball (e a) U) := UniformSpace.isOpen_ball (e a) hUo - refine mem_of_superset (ho.mem_nhds <| (mem_ball_symmetry hsymm).2 ha) fun y hy => ?_ + refine mem_of_superset (ho.mem_nhds <| (UniformSpace.mem_ball_symmetry hsymm).2 ha) fun y hy => ?_ refine mem_closure_iff_nhds.2 fun V hV => ?_ 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, (· ∘ ·), 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] +/-- 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,12 +471,14 @@ 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 } @@ -350,7 +524,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,21 +533,24 @@ 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. -/ @@ -381,23 +558,26 @@ def Embedding.comapUniformSpace {α β} [TopologicalSpace α] [u : UniformSpace (h : Embedding f) : UniformSpace α := (u.comap f).replaceTopology h.induced -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 : Embedding 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 +585,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]⟩ 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 +612,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 +637,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 1a8a9c4a3a525..55c6405dda1b6 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⟩ @@ -64,11 +64,10 @@ instance : BoundedOrder I := Set.Icc.boundedOrder zero_le_one lemma univ_eq_Icc : (univ : Set I) = Icc (0 : I) (1 : I) := Icc_bot_top.symm -theorem coe_ne_zero {x : I} : (x : ℝ) ≠ 0 ↔ x ≠ 0 := - not_iff_not.mpr coe_eq_zero - -theorem coe_ne_one {x : I} : (x : ℝ) ≠ 1 ↔ x ≠ 1 := - not_iff_not.mpr coe_eq_one +@[norm_cast] theorem coe_ne_zero {x : I} : (x : ℝ) ≠ 0 ↔ x ≠ 0 := coe_eq_zero.not +@[norm_cast] theorem coe_ne_one {x : I} : (x : ℝ) ≠ 1 ↔ x ≠ 1 := coe_eq_one.not +@[simp, norm_cast] theorem coe_pos {x : I} : (0 : ℝ) < x ↔ 0 < x := Iff.rfl +@[simp, norm_cast] theorem coe_lt_one {x : I} : (x : ℝ) < 1 ↔ x < 1 := Iff.rfl instance : Nonempty I := ⟨0⟩ @@ -76,7 +75,6 @@ instance : Nonempty I := instance : Mul I := ⟨fun x y => ⟨x * y, mul_mem x.2 y.2⟩⟩ --- todo: we could set up a `LinearOrderedCommMonoidWithZero I` instance theorem mul_le_left {x y : I} : x * y ≤ x := Subtype.coe_le_coe.mp <| mul_le_of_le_one_right x.2.1 y.2.2 @@ -127,9 +125,40 @@ theorem strictAnti_symm : StrictAnti σ := fun _ _ h ↦ sub_lt_sub_left (α := @[deprecated (since := "2024-02-27")] alias involutive_symm := symm_involutive @[deprecated (since := "2024-02-27")] alias bijective_symm := symm_bijective +@[simp] +theorem symm_inj {i j : I} : σ i = σ j ↔ i = j := symm_bijective.injective.eq_iff + theorem half_le_symm_iff (t : I) : 1 / 2 ≤ (σ t : ℝ) ↔ (t : ℝ) ≤ 1 / 2 := by rw [coe_symm_eq, le_sub_iff_add_le, add_comm, ← le_sub_iff_add_le, sub_half] +@[simp] +lemma symm_eq_one {i : I} : σ i = 1 ↔ i = 0 := by + rw [← symm_zero, symm_inj] + +@[simp] +lemma symm_eq_zero {i : I} : σ i = 0 ↔ i = 1 := by + rw [← symm_one, symm_inj] + +@[simp] +theorem symm_le_symm {i j : I} : σ i ≤ σ j ↔ j ≤ i := by + simp only [symm, Subtype.mk_le_mk, sub_le_sub_iff, add_le_add_iff_left, Subtype.coe_le_coe] + +theorem le_symm_comm {i j : I} : i ≤ σ j ↔ j ≤ σ i := by + rw [← symm_le_symm, symm_symm] + +theorem symm_le_comm {i j : I} : σ i ≤ j ↔ σ j ≤ i := by + rw [← symm_le_symm, symm_symm] + +@[simp] +theorem symm_lt_symm {i j : I} : σ i < σ j ↔ j < i := by + simp only [symm, Subtype.mk_lt_mk, sub_lt_sub_iff_left, Subtype.coe_lt_coe] + +theorem lt_symm_comm {i j : I} : i < σ j ↔ j < σ i := by + rw [← symm_lt_symm, symm_symm] + +theorem symm_lt_comm {i j : I} : σ i < j ↔ σ j < i := by + rw [← symm_lt_symm, symm_symm] + instance : ConnectedSpace I := Subtype.connectedSpace ⟨nonempty_Icc.mpr zero_le_one, isPreconnected_Icc⟩ @@ -157,18 +186,39 @@ theorem nonneg' {t : I} : 0 ≤ t := theorem le_one' {t : I} : t ≤ 1 := t.2.2 +protected lemma pos_iff_ne_zero {x : I} : 0 < x ↔ x ≠ 0 := bot_lt_iff_ne_bot + +protected lemma lt_one_iff_ne_one {x : I} : x < 1 ↔ x ≠ 1 := lt_top_iff_ne_top + +lemma eq_one_or_eq_zero_of_le_mul {i j : I} (h : i ≤ j * i) : i = 0 ∨ j = 1 := by + contrapose! h + rw [← unitInterval.lt_one_iff_ne_one, ← coe_lt_one, ← unitInterval.pos_iff_ne_zero, + ← coe_pos] at h + rw [← Subtype.coe_lt_coe, coe_mul] + simpa using mul_lt_mul_of_pos_right h.right h.left + instance : Nontrivial I := ⟨⟨1, 0, (one_ne_zero <| congrArg Subtype.val ·)⟩⟩ theorem mul_pos_mem_iff {a t : ℝ} (ha : 0 < a) : a * t ∈ I ↔ t ∈ Set.Icc (0 : ℝ) (1 / a) := by constructor <;> rintro ⟨h₁, h₂⟩ <;> constructor · exact nonneg_of_mul_nonneg_right h₁ ha - · rwa [le_div_iff ha, mul_comm] + · rwa [le_div_iff₀ ha, mul_comm] · exact mul_nonneg ha.le h₁ - · rwa [le_div_iff ha, mul_comm] at h₂ + · rwa [le_div_iff₀ ha, mul_comm] at h₂ 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 +instance : LinearOrderedCommMonoidWithZero I where + zero_mul i := zero_mul i + mul_zero i := mul_zero i + zero_le_one := nonneg' + mul_le_mul_left i j h_ij k := by + simp only [← Subtype.coe_le_coe, coe_mul] + apply mul_le_mul le_rfl ?_ (nonneg i) (nonneg k) + simp [h_ij] + __ := inferInstanceAs (LinearOrder I) + end unitInterval section partition @@ -209,10 +259,15 @@ lemma monotone_addNSMul (hδ : 0 ≤ δ) : Monotone (addNSMul h δ) := lemma abs_sub_addNSMul_le (hδ : 0 ≤ δ) {t : Icc a b} (n : ℕ) (ht : t ∈ Icc (addNSMul h δ n) (addNSMul h δ (n+1))) : (|t - addNSMul h δ n| : α) ≤ δ := - (abs_eq_self.2 <| sub_nonneg.2 ht.1).trans_le <| (sub_le_sub_right (by exact ht.2) _).trans <| - (le_abs_self _).trans <| (abs_projIcc_sub_projIcc h).trans <| by - rw [add_sub_add_comm, sub_self, zero_add, succ_nsmul', add_sub_cancel_right] - exact (abs_eq_self.mpr hδ).le + calc + (|t - addNSMul h δ n| : α) = t - addNSMul h δ n := abs_eq_self.2 <| sub_nonneg.2 ht.1 + _ ≤ projIcc a b h (a + (n+1) • δ) - addNSMul h δ n := + sub_le_sub_right (b := (↑(projIcc a b h (a + (n + 1) • δ)))) (by exact ht.2) _ + _ ≤ (|projIcc a b h (a + (n+1) • δ) - addNSMul h δ n| : α) := le_abs_self _ + _ ≤ |a + (n+1) • δ - (a + n • δ)| := abs_projIcc_sub_projIcc h + _ ≤ δ := by + rw [add_sub_add_comm, sub_self, zero_add, succ_nsmul', add_sub_cancel_right] + exact (abs_eq_self.mpr hδ).le end Set.Icc 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 d6e4967be156a..705eb5ca08358 100644 --- a/Mathlib/Topology/UrysohnsLemma.lean +++ b/Mathlib/Topology/UrysohnsLemma.lean @@ -5,7 +5,7 @@ Authors: Yury Kudryashov -/ import Mathlib.Analysis.Normed.Affine.AddTorsor import Mathlib.LinearAlgebra.AffineSpace.Ordered -import Mathlib.Topology.ContinuousFunction.Basic +import Mathlib.Topology.ContinuousMap.Basic import Mathlib.Topology.GDelta import Mathlib.Analysis.NormedSpace.FunctionSeries import Mathlib.Analysis.SpecificLimits.Basic @@ -92,7 +92,7 @@ open neighborhood `U`, together with the assumption that `C` satisfies the prope latter assumption will make it possible to prove simultaneously both versions of Urysohn's lemma, in normal spaces (with `P` always true) and in locally compact spaces (with `P = IsCompact`). We put also in the structure the assumption that, for any such pair, one may find an intermediate -pair inbetween satisfying `P`, to avoid carrying it around in the argument. -/ +pair in between satisfying `P`, to avoid carrying it around in the argument. -/ structure CU {X : Type*} [TopologicalSpace X] (P : Set X → Prop) where /-- The inner set in the inductive construction towards Urysohn's lemma -/ protected C : Set X @@ -149,30 +149,35 @@ noncomputable def approx : ℕ → CU P → X → ℝ | n + 1, c, x => midpoint ℝ (approx n c.left x) (approx n c.right x) theorem approx_of_mem_C (c : CU P) (n : ℕ) {x : X} (hx : x ∈ c.C) : c.approx n x = 0 := by - induction' n with n ihn generalizing c - · exact indicator_of_not_mem (fun (hU : x ∈ c.Uᶜ) => hU <| c.subset hx) _ - · simp only [approx] + induction n generalizing c with + | zero => exact indicator_of_not_mem (fun (hU : x ∈ c.Uᶜ) => hU <| c.subset hx) _ + | succ n ihn => + simp only [approx] rw [ihn, ihn, midpoint_self] exacts [c.subset_right_C hx, hx] theorem approx_of_nmem_U (c : CU P) (n : ℕ) {x : X} (hx : x ∉ c.U) : c.approx n x = 1 := by - induction' n with n ihn generalizing c - · rw [← mem_compl_iff] at hx + induction n generalizing c with + | zero => + rw [← mem_compl_iff] at hx exact indicator_of_mem hx _ - · simp only [approx] + | succ n ihn => + simp only [approx] rw [ihn, ihn, midpoint_self] exacts [hx, fun hU => hx <| c.left_U_subset hU] theorem approx_nonneg (c : CU P) (n : ℕ) (x : X) : 0 ≤ c.approx n x := by - induction' n with n ihn generalizing c - · exact indicator_nonneg (fun _ _ => zero_le_one) _ - · simp only [approx, midpoint_eq_smul_add, invOf_eq_inv] + induction n generalizing c with + | zero => exact indicator_nonneg (fun _ _ => zero_le_one) _ + | succ n ihn => + simp only [approx, midpoint_eq_smul_add, invOf_eq_inv] refine mul_nonneg (inv_nonneg.2 zero_le_two) (add_nonneg ?_ ?_) <;> apply ihn theorem approx_le_one (c : CU P) (n : ℕ) (x : X) : c.approx n x ≤ 1 := by - induction' n with n ihn generalizing c - · exact indicator_apply_le' (fun _ => le_rfl) fun _ => zero_le_one - · simp only [approx, midpoint_eq_smul_add, invOf_eq_inv, smul_eq_mul, ← div_eq_inv_mul] + induction n generalizing c with + | zero => exact indicator_apply_le' (fun _ => le_rfl) fun _ => zero_le_one + | succ n ihn => + simp only [approx, midpoint_eq_smul_add, invOf_eq_inv, smul_eq_mul, ← div_eq_inv_mul] have := add_le_add (ihn (left c)) (ihn (right c)) norm_num at this exact Iff.mpr (div_le_one zero_lt_two) this @@ -225,6 +230,9 @@ theorem tendsto_approx_atTop (c : CU P) (x : X) : theorem lim_of_mem_C (c : CU P) (x : X) (h : x ∈ c.C) : c.lim x = 0 := by simp only [CU.lim, approx_of_mem_C, h, ciSup_const] +theorem disjoint_C_support_lim (c : CU P) : Disjoint c.C (Function.support c.lim) := + Function.disjoint_support_iff.mpr (fun x hx => lim_of_mem_C c x hx) + theorem lim_of_nmem_U (c : CU P) (x : X) (h : x ∉ c.U) : c.lim x = 1 := by simp only [CU.lim, approx_of_nmem_U c _ h, ciSup_const] @@ -426,6 +434,54 @@ theorem exists_continuous_one_zero_of_isCompact_of_isGδ [RegularSpace X] [Local · apply le_trans _ hu.le exact tsum_le_tsum (fun n ↦ I n x) (S x) u_sum +/-- A variation of Urysohn's lemma. In a `T2Space X`, for a closed set `t` and a relatively +compact open set `s` such that `t ⊆ s`, there is a continuous function `f` supported in `s`, +`f x = 1` on `t` and `0 ≤ f x ≤ 1`. -/ +lemma exists_tsupport_one_of_isOpen_isClosed [T2Space X] {s t : Set X} + (hs : IsOpen s) (hscp : IsCompact (closure s)) (ht : IsClosed t) (hst : t ⊆ s) : ∃ f : C(X, ℝ), + tsupport f ⊆ s ∧ EqOn f 1 t ∧ ∀ x, f x ∈ Icc (0 : ℝ) 1 := by +-- separate `sᶜ` and `t` by `u` and `v`. + rw [← compl_compl s] at hscp + obtain ⟨u, v, huIsOpen, hvIsOpen, hscompl_subset_u, ht_subset_v, hDjsjointuv⟩ := + SeparatedNhds.of_isClosed_isCompact_closure_compl_isClosed (isClosed_compl_iff.mpr hs) + hscp ht (HasSubset.Subset.disjoint_compl_left hst) + rw [← subset_compl_iff_disjoint_right] at hDjsjointuv + have huvc : closure u ⊆ vᶜ := closure_minimal hDjsjointuv hvIsOpen.isClosed_compl +-- although `sᶜ` is not compact, `closure s` is compact and we can apply +-- `SeparatedNhds.of_isClosed_isCompact_closure_compl_isClosed`. To apply the condition +-- recursively, we need to make sure that `sᶜ ⊆ C`. + let P : Set X → Prop := fun C => sᶜ ⊆ C + set c : Urysohns.CU P := + { C := closure u + U := tᶜ + P_C := hscompl_subset_u.trans subset_closure + closed_C := isClosed_closure + open_U := ht.isOpen_compl + subset := subset_compl_comm.mp + (Subset.trans ht_subset_v (subset_compl_comm.mp huvc)) + hP := by + intro c u0 cIsClosed Pc u0IsOpen csubu0 + obtain ⟨u1, hu1⟩ := SeparatedNhds.of_isClosed_isCompact_closure_compl_isClosed cIsClosed + (IsCompact.of_isClosed_subset hscp isClosed_closure + (closure_mono (compl_subset_compl.mpr Pc))) + (isClosed_compl_iff.mpr u0IsOpen) (HasSubset.Subset.disjoint_compl_right csubu0) + simp_rw [← subset_compl_iff_disjoint_right, compl_subset_comm (s := u0)] at hu1 + obtain ⟨v1, hu1, hv1, hcu1, hv1u, hu1v1⟩ := hu1 + refine ⟨u1, hu1, hcu1, ?_, (Pc.trans hcu1).trans subset_closure⟩ + exact closure_minimal hu1v1 hv1.isClosed_compl |>.trans hv1u } +-- `c.lim = 0` on `closure u` and `c.lim = 1` on `t`, so that `tsupport c.lim ⊆ s`. + use ⟨c.lim, c.continuous_lim⟩ + simp only [ContinuousMap.coe_mk] + refine ⟨?_, ?_, Urysohns.CU.lim_mem_Icc c⟩ + · apply Subset.trans _ (compl_subset_comm.mp hscompl_subset_u) + rw [← IsClosed.closure_eq (isClosed_compl_iff.mpr huIsOpen)] + apply closure_mono + exact Disjoint.subset_compl_right (disjoint_of_subset_right subset_closure + (Disjoint.symm (Urysohns.CU.disjoint_C_support_lim c))) + · intro x hx + apply Urysohns.CU.lim_of_nmem_U + exact not_mem_compl_iff.mpr hx + theorem exists_continuous_nonneg_pos [RegularSpace X] [LocallyCompactSpace X] (x : X) : ∃ f : C(X, ℝ), HasCompactSupport f ∧ 0 ≤ (f : X → ℝ) ∧ f x ≠ 0 := by rcases exists_compact_mem_nhds x with ⟨k, hk, k_mem⟩ diff --git a/Mathlib/Topology/VectorBundle/Basic.lean b/Mathlib/Topology/VectorBundle/Basic.lean index f7f9be5e65667..cf55b20054f31 100644 --- a/Mathlib/Topology/VectorBundle/Basic.lean +++ b/Mathlib/Topology/VectorBundle/Basic.lean @@ -538,7 +538,7 @@ theorem coordChange_linear_comp (i j k : ι) : @[nolint unusedArguments] -- Porting note(#5171): was `nolint has_nonempty_instance` def Index := ι -/-- The base space of a vector bundle core, as a convenience function for dot notation-/ +/-- The base space of a vector bundle core, as a convenience function for dot notation -/ @[nolint unusedArguments, reducible] def Base := B diff --git a/Mathlib/Topology/VectorBundle/Hom.lean b/Mathlib/Topology/VectorBundle/Hom.lean index db2f9b8915afc..3b7a3339e4105 100644 --- a/Mathlib/Topology/VectorBundle/Hom.lean +++ b/Mathlib/Topology/VectorBundle/Hom.lean @@ -58,12 +58,6 @@ Porting note: after the port is done, we may want to remove this definition. protected abbrev Bundle.ContinuousLinearMap [∀ x, TopologicalSpace (E₁ x)] [∀ x, TopologicalSpace (E₂ x)] : B → Type _ := fun x => E₁ x →SL[σ] E₂ x --- Porting note: possibly remove after the port -instance Bundle.ContinuousLinearMap.module [∀ x, TopologicalSpace (E₁ x)] - [∀ x, TopologicalSpace (E₂ x)] [∀ x, TopologicalAddGroup (E₂ x)] - [∀ x, ContinuousConstSMul 𝕜₂ (E₂ x)] : ∀ x, Module 𝕜₂ (Bundle.ContinuousLinearMap σ E₁ E₂ x) := - fun _ => inferInstance - variable {E₁ E₂} variable [TopologicalSpace B] (e₁ e₁' : Trivialization F₁ (π F₁ E₁)) (e₂ e₂' : Trivialization F₂ (π F₂ E₂)) @@ -97,15 +91,9 @@ theorem continuousOn_continuousLinearMapCoordChange [RingHomIsometric σ] refine ((h₁.comp_continuousOn (h₄.mono ?_)).clm_comp (h₂.comp_continuousOn (h₃.mono ?_))).congr ?_ · mfld_set_tac · mfld_set_tac - · intro b _; ext L v - -- Porting note: was - -- simp only [continuousLinearMapCoordChange, ContinuousLinearEquiv.coe_coe, - -- ContinuousLinearEquiv.arrowCongrₛₗ_apply, LinearEquiv.toFun_eq_coe, coe_comp', - -- ContinuousLinearEquiv.arrowCongrSL_apply, comp_apply, Function.comp, compSL_apply, - -- flip_apply, ContinuousLinearEquiv.symm_symm] - -- Now `simp` fails to use `ContinuousLinearMap.comp_apply` in this case + · intro b _ + ext L v dsimp [continuousLinearMapCoordChange] - rw [ContinuousLinearEquiv.symm_symm] variable (σ e₁ e₁' e₂ e₂') variable [e₁.IsLinear 𝕜₁] [e₁'.IsLinear 𝕜₁] [e₂.IsLinear 𝕜₂] [e₂'.IsLinear 𝕜₂] diff --git a/Mathlib/Util/AddRelatedDecl.lean b/Mathlib/Util/AddRelatedDecl.lean index 22625a2347426..ecea6a5c315b8 100644 --- a/Mathlib/Util/AddRelatedDecl.lean +++ b/Mathlib/Util/AddRelatedDecl.lean @@ -1,8 +1,9 @@ /- -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 import Lean.Elab.Term @@ -73,3 +74,5 @@ def addRelatedDecl (src : Name) (suffix : String) (ref : Syntax) let attrs ← elabAttrs attrs Term.applyAttributes src attrs Term.applyAttributes tgt attrs + +end Mathlib.Tactic diff --git a/Mathlib/Util/AssertExists.lean b/Mathlib/Util/AssertExists.lean index 747726c2b139b..386f6f122afc9 100644 --- a/Mathlib/Util/AssertExists.lean +++ b/Mathlib/Util/AssertExists.lean @@ -1,9 +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: Patrick Massot, Scott Morrison +Authors: Patrick Massot, Kim Morrison -/ +import Mathlib.Init import Lean.Elab.Command +import Mathlib.Util.AssertExistsExt /-! # User commands for assert the (non-)existence of declaration or instances. @@ -21,6 +23,49 @@ Implement `assert_instance` and `assert_no_instance` section open Lean Elab Meta Command +namespace Mathlib.AssertNotExist + +/-- `#check_assertions` retrieves all declarations and all imports that were declared +not to exist so far (including in transitively imported files) and reports their current +status: +* ✓ means the declaration or import exists, +* × means the declaration or import does not exist. + +This means that the expectation is that all checks *succeed* by the time `#check_assertions` +is used, typically once all of `Mathlib` has been built. + +If all declarations and imports are available when `#check_assertions` is used, +then the command logs an info. Otherwise, it emits a warning. + +The variant `#check_assertions!` only prints declarations/imports that are not present in the +environment. In particular, it is silent if everything is imported, making it useful for testing. +-/ +elab "#check_assertions" tk:("!")?: command => do + let env ← getEnv + let entries := env.getSortedAssertExists + if entries.isEmpty && tk.isNone then logInfo "No assertions made." else + let allMods := env.allImportedModuleNames + let mut msgs := #[m!""] + let mut outcome := m!"" + let mut allExist? := true + for d in entries do + let type := if d.isDecl then "declaration" else "module" + let cond := if d.isDecl then env.contains d.givenName else allMods.contains d.givenName + outcome := if cond then m!"{checkEmoji}" else m!"{crossEmoji}" + allExist? := allExist? && cond + if tk.isNone || !cond then + msgs := msgs.push m!"{outcome} '{d.givenName}' ({type}) asserted in '{d.modName}'." + msgs := msgs.push m!"---" + |>.push m!"{checkEmoji} means the declaration or import exists." + |>.push m!"{crossEmoji} means the declaration or import does not exist." + let msg := MessageData.joinSep msgs.toList "\n" + if allExist? && tk.isNone then + logInfo msg + if !allExist? then + logWarning msg + +end Mathlib.AssertNotExist + /-- `assert_exists n` is a user command that asserts that a declaration named `n` exists in the current import scope. @@ -51,7 +96,11 @@ You should *not* delete the `assert_not_exists` statement without careful discus `assert_not_exists` statements should generally live at the top of the file, after the module doc. -/ elab "assert_not_exists " n:ident : command => do - let decl ← try liftCoreM <| realizeGlobalConstNoOverloadWithInfo n catch _ => return + let decl ← + try liftCoreM <| realizeGlobalConstNoOverloadWithInfo n + catch _ => + Mathlib.AssertNotExist.addDeclEntry true n.getId (← getMainModule) + return let env ← getEnv let c ← mkConstWithLevelParams decl let msg ← (do @@ -68,3 +117,19 @@ elab "assert_not_exists " n:ident : command => do These invariants are maintained by `assert_not_exists` statements, \ and exist in order to ensure that \"complicated\" parts of the library \ are not accidentally introduced as dependencies of \"simple\" parts of the library." + +/-- `assert_not_imported m₁ m₂ ... mₙ` checks that each one of the modules `m₁ m₂ ... mₙ` is not +among the transitive imports of the current file. + +The command does not currently check whether the modules `m₁ m₂ ... mₙ` actually exist. +-/ +-- TODO: make sure that each one of `m₁ m₂ ... mₙ` is the name of an actually existing module! +elab "assert_not_imported " ids:ident+ : command => do + let mods := (← getEnv).allImportedModuleNames + for id in ids do + if mods.contains id.getId then + logWarningAt id m!"the module '{id}' is (transitively) imported" + else + Mathlib.AssertNotExist.addDeclEntry false id.getId (← getMainModule) + +end diff --git a/Mathlib/Util/AssertExistsExt.lean b/Mathlib/Util/AssertExistsExt.lean new file mode 100644 index 0000000000000..e97a78563f4cf --- /dev/null +++ b/Mathlib/Util/AssertExistsExt.lean @@ -0,0 +1,57 @@ +/- +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.Environment + +/-! +# Environment extension for tracking existence of declarations and imports + +This is used by the `assert_not_exists` and `assert_not_imported` commands. +-/ + +section +open Lean Elab Meta + +namespace Mathlib.AssertNotExist + +/-- `AssertExists` is the structure that carries the data to check if a declaration or an +import are meant to exist somewhere in Mathlib. -/ +structure AssertExists where + /-- The type of the assertion: `true` means declaration, `false` means import. -/ + isDecl : Bool + /-- The fully qualified name of a declaration that is expected to exist. -/ + givenName : Name + /-- The name of the module where the assertion was made. -/ + modName : Name + deriving BEq, Hashable + +/-- Defines the `assertExistsExt` extension for adding a `HashSet` of `AssertExists`s +to the environment. -/ +initialize assertExistsExt : SimplePersistentEnvExtension AssertExists (Std.HashSet AssertExists) ← + registerSimplePersistentEnvExtension { + addImportedFn := fun as => as.foldl Std.HashSet.insertMany {} + addEntryFn := .insert + } + +/-- +`addDeclEntry isDecl declName mod` takes as input the `Bool`ean `isDecl` and the `Name`s of +a declaration or import, `declName`, and of a module, `mod`. +It extends the `AssertExists` environment extension with the data `isDecl, declName, mod`. +This information is used to capture declarations and modules that are required to not +exist/be imported at some point, but should eventually exist/be imported. +-/ +def addDeclEntry {m : Type → Type} [MonadEnv m] (isDecl : Bool) (declName mod : Name) : m Unit := + modifyEnv (assertExistsExt.addEntry · { isDecl := isDecl, givenName := declName, modName := mod }) + +end Mathlib.AssertNotExist + +open Mathlib.AssertNotExist + +/-- `getSortedAssertExists env` returns the array of `AssertExists`, placing first all declarations, +in alphabetical order, and then all modules, also in alphabetical order. -/ +def Lean.Environment.getSortedAssertExists (env : Environment) : Array AssertExists := + assertExistsExt.getState env |>.toArray.qsort fun d e => (e.isDecl < d.isDecl) || + (e.isDecl == d.isDecl && (d.givenName.toString < e.givenName.toString)) diff --git a/Mathlib/Util/AssertNoSorry.lean b/Mathlib/Util/AssertNoSorry.lean index e29f256c1db8b..5f320192712f4 100644 --- a/Mathlib/Util/AssertNoSorry.lean +++ b/Mathlib/Util/AssertNoSorry.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: David Renshaw -/ +import Mathlib.Init import Lean.Util.CollectAxioms import Lean.Elab.Command diff --git a/Mathlib/Util/AtomM.lean b/Mathlib/Util/AtomM.lean index 0d865b9f138e8..0b829028c0b11 100644 --- a/Mathlib/Util/AtomM.lean +++ b/Mathlib/Util/AtomM.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ +import Mathlib.Init import Lean.Meta.Tactic.Simp.Types /-! @@ -10,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, @@ -25,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 := #[] @@ -46,3 +52,5 @@ def AtomM.addAtom (e : Expr) : AtomM Nat := do if ← withTransparency (← read).red <| isDefEq e c.atoms[i] then return i modifyGet fun c ↦ (c.atoms.size, { c with atoms := c.atoms.push e }) + +end Mathlib.Tactic diff --git a/Mathlib/Util/CompileInductive.lean b/Mathlib/Util/CompileInductive.lean index fb9468d94d35f..5c98f82d30a38 100644 --- a/Mathlib/Util/CompileInductive.lean +++ b/Mathlib/Util/CompileInductive.lean @@ -3,9 +3,11 @@ Copyright (c) 2023 Parth Shastri. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Parth Shastri, Gabriel Ebner, Mario Carneiro -/ +import Mathlib.Init import Lean.Elab.Command import Lean.Compiler.CSimpAttr import Lean.Util.FoldConsts +import Lean.Data.AssocList /-! # Define the `compile_inductive%` command. diff --git a/Mathlib/Util/CountHeartbeats.lean b/Mathlib/Util/CountHeartbeats.lean index 3161930d15e2c..bbc00430ba743 100644 --- a/Mathlib/Util/CountHeartbeats.lean +++ b/Mathlib/Util/CountHeartbeats.lean @@ -1,8 +1,9 @@ /- -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 import Lean.Meta.Tactic.TryThis @@ -42,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 @@ -146,3 +147,7 @@ elab "count_heartbeats! " n:(num)? "in" ppLine cmd:command : command => do -- Then run once more, keeping the state. let counts := (← elabForHeartbeats cmd (revert := false)) :: counts logVariation counts + +end CountHeartbeats + +end Mathlib diff --git a/Mathlib/Util/Delaborators.lean b/Mathlib/Util/Delaborators.lean index a37232c230318..b45007dc4e2af 100644 --- a/Mathlib/Util/Delaborators.lean +++ b/Mathlib/Util/Delaborators.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 Mathlib.Init import Lean.PrettyPrinter.Delaborator.Builtins /-! # Pi type notation @@ -163,4 +164,4 @@ open Lean Lean.PrettyPrinter.Delaborator guard <| f.isAppOfArity ``Membership.mem 5 let stx₁ ← SubExpr.withAppArg <| SubExpr.withNaryArg 3 delab let stx₂ ← SubExpr.withAppArg <| SubExpr.withNaryArg 4 delab - return ← `($stx₁ ∉ $stx₂) + return ← `($stx₂ ∉ $stx₁) diff --git a/Mathlib/Util/DischargerAsTactic.lean b/Mathlib/Util/DischargerAsTactic.lean index c9e350e1ee0ab..b7662072b5f0a 100644 --- a/Mathlib/Util/DischargerAsTactic.lean +++ b/Mathlib/Util/DischargerAsTactic.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Alex J. Best. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Alex J. Best -/ +import Mathlib.Init import Lean.Elab.Tactic.Basic import Lean.Meta.Tactic.Simp.Rewrite import Batteries.Tactic.Exact diff --git a/Mathlib/Util/Export.lean b/Mathlib/Util/Export.lean index 1aef9a303dcb8..cf8ba9f835a02 100644 --- a/Mathlib/Util/Export.lean +++ b/Mathlib/Util/Export.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ +import Mathlib.Init import Lean.CoreM import Lean.Util.FoldConsts @@ -12,7 +13,8 @@ A rudimentary export format, adapted from with support for lean 4 kernel primitives. -/ -open Lean (HashMap HashSet) +open Lean +open Std (HashMap HashSet) namespace Lean @@ -35,15 +37,15 @@ instance : Coe Level Entry := ⟨Entry.level⟩ instance : Coe Expr Entry := ⟨Entry.expr⟩ structure Alloc (α) [BEq α] [Hashable α] where - map : HashMap α Nat + map : Std.HashMap α Nat next : Nat deriving Inhabited structure State where - names : Alloc Name := ⟨HashMap.empty.insert Name.anonymous 0, 1⟩ - levels : Alloc Level := ⟨HashMap.empty.insert levelZero 0, 1⟩ + names : Alloc Name := ⟨Std.HashMap.empty.insert Name.anonymous 0, 1⟩ + levels : Alloc Level := ⟨Std.HashMap.empty.insert levelZero 0, 1⟩ exprs : Alloc Expr - defs : HashSet Name + defs : Std.HashSet Name stk : Array (Bool × Entry) deriving Inhabited @@ -75,7 +77,7 @@ def alloc {α} [BEq α] [Hashable α] [OfState α] (a : α) : ExportM Nat := do pure n def exportName (n : Name) : ExportM Nat := do - match (← get).names.map.find? n with + match (← get).names.map[n]? with | some i => pure i | none => match n with | .anonymous => pure 0 @@ -83,7 +85,7 @@ def exportName (n : Name) : ExportM Nat := do | .str p s => let i ← alloc n; IO.println s!"{i} #NS {← exportName p} {s}"; pure i def exportLevel (L : Level) : ExportM Nat := do - match (← get).levels.map.find? L with + match (← get).levels.map[L]? with | some i => pure i | none => match L with | .zero => pure 0 @@ -107,7 +109,7 @@ open ConstantInfo in mutual partial def exportExpr (E : Expr) : ExportM Nat := do - match (← get).exprs.map.find? E with + match (← get).exprs.map[E]? with | some i => pure i | none => match E with | .bvar n => let i ← alloc E; IO.println s!"{i} #EV {n}"; pure i diff --git a/Mathlib/Util/GetAllModules.lean b/Mathlib/Util/GetAllModules.lean index 216d205cb93bc..c0e303c750528 100644 --- a/Mathlib/Util/GetAllModules.lean +++ b/Mathlib/Util/GetAllModules.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Kim Morrison, Damiano Testa -/ +import Mathlib.Init import Lean.Util.Path /-! diff --git a/Mathlib/Util/IncludeStr.lean b/Mathlib/Util/IncludeStr.lean index cad43a37b0703..691268eaf5e17 100644 --- a/Mathlib/Util/IncludeStr.lean +++ b/Mathlib/Util/IncludeStr.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Henrik Böving. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Henrik Böving, Xubai Wang -/ +import Mathlib.Init import Lean /-! @@ -18,3 +19,5 @@ elab (name := includeStr) "include_str " str:str : term => do let some srcDir := srcPath.parent | throwError "{srcPath} not in a valid directory" let path := srcDir / str Lean.mkStrLit <$> IO.FS.readFile path + +end Mathlib.Util diff --git a/Mathlib/Util/LongNames.lean b/Mathlib/Util/LongNames.lean index 1551a5e5ae21e..081b0dfe749d6 100644 --- a/Mathlib/Util/LongNames.lean +++ b/Mathlib/Util/LongNames.lean @@ -1,10 +1,11 @@ /- -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 +import Lean.Elab.Command /-! # Commands `#long_names` and `#long_instances` diff --git a/Mathlib/Util/MemoFix.lean b/Mathlib/Util/MemoFix.lean index ab8344cbc6c6c..0dead3fbcac55 100644 --- a/Mathlib/Util/MemoFix.lean +++ b/Mathlib/Util/MemoFix.lean @@ -3,7 +3,8 @@ Copyright (c) 2022 Gabriel Ebner. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner, Edward Ayers -/ -import Lean.Data.HashMap +import Std.Data.HashMap.Basic +import Mathlib.Init /-! # Fixpoint function with memoisation @@ -11,15 +12,15 @@ import Lean.Data.HashMap -/ universe u v -open ShareCommon +open ShareCommon Std -private unsafe abbrev ObjectMap := @Lean.HashMap Object Object ⟨Object.ptrEq⟩ ⟨Object.hash⟩ +private unsafe abbrev ObjectMap := @Std.HashMap Object Object ⟨Object.ptrEq⟩ ⟨Object.hash⟩ private unsafe def memoFixImplObj (f : (Object → Object) → (Object → Object)) (a : Object) : Object := unsafeBaseIO do let cache : IO.Ref ObjectMap ← ST.mkRef ∅ let rec fix (a) := unsafeBaseIO do - if let some b := (← cache.get).find? a then + if let some b := (← cache.get)[a]? then return b let b := f fix a cache.modify (·.insert a b) diff --git a/Mathlib/Util/Notation3.lean b/Mathlib/Util/Notation3.lean index fd02609f63fab..9ca6324227c12 100644 --- a/Mathlib/Util/Notation3.lean +++ b/Mathlib/Util/Notation3.lean @@ -97,12 +97,12 @@ structure MatchState where that have been found so far during the course of the matching algorithm. We store the contexts since we need to delaborate expressions after we leave scoping constructs. -/ - vars : HashMap Name (SubExpr × LocalContext × LocalInstances) + vars : Std.HashMap Name (SubExpr × LocalContext × LocalInstances) /-- The binders accumulated while matching a `scoped` expression. -/ scopeState : Option (Array (TSyntax ``extBinderParenthesized)) /-- The arrays of delaborated `Term`s accumulated while matching `foldl` and `foldr` expressions. For `foldl`, the arrays are stored in reverse order. -/ - foldState : HashMap Name (Array Term) + foldState : Std.HashMap Name (Array Term) /-- A matcher is a delaboration function that transforms `MatchState`s. -/ def Matcher := MatchState → DelabM MatchState @@ -118,7 +118,7 @@ def MatchState.empty : MatchState where saved context. Fails if the variable has no value. -/ def MatchState.withVar {α : Type} (s : MatchState) (name : Name) (m : DelabM α) : DelabM α := do - let some (se, lctx, linsts) := s.vars.find? name | failure + let some (se, lctx, linsts) := s.vars[name]? | failure withLCtx lctx linsts <| withTheReader SubExpr (fun _ => se) <| m /-- Delaborate the given variable's value. Fails if the variable has no value. @@ -138,7 +138,7 @@ def MatchState.captureSubexpr (s : MatchState) (name : Name) : DelabM MatchState /-- Get the accumulated array of delaborated terms for a given foldr/foldl. Returns `#[]` if nothing has been pushed yet. -/ def MatchState.getFoldArray (s : MatchState) (name : Name) : Array Term := - (s.foldState.find? name).getD #[] + s.foldState[name]?.getD #[] /-- Get the accumulated array of delaborated terms for a given foldr/foldl. Returns `#[]` if nothing has been pushed yet. -/ @@ -153,7 +153,7 @@ def MatchState.pushFold (s : MatchState) (name : Name) (t : Term) : MatchState : /-- Matcher that assigns the current `SubExpr` into the match state; if a value already exists, then it checks for equality. -/ def matchVar (c : Name) : Matcher := fun s => do - if let some (se, _, _) := s.vars.find? c then + if let some (se, _, _) := s.vars[c]? then guard <| se.expr == (← getExpr) return s else @@ -206,7 +206,7 @@ def matchLambda (matchDom : Matcher) (matchBody : Expr → Matcher) : Matcher := with types that are fresh metavariables. This is used for example when initializing `p` in `(scoped p => ...)` when elaborating `...`. -/ def setupLCtx (lctx : LocalContext) (boundNames : Array Name) : - MetaM (LocalContext × HashMap FVarId Name) := do + MetaM (LocalContext × Std.HashMap FVarId Name) := do let mut lctx := lctx let mut boundFVars := {} for name in boundNames do @@ -224,18 +224,18 @@ If it succeeds generating a matcher, returns 1. a list of keys that should be used for the `delab` attribute when defining the elaborator 2. a `Term` that represents a `Matcher` for the given expression `e`. -/ -partial def exprToMatcher (boundFVars : HashMap FVarId Name) (localFVars : HashMap FVarId Term) - (e : Expr) : +partial def exprToMatcher (boundFVars : Std.HashMap FVarId Name) + (localFVars : Std.HashMap FVarId Term) (e : Expr) : OptionT TermElabM (List Name × Term) := do match e with | .mvar .. => return ([], ← `(pure)) | .const n _ => return ([`app ++ n], ← ``(matchExpr (Expr.isConstOf · $(quote n)))) | .sort .. => return ([`sort], ← ``(matchExpr Expr.isSort)) | .fvar fvarId => - if let some n := boundFVars.find? fvarId then + if let some n := boundFVars[fvarId]? then -- This fvar is a pattern variable. return ([], ← ``(matchVar $(quote n))) - else if let some s := localFVars.find? fvarId then + else if let some s := localFVars[fvarId]? then -- This fvar is bound by a lambda or forall expression in the pattern itself return ([], ← ``(matchExpr (· == $s))) else @@ -377,7 +377,7 @@ partial def matchFoldl (lit x y : Name) (smatcher : Matcher) (sinit : Matcher) : -- y gives the next element of the list let s := s.pushFold lit (← s.delabVar y expr) -- x gives the next lit - let some newLit := s.vars.find? x | failure + let some newLit := s.vars[x]? | failure -- If progress was not made, fail if newLit.1.expr == expr then failure -- Progress was made, so recurse @@ -462,13 +462,13 @@ elab (name := notation3) doc:(docComment)? attrs?:(Parser.Term.attributes)? attr pp?:(ppSpace prettyPrintOpt)? items:(ppSpace notation3Item)+ " => " val:term : command => do -- We use raw `Name`s for variables. This maps variable names back to the -- identifiers that appear in `items` - let mut boundIdents : HashMap Name Ident := {} + let mut boundIdents : Std.HashMap Name Ident := {} -- Replacements to use for the `macro` - let mut boundValues : HashMap Name Syntax := {} + let mut boundValues : Std.HashMap Name Syntax := {} -- The names of the bound names in order, used when constructing patterns for delaboration. let mut boundNames : Array Name := #[] -- The normal/foldl/foldr type of each variable (for delaborator) - let mut boundType : HashMap Name BoundValueType := {} + let mut boundType : Std.HashMap Name BoundValueType := {} -- Function to update `syntaxArgs` and `pattArgs` using `macroArg` syntax let pushMacro (syntaxArgs : Array (TSyntax `stx)) (pattArgs : Array Syntax) (mac : TSyntax ``macroArg) := do @@ -506,8 +506,8 @@ elab (name := notation3) doc:(docComment)? attrs?:(Parser.Term.attributes)? attr (syntaxArgs, pattArgs) ← pushMacro syntaxArgs pattArgs <| ← `(macroArg| $id:ident:sepBy(term $(prec?)?, $sep:str)) -- N.B. `Syntax.getId` returns `.anonymous` for non-idents - let scopedTerm' ← scopedTerm.replaceM fun s => pure (boundValues.find? s.getId) - let init' ← init.replaceM fun s => pure (boundValues.find? s.getId) + let scopedTerm' ← scopedTerm.replaceM fun s => pure boundValues[s.getId]? + let init' ← init.replaceM fun s => pure boundValues[s.getId]? boundIdents := boundIdents.insert id.getId id match kind with | `(foldKind| foldl) => @@ -531,7 +531,7 @@ elab (name := notation3) doc:(docComment)? attrs?:(Parser.Term.attributes)? attr `(macroArg| $lit:ident:term $(prec?)?) matchers := matchers.push <| mkScopedMatcher lit.getId scopedId.getId scopedTerm boundNames - let scopedTerm' ← scopedTerm.replaceM fun s => pure (boundValues.find? s.getId) + let scopedTerm' ← scopedTerm.replaceM fun s => pure boundValues[s.getId]? boundIdents := boundIdents.insert lit.getId lit boundValues := boundValues.insert lit.getId <| ← `(expand_binders% ($scopedId => $scopedTerm') $$binders:extBinders, @@ -560,7 +560,7 @@ elab (name := notation3) doc:(docComment)? attrs?:(Parser.Term.attributes)? attr let fullName := currNamespace ++ name trace[notation3] "syntax declaration has name {fullName}" let pat : Term := ⟨mkNode fullName pattArgs⟩ - let val' ← val.replaceM fun s => pure (boundValues.find? s.getId) + let val' ← val.replaceM fun s => pure boundValues[s.getId]? let mut macroDecl ← `(macro_rules | `($pat) => `($val')) if isLocalAttrKind attrKind then -- For local notation, take section variables into account @@ -584,7 +584,7 @@ elab (name := notation3) doc:(docComment)? attrs?:(Parser.Term.attributes)? attr trace[notation3] "matcher:{indentD matcher}" let mut result ← `(`($pat)) for (name, id) in boundIdents.toArray do - match boundType.findD name .normal with + match boundType.getD name .normal with | .normal => result ← `(MatchState.delabVar s $(quote name) (some e) >>= fun $id => $result) | .foldl => result ← `(let $id := (MatchState.getFoldArray s $(quote name)).reverse; $result) @@ -620,3 +620,7 @@ macro_rules | `($[$doc]? $(attr)? scoped[$ns] notation3 $(prec)? $(n)? $(prio)? $(pp)? $items* => $t) => `(with_weak_namespace $(mkIdentFrom ns <| rootNamespace ++ ns.getId) $[$doc]? $(attr)? scoped notation3 $(prec)? $(n)? $(prio)? $(pp)? $items* => $t) + +end Notation3 + +end Mathlib diff --git a/Mathlib/Util/Qq.lean b/Mathlib/Util/Qq.lean index fee01e5b0f6e4..5232470c0d692 100644 --- a/Mathlib/Util/Qq.lean +++ b/Mathlib/Util/Qq.lean @@ -1,8 +1,9 @@ /- -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 2fdfdeb4238a3..f6cb76c320e8d 100644 --- a/Mathlib/Util/SleepHeartbeats.lean +++ b/Mathlib/Util/SleepHeartbeats.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Alex J. Best. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Alex J. Best -/ +import Mathlib.Init import Lean.Elab.Tactic.Basic /-! diff --git a/Mathlib/Util/Superscript.lean b/Mathlib/Util/Superscript.lean index 340ca3a3d174d..85d3b2fecae7f 100644 --- a/Mathlib/Util/Superscript.lean +++ b/Mathlib/Util/Superscript.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ +import Mathlib.Init import Batteries.Tactic.Lint /-! @@ -28,7 +29,7 @@ universe u namespace Mathlib.Tactic -open Lean Parser PrettyPrinter +open Lean Parser PrettyPrinter Std namespace Superscript @@ -37,9 +38,9 @@ instance : Hashable Char := ⟨fun c => hash c.1⟩ /-- A bidirectional character mapping. -/ structure Mapping where /-- Map from "special" (e.g. superscript) characters to "normal" characters. -/ - toNormal : HashMap Char Char := {} + toNormal : Std.HashMap Char Char := {} /-- Map from "normal" text to "special" (e.g. superscript) characters. -/ - toSpecial : HashMap Char Char := {} + toSpecial : Std.HashMap Char Char := {} deriving Inhabited /-- Constructs a mapping (intended for compile time use). Panics on violated invariants. -/ @@ -94,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 @@ -103,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: @@ -127,7 +130,7 @@ partial def scriptFnNoAntiquot (m : Mapping) (errorMsg : String) (p : ParserFn) let mut pos := start while pos < stopTk do let c := input.get pos - let c' := m.toNormal.find! c + let c' := m.toNormal[c]! newStr := newStr.push c' pos := pos + c if c.utf8Size != c'.utf8Size then @@ -212,7 +215,7 @@ def scriptParser.formatter (name : String) (m : Mapping) (k : SyntaxNodeKind) (p Formatter.node.formatter k p let st ← get let transformed : Except String _ := st.stack.mapM (·.mapStringsM fun s => do - let .some s := s.toList.mapM (m.toSpecial.insert ' ' ' ').find? | .error s + let .some s := s.toList.mapM (m.toSpecial.insert ' ' ' ').get? | .error s .ok ⟨s⟩) match transformed with | .error err => @@ -280,3 +283,5 @@ initialize registerAlias `subscript ``subscript subscript registerAliasCore Formatter.formatterAliasesRef `subscript subscript.formatter registerAliasCore Parenthesizer.parenthesizerAliasesRef `subscript subscript.parenthesizer + +end Mathlib.Tactic diff --git a/Mathlib/Util/SynthesizeUsing.lean b/Mathlib/Util/SynthesizeUsing.lean index c850177038553..6e65203680e84 100644 --- a/Mathlib/Util/SynthesizeUsing.lean +++ b/Mathlib/Util/SynthesizeUsing.lean @@ -1,8 +1,9 @@ /- -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 import Qq diff --git a/Mathlib/Util/Tactic.lean b/Mathlib/Util/Tactic.lean index b306cfd4dd034..41a28ecce696f 100644 --- a/Mathlib/Util/Tactic.lean +++ b/Mathlib/Util/Tactic.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Arthur Paulino. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Arthur Paulino, Jannis Limperg -/ +import Mathlib.Init import Lean.MetavarContext /-! @@ -71,3 +72,5 @@ exist in the local context of `mvarId`, nothing happens. def modifyLocalDecl [MonadMCtx m] (mvarId : MVarId) (fvarId : FVarId) (f : LocalDecl → LocalDecl) : m Unit := modifyLocalContext mvarId fun lctx ↦ lctx.modifyLocalDecl fvarId f + +end Mathlib.Tactic diff --git a/Mathlib/Util/TermBeta.lean b/Mathlib/Util/TermBeta.lean index 2cd8f8d0ccca8..894ced6315fb4 100644 --- a/Mathlib/Util/TermBeta.lean +++ b/Mathlib/Util/TermBeta.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 Mathlib.Init import Lean.Elab.Term /-! `beta%` term elaborator @@ -36,3 +37,5 @@ def elabBeta : TermElab := fun stx expectedType? => let e ← elabTerm t expectedType? return (← instantiateMVars e).headBeta | _ => throwUnsupportedSyntax + +end Mathlib.Util.TermBeta diff --git a/Mathlib/Util/Time.lean b/Mathlib/Util/Time.lean deleted file mode 100644 index 87e2df48ef086..0000000000000 --- a/Mathlib/Util/Time.lean +++ /dev/null @@ -1,35 +0,0 @@ -/- -Copyright (c) 2021 Mario Carneiro. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Mario Carneiro --/ -import Lean - -/-! -# Defines `#time` command. - -Time the elaboration of a command, and print the result (in milliseconds). --/ - -section -open Lean Elab Command - -syntax (name := timeCmd) "#time " command : command - -/-- -Time the elaboration of a command, and print the result (in milliseconds). - -Example usage: -``` -set_option maxRecDepth 100000 in -#time example : (List.range 500).length = 500 := rfl -``` --/ -@[command_elab timeCmd] def timeCmdElab : CommandElab - | `(#time%$tk $stx:command) => do - let start ← IO.monoMsNow - elabCommand stx - logInfoAt tk m!"time: {(← IO.monoMsNow) - start}ms" - | _ => throwUnsupportedSyntax - -end diff --git a/Mathlib/Util/WhatsNew.lean b/Mathlib/Util/WhatsNew.lean index 6219583ff984b..bf3515832cd40 100644 --- a/Mathlib/Util/WhatsNew.lean +++ b/Mathlib/Util/WhatsNew.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Gabriel Ebner -/ +import Mathlib.Init import Lean /-! @@ -116,3 +117,5 @@ elab "whatsnew " "in" ppLine cmd:command : command => do finally let newEnv ← getEnv logInfo (← liftCoreM <| whatsNew oldEnv newEnv) + +end Mathlib.WhatsNew diff --git a/Mathlib/Util/WithWeakNamespace.lean b/Mathlib/Util/WithWeakNamespace.lean index 51e164d83a3c6..04fcad50d7093 100644 --- a/Mathlib/Util/WithWeakNamespace.lean +++ b/Mathlib/Util/WithWeakNamespace.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Daniel Selsam, Gabriel Ebner -/ +import Mathlib.Init import Lean /-! @@ -37,3 +38,5 @@ def withWeakNamespace {α : Type} (ns : Name) (m : CommandElabM α) : CommandEla /-- Changes the current namespace without causing scoped things to go out of scope -/ elab "with_weak_namespace " ns:ident cmd:command : command => withWeakNamespace ns.getId (elabCommand cmd) + +end Lean.Elab.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 b6787a87fd6cf..e5b7645a31d81 100644 --- a/Shake/Main.lean +++ b/Shake/Main.lean @@ -81,7 +81,7 @@ abbrev Bitset := Nat /-- The main state of the checker, containing information on all loaded modules. -/ structure State where /-- Maps a module name to its index in the module list. -/ - toIdx : HashMap Name USize := {} + toIdx : Std.HashMap Name USize := {} /-- Maps a module index to the module name. -/ modNames : Array Name := #[] /-- Maps a module index to the module data. -/ @@ -96,7 +96,7 @@ structure State where /-- Maps a constant name to the module index containing it. A value of `none` means the constant was found in multiple modules, in which case we do not track it. -/ - constToIdx : HashMap Name (Option USize) := {} + constToIdx : Std.HashMap Name (Option USize) := {} /-- Returns `true` if this is a constant whose body should not be considered for dependency tracking purposes. -/ @@ -110,7 +110,7 @@ def isBlacklisted (name : Name) : Bool := /-- Calculates the value of the `needs[i]` bitset for a given module `mod`. Bit `j` is set in the result if some constant from module `j` is used in this module. -/ -def calcNeeds (constToIdx : HashMap Name (Option USize)) (mod : ModuleData) : Bitset := +def calcNeeds (constToIdx : Std.HashMap Name (Option USize)) (mod : ModuleData) : Bitset := mod.constants.foldl (init := 0) fun deps ci => if isBlacklisted ci.name then deps else let deps := visitExpr ci.type deps @@ -120,13 +120,13 @@ def calcNeeds (constToIdx : HashMap Name (Option USize)) (mod : ModuleData) : Bi where /-- Accumulate the results from expression `e` into `deps`. -/ visitExpr e deps := - Lean.Expr.foldConsts e deps fun c deps => match constToIdx.find? c with + Lean.Expr.foldConsts e deps fun c deps => match constToIdx[c]? with | some (some i) => deps ||| (1 <<< i.toNat) | _ => deps /-- Calculates the same as `calcNeeds` but tracing each module to a specific constant. -/ -def getExplanations (constToIdx : HashMap Name (Option USize)) (mod : ModuleData) : - HashMap USize (Name × Name) := +def getExplanations (constToIdx : Std.HashMap Name (Option USize)) (mod : ModuleData) : + Std.HashMap USize (Name × Name) := mod.constants.foldl (init := {}) fun deps ci => if isBlacklisted ci.name then deps else let deps := visitExpr ci.name ci.type deps @@ -136,10 +136,10 @@ def getExplanations (constToIdx : HashMap Name (Option USize)) (mod : ModuleData where /-- Accumulate the results from expression `e` into `deps`. -/ visitExpr name e deps := - Lean.Expr.foldConsts e deps fun c deps => match constToIdx.find? c with + Lean.Expr.foldConsts e deps fun c deps => match constToIdx[c]? with | some (some i) => if - if let some (name', _) := deps.find? i then + if let some (name', _) := deps[i]? then decide (name.toString.length < name'.toString.length) else true then @@ -159,7 +159,7 @@ partial def loadModules (imports : Array Import) : StateT State IO (Array USize let mut transImps := 0 for imp in imports do let s ← get - if let some i := s.toIdx.find? imp.module then + if let some i := s.toIdx[imp.module]? then imps := imps.push i transImps := transImps ||| s.transDeps[i]! else @@ -181,14 +181,14 @@ partial def loadModules (imports : Array Import) : StateT State IO (Array USize transDeps := s.transDeps.push transDeps needs := s.needs constToIdx := mod.constNames.foldl (init := s.constToIdx) fun m a => - match m.insertIfNew a n with - | (m, some (some _)) => + match m.getThenInsertIfNew? a n with + | (some (some _), m) => -- Note: If a constant is found in multiple modules, we assume it is an auto-generated -- definition which is created on demand, and therefore it is safe to ignore any -- dependencies via this definition because it will just be re-created in the current -- module if we don't import it. m.insert a none - | (m, _) => m + | (_, m) => m } return (imps, transImps) @@ -198,17 +198,17 @@ partial def loadModules (imports : Array Import) : StateT State IO (Array USize * If `j ∈ added` then we want to add module index `j` to the imports of `i`. We keep this as a bitset because we will do transitive reduction before applying it -/ -def Edits := HashMap Name (NameSet × Bitset) +def Edits := Std.HashMap Name (NameSet × Bitset) /-- Register that we want to remove `tgt` from the imports of `src`. -/ def Edits.remove (ed : Edits) (src tgt : Name) : Edits := - match ed.find? src with + match ed.get? src with | none => ed.insert src (RBTree.insert ∅ tgt, 0) | some (a, b) => ed.insert src (a.insert tgt, b) /-- Register that we want to add `tgt` to the imports of `src`. -/ def Edits.add (ed : Edits) (src : Name) (tgt : Nat) : Edits := - match ed.find? src with + match ed.get? src with | none => ed.insert src (∅, 1 <<< tgt) | some (a, b) => ed.insert src (a, b ||| (1 <<< tgt)) @@ -262,7 +262,7 @@ def visitModule (s : State) (srcSearchPath : SearchPath) (ignoreImps : Bitset) let mut toRemove := #[] let mut newDeps := 0 for imp in s.mods[i]!.imports do - let j := s.toIdx.find! imp.module + let j := s.toIdx[imp.module]! if transDeps &&& (1 <<< j.toNat) == 0 then toRemove := toRemove.push j else @@ -360,11 +360,11 @@ def visitModule (s : State) (srcSearchPath : SearchPath) (ignoreImps : Bitset) if explain then let explanation := getExplanations s.constToIdx s.mods[i]! let sanitize n := if n.hasMacroScopes then (sanitizeName n).run' { options := {} } else n - let run j := do - if let some (n, c) := explanation.find? j then + let run (j : USize) := do + if let some (n, c) := explanation[j]? then println! " note: {s.modNames[i]!} requires {s.modNames[j]!}\ \n because {sanitize n} refers to {sanitize c}" - for imp in s.mods[i]!.imports do run <| s.toIdx.find! imp.module + for imp in s.mods[i]!.imports do run <| s.toIdx[imp.module]! for i in toAdd do run i.toUSize return edits @@ -372,7 +372,7 @@ def visitModule (s : State) (srcSearchPath : SearchPath) (ignoreImps : Bitset) /-- Convert a list of module names to a bitset of module indexes -/ def toBitset (s : State) (ns : List Name) : Bitset := ns.foldl (init := 0) fun c name => - match s.toIdx.find? name with + match s.toIdx[name]? with | some i => c ||| (1 <<< i.toNat) | none => c @@ -470,7 +470,7 @@ def main (args : List String) : IO UInt32 := do -- Parse the config file let ignoreMods := toBitset s (cfg.ignoreAll?.getD []) let ignoreImps := toBitset s (cfg.ignoreImport?.getD []) - let ignore := (cfg.ignore?.getD {}).fold (init := mkHashMap) fun m a v => + let ignore := (cfg.ignore?.getD {}).fold (init := Std.HashMap.empty) fun m a v => m.insert a (toBitset s v.toList) let noIgnore (i : Nat) := @@ -493,11 +493,11 @@ def main (args : List String) : IO UInt32 := do println! "The following changes will be made automatically:" -- Check all selected modules - let mut edits : Edits := mkHashMap + let mut edits : Edits := Std.HashMap.empty for i in [0:s.mods.size], t in needs do if let some t := t then if noIgnore i then - let ignoreImps := ignoreImps ||| ignore.findD s.modNames[i]! 0 + let ignoreImps := ignoreImps ||| ignore.getD s.modNames[i]! 0 edits ← visitModule s srcSearchPath ignoreImps i t.get edits args.downstream args.githubStyle args.explain 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 5d884c7e1cabb..d020bc5328e44 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' @@ -231,7 +231,7 @@ Topology: Topological algebra: order topology: 'OrderTopology' intermediate value theorem: 'intermediate_value_Icc' - extreme value theorem: 'IsCompact.exists_forall_le' + extreme value theorem: 'IsCompact.exists_isMinOn' limit infimum and supremum: 'order/liminf_limsup.html' topological group: 'TopologicalGroup' completion of an abelian topological group: 'UniformSpace.Completion.instAddCommGroup' @@ -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' diff --git a/docs/references.bib b/docs/references.bib index b98a31a74d6fb..67919e2ced15f 100644 --- a/docs/references.bib +++ b/docs/references.bib @@ -944,6 +944,23 @@ @Misc{ conradQ eprint = {https://kconrad.math.uconn.edu/blurbs/gradnumthy/ostrowskiQ.pdf} } +@Book{ conway1990, + author = {Conway, John B.}, + title = {A course in functional analysis.}, + edition = {2nd ed.}, + fseries = {Graduate Texts in Mathematics}, + series = {Grad. Texts Math.}, + issn = {0072-5285}, + volume = {96}, + isbn = {0-387-97245-5}, + year = {1990}, + publisher = {New York etc.: Springer-Verlag}, + language = {English}, + keywords = {46-02,47-02,47A53}, + zbmath = {47995}, + zbl = {0706.46003} +} + @Book{ conway2001, author = {Conway, J. H.}, title = {On numbers and games}, @@ -1379,6 +1396,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}, @@ -1412,6 +1441,13 @@ @InProceedings{ fuerer-lochbihler-schneider-traytel2020 bibsource = {dblp computer science bibliography, https://dblp.org} } +@Book{ fulton2004, + title = {Representation theory: a first course}, + author = {Fulton, William and Harris, Joe}, + year = {2004}, + publisher = {Springer} +} + @Article{ furedi-loeb1994, author = {Zolt\'an {F\"uredi} and Peter A. {Loeb}}, journal = {{Proc. Am. Math. Soc.}}, @@ -2052,6 +2088,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}}, @@ -2803,6 +2847,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 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 d771a7dee19b1..4a49ec817f12a 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -5,7 +5,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "ad26fe1ebccc9d5b7ca9111d5daf9b4488374415", + "rev": "daf1ed91789811cf6bbb7bf2f4dad6b3bad8fbf4", "name": "batteries", "manifestFile": "lake-manifest.json", "inputRev": "main", @@ -15,7 +15,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "71f54425e6fe0fa75f3aef33a2813a7898392222", + "rev": "2b2f6d7fbe9d917fc010e9054c1ce11774c9088b", "name": "Qq", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -25,7 +25,7 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "776a5a8f9c789395796e442d78a9d4cb9c4c9d03", + "rev": "b20a88676fd00affb90cbc9f1ff004ae588103b3", "name": "aesop", "manifestFile": "lake-manifest.json", "inputRev": "master", @@ -35,16 +35,16 @@ "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "a96aee5245720f588876021b6a0aa73efee49c76", + "rev": "eb08eee94098fe530ccd6d8751a86fe405473d4c", "name": "proofwidgets", "manifestFile": "lake-manifest.json", - "inputRev": "v0.0.41", + "inputRev": "v0.0.42", "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": "57bd2065f1dbea5e9235646fb836c7cea9ab03b6", + "rev": "7376ac07aa2b0492372c056b7a2c3163b3026d1e", "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": "4b61d4abc1659f15ffda5ec24fdebc229d51d066", + "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 2d1665c48244d..212047a97ac35 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -2,26 +2,60 @@ import Lake open Lake DSL -package mathlib where - leanOptions := #[ - ⟨`pp.unicode.fun, true⟩, -- pretty-prints `fun a ↦ b` - ⟨`autoImplicit, false⟩ - ] - -- 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, - -- or inconsistent behavior may result - -- weakLeanArgs := #[] /-! -## Mathlib dependencies on upstream projects. +## Mathlib dependencies on upstream projects -/ 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.41" +require "leanprover-community" / "proofwidgets" @ git "v0.0.42" 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 +-/ + +/-- These options are used +* as `leanOptions`, prefixed by `` `weak``, so that `lake build` uses them; +* as `moreServerArgs`, to set their default value in mathlib + (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.lambdaSyntax, true⟩, + ⟨`linter.style.longLine, true⟩, + ⟨`linter.style.longFile, .ofNat 1500⟩, + ⟨`linter.style.missingEnd, true⟩, + ⟨`linter.style.setOption, true⟩, + ⟨`aesop.warn.applyIff, false⟩ -- This became a problem after https://github.com/leanprover-community/aesop/commit/29cf094e84ae9852f0011b47b6ddc684ffe4be5f +] + +/-- These options are passed as `leanOptions` to building mathlib, as well as the +`Archive` and `Counterexamples`. (`tests` omits the first two options.) -/ +abbrev mathlibLeanOptions := #[ + ⟨`pp.unicode.fun, true⟩, -- pretty-prints `fun a ↦ b` + ⟨`autoImplicit, false⟩ + ] ++ -- options that are used in `lake build` + mathlibOnlyLinters.map fun s ↦ { s with name := `weak ++ s.name } + +package mathlib where + leanOptions := mathlibLeanOptions + -- Mathlib also enforces these linter options, which are not active by default. + moreServerOptions := mathlibOnlyLinters + -- 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, + -- or inconsistent behavior may result + -- weakLeanArgs := #[] /-! ## Mathlib libraries @@ -34,8 +68,15 @@ lean_lib Mathlib -- `scripts/mk_all.lean`. lean_lib Cache lean_lib LongestPole -lean_lib Archive -lean_lib Counterexamples + +lean_lib Archive where + leanOptions := mathlibLeanOptions + moreServerOptions := mathlibOnlyLinters + +lean_lib Counterexamples where + leanOptions := mathlibLeanOptions + moreServerOptions := mathlibOnlyLinters + /-- Additional documentation in the form of modules that only contain module docstrings. -/ lean_lib docs where roots := #[`docs] @@ -44,6 +85,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 @@ -88,6 +139,8 @@ You can also use it as e.g. `lake exe test conv eval_elab` to only run the named -/ @[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" /-! diff --git a/lean-toolchain b/lean-toolchain index e7a4f40b892b4..eff86fd63de9e 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.11.0-rc2 +leanprover/lean4:v4.13.0-rc3 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..9fdeceaa83cda 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 .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/check-yaml.lean b/scripts/check-yaml.lean index 23730a3fabb2e..44aca0b63758a 100644 --- a/scripts/check-yaml.lean +++ b/scripts/check-yaml.lean @@ -22,11 +22,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 f9611d8e63e3b..c64a006cbf1a3 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="no" + +# Function to display usage +usage() { echo "Usage: $0 " - echo "BUMPVERSION: The upcoming release that we are targetting, e.g., 'v4.10.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 'no'" 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 @@ -38,8 +80,13 @@ if [ "$status" != "completed" ]; then 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." + if [ "$AUTO" = "yes" ]; then + echo "Auto mode enabled. Bailing out because the latest commit on 'nightly-testing' is still running CI." + exit 1 + else + echo "The latest commit on 'nightly-testing' is still running CI." + read -p "Press enter to continue, or ctrl-C if you'd prefer to wait for CI." + fi fi fi @@ -61,7 +108,7 @@ echo "### [auto] checkout 'bump/$BUMPVERSION' and merge the latest changes from git checkout "bump/$BUMPVERSION" git pull -git merge origin/master +git merge 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 @@ -70,34 +117,58 @@ if git diff --name-only --diff-filter=U | grep -q .; then echo "### Automatically choosing 'lean-toolchain' and 'lake-manifest.json' from the newer branch" echo "### In this case, the newer branch is 'bump/$BUMPVERSION'" git checkout bump/$BUMPVERSION -- lean-toolchain lake-manifest.json + git add lean-toolchain lake-manifest.json + + # Check if there are more merge conflicts after auto-resolution + if ! git diff --name-only --diff-filter=U | grep -q .; then + # Auto-commit the resolved conflicts if no other conflicts remain + git commit -m "Auto-resolved conflicts in lean-toolchain and lake-manifest.json" + fi fi -# Check if there are more merge conflicts -if git diff --name-only --diff-filter=U | grep -q .; then +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 echo "### [user] Conflict resolution" echo "We are merging the latest changes from 'origin/master' into 'bump/$BUMPVERSION'" - echo "There seem to be conflicts: please resolve them" - echo "Open `pwd` in a new terminal and run 'git status'" - echo "Make sure to commit the resolved conflicts, but do not push them" - read -p "Press enter to continue, when you are done" -fi - + echo "There seem to be conflicts or uncommitted files" + echo "" + echo " 1) Open `pwd` in a new terminal and run 'git status'" + echo " 2) Make sure to commit the resolved conflicts, but do not push them" + read -p " 3) Press enter to continue, when you are done" +done + +echo "All conflicts resolved and committed." +echo "Proceeding with git push..." git push 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 +git merge $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 @@ -105,17 +176,24 @@ 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 "Open `pwd` in a new terminal and run 'git status'" - echo "Run 'git add' on the resolved files, but do not commit" - read -p "Press enter to continue, when you are done" + echo "" + echo " 1) Open `pwd` in a new terminal and run 'git status'" + echo " 2) Run 'git add' on the resolved files, but do not commit" + read -p " 3) Press enter to continue, when you are done" fi echo echo "### [auto] commit the changes and push the branch" pr_title="chore: adaptations for nightly-$NIGHTLYDATE" -git commit -m "$pr_title" +# Create a commit with the PR title +# We allow an empty commit, +# as the user might have inadvertently already committed changes +# In general, we do not want this command to fail. +git commit --allow-empty -m "$pr_title" git push --set-upstream origin "bump/nightly-$NIGHTLYDATE" # Check if there is a diff between bump/nightly-$NIGHTLYDATE and bump/$BUMPVERSION @@ -127,8 +205,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 @@ -136,7 +219,7 @@ 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" @@ -145,7 +228,33 @@ if git diff --name-only bump/$BUMPVERSION bump/nightly-$NIGHTLYDATE | grep -q .; 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 @@ -161,7 +270,7 @@ echo "### [auto] checkout the 'nightly-testing' branch and merge the new branch git checkout nightly-testing git pull -git merge "bump/nightly-$NIGHTLYDATE" +git merge "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 @@ -170,19 +279,38 @@ if git diff --name-only --diff-filter=U | grep -q .; then echo "### Automatically choosing lean-toolchain and lake-manifest.json from the newer branch" echo "### In this case, the newer branch is 'bump/nightly-$NIGHTLYDATE'" git checkout bump/nightly-$NIGHTLYDATE -- lean-toolchain lake-manifest.json + git add lean-toolchain lake-manifest.json + + # Check if there are more merge conflicts after auto-resolution + if ! git diff --name-only --diff-filter=U | grep -q .; then + # Auto-commit the resolved conflicts if no other conflicts remain + git commit -m "Auto-resolved conflicts in lean-toolchain and lake-manifest.json" + fi fi -# Check if there are more merge conflicts -if git diff --name-only --diff-filter=U | grep -q .; then +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 echo "### [user] Conflict resolution" echo "We are merging the new PR "bump/nightly-$NIGHTLYDATE" into 'nightly-testing'" - echo "There seem to be conflicts: please resolve them" - echo "Open `pwd` in a new terminal and run 'git status'" - echo "Make sure to commit the resolved conflicts, but do not push them" - read -p "Press enter to continue, when you are done" -fi - + echo "There seem to be conflicts or uncommitted files" + echo "" + echo " 1) Open `pwd` in a new terminal and run 'git status'" + echo " 2) Make sure to commit the resolved conflicts, but do not push them" + read -p " 3) Press enter to continue, when you are done" +done + +echo "All conflicts resolved and committed." +echo "Proceeding with git push..." git push echo diff --git a/scripts/declarations_diff.sh b/scripts/declarations_diff.sh index d12f8de3182fa..d7a9d1c5ac2ec 100755 --- a/scripts/declarations_diff.sh +++ b/scripts/declarations_diff.sh @@ -42,7 +42,7 @@ The script uses some heuristics to guide this process. BASH_DOC_MODULE ## we narrow the diff to lines beginning with `theorem`, `lemma` and a few other commands -begs="(theorem|lemma|inductive|structure|def|class|instance|alias)" +begs="(theorem|lemma|inductive|structure|def|class|instance|alias|abbrev)" if [ "${1}" == "long" ] then @@ -181,4 +181,5 @@ def testingLongDiff2 im a def def testingLongDiff3 im a def @[trying to fool you] instance. the messing dot alias ⟨d1, d2⟩ := d check the "split an iff alias" +abbrev a_new_one := I was not here before ReferenceTest diff --git a/scripts/fix-by-linebreaks.sh b/scripts/fix-by-linebreaks.sh deleted file mode 100755 index f0fdd8aa12f08..0000000000000 --- a/scripts/fix-by-linebreaks.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -# Modify all lean files in mathlib to put the "by" in lines that only contain " by" at the end of the previous line, -# when the previous line with " by" appended is not longer than 100 characters. - -grep -lr "^ by\$" Mathlib | xargs -n 1 awk -i inplace '{do {{if (match($0, "^ by$") && length(p) < 98 && (!(match(p, "^[ \t]*--.*$")))) {p=p " by";} else {if (NR!=1) {print p}; p=$0}}} while (getline == 1) if (getline==0) print p}' diff --git a/scripts/get_tlabel.sh b/scripts/get_tlabel.sh new file mode 100755 index 0000000000000..6e03a8f27d23f --- /dev/null +++ b/scripts/get_tlabel.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + + : <<'BASH_MODULE_DOCS' + +This script is used by the maintainer merge actions to extract +* either `t-xxx` if `t-xxx` is the unique `t-`label of the PR; +* or `generic` otherwise +and stores it in `tlabels`. + +In turn, the string `tlabels` extracted above is converted into the +topic name `maintainer merge: tlabels` for the post to the +`maintainer merge` stream. + +BASH_MODULE_DOCS + +PR="${1}" + +>&2 printf $'Using PR: \'%s\'\n' "${PR}" + +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`, `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}" +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/import_trans_difference.sh b/scripts/import_trans_difference.sh index f97a0094cb50f..1fd4102c594d9 100755 --- a/scripts/import_trans_difference.sh +++ b/scripts/import_trans_difference.sh @@ -1,10 +1,13 @@ #!/usr/bin/env bash : <<'BASH_MODULE_DOCS' -`scripts/import_trans_difference.sh ` outputs a full diff of the -change of transitive imports in all the files between `` and ``. +`scripts/import_trans_difference.sh ` outputs a full diff +of the change of transitive imports in all the files between `` and ``. -If the commits are not provided, then it uses the current commit as `commit1` and +The optional flag `` must either be `all` or not be passed. +Without `all`, the script only displays the difference if the output does not exceed 200 lines. + +If the commits are not provided, then the script uses the current commit as `commit1` and current `master` as `commit2`. The output is of the form @@ -18,6 +21,14 @@ The output is of the form with collapsible tabs for file entries with at least 3 files. BASH_MODULE_DOCS +# `all=1` is the flag to print all import changes, without cut-off +all=0 +if [ "${1}" == "all" ] +then + all=1 + shift +fi + if [ -n "${1}" ] then commit1="${1}" @@ -34,7 +45,13 @@ fi #printf 'commit1: %s\ncommit2: %s\n' "$commit1" "$commit2" -currCommit="$(git rev-parse HEAD)" +currCommit="$(git rev-parse --abbrev-ref HEAD)" +# if we are in a detached head, `currCommit` would be the unhelpful `HEAD` +# in this case, we fetch the commit hash +if [ "${currCommit}" == "HEAD" ] +then + currCommit="$(git rev-parse HEAD)" +fi getTransImports () { python3 scripts/count-trans-deps.py Mathlib | @@ -55,16 +72,20 @@ git checkout "${currCommit}" printf '\n\n
Import changes for all files\n\n%s\n\n
\n' "$( printf "|Files|Import difference|\n|-|-|\n" - (awk -F, '{ diff[$1]+=$2 } END { - con=0 + (awk -F, -v all="${all}" -v ghLimit='261752' '{ diff[$1]+=$2 } END { + fileCount=0 + outputLength=0 for(fil in diff) { if(!(diff[fil] == 0)) { - con++ + fileCount++ + outputLength+=length(fil)+4 nums[diff[fil]]++ reds[diff[fil]]=reds[diff[fil]]" `"fil"`" } } - if (200 <= con) { printf("There are %s files with changed transitive imports: this is too many to display!\n", con) } else { + if ((all == 0) && (ghLimit/2 <= outputLength)) { + printf("There are %s files with changed transitive imports taking up over %s characters: this is too many to display!\nYou can run `scripts/import_trans_difference.sh all` locally to see the whole output.", fileCount, outputLength) + } else { for(x in reds) { if (nums[x] <= 2) { printf("|%s|%s|\n", reds[x], x) } else { printf("|
%s files%s
|%s|\n", nums[x], reds[x], x) } diff --git a/scripts/init_creation.sh b/scripts/init_creation.sh new file mode 100644 index 0000000000000..7abca30241c43 --- /dev/null +++ b/scripts/init_creation.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + + : <<'BASH_MODULE_DOC' + +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...";` +# using `"` as separator, the 2nd field is an imported module ("source") and +# the 4th field is a module that imports it ("target"). +# so we want the sources that are not targets. +mathlibNonImportingFiles () { +lake exe graph | + awk -F'"' '($4 ~ ".") { sources[$2]; targets[$4] } + END{ + printf "for f in" + for(t in sources) { if(!(t in targets)) { + gsub(/\./, "/", t) + print t".lean" + } } + }' +} + +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) 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 bb471f1ba4099..f45895008d4a0 100755 --- a/scripts/install_macos.sh +++ b/scripts/install_macos.sh @@ -1,24 +1,30 @@ #!/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' -# Install Homebrew -if ! which brew > /dev/null; then - # Install Homebrew - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" -else - # Update it, in case it has been ages since it's been updated - brew update -fi +set -x +# Install elan using the official script curl https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh -sSf | sh + +# Set the default Lean version to the latest stable release elan toolchain install stable elan default stable -# Install and configure VS Code -if ! which code > /dev/null; then - brew install --cask visual-studio-code -fi +# 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 + +# Add the VS Code binary to the PATH to enable launching from the terminal +cat << EOF >> ~/.zprofile +# Add Visual Studio Code (code) +export PATH="\$PATH:/Applications/Visual Studio Code.app/Contents/Resources/app/bin" +EOF # 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 df6bcb257f4fb..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 - echo "Adding labels breaks-mathlib and release-ci" + $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 \ - -d '{"labels":["breaks-mathlib", "release-ci"]}' + $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 93a1068c14cad..a7eb1c953caa1 100644 --- a/scripts/lint-style.lean +++ b/scripts/lint-style.lean @@ -14,22 +14,27 @@ This files defines the `lint-style` executable which runs all text-based style l The linters themselves are defined in `Mathlib.Tactic.Linter.TextBased`. -/ -open Cli +open Cli Mathlib.Linter.TextBased /-- Implementation of the `lint-style` command line program. -/ def lintStyleCli (args : Cli.Parsed) : IO UInt32 := do - let mode : OutputSetting := match (args.hasFlag "update", args.hasFlag "github") with - | (true, _) => OutputSetting.update - | (false, true) => OutputSetting.print ErrorFormat.github - | (false, false) => OutputSetting.print ErrorFormat.humanReadable + let style : ErrorFormat := match args.hasFlag "github" with + | true => ErrorFormat.github + | false => ErrorFormat.humanReadable + let fix := args.hasFlag "fix" -- Read all module names to lint. let mut allModules := #[] for s in ["Archive.lean", "Counterexamples.lean", "Mathlib.lean"] do allModules := allModules.append ((← IO.FS.lines s).map (·.stripPrefix "import ")) - let numberErrorFiles ← lintModules allModules mode - -- Make sure to return an exit code of at most 125, so this return value can be used further - -- in shell scripts. - return min numberErrorFiles 125 + -- note: since we manually add "Batteries" to "Mathlib.lean", we remove it here manually + allModules := allModules.erase "Batteries" + let numberErrorFiles ← lintModules allModules style fix + -- 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 /-- Setting up command line options and help text for `lake exe lint-style`. -/ -- so far, no help options or so: perhaps that is fine? @@ -41,11 +46,7 @@ def lintStyle : Cmd := `[Cli| FLAGS: github; "Print errors in a format suitable for github problem matchers\n\ otherwise, produce human-readable output" - update; "Also update the style exceptions file.\ - This adds entries for any new exceptions, removes any entries which are no longer necessary,\ - and tries to not modify exception entries unless necessary. - To fully regenerate the list of style exceptions, delete `style-exceptions.txt` - and run this script again with this flag." + fix; "Automatically fix the style error, if possible" ] /-- The entry point to the `lake exe lint-style` command. -/ diff --git a/scripts/lint-style.py b/scripts/lint-style.py index 43e6f34940475..face057f0f464 100755 --- a/scripts/lint-style.py +++ b/scripts/lint-style.py @@ -26,8 +26,6 @@ Do not add new linters here; please write them in Lean instead. To run all style linters, run `lake exe lint-style`. -To update the list of allowed/ignored style exceptions, use - $ lake exe lint-style --update """ # TODO: This is adapted from the linter for mathlib3. It should be rewritten in Lean. @@ -40,9 +38,7 @@ ERR_MOD = 2 # module docstring ERR_IBY = 11 # isolated by ERR_IWH = 22 # isolated where -ERR_DOT = 12 # isolated or low focusing dot ERR_SEM = 13 # the substring " ;" -ERR_WIN = 14 # Windows line endings "\r\n" ERR_TWS = 15 # trailing whitespace ERR_CLN = 16 # line starts with a colon ERR_IND = 17 # second line not correctly indented @@ -50,25 +46,9 @@ ERR_NSP = 20 # non-terminal simp exceptions = [] - -SCRIPTS_DIR = Path(__file__).parent.resolve() -ROOT_DIR = SCRIPTS_DIR.parent - - -with SCRIPTS_DIR.joinpath("style-exceptions.txt").open(encoding="utf-8") as f: - for exline in f: - filename, _, _, _, _, errno, *extra = exline.split() - path = ROOT_DIR / filename - if errno == "ERR_MOD": - exceptions += [(ERR_MOD, path, None)] - elif errno in ["ERR_LIN", "ERR_ADN", "ERR_NUM_LIN"]: - pass # maintained by the Lean style linter now - else: - print(f"Error: unexpected errno in style-exceptions.txt: {errno}") - sys.exit(1) - new_exceptions = False + def annotate_comments(enumerate_lines): """ Take a list of tuples of enumerated lines of the form @@ -131,9 +111,6 @@ def line_endings_check(lines, path): errors = [] newlines = [] for line_nr, line in lines: - if "\r\n" in line: - errors += [(ERR_WIN, line_nr, path)] - line = line.replace("\r\n", "\n") if line.endswith(" \n"): errors += [(ERR_TWS, line_nr, path)] line = line.rstrip() + "\n" @@ -264,11 +241,6 @@ def isolated_by_dot_semicolon_check(lines, path): line = f"{indent}{line.lstrip()[3:]}" elif line.lstrip() == "where": errors += [(ERR_IWH, line_nr, path)] - if line.lstrip().startswith(". "): - errors += [(ERR_DOT, line_nr, path)] - line = line.replace(". ", "· ", 1) - if line.strip() in (".", "·"): - errors += [(ERR_DOT, line_nr, path)] if " ;" in line: errors += [(ERR_SEM, line_nr, path)] line = line.replace(" ;", ";") @@ -293,18 +265,10 @@ def left_arrow_check(lines, path): return errors, newlines def output_message(path, line_nr, code, msg): - if len(exceptions) == 0: - # we are generating a new exceptions file - # filename first, then line so that we can call "sort" on the output - print(f"{path} : line {line_nr} : {code} : {msg}") - else: - if code.startswith("ERR"): - msg_type = "error" - if code.startswith("WRN"): - msg_type = "warning" - # We are outputting for github. We duplicate path, line_nr and code, - # so that they are also visible in the plaintext output. - print(f"::{msg_type} file={path},line={line_nr},code={code}::{path}:{line_nr} {code}: {msg}") + # We are outputting for github. We duplicate path, line_nr and code, + # so that they are also visible in the plaintext output. + print(f"::error file={path},line={line_nr},code={code}::{path}:{line_nr} {code}: {msg}") + def format_errors(errors): global new_exceptions @@ -318,12 +282,8 @@ def format_errors(errors): output_message(path, line_nr, "ERR_IBY", "Line is an isolated 'by'") if errno == ERR_IWH: output_message(path, line_nr, "ERR_IWH", "Line is an isolated where") - if errno == ERR_DOT: - output_message(path, line_nr, "ERR_DOT", "Line is an isolated focusing dot or uses . instead of ·") if errno == ERR_SEM: output_message(path, line_nr, "ERR_SEM", "Line contains a space before a semicolon") - if errno == ERR_WIN: - output_message(path, line_nr, "ERR_WIN", "Windows line endings (\\r\\n) detected") if errno == ERR_TWS: output_message(path, line_nr, "ERR_TWS", "Trailing whitespace detected on line") if errno == ERR_CLN: diff --git a/scripts/lint-style.sh b/scripts/lint-style.sh deleted file mode 100755 index 91d550ab65b55..0000000000000 --- a/scripts/lint-style.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env bash - -set -exo pipefail - -# # Style linter - -# ## Usage - -# Run this script from the root of mathlib using: -# ./scripts/lint-style.sh - -# ## Purpose - -# The style linter checks for new style issues, -# and maintains a list of exceptions for legacy reasons. -# Ideally, the length of the list of exceptions tends to 0. - -# Examples of issues that are checked for are: -# * existence of copyright header -# * existence of module docstrings (in the right place) -# * line length <= 100 (unless URL) - -# ## Implementation details - -# There are two parts. -# 1. A Python script `scripts/lint-style.py` that lints the contents of a Lean file. -# This script is called below on all Lean files in the repository. -# Exceptions are maintained in `scripts/style-exceptions.txt`. -# (Rewriting these checks in Lean is work in progress.) -# 2. The remainder of this shell script -# contains a lint on the global repository. -# -# TODO: This is adapted from the linter for mathlib3. It should be rewritten in Lean. - -################################################################################ - -# 1. Call the Lean file linter, implemented in Python - -touch scripts/style-exceptions.txt - -git ls-files 'Mathlib/*.lean' | xargs ./scripts/lint-style.py "$@" -git ls-files 'Archive/*.lean' | xargs ./scripts/lint-style.py "$@" -git ls-files 'Counterexamples/*.lean' | xargs ./scripts/lint-style.py "$@" - -# Call the in-progress Lean rewrite of these Python lints. -lake exe lint-style --github - -# 2. Global checks on the mathlib repository - -executable_files="$(find . -name '*.lean' -type f \( -perm -u=x -o -perm -g=x -o -perm -o=x \))" - -if [[ -n "$executable_files" ]] -then - echo "ERROR: The following Lean files have the executable bit set." - echo "$executable_files" - exit 1 -fi diff --git a/scripts/mk_all.lean b/scripts/mk_all.lean index 607a868e518e4..309a4bf49d2c4 100644 --- a/scripts/mk_all.lean +++ b/scripts/mk_all.lean @@ -50,7 +50,10 @@ def mkAllCLI (args : Parsed) : IO UInt32 := do let mut updates := 0 for d in libs.reverse do -- reverse to create `Mathlib/Tactic.lean` before `Mathlib.lean` let fileName := addExtension d "lean" - let allFiles ← getAllModulesSorted git d + let mut allFiles ← getAllModulesSorted git d + -- mathlib exception: manually import Batteries in `Mathlib.lean` + if d == "Mathlib" then + allFiles := #["Batteries"] ++ allFiles let fileContent := ("\n".intercalate (allFiles.map ("import " ++ ·)).toList).push '\n' if !(← pathExists fileName) then if check then @@ -61,7 +64,8 @@ def mkAllCLI (args : Parsed) : IO UInt32 := do updates := updates + 1 else if (← IO.FS.readFile fileName) != fileContent then if check then - IO.println s!"The file '{fileName}' is out of date: run `lake exe mk_all{if git then " --git" else ""}` to update it" + IO.println s!"The file '{fileName}' is out of date: \ + run `lake exe mk_all{if git then " --git" else ""}` to update it" else IO.println s!"Updating '{fileName}'" IO.FS.writeFile fileName fileContent diff --git a/scripts/no_lints_prime_decls.txt b/scripts/no_lints_prime_decls.txt new file mode 100644 index 0000000000000..b2fa718c5be98 --- /dev/null +++ b/scripts/no_lints_prime_decls.txt @@ -0,0 +1,4879 @@ +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' +Embedding.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' +Inducing.continuousAt_iff' +Inducing.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' +OpenEmbedding.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_eq_natTrailingDegree' +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'' +quotientMap_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'.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.openEmbedding_iff_comp_isIso' +TopCat.openEmbedding_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.openEmbedding' +TopologicalSpace.Opens.set_range_forget_map_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.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 efee926577dd7..9467ae24e5650 100644 --- a/scripts/nolints-style.txt +++ b/scripts/nolints-style.txt @@ -1,9 +1,11 @@ -- Manual exceptions for the text-based linters. --- This file is to `style-exceptions.txt` what `nolints.json` is to `@nolint` attributes: --- The latter is supposed to become and stay mostly empty over time (though files longer than --- 1500 lines can be transient exceptions for some longer time period), --- the former could be necessary in the long term. --- In this case, it's a side-effect of making the linter stricter than its Python ancestor. +-- The entries in this file could be necessary in the long term. +-- In some cases, entries are a side effect of making the linter stricter than its Python ancestor. + +-- The `Mathlib/Init.lean` files does not have a copyright header +Mathlib/Init.lean : line 2 : ERR_COP : Malformed or missing copyright header: Copyright line is malformed +Mathlib/Init.lean : line 3 : ERR_COP : Malformed or missing copyright header: Second line should be "Released under Apache 2.0 license as described in the file LICENSE." +Mathlib/Init.lean : line 4 : ERR_COP : Malformed or missing copyright header: The third line should describe the file's main authors -- This file was recognised as import-only by the old heuristic, but not by the new, simpler one. Mathlib/Tactic/Linter.lean : line 2 : ERR_COP : Malformed or missing copyright header: Copyright line is malformed @@ -24,8 +26,9 @@ Mathlib/Tactic/AdaptationNote.lean : line 21 : ERR_ADN : Found the string "Adapt Mathlib/Tactic/AdaptationNote.lean : line 27 : ERR_ADN : Found the string "Adaptation note:", please use the #adaptation_note command instead Mathlib/Tactic/AdaptationNote.lean : line 39 : ERR_ADN : Found the string "Adaptation note:", please use the #adaptation_note command instead Mathlib/Tactic/AdaptationNote.lean : line 52 : ERR_ADN : Found the string "Adaptation note:", please use the #adaptation_note command instead -Mathlib/Tactic/Linter/TextBased.lean : line 33 : ERR_ADN : Found the string "Adaptation note:", please use the #adaptation_note command instead -Mathlib/Tactic/Linter/TextBased.lean : line 60 : ERR_ADN : Found the string "Adaptation note:", please use the #adaptation_note command instead -Mathlib/Tactic/Linter/TextBased.lean : line 222 : ERR_ADN : Found the string "Adaptation note:", please use the #adaptation_note command instead -Mathlib/Tactic/Linter/TextBased.lean : line 227 : ERR_ADN : Found the string "Adaptation note:", please use the #adaptation_note command instead -Mathlib/Tactic/Linter/TextBased.lean : line 228 : ERR_ADN : Found the string "Adaptation note:", please use the #adaptation_note command instead +Mathlib/Tactic/Linter/TextBased.lean : line 20 : ERR_ADN : Found the string "Adaptation note:", please use the #adaptation_note command instead +Mathlib/Tactic/Linter/TextBased.lean : line 49 : ERR_ADN : Found the string "Adaptation note:", please use the #adaptation_note command instead +Mathlib/Tactic/Linter/TextBased.lean : line 84 : ERR_ADN : Found the string "Adaptation note:", please use the #adaptation_note command instead +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 diff --git a/scripts/nolints.json b/scripts/nolints.json index 9642b4626c92c..8ea41fbf362a9 100644 --- a/scripts/nolints.json +++ b/scripts/nolints.json @@ -6,32 +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", "bit0"], - ["docBlame", "bit1"], ["docBlame", "cancelDenominators"], ["docBlame", "cancelDenominatorsAt"], ["docBlame", "cancelDenominatorsTarget"], @@ -51,13 +42,11 @@ ["docBlame", "«term_≃ᵃⁱ[_]_»"], ["docBlame", "«term_≃ᵈ_»"], ["docBlame", "«term_≡_[SMOD_]»"], - ["docBlame", "termℤ"], ["docBlame", "«termℤ√_»"], ["docBlame", "«term∫_In_.._,_»"], ["docBlame", "«term∫_In_.._,_∂_»"], ["docBlame", "«term∮_InC(_,_),_»"], ["docBlame", "«term⨍_In_.._,_»"], - ["docBlame", "timeCmd"], ["docBlame", "when"], ["docBlame", "whenM"], ["docBlame", "Action.V"], @@ -80,7 +69,6 @@ ["docBlame", "Bitraversable.bitraverse"], ["docBlame", "BoundedContinuousFunction.«term_→ᵇ_»"], ["docBlame", "BoundedRandom.randomR"], - ["docBlame", "BumpCovering.toFun"], ["docBlame", "ByteSlice.arr"], ["docBlame", "ByteSlice.len"], ["docBlame", "ByteSlice.off"], @@ -279,11 +267,9 @@ ["docBlame", "Nat.subInduction"], ["docBlame", "Nat.«termOrd_compl[_]_»"], ["docBlame", "Nat.«termOrd_proj[_]_»"], - ["docBlame", "Nat.twoStepInduction"], ["docBlame", "One.one"], ["docBlame", "OptionT.callCC"], ["docBlame", "OptionT.mkLabel"], - ["docBlame", "PartitionOfUnity.toFun"], ["docBlame", "PicardLindelof.C"], ["docBlame", "PicardLindelof.L"], ["docBlame", "PicardLindelof.R"], @@ -298,7 +284,6 @@ ["docBlame", "PowerBasis.basis"], ["docBlame", "PowerBasis.dim"], ["docBlame", "PowerBasis.gen"], - ["docBlame", "PresheafOfModules.presheaf"], ["docBlame", "Pretrivialization.baseSet"], ["docBlame", "PrimeSpectrum.asIdeal"], ["docBlame", "ProbabilityTheory.«termEVar[_]»"], @@ -306,9 +291,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∂_/∂_»"], @@ -321,9 +304,6 @@ ["docBlame", "QPF.repr"], ["docBlame", "QuadraticMap.toFun"], ["docBlame", "Quaternion.«termℍ[_]»"], - ["docBlame", "QuaternionAlgebra.imI"], - ["docBlame", "QuaternionAlgebra.imJ"], - ["docBlame", "QuaternionAlgebra.imK"], ["docBlame", "RCLike.im"], ["docBlame", "RCLike.re"], ["docBlame", "Random.randBool"], @@ -340,7 +320,6 @@ ["docBlame", "SchwartzMap.toFun"], ["docBlame", "SemiRingCat.forget_obj_eq_coe"], ["docBlame", "Semigrp.forget_obj_eq_coe"], - ["docBlame", "Set.«term{_|_}»"], ["docBlame", "Shrink.rec"], ["docBlame", "SlashAction.map"], ["docBlame", "SlashInvariantForm.toFun"], @@ -394,7 +373,6 @@ ["docBlame", "WriterT.mkLabel'"], ["docBlame", "WriterT.run"], ["docBlame", "WriterT.runThe"], - ["docBlame", "Zero.zero"], ["docBlame", "Zsqrtd.im"], ["docBlame", "Zsqrtd.re"], ["docBlame", "algebraMap.coeHTCT"], @@ -430,8 +408,6 @@ ["docBlame", "CategoryTheory.Comma.right"], ["docBlame", "CategoryTheory.CommaMorphism.left"], ["docBlame", "CategoryTheory.CommaMorphism.right"], - ["docBlame", "CategoryTheory.Comonad.δ'"], - ["docBlame", "CategoryTheory.Comonad.ε'"], ["docBlame", "CategoryTheory.EnrichedCategory.Hom"], ["docBlame", "CategoryTheory.EnrichedCategory.comp"], ["docBlame", "CategoryTheory.EnrichedCategory.id"], @@ -444,8 +420,6 @@ ["docBlame", "CategoryTheory.GlueData.t"], ["docBlame", "CategoryTheory.GlueData.t'"], ["docBlame", "CategoryTheory.GradedNatTrans.app"], - ["docBlame", - "CategoryTheory.GrothendieckTopology.sheafificationIsoPresheafToSheafCompSheafToPreasheaf"], ["docBlame", "CategoryTheory.HalfBraiding.β"], ["docBlame", "CategoryTheory.Mat_.X"], ["docBlame", "CategoryTheory.Mat_.ι"], @@ -454,8 +428,6 @@ ["docBlame", "CategoryTheory.Monad.PreservesColimitOfIsReflexivePair"], ["docBlame", "CategoryTheory.Monad.PreservesColimitOfIsSplitPair"], ["docBlame", "CategoryTheory.Monad.ReflectsColimitOfIsSplitPair"], - ["docBlame", "CategoryTheory.Monad.η'"], - ["docBlame", "CategoryTheory.Monad.μ'"], ["docBlame", "CategoryTheory.Presieve.yonedaFamilyOfElements_fromCocone"], ["docBlame", "CategoryTheory.Pretopology.coverings"], ["docBlame", "CategoryTheory.ProjectivePresentation.f"], @@ -492,7 +464,6 @@ ["docBlame", "GromovHausdorff.AuxGluingStruct.Space"], ["docBlame", "GromovHausdorff.AuxGluingStruct.embed"], ["docBlame", "GromovHausdorff.AuxGluingStruct.metric"], - ["docBlame", "HahnSeries.SummableFamily.toFun"], ["docBlame", "HomogeneousLocalization.NumDenSameDeg.deg"], ["docBlame", "HomogeneousLocalization.NumDenSameDeg.den"], ["docBlame", "HomogeneousLocalization.NumDenSameDeg.num"], @@ -500,7 +471,6 @@ ["docBlame", "Ideal.Filtration.N"], ["docBlame", "IntermediateField.delabAdjoinNotation.delabInsertArray"], ["docBlame", "IsDedekindDomain.HeightOneSpectrum.asIdeal"], - ["docBlame", "Lean.Attr.substAttr"], ["docBlame", "Lean.Export.Alloc"], ["docBlame", "Lean.Export.Entry"], ["docBlame", "Lean.Export.OfState"], @@ -518,10 +488,6 @@ ["docBlame", "Lean.Expr.modifyRevArg"], ["docBlame", "Lean.MVarId.casesType"], ["docBlame", "Lean.MVarId.congrCore!"], - ["docBlame", "Lean.Meta.checkTypeIsProp"], - ["docBlame", "Lean.Meta.mkSimpTheoremCore"], - ["docBlame", "Lean.Meta.preprocess"], - ["docBlame", "Lean.Meta.shouldPreprocess"], ["docBlame", "Lean.Name.isBlackListed"], ["docBlame", "Lean.PHashSet.toList"], ["docBlame", "LocallyFinite.Realizer.bas"], @@ -531,115 +497,18 @@ ["docBlame", "Mathlib.Notation3.expandFoldl"], ["docBlame", "Mathlib.Notation3.expandFoldr"], ["docBlame", "Mathlib.Notation3.prettyPrintOpt"], - ["docBlame", "Mathlib.Tactic.abstract"], - ["docBlame", "Mathlib.Tactic.acMono"], - ["docBlame", "Mathlib.Tactic.addTacticDoc"], - ["docBlame", "Mathlib.Tactic.applyField"], - ["docBlame", "Mathlib.Tactic.applyNormed"], - ["docBlame", "Mathlib.Tactic.assertInstance"], - ["docBlame", "Mathlib.Tactic.assertNoInstance"], - ["docBlame", "Mathlib.Tactic.assocRw"], - ["docBlame", "Mathlib.Tactic.async"], - ["docBlame", "Mathlib.Tactic.cases'"], - ["docBlame", "Mathlib.Tactic.cases''"], - ["docBlame", "Mathlib.Tactic.clarify"], - ["docBlame", "Mathlib.Tactic.compVal"], - ["docBlame", "Mathlib.Tactic.computeDegreeLE"], - ["docBlame", "Mathlib.Tactic.continue"], - ["docBlame", "Mathlib.Tactic.decide!"], - ["docBlame", "Mathlib.Tactic.defReplacer"], - ["docBlame", "Mathlib.Tactic.deltaInstance"], - ["docBlame", "Mathlib.Tactic.deriveElementwiseProof"], - ["docBlame", "Mathlib.Tactic.deriveReassocProof"], - ["docBlame", "Mathlib.Tactic.dsimpResult"], ["docBlame", "Mathlib.Tactic.elabConfig"], - ["docBlame", "Mathlib.Tactic.elabVariables"], - ["docBlame", "Mathlib.Tactic.elide"], - ["docBlame", "Mathlib.Tactic.equivRw"], - ["docBlame", "Mathlib.Tactic.equivRwType"], ["docBlame", "Mathlib.Tactic.evalIntrov"], - ["docBlame", "Mathlib.Tactic.expandExists"], - ["docBlame", "Mathlib.Tactic.extractGoal!"], - ["docBlame", "Mathlib.Tactic.failIfSuccess?"], - ["docBlame", "Mathlib.Tactic.field"], - ["docBlame", "Mathlib.Tactic.finish"], - ["docBlame", "Mathlib.Tactic.fixingClause"], - ["docBlame", "Mathlib.Tactic.generalizes"], - ["docBlame", "Mathlib.Tactic.generalizesArg"], - ["docBlame", "Mathlib.Tactic.generalizingClause"], - ["docBlame", "Mathlib.Tactic.guardProofTerm"], - ["docBlame", "Mathlib.Tactic.guardTags"], - ["docBlame", "Mathlib.Tactic.hGeneralize"], - ["docBlame", "Mathlib.Tactic.hGeneralize!"], - ["docBlame", "Mathlib.Tactic.haveField"], - ["docBlame", "Mathlib.Tactic.include"], - ["docBlame", "Mathlib.Tactic.induction'"], - ["docBlame", "Mathlib.Tactic.induction''"], - ["docBlame", "Mathlib.Tactic.injectionsAndClear"], - ["docBlame", "Mathlib.Tactic.interactive"], - ["docBlame", "Mathlib.Tactic.intro"], - ["docBlame", "Mathlib.Tactic.intro!"], - ["docBlame", "Mathlib.Tactic.isBounded_default"], - ["docBlame", "Mathlib.Tactic.listUnusedDecls"], - ["docBlame", "Mathlib.Tactic.mapply"], - ["docBlame", "Mathlib.Tactic.matchHyp"], - ["docBlame", "Mathlib.Tactic.mkDecorations"], - ["docBlame", "Mathlib.Tactic.mvBisim"], - ["docBlame", "Mathlib.Tactic.notationClass"], - ["docBlame", "Mathlib.Tactic.nthRwLHS"], - ["docBlame", "Mathlib.Tactic.nthRwRHS"], - ["docBlame", "Mathlib.Tactic.obviously"], - ["docBlame", "Mathlib.Tactic.omit"], - ["docBlame", "Mathlib.Tactic.padicIndexSimp"], - ["docBlame", "Mathlib.Tactic.parameter"], - ["docBlame", "Mathlib.Tactic.piInstance"], - ["docBlame", "Mathlib.Tactic.piInstanceDeriveField"], - ["docBlame", "Mathlib.Tactic.prettyCases"], - ["docBlame", "Mathlib.Tactic.printSorryIn"], - ["docBlame", "Mathlib.Tactic.propagateTags"], - ["docBlame", "Mathlib.Tactic.protectProj"], - ["docBlame", "Mathlib.Tactic.rcases?"], - ["docBlame", "Mathlib.Tactic.reassoc"], - ["docBlame", "Mathlib.Tactic.reassoc!"], - ["docBlame", "Mathlib.Tactic.reassocAxiom"], - ["docBlame", "Mathlib.Tactic.refineStruct"], - ["docBlame", "Mathlib.Tactic.renameArg"], - ["docBlame", "Mathlib.Tactic.revertAfter"], - ["docBlame", "Mathlib.Tactic.revertDeps"], - ["docBlame", "Mathlib.Tactic.revertTargetDeps"], - ["docBlame", "Mathlib.Tactic.rintro?"], - ["docBlame", "Mathlib.Tactic.rsimp"], - ["docBlame", "Mathlib.Tactic.safe"], - ["docBlame", "Mathlib.Tactic.sample"], ["docBlame", "Mathlib.Tactic.setArgsRest"], ["docBlame", "Mathlib.Tactic.setTactic"], - ["docBlame", "Mathlib.Tactic.simpResult"], - ["docBlame", "Mathlib.Tactic.subtypeInstance"], - ["docBlame", "Mathlib.Tactic.suggest"], - ["docBlame", "Mathlib.Tactic.tacticDestruct_"], ["docBlame", "Mathlib.Tactic.tacticHave_"], ["docBlame", "Mathlib.Tactic.tacticLet_"], ["docBlame", "Mathlib.Tactic.tacticMatch_target_"], ["docBlame", "Mathlib.Tactic.tacticSet!_"], ["docBlame", "Mathlib.Tactic.tacticSuffices_"], ["docBlame", "Mathlib.Tactic.tacticTransitivity___"], - ["docBlame", "Mathlib.Tactic.tidy"], - ["docBlame", "Mathlib.Tactic.tidy?"], - ["docBlame", "Mathlib.Tactic.transport"], - ["docBlame", "Mathlib.Tactic.truncCases"], - ["docBlame", "Mathlib.Tactic.tryFor"], - ["docBlame", "Mathlib.Tactic.unelide"], - ["docBlame", "Mathlib.Tactic.unfoldAux"], - ["docBlame", "Mathlib.Tactic.unfoldCases"], - ["docBlame", "Mathlib.Tactic.unfoldCoes"], - ["docBlame", "Mathlib.Tactic.unfoldWf"], - ["docBlame", "Mathlib.Tactic.uniqueDiffWithinAt_Ici_Iic_univ"], - ["docBlame", "Mathlib.Tactic.unitInterval"], ["docBlame", "Mathlib.Tactic.usingArg"], - ["docBlame", "Mathlib.Tactic.variables"], ["docBlame", "Mathlib.Tactic.withArgs"], - ["docBlame", "Mathlib.Tactic.withPattern"], - ["docBlame", "Mathlib.Tactic.wittTruncateFunTac"], ["docBlame", "Mathlib.WhatsNew.diffExtension"], ["docBlame", "Mathlib.WhatsNew.whatsNew"], ["docBlame", "Matrix.TransvectionStruct.c"], @@ -671,14 +540,12 @@ ["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"], ["docBlame", "QuaternionAlgebra.Basis.k"], ["docBlame", "Sat.Clause.cons"], ["docBlame", "Sat.Clause.nil"], - ["docBlame", "Set.setOf.unexpander"], ["docBlame", "SimpleGraph.Subgraph.Adj"], ["docBlame", "SimpleGraph.Subgraph.verts"], ["docBlame", "SimpleGraph.Walk.notNilRec"], @@ -703,7 +570,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!___"], @@ -761,7 +627,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"], @@ -847,10 +712,10 @@ ["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.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.evalMinFac.aux"], ["docBlame", "Mathlib.Meta.NormNum.evalMinFac.core"], ["docBlame", "Mathlib.Meta.NormNum.evalNatPrime.core"], @@ -886,4 +751,4 @@ ["docBlame", "Mathlib.Meta.NormNum.evalAdd.core.ratArm"], ["docBlame", "Mathlib.Meta.NormNum.evalMul.core.intArm"], ["docBlame", "Mathlib.Meta.NormNum.evalMul.core.ratArm"], - ["unusedArguments", "Combinator.K"]] + ["unusedArguments", "Combinator.K"]] diff --git a/scripts/noshake.json b/scripts/noshake.json index 021b8a75f57ef..6448419d87171 100644 --- a/scripts/noshake.json +++ b/scripts/noshake.json @@ -39,6 +39,7 @@ "Mathlib.CategoryTheory.Category.Init", "Mathlib.Combinatorics.SimpleGraph.Init", "Mathlib.Control.Traversable.Lemmas", + "Mathlib.Data.Finsupp.Notation", "Mathlib.Data.Int.Defs", "Mathlib.Data.Matrix.Notation", "Mathlib.Data.Matroid.Init", @@ -48,6 +49,7 @@ "Mathlib.Data.Sym.Sym2.Init", "Mathlib.Data.Vector.Basic", "Mathlib.Geometry.Manifold.Instances.Real", + "Mathlib.Init", "Mathlib.Init.Align", "Mathlib.LinearAlgebra.AffineSpace.Basic", "Mathlib.Mathport.Attributes", @@ -100,7 +102,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", @@ -192,8 +194,10 @@ "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.Data.Set.Pointwise.Basic"], + {"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.Germ": ["Mathlib.Analysis.Normed.Module.Basic"], "Mathlib.Topology.Defs.Basic": ["Mathlib.Tactic.FunProp"], "Mathlib.Topology.Category.UniformSpace": @@ -208,7 +212,7 @@ "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"], @@ -233,10 +237,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"], @@ -268,10 +273,14 @@ "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": ["Mathlib.CategoryTheory.Functor.Basic"], + "Mathlib.Tactic.CategoryTheory.Monoidal": + ["Mathlib.Tactic.CategoryTheory.MonoidalComp"], "Mathlib.Tactic.CategoryTheory.Coherence": ["Mathlib.CategoryTheory.Monoidal.Free.Coherence", "Mathlib.Tactic.CategoryTheory.MonoidalComp"], @@ -293,12 +302,23 @@ "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"], + "Mathlib.RepresentationTheory.FDRep": + ["Mathlib.CategoryTheory.Monoidal.Rigid.Braided"], "Mathlib.Probability.Notation": ["Mathlib.MeasureTheory.Decomposition.Lebesgue", "Mathlib.MeasureTheory.Function.ConditionalExpectation.Basic"], @@ -322,14 +342,9 @@ "Mathlib.LinearAlgebra.AffineSpace.FiniteDimensional": ["Mathlib.Init.Core"], "Mathlib.LinearAlgebra.AffineSpace.Basic": ["Mathlib.Algebra.AddTorsor"], "Mathlib.Lean.Meta": ["Batteries.Logic"], - "Mathlib.Lean.Expr.ExtraRecognizers": ["Mathlib.Data.Set.Defs"], + "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.Init.Data.List.Lemmas": ["Batteries.Data.List.Lemmas"], - "Mathlib.Init.Data.List.Basic": ["Batteries.Data.List.Basic"], - "Mathlib.Init.Data.Int.Order": ["Mathlib.Data.Int.Notation"], - "Mathlib.Init.Data.Int.Basic": ["Batteries.Data.Int.Order"], - "Mathlib.Init.Data.Bool.Lemmas": ["Mathlib.Tactic.AdaptationNote"], "Mathlib.GroupTheory.MonoidLocalization.Basic": ["Mathlib.Init.Data.Prod"], "Mathlib.Geometry.Manifold.Sheaf.Smooth": ["Mathlib.CategoryTheory.Sites.Whiskering"], @@ -350,12 +365,14 @@ ["Batteries.Data.Nat.Lemmas", "Mathlib.Data.List.Basic"], "Mathlib.Data.List.Lemmas": ["Mathlib.Data.List.InsertNth"], "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"], "Mathlib.Control.Monad.Cont": ["Batteries.Tactic.Congr"], @@ -364,15 +381,27 @@ ["Mathlib.Algebra.Order.Field.Basic"], "Mathlib.CategoryTheory.Sites.IsSheafFor": ["Mathlib.CategoryTheory.Limits.Shapes.Pullback.Mono"], + "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": ["Mathlib.Algebra.Module.LinearMap.Basic"], "Mathlib.Analysis.Distribution.SchwartzSpace": ["Mathlib.Tactic.MoveAdd"], + "Mathlib.Analysis.Convex.Star": ["Mathlib.Algebra.Order.Module.Synonym"], "Mathlib.Analysis.Convex.Basic": ["Mathlib.Algebra.Order.BigOperators.Ring.Finset"], "Mathlib.Analysis.CStarAlgebra.ContinuousFunctionalCalculus.NonUnital": 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 1eda2b5b93663..f48fdd08c79a1 100755 --- a/scripts/print-style-errors.sh +++ b/scripts/print-style-errors.sh @@ -1,9 +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 --update` +# 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 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/style-exceptions.txt b/scripts/style-exceptions.txt deleted file mode 100644 index 9b6d457b4a950..0000000000000 --- a/scripts/style-exceptions.txt +++ /dev/null @@ -1,68 +0,0 @@ -Mathlib/SetTheory/Ordinal/Segfault.lean : line 6 : ERR_MOD : Module docstring missing, or too late -Mathlib/Algebra/BigOperators/Group/Finset.lean : line 1 : ERR_NUM_LIN : 2400 file contains 2245 lines, try to split it up -Mathlib/Algebra/Group/Subgroup/Basic.lean : line 1 : ERR_NUM_LIN : 3000 file contains 2893 lines, try to split it up -Mathlib/Algebra/MonoidAlgebra/Basic.lean : line 1 : ERR_NUM_LIN : 2100 file contains 1965 lines, try to split it up -Mathlib/Algebra/MvPolynomial/Basic.lean : line 1 : ERR_NUM_LIN : 1700 file contains 1544 lines, try to split it up -Mathlib/Algebra/Order/Floor.lean : line 1 : ERR_NUM_LIN : 1700 file contains 1593 lines, try to split it up -Mathlib/AlgebraicGeometry/EllipticCurve/Jacobian.lean : line 1 : ERR_NUM_LIN : 1700 file contains 1511 lines, try to split it up -Mathlib/Analysis/Asymptotics/Asymptotics.lean : line 1 : ERR_NUM_LIN : 2100 file contains 1955 lines, try to split it up -Mathlib/Analysis/Calculus/ContDiff/Basic.lean : line 1 : ERR_NUM_LIN : 2100 file contains 1952 lines, try to split it up -Mathlib/Analysis/Calculus/ContDiff/Defs.lean : line 1 : ERR_NUM_LIN : 1700 file contains 1595 lines, try to split it up -Mathlib/Analysis/InnerProductSpace/Basic.lean : line 1 : ERR_NUM_LIN : 2500 file contains 2433 lines, try to split it up -Mathlib/CategoryTheory/Limits/Shapes/Biproducts.lean : line 1 : ERR_NUM_LIN : 2100 file contains 1998 lines, try to split it up -Mathlib/Computability/TMToPartrec.lean : line 1 : ERR_NUM_LIN : 2200 file contains 2071 lines, try to split it up -Mathlib/Computability/TuringMachine.lean : line 1 : ERR_NUM_LIN : 2700 file contains 2561 lines, try to split it up -Mathlib/Data/DFinsupp/Basic.lean : line 1 : ERR_NUM_LIN : 2200 file contains 2078 lines, try to split it up -Mathlib/Data/Fin/Basic.lean : line 1 : ERR_NUM_LIN : 1700 file contains 1524 lines, try to split it up -Mathlib/Data/Finset/Basic.lean : line 1 : ERR_NUM_LIN : 3100 file contains 2999 lines, try to split it up -Mathlib/Data/Finset/Lattice.lean : line 1 : ERR_NUM_LIN : 2100 file contains 1968 lines, try to split it up -Mathlib/Data/Finset/Pointwise/Basic.lean : line 1 : ERR_NUM_LIN : 2100 file contains 1997 lines, try to split it up -Mathlib/Data/Finsupp/Basic.lean : line 1 : ERR_NUM_LIN : 1900 file contains 1703 lines, try to split it up -Mathlib/Data/List/Basic.lean : line 1 : ERR_NUM_LIN : 2700 file contains 2598 lines, try to split it up -Mathlib/Data/Matrix/Basic.lean : line 1 : ERR_NUM_LIN : 2700 file contains 2519 lines, try to split it up -Mathlib/Data/Multiset/Basic.lean : line 1 : ERR_NUM_LIN : 2900 file contains 2725 lines, try to split it up -Mathlib/Data/Num/Lemmas.lean : line 1 : ERR_NUM_LIN : 1700 file contains 1576 lines, try to split it up -Mathlib/Data/Ordmap/Ordset.lean : line 1 : ERR_NUM_LIN : 1700 file contains 1580 lines, try to split it up -Mathlib/Data/QPF/Multivariate/Basic.lean : line 76 : ERR_LIN : Line has 127 characters, which is more than 100 -Mathlib/Data/Real/EReal.lean : line 1 : ERR_NUM_LIN : 1900 file contains 1778 lines, try to split it up -Mathlib/Data/Seq/WSeq.lean : line 1 : ERR_NUM_LIN : 1800 file contains 1622 lines, try to split it up -Mathlib/Data/Set/Basic.lean : line 1 : ERR_NUM_LIN : 2300 file contains 2170 lines, try to split it up -Mathlib/Data/Set/Finite.lean : line 1 : ERR_NUM_LIN : 1700 file contains 1535 lines, try to split it up -Mathlib/Data/Set/Function.lean : line 1 : ERR_NUM_LIN : 1900 file contains 1740 lines, try to split it up -Mathlib/Data/Set/Lattice.lean : line 1 : ERR_NUM_LIN : 2100 file contains 1932 lines, try to split it up -Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean : line 1 : ERR_NUM_LIN : 1800 file contains 1693 lines, try to split it up -Mathlib/LinearAlgebra/Dual.lean : line 1 : ERR_NUM_LIN : 1900 file contains 1738 lines, try to split it up -Mathlib/LinearAlgebra/Multilinear/Basic.lean : line 1 : ERR_NUM_LIN : 1900 file contains 1775 lines, try to split it up -Mathlib/Logic/Equiv/Basic.lean : line 1 : ERR_NUM_LIN : 2000 file contains 1806 lines, try to split it up -Mathlib/MeasureTheory/Function/LpSpace.lean : line 1 : ERR_NUM_LIN : 2100 file contains 1978 lines, try to split it up -Mathlib/MeasureTheory/Function/StronglyMeasurable/Basic.lean : line 1 : ERR_NUM_LIN : 2000 file contains 1879 lines, try to split it up -Mathlib/MeasureTheory/Integral/Bochner.lean : line 1 : ERR_NUM_LIN : 2100 file contains 1947 lines, try to split it up -Mathlib/MeasureTheory/Integral/FundThmCalculus.lean : line 1 : ERR_NUM_LIN : 1800 file contains 1647 lines, try to split it up -Mathlib/MeasureTheory/Integral/Lebesgue.lean : line 1 : ERR_NUM_LIN : 2200 file contains 2051 lines, try to split it up -Mathlib/MeasureTheory/Integral/SetIntegral.lean : line 1 : ERR_NUM_LIN : 1700 file contains 1579 lines, try to split it up -Mathlib/MeasureTheory/Integral/SetToL1.lean : line 1 : ERR_NUM_LIN : 1800 file contains 1640 lines, try to split it up -Mathlib/MeasureTheory/Measure/MeasureSpace.lean : line 1 : ERR_NUM_LIN : 2200 file contains 2008 lines, try to split it up -Mathlib/Order/CompleteLattice.lean : line 1 : ERR_NUM_LIN : 1900 file contains 1709 lines, try to split it up -Mathlib/Order/ConditionallyCompleteLattice/Basic.lean : line 1 : ERR_NUM_LIN : 1700 file contains 1549 lines, try to split it up -Mathlib/Order/Filter/AtTopBot.lean : line 1 : ERR_NUM_LIN : 2000 file contains 1828 lines, try to split it up -Mathlib/Order/Filter/Basic.lean : line 1 : ERR_NUM_LIN : 3000 file contains 2898 lines, try to split it up -Mathlib/Order/Hom/Lattice.lean : line 1 : ERR_NUM_LIN : 1800 file contains 1661 lines, try to split it up -Mathlib/Order/Interval/Set/Basic.lean : line 1 : ERR_NUM_LIN : 1800 file contains 1652 lines, try to split it up -Mathlib/Order/LiminfLimsup.lean : line 1 : ERR_NUM_LIN : 1900 file contains 1791 lines, try to split it up -Mathlib/Order/UpperLower/Basic.lean : line 1 : ERR_NUM_LIN : 1900 file contains 1795 lines, try to split it up -Mathlib/RingTheory/UniqueFactorizationDomain.lean : line 1 : ERR_NUM_LIN : 2100 file contains 1982 lines, try to split it up -Mathlib/SetTheory/Cardinal/Basic.lean : line 1 : ERR_NUM_LIN : 2200 file contains 2004 lines, try to split it up -Mathlib/SetTheory/Cardinal/Ordinal.lean : line 1 : ERR_NUM_LIN : 1700 file contains 1501 lines, try to split it up -Mathlib/SetTheory/Game/PGame.lean : line 1 : ERR_NUM_LIN : 1900 file contains 1753 lines, try to split it up -Mathlib/SetTheory/Ordinal/Arithmetic.lean : line 1 : ERR_NUM_LIN : 2400 file contains 2269 lines, try to split it up -Mathlib/SetTheory/ZFC/Basic.lean : line 1 : ERR_NUM_LIN : 1700 file contains 1549 lines, try to split it up -Mathlib/Tactic/CC/Addition.lean : line 1 : ERR_NUM_LIN : 2300 file contains 2100 lines, try to split it up -Mathlib/Topology/Algebra/Group/Basic.lean : line 1 : ERR_NUM_LIN : 2100 file contains 1932 lines, try to split it up -Mathlib/Topology/Algebra/Module/Basic.lean : line 1 : ERR_NUM_LIN : 2600 file contains 2405 lines, try to split it up -Mathlib/Topology/Basic.lean : line 1 : ERR_NUM_LIN : 1900 file contains 1731 lines, try to split it up -Mathlib/Topology/Category/Profinite/Nobeling.lean : line 1 : ERR_NUM_LIN : 2000 file contains 1806 lines, try to split it up -Mathlib/Topology/Constructions.lean : line 1 : ERR_NUM_LIN : 1700 file contains 1591 lines, try to split it up -Mathlib/Topology/ContinuousFunction/Bounded.lean : line 1 : ERR_NUM_LIN : 1800 file contains 1682 lines, try to split it up -Mathlib/Topology/Instances/ENNReal.lean : line 1 : ERR_NUM_LIN : 1700 file contains 1513 lines, try to split it up -Mathlib/Topology/Separation.lean : line 1 : ERR_NUM_LIN : 2900 file contains 2716 lines, try to split it up -Mathlib/Topology/UniformSpace/Basic.lean : line 1 : ERR_NUM_LIN : 1900 file contains 1768 lines, try to split it up diff --git a/scripts/technical-debt-metrics.sh b/scripts/technical-debt-metrics.sh index 4e5f937b7aad9..ce9a3a5202b16 100755 --- a/scripts/technical-debt-metrics.sh +++ b/scripts/technical-debt-metrics.sh @@ -1,5 +1,10 @@ #!/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' + # `./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 +12,8 @@ # 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)"}" # `tdc` produces a semi-formatted output of the form # ... @@ -54,10 +49,16 @@ for i in ${!titlesAndRegexes[@]}; do done printf '%s|%s\n' "$(grep -c 'docBlame' scripts/nolints.json)" "documentation nolint entries" -printf '%s|%s\n' "$(grep -c 'ERR_NUM_LIN' scripts/style-exceptions.txt)" "large files" +# 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' initFiles="$(git ls-files '**/Init/*.lean' | xargs wc -l | sed 's=^ *==')" diff --git a/scripts/test.lean b/scripts/test.lean index 57c05c325fd17..f02a621637377 100644 --- a/scripts/test.lean +++ b/scripts/test.lean @@ -14,7 +14,8 @@ When https://github.com/leanprover/lean4/issues/4121 is resolved, this file can be replaced with a line in `lakefile.lean`. -/ def main (args : List String) : IO Unit := do - -- ProofWidgets may not have been built by `lake build` yet, but it is needed by some tests. - _ ← (← spawn { cmd := "lake", args := #["build", "ProofWidgets"] }).wait + -- 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/update_nolints_CI.sh b/scripts/update_nolints_CI.sh index 42c50b9c2074e..551b6664fa1e5 100755 --- a/scripts/update_nolints_CI.sh +++ b/scripts/update_nolints_CI.sh @@ -1,10 +1,13 @@ #!/usr/bin/env bash -# Check if there are changes to `nolints.json` or `style-exceptions.txt`, -# and file a PR updating these files otherwise. +# 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 @@ -12,17 +15,17 @@ branch_name=nolints owner_name=leanprover-community # Exit if the branch already exists -git fetch "$remote_name" +git fetch --quiet "$remote_name" git rev-parse --verify --quiet "refs/remotes/${remote_name}/${branch_name}" && exit 0 # Exit if there are no changes relative to master -git diff-index --quiet "refs/remotes/${remote_name}/master" -- scripts/nolints.json scripts/style-exceptions.txt && exit 0 +git diff-index --quiet "refs/remotes/${remote_name}/master" -- scripts/nolints.json && exit 0 -pr_title='chore(scripts): update nolints.json and style-exceptions.txt' +pr_title='chore(scripts): update nolints.json' pr_body='I am happy to remove some nolints for you!' git checkout -b "$branch_name" -git add scripts/nolints.json scripts/style-exceptions.txt +git add scripts/nolints.json git commit -m "$pr_title" gh_api() { @@ -34,7 +37,7 @@ gh_api() { git push "${remote_name}" "HEAD:$branch_name" -pr_id=$(gh_api "repos/${owner_name}/mathlib/pulls" -X POST -d @- < 0 := by bound example (h : x < y) : Real.exp (y - x) > 1 := by bound example (h : x < y) (y0 : 0 < y) : x / y < 1 := by bound @@ -42,16 +43,17 @@ section guess_tests variable {a b c : ℝ} {n m : ℕ} example (h : a ≤ b) : a ≤ max b c := by bound example (h : a ≤ c) : a ≤ max b c := by bound -example (h : a < b) : a < max b c := by bound -example (h : a < c) : a < max b c := by bound example (h : a ≤ c) : min a b ≤ c := by bound example (h : b ≤ c) : min a b ≤ c := by bound +example (h : a < b) : a < max b c := by bound +example (h : a < c) : a < max b c := by bound example (h : a < c) : min a b < c := by bound example (h : b < c) : min a b < c := by bound example (a1 : 1 ≤ a) (h : m ≤ n) : a^m ≤ a^n := by bound example (a0 : 0 ≤ a) (a1 : a ≤ 1) (h : n ≤ m) : a^m ≤ a^n := by bound example (a1 : 1 ≤ a) (h : b ≤ c) : a^b ≤ a^c := by bound example (a0 : 0 < a) (a1 : a ≤ 1) (h : c ≤ b) : a^b ≤ a^c := by bound + end guess_tests section positive_tests @@ -108,6 +110,7 @@ example (h : x > 0) : x ≥ 0 := by bound example (hc : c ≥ 0) (h : a ≤ b) : a / c ≤ b / c := by bound example (ha : a ≥ 0) (hc : c > 0) (h : b ≥ c) : a / b ≤ a / c := by bound example (x y : ℝ) (x0 : 0 < x) (h : x ≤ y) : x.log ≤ y.log := by bound + end bound_tests /-- This broke without appropriate `g.withContext` use in an older implementation of `bound`. 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/Coherence.lean b/test/CategoryTheory/Coherence.lean index 14f04ea1f2efb..35f0cdf3b3148 100644 --- a/test/CategoryTheory/Coherence.lean +++ b/test/CategoryTheory/Coherence.lean @@ -4,7 +4,7 @@ open CategoryTheory universe w v u -section monoidal +section Monoidal variable {C : Type u} [Category.{v} C] [MonoidalCategory C] open scoped MonoidalCategory @@ -79,7 +79,7 @@ example (X₁ X₂ : C) : (𝟙 (X₁ ⊗ X₂) ⊗ (λ_ (𝟙_ C)).inv) := by coherence -end monoidal +end Monoidal section Bicategory @@ -106,6 +106,7 @@ example (f : a ⟶ b) (g : b ⟶ c) : example : 𝟙 (𝟙 a ≫ 𝟙 a) ≫ (λ_ (𝟙 a)).hom = 𝟙 (𝟙 a ≫ 𝟙 a) ≫ (ρ_ (𝟙 a)).hom := by bicategory_coherence +set_option linter.unusedVariables false in example (f g : a ⟶ a) (η : 𝟙 a ⟶ f) (θ : f ⟶ g) (w : false) : (λ_ (𝟙 a)).hom ≫ η ≫ θ = (ρ_ (𝟙 a)).hom ≫ η ≫ θ := by coherence diff --git a/test/CategoryTheory/Elementwise.lean b/test/CategoryTheory/Elementwise.lean index 9117dd1581f56..4b8056c788b1f 100644 --- a/test/CategoryTheory/Elementwise.lean +++ b/test/CategoryTheory/Elementwise.lean @@ -1,12 +1,11 @@ import Mathlib.Tactic.CategoryTheory.Elementwise ---import Mathlib.Algebra.Category.Mon.Basic +import Mathlib.Algebra.Category.MonCat.Basic set_option autoImplicit true namespace ElementwiseTest open CategoryTheory -set_option linter.existingAttributeWarning false in attribute [simp] Iso.hom_inv_id Iso.inv_hom_id IsIso.hom_inv_id IsIso.inv_hom_id attribute [local instance] ConcreteCategory.instFunLike ConcreteCategory.hasCoeToSort @@ -82,22 +81,20 @@ example {C : Type u} [Category.{v} C] [ConcreteCategory.{w} C] rw [this] section Mon --- TODO: switch to actual Mon when it is ported -variable (Mon : Type _) [Category Mon] [ConcreteCategory Mon] -lemma bar' {M N K : Mon} {f : M ⟶ N} {g : N ⟶ K} {h : M ⟶ K} (w : f ≫ g = h) (x : M) : +lemma bar' {M N K : MonCat} {f : M ⟶ N} {g : N ⟶ K} {h : M ⟶ K} (w : f ≫ g = h) (x : M) : g (f x) = h x := by exact foo_apply w x -lemma bar'' {M N K : Mon} {f : M ⟶ N} {g : N ⟶ K} {h : M ⟶ K} (w : f ≫ g = h) (x : M) : +lemma bar'' {M N K : MonCat} {f : M ⟶ N} {g : N ⟶ K} {h : M ⟶ K} (w : f ≫ g = h) (x : M) : g (f x) = h x := by apply foo_apply w -lemma bar''' {M N K : Mon} {f : M ⟶ N} {g : N ⟶ K} {h : M ⟶ K} (w : f ≫ g = h) (x : M) : +lemma bar''' {M N K : MonCat} {f : M ⟶ N} {g : N ⟶ K} {h : M ⟶ K} (w : f ≫ g = h) (x : M) : g (f x) = h x := by apply foo_apply w -example (M N K : Mon) (f : M ⟶ N) (g : N ⟶ K) (h : M ⟶ K) (w : f ≫ g = h) (m : M) : +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 rw [elementwise_of% w] -example (M N K : Mon) (f : M ⟶ N) (g : N ⟶ K) (h : M ⟶ K) (w : f ≫ g = h) (m : M) : +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 -- Porting note: did not port `elementwise!` tactic replace w := elementwise_of% w diff --git a/test/CategoryTheory/Monoidal.lean b/test/CategoryTheory/Monoidal.lean deleted file mode 100644 index fd521a53e7c5d..0000000000000 --- a/test/CategoryTheory/Monoidal.lean +++ /dev/null @@ -1,44 +0,0 @@ -import Mathlib.Tactic.CategoryTheory.Monoidal - -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 simp - -example : (X ⊗ Y) ◁ f = (α_ _ _ _).hom ≫ X ◁ Y ◁ f ≫ (α_ _ _ _).inv := by - monoidal_nf - repeat' apply congrArg₂ (· ≫ ·) ?_ <| congrArg₂ (· ≫ ·) rfl ?_ - all_goals simp - -example : f ≫ g = f ≫ g := by - monoidal_nf - repeat' apply congrArg₂ (· ≫ ·) ?_ <| congrArg₂ (· ≫ ·) rfl ?_ - all_goals simp 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/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/Change.lean b/test/Change.lean index babc274c86b5c..a221341553ada 100644 --- a/test/Change.lean +++ b/test/Change.lean @@ -1,5 +1,6 @@ import Mathlib.Tactic.Change +set_option linter.style.setOption false set_option pp.unicode.fun true set_option autoImplicit true diff --git a/test/Check.lean b/test/Check.lean index 5deb44a3b1e48..baa5c95f009a5 100644 --- a/test/Check.lean +++ b/test/Check.lean @@ -6,6 +6,8 @@ open Lean PrettyPrinter Delaborator in @[delab mvar] def delabMVar : Delab := do unless kind.isNatural do failure `(?m) +set_option linter.unusedTactic false + /-! Basic check of `#check` -/ diff --git a/test/Clean.lean b/test/Clean.lean index 8e6bab55aaed1..ec96dc00e6179 100644 --- a/test/Clean.lean +++ b/test/Clean.lean @@ -51,3 +51,5 @@ example : True := by guard_hyp z :ₛ Nat := let_fun x := 1; x + x trivial + +end Tests diff --git a/test/Clear!.lean b/test/Clear!.lean index 51a427231d9c3..cf2817c2edc17 100644 --- a/test/Clear!.lean +++ b/test/Clear!.lean @@ -13,7 +13,8 @@ example [delete_this : Inhabited Nat] : Inhabited Nat := by infer_instance -- Confirms clear! can clear the dependencies of multiple hypotheses -example (delete_this : Nat) (delete_this2 : Nat) (_delete_this_dep : delete_this = delete_this2) : Nat := by +example (delete_this : Nat) (delete_this2 : Nat) (_delete_this_dep : delete_this = delete_this2) : + Nat := by clear! delete_this delete_this2 fail_if_success assumption exact 0 diff --git a/test/ClearExcept.lean b/test/ClearExcept.lean index eb1c41a293f92..63bdec1685482 100644 --- a/test/ClearExcept.lean +++ b/test/ClearExcept.lean @@ -1,5 +1,7 @@ import Mathlib.Tactic.ClearExcept +set_option linter.unusedTactic false + -- Most basic test example (_delete_this : Nat) (dont_delete_this : Int) : Nat := by clear * - dont_delete_this @@ -12,13 +14,16 @@ example [dont_delete_this : Inhabited Nat] (dont_delete_this2 : Prop) : Inhabite assumption -- Confirms that clearExcept can clear hypotheses even when they have dependencies -example (delete_this : Nat) (_delete_this2 : delete_this = delete_this) (dont_delete_this : Int) : Nat := by +example (delete_this : Nat) (_delete_this2 : delete_this = delete_this) (dont_delete_this : Int) : + Nat := by clear * - dont_delete_this fail_if_success assumption exact dont_delete_this.toNat --- Confirms that clearExcept does not clear hypotheses when they have dependencies that should not be cleared -example (dont_delete_this : Nat) (dont_delete_this2 : dont_delete_this = dont_delete_this) : Nat := by +-- Confirms that clearExcept does not clear hypotheses +-- when they have dependencies that should not be cleared +example (dont_delete_this : Nat) (dont_delete_this2 : dont_delete_this = dont_delete_this) : + Nat := by clear * - dont_delete_this2 exact dont_delete_this diff --git a/test/Clear_.lean b/test/Clear_.lean index c3dfeefe0a60c..163790d5fb052 100644 --- a/test/Clear_.lean +++ b/test/Clear_.lean @@ -1,6 +1,8 @@ import Mathlib.Tactic.Clear_ import Mathlib.Tactic.Replace +set_option linter.unusedTactic false + -- Most basic test example (_delete_this : Nat) : Nat := by clear_ @@ -19,14 +21,16 @@ example (_delete_this : Nat) (dont_delete_this : Int) : Nat := by exact dont_delete_this.toNat -- Confirms that clear_ can clear hypotheses even when they have dependencies -example (_delete_this : Type) (_delete_this_dep : _delete_this) (_delete_this_rw : _delete_this = Nat) - (_delete_this_dep_dep : _delete_this_dep = _delete_this_dep) : Nat := by +example (_delete_this : Type) (_delete_this_dep : _delete_this) + (_delete_this_rw : _delete_this = Nat) + (_delete_this_dep_dep : _delete_this_dep = _delete_this_dep) : Nat := by clear_ fail_if_success rw [← _delete_this_rw] exact 0 --- Confirms that clear_ does not clear hypotheses when they have dependencies that should not be cleared +-- Confirms that clear_ does not clear hypotheses +-- when they have dependencies that should not be cleared example (_dont_delete_this : Type) (dep : _dont_delete_this) : _dont_delete_this := by clear_ assumption 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/DefEqTransformations.lean b/test/DefEqTransformations.lean index 9ae2b7dc6e3f5..496e641a680f8 100644 --- a/test/DefEqTransformations.lean +++ b/test/DefEqTransformations.lean @@ -1,11 +1,12 @@ import Mathlib.Tactic.DefEqTransformations -import Mathlib.Init.Logic set_option autoImplicit true private axiom test_sorry : ∀ {α}, α namespace Tests +set_option linter.unusedTactic false + example : id (1 = 1) := by with_reducible whnf guard_target =ₛ id (1 = 1) @@ -182,3 +183,5 @@ example (n : Fin 5) : n = ⟨n.val2, n.prop2⟩ := by eta_struct guard_target =ₛ n = n rfl + +end Tests diff --git a/test/DeriveToExpr.lean b/test/DeriveToExpr.lean index 7780eef44e28c..bed70062a0acb 100644 --- a/test/DeriveToExpr.lean +++ b/test/DeriveToExpr.lean @@ -57,6 +57,7 @@ instance {α : Type u} [ToExpr α] [ToLevel.{u+1}] : ToExpr (Bool → α) where deriving instance ToExpr for Bar +set_option linter.unusedTactic false in example : True := by run_tac do let f : Bool → Nat | false => 0 | true => 1 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/Explode.lean b/test/Explode.lean index 365331fea1844..e19fafdd43863 100644 --- a/test/Explode.lean +++ b/test/Explode.lean @@ -24,7 +24,7 @@ info: true_iff : ∀ (p : Prop), (True ↔ p) = p -/ #guard_msgs in #explode true_iff -set_option linter.setOption false +set_option linter.style.setOption false -- On command line, tests format functions with => rather than ↦ without this. set_option pp.unicode.fun true diff --git a/test/ExtractGoal.lean b/test/ExtractGoal.lean index a69a4e97db20b..c4bb2a70c7fb6 100644 --- a/test/ExtractGoal.lean +++ b/test/ExtractGoal.lean @@ -1,8 +1,8 @@ import Mathlib.Tactic.ExtractGoal -import Mathlib.Init.Data.Nat.Lemmas import Mathlib.Order.Basic import Mathlib.Data.Nat.Defs +set_option linter.style.setOption false set_option pp.unicode.fun true set_option autoImplicit true set_option linter.unusedVariables false diff --git a/test/ExtractLets.lean b/test/ExtractLets.lean index 1cbe0dcc7678c..b2ff5f1b6ecb4 100644 --- a/test/ExtractLets.lean +++ b/test/ExtractLets.lean @@ -32,7 +32,6 @@ example (h : let x := 1; let y := 2; x + 1 = y) : True := by example (h : let x := 1; let y := 2; x + 1 = y) : True := by extract_lets x at h - intros guard_hyp x : Nat := 1 guard_hyp h :ₛ let y := 2; x + 1 = y trivial diff --git a/test/FlexibleLinter.lean b/test/FlexibleLinter.lean new file mode 100644 index 0000000000000..75ff835bdc5a3 --- /dev/null +++ b/test/FlexibleLinter.lean @@ -0,0 +1,342 @@ +import Batteries.Tactic.PermuteGoals +import Mathlib.Tactic.Linter.FlexibleLinter +import Mathlib.Tactic.Abel +import Mathlib.Tactic.Ring + +set_option linter.flexible false + +/-- +warning: 'simp at h' is a flexible tactic modifying 'h'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'exact h' uses 'h'! +-/ +#guard_msgs in +set_option linter.flexible true in +example (h : 0 + 0 = 0) : True := by + simp at h + try exact h + +-- `subst` does not use the goal +#guard_msgs in +example {a b : Nat} (h : a = b) : a + 0 = b := by + simp + subst h + rfl + +-- `by_cases` does not use the goal +#guard_msgs in +example {a b : Nat} (h : a = b) : a + 0 = b := by + simp + by_cases a = b + subst h; rfl + subst h; rfl + +-- `induction` does not use the goal +/-- +warning: 'simp' is a flexible tactic modifying '⊢'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'assumption' uses '⊢'! +--- +warning: 'simp' is a flexible tactic modifying '⊢'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'assumption' uses '⊢'! +-/ +#guard_msgs in +set_option linter.flexible true in +example {a b : Nat} (h : a = b) : a + 0 = b := by + simp + induction a <;> assumption + + +/-- +warning: 'simp at h' is a flexible tactic modifying 'h'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'exact h' uses 'h'! +-/ +#guard_msgs in +set_option linter.flexible true in +example (h : 0 = 0 ∨ 0 = 0) : True := by + cases h <;> + rename_i h <;> + simp at h + · exact h + · assumption --exact h + +/-- +warning: 'simp' is a flexible tactic modifying '⊢'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'on_goal 2 => · contradiction' uses '⊢'! +--- +warning: 'simp' is a flexible tactic modifying '⊢'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'contradiction' uses '⊢'! +-/ +#guard_msgs in +set_option linter.flexible true in +example (h : 0 = 1 ∨ 0 = 1) : 0 = 1 ∧ 0 = 1 := by + cases h <;> simp + on_goal 2 => · contradiction + · contradiction + +-- `omega` is a follower and `all_goals` is a `combinatorLike` +#guard_msgs in +example {a : Nat} : a + 1 + 0 = 1 + a := by simp; all_goals omega + +/-- +warning: 'simp' is a flexible tactic modifying '⊢'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'contradiction' uses '⊢'! +--- +warning: 'simp' is a flexible tactic modifying '⊢'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'contradiction' uses '⊢'! +-/ +#guard_msgs in +set_option linter.flexible true in +example (h : 0 = 1 ∨ 0 = 1) : 0 = 1 ∧ 0 = 1 := by + cases h <;> simp + · contradiction + · contradiction + +/-- +warning: 'simp at h k' is a flexible tactic modifying 'k'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'rw [← Classical.not_not (a := True)] at k' uses 'k'! +--- +warning: 'simp at h k' is a flexible tactic modifying 'h'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'rw [← Classical.not_not (a := True)] at h' uses 'h'! +-/ +#guard_msgs in +-- `simp at h` stains `h` but not other locations +set_option linter.flexible true in +example {h : 0 = 0} {k : 1 = 1} : True := by + simp at h k; + rw [← Classical.not_not (a := True)] + -- flag the two below vvv do not above ^^^ + rw [← Classical.not_not (a := True)] at k + rw [← Classical.not_not (a := True)] at h + assumption + +-- `specialize` does not touch, by default, the target +#guard_msgs in +example {a b : Nat} (h : ∀ c, c + a + b = a + c) : (0 + 2 + 1 + a + b) = a + 3 := by + simp + specialize h 3 + simp_all + +-- `norm_num` is allowed after `simp`. +#guard_msgs in +example : (0 + 2 : Rat) + 1 = 3 := by + simp + norm_num + +/-- +warning: 'simp' is a flexible tactic modifying '⊢'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'rw [add_comm]' uses '⊢'! +-/ +#guard_msgs in +-- `norm_num` is allowed after `simp`, but "passes along the stain". +set_option linter.flexible true in +example {a : Rat} : a + (0 + 2 + 1 : Rat) = 3 + a := by + simp + norm_num + rw [add_comm] + +/-- +warning: 'simp' is a flexible tactic modifying '⊢'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'exact h.symm' uses '⊢'! +-/ +#guard_msgs in +-- `congr` is allowed after `simp`, but "passes along the stain". +set_option linter.flexible true in +example {a b : Nat} (h : a = b) : a + b + 0 = b + a := by + simp + congr + exact h.symm + +-- `done` is an allowed follower +#guard_msgs in +example (h : False) : 0 ≠ 0 := by + try (simp; done) + exact h.elim + +-- `abel_nf` is a `rigidifier`: the "stain" of `simp` does not continue past `abel_nf`. +#guard_msgs in +example {a b : Nat} (h : a + b = a + (b + 1)) : a + b = b + a + 0 + 1 := by + simp + abel_nf + assumption + +-- `abel` is an allowed `simp`-follower. +#guard_msgs in +example {a b : Nat} : a + b = b + a + 0 := by + simp + abel + +-- `ring_nf` is a `rigidifier`: the "stain" of `simp` does not continue past `ring_nf`. +#guard_msgs in +example {a b : Nat} (h : a + b = 1 + a + b) : a + b = b + a + 0 + 1 := by + simp + ring_nf + assumption + +-- `ring` is an allowed `simp`-follower. +#guard_msgs in +example {a b : Nat} : a + b = b + a + 0 := by + simp + ring + +/-- +warning: 'simp' is a flexible tactic modifying '⊢'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'contradiction' uses '⊢'! +-/ +#guard_msgs in +set_option linter.flexible true in +example (h : 0 = 1 ∨ 0 = 1) : 0 = 1 ∧ 0 = 1 := by + cases h <;> simp + · simp_all + · contradiction + +-- forget stained locations, once the corresponding goal is closed +#guard_msgs in +example (n : Nat) : n + 1 = 1 + n := by + by_cases 0 = 0 + · simp_all + omega + · have : 0 ≠ 1 := by + intro h + -- should not flag `cases`! + cases h + -- should not flag `exact`! + exact Nat.add_comm .. + +/-- +warning: 'simp at h' is a flexible tactic modifying 'h'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'rw [← Classical.not_not (a := True)] at h' uses 'h'! +-/ +#guard_msgs in +set_option linter.flexible true in +-- `simp at h` stains `h` but not other locations +example {h : 0 = 0} {k : 1 = 1} : ¬ ¬ True := by + simp at h + rw [← Nat.add_zero 1] at k + -- flag below vvv do not flag above ^^^ + rw [← Classical.not_not (a := True)] at h + --exact h -- <-- flagged + assumption + +/-- +warning: 'simp at h k' is a flexible tactic modifying 'k'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'rw [← Classical.not_not (a := True)] at k' uses 'k'! +--- +warning: 'simp at h k' is a flexible tactic modifying 'h'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'rw [← Classical.not_not (a := True)] at h' uses 'h'! +-/ +#guard_msgs in +set_option linter.flexible true in +-- `simp at h` stains `h` but not other locations +example {h : 0 = 0} {k : 1 = 1} : True := by + simp at h k + rw [← Classical.not_not (a := True)] + -- flag the two below vvv do not above ^^^ + rw [← Classical.not_not (a := True)] at k + rw [← Classical.not_not (a := True)] at h + assumption + +/-- +warning: 'simp at h' is a flexible tactic modifying 'h'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'rw [← Classical.not_not (a := True)] at h' uses 'h'! +-/ +#guard_msgs in +-- `simp at h` stains `h` but not other locations +set_option linter.flexible true in +example {h : 0 = 0} : True := by + simp at h + rw [← Classical.not_not (a := True)] + -- flag below vvv do not flag above ^^^ + rw [← Classical.not_not (a := True)] at h + assumption + +/-- +warning: 'simp' is a flexible tactic modifying '⊢'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'rwa [← Classical.not_not (a := False)]' uses '⊢'! +-/ +#guard_msgs in +set_option linter.flexible true in +example {h : False} : 0 = 1 := by + simp + rw [← Classical.not_not (a := False)] at h + -- flag below vvv do not flag above ^^^ + rwa [← Classical.not_not (a := False)] + +/-- +warning: 'simp' is a flexible tactic modifying '⊢'… +note: this linter can be disabled with `set_option linter.flexible false` +--- +info: … and 'rwa [← Classical.not_not (a := False)]' uses '⊢'! +-/ +#guard_msgs in +set_option linter.flexible true in +example {h : False} : 0 = 1 ∧ 0 = 1 := by + constructor + · simpa + . simp + rw [← Classical.not_not (a := False)] at h + rwa [← Classical.not_not (a := False)] + +section test_internals +open Lean Mathlib.Linter Flexible + +/-- `flex? tac` logs an info `true` if the tactic is flexible, logs a warning `false` otherwise. -/ +elab "flex? " tac:tactic : command => do + match flexible? tac with + | true => logWarningAt tac m!"{flexible? tac}" + | false => logInfoAt tac m!"{flexible? tac}" + +section +set_option linter.unusedTactic false +set_option linter.unreachableTactic false +/-- info: false -/#guard_msgs in +flex? done +/-- info: false -/#guard_msgs in +flex? simp only +/-- info: false -/#guard_msgs in +flex? simp_all only +/-- warning: true -/#guard_msgs in +flex? simp +/-- warning: true -/#guard_msgs in +flex? simp_all +end + +/-- info: #[h] -/ #guard_msgs in +#eval show CoreM _ from do + let h := mkIdent `h + let hc : TSyntax `Lean.Parser.Tactic.casesTarget := ⟨h⟩ + IO.println s!"{(toStained (← `(tactic| cases $hc))).toArray}" 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/GuardGoalNums.lean b/test/GuardGoalNums.lean index 89e219de17f11..143a75fa193c8 100644 --- a/test/GuardGoalNums.lean +++ b/test/GuardGoalNums.lean @@ -1,5 +1,7 @@ import Mathlib.Tactic.GuardGoalNums +set_option linter.unusedTactic false + example : true ∧ true := by constructor guard_goal_nums 2 diff --git a/test/GuardHypNums.lean b/test/GuardHypNums.lean index cafdfbdc05042..3498547c21238 100644 --- a/test/GuardHypNums.lean +++ b/test/GuardHypNums.lean @@ -1,5 +1,7 @@ import Mathlib.Tactic.GuardHypNums +set_option linter.unusedTactic false + example (a b c : Nat) (_ : a = b) (_ : c = 3) : true := by guard_hyp_nums 6 trivial diff --git a/test/HashCommandLinter.lean b/test/HashCommandLinter.lean index 28bd92ff090c3..203db4657db9e 100644 --- a/test/HashCommandLinter.lean +++ b/test/HashCommandLinter.lean @@ -2,6 +2,8 @@ import Lean.Elab.GuardMsgs import Mathlib.Tactic.AdaptationNote import Mathlib.Tactic.Linter.HashCommandLinter +set_option linter.hashCommand true + section ignored_commands -- `#guard_msgs in` without a doc-string triggers the linter, but with the `doc-string does not @@ -47,6 +49,7 @@ note: this linter can be disabled with `set_option linter.hashCommand false` #guard_msgs in #guard true +set_option linter.unusedTactic false in /-- warning: `#`-commands, such as '#check_tactic', are not allowed in 'Mathlib' note: this linter can be disabled with `set_option linter.hashCommand false` diff --git a/test/HaveLetLinter.lean b/test/HaveLetLinter.lean index 35accc8e607e7..ec7409b66ccde 100644 --- a/test/HaveLetLinter.lean +++ b/test/HaveLetLinter.lean @@ -1,6 +1,8 @@ import Mathlib.Tactic.Linter.HaveLetLinter import Mathlib.Tactic.Tauto +set_option linter.haveLet 1 + /-- A tactic that adds a vacuous `sorry`. Useful for testing the chattiness of the `haveLet` linter. -/ diff --git a/test/InferParam.lean b/test/InferParam.lean index d8f9a84f68a5c..835574cb0dec9 100644 --- a/test/InferParam.lean +++ b/test/InferParam.lean @@ -19,3 +19,5 @@ example : 0 ≤ 2 + 2 := by example : 0 ≤ 2 + 2 := by apply zero_le_add' infer_param + +end InferParamTest diff --git a/test/LibrarySearch/basic.lean b/test/LibrarySearch/basic.lean index be136b66c0983..ba5f6e3724172 100644 --- a/test/LibrarySearch/basic.lean +++ b/test/LibrarySearch/basic.lean @@ -6,7 +6,7 @@ import Mathlib.Data.Real.Basic set_option autoImplicit true -set_option linter.setOption false +set_option linter.style.setOption false -- Enable this option for tracing: -- set_option trace.Tactic.librarySearch true -- And this option to trace all candidate lemmas before application. diff --git a/test/Lint.lean b/test/Lint.lean index 423b30a42e594..25bf9c9147d13 100644 --- a/test/Lint.lean +++ b/test/Lint.lean @@ -1,5 +1,6 @@ import Mathlib.Tactic.Linter.Lint import Mathlib.Tactic.ToAdditive +import Mathlib.Order.SetNotation -- TODO: the linter also runs on the #guard_msg, so disable it once -- See https://leanprover.zulipchat.com/#narrow/stream/348111-std4/topic/.23guard_msgs.20doesn't.20silence.20warnings/near/423534679 @@ -58,19 +59,23 @@ export Nat (add) end add -set_option linter.cdot false in +section cdotLinter + +set_option linter.style.cdot false + +set_option linter.globalAttributeIn false in /-- warning: Please, use '·' (typed as `\.`) instead of '.' as 'cdot'. -note: this linter can be disabled with `set_option linter.cdot false` +note: this linter can be disabled with `set_option linter.style.cdot false` --- warning: Please, use '·' (typed as `\.`) instead of '.' as 'cdot'. -note: this linter can be disabled with `set_option linter.cdot false` +note: this linter can be disabled with `set_option linter.style.cdot false` --- warning: Please, use '·' (typed as `\.`) instead of '.' as 'cdot'. -note: this linter can be disabled with `set_option linter.cdot false` +note: this linter can be disabled with `set_option linter.style.cdot false` -/ #guard_msgs in -set_option linter.cdot true in +set_option linter.style.cdot true in attribute [instance] Int.add in instance : Inhabited Nat where default := by @@ -78,34 +83,196 @@ instance : Inhabited Nat where · have : Nat → Nat → Nat := (· + .) . exact 0 -set_option linter.cdot false in +set_option linter.style.cdot false in /-- warning: Please, use '·' (typed as `\.`) instead of '.' as 'cdot'. -note: this linter can be disabled with `set_option linter.cdot false` +note: this linter can be disabled with `set_option linter.style.cdot false` -/ #guard_msgs in -set_option linter.cdot true in +set_option linter.style.cdot true in example : Add Nat where add := (. + ·) -set_option linter.longLine false +/-- +warning: Please, use '·' (typed as `\.`) instead of '.' as 'cdot'. +note: this linter can be disabled with `set_option linter.style.cdot false` +-/ +#guard_msgs in +set_option linter.style.cdot true in +example : Add Nat where add := (. + ·) + +/-- +warning: Please, use '·' (typed as `\.`) instead of '.' as 'cdot'. +note: this linter can be disabled with `set_option linter.style.cdot false` +--- +warning: This central dot `·` is isolated; please merge it with the next line. +--- +warning: This central dot `·` is isolated; please merge it with the next line. +-/ +#guard_msgs in +set_option linter.style.cdot true in +example : Nat := by + have : Nat := by + · + -- some empty have + have := 0 + · + + -- another + have := 1 + . exact 2 + exact 0 + +#guard_msgs in +set_option linter.style.cdot true in +example : True := by + have : Nat := by + -- This is how code should look: no error. + · -- comment + exact 37 + trivial + +end cdotLinter + +set_option linter.globalAttributeIn false in +set_option linter.style.dollarSyntax false in +/-- +warning: Please use '<|' instead of '$' for the pipe operator. +note: this linter can be disabled with `set_option linter.style.dollarSyntax false` +--- +warning: Please use '<|' instead of '$' for the pipe operator. +note: this linter can be disabled with `set_option linter.style.dollarSyntax false` +-/ +#guard_msgs in +set_option linter.style.dollarSyntax true in +attribute [instance] Int.add in +instance (f g : Nat → Nat) : Inhabited Nat where + default := by + · have := 0 + · have : Nat := f $ g $ 0 + · exact 0 + +section lambdaSyntaxLinter + +set_option linter.style.lambdaSyntax false + +/-- +warning: Please use 'fun' and not 'λ' to define anonymous functions. +The 'λ' syntax is deprecated in mathlib4. +note: this linter can be disabled with `set_option linter.style.lambdaSyntax false` +-/ +#guard_msgs in +set_option linter.style.lambdaSyntax true in +example : ℕ → ℕ := λ _ ↦ 0 + +/-- +warning: Please use 'fun' and not 'λ' to define anonymous functions. +The 'λ' syntax is deprecated in mathlib4. +note: this linter can be disabled with `set_option linter.style.lambdaSyntax false` +-/ +#guard_msgs in +set_option linter.style.lambdaSyntax true in +def foo : Bool := by + let _f : ℕ → ℕ := λ _ ↦ 0 + exact true + +example : ℕ → ℕ := fun n ↦ n - 1 + +/-- +warning: Please use 'fun' and not 'λ' to define anonymous functions. +The 'λ' syntax is deprecated in mathlib4. +note: this linter can be disabled with `set_option linter.style.lambdaSyntax false` +-/ +#guard_msgs in +set_option linter.style.lambdaSyntax true in +example : ℕ → ℕ := by exact λ n ↦ 3 * n + 1 + +/-- +warning: declaration uses 'sorry' +--- +warning: Please use 'fun' and not 'λ' to define anonymous functions. +The 'λ' syntax is deprecated in mathlib4. +note: this linter can be disabled with `set_option linter.style.lambdaSyntax false` +--- +warning: Please use 'fun' and not 'λ' to define anonymous functions. +The 'λ' syntax is deprecated in mathlib4. +note: this linter can be disabled with `set_option linter.style.lambdaSyntax false` +--- +warning: Please use 'fun' and not 'λ' to define anonymous functions. +The 'λ' syntax is deprecated in mathlib4. +note: this linter can be disabled with `set_option linter.style.lambdaSyntax false` +-/ +#guard_msgs in +set_option linter.style.lambdaSyntax true in +example : ℕ → ℕ → ℕ → ℕ := by + have (n : ℕ) : True := trivial + have : (Set.univ : Set ℕ) = ⋃ (i : ℕ), (Set.iUnion λ j ↦ ({0, j} : Set ℕ)) := sorry + have : ∃ m : ℕ, ⋃ i : ℕ, (Set.univ : Set ℕ) = ∅ := sorry + exact λ _a ↦ fun _b ↦ λ _c ↦ 0 + +/-- +warning: Please use 'fun' and not 'λ' to define anonymous functions. +The 'λ' syntax is deprecated in mathlib4. +note: this linter can be disabled with `set_option linter.style.lambdaSyntax false` +--- +warning: Please use 'fun' and not 'λ' to define anonymous functions. +The 'λ' syntax is deprecated in mathlib4. +note: this linter can be disabled with `set_option linter.style.lambdaSyntax false` +--- +warning: Please use 'fun' and not 'λ' to define anonymous functions. +The 'λ' syntax is deprecated in mathlib4. +note: this linter can be disabled with `set_option linter.style.lambdaSyntax false` +-/ +#guard_msgs in +set_option linter.style.lambdaSyntax true in +example : True := by + have : 0 = 0 ∧ 0 = 0 ∧ 1 + 3 = 4 := by + refine ⟨by trivial, by + let _f := λ n : ℕ ↦ 0; + have : ℕ := by + · -- comment + · have := λ k : ℕ ↦ -5 + · exact 0 + refine ⟨by trivial, have := λ k : ℕ ↦ -5; by simp⟩ + ⟩ + trivial + +-- Code such as the following would require walking the infotree instead: +-- the inner set_option is ignore (in either direction). +-- As this seems unlikely to occur by accident and its use is dubious, we don't worry about this. +/-- +warning: Please use 'fun' and not 'λ' to define anonymous functions. +The 'λ' syntax is deprecated in mathlib4. +note: this linter can be disabled with `set_option linter.style.lambdaSyntax false` +-/ +#guard_msgs in +set_option linter.style.lambdaSyntax true in +example : ℕ → ℕ := set_option linter.style.lambdaSyntax false in λ _ ↦ 0 + +set_option linter.style.lambdaSyntax false +#guard_msgs in +example : ℕ → ℕ := set_option linter.style.lambdaSyntax true in λ _ ↦ 0 + +end lambdaSyntaxLinter + +set_option linter.style.longLine false /-- warning: This line exceeds the 100 character limit, please shorten it! -note: this linter can be disabled with `set_option linter.longLine false` +note: this linter can be disabled with `set_option linter.style.longLine false` -/ #guard_msgs in -set_option linter.longLine true in +set_option linter.style.longLine true in /-! -/ #guard_msgs in -- Lines with more than 100 characters containing URLs are allowed. -set_option linter.longLine true in +set_option linter.style.longLine true in /-! http -/ -set_option linter.longLine true +set_option linter.style.longLine true -- The *argument* of `#guard_msgs` is *not* exempt from the linter. /-- warning: This line exceeds the 100 character limit, please shorten it! -note: this linter can be disabled with `set_option linter.longLine false` +note: this linter can be disabled with `set_option linter.style.longLine false` -/ #guard_msgs in #guard true @@ -116,3 +283,14 @@ 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 + +/-- +info: " \" " : String +--- +warning: This line exceeds the 100 character limit, please shorten it! +You can use "string gaps" to format long strings: within a string quotation, using a '' at the end of a line allows you to continue the string on the following line, removing all intervening whitespace. +note: this linter can be disabled with `set_option linter.style.longLine false` +-/ +#guard_msgs in +set_option linter.style.longLine true in +#check " \" " diff --git a/test/LintStyle.lean b/test/LintStyle.lean index 79df48ee1345e..7a58c6c946e9e 100644 --- a/test/LintStyle.lean +++ b/test/LintStyle.lean @@ -6,11 +6,11 @@ import Mathlib.Tactic.Common /-! Tests for the `setOption` linter -/ section setOption --- The warning generated by `linter.setOption` is not suppressed by `#guard_msgs`, +-- The warning generated by `linter.style.setOption` 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.setOption false +set_option linter.style.setOption false -- All types of options are supported: boolean, numeric and string-valued. -- On the top level, i.e. as commands. @@ -19,60 +19,60 @@ set_option linter.setOption false warning: Setting options starting with 'debug', 'pp', 'profiler', 'trace' is only intended for development and not for final code. If you intend to submit this contribution to the Mathlib project, please remove 'set_option pp.all'. -note: this linter can be disabled with `set_option linter.setOption false` +note: this linter can be disabled with `set_option linter.style.setOption false` -/ #guard_msgs in -set_option linter.setOption true in +set_option linter.style.setOption true in set_option pp.all true /-- warning: Setting options starting with 'debug', 'pp', 'profiler', 'trace' is only intended for development and not for final code. If you intend to submit this contribution to the Mathlib project, please remove 'set_option profiler'. -note: this linter can be disabled with `set_option linter.setOption false` +note: this linter can be disabled with `set_option linter.style.setOption false` -/ #guard_msgs in -set_option linter.setOption true in +set_option linter.style.setOption true in set_option profiler false /-- warning: Setting options starting with 'debug', 'pp', 'profiler', 'trace' is only intended for development and not for final code. If you intend to submit this contribution to the Mathlib project, please remove 'set_option pp.all'. -note: this linter can be disabled with `set_option linter.setOption false` +note: this linter can be disabled with `set_option linter.style.setOption false` -/ #guard_msgs in -set_option linter.setOption true in +set_option linter.style.setOption true in set_option pp.all false /-- warning: Setting options starting with 'debug', 'pp', 'profiler', 'trace' is only intended for development and not for final code. If you intend to submit this contribution to the Mathlib project, please remove 'set_option profiler.threshold'. -note: this linter can be disabled with `set_option linter.setOption false` +note: this linter can be disabled with `set_option linter.style.setOption false` -/ #guard_msgs in -set_option linter.setOption true in +set_option linter.style.setOption true in set_option profiler.threshold 50 /-- warning: Setting options starting with 'debug', 'pp', 'profiler', 'trace' is only intended for development and not for final code. If you intend to submit this contribution to the Mathlib project, please remove 'set_option trace.profiler.output'. -note: this linter can be disabled with `set_option linter.setOption false` +note: this linter can be disabled with `set_option linter.style.setOption false` -/ #guard_msgs in -set_option linter.setOption true in +set_option linter.style.setOption true in set_option trace.profiler.output "foo" /-- warning: Setting options starting with 'debug', 'pp', 'profiler', 'trace' is only intended for development and not for final code. If you intend to submit this contribution to the Mathlib project, please remove 'set_option debug.moduleNameAtTimeout'. -note: this linter can be disabled with `set_option linter.setOption false` +note: this linter can be disabled with `set_option linter.style.setOption false` -/ #guard_msgs in -set_option linter.setOption true in +set_option linter.style.setOption true in set_option debug.moduleNameAtTimeout false -- The lint does not fire on arbitrary options. @@ -84,10 +84,10 @@ set_option autoImplicit false warning: Setting options starting with 'debug', 'pp', 'profiler', 'trace' is only intended for development and not for final code. If you intend to submit this contribution to the Mathlib project, please remove 'set_option pp.all'. -note: this linter can be disabled with `set_option linter.setOption false` +note: this linter can be disabled with `set_option linter.style.setOption false` -/ #guard_msgs in -set_option linter.setOption true in +set_option linter.style.setOption true in lemma tactic : True := by set_option pp.all true in trivial @@ -96,10 +96,10 @@ lemma tactic : True := by warning: Setting options starting with 'debug', 'pp', 'profiler', 'trace' is only intended for development and not for final code. If you intend to submit this contribution to the Mathlib project, please remove 'set_option pp.raw.maxDepth'. -note: this linter can be disabled with `set_option linter.setOption false` +note: this linter can be disabled with `set_option linter.style.setOption false` -/ #guard_msgs in -set_option linter.setOption true in +set_option linter.style.setOption true in lemma tactic2 : True := by set_option pp.raw.maxDepth 32 in trivial @@ -108,10 +108,10 @@ lemma tactic2 : True := by warning: Setting options starting with 'debug', 'pp', 'profiler', 'trace' is only intended for development and not for final code. If you intend to submit this contribution to the Mathlib project, please remove 'set_option pp.all'. -note: this linter can be disabled with `set_option linter.setOption false` +note: this linter can be disabled with `set_option linter.style.setOption false` -/ #guard_msgs in -set_option linter.setOption true in +set_option linter.style.setOption true in lemma tactic3 : True := by set_option pp.all false in trivial @@ -120,10 +120,10 @@ lemma tactic3 : True := by warning: Setting options starting with 'debug', 'pp', 'profiler', 'trace' is only intended for development and not for final code. If you intend to submit this contribution to the Mathlib project, please remove 'set_option trace.profiler.output'. -note: this linter can be disabled with `set_option linter.setOption false` +note: this linter can be disabled with `set_option linter.style.setOption false` -/ #guard_msgs in -set_option linter.setOption true in +set_option linter.style.setOption true in lemma tactic4 : True := by set_option trace.profiler.output "foo" in trivial diff --git a/test/LongFile.lean b/test/LongFile.lean new file mode 100644 index 0000000000000..faec16c404806 --- /dev/null +++ b/test/LongFile.lean @@ -0,0 +1,68 @@ +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 + `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 +--- +warning: The default value of the `longFile` linter is 1500. +This file is 36 lines long which does not exceed the allowed bound. +Please, remove the `set_option linter.style.longFile 1600`. +-/ +#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 51 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 66 lines long which does not exceed the allowed bound. +Please, remove the `set_option linter.style.longFile 1700`. +-/ +#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 diff --git a/test/MLList.lean b/test/MLList.lean deleted file mode 100644 index 48aa924f5d021..0000000000000 --- a/test/MLList.lean +++ /dev/null @@ -1,68 +0,0 @@ -/- -Copyright (c) 2019 Scott Morrison. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Scott Morrison --/ -import Batteries.Data.MLList.Basic -import Mathlib.Control.Basic - -abbrev S (α : Type) := StateT (List Nat) Option α -def append (x : Nat) : S Unit := - fun s => some ((), x :: s) - -def F : Nat → S Nat - | 0 => failure - | (n+1) => do - append (n+1) - pure n - -open Lean - -run_cmd Lean.Elab.Command.liftTermElabM do - -- Note that `fix` fails if any invocation of `F` fails. - -- This is different from previous behaviour, where it just terminated the lazy list. - -- Hence we must use `.takeAsList 11` here rather than `.force`. - let x := ((MLList.fix F 10).takeAsList 11).run [] - guard <| x = some ([10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - -example : ((MLList.fix F 10).takeAsList 4).run [] = some ([10, 9, 8, 7], [8, 9, 10]) := by - native_decide -example : - (((MLList.fix F 10).map fun n => n*n).takeAsList 3).run [] = - some ([100, 81, 64], [9, 10]) := by - native_decide - -def l1 : MLList S Nat := MLList.ofList [0,1,2] -def l2 : MLList S Nat := MLList.ofList [3,4,5] -def ll : MLList S Nat := (MLList.ofList [l1, l2]).join - -run_cmd Lean.Elab.Command.liftTermElabM do - let x := ll.force.run [] - guard <| x = some ([0, 1, 2, 3, 4, 5], []) - -def half_or_fail (n : Nat) : MetaM Nat := -do guard (n % 2 = 0) - pure (n / 2) - -run_cmd Lean.Elab.Command.liftTermElabM do - let x : MLList MetaM Nat := MLList.range - let y := x.filterMapM fun n => try? <| half_or_fail n - let z ← y.takeAsList 10 - guard <| z.length = 10 - -run_cmd Lean.Elab.Command.liftTermElabM do - let R : MLList MetaM Nat := MLList.range - let S : MLList MetaM Nat := R.filterMapM fun n => try? do - guard (n % 5 = 0) - pure n - let n ← R.takeAsList 5 - let m ← S.head - guard <| n = [0,1,2,3,4] - guard <| m = 0 - -run_cmd Lean.Elab.Command.liftTermElabM do - let R : MLList MetaM Nat := MLList.range - let n ← R.firstM fun n => try? do - guard (n = 5) - pure n - guard <| n = 5 diff --git a/test/MaxPowDiv.lean b/test/MaxPowDiv.lean index dd55a64f247cd..8ec14a17d24c2 100644 --- a/test/MaxPowDiv.lean +++ b/test/MaxPowDiv.lean @@ -1,4 +1,4 @@ -import Mathlib.NumberTheory.Padics.PadicVal +import Mathlib.NumberTheory.Padics.PadicVal.Basic /-- info: 100000 diff --git a/test/MfldSetTac.lean b/test/MfldSetTac.lean index ae6bf752c33cf..ad921934de097 100644 --- a/test/MfldSetTac.lean +++ b/test/MfldSetTac.lean @@ -24,7 +24,8 @@ section stub_lemmas structure PartialHomeomorph (α : Type u) (β : Type u) extends PartialEquiv α β noncomputable -instance PartialHomeomorph.has_coe_to_fun : CoeFun (PartialHomeomorph α β) (fun _ ↦ α → β) := test_sorry +instance PartialHomeomorph.has_coe_to_fun : CoeFun (PartialHomeomorph α β) (fun _ ↦ α → β) := + test_sorry noncomputable def PartialHomeomorph.symm (_e : PartialHomeomorph α β) : PartialHomeomorph β α := test_sorry @@ -46,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 @@ -55,7 +56,8 @@ noncomputable def ModelWithCorners.symm (_I : ModelWithCorners 𝕜 E H) : PartialEquiv E H := test_sorry noncomputable -instance ModelWithCorners.has_coe_to_fun : CoeFun (ModelWithCorners 𝕜 E H) (fun _ ↦ H → E) := test_sorry +instance ModelWithCorners.has_coe_to_fun : CoeFun (ModelWithCorners 𝕜 E H) (fun _ ↦ H → E) := + test_sorry @[mfld_simps] lemma ModelWithCorners.left_inv (I : ModelWithCorners 𝕜 E H) (x : H) : I.symm (I x) = x := diff --git a/test/MinImports.lean b/test/MinImports.lean index 174943a1933b9..abf1594c8f565 100644 --- a/test/MinImports.lean +++ b/test/MinImports.lean @@ -1,4 +1,3 @@ -import Mathlib.Tactic.Linter.MinImports import Mathlib.Tactic.NormNum.Basic import Mathlib.Tactic.FunProp.Attr @@ -37,8 +36,7 @@ noncomputable instance : Semiring Nat := inferInstance /-- info: ℤ : Type --- -info: import Lean.Parser.Command -import Mathlib.Data.Int.Notation +info: import Mathlib.Data.Int.Notation -/ #guard_msgs in #min_imports in #check ℤ @@ -78,7 +76,7 @@ lemma hi (n : ℕ) : n = n := by extract_goal; rfl /-- warning: Imports increased to -[Init.Guard, Lean.Parser.Term, Mathlib.Data.Int.Notation] +[Init.Guard, Mathlib.Data.Int.Notation] note: this linter can be disabled with `set_option linter.minImports false` -/ #guard_msgs in @@ -95,7 +93,7 @@ set_option linter.minImports false in /-- warning: Imports increased to -[Init.Guard, Lean.Parser.Term, Mathlib.Data.Int.Notation] +[Init.Guard, Mathlib.Data.Int.Notation] note: this linter can be disabled with `set_option linter.minImports false` -/ #guard_msgs in @@ -118,7 +116,7 @@ note: this linter can be disabled with `set_option linter.minImports false` /-- warning: Imports increased to -[Mathlib.Tactic.FunProp.Attr, Mathlib.Tactic.Linter.MinImports, Mathlib.Tactic.NormNum.Basic] +[Mathlib.Tactic.FunProp.Attr, Mathlib.Tactic.NormNum.Basic] note: this linter can be disabled with `set_option linter.minImports false` -/ #guard_msgs in diff --git a/test/MoveAdd.lean b/test/MoveAdd.lean index e115ab0e6a48c..74d7a9fd44d70 100644 --- a/test/MoveAdd.lean +++ b/test/MoveAdd.lean @@ -1,5 +1,4 @@ import Mathlib.Tactic.MoveAdd -import Mathlib.Init.Data.Nat.Lemmas import Mathlib.Algebra.Ring.Nat universe u 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/Recall.lean b/test/Recall.lean index 9f4a987ba1abd..198fed552b93d 100644 --- a/test/Recall.lean +++ b/test/Recall.lean @@ -3,7 +3,7 @@ import Mathlib.Analysis.Calculus.Deriv.Basic import Mathlib.Analysis.SpecialFunctions.Trigonometric.Basic import Mathlib.Data.Complex.Exponential -set_option linter.setOption false +set_option linter.style.setOption false -- Remark: When the test is run by make/CI, this option is not set, so we set it here. set_option pp.unicode.fun true set_option autoImplicit true diff --git a/test/RewriteSearch/Basic.lean b/test/RewriteSearch/Basic.lean index ef4fb08df014d..8b70141718832 100644 --- a/test/RewriteSearch/Basic.lean +++ b/test/RewriteSearch/Basic.lean @@ -17,7 +17,7 @@ example (xs ys : List α) : (xs ++ ys).length = ys.length + xs.length := by -- This worked in previous versions, but for now doesn't. -- There are of course better tools for AC rewriting, but it would be nice if `rw_search` -- could do a little of it in the course of a longer rewrite. -set_option linter.longLine false in +set_option linter.style.longLine false in /-! -- /- -- info: Try this: rw [← add_assoc, add_right_comm, add_assoc, add_add_add_comm, ← add_assoc, add_right_comm] @@ -35,7 +35,7 @@ example (xs ys : List α) : (xs ++ ys ++ ys).length = 2 * ys.length + xs.length := by rw_search -set_option linter.longLine false in +set_option linter.style.longLine false in /-! info: Try this: rw [List.length_append, List.length_append, Nat.two_mul, Nat.add_assoc, Nat.add_left_comm, Nat.add_right_comm, Nat.add_assoc] -/ @@ -44,7 +44,7 @@ example (xs ys : List α) : (xs ++ ys ++ ys).length = 2 * ys.length + xs.length := by rw_search [-add_rotate] -set_option linter.longLine false in +set_option linter.style.longLine false in /-! info: Try this: rw [Int.add_right_comm, add_right_cancel_iff, add_sub_left_comm, add_sub, Int.add_sub_cancel] -/ diff --git a/test/RewriteSearch/Polynomial.lean b/test/RewriteSearch/Polynomial.lean index 7fb4c512a6d94..cf1cab0e57a5f 100644 --- a/test/RewriteSearch/Polynomial.lean +++ b/test/RewriteSearch/Polynomial.lean @@ -1,6 +1,5 @@ import Mathlib.Algebra.Polynomial.Eval import Mathlib.Algebra.Polynomial.Inductions -import Mathlib.Init.Core import Mathlib.Tactic.RewriteSearch set_option autoImplicit true @@ -175,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/SimpRw.lean b/test/SimpRw.lean index bf5c80caee23a..466c3c32025e1 100644 --- a/test/SimpRw.lean +++ b/test/SimpRw.lean @@ -34,6 +34,7 @@ example {a : Nat} (∀ b, a - 1 ≤ b) = ∀ b c : Nat, c < a → c < b + 1 := by simp_rw [h1, h2] +set_option linter.unusedTactic false in -- `simp_rw` respects config options example : 1 = 2 := by let a := 2 diff --git a/test/Simps.lean b/test/Simps.lean index 4fb569642e899..af1bc4b6f4a5e 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) @@ -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/SplitIfs.lean b/test/SplitIfs.lean index e8dbcd8c69649..1809a04cb709e 100644 --- a/test/SplitIfs.lean +++ b/test/SplitIfs.lean @@ -73,6 +73,7 @@ example (P Q : Prop) (w : if P then (if Q then true else true) else true = true) · trivial · trivial +set_option linter.unusedTactic false in example (u : Nat) : (if u = u then 0 else 1) = 0 := by have h : u = u := by rfl split_ifs diff --git a/test/StacksAttribute.lean b/test/StacksAttribute.lean new file mode 100644 index 0000000000000..92fe5efb40fcd --- /dev/null +++ b/test/StacksAttribute.lean @@ -0,0 +1,77 @@ +import Mathlib.Tactic.StacksAttribute + +/-- info: No tags found. -/ +#guard_msgs in +#stacks_tags + +namespace X + +@[stacks A04Q "A comment", kerodon B15R "Also a comment"] +theorem tagged : True := .intro + +end X + +#guard_msgs in +@[stacks 0BR2, kerodon 0X12] +example : True := .intro + +@[stacks 0BR2, stacks 0X14 "I can also have a comment"] +example : True := .intro + +@[stacks 0X14 "I can also have a comment"] +example : True := .intro + +/-- +info: +[Stacks Tag A04Q](https://stacks.math.columbia.edu/tag/A04Q) corresponds to declaration 'X.tagged'. (A comment) +-/ +#guard_msgs in +#stacks_tags + +/-- +info: +[Stacks Tag A04Q](https://stacks.math.columbia.edu/tag/A04Q) corresponds to declaration 'X.tagged'. (A comment) +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.StacksTag + +def captureException (env : Environment) (s : ParserFn) (input : String) : Except String Syntax := + let ictx := mkInputContext input "" + let s := s.run ictx { env, options := {} } (getTokenTable env) (mkParserState input) + if !s.allErrors.isEmpty then + .error (s.toErrorMsg ictx) + else if ictx.input.atEnd s.pos then + .ok s.stxStack.back + else + .error ((s.mkError "end of input").toErrorMsg ictx) + +/-- error: :1:3: Stacks tags must be exactly 4 characters -/ +#guard_msgs in +run_cmd do + let _ ← Lean.ofExcept <| captureException (← getEnv) stacksTagFn "A05" + +/-- error: :1:4: Stacks tags must consist only of digits and uppercase letters. -/ +#guard_msgs in +run_cmd do + let _ ← Lean.ofExcept <| captureException (← getEnv) stacksTagFn "aaaa" + +/-- error: :1:0: expected stacks tag -/ +#guard_msgs in +run_cmd do + let env ← getEnv + let _ ← Lean.ofExcept <| captureException env stacksTagFn "\"A04Q\"" + +end errors diff --git a/test/StringDiagram.lean b/test/StringDiagram.lean index ec654cf09ce73..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. -/ @@ -24,7 +26,7 @@ lemma left_triangle {X Y : C} (η : 𝟙_ _ ⟶ X ⊗ Y) (ε : Y ⊗ X ⟶ 𝟙_ /- Place the cursor here and shift-click the 2-morphisms in the tactic state. -/ exact w.elim -/- Instead of writing `with_panel_widgets` everywhere, you can also use this command. -/ +/- Instead of writing `with_panel_widgets` everywhere, you can also use this command. -/ show_panel_widgets [local StringDiagram, local SelectionPanel] lemma yang_baxter {V₁ V₂ V₃ : C} (R : ∀ V₁ V₂ : C, V₁ ⊗ V₂ ⟶ V₂ ⊗ V₁) (w : False) : @@ -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 391a3a3bd3101..2371d40e8e971 100644 --- a/test/TCSynth.lean +++ b/test/TCSynth.lean @@ -63,7 +63,7 @@ section -- Initial issue: https://github.com/leanprover-community/mathlib4/issues/12230 open Complex in -set_option synthInstance.maxHeartbeats 3000 in +set_option synthInstance.maxHeartbeats 3200 in example (x : ℝ) : abs (cos x + sin x * I) = 1 := by simp end @@ -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/TermBeta.lean b/test/TermBeta.lean index 30a3b74742f04..f54d02ecde615 100644 --- a/test/TermBeta.lean +++ b/test/TermBeta.lean @@ -1,5 +1,6 @@ import Mathlib.Util.TermBeta -- On command line, tests format functions with => rather than ↦ without this. +set_option linter.style.setOption false set_option pp.unicode.fun true /-- info: (fun x ↦ x) true : Bool -/ @@ -23,7 +24,7 @@ set_option pp.unicode.fun true /-- info: ∀ (i : Nat), 0 ≤ i : Prop -/ #guard_msgs in #check ∀ i : Nat, beta% (fun j => 0 ≤ j) i -/-- info: (fun x x_1 ↦ x && x_1) true false : Bool -/ +/-- info: (fun x1 x2 ↦ x1 && x2) true false : Bool -/ #guard_msgs in #check (· && ·) true false /-- info: true && false : Bool -/ diff --git a/test/TermCongr.lean b/test/TermCongr.lean index 0f3376e1efaa0..c429d5c4d916a 100644 --- a/test/TermCongr.lean +++ b/test/TermCongr.lean @@ -160,3 +160,5 @@ example {s t : α → Prop} (h : s = t) (p : α → Prop) : congr(∀ (n : Subtype $h), p n) end limitations + +end Tests diff --git a/test/TypeCheck.lean b/test/TypeCheck.lean index c707c493a6bd8..9d38a614053df 100644 --- a/test/TypeCheck.lean +++ b/test/TypeCheck.lean @@ -1,5 +1,7 @@ import Mathlib.Tactic.TypeCheck +set_option linter.unusedTactic false + /-- A term where `inferType` returns `Prop`, but which does not type check. -/ elab "wrong" : term => return Lean.mkApp2 (.const ``id [.zero]) (.sort .zero) (.app (.sort .zero) (.sort .zero)) diff --git a/test/UnsetOption.lean b/test/UnsetOption.lean index b6cbbe719b387..796a26191f37b 100644 --- a/test/UnsetOption.lean +++ b/test/UnsetOption.lean @@ -1,5 +1,7 @@ import Mathlib.Tactic.UnsetOption +set_option linter.style.setOption false +set_option linter.unusedTactic false set_option pp.all true example : True := by diff --git a/test/UnusedTactic.lean b/test/UnusedTactic.lean index 5dd2b6a81221b..e12d30af91f30 100644 --- a/test/UnusedTactic.lean +++ b/test/UnusedTactic.lean @@ -4,7 +4,7 @@ import Mathlib.Tactic.AdaptationNote def why2 : True → True := (by refine ·) example : True := by - #adaptation_note /--hi-/ + #adaptation_note /-- hi -/ exact .intro -- both `;` and `<;>` are unseen by the linter diff --git a/test/Use.lean b/test/Use.lean index 9dd4b75d1c145..94acfd37571ab 100644 --- a/test/Use.lean +++ b/test/Use.lean @@ -205,8 +205,8 @@ example (α : Type u) : Embedding α α × Unit := by -- Note(kmill): mathlib3 `use` would try to rewrite any lingering existentials with -- `exists_prop` to turn them into conjunctions. It did not do this recursively. --- example : ∃ (n : Nat) (h : n > 0), n = n := --- by +set_option linter.style.longLine false in +-- example : ∃ (n : Nat) (h : n > 0), n = n := by -- use 1 -- -- goal should now be `1 > 0 ∧ 1 = 1`, whereas it would be `∃ (H : 1 > 0), 1 = 1` after existsi 1. -- guard_target = 1 > 0 ∧ 1 = 1 @@ -227,3 +227,5 @@ example (h1 : 1 > 0) : ∃ (n : Nat) (_h : n > 0), n = n := by example : let P : Nat → Prop := fun _x => ∃ _n : Nat, True; P 1 := by intro P use 1 + +end UseTests 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/Zify.lean b/test/Zify.lean index 0ff0f60de8ab5..a61537de310b2 100644 --- a/test/Zify.lean +++ b/test/Zify.lean @@ -29,11 +29,11 @@ example (a b : ℕ) (h : (a : ℤ) ≤ b) : a ≤ b := by guard_target = (a : ℤ) ≤ b exact h -/-example (a b : ℕ) (h : a = b ∧ b < a) : False := by +/- example (a b : ℕ) (h : a = b ∧ b < a) : False := by zify at h rcases h with ⟨ha, hb⟩ -- Preorder for `ℤ` is missing - exact ne_of_lt hb ha-/ + exact ne_of_lt hb ha -/ example (a b c : ℕ) (h : a - b < c) (hab : b ≤ a) : True := by zify [hab] at h 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..7cebc3123da0a --- /dev/null +++ b/test/algebraize.lean @@ -0,0 +1,96 @@ +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 + +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 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 := hf + trivial + +example (A B : Type*) [CommRing A] [CommRing B] (f : A →+* B) (hf : f.testProperty2) : True := by + algebraize [f] + guard_hyp algebraizeInst : Module.testProperty2 A B := hf + trivial + +example (A B : Type*) [CommRing A] [CommRing B] (f : A →+* B) (hf : f.testProperty3) : True := by + algebraize [f] + guard_hyp algebraizeInst : Algebra.testProperty3 A B := ⟨hf⟩ + 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 := hfg + guard_hyp scalarTowerInst := IsScalarTower.of_algebraMap_eq' rfl + trivial diff --git a/test/basicTactics.lean b/test/basicTactics.lean index 87c0505900a57..2eaa3aee8ce7e 100644 --- a/test/basicTactics.lean +++ b/test/basicTactics.lean @@ -5,6 +5,7 @@ example : ∀ a b : Nat, a = b → b = a := by introv h exact h.symm +set_option linter.unusedTactic false in example (n : Nat) : n = n := by induction n exacts [rfl, rfl] @@ -45,6 +46,7 @@ example (n m : Nat) : Unit := by cases m iterate exact () +set_option linter.unusedTactic false in example (n : Nat) : Nat := by iterate exact () -- silently succeeds, after iterating 0 times iterate exact n diff --git a/test/byContra.lean b/test/byContra.lean index dd0d781abe597..56a378b97d1e6 100644 --- a/test/byContra.lean +++ b/test/byContra.lean @@ -2,7 +2,6 @@ import Mathlib.Tactic.ByContra import Mathlib.Tactic.Rename import Mathlib.Tactic.Set -import Mathlib.Init.Data.Nat.Lemmas import Mathlib.Order.Basic import Mathlib.Data.Nat.Defs 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/casesm.lean b/test/casesm.lean index 5af4572b66196..327f1e0bda163 100644 --- a/test/casesm.lean +++ b/test/casesm.lean @@ -2,6 +2,7 @@ import Mathlib.Tactic.CasesM set_option autoImplicit true +set_option linter.unusedTactic false in example (h : a ∧ b ∨ c ∧ d) (h2 : e ∧ f) : True := by casesm* _∨_, _∧_ · clear ‹a› ‹b› ‹e› ‹f›; (fail_if_success clear ‹c›); trivial diff --git a/test/congr.lean b/test/congr.lean index 7dd402f4cb5dc..d1e2254a6dd4a 100644 --- a/test/congr.lean +++ b/test/congr.lean @@ -343,3 +343,16 @@ example {α : Type} (inst1 : BEq α) [LawfulBEq α] (inst2 : BEq α) [LawfulBEq α] (xs : List α) (x : α) : @List.erase _ inst1 xs x = @List.erase _ inst2 xs x := by congr! (config := { beqEq := false }) + + +/-! +Check that congruence theorem generator operates at default transparency. +Fixes error reported on Zulip: +https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/congr!.20internal.20error/near/464820779 +-/ + +def F := ∀ x : ℕ, x = 0 → ℕ +def F.A (_ : F) : ℕ := 0 +def F.B (_ : F) : ℕ := 0 +theorem bug (H : F) (hp : H.A = 0) (hp' : H.B = 0) : + H H.A hp = H H.B hp' := by with_reducible congr! diff --git a/test/convert.lean b/test/convert.lean index d260bb7ec431c..4f404da7265ba 100644 --- a/test/convert.lean +++ b/test/convert.lean @@ -110,6 +110,7 @@ example : True := by -- Prior to https://github.com/leanprover/lean4/pull/4493 it did, -- because previously bodies of `example`s were (confusingly!) allowed to -- affect the elaboration of the signature! +set_option linter.unusedTactic false in example {α β : Type u} [Fintype α] [Fintype β] : Fintype.card α = Fintype.card β := by congr! guard_target = Fintype.card α = Fintype.card β @@ -125,3 +126,5 @@ example (x y z : Nat) (h : x + y = z) : y + x = z := by convert_to y + x = _ at h · rw [Nat.add_comm] exact h + +end Tests diff --git a/test/delabLinearIndependent.lean b/test/delabLinearIndependent.lean index 68798c6dd1627..3dbfbf8b3fda9 100644 --- a/test/delabLinearIndependent.lean +++ b/test/delabLinearIndependent.lean @@ -1,6 +1,6 @@ import Mathlib.LinearAlgebra.LinearIndependent -set_option linter.setOption false +set_option linter.style.setOption false set_option pp.unicode.fun true variable {K V : Type*} [DivisionRing K] [AddCommGroup V] [Module K V] {s : Set V} {x : V} @@ -10,7 +10,7 @@ variable (h : LinearIndependent K (fun b => b : s → V)) in #guard_msgs in #check h variable (h : LinearIndependent K (Subtype.val : s → V)) in -/-- info: h : LinearIndependent (ι := { x // x ∈ s }) K Subtype.val -/ +/-- info: h : LinearIndependent K Subtype.val -/ #guard_msgs in #check h variable (h : LinearIndependent K (by exact Subtype.val : s → V)) in 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/fail_if_no_progress.lean b/test/fail_if_no_progress.lean index a4284da8a7c3a..3a69c7344ef13 100644 --- a/test/fail_if_no_progress.lean +++ b/test/fail_if_no_progress.lean @@ -2,6 +2,7 @@ import Mathlib.Tactic.FailIfNoProgress import Mathlib.Tactic.Basic set_option linter.unusedVariables false +set_option linter.style.setOption false set_option pp.unicode.fun true section success diff --git a/test/finset_builder.lean b/test/finset_builder.lean new file mode 100644 index 0000000000000..dadd88cf2edea --- /dev/null +++ b/test/finset_builder.lean @@ -0,0 +1,69 @@ +import Mathlib.Order.Interval.Finset.Basic + +/-! +# Examples of finset builder notation +-/ + +open Finset + +variable {α : Type*} (p : α → Prop) [DecidablePred p] + +/-! ## `Data.Finset.Basic` -/ + +example (s : Finset α) : {x ∈ s | p x} = s.filter p := rfl + +/-! ## `Data.Fintype.Basic` -/ + +section Fintype +variable [Fintype α] + +example : ({x | p x} : Finset α) = univ.filter p := rfl +example : ({x : α | p x} : Finset α) = univ.filter p := rfl + +-- If the type of `s` (or the entire expression) is `Finset ?α`, elaborate as `Finset`; +-- otherwise as `Set` +example (s : Finset α) : {x ∈ s | p x} = s.filter p := rfl +example (s : Finset α) : ({x ∈ s | p x} : Set α) = setOf fun x => x ∈ s ∧ p x := rfl +example (s : Finset α) : {x ∈ (s : Set α) | p x} = setOf fun x => x ∈ s ∧ p x := rfl + +-- elaborate as `Set` if no expected type present +example : {x | p x} = setOf p := rfl +example : {x : α | p x} = setOf p := rfl + +variable [DecidableEq α] + +example (s : Finset α) : {x ∉ s | p x} = sᶜ.filter p := rfl +example (a : α) : ({x ≠ a | p x} : Finset α) = ({a}ᶜ : Finset α).filter p := rfl + +-- elaborate as `Set` if the `s` or the expected type is not `Finset ?α` +example (s : Set α) : {x ∉ s | p x} = setOf fun x => x ∉ s ∧ p x := rfl +example (a : α) : {x ≠ a | p x} = setOf fun x => x ≠ a ∧ p x := rfl + +end Fintype + +/-! ## `Order.Interval.Finset.Basic` -/ + +section LocallyFiniteOrderBot +variable [Preorder α] [LocallyFiniteOrderBot α] + +example (a : α) : ({x ≤ a | p x} : Finset α) = (Iic a).filter p := rfl +example (a : α) : ({x < a | p x} : Finset α) = (Iio a).filter p := rfl + +-- elaborate as `Set` if the expected type is not `Finset ?α` +example (a : α) : {x ≤ a | p x} = setOf fun x => x ≤ a ∧ p x := rfl +example (a : α) : {x < a | p x} = setOf fun x => x < a ∧ p x := rfl + +end LocallyFiniteOrderBot + +section LocallyFiniteOrderTop +variable [Preorder α] [LocallyFiniteOrderTop α] + +example (a : α) : ({x ≥ a | p x} : Finset α) = (Ici a).filter p := rfl +example (a : α) : ({x > a | p x} : Finset α) = (Ioi a).filter p := rfl + +-- elaborate as `Set` if the expected type is not `Finset ?α` +example (a : α) : {x ≥ a | p x} = setOf fun x => x ≥ a ∧ p x := rfl +example (a : α) : {x > a | p x} = setOf fun x => x > a ∧ p x := rfl + +end LocallyFiniteOrderTop + diff --git a/test/finsupp_notation.lean b/test/finsupp_notation.lean index e713fedca935a..e042b67a8903f 100644 --- a/test/finsupp_notation.lean +++ b/test/finsupp_notation.lean @@ -21,7 +21,7 @@ info: reprStr (Finsupp.mk {1, 2} (fun | 1 | 2 => 3 | _ => 0) (fun x => by aesop)) = "fun₀ | 1 => 3 | 2 => 3" -/-! ## (computable) number theory examples-/ +/-! ## (computable) number theory examples -/ /-- info: fun₀ | 2 => 2 | 7 => 1 -/ #guard_msgs in diff --git a/test/fun_prop.lean b/test/fun_prop.lean index 5b7a7d504d31b..953fa071dd9a3 100644 --- a/test/fun_prop.lean +++ b/test/fun_prop.lean @@ -188,7 +188,7 @@ The theorem `Measurable.apply_continuousLinearMap` states measurability in `f` i form. -/ -set_option linter.longLine false in +set_option linter.style.longLine false in attribute [fun_prop] ContinuousLinearMap.measurable -- Measurable fun (x : E) => DFunLike.coe L x ContinuousLinearMap.measurable_comp -- Measurable φ → Measurable fun (x : E) => DFunLike.coe L (φ x) @@ -203,7 +203,7 @@ A silly example that everything together works as expected example (f : ℝ → ℝ → (ℝ →L[ℝ] ℝ)) (hf : Continuous (fun (x,y) => f x y)) : Measurable fun x => (f (x / x) (x * x) 1 + x) := by fun_prop -set_option linter.longLine false in +set_option linter.style.longLine false in /-! In the current state of `fun_prop`, morphism theorems **have to** be stated in compositional form. Sometimes they might work in uncurried form but `fun_prop` is not designed that way right now. diff --git a/test/fun_prop2.lean b/test/fun_prop2.lean index 4fcc1f27e7a48..e98b764c72c0a 100644 --- a/test/fun_prop2.lean +++ b/test/fun_prop2.lean @@ -38,11 +38,11 @@ example : Continuous fun ((_, _, z) : ℝ × ℝ × ℝ) ↦ z := by fun_prop @[fun_prop] theorem ContinuousOn.log' : ContinuousOn Real.log {0}ᶜ := ContinuousOn.log (by fun_prop) (by aesop) --- Notice that no theorems about measuability of log are used. It is infered from continuity. +-- Notice that no theorems about measuability of log are used. It is inferred from continuity. example : Measurable (fun x => x * (Real.log x) ^ 2 - Real.exp x / x) := by fun_prop --- Notice that no theorems about measuability of log are used. It is infered from continuity. +-- Notice that no theorems about measuability of log are used. It is inferred from continuity. example : AEMeasurable (fun x => x * (Real.log x) ^ 2 - Real.exp x / x) := by fun_prop (config:={maxTransitionDepth:=2}) diff --git a/test/fun_prop_dev.lean b/test/fun_prop_dev.lean index c9443462421a9..f78abae43617a 100644 --- a/test/fun_prop_dev.lean +++ b/test/fun_prop_dev.lean @@ -6,6 +6,7 @@ Authors: Tomáš Skřivan import Mathlib.Tactic.FunProp import Mathlib.Logic.Function.Basic import Mathlib.Data.FunLike.Basic +import Aesop /-! # Tests for the `fun_prop` tactic @@ -13,6 +14,8 @@ This file is designed for development of fun_prop and does not depend on most of two function properties `Con` and `Lin` which roughly correspond to `Continuity` and `IsLinearMap`. -/ +set_option linter.style.longLine false + open Function variable {α β γ δ ι : Type _} {E : α → Type _} @@ -25,18 +28,13 @@ set_option linter.unusedVariables false -- define function propositions -- ---------------------------------- -class Obj (α : Type _) : Type where - -instance [Obj α] [Obj β] : Obj (α × β) := ⟨⟩ -instance [∀ x, Obj (E x)] : Obj ((x' : α) → E x') := ⟨⟩ -instance : Obj Nat := ⟨⟩ - @[fun_prop] opaque Con {α β} (f : α → β) : Prop @[fun_prop] opaque Lin {α β} (f : α → β) : Prop -- state basic lambda calculus rules -- --------------------------------------- +-- variable [Obj α] [Obj β] [Obj γ] [Obj δ] [∀ x, Obj (E x)] @[fun_prop] theorem Con_id : Con (id : α → α) := silentSorry @[fun_prop] theorem Con_const (y : β) : Con (fun x : α => y) := silentSorry @@ -48,7 +46,7 @@ instance : Obj Nat := ⟨⟩ -- Lin is missing `const` theorem @[fun_prop] theorem Lin_id : Lin (fun x : α => x) := silentSorry -@[fun_prop] theorem Lin_const {β} [Obj β] [Zero β] : Lin (fun x : α => (0 : β)) := silentSorry +@[fun_prop] theorem Lin_const {β} [Zero β] : Lin (fun x : α => (0 : β)) := silentSorry @[fun_prop] theorem Lin_apply (x : α) : Lin (fun f : α → β => f x) := silentSorry @[fun_prop] theorem Lin_applyDep (x : α) : Lin (fun f : (x' : α) → E x' => f x) := silentSorry @[fun_prop] theorem Lin_comp (f : β → γ) (g : α → β) (hf : Lin f) (hg : Lin g) : Lin (f ∘ g) := silentSorry @@ -109,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 @@ -130,13 +128,10 @@ instance [HasUncurry β γ δ] : HasUncurry (α -o β) (α × γ) δ := ⟨fun f p ↦ (↿(f p.1)) p.2⟩ -instance : Obj (α ->> β) := ⟨⟩ -instance : Obj (α -o β) := ⟨⟩ - -- morphism theorems i.e. theorems about `FunLike.coe` -- --------------------------------------------------------- --- this is some form of cartesion closedness with homs `α ->> β` +-- this is some form of cartesian closedness with homs `α ->> β` @[fun_prop] theorem conHom_con' (f : α → β ->> γ) (g : α → β) (hf : Con f) (hg : Con g) : Con (fun x => (f x) (g x)) := silentSorry @[fun_prop] theorem conHom_lin_in_fn' (f : α → β ->> γ) (y : β) (hf : Lin f) : Lin (fun x => f x y) := silentSorry @@ -165,7 +160,7 @@ example [Add β] (f : α → β → γ) (hx : ∀ y, Lin (f · y)) (hy : ∀ x, example [Add α] (f : α → α → α → α) (hx : ∀ x y, Lin (f x y ·)) (hy : ∀ x z, Lin (f x · z)) (hz : ∀ y z, Lin (f · y z)) : Lin (fun x => fun y z ⊸ f z (x+x) y) := by fun_prop --- the only analoge is this theorem but that is alredy provable +-- the only analogue is this theorem but that is already provable example (f : α → β -o γ) (g : α → β) (hf : Lin (fun (x,y) => f x y)) (hg : Lin g) : Lin (fun x => (f x) (g x)) := by fun_prop @@ -239,6 +234,7 @@ example (f : α → β ->> γ) (hf : Con fun (x,y) => f x y) (y) : Con fun x => example (f : α → β ->> γ) (hf : Con fun (x,y) => f x y) : Con fun x y => f x y := by fun_prop example (f : α → β ->> γ) (hf : Con fun (x,y) => f x y) (x) : Con fun y => f x y := by fun_prop example (f : α → α ->> (α → α)) (hf : Con fun (x,y,z) => f x y z) (x) : Con fun y => f x y := by fun_prop +example (f : α → α ->> (α → α)) (y : α) (hf : Con fun (x,y,z) => f x y z) : Con fun x => f y x x := by fun_prop example (f : α → α ->> (α → α)) (hf : Con fun (x,y,z) => f x y z) : Con fun x y => f y x x := by fun_prop example (f : α → β ->> γ) (hf : Con ↿f) (y) : Con fun x => f x y := by fun_prop @@ -317,7 +313,7 @@ example (x) : Con fun (f : α ->> α) => f (f x) := by fun_prop example (x) : Con fun (f : α ->> α) => f (f (f x)) := by fun_prop -example [Zero α] [Obj α] [Add α] : Lin (fun x : α => (0 : α) + x + (0 : α) + (0 : α) + x) := by fun_prop +example [Zero α] [Add α] : Lin (fun x : α => (0 : α) + x + (0 : α) + (0 : α) + x) := by fun_prop noncomputable def foo : α ->> α ->> α := silentSorry @@ -463,3 +459,97 @@ Issues: -/ #guard_msgs in example : Con (fun x : α => f3 x) := by fun_prop (config:={maxTransitionDepth:=0}) + +@[fun_prop] opaque Dif (𝕜:Type) [Add 𝕜] {α β} (f : α → β) : Prop + +variable {𝕜 : Type} +@[fun_prop] theorem Dif_id [Add 𝕜] : Dif 𝕜 (id : α → α) := silentSorry +@[fun_prop] theorem Dif_const [Add 𝕜] (y : β) : Dif 𝕜 (fun x : α => y) := silentSorry +@[fun_prop] theorem Dif_apply [Add 𝕜] (x : α) : Dif 𝕜 (fun f : α → β => f x) := silentSorry +@[fun_prop] theorem Dif_applyDep [Add 𝕜] (x : α) : Dif 𝕜 (fun f : (x' : α) → E x' => f x) := silentSorry +@[fun_prop] theorem Dif_comp [Add 𝕜] (f : β → γ) (g : α → β) (hf : Dif 𝕜 f) (hg : Dif 𝕜 g) : Dif 𝕜 (fun x => f (g x)) := silentSorry +@[fun_prop] theorem Dif_pi [Add 𝕜] (f : β → (i : α) → (E i)) (hf : ∀ i, Dif 𝕜 (fun x => f x i)) : Dif 𝕜 (fun x i => f x i) := silentSorry + +@[fun_prop] +theorem Dif_Con [Add 𝕜] (f : α → β) (hf : Dif 𝕜 f) : Con f := silentSorry + +def f4 (a : α) := a + +example (hf : Dif Nat (f4 : α → α)) : Con (f4 : α → α) := by fun_prop (disch:=aesop) + +@[fun_prop] +theorem f4_dif : Dif Nat (f4 : α → α) := silentSorry + +example (hf : Dif Nat (f4 : α → α)) : Con (f4 : α → α) := by fun_prop (disch:=aesop) + + +-- Test abbrev transparency +abbrev my_id {α} (a : α) := a +example : Con (fun x : α => my_id x) := by fun_prop +example (f : α → β) (hf : Con (my_id f)) : Con f := by fun_prop + +-- Testing some issues with bundled morphisms of multiple arguments +structure Mor where + toFun : Int → Int → Int + hcon : Con (fun (x,y) => toFun x y) + +@[fun_prop] +theorem Mor.toFun_Con (m : Mor) (f g : α → Int) (hf : Con f) (g : α → Int) (hg : Con g) : + Con (fun x => m.toFun (f x) (g x)) := by + have := m.hcon + fun_prop + +-- Test improved beta reduction of the head function when we interleave lambdas and lets +example [Add α] (a : α) : Con (fun x0 : α => + (fun x => + let y := x + x + fun z : α => + x + y + z) x0 a) := by fun_prop + +example [Add α] (a : α) : + let f := (fun x : α => + let y := x + x + fun z : α => + x + y + z) + Con (fun x => f x a) := by fun_prop + +example [Add α] (a a' : α) : Con (fun x0 : α => + (fun x => + let y := x + x + fun z : α => + let h := x + y + z + fun w => + w + x + y + z + h) x0 a a') := by fun_prop + + +-- test that local function is being properly unfolded +example [Add α] (a : α) : + let f := (fun x : α => + let y := x + x + fun z : α => + x + y + z) + Con (fun x => + f x a) := by + fun_prop + + +-- Test that local theorem is being used +/-- +info: [Meta.Tactic.fun_prop] [✅️] Con fun x => f x y + [Meta.Tactic.fun_prop] candidate local theorems for f #[this : Con f] + [Meta.Tactic.fun_prop] removing argument to later use this : Con f + [Meta.Tactic.fun_prop] [✅️] applying: Con_comp + [Meta.Tactic.fun_prop] [✅️] Con fun f => f y + [Meta.Tactic.fun_prop] [✅️] applying: Con_apply + [Meta.Tactic.fun_prop] [✅️] Con fun x => f x + [Meta.Tactic.fun_prop] candidate local theorems for f #[this : Con f] + [Meta.Tactic.fun_prop] [✅️] applying: this : Con f +-/ +#guard_msgs in +example [Add α] (y : α): + let f := (fun x y : α => x+x+y) + Con (fun x => f x y) := by + intro f + have : Con f := by fun_prop + set_option trace.Meta.Tactic.fun_prop true in + fun_prop diff --git a/test/instance_diamonds.lean b/test/instance_diamonds.lean index 7b746593fdb05..f26a6b719c7ff 100644 --- a/test/instance_diamonds.lean +++ b/test/instance_diamonds.lean @@ -141,7 +141,7 @@ example : @Monoid.toMulOneClass (Multiplicative ℕ) CommMonoid.toMonoid = end Multiplicative -/-! ## `Finsupp` instances-/ +/-! ## `Finsupp` instances -/ section Finsupp diff --git a/test/instance_diamonds/algebra_rat.lean b/test/instance_diamonds/algebra_rat.lean new file mode 100644 index 0000000000000..ac1fa3612b061 --- /dev/null +++ b/test/instance_diamonds/algebra_rat.lean @@ -0,0 +1,7 @@ +import Mathlib.Algebra.Algebra.Rat + +/-- The two `Algebra ℚ≥0 ℚ≥0` instances should coincide. -/ +example : DivisionSemiring.toNNRatAlgebra = Algebra.id ℚ≥0 := rfl + +/-- The two `Algebra ℚ ℚ` instances should coincide. -/ +example : DivisionRing.toRatAlgebra = Algebra.id ℚ := rfl diff --git a/test/interactiveUnfold.lean b/test/interactiveUnfold.lean index 0d6bdbed1193f..b17d3daa3cae8 100644 --- a/test/interactiveUnfold.lean +++ b/test/interactiveUnfold.lean @@ -57,14 +57,15 @@ 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 /-- info: Unfolds for 3 ∈ {1, 2, 3}: -· Set.Mem 3 {1, 2, 3} +· {1, 2, 3}.Mem 3 · {1, 2, 3} 3 · Set.insert 1 {2, 3} 3 · {b | b = 1 ∨ b ∈ {2, 3}} 3 @@ -85,7 +86,7 @@ variable (A B : Set Nat) (n : Nat) /-- info: Unfolds for 1 ∈ A ∪ B: -· Set.Mem 1 (A ∪ B) +· (A ∪ B).Mem 1 · (A ∪ B) 1 · A.union B 1 · {a | a ∈ A ∨ a ∈ B} 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/itauto.lean b/test/itauto.lean index b628906eca815..94353f251dd30 100644 --- a/test/itauto.lean +++ b/test/itauto.lean @@ -55,6 +55,7 @@ example (b : Bool) : ¬b ∨ b := by itauto * example (p : Prop) : ¬p ∨ p := by itauto! [p] example (p : Prop) : ¬p ∨ p := by itauto! * +set_option linter.unusedTactic false in -- failure tests example (p q r : Prop) : True := by haveI : p ∨ ¬p := by (fail_if_success itauto); sorry diff --git a/test/lift.lean b/test/lift.lean index a8c84bce02c83..979eed74ce45c 100644 --- a/test/lift.lean +++ b/test/lift.lean @@ -1,8 +1,8 @@ import Mathlib.Tactic.Lift import Batteries.Tactic.PermuteGoals import Mathlib.Tactic.Coe -import Mathlib.Init.Set -import Mathlib.Order.Basic +import Mathlib.Data.Set.Defs +import Mathlib.Order.WithBot import Mathlib.Algebra.Group.WithOne.Defs import Mathlib.Data.Set.Image import Mathlib.Data.Set.List diff --git a/test/linear_combination'.lean b/test/linear_combination'.lean new file mode 100644 index 0000000000000..14516504da879 --- /dev/null +++ b/test/linear_combination'.lean @@ -0,0 +1,294 @@ +import Mathlib.Tactic.LinearCombination' +import Mathlib.Tactic.Linarith + + +set_option autoImplicit true + +private axiom test_sorry : ∀ {α}, α + +-- We deliberately mock R here so that we don't have to import the deps +axiom Real : Type +notation "ℝ" => Real +@[instance] axiom Real.linearOrderedField : LinearOrderedField ℝ + +/-! ### Simple Cases with ℤ and two or less equations -/ + +example (x y : ℤ) (h1 : 3 * x + 2 * y = 10) : 3 * x + 2 * y = 10 := by + linear_combination' 1 * h1 + +example (x y : ℤ) (h1 : 3 * x + 2 * y = 10) : 3 * x + 2 * y = 10 := by + linear_combination' h1 + +example (x y : ℤ) (h1 : x + 2 = -3) (_h2 : y = 10) : 2 * x + 4 = -6 := by + linear_combination' 2 * h1 + +example (x y : ℤ) (h1 : x * y + 2 * x = 1) (h2 : x = y) : x * y = -2 * y + 1 := by + linear_combination' 1 * h1 - 2 * h2 + +example (x y : ℤ) (h1 : x * y + 2 * x = 1) (h2 : x = y) : x * y = -2 * y + 1 := by + linear_combination' -2 * h2 + h1 + +example (x y : ℤ) (h1 : x + 2 = -3) (h2 : y = 10) : 2 * x + 4 - y = -16 := by + linear_combination' 2 * h1 + -1 * h2 + +example (x y : ℤ) (h1 : x + 2 = -3) (h2 : y = 10) : -y + 2 * x + 4 = -16 := by + linear_combination' -h2 + 2 * h1 + +example (x y : ℤ) (h1 : 3 * x + 2 * y = 10) (h2 : 2 * x + 5 * y = 3) : 11 * y = -11 := by + linear_combination' -2 * h1 + 3 * h2 + +example (x y : ℤ) (h1 : 3 * x + 2 * y = 10) (h2 : 2 * x + 5 * y = 3) : -11 * y = 11 := by + linear_combination' 2 * h1 - 3 * h2 + +example (x y : ℤ) (h1 : 3 * x + 2 * y = 10) (h2 : 2 * x + 5 * y = 3) : -11 * y = 11 + 1 - 1 := by + linear_combination' 2 * h1 + -3 * h2 + +example (x y : ℤ) (h1 : 10 = 3 * x + 2 * y) (h2 : 3 = 2 * x + 5 * y) : 11 + 1 - 1 = -11 * y := by + linear_combination' 2 * h1 - 3 * h2 + +/-! ### More complicated cases with two equations -/ + +example (x y : ℤ) (h1 : x + 2 = -3) (h2 : y = 10) : -y + 2 * x + 4 = -16 := by + linear_combination' 2 * h1 - h2 + +example (x y : ℚ) (h1 : 3 * x + 2 * y = 10) (h2 : 2 * x + 5 * y = 3) : -11 * y + 1 = 11 + 1 := by + linear_combination' 2 * h1 - 3 * h2 + +example (a b : ℝ) (ha : 2 * a = 4) (hab : 2 * b = a - b) : b = 2 / 3 := by + linear_combination' ha / 6 + hab / 3 + +/-! ### Cases with more than 2 equations -/ + +example (a b : ℝ) (ha : 2 * a = 4) (hab : 2 * b = a - b) (hignore : 3 = a + b) : b = 2 / 3 := by + linear_combination' 1 / 6 * ha + 1 / 3 * hab + 0 * hignore + +example (x y z : ℝ) (ha : x + 2 * y - z = 4) (hb : 2 * x + y + z = -2) (hc : x + 2 * y + z = 2) : + -3 * x - 3 * y - 4 * z = 2 := by linear_combination' ha - hb - 2 * hc + +example (x y z : ℝ) (ha : x + 2 * y - z = 4) (hb : 2 * x + y + z = -2) (hc : x + 2 * y + z = 2) : + 6 * x = -10 := by + linear_combination' 1 * ha + 4 * hb - 3 * hc + +example (x y z : ℝ) (ha : x + 2 * y - z = 4) (hb : 2 * x + y + z = -2) (hc : x + 2 * y + z = 2) : + 10 = 6 * -x := by + linear_combination' ha + 4 * hb - 3 * hc + +example (w x y z : ℝ) (h1 : x + 2.1 * y + 2 * z = 2) (h2 : x + 8 * z + 5 * w = -6.5) + (h3 : x + y + 5 * z + 5 * w = 3) : x + 2.2 * y + 2 * z - 5 * w = -8.5 := by + linear_combination' 2 * h1 + 1 * h2 - 2 * h3 + +example (w x y z : ℝ) (h1 : x + 2.1 * y + 2 * z = 2) (h2 : x + 8 * z + 5 * w = -6.5) + (h3 : x + y + 5 * z + 5 * w = 3) : x + 2.2 * y + 2 * z - 5 * w = -8.5 := by + linear_combination' 2 * h1 + h2 - 2 * h3 + +example (a b c d : ℚ) (h1 : a = 4) (h2 : 3 = b) (h3 : c * 3 = d) (h4 : -d = a) : + 2 * a - 3 + 9 * c + 3 * d = 8 - b + 3 * d - 3 * a := by + linear_combination' 2 * h1 - 1 * h2 + 3 * h3 - 3 * h4 + +example (a b c d : ℚ) (h1 : a = 4) (h2 : 3 = b) (h3 : c * 3 = d) (h4 : -d = a) : + 6 - 3 * c + 3 * a + 3 * d = 2 * b - d + 12 - 3 * a := by + linear_combination' 2 * h2 - h3 + 3 * h1 - 3 * h4 + +/-! ### Cases with non-hypothesis inputs -/ + +axiom qc : ℚ +axiom hqc : qc = 2 * qc + +example (a b : ℚ) (h : ∀ p q : ℚ, p = q) : 3 * a + qc = 3 * b + 2 * qc := by + linear_combination' 3 * h a b + hqc + +axiom bad (q : ℚ) : q = 0 + +example (a b : ℚ) : a + b ^ 3 = 0 := by linear_combination' bad a + b * bad (b * b) + +/-! ### Cases with arbitrary coefficients -/ + +example (a b : ℤ) (h : a = b) : a * a = a * b := by linear_combination' a * h + +example (a b c : ℤ) (h : a = b) : a * c = b * c := by linear_combination' c * h + +example (a b c : ℤ) (h1 : a = b) (h2 : b = 1) : c * a + b = c * b + 1 := by + linear_combination' c * h1 + h2 + +example (x y : ℚ) (h1 : x + y = 3) (h2 : 3 * x = 7) : + x * x * y + y * x * y + 6 * x = 3 * x * y + 14 := by + linear_combination' x * y * h1 + 2 * h2 + +example {α} [h : CommRing α] {a b c d e f : α} (h1 : a * d = b * c) (h2 : c * f = e * d) : + c * (a * f - b * e) = 0 := by linear_combination' e * h1 + a * h2 + +example (x y z w : ℚ) (hzw : z = w) : x * z + 2 * y * z = x * w + 2 * y * w := by + linear_combination' (x + 2 * y) * hzw + +example (x : ℤ) : x ^ 2 = x ^ 2 := by linear_combination' x ^ 2 + +example (x y : ℤ) (h : x = 0) : y ^ 2 * x = 0 := by linear_combination' y ^ 2 * h + +/-! ### Cases that explicitly use a config -/ + +example (x y : ℚ) (h1 : 3 * x + 2 * y = 10) (h2 : 2 * x + 5 * y = 3) : -11 * y + 1 = 11 + 1 := by + linear_combination' (norm := ring) 2 * h1 - 3 * h2 + +example (x y : ℚ) (h1 : 3 * x + 2 * y = 10) (h2 : 2 * x + 5 * y = 3) : -11 * y + 1 = 11 + 1 := by + linear_combination' (norm := ring1) 2 * h1 + -3 * h2 + +example (a b : ℝ) (ha : 2 * a = 4) (hab : 2 * b = a - b) : b = 2 / 3 := by + linear_combination' (norm := ring_nf) 1 / 6 * ha + 1 / 3 * hab + +example (x y : ℤ) (h1 : 3 * x + 2 * y = 10) : 3 * x + 2 * y = 10 := by + linear_combination' (norm := simp) h1 + +/-! ### Cases that have linear_combination' skip normalization -/ + +example (a b : ℝ) (ha : 2 * a = 4) (hab : 2 * b = a - b) : b = 2 / 3 := by + linear_combination' (norm := skip) 1 / 6 * ha + 1 / 3 * hab + linarith + +example (x y : ℤ) (h1 : x = -3) (_h2 : y = 10) : 2 * x = -6 := by + linear_combination' (norm := skip) 2 * h1 + simp (config := {decide := true}) + +/-! ### Cases without any arguments provided -/ + +-- the corner case is "just apply the normalization procedure". +example {x y z w : ℤ} (_h₁ : 3 * x = 4 + y) (_h₂ : x + 2 * y = 1) : z + w = w + z := by + linear_combination' + +-- this interacts as expected with options +example {x y z w : ℤ} (_h₁ : 3 * x = 4 + y) (_h₂ : x + 2 * y = 1) : z + w = w + z := by + linear_combination' (norm := skip) + guard_target = z + w - (w + z) - (0 - 0) = 0 + simp [add_comm] + +example {x y z w : ℤ} (_h₁ : 3 * x = 4 + y) (_h₂ : x + 2 * y = 1) : z + w = w + z := by + linear_combination' (norm := simp [add_comm]) + +/-! ### Cases where the goal is not closed -/ + +example (x y : ℚ) (h1 : x + y = 3) (h2 : 3 * x = 7) : + x * x * y + y * x * y + 6 * x = 3 * x * y + 14 := by + linear_combination' (norm := ring_nf) x * y * h1 + h2 + guard_target = -7 + x * 3 = 0 + linear_combination' h2 + +example (a b c d : ℚ) (h1 : a = 4) (h2 : 3 = b) (h3 : c * 3 = d) (h4 : -d = a) : + 6 - 3 * c + 3 * a + 3 * d = 2 * b - d + 12 - 3 * a := by + linear_combination' (norm := ring_nf) 2 * h2 + linear_combination' (norm := ring_nf) -h3 + linear_combination' (norm := ring_nf) 3 * h1 + linear_combination' (norm := ring_nf) -3 * h4 + +example (x y : ℤ) (h1 : x * y + 2 * x = 1) (h2 : x = y) : x * y = -2 * y + 1 := by + linear_combination' (norm := ring_nf) + linear_combination' h1 - 2 * h2 + +/-! ### 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 + +-- This should fail because the second coefficient has a different type than +-- the equations it is being combined with. This was a design choice for the +-- sake of simplicity, but the tactic could potentially be modified to allow +-- this behavior. +/-- +error: application type mismatch + Mathlib.Tactic.LinearCombination'.c_mul_pf h2 0 +argument + 0 +has type + ℝ : Type +but is expected to have type + ℤ : Type +-/ +#guard_msgs in +example (x y : ℤ) (h1 : x * y + 2 * x = 1) (h2 : x = y) : x * y + 2 * x = 1 := by + linear_combination' h1 + (0 : ℝ) * h2 + +-- This fails because the linear_combination' tactic requires the equations +-- and coefficients to use a type that fulfills the add_group condition, +-- and ℕ does not. +example (a _b : ℕ) (h1 : a = 3) : a = 3 := by + fail_if_success linear_combination' h1 + linear_combination2 h1 + +example (a b : ℤ) (x y : ℝ) (hab : a = b) (hxy : x = y) : 2 * x = 2 * y := by + fail_if_success linear_combination' 2 * hab + linear_combination' 2 * hxy + +/-! ### Cases with exponent -/ + +example (x y z : ℚ) (h : x = y) (h2 : x * y = 0) : x + y*z = 0 := by + linear_combination' (exp := 2) (-y * z ^ 2 + x) * h + (z ^ 2 + 2 * z + 1) * h2 + +example (x y z : ℚ) (h : x = y) (h2 : x * y = 0) : y*z = -x := by + linear_combination' (norm := skip) (exp := 2) (-y * z ^ 2 + x) * h + (z ^ 2 + 2 * z + 1) * h2 + ring + +example (K : Type) + [Field K] + [CharZero K] + {x y z : K} + (h₂ : y ^ 3 + x * (3 * z ^ 2) = 0) + (h₁ : x ^ 3 + z * (3 * y ^ 2) = 0) + (h₀ : y * (3 * x ^ 2) + z ^ 3 = 0) + (h : x ^ 3 * y + y ^ 3 * z + z ^ 3 * x = 0) : + x = 0 := by + linear_combination' (exp := 6) 2 * y * z ^ 2 * h₂ / 7 + (x ^ 3 - y ^ 2 * z / 7) * h₁ - + x * y * z * h₀ + y * z * h / 7 + + +/-! ### Regression tests -/ + +def g (a : ℤ) : ℤ := a ^ 2 + +example (h : g a = g b) : a ^ 4 = b ^ 4 := by + dsimp [g] at h + linear_combination' (a ^ 2 + b ^ 2) * h + +example {r s a b : ℕ} (h₁ : (r : ℤ) = a + 1) (h₂ : (s : ℤ) = b + 1) : + r * s = (a + 1 : ℤ) * (b + 1) := by + linear_combination' (↑b + 1) * h₁ + ↑r * h₂ + +-- Implementation at the time of the port (Nov 2022) was 110,000 heartbeats. +-- Eagerly elaborating leaf nodes brings this to 7,540 heartbeats. +set_option maxHeartbeats 8000 in +example (K : Type*) [Field K] [CharZero K] {x y z p q : K} + (h₀ : 3 * x ^ 2 + z ^ 2 * p = 0) + (h₁ : z * (2 * y) = 0) + (h₂ : -y ^ 2 + p * x * (2 * z) + q * (3 * z ^ 2) = 0) : + ((27 * q ^ 2 + 4 * p ^ 3) * x) ^ 4 = 0 := by + linear_combination' (norm := skip) + (256 / 3 * p ^ 12 * x ^ 2 + 128 * q * p ^ 11 * x * z + 2304 * q ^ 2 * p ^ 9 * x ^ 2 + + 2592 * q ^ 3 * p ^ 8 * x * z - + 64 * q * p ^ 10 * y ^ 2 + + 23328 * q ^ 4 * p ^ 6 * x ^ 2 + + 17496 * q ^ 5 * p ^ 5 * x * z - + 1296 * q ^ 3 * p ^ 7 * y ^ 2 + + 104976 * q ^ 6 * p ^ 3 * x ^ 2 + + 39366 * q ^ 7 * p ^ 2 * x * z - + 8748 * q ^ 5 * p ^ 4 * y ^ 2 + + 177147 * q ^ 8 * x ^ 2 - + 19683 * q ^ 7 * p * y ^ 2) * + h₀ + + (-(64 / 3 * p ^ 12 * x * y) + 32 * q * p ^ 11 * z * y - 432 * q ^ 2 * p ^ 9 * x * y + + 648 * q ^ 3 * p ^ 8 * z * y - + 2916 * q ^ 4 * p ^ 6 * x * y + + 4374 * q ^ 5 * p ^ 5 * z * y - + 6561 * q ^ 6 * p ^ 3 * x * y + + 19683 / 2 * q ^ 7 * p ^ 2 * z * y) * + h₁ + + (-(128 / 3 * p ^ 12 * x * z) - 192 * q * p ^ 10 * x ^ 2 - 864 * q ^ 2 * p ^ 9 * x * z - + 3888 * q ^ 3 * p ^ 7 * x ^ 2 - + 5832 * q ^ 4 * p ^ 6 * x * z - + 26244 * q ^ 5 * p ^ 4 * x ^ 2 - + 13122 * q ^ 6 * p ^ 3 * x * z - + 59049 * q ^ 7 * p * x ^ 2) * + h₂ + exact test_sorry diff --git a/test/linear_combination.lean b/test/linear_combination.lean index efb18bd1c26d2..9f652a8186a63 100644 --- a/test/linear_combination.lean +++ b/test/linear_combination.lean @@ -120,10 +120,53 @@ example {α} [h : CommRing α] {a b c d e f : α} (h1 : a * d = b * c) (h2 : c * example (x y z w : ℚ) (hzw : z = w) : x * z + 2 * y * z = x * w + 2 * y * w := by linear_combination (x + 2 * y) * hzw -example (x : ℤ) : x ^ 2 = x ^ 2 := by linear_combination x ^ 2 - example (x y : ℤ) (h : x = 0) : y ^ 2 * x = 0 := by linear_combination y ^ 2 * h +/-! ### Tests in semirings -/ + +example (a _b : ℕ) (h1 : a = 3) : a = 3 := by + linear_combination h1 + +example {a b : ℕ} (h1 : a = b + 4) (h2 : b = 2) : a = 6 := by + linear_combination h1 + h2 + +example {a : ℕ} (h : a = 3) : 3 = a := by linear_combination -h + +example {a b : ℕ} (h1 : 3 * a = b + 5) (h2 : 2 * a = b + 3) : a = 2 := by + linear_combination h1 - h2 + +/- Note: currently negation/subtraction is handled differently in "constants" than in "proofs", so +in particular negation/subtraction does not "distribute". The following four tests record the +current behaviour, without taking a stance on whether this should be considered a feature or a bug. +-/ + +example {a : ℕ} (h : a = 3) : a ^ 2 + 3 = 4 * a := by + linear_combination a * h - h + +/-- +error: ring failed, ring expressions not equal +a b : ℕ +h : a = 3 +⊢ 3 + a ^ 2 + (a - 1) * 3 = a * 4 + a * (a - 1) +-/ +#guard_msgs in +example {a b : ℕ} (h : a = 3) : a ^ 2 + 3 = 4 * a := by + linear_combination (a - 1) * h + +example {a b c : ℕ} (h1 : c = 1) (h2 : a - b = 4) : (a - b) * c = 4 := by + linear_combination (a - b) * h1 + h2 + +/-- +error: ring failed, ring expressions not equal +a b c : ℕ +h1 : c = 1 +h2 : a - b = 4 +⊢ 4 + (a - b) * c + c * b + a = 4 + (a - b) + c * a + b +-/ +#guard_msgs in +example {a b c : ℕ} (h1 : c = 1) (h2 : a - b = 4) : (a - b) * c = 4 := by + linear_combination a * h1 - b * h1 + h2 + /-! ### Cases that explicitly use a config -/ example (x y : ℚ) (h1 : 3 * x + 2 * y = 10) (h2 : 2 * x + 5 * y = 3) : -11 * y + 1 = 11 + 1 := by @@ -154,6 +197,8 @@ example (x y : ℤ) (h1 : x = -3) (_h2 : y = 10) : 2 * x = -6 := by example {x y z w : ℤ} (_h₁ : 3 * x = 4 + y) (_h₂ : x + 2 * y = 1) : z + w = w + z := by linear_combination +example (x : ℤ) : x ^ 2 = x ^ 2 := by linear_combination + -- this interacts as expected with options example {x y z w : ℤ} (_h₁ : 3 * x = 4 + y) (_h₂ : x + 2 * y = 1) : z + w = w + z := by linear_combination (norm := skip) @@ -184,25 +229,67 @@ 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 : ℚ +ha : a = 1 +⊢ -1 = 0 +-/ +#guard_msgs in +example (a : ℚ) (ha : a = 1) : a = 2 := by linear_combination ha + -- This should fail because the second coefficient has a different type than -- the equations it is being combined with. This was a design choice for the -- sake of simplicity, but the tactic could potentially be modified to allow -- this behavior. +/-- +error: application type mismatch + Mathlib.Tactic.LinearCombination.c_mul_pf h2 0 +argument + 0 +has type + ℝ : Type +but is expected to have type + ℤ : Type +-/ +#guard_msgs in example (x y : ℤ) (h1 : x * y + 2 * x = 1) (h2 : x = y) : x * y + 2 * x = 1 := by - fail_if_success linear_combination h1 + (0 : ℝ) * h2 - linear_combination h1 - --- This fails because the linear_combination tactic requires the equations --- and coefficients to use a type that fulfills the add_group condition, --- and ℕ does not. -example (a _b : ℕ) (h1 : a = 3) : a = 3 := by - fail_if_success linear_combination h1 - linear_combination2 h1 + linear_combination h1 + (0 : ℝ) * h2 example (a b : ℤ) (x y : ℝ) (hab : a = b) (hxy : x = y) : 2 * x = 2 * y := by fail_if_success linear_combination 2 * hab linear_combination 2 * hxy +/-- +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/meta.lean b/test/meta.lean index 5cd408d0b195a..3d5620d3af41c 100644 --- a/test/meta.lean +++ b/test/meta.lean @@ -11,6 +11,7 @@ namespace Tests open Lean Meta private axiom test_sorry : ∀ {α}, α +set_option linter.style.setOption false in set_option pp.unicode.fun true def eTrue := Expr.const ``True [] @@ -59,6 +60,8 @@ elab "test_forallNot_of_notExists" t:term : tactic => do unless ← isDefEq ety' (← inferType e') do throwError "bad proof" logInfo m!"{ety'}" +set_option linter.unusedTactic false + /-- info: ∀ (x : Nat), ¬0 < x -/ #guard_msgs in example (h : ¬ ∃ x, 0 < x) : False := by diff --git a/test/module.lean b/test/module.lean new file mode 100644 index 0000000000000..ee59dd02d0d9f --- /dev/null +++ b/test/module.lean @@ -0,0 +1,308 @@ +/- +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.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/notation3.lean b/test/notation3.lean index 44116cca2ce50..c4473b94e10e7 100644 --- a/test/notation3.lean +++ b/test/notation3.lean @@ -1,7 +1,7 @@ import Mathlib.Util.Notation3 -import Mathlib.Init.Data.Nat.Lemmas import Mathlib.Data.Nat.Defs +set_option linter.style.setOption false set_option pp.unicode.fun true set_option autoImplicit true @@ -151,6 +151,7 @@ matcher from the expansion. (Use `set_option trace.notation3 true` to get some d end section +set_option linter.unusedTactic false local notation3 (prettyPrint := false) "#" n => Fin.mk n (by decide) example : Fin 5 := #1 @@ -202,3 +203,5 @@ notation3 "δNat" => (default : Nat) #guard_msgs in #check (default : Nat) /-- info: δNat : ℕ -/ #guard_msgs in #check @default Nat (Inhabited.mk 5) + +end Test diff --git a/test/old_obtain.lean b/test/oldObtain.lean similarity index 92% rename from test/old_obtain.lean rename to test/oldObtain.lean index 254bb06f364ef..bdbf53e7e9e94 100644 --- a/test/old_obtain.lean +++ b/test/oldObtain.lean @@ -7,6 +7,8 @@ import Mathlib.Tactic.Linter.OldObtain /-! Tests for the `oldObtain` linter. -/ +set_option linter.oldObtain false + -- These cases are fine. theorem foo : True := by obtain := trivial @@ -17,7 +19,6 @@ theorem foo : True := by -- These cases are linted against. -set_option linter.oldObtain false in /-- warning: Please remove stream-of-conciousness `obtain` syntax note: this linter can be disabled with `set_option linter.oldObtain false` @@ -29,7 +30,6 @@ theorem foo' : True := by · trivial trivial -set_option linter.oldObtain false in /-- warning: Please remove stream-of-conciousness `obtain` syntax note: this linter can be disabled with `set_option linter.oldObtain false` diff --git a/test/polyrith.lean b/test/polyrith.lean index a0bd8b137e1f3..58c192b53bdc6 100644 --- a/test/polyrith.lean +++ b/test/polyrith.lean @@ -7,7 +7,7 @@ import Mathlib.Tactic.Polyrith -- Except for the `import`, the doc-modules and the following `set_option`, this file is just -- comments and whitespace. Once the file gets revived, the linting can start! -set_option linter.longLine false +set_option linter.style.longLine false /-! @@ -183,7 +183,7 @@ A full test suite is provided at the bottom of the file. -- "(((((2 * var0) - 3) + (9 * var1)) + (3 * var2)) - (((8 - var3) + (3 * var2)) - (3 * var0)))"] -- "linear_combination 2 * h1 - h2 + 3 * h3 - 3 * h4" --- /-! ### Case with ambiguous identifiers-/ +-- /-! ### Case with ambiguous identifiers -/ -- example («def evil» y : ℤ) (h1 : 3*«def evil» + 2*y = 10) : -- 3*«def evil» + 2*y = 10 := @@ -481,7 +481,7 @@ example (a b c d : ℚ) (h1 : a = 4) (h2 : 3 = b) (h3 : c*3 = d) (h4 : -d = a) : 2*a - 3 + 9*c + 3*d = 8 - b + 3*d - 3*a := by polyrith -/-! ### Case with ambiguous identifiers-/ +/-! ### Case with ambiguous identifiers -/ -- set_option trace.Meta.Tactic.polyrith true example («def evil» y : ℤ) (h1 : 3*«def evil» + 2*y = 10) : 3*«def evil» + 2*y = 10 := by @@ -631,7 +631,7 @@ example (a b c d : ℚ) (h1 : a = 4) (h2 : 3 = b) (h3 : c*3 = d) (h4 : -d = a) : 2*a - 3 + 9*c + 3*d = 8 - b + 3*d - 3*a := by create_polyrith_test -/-! ### Case with ambiguous identifiers-/ +/-! ### Case with ambiguous identifiers -/ example («def evil» y : ℤ) (h1 : 3*«def evil» + 2*y = 10) : 3*«def evil» + 2*y = 10 := by diff --git a/test/positivity.lean b/test/positivity.lean index d75fda862bd69..fc773c8abd962 100644 --- a/test/positivity.lean +++ b/test/positivity.lean @@ -23,6 +23,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 diff --git a/test/propose.lean b/test/propose.lean index bb39586ed5ccd..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 @@ -11,9 +12,9 @@ set_option autoImplicit true theorem foo (L M : List α) (w : L.Disjoint M) (m : a ∈ L) : a ∉ M := fun h => w m h /-- -info: Try this: have : K.Disjoint M := List.disjoint_of_subset_left m w ---- info: Try this: have : M.Disjoint L := List.disjoint_symm w +--- +info: Try this: have : K.Disjoint M := List.disjoint_of_subset_left m w -/ #guard_msgs in example (K L M : List α) (w : L.Disjoint M) (m : K ⊆ L) : True := by @@ -70,16 +71,16 @@ info: Try this: have : IsUnit p := isUnit_of_dvd_one h --- info: Try this: have : ¬IsUnit p := not_unit hp --- -info: Try this: have : ¬p ∣ 1 := not_dvd_one hp +info: Try this: have : p ∣ p * p ↔ p ∣ p ∨ p ∣ p := Prime.dvd_mul hp --- info: Try this: have : p ∣ p ∨ p ∣ p := dvd_or_dvd hp (Exists.intro p (Eq.refl (p * p))) --- -info: Try this: have : p ≠ 0 := ne_zero hp ---- -info: Try this: have : p ∣ p * p ↔ p ∣ p ∨ p ∣ p := Prime.dvd_mul hp +info: Try this: have : ¬p ∣ 1 := not_dvd_one hp --- info: Try this: have : IsPrimal p := isPrimal hp --- +info: Try this: have : p ≠ 0 := ne_zero hp +--- info: Try this: have : p ≠ 1 := ne_one hp -/ #guard_msgs in diff --git a/test/recover.lean b/test/recover.lean index f31c6d95e8cca..72d81332f21b0 100644 --- a/test/recover.lean +++ b/test/recover.lean @@ -1,10 +1,12 @@ import Mathlib.Tactic.Recover +set_option linter.unusedTactic false + /-- problematic tactic for testing recovery -/ elab "this" "is" "a" "problem" : tactic => Lean.Elab.Tactic.setGoals [] -/- The main test-/ +/- The main test -/ example : 1 = 1 := by recover this is a problem rfl 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 0124fb55fd94c..4315e51cb870d 100644 --- a/test/says.lean +++ b/test/says.lean @@ -57,6 +57,7 @@ example (x y : List α) : (x ++ y).length = x.length + y.length := by simp? says simp only [] set_option linter.unreachableTactic false +set_option linter.unusedTactic false in -- Now we check that `says` does not consume following tactics unless they are indented. /-- error: Tactic `simp` did not produce any messages. @@ -100,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/search/DepthFirst.lean b/test/search/DepthFirst.lean deleted file mode 100644 index fb20922be969c..0000000000000 --- a/test/search/DepthFirst.lean +++ /dev/null @@ -1,11 +0,0 @@ -import Lean.Meta.Basic -import Mathlib.Data.MLList.DepthFirst - -/-- -info: --/ -#guard_msgs in --- We perform a depth first search of the "proper divisors in descending order" tree. -#eval show Lean.MetaM Unit from do - let r := depthFirstRemovingDuplicates' (fun n => List.range n |>.filter (n % · = 0) |>.reverse) 24 - guard <| r = [24, 12, 6, 3, 1, 2, 4, 8] diff --git a/test/set_like.lean b/test/set_like.lean index 284818ca75cd9..2847a594eb156 100644 --- a/test/set_like.lean +++ b/test/set_like.lean @@ -51,7 +51,7 @@ example [Monoid M] (x y z : M) (S₁ S₂ : Submonoid M) (h : S₁ ≤ S₂) (hx x * y * z ∈ S₁ ⊔ S₂ := by aesop -example [Monoid M] (x y z : M) (S : Submonoid M) (hxy : x * y ∈ S) (hz : z ∈ S) : +example [Monoid M] (x y z : M) (S : Submonoid M) (hxy : x * y ∈ S) (hz : z ∈ S) : z * (x * y) ∈ S := by aesop 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/symm.lean b/test/symm.lean index ac2bf3a8d6830..7d88a90868362 100644 --- a/test/symm.lean +++ b/test/symm.lean @@ -15,6 +15,7 @@ def sameParity : Nat → Nat → Prop example (a b : Nat) : sameParity a b → sameParity b a := by intros; symm; assumption +set_option linter.unusedTactic false in example (a b c : Nat) (ab : a = b) (bc : b = c) : c = a := by symm_saturate -- Run twice to check that we don't add repeated copies. @@ -43,7 +44,8 @@ infixl:25 " ≃* " => MulEquiv @[symm] def foo_symm {M N : Type _} [Mul M] [Mul N] (h : M ≃* N) : N ≃* M := - { h.toEquiv.symm with map_mul' := (h.toMulHom.inverse h.toEquiv.symm h.left_inv h.right_inv).map_mul } + { h.toEquiv.symm with map_mul' := + (h.toMulHom.inverse h.toEquiv.symm h.left_inv h.right_inv).map_mul } def MyEq (n m : Nat) := ∃ k, n + k = m ∧ m + k = n 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 13390631ccf6c..bd2ad86c8e087 100644 --- a/test/toAdditive.lean +++ b/test/toAdditive.lean @@ -1,6 +1,5 @@ import Mathlib.Algebra.Group.Defs import Mathlib.Lean.Exception -import Mathlib.Util.Time import Qq.MetaM open Qq Lean Meta Elab Command ToAdditive @@ -20,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/trace.lean b/test/trace.lean index 1ba2fcaed0693..829fd7ee45918 100644 --- a/test/trace.lean +++ b/test/trace.lean @@ -1,4 +1,7 @@ import Mathlib.Tactic.Trace + +set_option linter.unusedTactic false + /-- info: 7 -/ diff --git a/test/trans.lean b/test/trans.lean index 31f9e5506fb08..50b5bc01e7b20 100644 --- a/test/trans.lean +++ b/test/trans.lean @@ -90,6 +90,7 @@ example {A B C : Prop} (h : A → B) (g : B → C) : A → C := by · 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 @@ -99,6 +100,7 @@ example {A B C : Type} (h : A → B) (g : B → C) : A → C := by 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 diff --git a/test/vec_notation.lean b/test/vec_notation.lean index 6828096e09696..6efacef50359c 100644 --- a/test/vec_notation.lean +++ b/test/vec_notation.lean @@ -8,7 +8,7 @@ open Lean open Lean.Meta open Qq -set_option linter.setOption false in +set_option linter.style.setOption false in set_option pp.unicode.fun false /-! These tests are testing `PiFin.toExpr` and fail with diff --git a/widget/src/penrose/commutative.sty b/widget/src/penrose/commutative.sty index f6e189f7b9164..ba276afa7f29c 100644 --- a/widget/src/penrose/commutative.sty +++ b/widget/src/penrose/commutative.sty @@ -18,7 +18,7 @@ const { layout = [Grid, Arrows, EnsureOnCanvas] forall Targettable x { - -- The `center` is the "root" position of a targettable. Cells targetting + -- The `center` is the "root" position of a targettable. Cells targeting -- this targettable start/end at positions relative to the center. -- HACK: The optimization variable has to be defined in terms of two separate -- floats to force Penrose to track dependencies at this granularity rather @@ -46,7 +46,7 @@ forall Targettable x { } -- NOTE: Not used anymore, we use the optimization engine instead. - -- Sides of a Targettable where the ends of cells targetting it are attached. + -- Sides of a Targettable where the ends of cells targeting it are attached. -- +-T-+ -- L C R -- +-B-+ @@ -136,7 +136,7 @@ where f := MakeCell(A, B) { -- in order to make convergence possible. override f.textBox.ensureOnCanvas = false - -- NOTE: This is only necessary for the playground. The Lean widget programatically positions + -- NOTE: This is only necessary for the playground. The Lean widget programmatically positions -- the diagram after optimization. -- ensure onCanvas(f.textBox, canvas.width, canvas.height) in EnsureOnCanvas -- ensure onCanvas(f.shape, canvas.width, canvas.height) in EnsureOnCanvas